# HG changeset patch # User Chris Cannam # Date 1330350798 0 # Node ID 5e80956cc792ae026e97fced5330067867bf438a # Parent 487d96eac004f072a05fe1b66104e54daab63607# Parent cbb26bc654de6d83f4e26cb599a865d2541f5476 Merge from branch "redmine-1.3" diff -r 487d96eac004 -r 5e80956cc792 .gitignore --- a/.gitignore Fri Feb 24 20:18:25 2012 +0000 +++ b/.gitignore Mon Feb 27 13:53:18 2012 +0000 @@ -23,3 +23,8 @@ /tmp/test/* /vendor/rails *.rbc + +/.bundle +/Gemfile.lock +/Gemfile.local + diff -r 487d96eac004 -r 5e80956cc792 .hgignore --- a/.hgignore Fri Feb 24 20:18:25 2012 +0000 +++ b/.hgignore Mon Feb 27 13:53:18 2012 +0000 @@ -18,13 +18,20 @@ log/mongrel_debug public/dispatch.* public/plugin_assets +tmp/* tmp/cache/* tmp/sessions/* tmp/sockets/* tmp/test/* vendor/rails *.rbc + .svn/ .git/ *~ + +.bundle +Gemfile.lock +Gemfile.local + diff -r 487d96eac004 -r 5e80956cc792 .svn/dir-prop-base --- a/.svn/dir-prop-base Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -K 9 -svk:merge -V 48 -e93f8b46-1217-0410-a6f0-8f06a7374b81:/trunk:1751 -K 10 -svn:ignore -V 28 -coverage -.project -.loadpath - -END diff -r 487d96eac004 -r 5e80956cc792 .svn/entries --- a/.svn/entries Fri Feb 24 20:18:25 2012 +0000 +++ b/.svn/entries Mon Feb 27 13:53:18 2012 +0000 @@ -1,181 +1,1 @@ -10 - -dir -6270 -http://redmine.rubyforge.org/svn/branches/1.2-stable -http://redmine.rubyforge.org/svn - - - -2011-07-11T11:45:14.631570Z -6261 -jplang -has-props - - - - - - - - - - - - - -e93f8b46-1217-0410-a6f0-8f06a7374b81 - -test -dir - -app -dir - -.hgignore -file - - - - - -cf080444603c5774a6f20da6bbafe234 -2011-03-28T04:54:13.617808Z -5235 -tmaruyama - -log -dir - -Rakefile -file - - - - -2011-07-14T09:24:09.000000Z -bbf560d44f092d22a30d3a562436ad8c -2006-12-05T20:45:04.842118Z -67 -jplang - - - - - - - - - - - - - - - - - - - - - -307 - -README.rdoc -file - - - - -2011-07-14T09:24:09.000000Z -67c937b1f1d0603e69f322de34bbfe04 -2010-07-18T15:49:24.341728Z -3849 -edavis10 - - - - - - - - - - - - - - - - - - - - - -208 - -extra -dir - -db -dir - -vendor -dir - -tmp -dir - -files -dir - -script -dir - -.gitignore -file - - - - -2011-07-14T09:24:09.000000Z -84dbba0b6ddcd80d28c62a3f8e344bc4 -2011-02-15T11:04:52.942730Z -4834 -tmaruyama - - - - - - - - - - - - - - - - - - - - - -477 - -config -dir - -doc -dir - -lib -dir - -public -dir - +12 diff -r 487d96eac004 -r 5e80956cc792 .svn/format --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/format Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +12 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/00/005b22dce38bfa0d4254f9b889284c20d8267418.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/00/005b22dce38bfa0d4254f9b889284c20d8267418.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + create_table :open_id_authentication_associations, :force => true do |t| + t.integer :issued, :lifetime + t.string :handle, :assoc_type + t.binary :server_url, :secret + end + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_associations + drop_table :open_id_authentication_nonces + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/00/0065f42c8aab54558480736376f69f7b72cabc58.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/00/0065f42c8aab54558480736376f69f7b72cabc58.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +require 'test/unit' +require 'rubygems' + +gem 'activesupport' +require 'active_support' + +gem 'actionpack' +require 'action_controller' + +gem 'mocha' +require 'mocha' + +gem 'ruby-openid' +require 'openid' + +RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT +require File.dirname(__FILE__) + "/../lib/open_id_authentication" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/00/007e22f777adc578342260747f72f3fcfceb129d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/00/007e22f777adc578342260747f72f3fcfceb129d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class ProjectCustomField < CustomField + def type_name + :label_project_plural + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/00/00c4bd6691f32db8720a826db98aecc930f926d9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/00/00c4bd6691f32db8720a826db98aecc930f926d9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,165 @@ +# $Id: entry.rb 123 2006-05-18 03:52:38Z blackhedd $ +# +# LDAP Entry (search-result) support classes +# +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Gmail: garbagecat10 +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +#--------------------------------------------------------------------------- +# + + + + +module Net +class LDAP + + + # Objects of this class represent individual entries in an LDAP + # directory. User code generally does not instantiate this class. + # Net::LDAP#search provides objects of this class to user code, + # either as block parameters or as return values. + # + # In LDAP-land, an "entry" is a collection of attributes that are + # uniquely and globally identified by a DN ("Distinguished Name"). + # Attributes are identified by short, descriptive words or phrases. + # Although a directory is + # free to implement any attribute name, most of them follow rigorous + # standards so that the range of commonly-encountered attribute + # names is not large. + # + # An attribute name is case-insensitive. Most directories also + # restrict the range of characters allowed in attribute names. + # To simplify handling attribute names, Net::LDAP::Entry + # internally converts them to a standard format. Therefore, the + # methods which take attribute names can take Strings or Symbols, + # and work correctly regardless of case or capitalization. + # + # An attribute consists of zero or more data items called + # values. An entry is the combination of a unique DN, a set of attribute + # names, and a (possibly-empty) array of values for each attribute. + # + # Class Net::LDAP::Entry provides convenience methods for dealing + # with LDAP entries. + # In addition to the methods documented below, you may access individual + # attributes of an entry simply by giving the attribute name as + # the name of a method call. For example: + # ldap.search( ... ) do |entry| + # puts "Common name: #{entry.cn}" + # puts "Email addresses:" + # entry.mail.each {|ma| puts ma} + # end + # If you use this technique to access an attribute that is not present + # in a particular Entry object, a NoMethodError exception will be raised. + # + #-- + # Ugly problem to fix someday: We key off the internal hash with + # a canonical form of the attribute name: convert to a string, + # downcase, then take the symbol. Unfortunately we do this in + # at least three places. Should do it in ONE place. + class Entry + + # This constructor is not generally called by user code. + def initialize dn = nil # :nodoc: + @myhash = Hash.new {|k,v| k[v] = [] } + @myhash[:dn] = [dn] + end + + + def []= name, value # :nodoc: + sym = name.to_s.downcase.intern + @myhash[sym] = value + end + + + #-- + # We have to deal with this one as we do with []= + # because this one and not the other one gets called + # in formulations like entry["CN"] << cn. + # + def [] name # :nodoc: + name = name.to_s.downcase.intern unless name.is_a?(Symbol) + @myhash[name] + end + + # Returns the dn of the Entry as a String. + def dn + self[:dn][0] + end + + # Returns an array of the attribute names present in the Entry. + def attribute_names + @myhash.keys + end + + # Accesses each of the attributes present in the Entry. + # Calls a user-supplied block with each attribute in turn, + # passing two arguments to the block: a Symbol giving + # the name of the attribute, and a (possibly empty) + # Array of data values. + # + def each + if block_given? + attribute_names.each {|a| + attr_name,values = a,self[a] + yield attr_name, values + } + end + end + + alias_method :each_attribute, :each + + + #-- + # Convenience method to convert unknown method names + # to attribute references. Of course the method name + # comes to us as a symbol, so let's save a little time + # and not bother with the to_s.downcase two-step. + # Of course that means that a method name like mAIL + # won't work, but we shouldn't be encouraging that + # kind of bad behavior in the first place. + # Maybe we should thow something if the caller sends + # arguments or a block... + # + def method_missing *args, &block # :nodoc: + s = args[0].to_s.downcase.intern + if attribute_names.include?(s) + self[s] + elsif s.to_s[-1] == 61 and s.to_s.length > 1 + value = args[1] or raise RuntimeError.new( "unable to set value" ) + value = [value] unless value.is_a?(Array) + name = s.to_s[0..-2].intern + self[name] = value + else + raise NoMethodError.new( "undefined method '#{s}'" ) + end + end + + def write + end + + end # class Entry + + +end # class LDAP +end # module Net + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/00/00c75f473c43fdd31d40a91d365b29f9d7f944cd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/00/00c75f473c43fdd31d40a91d365b29f9d7f944cd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +See http://dejavu.sourceforge.net/wiki/index.rb/Bugs + +$Id: BUGS 80 2004-11-13 13:12:02Z src $ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01049e9d9cec55a96b7b1a93672943d74c1a87d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/01049e9d9cec55a96b7b1a93672943d74c1a87d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddCustomFieldsSearchable < ActiveRecord::Migration + def self.up + add_column :custom_fields, :searchable, :boolean, :default => false + end + + def self.down + remove_column :custom_fields, :searchable + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/011d952bc7773843d5a8219df22dce0959479d6d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/011d952bc7773843d5a8219df22dce0959479d6d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class DocumentCategoryTest < ActiveSupport::TestCase + fixtures :enumerations, :documents, :issues + + def test_should_be_an_enumeration + assert DocumentCategory.ancestors.include?(Enumeration) + end + + def test_objects_count + assert_equal 2, DocumentCategory.find_by_name("Uncategorized").objects_count + assert_equal 0, DocumentCategory.find_by_name("User documentation").objects_count + end + + def test_option_name + assert_equal :enumeration_doc_categories, DocumentCategory.new.option_name + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01272907f6842a5e924d61c923ee0994110ab686.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/01272907f6842a5e924d61c923ee0994110ab686.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,260 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) + +class Redmine::MenuManager::MenuHelperTest < HelperTestCase + include Redmine::MenuManager::MenuHelper + include ActionController::Assertions::SelectorAssertions + fixtures :users, :members, :projects, :enabled_modules + + # Used by assert_select + def html_document + HTML::Document.new(@response.body) + end + + def setup + super + @response = ActionController::TestResponse.new + # Stub the current menu item in the controller + def current_menu_item + :index + end + end + + + context "MenuManager#current_menu_item" do + should "be tested" + end + + context "MenuManager#render_main_menu" do + should "be tested" + end + + context "MenuManager#render_menu" do + should "be tested" + end + + context "MenuManager#menu_item_and_children" do + should "be tested" + end + + context "MenuManager#extract_node_details" do + should "be tested" + end + + def test_render_single_menu_node + node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { }) + @response.body = render_single_menu_node(node, 'This is a test', node.url, false) + + assert_select("a.testing", "This is a test") + end + + def test_render_menu_node + single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { }) + @response.body = render_menu_node(single_node, nil) + + assert_select("li") do + assert_select("a.single-node", "Single node") + end + end + + def test_render_menu_node_with_nested_items + parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { }) + parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { }) + parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { }) + parent_node << + Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) << + Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { }) + + @response.body = render_menu_node(parent_node, nil) + + assert_select("li") do + assert_select("a.parent-node", "Parent node") + assert_select("ul") do + assert_select("li a.child-one-node", "Child one node") + assert_select("li a.child-two-node", "Child two node") + assert_select("li") do + assert_select("a.child-three-node", "Child three node") + assert_select("ul") do + assert_select("li a.child-three-inner-node", "Child three inner node") + end + end + end + end + + end + + def test_render_menu_node_with_children + User.current = User.find(2) + + parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, + '/test', + { + :children => Proc.new {|p| + children = [] + 3.times do |time| + children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", + {:controller => 'issues', :action => 'index'}, + {}) + end + children + } + }) + @response.body = render_menu_node(parent_node, Project.find(1)) + + assert_select("li") do + assert_select("a.parent-node", "Parent node") + assert_select("ul") do + assert_select("li a.test-child-0", "Test child 0") + assert_select("li a.test-child-1", "Test child 1") + assert_select("li a.test-child-2", "Test child 2") + end + end + end + + def test_render_menu_node_with_nested_items_and_children + User.current = User.find(2) + + parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, + '/test', + { + :children => Proc.new {|p| + children = [] + 3.times do |time| + children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {}) + end + children + } + }) + + parent_node << Redmine::MenuManager::MenuItem.new(:child_node, + '/test', + { + :children => Proc.new {|p| + children = [] + 6.times do |time| + children << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {}) + end + children + } + }) + + @response.body = render_menu_node(parent_node, Project.find(1)) + + assert_select("li") do + assert_select("a.parent-node", "Parent node") + assert_select("ul") do + assert_select("li a.child-node", "Child node") + assert_select("ul") do + assert_select("li a.test-dynamic-child-0", "Test dynamic child 0") + assert_select("li a.test-dynamic-child-1", "Test dynamic child 1") + assert_select("li a.test-dynamic-child-2", "Test dynamic child 2") + assert_select("li a.test-dynamic-child-3", "Test dynamic child 3") + assert_select("li a.test-dynamic-child-4", "Test dynamic child 4") + assert_select("li a.test-dynamic-child-5", "Test dynamic child 5") + end + assert_select("li a.test-child-0", "Test child 0") + assert_select("li a.test-child-1", "Test child 1") + assert_select("li a.test-child-2", "Test child 2") + end + end + end + + def test_render_menu_node_with_children_without_an_array + parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, + '/test', + { + :children => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})} + }) + + assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do + @response.body = render_menu_node(parent_node, Project.find(1)) + end + end + + def test_render_menu_node_with_incorrect_children + parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, + '/test', + { + :children => Proc.new {|p| ["a string"] } + }) + + assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do + @response.body = render_menu_node(parent_node, Project.find(1)) + end + + end + + def test_menu_items_for_should_yield_all_items_if_passed_a_block + menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block + Redmine::MenuManager.map menu_name do |menu| + menu.push(:a_menu, '/', { }) + menu.push(:a_menu_2, '/', { }) + menu.push(:a_menu_3, '/', { }) + end + + items_yielded = [] + menu_items_for(menu_name) do |item| + items_yielded << item + end + + assert_equal 3, items_yielded.size + end + + def test_menu_items_for_should_return_all_items + menu_name = :test_menu_items_for_should_return_all_items + Redmine::MenuManager.map menu_name do |menu| + menu.push(:a_menu, '/', { }) + menu.push(:a_menu_2, '/', { }) + menu.push(:a_menu_3, '/', { }) + end + + items = menu_items_for(menu_name) + assert_equal 3, items.size + end + + def test_menu_items_for_should_skip_unallowed_items_on_a_project + menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project + Redmine::MenuManager.map menu_name do |menu| + menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { }) + menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { }) + menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { }) + end + + User.current = User.find(2) + + items = menu_items_for(menu_name, Project.find(1)) + assert_equal 2, items.size + end + + def test_menu_items_for_should_skip_items_that_fail_the_conditions + menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions + Redmine::MenuManager.map menu_name do |menu| + menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { }) + menu.push(:unallowed, + {:controller => 'issues', :action => 'index' }, + { :if => Proc.new { false }}) + end + + User.current = User.find(2) + + items = menu_items_for(menu_name, Project.find(1)) + assert_equal 1, items.size + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/013035c9e2d7a0734359dad136ab782f7272366b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/013035c9e2d7a0734359dad136ab782f7272366b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +class CreateJournals < ActiveRecord::Migration + + # model removed, but needed for data migration + class IssueHistory < ActiveRecord::Base; belongs_to :issue; end + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + create_table :journals, :force => true do |t| + t.column "journalized_id", :integer, :default => 0, :null => false + t.column "journalized_type", :string, :limit => 30, :default => "", :null => false + t.column "user_id", :integer, :default => 0, :null => false + t.column "notes", :text + t.column "created_on", :datetime, :null => false + end + create_table :journal_details, :force => true do |t| + t.column "journal_id", :integer, :default => 0, :null => false + t.column "property", :string, :limit => 30, :default => "", :null => false + t.column "prop_key", :string, :limit => 30, :default => "", :null => false + t.column "old_value", :string + t.column "value", :string + end + + # indexes + add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" + add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" + + Permission.create :controller => "issues", :action => "history", :description => "label_history", :sort => 1006, :is_public => true, :mail_option => 0, :mail_enabled => 0 + + # data migration + IssueHistory.find(:all, :include => :issue).each {|h| + j = Journal.new(:journalized => h.issue, :user_id => h.author_id, :notes => h.notes, :created_on => h.created_on) + j.details << JournalDetail.new(:property => 'attr', :prop_key => 'status_id', :value => h.status_id) + j.save + } + + drop_table :issue_histories + end + + def self.down + drop_table :journal_details + drop_table :journals + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text, :default => "" + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'history']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01346eb099170b569ce9589ce5f15a834ff1b1a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/01346eb099170b569ce9589ce5f15a834ff1b1a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,90 @@ +# Various mathematical calculations extracted from the PDF::Writer for Ruby gem. +# - http://rubyforge.org/projects/ruby-pdf +# - Copyright 2003 - 2005 Austin Ziegler. +# - Licensed under a MIT-style licence. +# + +module RFPDF::Math + PI2 = ::Math::PI * 2.0 + + # One degree of arc measured in terms of radians. + DR = PI2 / 360.0 + # One radian of arc, measured in terms of degrees. + RD = 360 / PI2 + # One degree of arc, measured in terms of gradians. + DG = 400 / 360.0 + # One gradian of arc, measured in terms of degrees. + GD = 360 / 400.0 + # One radian of arc, measured in terms of gradians. + RG = 400 / PI2 + # One gradian of arc, measured in terms of radians. + GR = PI2 / 400.0 + + # Truncate the remainder. + def remt(num, den) + num - den * (num / den.to_f).to_i + end + + # Wrap radian values within the range of radians (0..PI2). + def rad2rad(rad) + remt(rad, PI2) + end + + # Wrap degree values within the range of degrees (0..360). + def deg2deg(deg) + remt(deg, 360) + end + + # Wrap gradian values within the range of gradians (0..400). + def grad2grad(grad) + remt(grad, 400) + end + + # Convert degrees to radians. The value will be constrained to the + # range of radians (0..PI2) unless +wrap+ is false. + def deg2rad(deg, wrap = true) + rad = DR * deg + rad = rad2rad(rad) if wrap + rad + end + + # Convert degrees to gradians. The value will be constrained to the + # range of gradians (0..400) unless +wrap+ is false. + def deg2grad(deg, wrap = true) + grad = DG * deg + grad = grad2grad(grad) if wrap + grad + end + + # Convert radians to degrees. The value will be constrained to the + # range of degrees (0..360) unless +wrap+ is false. + def rad2deg(rad, wrap = true) + deg = RD * rad + deg = deg2deg(deg) if wrap + deg + end + + # Convert radians to gradians. The value will be constrained to the + # range of gradians (0..400) unless +wrap+ is false. + def rad2grad(rad, wrap = true) + grad = RG * rad + grad = grad2grad(grad) if wrap + grad + end + + # Convert gradians to degrees. The value will be constrained to the + # range of degrees (0..360) unless +wrap+ is false. + def grad2deg(grad, wrap = true) + deg = GD * grad + deg = deg2deg(deg) if wrap + deg + end + + # Convert gradians to radians. The value will be constrained to the + # range of radians (0..PI2) unless +wrap+ is false. + def grad2rad(grad, wrap = true) + rad = GR * grad + rad = rad2rad(rad) if wrap + rad + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/0162b6b3641be6f64f06d092167f50f74bce25a2.svn-base Binary file .svn/pristine/01/0162b6b3641be6f64f06d092167f50f74bce25a2.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/016b47aef50027cc7a73f1b3fdde3506ed5b4072.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/016b47aef50027cc7a73f1b3fdde3506ed5b4072.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class IssueCategory < ActiveRecord::Base + generator_for :name, :start => 'Category 0001' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/0171e251406a6b1885f3fa9813dc6f97a4ee7ea8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/0171e251406a6b1885f3fa9813dc6f97a4ee7ea8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/test_helper' + +class NormalizeTest < Test::Unit::TestCase + include OpenIdAuthentication + + NORMALIZATIONS = { + "openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", + "http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", + "https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler", + "HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER", + "HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER", + "loudthinking.com" => "http://loudthinking.com/", + "http://loudthinking.com" => "http://loudthinking.com/", + "http://loudthinking.com:80" => "http://loudthinking.com/", + "https://loudthinking.com:443" => "https://loudthinking.com/", + "http://loudthinking.com:8080" => "http://loudthinking.com:8080/", + "techno-weenie.net" => "http://techno-weenie.net/", + "http://techno-weenie.net" => "http://techno-weenie.net/", + "http://techno-weenie.net " => "http://techno-weenie.net/", + "=name" => "=name" + } + + def test_normalizations + NORMALIZATIONS.each do |from, to| + assert_equal to, normalize_identifier(from) + end + end + + def test_broken_open_id + assert_raises(InvalidOpenId) { normalize_identifier(nil) } + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01a6ee1f20ebd9960efb3d88db810fb607deb030.svn-base Binary file .svn/pristine/01/01a6ee1f20ebd9960efb3d88db810fb607deb030.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01c72fb7f3d1eed2891447f585aaa09ce5f33082.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/01c72fb7f3d1eed2891447f585aaa09ce5f33082.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'پررنگ'; +jsToolBar.strings['Italic'] = 'کج'; +jsToolBar.strings['Underline'] = 'زیرخط'; +jsToolBar.strings['Deleted'] = 'برداشته شده'; +jsToolBar.strings['Code'] = 'کد درون خطی'; +jsToolBar.strings['Heading 1'] = 'سربرگ ۱'; +jsToolBar.strings['Heading 2'] = 'سربرگ ۲'; +jsToolBar.strings['Heading 3'] = 'سربرگ ۳'; +jsToolBar.strings['Unordered list'] = 'فهرست بدون شماره'; +jsToolBar.strings['Ordered list'] = 'فهرست با شماره'; +jsToolBar.strings['Quote'] = 'تو بردن'; +jsToolBar.strings['Unquote'] = 'بیرون آوردن'; +jsToolBar.strings['Preformatted text'] = 'نوشته قالب بندی شده'; +jsToolBar.strings['Wiki link'] = 'پیوند به برگ ویکی'; +jsToolBar.strings['Image'] = 'عکس'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01d08f5b37dfa46aae097b270dbf10baa02d7e48.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/01d08f5b37dfa46aae097b270dbf10baa02d7e48.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class ExportPdf < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "export_issues_pdf", :description => "label_export_pdf", :sort => 1002, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "issues", :action => "export_pdf", :description => "label_export_pdf", :sort => 1015, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'export_issues_pdf']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'export_pdf']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/01/01fd40d061a2be270b23a0152d0699de1966efc7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/01/01fd40d061a2be270b23a0152d0699de1966efc7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,194 @@ +--- +roles_001: + name: Manager + id: 1 + builtin: 0 + issues_visibility: all + permissions: | + --- + - :add_project + - :edit_project + - :select_project_modules + - :manage_members + - :manage_versions + - :manage_categories + - :view_issues + - :add_issues + - :edit_issues + - :manage_issue_relations + - :manage_subtasks + - :add_issue_notes + - :move_issues + - :delete_issues + - :view_issue_watchers + - :add_issue_watchers + - :set_issues_private + - :delete_issue_watchers + - :manage_public_queries + - :save_queries + - :view_gantt + - :view_calendar + - :log_time + - :view_time_entries + - :edit_time_entries + - :delete_time_entries + - :manage_news + - :comment_news + - :view_documents + - :manage_documents + - :view_wiki_pages + - :export_wiki_pages + - :view_wiki_edits + - :edit_wiki_pages + - :delete_wiki_pages_attachments + - :protect_wiki_pages + - :delete_wiki_pages + - :rename_wiki_pages + - :add_messages + - :edit_messages + - :delete_messages + - :manage_boards + - :view_files + - :manage_files + - :browse_repository + - :manage_repository + - :view_changesets + - :manage_project_activities + + position: 1 +roles_002: + name: Developer + id: 2 + builtin: 0 + issues_visibility: default + permissions: | + --- + - :edit_project + - :manage_members + - :manage_versions + - :manage_categories + - :view_issues + - :add_issues + - :edit_issues + - :manage_issue_relations + - :manage_subtasks + - :add_issue_notes + - :move_issues + - :delete_issues + - :view_issue_watchers + - :save_queries + - :view_gantt + - :view_calendar + - :log_time + - :view_time_entries + - :edit_own_time_entries + - :manage_news + - :comment_news + - :view_documents + - :manage_documents + - :view_wiki_pages + - :view_wiki_edits + - :edit_wiki_pages + - :protect_wiki_pages + - :delete_wiki_pages + - :add_messages + - :edit_own_messages + - :delete_own_messages + - :manage_boards + - :view_files + - :manage_files + - :browse_repository + - :view_changesets + + position: 2 +roles_003: + name: Reporter + id: 3 + builtin: 0 + issues_visibility: default + permissions: | + --- + - :edit_project + - :manage_members + - :manage_versions + - :manage_categories + - :view_issues + - :add_issues + - :edit_issues + - :manage_issue_relations + - :add_issue_notes + - :move_issues + - :view_issue_watchers + - :save_queries + - :view_gantt + - :view_calendar + - :log_time + - :view_time_entries + - :manage_news + - :comment_news + - :view_documents + - :manage_documents + - :view_wiki_pages + - :view_wiki_edits + - :edit_wiki_pages + - :delete_wiki_pages + - :add_messages + - :manage_boards + - :view_files + - :manage_files + - :browse_repository + - :view_changesets + + position: 3 +roles_004: + name: Non member + id: 4 + builtin: 1 + issues_visibility: default + permissions: | + --- + - :view_issues + - :add_issues + - :edit_issues + - :manage_issue_relations + - :add_issue_notes + - :move_issues + - :save_queries + - :view_gantt + - :view_calendar + - :log_time + - :view_time_entries + - :comment_news + - :view_documents + - :manage_documents + - :view_wiki_pages + - :view_wiki_edits + - :edit_wiki_pages + - :add_messages + - :view_files + - :manage_files + - :browse_repository + - :view_changesets + + position: 4 +roles_005: + name: Anonymous + id: 5 + builtin: 2 + issues_visibility: default + permissions: | + --- + - :view_issues + - :add_issue_notes + - :view_gantt + - :view_calendar + - :view_time_entries + - :view_documents + - :view_wiki_pages + - :view_wiki_edits + - :view_files + - :browse_repository + - :view_changesets + + position: 5 + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/02/025612e4a47b7cb1c36f52b9661b0cc1f94b2a45.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/02/025612e4a47b7cb1c36f52b9661b0cc1f94b2a45.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +one: + id: 1 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> +two: + id: 2 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/02/028f99ce7a03d78da3e425bf63496e052307234f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/02/028f99ce7a03d78da3e425bf63496e052307234f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +Message-ID: <4974C93E.3070005@somenet.foo> +Date: Mon, 19 Jan 2009 19:41:02 +0100 +From: "John Smith" +User-Agent: Thunderbird 2.0.0.19 (Windows/20081209) +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: Reply via email +References: +In-Reply-To: +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: 7bit + +This is a reply to a forum message. + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/02/02b12282c390ad19361bfb60d3816f4197374dad.svn-base Binary file .svn/pristine/02/02b12282c390ad19361bfb60d3816f4197374dad.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/02/02c8aed5827fd37b4953522a150e77160bca0811.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/02/02c8aed5827fd37b4953522a150e77160bca0811.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +--- +issue_categories_001: + name: Printing + project_id: 1 + assigned_to_id: 2 + id: 1 +issue_categories_002: + name: Recipes + project_id: 1 + assigned_to_id: + id: 2 +issue_categories_003: + name: Stock management + project_id: 2 + assigned_to_id: + id: 3 +issue_categories_004: + name: Printing + project_id: 2 + assigned_to_id: + id: 4 + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/02/02dadac204e591b101d6e3bacd9c59cdeb84b1b6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/02/02dadac204e591b101d6e3bacd9c59cdeb84b1b6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +
    + <% if !@time_entry.nil? -%> +
  • <%= context_menu_link l(:button_edit), {:controller => 'timelog', :action => 'edit', :id => @time_entry}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
  • + <% else %> +
  • <%= context_menu_link l(:button_edit), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id)}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
  • + <% end %> + + <%= call_hook(:view_time_entries_context_menu_start, {:time_entries => @time_entries, :can => @can, :back => @back }) %> + + <% if @activities.present? -%> +
  • + <%= l(:field_activity) %> +
      + <% @activities.each do |u| -%> +
    • <%= context_menu_link h(u.name), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post, + :selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:edit] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_none), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:edit] %>
    • +
    +
  • + <% end %> + + <%= call_hook(:view_time_entries_context_menu_end, {:time_entries => @time_entries, :can => @can, :back => @back }) %> + +
  • + <%= context_menu_link l(:button_delete), + {:controller => 'timelog', :action => 'destroy', :ids => @time_entries.collect(&:id), :back_url => @back}, + :method => :delete, :confirm => l(:text_time_entries_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %> +
  • +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/02/02f1dca1c1029f6ec67eec5619e4edd46e4ee43d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/02/02f1dca1c1029f6ec67eec5619e4edd46e4ee43d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddChangesetsScmid < ActiveRecord::Migration + def self.up + add_column :changesets, :scmid, :string + end + + def self.down + remove_column :changesets, :scmid + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/03110323c21c0fa4339bdcd80aed971c5c6bd9d4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/03110323c21c0fa4339bdcd80aed971c5c6bd9d4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +api.issue_category do + api.id @category.id + api.project(:id => @category.project_id, :name => @category.project.name) unless @category.project.nil? + api.name @category.name + api.assigned_to(:id => @category.assigned_to_id, :name => @category.assigned_to.name) unless @category.assigned_to.nil? +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/032e9aa73399010aaf3eb408ecd8fb8f296696b1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/032e9aa73399010aaf3eb408ecd8fb8f296696b1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,80 @@ +
+ <% if User.current.allowed_to?(:add_subprojects, @project) %> + <%= link_to l(:label_subproject_new), {:controller => 'projects', :action => 'new', :parent_id => @project}, :class => 'icon icon-add' %> + <% end %> +
+ +

<%=l(:label_overview)%>

+ +
+
+ <%= textilizable @project.description %> +
+
    + <% unless @project.homepage.blank? %>
  • <%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %>
  • <% end %> + <% if @subprojects.any? %> +
  • <%=l(:label_subproject_plural)%>: + <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ").html_safe %>
  • + <% end %> + <% @project.visible_custom_field_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
  • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
  • + <% end %> + <% end %> +
+ + <% if User.current.allowed_to?(:view_issues, @project) %> +
+

<%=l(:label_issue_tracking)%>

+
    + <% for tracker in @trackers %> +
  • <%= link_to h(tracker.name), :controller => 'issues', :action => 'index', :project_id => @project, + :set_filter => 1, + "tracker_id" => tracker.id %>: + <%= l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i, + :total => @total_issues_by_tracker[tracker].to_i) %> +
  • + <% end %> +
+

+ <%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 %> + <% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> + | <%= link_to(l(:label_calendar), :controller => 'calendars', :action => 'show', :project_id => @project) %> + <% end %> + <% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> + | <%= link_to(l(:label_gantt), :controller => 'gantts', :action => 'show', :project_id => @project) %> + <% end %> +

+
+ <% end %> + <%= call_hook(:view_projects_show_left, :project => @project) %> +
+ +
+ <%= render :partial => 'members_box' %> + + <% if @news.any? && authorize_for('news', 'index') %> +
+

<%=l(:label_news_latest)%>

+ <%= render :partial => 'news/news', :collection => @news %> +

<%= link_to l(:label_news_view_all), :controller => 'news', :action => 'index', :project_id => @project %>

+
+ <% end %> + <%= call_hook(:view_projects_show_right, :project => @project) %> +
+ +<% content_for :sidebar do %> + <% if @total_hours.present? %> +

<%= l(:label_spent_time) %>

+

<%= l_hours(@total_hours) %>

+

<%= link_to(l(:label_details), {:controller => 'timelog', :action => 'index', :project_id => @project}) %> | + <%= link_to(l(:label_report), {:controller => 'time_entry_reports', :action => 'report', :project_id => @project}) %>

+ <% end %> + <%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +<% html_title(l(:label_overview)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/033178c724d843125ead35eb43e31dacdb4a5511.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/033178c724d843125ead35eb43e31dacdb4a5511.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +# Patch the data from a boolean change. +class UpdateMailNotificationValues < ActiveRecord::Migration + def self.up + # No-op + # See 20100129193402_change_users_mail_notification_to_string.rb + end + + def self.down + # No-op + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/03389ce7c25a023f73b895dc03af8c3f1ee755e9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/03389ce7c25a023f73b895dc03af8c3f1ee755e9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

<%=l(:label_document)%>

+ +<% form_tag({:action => 'edit', :id => @document}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<% end %> + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/033d037b8655e755ff07ebfb8102a3786ab52ea0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/033d037b8655e755ff07ebfb8102a3786ab52ea0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

<%= l(:mail_body_account_activation_request, h(@user.login)) %>

+

<%= link_to h(@url), @url %>

diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/033e041df5add14807dd8e40c1a8ef8894cdf897.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/033e041df5add14807dd8e40c1a8ef8894cdf897.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +From: "John Doe" +To: +Subject: Ticket by unknown user +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit + +This is a ticket submitted by an unknown user. + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/0341468b2bb841c8c330355c1e3aa94ad3cce987.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/0341468b2bb841c8c330355c1e3aa94ad3cce987.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,74 @@ +*SVN* (version numbers are overrated) + +* (5 Oct 2006) Allow customization of #versions association options [Dan Peterson] + +*0.5.1* + +* (8 Aug 2006) Versioned models now belong to the unversioned model. @article_version.article.class => Article [Aslak Hellesoy] + +*0.5* # do versions even matter for plugins? + +* (21 Apr 2006) Added without_locking and without_revision methods. + + Foo.without_revision do + @foo.update_attributes ... + end + +*0.4* + +* (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility). +* (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns. + +*0.3.1* + +* (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged] +* (7 Jan 2006) added tests to prove has_many :through joins work + +*0.3* + +* (2 Jan 2006) added ability to share a mixin with versioned class +* (2 Jan 2006) changed the dynamic version model to MyModel::Version + +*0.2.4* + +* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig] + +*0.2.3* + +* (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig] +* (12 Nov 2005) updated tests to use ActiveRecord Schema + +*0.2.2* + +* (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul] + +*0.2.1* + +* (6 Oct 2005) renamed dirty? to changed? to keep it uniform. it was aliased to keep it backwards compatible. + +*0.2* + +* (6 Oct 2005) added find_versions and find_version class methods. + +* (6 Oct 2005) removed transaction from create_versioned_table(). + this way you can specify your own transaction around a group of operations. + +* (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark) + +* (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model + +*0.1.3* (18 Sep 2005) + +* First RubyForge release + +*0.1.2* + +* check if module is already included when acts_as_versioned is called + +*0.1.1* + +* Adding tests and rdocs + +*0.1* + +* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974 \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/0367c769a1dec5c6ffea095893b82d493a02e68a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/0367c769a1dec5c6ffea095893b82d493a02e68a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,93 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/subversion_adapter' + +class Repository::Subversion < Repository + attr_protected :root_url + validates_presence_of :url + validates_format_of :url, :with => /^(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+/i + + def self.scm_adapter_class + Redmine::Scm::Adapters::SubversionAdapter + end + + def self.scm_name + 'Subversion' + end + + def supports_directory_revisions? + true + end + + def repo_log_encoding + 'UTF-8' + end + + def latest_changesets(path, rev, limit=10) + revisions = scm.revisions(path, rev, nil, :limit => limit) + revisions ? changesets.find_all_by_revision(revisions.collect(&:identifier), :order => "committed_on DESC", :include => :user) : [] + end + + # Returns a path relative to the url of the repository + def relative_path(path) + path.gsub(Regexp.new("^\/?#{Regexp.escape(relative_url)}"), '') + end + + def fetch_changesets + scm_info = scm.info + if scm_info + # latest revision found in database + db_revision = latest_changeset ? latest_changeset.revision.to_i : 0 + # latest revision in the repository + scm_revision = scm_info.lastrev.identifier.to_i + if db_revision < scm_revision + logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? + identifier_from = db_revision + 1 + while (identifier_from <= scm_revision) + # loads changesets by batches of 200 + identifier_to = [identifier_from + 199, scm_revision].min + revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true) + revisions.reverse_each do |revision| + transaction do + changeset = Changeset.create(:repository => self, + :revision => revision.identifier, + :committer => revision.author, + :committed_on => revision.time, + :comments => revision.message) + + revision.paths.each do |change| + changeset.create_change(change) + end unless changeset.new_record? + end + end unless revisions.nil? + identifier_from = identifier_to + 1 + end + end + end + end + + private + + # Returns the relative url of the repository + # Eg: root_url = file:///var/svn/foo + # url = file:///var/svn/foo/bar + # => returns /bar + def relative_url + @relative_url ||= url.gsub(Regexp.new("^#{Regexp.escape(root_url || scm.root_url)}", Regexp::IGNORECASE), '') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/03803ec02697cfe8f89b59eb47e58dc9312a0502.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/03803ec02697cfe8f89b59eb47e58dc9312a0502.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,156 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::UnifiedDiffTest < ActiveSupport::TestCase + + def setup + end + + def test_subversion_diff + diff = Redmine::UnifiedDiff.new(read_diff_fixture('subversion.diff')) + # number of files + assert_equal 4, diff.size + assert diff.detect {|file| file.file_name =~ %r{^config/settings.yml}} + end + + def test_truncate_diff + diff = Redmine::UnifiedDiff.new(read_diff_fixture('subversion.diff'), :max_lines => 20) + assert_equal 2, diff.size + end + + def test_inline_partials + diff = Redmine::UnifiedDiff.new(read_diff_fixture('partials.diff')) + assert_equal 1, diff.size + diff = diff.first + assert_equal 43, diff.size + + assert_equal [51, -1], diff[0].offsets + assert_equal [51, -1], diff[1].offsets + assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', diff[0].html_line + assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing xx', diff[1].html_line + + assert_nil diff[2].offsets + assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[2].html_line + + assert_equal [0, -14], diff[3].offsets + assert_equal [0, -14], diff[4].offsets + assert_equal 'Ut sed auctor justo', diff[3].html_line + assert_equal 'xxx auctor justo', diff[4].html_line + + assert_equal [13, -19], diff[6].offsets + assert_equal [13, -19], diff[7].offsets + + assert_equal [24, -8], diff[9].offsets + assert_equal [24, -8], diff[10].offsets + + assert_equal [37, -1], diff[12].offsets + assert_equal [37, -1], diff[13].offsets + + assert_equal [0, -38], diff[15].offsets + assert_equal [0, -38], diff[16].offsets + end + + def test_side_by_side_partials + diff = Redmine::UnifiedDiff.new(read_diff_fixture('partials.diff'), :type => 'sbs') + assert_equal 1, diff.size + diff = diff.first + assert_equal 32, diff.size + + assert_equal [51, -1], diff[0].offsets + assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', diff[0].html_line_left + assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing xx', diff[0].html_line_right + + assert_nil diff[1].offsets + assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[1].html_line_left + assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[1].html_line_right + + assert_equal [0, -14], diff[2].offsets + assert_equal 'Ut sed auctor justo', diff[2].html_line_left + assert_equal 'xxx auctor justo', diff[2].html_line_right + + assert_equal [13, -19], diff[4].offsets + assert_equal [24, -8], diff[6].offsets + assert_equal [37, -1], diff[8].offsets + assert_equal [0, -38], diff[10].offsets + + end + + def test_line_starting_with_dashes + diff = Redmine::UnifiedDiff.new(<<-DIFF +--- old.txt Wed Nov 11 14:24:58 2009 ++++ new.txt Wed Nov 11 14:25:02 2009 +@@ -1,8 +1,4 @@ +-Lines that starts with dashes: +- +------------------------- +--- file.c +------------------------- ++A line that starts with dashes: + + and removed. + +@@ -23,4 +19,4 @@ + + + +-Another chunk of change ++Another chunk of changes + +DIFF + ) + assert_equal 1, diff.size + end + + def test_one_line_new_files + diff = Redmine::UnifiedDiff.new(<<-DIFF +diff -r 000000000000 -r ea98b14f75f0 README1 +--- /dev/null ++++ b/README1 +@@ -0,0 +1,1 @@ ++test1 +diff -r 000000000000 -r ea98b14f75f0 README2 +--- /dev/null ++++ b/README2 +@@ -0,0 +1,1 @@ ++test2 +diff -r 000000000000 -r ea98b14f75f0 README3 +--- /dev/null ++++ b/README3 +@@ -0,0 +1,3 @@ ++test4 ++test5 ++test6 +diff -r 000000000000 -r ea98b14f75f0 README4 +--- /dev/null ++++ b/README4 +@@ -0,0 +1,3 @@ ++test4 ++test5 ++test6 +DIFF + ) + assert_equal 4, diff.size + end + + private + + def read_diff_fixture(filename) + File.new(File.join(File.dirname(__FILE__), '/../../../fixtures/diffs', filename)).read + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/038dcd875902d442a622bf1915b8e83469f95936.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/038dcd875902d442a622bf1915b8e83469f95936.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,177 @@ +require File.dirname(__FILE__) + '/helper' +require File.dirname(__FILE__) + '/../init' + +class PaginationTest < ActiveRecordTestCase + fixtures :topics, :replies, :developers, :projects, :developers_projects + + class PaginationController < ActionController::Base + if respond_to? :view_paths= + self.view_paths = [ "#{File.dirname(__FILE__)}/../fixtures/" ] + else + self.template_root = [ "#{File.dirname(__FILE__)}/../fixtures/" ] + end + + def simple_paginate + @topic_pages, @topics = paginate(:topics) + render :nothing => true + end + + def paginate_with_per_page + @topic_pages, @topics = paginate(:topics, :per_page => 1) + render :nothing => true + end + + def paginate_with_order + @topic_pages, @topics = paginate(:topics, :order => 'created_at asc') + render :nothing => true + end + + def paginate_with_order_by + @topic_pages, @topics = paginate(:topics, :order_by => 'created_at asc') + render :nothing => true + end + + def paginate_with_include_and_order + @topic_pages, @topics = paginate(:topics, :include => :replies, :order => 'replies.created_at asc, topics.created_at asc') + render :nothing => true + end + + def paginate_with_conditions + @topic_pages, @topics = paginate(:topics, :conditions => ["created_at > ?", 30.minutes.ago]) + render :nothing => true + end + + def paginate_with_class_name + @developer_pages, @developers = paginate(:developers, :class_name => "DeVeLoPeR") + render :nothing => true + end + + def paginate_with_singular_name + @developer_pages, @developers = paginate() + render :nothing => true + end + + def paginate_with_joins + @developer_pages, @developers = paginate(:developers, + :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id', + :conditions => 'project_id=1') + render :nothing => true + end + + def paginate_with_join + @developer_pages, @developers = paginate(:developers, + :join => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id', + :conditions => 'project_id=1') + render :nothing => true + end + + def paginate_with_join_and_count + @developer_pages, @developers = paginate(:developers, + :join => 'd LEFT JOIN developers_projects ON d.id = developers_projects.developer_id', + :conditions => 'project_id=1', + :count => "d.id") + render :nothing => true + end + + def paginate_with_join_and_group + @developer_pages, @developers = paginate(:developers, + :join => 'INNER JOIN developers_projects ON developers.id = developers_projects.developer_id', + :group => 'developers.id') + render :nothing => true + end + + def rescue_errors(e) raise e end + + def rescue_action(e) raise end + + end + + def setup + @controller = PaginationController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + super + end + + # Single Action Pagination Tests + + def test_simple_paginate + get :simple_paginate + assert_equal 1, assigns(:topic_pages).page_count + assert_equal 3, assigns(:topics).size + end + + def test_paginate_with_per_page + get :paginate_with_per_page + assert_equal 1, assigns(:topics).size + assert_equal 3, assigns(:topic_pages).page_count + end + + def test_paginate_with_order + get :paginate_with_order + expected = [topics(:futurama), + topics(:harvey_birdman), + topics(:rails)] + assert_equal expected, assigns(:topics) + assert_equal 1, assigns(:topic_pages).page_count + end + + def test_paginate_with_order_by + get :paginate_with_order + expected = assigns(:topics) + get :paginate_with_order_by + assert_equal expected, assigns(:topics) + assert_equal 1, assigns(:topic_pages).page_count + end + + def test_paginate_with_conditions + get :paginate_with_conditions + expected = [topics(:rails)] + assert_equal expected, assigns(:topics) + assert_equal 1, assigns(:topic_pages).page_count + end + + def test_paginate_with_class_name + get :paginate_with_class_name + + assert assigns(:developers).size > 0 + assert_equal DeVeLoPeR, assigns(:developers).first.class + end + + def test_paginate_with_joins + get :paginate_with_joins + assert_equal 2, assigns(:developers).size + developer_names = assigns(:developers).map { |d| d.name } + assert developer_names.include?('David') + assert developer_names.include?('Jamis') + end + + def test_paginate_with_join_and_conditions + get :paginate_with_joins + expected = assigns(:developers) + get :paginate_with_join + assert_equal expected, assigns(:developers) + end + + def test_paginate_with_join_and_count + get :paginate_with_joins + expected = assigns(:developers) + get :paginate_with_join_and_count + assert_equal expected, assigns(:developers) + end + + def test_paginate_with_include_and_order + get :paginate_with_include_and_order + expected = Topic.find(:all, :include => 'replies', :order => 'replies.created_at asc, topics.created_at asc', :limit => 10) + assert_equal expected, assigns(:topics) + end + + def test_paginate_with_join_and_group + get :paginate_with_join_and_group + assert_equal 2, assigns(:developers).size + assert_equal 2, assigns(:developer_pages).item_count + developer_names = assigns(:developers).map { |d| d.name } + assert developer_names.include?('David') + assert developer_names.include?('Jamis') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/03b7cab2c78e7db2be70be489d305cf0f31baf79.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/03/03b7cab2c78e7db2be70be489d305cf0f31baf79.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,68 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Tracker < ActiveRecord::Base + before_destroy :check_integrity + has_many :issues + has_many :workflows, :dependent => :delete_all do + def copy(source_tracker) + Workflow.copy(source_tracker, nil, proxy_owner, nil) + end + end + + has_and_belongs_to_many :projects + has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id' + acts_as_list + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 30 + + named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} + + def to_s; name end + + def <=>(tracker) + name <=> tracker.name + end + + def self.all + find(:all, :order => 'position') + end + + # Returns an array of IssueStatus that are used + # in the tracker's workflows + def issue_statuses + if @issue_statuses + return @issue_statuses + elsif new_record? + return [] + end + + ids = Workflow. + connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{Workflow.table_name} WHERE tracker_id = #{id}"). + flatten. + uniq + + @issue_statuses = IssueStatus.find_all_by_id(ids).sort + end + +private + def check_integrity + raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id]) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/03/03e302ac3faa55d3e2da81847b693122c9f0c6e8.svn-base Binary file .svn/pristine/03/03e302ac3faa55d3e2da81847b693122c9f0c6e8.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/04389a310fa0201bca85505cd492c1ab5010af2e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/04389a310fa0201bca85505cd492c1ab5010af2e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 DocumentsHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/045cde29760447c94f70470e61f71e26e3da5dec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/045cde29760447c94f70470e61f71e26e3da5dec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each { |file| require(file) } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/046e745fdf9ac7fc7dec5d1b9e47c29909c11738.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/046e745fdf9ac7fc7dec5d1b9e47c29909c11738.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,97 @@ +.jstEditor { + padding-left: 0px; +} +.jstEditor textarea, .jstEditor iframe { + margin: 0; +} + +.jstHandle { + height: 10px; + font-size: 0.1em; + cursor: s-resize; + /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/ +} + +.jstElements { + padding: 3px 3px 3px 0; +} + +.jstElements button { + margin-right: 4px; + width : 24px; + height: 24px; + padding: 4px; + border-style: solid; + border-width: 1px; + border-color: #ddd; + background-color : #f7f7f7; + background-position : 50% 50%; + background-repeat: no-repeat; +} +.jstElements button:hover { + border-color: #bbb; + background-color: #e5e5e5; +} +.jstElements button span { + display : none; +} +.jstElements span { + display : inline; +} + +.jstSpacer { + width : 0px; + font-size: 1px; + margin-right: 6px; +} + +.jstElements .help { float: right; margin-right: 0.5em; padding-top: 8px; font-size: 0.9em; } +.jstElements .help a {padding: 2px 0 2px 20px; background: url(../images/help.png) no-repeat 0 50%;} + +/* Buttons +-------------------------------------------------------- */ +.jstb_strong { + background-image: url(../images/jstoolbar/bt_strong.png); +} +.jstb_em { + background-image: url(../images/jstoolbar/bt_em.png); +} +.jstb_ins { + background-image: url(../images/jstoolbar/bt_ins.png); +} +.jstb_del { + background-image: url(../images/jstoolbar/bt_del.png); +} +.jstb_code { + background-image: url(../images/jstoolbar/bt_code.png); +} +.jstb_h1 { + background-image: url(../images/jstoolbar/bt_h1.png); +} +.jstb_h2 { + background-image: url(../images/jstoolbar/bt_h2.png); +} +.jstb_h3 { + background-image: url(../images/jstoolbar/bt_h3.png); +} +.jstb_ul { + background-image: url(../images/jstoolbar/bt_ul.png); +} +.jstb_ol { + background-image: url(../images/jstoolbar/bt_ol.png); +} +.jstb_bq { + background-image: url(../images/jstoolbar/bt_bq.png); +} +.jstb_unbq { + background-image: url(../images/jstoolbar/bt_bq_remove.png); +} +.jstb_pre { + background-image: url(../images/jstoolbar/bt_pre.png); +} +.jstb_link { + background-image: url(../images/jstoolbar/bt_link.png); +} +.jstb_img { + background-image: url(../images/jstoolbar/bt_img.png); +} diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/0498f22fd69f96a75cd1f1df26f11c6b9f18a2ee.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/0498f22fd69f96a75cd1f1df26f11c6b9f18a2ee.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/test_helper' + +class StatusTest < Test::Unit::TestCase + include OpenIdAuthentication + + def test_state_conditional + assert Result[:missing].missing? + assert Result[:missing].unsuccessful? + assert !Result[:missing].successful? + + assert Result[:successful].successful? + assert !Result[:successful].unsuccessful? + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/04bafe6e6b402a0f59316ed78a7582dc8951a46f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/04bafe6e6b402a0f59316ed78a7582dc8951a46f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +
+ <%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') + ' |' if User.current.allowed_to?(:add_project, nil, :global => true) %> + <%= link_to(l(:label_issue_view_all), { :controller => 'issues' }) + ' |' if User.current.allowed_to?(:view_issues, nil, :global => true) %> + <%= link_to(l(:label_overall_spent_time), { :controller => 'time_entries' }) + ' |' if User.current.allowed_to?(:view_time_entries, nil, :global => true) %> + <%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%> +
+ +

<%=l(:label_project_plural)%>

+ +<%= render_project_hierarchy(@projects)%> + +<% if User.current.logged? %> +

+<%= l(:label_my_projects) %> +

+<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title(l(:label_project_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/04bd6b422ff086dcb557f90d7ba79b9553b3ae87.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/04bd6b422ff086dcb557f90d7ba79b9553b3ae87.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,71 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + class Ruby + + class StringState < Struct.new :type, :interpreted, :delim, :heredoc, + :opening_paren, :paren_depth, :pattern, :next_state # :nodoc: all + + CLOSING_PAREN = Hash[ *%w[ + ( ) + [ ] + < > + { } + ] ].each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with << + + STRING_PATTERN = Hash.new do |h, k| + delim, interpreted = *k + # delim = delim.dup # workaround for old Ruby + delim_pattern = Regexp.escape(delim) + if closing_paren = CLOSING_PAREN[delim] + delim_pattern << Regexp.escape(closing_paren) + end + delim_pattern << '\\\\' unless delim == '\\' + + # special_escapes = + # case interpreted + # when :regexp_symbols + # '| [|?*+(){}\[\].^$]' + # end + + h[k] = + if interpreted && delim != '#' + / (?= [#{delim_pattern}] | \# [{$@] ) /mx + else + / (?= [#{delim_pattern}] ) /mx + end + end + + def initialize kind, interpreted, delim, heredoc = false + if heredoc + pattern = heredoc_pattern delim, interpreted, heredoc == :indented + delim = nil + else + pattern = STRING_PATTERN[ [delim, interpreted] ] + if closing_paren = CLOSING_PAREN[delim] + opening_paren = delim + delim = closing_paren + paren_depth = 1 + end + end + super kind, interpreted, delim, heredoc, opening_paren, paren_depth, pattern, :initial + end + + def heredoc_pattern delim, interpreted, indented + # delim = delim.dup # workaround for old Ruby + delim_pattern = Regexp.escape(delim) + delim_pattern = / (?:\A|\n) #{ '(?>[ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x + if interpreted + / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc + else + / (?= #{delim_pattern}() | \\ ) /mx + end + end + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/04/04fbda284b00bec052d898fc58aac289855e9000.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/04/04fbda284b00bec052d898fc58aac289855e9000.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +class Wiki < ActiveRecord::Base + generator_for :start_page => 'Start' + generator_for :project, :method => :generate_project + + def self.generate_project + Project.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/05366a1767d0cebdb112d7b0a839d8704040e98a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/05366a1767d0cebdb112d7b0a839d8704040e98a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby +# +# You may specify the path to the FastCGI crash log (a log of unhandled +# exceptions which forced the FastCGI instance to exit, great for debugging) +# and the number of requests to process before running garbage collection. +# +# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log +# and the GC period is nil (turned off). A reasonable number of requests +# could range from 10-100 depending on the memory footprint of your app. +# +# Example: +# # Default log path, normal GC behavior. +# RailsFCGIHandler.process! +# +# # Default log path, 50 requests between GC. +# RailsFCGIHandler.process! nil, 50 +# +# # Custom log path, normal GC behavior. +# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log' +# +require File.dirname(__FILE__) + "/../config/environment" +require 'fcgi_handler' + +RailsFCGIHandler.process! diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/053c71b830593b5a759e13f9676269b7c9bf4645.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/053c71b830593b5a759e13f9676269b7c9bf4645.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,47 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssueCategory < ActiveRecord::Base + belongs_to :project + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' + has_many :issues, :foreign_key => 'category_id', :dependent => :nullify + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + validates_length_of :name, :maximum => 30 + + attr_protected :project_id + + named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} + + alias :destroy_without_reassign :destroy + + # Destroy the category + # If a category is specified, issues are reassigned to this category + def destroy(reassign_to = nil) + if reassign_to && reassign_to.is_a?(IssueCategory) && reassign_to.project == self.project + Issue.update_all("category_id = #{reassign_to.id}", "category_id = #{id}") + end + destroy_without_reassign + end + + def <=>(category) + name <=> category.name + end + + def to_s; name end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/053ccbadc6aeeda1db20f88d64520439b568415d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/053ccbadc6aeeda1db20f88d64520439b568415d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 AccountHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/058be0b3a53e81bfbd2f18f23f7014355fe7cd0a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/058be0b3a53e81bfbd2f18f23f7014355fe7cd0a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,150 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class MemberTest < ActiveSupport::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :groups_users, + :watchers, + :journals, :journal_details, + :messages, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :boards + + def setup + @jsmith = Member.find(1) + end + + def test_create + member = Member.new(:project_id => 1, :user_id => 4, :role_ids => [1, 2]) + assert member.save + member.reload + + assert_equal 2, member.roles.size + assert_equal Role.find(1), member.roles.sort.first + end + + def test_update + assert_equal "eCookbook", @jsmith.project.name + assert_equal "Manager", @jsmith.roles.first.name + assert_equal "jsmith", @jsmith.user.login + + @jsmith.mail_notification = !@jsmith.mail_notification + assert @jsmith.save + end + + def test_update_roles + assert_equal 1, @jsmith.roles.size + @jsmith.role_ids = [1, 2] + assert @jsmith.save + assert_equal 2, @jsmith.reload.roles.size + end + + def test_validate + member = Member.new(:project_id => 1, :user_id => 2, :role_ids => [2]) + # same use can't have more than one membership for a project + assert !member.save + + member = Member.new(:project_id => 1, :user_id => 2, :role_ids => []) + # must have one role at least + assert !member.save + end + + def test_destroy + assert_difference 'Member.count', -1 do + assert_difference 'MemberRole.count', -1 do + @jsmith.destroy + end + end + + assert_raise(ActiveRecord::RecordNotFound) { Member.find(@jsmith.id) } + end + + context "removing permissions" do + setup do + Watcher.delete_all("user_id = 9") + user = User.find(9) + # public + Watcher.create!(:watchable => Issue.find(1), :user => user) + # private + Watcher.create!(:watchable => Issue.find(4), :user => user) + Watcher.create!(:watchable => Message.find(7), :user => user) + Watcher.create!(:watchable => Wiki.find(2), :user => user) + Watcher.create!(:watchable => WikiPage.find(3), :user => user) + end + + context "of user" do + setup do + @member = Member.create!(:project => Project.find(2), :principal => User.find(9), :role_ids => [1, 2]) + end + + context "by deleting membership" do + should "prune watchers" do + assert_difference 'Watcher.count', -4 do + @member.destroy + end + end + end + + context "by updating roles" do + should "prune watchers" do + Role.find(2).remove_permission! :view_wiki_pages + member = Member.first(:order => 'id desc') + assert_difference 'Watcher.count', -2 do + member.role_ids = [2] + member.save + end + assert !Message.find(7).watched_by?(@user) + end + end + end + + context "of group" do + setup do + group = Group.find(10) + @member = Member.create!(:project => Project.find(2), :principal => group, :role_ids => [1, 2]) + group.users << User.find(9) + end + + context "by deleting membership" do + should "prune watchers" do + assert_difference 'Watcher.count', -4 do + @member.destroy + end + end + end + + context "by updating roles" do + should "prune watchers" do + Role.find(2).remove_permission! :view_wiki_pages + assert_difference 'Watcher.count', -2 do + @member.role_ids = [2] + @member.save + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/05d53773172688f95b7f90e6ffa69f1cbdf7504b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/05d53773172688f95b7f90e6ffa69f1cbdf7504b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,97 @@ +
+ « + <% unless @changeset.previous.nil? -%> + <%= link_to_revision(@changeset.previous, @project, :text => l(:label_previous)) %> + <% else -%> + <%= l(:label_previous) %> + <% end -%> +| + <% unless @changeset.next.nil? -%> + <%= link_to_revision(@changeset.next, @project, :text => l(:label_next)) %> + <% else -%> + <%= l(:label_next) %> + <% end -%> + »  + + <% form_tag({:controller => 'repositories', + :action => 'revision', + :id => @project, + :rev => nil}, + :method => :get) do %> + <%= text_field_tag 'rev', @rev, :size => 8 %> + <%= submit_tag 'OK', :name => nil %> + <% end %> +
+ +

<%= l(:label_revision) %> <%= format_revision(@changeset) %>

+ + + <% if @changeset.scmid %> + + + + <% end %> + <% unless @changeset.parents.blank? %> + + + + + <% end %> + <% unless @changeset.children.blank? %> + + + + + <% end %> +
ID<%= h(@changeset.scmid) %>
<%= l(:label_parent_revision) %> + <%= @changeset.parents.collect{ + |p| link_to_revision(p, @project, :text => format_revision(p)) + }.join(", ") %> +
<%= l(:label_child_revision) %> + <%= @changeset.children.collect{ + |p| link_to_revision(p, @project, :text => format_revision(p)) + }.join(", ") %> +
+

+ +<%= authoring(@changeset.committed_on, @changeset.author) %> + +

+ +<%= textilizable @changeset.comments %> + +<% if @changeset.issues.visible.any? %> +

<%= l(:label_related_issues) %>

+
    +<% @changeset.issues.visible.each do |issue| %> +
  • <%= link_to_issue issue %>
  • +<% end %> +
+<% end %> + +<% if User.current.allowed_to?(:browse_repository, @project) %> +

<%= l(:label_attachment_plural) %>

+
    +
  • <%= l(:label_added) %>
  • +
  • <%= l(:label_modified) %>
  • +
  • <%= l(:label_copied) %>
  • +
  • <%= l(:label_renamed) %>
  • +
  • <%= l(:label_deleted) %>
  • +
+ +

<%= link_to(l(:label_view_diff), + :action => 'diff', + :id => @project, + :path => "", + :rev => @changeset.identifier) if @changeset.changes.any? %>

+ +
+<%= render_changeset_changes %> +
+<% end %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title("#{l(:label_revision)} #{format_revision(@changeset)}") -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/05e06f37663175a7e86aab01c766edf25f24a007.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/05e06f37663175a7e86aab01c766edf25f24a007.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +class CreateWikiContents < ActiveRecord::Migration + def self.up + create_table :wiki_contents do |t| + t.column :page_id, :integer, :null => false + t.column :author_id, :integer + t.column :text, :text + t.column :comments, :string, :limit => 255, :default => "" + t.column :updated_on, :datetime, :null => false + t.column :version, :integer, :null => false + end + add_index :wiki_contents, :page_id, :name => :wiki_contents_page_id + + create_table :wiki_content_versions do |t| + t.column :wiki_content_id, :integer, :null => false + t.column :page_id, :integer, :null => false + t.column :author_id, :integer + t.column :data, :binary + t.column :compression, :string, :limit => 6, :default => "" + t.column :comments, :string, :limit => 255, :default => "" + t.column :updated_on, :datetime, :null => false + t.column :version, :integer, :null => false + end + add_index :wiki_content_versions, :wiki_content_id, :name => :wiki_content_versions_wcid + end + + def self.down + drop_table :wiki_contents + drop_table :wiki_content_versions + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/05/05f81f90a3570490e6ea8a94e643c12e2ec9cbe3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/05/05f81f90a3570490e6ea8a94e643c12e2ec9cbe3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,879 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Project < ActiveRecord::Base + include Redmine::SafeAttributes + + # Project statuses + STATUS_ACTIVE = 1 + STATUS_ARCHIVED = 9 + + # Maximum length for project identifiers + IDENTIFIER_MAX_LENGTH = 100 + + # Specific overidden Activities + has_many :time_entry_activities + has_many :members, :include => [:user, :roles], :conditions => "#{User.table_name}.type='User' AND #{User.table_name}.status=#{User::STATUS_ACTIVE}" + has_many :memberships, :class_name => 'Member' + has_many :member_principals, :class_name => 'Member', + :include => :principal, + :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{User::STATUS_ACTIVE})" + has_many :users, :through => :members + has_many :principals, :through => :member_principals, :source => :principal + + has_many :enabled_modules, :dependent => :delete_all + has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" + has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker] + has_many :issue_changes, :through => :issues, :source => :journals + has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC" + has_many :time_entries, :dependent => :delete_all + has_many :queries, :dependent => :delete_all + has_many :documents, :dependent => :destroy + has_many :news, :dependent => :destroy, :include => :author + has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name" + has_many :boards, :dependent => :destroy, :order => "position ASC" + has_one :repository, :dependent => :destroy + has_many :changesets, :through => :repository + has_one :wiki, :dependent => :destroy + # Custom field for the project issues + has_and_belongs_to_many :issue_custom_fields, + :class_name => 'IssueCustomField', + :order => "#{CustomField.table_name}.position", + :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", + :association_foreign_key => 'custom_field_id' + + acts_as_nested_set :order => 'name', :dependent => :destroy + acts_as_attachable :view_permission => :view_files, + :delete_permission => :manage_files + + acts_as_customizable + acts_as_searchable :columns => ['name', 'identifier', 'description'], :project_key => 'id', :permission => nil + acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"}, + :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o}}, + :author => nil + + attr_protected :status + + validates_presence_of :name, :identifier + validates_uniqueness_of :identifier + validates_associated :repository, :wiki + validates_length_of :name, :maximum => 255 + validates_length_of :homepage, :maximum => 255 + validates_length_of :identifier, :in => 1..IDENTIFIER_MAX_LENGTH + # donwcase letters, digits, dashes but not digits only + validates_format_of :identifier, :with => /^(?!\d+$)[a-z0-9\-]*$/, :if => Proc.new { |p| p.identifier_changed? } + # reserved words + validates_exclusion_of :identifier, :in => %w( new ) + + before_destroy :delete_all_members + + named_scope :has_module, lambda { |mod| { :conditions => ["#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s] } } + named_scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"} + named_scope :all_public, { :conditions => { :is_public => true } } + named_scope :visible, lambda {|*args| {:conditions => Project.visible_condition(args.shift || User.current, *args) }} + + def initialize(attributes = nil) + super + + initialized = (attributes || {}).stringify_keys + if !initialized.key?('identifier') && Setting.sequential_project_identifiers? + self.identifier = Project.next_identifier + end + if !initialized.key?('is_public') + self.is_public = Setting.default_projects_public? + end + if !initialized.key?('enabled_module_names') + self.enabled_module_names = Setting.default_projects_modules + end + if !initialized.key?('trackers') && !initialized.key?('tracker_ids') + self.trackers = Tracker.all + end + end + + def identifier=(identifier) + super unless identifier_frozen? + end + + def identifier_frozen? + errors[:identifier].nil? && !(new_record? || identifier.blank?) + end + + # returns latest created projects + # non public projects will be returned only if user is a member of those + def self.latest(user=nil, count=5) + visible(user).find(:all, :limit => count, :order => "created_on DESC") + end + + # Returns true if the project is visible to +user+ or to the current user. + def visible?(user=User.current) + user.allowed_to?(:view_project, self) + end + + # Returns a SQL conditions string used to find all projects visible by the specified user. + # + # Examples: + # Project.visible_condition(admin) => "projects.status = 1" + # Project.visible_condition(normal_user) => "((projects.status = 1) AND (projects.is_public = 1 OR projects.id IN (1,3,4)))" + # Project.visible_condition(anonymous) => "((projects.status = 1) AND (projects.is_public = 1))" + def self.visible_condition(user, options={}) + allowed_to_condition(user, :view_project, options) + end + + # Returns a SQL conditions string used to find all projects for which +user+ has the given +permission+ + # + # Valid options: + # * :project => limit the condition to project + # * :with_subprojects => limit the condition to project and its subprojects + # * :member => limit the condition to the user projects + def self.allowed_to_condition(user, permission, options={}) + base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" + if perm = Redmine::AccessControl.permission(permission) + unless perm.project_module.nil? + # If the permission belongs to a project module, make sure the module is enabled + base_statement << " AND #{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.project_module}')" + end + end + if options[:project] + project_statement = "#{Project.table_name}.id = #{options[:project].id}" + project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects] + base_statement = "(#{project_statement}) AND (#{base_statement})" + end + + if user.admin? + base_statement + else + statement_by_role = {} + unless options[:member] + role = user.logged? ? Role.non_member : Role.anonymous + if role.allowed_to?(permission) + statement_by_role[role] = "#{Project.table_name}.is_public = #{connection.quoted_true}" + end + end + if user.logged? + user.projects_by_role.each do |role, projects| + if role.allowed_to?(permission) + statement_by_role[role] = "#{Project.table_name}.id IN (#{projects.collect(&:id).join(',')})" + end + end + end + if statement_by_role.empty? + "1=0" + else + if block_given? + statement_by_role.each do |role, statement| + if s = yield(role, user) + statement_by_role[role] = "(#{statement} AND (#{s}))" + end + end + end + "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))" + end + end + end + + # Returns the Systemwide and project specific activities + def activities(include_inactive=false) + if include_inactive + return all_activities + else + return active_activities + end + end + + # Will create a new Project specific Activity or update an existing one + # + # This will raise a ActiveRecord::Rollback if the TimeEntryActivity + # does not successfully save. + def update_or_create_time_entry_activity(id, activity_hash) + if activity_hash.respond_to?(:has_key?) && activity_hash.has_key?('parent_id') + self.create_time_entry_activity_if_needed(activity_hash) + else + activity = project.time_entry_activities.find_by_id(id.to_i) + activity.update_attributes(activity_hash) if activity + end + end + + # Create a new TimeEntryActivity if it overrides a system TimeEntryActivity + # + # This will raise a ActiveRecord::Rollback if the TimeEntryActivity + # does not successfully save. + def create_time_entry_activity_if_needed(activity) + if activity['parent_id'] + + parent_activity = TimeEntryActivity.find(activity['parent_id']) + activity['name'] = parent_activity.name + activity['position'] = parent_activity.position + + if Enumeration.overridding_change?(activity, parent_activity) + project_activity = self.time_entry_activities.create(activity) + + if project_activity.new_record? + raise ActiveRecord::Rollback, "Overridding TimeEntryActivity was not successfully saved" + else + self.time_entries.update_all("activity_id = #{project_activity.id}", ["activity_id = ?", parent_activity.id]) + end + end + end + end + + # Returns a :conditions SQL string that can be used to find the issues associated with this project. + # + # Examples: + # project.project_condition(true) => "(projects.id = 1 OR (projects.lft > 1 AND projects.rgt < 10))" + # project.project_condition(false) => "projects.id = 1" + def project_condition(with_subprojects) + cond = "#{Project.table_name}.id = #{id}" + cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects + cond + end + + def self.find(*args) + if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/) + project = find_by_identifier(*args) + raise ActiveRecord::RecordNotFound, "Couldn't find Project with identifier=#{args.first}" if project.nil? + project + else + super + end + end + + def to_param + # id is used for projects with a numeric identifier (compatibility) + @to_param ||= (identifier.to_s =~ %r{^\d*$} ? id : identifier) + end + + def active? + self.status == STATUS_ACTIVE + end + + def archived? + self.status == STATUS_ARCHIVED + end + + # Archives the project and its descendants + def archive + # Check that there is no issue of a non descendant project that is assigned + # to one of the project or descendant versions + v_ids = self_and_descendants.collect {|p| p.version_ids}.flatten + if v_ids.any? && Issue.find(:first, :include => :project, + :conditions => ["(#{Project.table_name}.lft < ? OR #{Project.table_name}.rgt > ?)" + + " AND #{Issue.table_name}.fixed_version_id IN (?)", lft, rgt, v_ids]) + return false + end + Project.transaction do + archive! + end + true + end + + # Unarchives the project + # All its ancestors must be active + def unarchive + return false if ancestors.detect {|a| !a.active?} + update_attribute :status, STATUS_ACTIVE + end + + # Returns an array of projects the project can be moved to + # by the current user + def allowed_parents + return @allowed_parents if @allowed_parents + @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects)) + @allowed_parents = @allowed_parents - self_and_descendants + if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?) + @allowed_parents << nil + end + unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent) + @allowed_parents << parent + end + @allowed_parents + end + + # Sets the parent of the project with authorization check + def set_allowed_parent!(p) + unless p.nil? || p.is_a?(Project) + if p.to_s.blank? + p = nil + else + p = Project.find_by_id(p) + return false unless p + end + end + if p.nil? + if !new_record? && allowed_parents.empty? + return false + end + elsif !allowed_parents.include?(p) + return false + end + set_parent!(p) + end + + # Sets the parent of the project + # Argument can be either a Project, a String, a Fixnum or nil + def set_parent!(p) + unless p.nil? || p.is_a?(Project) + if p.to_s.blank? + p = nil + else + p = Project.find_by_id(p) + return false unless p + end + end + if p == parent && !p.nil? + # Nothing to do + true + elsif p.nil? || (p.active? && move_possible?(p)) + # Insert the project so that target's children or root projects stay alphabetically sorted + sibs = (p.nil? ? self.class.roots : p.children) + to_be_inserted_before = sibs.detect {|c| c.name.to_s.downcase > name.to_s.downcase } + if to_be_inserted_before + move_to_left_of(to_be_inserted_before) + elsif p.nil? + if sibs.empty? + # move_to_root adds the project in first (ie. left) position + move_to_root + else + move_to_right_of(sibs.last) unless self == sibs.last + end + else + # move_to_child_of adds the project in last (ie.right) position + move_to_child_of(p) + end + Issue.update_versions_from_hierarchy_change(self) + true + else + # Can not move to the given target + false + end + end + + # Returns an array of the trackers used by the project and its active sub projects + def rolled_up_trackers + @rolled_up_trackers ||= + Tracker.find(:all, :joins => :projects, + :select => "DISTINCT #{Tracker.table_name}.*", + :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt], + :order => "#{Tracker.table_name}.position") + end + + # Closes open and locked project versions that are completed + def close_completed_versions + Version.transaction do + versions.find(:all, :conditions => {:status => %w(open locked)}).each do |version| + if version.completed? + version.update_attribute(:status, 'closed') + end + end + end + end + + # Returns a scope of the Versions on subprojects + def rolled_up_versions + @rolled_up_versions ||= + Version.scoped(:include => :project, + :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt]) + end + + # Returns a scope of the Versions used by the project + def shared_versions + @shared_versions ||= begin + r = root? ? self : root + Version.scoped(:include => :project, + :conditions => "#{Project.table_name}.id = #{id}" + + " OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" + + " #{Version.table_name}.sharing = 'system'" + + " OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" + + " OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" + + " OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{Version.table_name}.sharing = 'hierarchy')" + + "))") + end + end + + # Returns a hash of project users grouped by role + def users_by_role + members.find(:all, :include => [:user, :roles]).inject({}) do |h, m| + m.roles.each do |r| + h[r] ||= [] + h[r] << m.user + end + h + end + end + + # Deletes all project's members + def delete_all_members + me, mr = Member.table_name, MemberRole.table_name + connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})") + Member.delete_all(['project_id = ?', id]) + end + + # Users/groups issues can be assigned to + def assignable_users + assignable = Setting.issue_group_assignment? ? member_principals : members + assignable.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.principal}.sort + end + + # Returns the mail adresses of users that should be always notified on project events + def recipients + notified_users.collect {|user| user.mail} + end + + # Returns the users that should be notified on project events + def notified_users + # TODO: User part should be extracted to User#notify_about? + members.select {|m| m.mail_notification? || m.user.mail_notification == 'all'}.collect {|m| m.user} + end + + # Returns an array of all custom fields enabled for project issues + # (explictly associated custom fields and custom fields enabled for all projects) + def all_issue_custom_fields + @all_issue_custom_fields ||= (IssueCustomField.for_all + issue_custom_fields).uniq.sort + end + + # Returns an array of all custom fields enabled for project time entries + # (explictly associated custom fields and custom fields enabled for all projects) + def all_time_entry_custom_fields + @all_time_entry_custom_fields ||= (TimeEntryCustomField.for_all + time_entry_custom_fields).uniq.sort + end + + def project + self + end + + def <=>(project) + name.downcase <=> project.name.downcase + end + + def to_s + name + end + + # Returns a short description of the projects (first lines) + def short_description(length = 255) + description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description + end + + def css_classes + s = 'project' + s << ' root' if root? + s << ' child' if child? + s << (leaf? ? ' leaf' : ' parent') + s + end + + # The earliest start date of a project, based on it's issues and versions + def start_date + [ + issues.minimum('start_date'), + shared_versions.collect(&:effective_date), + shared_versions.collect(&:start_date) + ].flatten.compact.min + end + + # The latest due date of an issue or version + def due_date + [ + issues.maximum('due_date'), + shared_versions.collect(&:effective_date), + shared_versions.collect {|v| v.fixed_issues.maximum('due_date')} + ].flatten.compact.max + end + + def overdue? + active? && !due_date.nil? && (due_date < Date.today) + end + + # Returns the percent completed for this project, based on the + # progress on it's versions. + def completed_percent(options={:include_subprojects => false}) + if options.delete(:include_subprojects) + total = self_and_descendants.collect(&:completed_percent).sum + + total / self_and_descendants.count + else + if versions.count > 0 + total = versions.collect(&:completed_pourcent).sum + + total / versions.count + else + 100 + end + end + end + + # Return true if this project is allowed to do the specified action. + # action can be: + # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') + # * a permission Symbol (eg. :edit_project) + def allows_to?(action) + if action.is_a? Hash + allowed_actions.include? "#{action[:controller]}/#{action[:action]}" + else + allowed_permissions.include? action + end + end + + def module_enabled?(module_name) + module_name = module_name.to_s + enabled_modules.detect {|m| m.name == module_name} + end + + def enabled_module_names=(module_names) + if module_names && module_names.is_a?(Array) + module_names = module_names.collect(&:to_s).reject(&:blank?) + self.enabled_modules = module_names.collect {|name| enabled_modules.detect {|mod| mod.name == name} || EnabledModule.new(:name => name)} + else + enabled_modules.clear + end + end + + # Returns an array of the enabled modules names + def enabled_module_names + enabled_modules.collect(&:name) + end + + # Enable a specific module + # + # Examples: + # project.enable_module!(:issue_tracking) + # project.enable_module!("issue_tracking") + def enable_module!(name) + enabled_modules << EnabledModule.new(:name => name.to_s) unless module_enabled?(name) + end + + # Disable a module if it exists + # + # Examples: + # project.disable_module!(:issue_tracking) + # project.disable_module!("issue_tracking") + # project.disable_module!(project.enabled_modules.first) + def disable_module!(target) + target = enabled_modules.detect{|mod| target.to_s == mod.name} unless enabled_modules.include?(target) + target.destroy unless target.blank? + end + + safe_attributes 'name', + 'description', + 'homepage', + 'is_public', + 'identifier', + 'custom_field_values', + 'custom_fields', + 'tracker_ids', + 'issue_custom_field_ids' + + safe_attributes 'enabled_module_names', + :if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) } + + # Returns an array of projects that are in this project's hierarchy + # + # Example: parents, children, siblings + def hierarchy + parents = project.self_and_ancestors || [] + descendants = project.descendants || [] + project_hierarchy = parents | descendants # Set union + end + + # Returns an auto-generated project identifier based on the last identifier used + def self.next_identifier + p = Project.find(:first, :order => 'created_on DESC') + p.nil? ? nil : p.identifier.to_s.succ + end + + # Copies and saves the Project instance based on the +project+. + # Duplicates the source project's: + # * Wiki + # * Versions + # * Categories + # * Issues + # * Members + # * Queries + # + # Accepts an +options+ argument to specify what to copy + # + # Examples: + # project.copy(1) # => copies everything + # project.copy(1, :only => 'members') # => copies members only + # project.copy(1, :only => ['members', 'versions']) # => copies members and versions + def copy(project, options={}) + project = project.is_a?(Project) ? project : Project.find(project) + + to_be_copied = %w(wiki versions issue_categories issues members queries boards) + to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil? + + Project.transaction do + if save + reload + to_be_copied.each do |name| + send "copy_#{name}", project + end + Redmine::Hook.call_hook(:model_project_copy_before_save, :source_project => project, :destination_project => self) + save + end + end + end + + + # Copies +project+ and returns the new instance. This will not save + # the copy + def self.copy_from(project) + begin + project = project.is_a?(Project) ? project : Project.find(project) + if project + # clear unique attributes + attributes = project.attributes.dup.except('id', 'name', 'identifier', 'status', 'parent_id', 'lft', 'rgt') + copy = Project.new(attributes) + copy.enabled_modules = project.enabled_modules + copy.trackers = project.trackers + copy.custom_values = project.custom_values.collect {|v| v.clone} + copy.issue_custom_fields = project.issue_custom_fields + return copy + else + return nil + end + rescue ActiveRecord::RecordNotFound + return nil + end + end + + # Yields the given block for each project with its level in the tree + def self.project_tree(projects, &block) + ancestors = [] + projects.sort_by(&:lft).each do |project| + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + end + yield project, ancestors.size + ancestors << project + end + end + + private + + # Copies wiki from +project+ + def copy_wiki(project) + # Check that the source project has a wiki first + unless project.wiki.nil? + self.wiki ||= Wiki.new + wiki.attributes = project.wiki.attributes.dup.except("id", "project_id") + wiki_pages_map = {} + project.wiki.pages.each do |page| + # Skip pages without content + next if page.content.nil? + new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on")) + new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id")) + new_wiki_page.content = new_wiki_content + wiki.pages << new_wiki_page + wiki_pages_map[page.id] = new_wiki_page + end + wiki.save + # Reproduce page hierarchy + project.wiki.pages.each do |page| + if page.parent_id && wiki_pages_map[page.id] + wiki_pages_map[page.id].parent = wiki_pages_map[page.parent_id] + wiki_pages_map[page.id].save + end + end + end + end + + # Copies versions from +project+ + def copy_versions(project) + project.versions.each do |version| + new_version = Version.new + new_version.attributes = version.attributes.dup.except("id", "project_id", "created_on", "updated_on") + self.versions << new_version + end + end + + # Copies issue categories from +project+ + def copy_issue_categories(project) + project.issue_categories.each do |issue_category| + new_issue_category = IssueCategory.new + new_issue_category.attributes = issue_category.attributes.dup.except("id", "project_id") + self.issue_categories << new_issue_category + end + end + + # Copies issues from +project+ + # Note: issues assigned to a closed version won't be copied due to validation rules + def copy_issues(project) + # Stores the source issue id as a key and the copied issues as the + # value. Used to map the two togeather for issue relations. + issues_map = {} + + # Get issues sorted by root_id, lft so that parent issues + # get copied before their children + project.issues.find(:all, :order => 'root_id, lft').each do |issue| + new_issue = Issue.new + new_issue.copy_from(issue) + new_issue.project = self + # Reassign fixed_versions by name, since names are unique per + # project and the versions for self are not yet saved + if issue.fixed_version + new_issue.fixed_version = self.versions.select {|v| v.name == issue.fixed_version.name}.first + end + # Reassign the category by name, since names are unique per + # project and the categories for self are not yet saved + if issue.category + new_issue.category = self.issue_categories.select {|c| c.name == issue.category.name}.first + end + # Parent issue + if issue.parent_id + if copied_parent = issues_map[issue.parent_id] + new_issue.parent_issue_id = copied_parent.id + end + end + + self.issues << new_issue + if new_issue.new_record? + logger.info "Project#copy_issues: issue ##{issue.id} could not be copied: #{new_issue.errors.full_messages}" if logger && logger.info + else + issues_map[issue.id] = new_issue unless new_issue.new_record? + end + end + + # Relations after in case issues related each other + project.issues.each do |issue| + new_issue = issues_map[issue.id] + unless new_issue + # Issue was not copied + next + end + + # Relations + issue.relations_from.each do |source_relation| + new_issue_relation = IssueRelation.new + new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id") + new_issue_relation.issue_to = issues_map[source_relation.issue_to_id] + if new_issue_relation.issue_to.nil? && Setting.cross_project_issue_relations? + new_issue_relation.issue_to = source_relation.issue_to + end + new_issue.relations_from << new_issue_relation + end + + issue.relations_to.each do |source_relation| + new_issue_relation = IssueRelation.new + new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id") + new_issue_relation.issue_from = issues_map[source_relation.issue_from_id] + if new_issue_relation.issue_from.nil? && Setting.cross_project_issue_relations? + new_issue_relation.issue_from = source_relation.issue_from + end + new_issue.relations_to << new_issue_relation + end + end + end + + # Copies members from +project+ + def copy_members(project) + # Copy users first, then groups to handle members with inherited and given roles + members_to_copy = [] + members_to_copy += project.memberships.select {|m| m.principal.is_a?(User)} + members_to_copy += project.memberships.select {|m| !m.principal.is_a?(User)} + + members_to_copy.each do |member| + new_member = Member.new + new_member.attributes = member.attributes.dup.except("id", "project_id", "created_on") + # only copy non inherited roles + # inherited roles will be added when copying the group membership + role_ids = member.member_roles.reject(&:inherited?).collect(&:role_id) + next if role_ids.empty? + new_member.role_ids = role_ids + new_member.project = self + self.members << new_member + end + end + + # Copies queries from +project+ + def copy_queries(project) + project.queries.each do |query| + new_query = Query.new + new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria") + new_query.sort_criteria = query.sort_criteria if query.sort_criteria + new_query.project = self + new_query.user_id = query.user_id + self.queries << new_query + end + end + + # Copies boards from +project+ + def copy_boards(project) + project.boards.each do |board| + new_board = Board.new + new_board.attributes = board.attributes.dup.except("id", "project_id", "topics_count", "messages_count", "last_message_id") + new_board.project = self + self.boards << new_board + end + end + + def allowed_permissions + @allowed_permissions ||= begin + module_names = enabled_modules.all(:select => :name).collect {|m| m.name} + Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name} + end + end + + def allowed_actions + @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten + end + + # Returns all the active Systemwide and project specific activities + def active_activities + overridden_activity_ids = self.time_entry_activities.collect(&:parent_id) + + if overridden_activity_ids.empty? + return TimeEntryActivity.shared.active + else + return system_activities_and_project_overrides + end + end + + # Returns all the Systemwide and project specific activities + # (inactive and active) + def all_activities + overridden_activity_ids = self.time_entry_activities.collect(&:parent_id) + + if overridden_activity_ids.empty? + return TimeEntryActivity.shared + else + return system_activities_and_project_overrides(true) + end + end + + # Returns the systemwide active activities merged with the project specific overrides + def system_activities_and_project_overrides(include_inactive=false) + if include_inactive + return TimeEntryActivity.shared. + find(:all, + :conditions => ["id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)]) + + self.time_entry_activities + else + return TimeEntryActivity.shared.active. + find(:all, + :conditions => ["id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)]) + + self.time_entry_activities.active + end + end + + # Archives subprojects recursively + def archive! + children.each do |subproject| + subproject.send :archive! + end + update_attribute :status, STATUS_ARCHIVED + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/061fdfd5800e4aa71d26012579cbbe6954d78738.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/061fdfd5800e4aa71d26012579cbbe6954d78738.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +# $Id: testem.rb 121 2006-05-15 18:36:24Z blackhedd $ +# +# + +require 'test/unit' +require 'tests/testber' +require 'tests/testldif' +require 'tests/testldap' +require 'tests/testpsw' +require 'tests/testfilter' + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/066092ac11c4635256b7145aa6a62ea7837d8a81.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/066092ac11c4635256b7145aa6a62ea7837d8a81.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,244 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8D U+00A8 dieresis +!8E U+02C7 caron +!8F U+00B8 cedilla +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!9D U+00AF macron +!9E U+02DB ogonek +!A0 U+00A0 space +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00D8 Oslash +!A9 U+00A9 copyright +!AA U+0156 Rcommaaccent +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00C6 AE +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00F8 oslash +!B9 U+00B9 onesuperior +!BA U+0157 rcommaaccent +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00E6 ae +!C0 U+0104 Aogonek +!C1 U+012E Iogonek +!C2 U+0100 Amacron +!C3 U+0106 Cacute +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+0118 Eogonek +!C7 U+0112 Emacron +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0179 Zacute +!CB U+0116 Edotaccent +!CC U+0122 Gcommaaccent +!CD U+0136 Kcommaaccent +!CE U+012A Imacron +!CF U+013B Lcommaaccent +!D0 U+0160 Scaron +!D1 U+0143 Nacute +!D2 U+0145 Ncommaaccent +!D3 U+00D3 Oacute +!D4 U+014C Omacron +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0172 Uogonek +!D9 U+0141 Lslash +!DA U+015A Sacute +!DB U+016A Umacron +!DC U+00DC Udieresis +!DD U+017B Zdotaccent +!DE U+017D Zcaron +!DF U+00DF germandbls +!E0 U+0105 aogonek +!E1 U+012F iogonek +!E2 U+0101 amacron +!E3 U+0107 cacute +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+0119 eogonek +!E7 U+0113 emacron +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+017A zacute +!EB U+0117 edotaccent +!EC U+0123 gcommaaccent +!ED U+0137 kcommaaccent +!EE U+012B imacron +!EF U+013C lcommaaccent +!F0 U+0161 scaron +!F1 U+0144 nacute +!F2 U+0146 ncommaaccent +!F3 U+00F3 oacute +!F4 U+014D omacron +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0173 uogonek +!F9 U+0142 lslash +!FA U+015B sacute +!FB U+016B umacron +!FC U+00FC udieresis +!FD U+017C zdotaccent +!FE U+017E zcaron +!FF U+02D9 dotaccent diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/066f939eced969c1eec65f1fe6ed629130668c67.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/066f939eced969c1eec65f1fe6ed629130668c67.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 IssueRelationsHelper + def collection_for_relation_type_select + values = IssueRelation::TYPES + values.keys.sort{|x,y| values[x][:order] <=> values[y][:order]}.collect{|k| [l(values[k][:name]), k]} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/067fc70eea1018fdccc706144d28aa0ea0565e34.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/067fc70eea1018fdccc706144d28aa0ea0565e34.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +--- +watchers_001: + watchable_type: Issue + watchable_id: 2 + user_id: 3 +watchers_002: + watchable_type: Message + watchable_id: 1 + user_id: 1 +watchers_003: + watchable_type: Issue + watchable_id: 2 + user_id: 1 + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/06877624ea5c77efe3b7e39b0f909eda6e25a4ec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/06877624ea5c77efe3b7e39b0f909eda6e25a4ec.svn-base Mon Feb 27 13:53:18 2012 +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. + + + Copyright (C) + + 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. + + , 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. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/068885f0c95ca2ed440e38b13dd95f7bb13f11dc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/068885f0c95ca2ed440e38b13dd95f7bb13f11dc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,59 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class CustomFieldTest < ActiveSupport::TestCase + fixtures :custom_fields + + def test_create + field = UserCustomField.new(:name => 'Money money money', :field_format => 'float') + assert field.save + end + + def test_regexp_validation + field = IssueCustomField.new(:name => 'regexp', :field_format => 'text', :regexp => '[a-z0-9') + assert !field.save + assert_equal I18n.t('activerecord.errors.messages.invalid'), field.errors.on(:regexp) + + field.regexp = '[a-z0-9]' + assert field.save + end + + def test_possible_values_should_accept_an_array + field = CustomField.new + field.possible_values = ["One value", ""] + assert_equal ["One value"], field.possible_values + end + + def test_possible_values_should_accept_a_string + field = CustomField.new + field.possible_values = "One value" + assert_equal ["One value"], field.possible_values + end + + def test_possible_values_should_accept_a_multiline_string + field = CustomField.new + field.possible_values = "One value\nAnd another one \r\n \n" + assert_equal ["One value", "And another one"], field.possible_values + end + + def test_destroy + field = CustomField.find(1) + assert field.destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/06aa9d1d0636535d93ef529aee72095eced64467.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/06aa9d1d0636535d93ef529aee72095eced64467.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
+ <%= render :partial => 'navigation' %> +
+ +

+ <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %> +

+ +

<%= render :partial => 'link_to_functions' %>

+ +<%= render_properties(@properties) %> + +<%= render(:partial => 'revisions', + :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %> + +<% html_title(l(:label_change_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/06b89fac956f5eaa8ae34a2daf2088c102b5cfb1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/06b89fac956f5eaa8ae34a2daf2088c102b5cfb1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,136 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Enumeration < ActiveRecord::Base + default_scope :order => "#{Enumeration.table_name}.position ASC" + + belongs_to :project + + acts_as_list :scope => 'type = \'#{type}\'' + acts_as_customizable + acts_as_tree :order => 'position ASC' + + before_destroy :check_integrity + before_save :check_default + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:type, :project_id] + validates_length_of :name, :maximum => 30 + + named_scope :shared, :conditions => { :project_id => nil } + named_scope :active, :conditions => { :active => true } + named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} + + def self.default + # Creates a fake default scope so Enumeration.default will check + # it's type. STI subclasses will automatically add their own + # types to the finder. + if self.descends_from_active_record? + find(:first, :conditions => { :is_default => true, :type => 'Enumeration' }) + else + # STI classes are + find(:first, :conditions => { :is_default => true }) + end + end + + # Overloaded on concrete classes + def option_name + nil + end + + def check_default + if is_default? && is_default_changed? + Enumeration.update_all("is_default = #{connection.quoted_false}", {:type => type}) + end + end + + # Overloaded on concrete classes + def objects_count + 0 + end + + def in_use? + self.objects_count != 0 + end + + # Is this enumeration overiding a system level enumeration? + def is_override? + !self.parent.nil? + end + + alias :destroy_without_reassign :destroy + + # Destroy the enumeration + # If a enumeration is specified, objects are reassigned + def destroy(reassign_to = nil) + if reassign_to && reassign_to.is_a?(Enumeration) + self.transfer_relations(reassign_to) + end + destroy_without_reassign + end + + def <=>(enumeration) + position <=> enumeration.position + end + + def to_s; name end + + # Returns the Subclasses of Enumeration. Each Subclass needs to be + # required in development mode. + # + # Note: subclasses is protected in ActiveRecord + def self.get_subclasses + @@subclasses[Enumeration] + end + + # Does the +new+ Hash override the previous Enumeration? + def self.overridding_change?(new, previous) + if (same_active_state?(new['active'], previous.active)) && same_custom_values?(new,previous) + return false + else + return true + end + end + + # Does the +new+ Hash have the same custom values as the previous Enumeration? + def self.same_custom_values?(new, previous) + previous.custom_field_values.each do |custom_value| + if custom_value.value != new["custom_field_values"][custom_value.custom_field_id.to_s] + return false + end + end + + return true + end + + # Are the new and previous fields equal? + def self.same_active_state?(new, previous) + new = (new == "1" ? true : false) + return new == previous + end + +private + def check_integrity + raise "Can't delete enumeration" if self.in_use? + end + +end + +# Force load the subclasses in development mode +require_dependency 'time_entry_activity' +require_dependency 'document_category' +require_dependency 'issue_priority' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/06b934af3bce9be376de55c695a81c0e464edbd4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/06b934af3bce9be376de55c695a81c0e464edbd4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +# Copyright (c) 2006 4ssoM LLC +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +require 'action_controller' +require 'action_view' + +require 'rfpdf/action_controller' +require 'rfpdf/action_view' + +require 'rfpdf/template_handler/compile_support' + +require 'rfpdf/template_handlers/base' + + +class ActionController::Base + include RFPDF::ActionController +end + +class ActionView::Base + include RFPDF::ActionView +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/06/06d13f36c723de5d4d11734c74881a345af8508f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/06/06d13f36c723de5d4d11734c74881a345af8508f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= TestHelper.view_path_for __FILE__ %> (from app) \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/07/07402976102eaabe37c42cc6aab7aeb00d221891.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/07/07402976102eaabe37c42cc6aab7aeb00d221891.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,164 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'repositories_controller' + +# Re-raise errors caught by the controller. +class RepositoriesController; def rescue_action(e) raise e end; end + +class RepositoriesDarcsControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules + + REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s + PRJ_ID = 3 + NUM_REV = 6 + + def setup + @controller = RepositoriesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @project = Project.find(PRJ_ID) + @repository = Repository::Darcs.create( + :project => @project, + :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8' + ) + assert @repository + end + + if File.directory?(REPOSITORY_PATH) + def test_browse_root + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal 3, assigns(:entries).size + assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} + end + + def test_browse_directory + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) + entry = assigns(:entries).detect {|e| e.name == 'edit.png'} + assert_not_nil entry + assert_equal 'file', entry.kind + assert_equal 'images/edit.png', entry.path + end + + def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'], :rev => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['delete.png'], assigns(:entries).collect(&:name) + end + + def test_changes + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :changes, :id => PRJ_ID, :path => ['images', 'edit.png'] + assert_response :success + assert_template 'changes' + assert_tag :tag => 'h2', :content => 'edit.png' + end + + def test_diff + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + # Full diff of changeset 5 + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 5, :type => dt + assert_response :success + assert_template 'diff' + # Line 22 removed + assert_tag :tag => 'th', + :content => '22', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /def remove/ } + end + end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Darcs.create( + :project => @project, + :url => "/invalid", + :log_encoding => 'UTF-8' + ) + assert @repository + @repository.fetch_changesets + @project.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + else + puts "Darcs test repository NOT FOUND. Skipping functional tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/07/074588d42b3ac157ab70417170443c5531685d7e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/07/074588d42b3ac157ab70417170443c5531685d7e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,270 @@ +module ActiveRecord + module Acts #:nodoc: + module List #:nodoc: + def self.included(base) + base.extend(ClassMethods) + end + + # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list. + # The class that has this specified needs to have a +position+ column defined as an integer on + # the mapped database table. + # + # Todo list example: + # + # class TodoList < ActiveRecord::Base + # has_many :todo_items, :order => "position" + # end + # + # class TodoItem < ActiveRecord::Base + # belongs_to :todo_list + # acts_as_list :scope => :todo_list + # end + # + # todo_list.first.move_to_bottom + # todo_list.last.move_higher + module ClassMethods + # Configuration options are: + # + # * +column+ - specifies the column name to use for keeping the position integer (default: +position+) + # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach _id + # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible + # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key. + # Example: acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0' + def acts_as_list(options = {}) + configuration = { :column => "position", :scope => "1 = 1" } + configuration.update(options) if options.is_a?(Hash) + + configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/ + + if configuration[:scope].is_a?(Symbol) + scope_condition_method = %( + def scope_condition + if #{configuration[:scope].to_s}.nil? + "#{configuration[:scope].to_s} IS NULL" + else + "#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}" + end + end + ) + else + scope_condition_method = "def scope_condition() \"#{configuration[:scope]}\" end" + end + + class_eval <<-EOV + include ActiveRecord::Acts::List::InstanceMethods + + def acts_as_list_class + ::#{self.name} + end + + def position_column + '#{configuration[:column]}' + end + + #{scope_condition_method} + + before_destroy :remove_from_list + before_create :add_to_list_bottom + EOV + end + end + + # All the methods available to a record that has had acts_as_list specified. Each method works + # by assuming the object to be the item in the list, so chapter.move_lower would move that chapter + # lower in the list of all chapters. Likewise, chapter.first? would return +true+ if that chapter is + # the first in the list of all chapters. + module InstanceMethods + # Insert the item at the given position (defaults to the top position of 1). + def insert_at(position = 1) + insert_at_position(position) + end + + # Swap positions with the next lower item, if one exists. + def move_lower + return unless lower_item + + acts_as_list_class.transaction do + lower_item.decrement_position + increment_position + end + end + + # Swap positions with the next higher item, if one exists. + def move_higher + return unless higher_item + + acts_as_list_class.transaction do + higher_item.increment_position + decrement_position + end + end + + # Move to the bottom of the list. If the item is already in the list, the items below it have their + # position adjusted accordingly. + def move_to_bottom + return unless in_list? + acts_as_list_class.transaction do + decrement_positions_on_lower_items + assume_bottom_position + end + end + + # Move to the top of the list. If the item is already in the list, the items above it have their + # position adjusted accordingly. + def move_to_top + return unless in_list? + acts_as_list_class.transaction do + increment_positions_on_higher_items + assume_top_position + end + end + + # Move to the given position + def move_to=(pos) + case pos.to_s + when 'highest' + move_to_top + when 'higher' + move_higher + when 'lower' + move_lower + when 'lowest' + move_to_bottom + end + end + + # Removes the item from the list. + def remove_from_list + if in_list? + decrement_positions_on_lower_items + update_attribute position_column, nil + end + end + + # Increase the position of this item without adjusting the rest of the list. + def increment_position + return unless in_list? + update_attribute position_column, self.send(position_column).to_i + 1 + end + + # Decrease the position of this item without adjusting the rest of the list. + def decrement_position + return unless in_list? + update_attribute position_column, self.send(position_column).to_i - 1 + end + + # Return +true+ if this object is the first in the list. + def first? + return false unless in_list? + self.send(position_column) == 1 + end + + # Return +true+ if this object is the last in the list. + def last? + return false unless in_list? + self.send(position_column) == bottom_position_in_list + end + + # Return the next higher item in the list. + def higher_item + return nil unless in_list? + acts_as_list_class.find(:first, :conditions => + "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}" + ) + end + + # Return the next lower item in the list. + def lower_item + return nil unless in_list? + acts_as_list_class.find(:first, :conditions => + "#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}" + ) + end + + # Test if this record is in a list + def in_list? + !send(position_column).nil? + end + + private + def add_to_list_top + increment_positions_on_all_items + end + + def add_to_list_bottom + self[position_column] = bottom_position_in_list.to_i + 1 + end + + # Overwrite this method to define the scope of the list changes + def scope_condition() "1" end + + # Returns the bottom position number in the list. + # bottom_position_in_list # => 2 + def bottom_position_in_list(except = nil) + item = bottom_item(except) + item ? item.send(position_column) : 0 + end + + # Returns the bottom item + def bottom_item(except = nil) + conditions = scope_condition + conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except + acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC") + end + + # Forces item to assume the bottom position in the list. + def assume_bottom_position + update_attribute(position_column, bottom_position_in_list(self).to_i + 1) + end + + # Forces item to assume the top position in the list. + def assume_top_position + update_attribute(position_column, 1) + end + + # This has the effect of moving all the higher items up one. + def decrement_positions_on_higher_items(position) + acts_as_list_class.update_all( + "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} <= #{position}" + ) + end + + # This has the effect of moving all the lower items up one. + def decrement_positions_on_lower_items + return unless in_list? + acts_as_list_class.update_all( + "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}" + ) + end + + # This has the effect of moving all the higher items down one. + def increment_positions_on_higher_items + return unless in_list? + acts_as_list_class.update_all( + "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}" + ) + end + + # This has the effect of moving all the lower items down one. + def increment_positions_on_lower_items(position) + acts_as_list_class.update_all( + "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} >= #{position}" + ) + end + + # Increments position (position_column) of all items in the list. + def increment_positions_on_all_items + acts_as_list_class.update_all( + "#{position_column} = (#{position_column} + 1)", "#{scope_condition}" + ) + end + + def insert_at_position(position) + remove_from_list + increment_positions_on_lower_items(position) + self.update_attribute(position_column, position) + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/08/084813ebc62b962e0c2151265f5ce7041604d329.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/08/084813ebc62b962e0c2151265f5ce7041604d329.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0138 kgreenlandic +!A3 U+0156 Rcommaaccent +!A4 U+00A4 currency +!A5 U+0128 Itilde +!A6 U+013B Lcommaaccent +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+0112 Emacron +!AB U+0122 Gcommaaccent +!AC U+0166 Tbar +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0157 rcommaaccent +!B4 U+00B4 acute +!B5 U+0129 itilde +!B6 U+013C lcommaaccent +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+0113 emacron +!BB U+0123 gcommaaccent +!BC U+0167 tbar +!BD U+014A Eng +!BE U+017E zcaron +!BF U+014B eng +!C0 U+0100 Amacron +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+012E Iogonek +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+0116 Edotaccent +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+012A Imacron +!D0 U+0110 Dcroat +!D1 U+0145 Ncommaaccent +!D2 U+014C Omacron +!D3 U+0136 Kcommaaccent +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+0172 Uogonek +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0168 Utilde +!DE U+016A Umacron +!DF U+00DF germandbls +!E0 U+0101 amacron +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+012F iogonek +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+0117 edotaccent +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+012B imacron +!F0 U+0111 dcroat +!F1 U+0146 ncommaaccent +!F2 U+014D omacron +!F3 U+0137 kcommaaccent +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+0173 uogonek +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0169 utilde +!FE U+016B umacron +!FF U+02D9 dotaccent diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/08/0856b80a2e3d388f4f051bee68228eb434db38ab.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/08/0856b80a2e3d388f4f051bee68228eb434db38ab.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,49 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::AccessControlTest < ActiveSupport::TestCase + + def setup + @access_module = Redmine::AccessControl + end + + def test_permissions + perms = @access_module.permissions + assert perms.is_a?(Array) + assert perms.first.is_a?(Redmine::AccessControl::Permission) + end + + def test_module_permission + perm = @access_module.permission(:view_issues) + assert perm.is_a?(Redmine::AccessControl::Permission) + assert_equal :view_issues, perm.name + assert_equal :issue_tracking, perm.project_module + assert perm.actions.is_a?(Array) + assert perm.actions.include?('issues/index') + end + + def test_no_module_permission + perm = @access_module.permission(:edit_project) + assert perm.is_a?(Redmine::AccessControl::Permission) + assert_equal :edit_project, perm.name + assert_nil perm.project_module + assert perm.actions.is_a?(Array) + assert perm.actions.include?('projects/settings') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/08/08671dfda70fdd4f87dd0171bec11e1d6e0c22e1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/08/08671dfda70fdd4f87dd0171bec11e1d6e0c22e1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,779 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) + +class Redmine::Helpers::GanttTest < ActiveSupport::TestCase + # Utility methods and classes so assert_select can be used. + class GanttViewTest < ActionView::Base + include ActionView::Helpers::UrlHelper + include ActionView::Helpers::TextHelper + include ActionController::UrlWriter + include ApplicationHelper + include ProjectsHelper + include IssuesHelper + + def self.default_url_options + {:only_path => true } + end + + end + + include ActionController::Assertions::SelectorAssertions + + def setup + @response = ActionController::TestResponse.new + # Fixtures + ProjectCustomField.delete_all + Project.destroy_all + + User.current = User.find(1) + end + + def build_view + @view = GanttViewTest.new + end + + def html_document + HTML::Document.new(@response.body) + end + + # Creates a Gantt chart for a 4 week span + def create_gantt(project=Project.generate!, options={}) + @project = project + @gantt = Redmine::Helpers::Gantt.new(options) + @gantt.project = @project + @gantt.query = Query.generate_default!(:project => @project) + @gantt.view = build_view + @gantt.instance_variable_set('@date_from', options[:date_from] || 2.weeks.ago.to_date) + @gantt.instance_variable_set('@date_to', options[:date_to] || 2.weeks.from_now.to_date) + end + + context "#number_of_rows" do + + context "with one project" do + should "return the number of rows just for that project" + end + + context "with no project" do + should "return the total number of rows for all the projects, resursively" + end + + should "not exceed max_rows option" do + p = Project.generate! + 5.times do + Issue.generate_for_project!(p) + end + + create_gantt(p) + @gantt.render + assert_equal 6, @gantt.number_of_rows + assert !@gantt.truncated + + create_gantt(p, :max_rows => 3) + @gantt.render + assert_equal 3, @gantt.number_of_rows + assert @gantt.truncated + end + end + + context "#number_of_rows_on_project" do + setup do + create_gantt + end + + should "count 0 for an empty the project" do + assert_equal 0, @gantt.number_of_rows_on_project(@project) + end + + should "count the number of issues without a version" do + @project.issues << Issue.generate_for_project!(@project, :fixed_version => nil) + assert_equal 2, @gantt.number_of_rows_on_project(@project) + end + + should "count the number of issues on versions, including cross-project" do + version = Version.generate! + @project.versions << version + @project.issues << Issue.generate_for_project!(@project, :fixed_version => version) + + assert_equal 3, @gantt.number_of_rows_on_project(@project) + end + end + + # TODO: more of an integration test + context "#subjects" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + @version = Version.generate!(:effective_date => 1.week.from_now.to_date, :sharing => 'none') + @project.versions << @version + + @issue = Issue.generate!(:fixed_version => @version, + :subject => "gantt#line_for_project", + :tracker => @tracker, + :project => @project, + :done_ratio => 30, + :start_date => Date.yesterday, + :due_date => 1.week.from_now.to_date) + @project.issues << @issue + end + + context "project" do + should "be rendered" do + @response.body = @gantt.subjects + assert_select "div.project-name a", /#{@project.name}/ + end + + should "have an indent of 4" do + @response.body = @gantt.subjects + assert_select "div.project-name[style*=left:4px]" + end + end + + context "version" do + should "be rendered" do + @response.body = @gantt.subjects + assert_select "div.version-name a", /#{@version.name}/ + end + + should "be indented 24 (one level)" do + @response.body = @gantt.subjects + assert_select "div.version-name[style*=left:24px]" + end + + context "without assigned issues" do + setup do + @version = Version.generate!(:effective_date => 2.week.from_now.to_date, :sharing => 'none', :name => 'empty_version') + @project.versions << @version + end + + should "not be rendered" do + @response.body = @gantt.subjects + assert_select "div.version-name a", :text => /#{@version.name}/, :count => 0 + end + end + end + + context "issue" do + should "be rendered" do + @response.body = @gantt.subjects + assert_select "div.issue-subject", /#{@issue.subject}/ + end + + should "be indented 44 (two levels)" do + @response.body = @gantt.subjects + assert_select "div.issue-subject[style*=left:44px]" + end + + context "assigned to a shared version of another project" do + setup do + p = Project.generate! + p.trackers << @tracker + p.enabled_module_names = [:issue_tracking] + @shared_version = Version.generate!(:sharing => 'system') + p.versions << @shared_version + # Reassign the issue to a shared version of another project + + @issue = Issue.generate!(:fixed_version => @shared_version, + :subject => "gantt#assigned_to_shared_version", + :tracker => @tracker, + :project => @project, + :done_ratio => 30, + :start_date => Date.yesterday, + :due_date => 1.week.from_now.to_date) + @project.issues << @issue + end + + should "be rendered" do + @response.body = @gantt.subjects + assert_select "div.issue-subject", /#{@issue.subject}/ + end + end + + context "with subtasks" do + setup do + attrs = {:project => @project, :tracker => @tracker, :fixed_version => @version} + @child1 = Issue.generate!(attrs.merge(:subject => 'child1', :parent_issue_id => @issue.id, :start_date => Date.yesterday, :due_date => 2.day.from_now.to_date)) + @child2 = Issue.generate!(attrs.merge(:subject => 'child2', :parent_issue_id => @issue.id, :start_date => Date.today, :due_date => 1.week.from_now.to_date)) + @grandchild = Issue.generate!(attrs.merge(:subject => 'grandchild', :parent_issue_id => @child1.id, :start_date => Date.yesterday, :due_date => 2.day.from_now.to_date)) + end + + should "indent subtasks" do + @response.body = @gantt.subjects + # parent task 44px + assert_select "div.issue-subject[style*=left:44px]", /#{@issue.subject}/ + # children 64px + assert_select "div.issue-subject[style*=left:64px]", /child1/ + assert_select "div.issue-subject[style*=left:64px]", /child2/ + # grandchild 84px + assert_select "div.issue-subject[style*=left:84px]", /grandchild/, @response.body + end + end + end + end + + context "#lines" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + @version = Version.generate!(:effective_date => 1.week.from_now.to_date) + @project.versions << @version + @issue = Issue.generate!(:fixed_version => @version, + :subject => "gantt#line_for_project", + :tracker => @tracker, + :project => @project, + :done_ratio => 30, + :start_date => Date.yesterday, + :due_date => 1.week.from_now.to_date) + @project.issues << @issue + + @response.body = @gantt.lines + end + + context "project" do + should "be rendered" do + assert_select "div.project.task_todo" + assert_select "div.project.starting" + assert_select "div.project.ending" + assert_select "div.label.project", /#{@project.name}/ + end + end + + context "version" do + should "be rendered" do + assert_select "div.version.task_todo" + assert_select "div.version.starting" + assert_select "div.version.ending" + assert_select "div.label.version", /#{@version.name}/ + end + end + + context "issue" do + should "be rendered" do + assert_select "div.task_todo" + assert_select "div.task.label", /#{@issue.done_ratio}/ + assert_select "div.tooltip", /#{@issue.subject}/ + end + end + end + + context "#render_project" do + should "be tested" + end + + context "#render_issues" do + should "be tested" + end + + context "#render_version" do + should "be tested" + end + + context "#subject_for_project" do + setup do + create_gantt + end + + context ":html format" do + should "add an absolute positioned div" do + @response.body = @gantt.subject_for_project(@project, {:format => :html}) + assert_select "div[style*=absolute]" + end + + should "use the indent option to move the div to the right" do + @response.body = @gantt.subject_for_project(@project, {:format => :html, :indent => 40}) + assert_select "div[style*=left:40]" + end + + should "include the project name" do + @response.body = @gantt.subject_for_project(@project, {:format => :html}) + assert_select 'div', :text => /#{@project.name}/ + end + + should "include a link to the project" do + @response.body = @gantt.subject_for_project(@project, {:format => :html}) + assert_select 'a[href=?]', "/projects/#{@project.identifier}", :text => /#{@project.name}/ + end + + should "style overdue projects" do + @project.enabled_module_names = [:issue_tracking] + @project.versions << Version.generate!(:effective_date => Date.yesterday) + + assert @project.overdue?, "Need an overdue project for this test" + @response.body = @gantt.subject_for_project(@project, {:format => :html}) + + assert_select 'div span.project-overdue' + end + + + end + + should "test the PNG format" + should "test the PDF format" + end + + context "#line_for_project" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + @version = Version.generate!(:effective_date => Date.yesterday) + @project.versions << @version + + @project.issues << Issue.generate!(:fixed_version => @version, + :subject => "gantt#line_for_project", + :tracker => @tracker, + :project => @project, + :done_ratio => 30, + :start_date => 1.week.ago.to_date, + :due_date => 1.week.from_now.to_date) + end + + context ":html format" do + context "todo line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.task_todo[style*=left:28px]", true, @response.body + end + + should "be the total width of the project" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.task_todo[style*=width:58px]", true, @response.body + end + + end + + context "late line" do + should_eventually "start from the starting point on the left" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.task_late[style*=left:28px]", true, @response.body + end + + should_eventually "be the total delayed width of the project" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.task_late[style*=width:30px]", true, @response.body + end + end + + context "done line" do + should_eventually "start from the starting point on the left" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.task_done[style*=left:28px]", true, @response.body + end + + should_eventually "Be the total done width of the project" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.task_done[style*=width:18px]", true, @response.body + end + end + + context "starting marker" do + should "not appear if the starting point is off the gantt chart" do + # Shift the date range of the chart + @gantt.instance_variable_set('@date_from', Date.today) + + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.starting", false, @response.body + end + + should "appear at the starting point" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.starting[style*=left:28px]", true, @response.body + end + end + + context "ending marker" do + should "not appear if the starting point is off the gantt chart" do + # Shift the date range of the chart + @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) + + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.ending", false, @response.body + + end + + should "appear at the end of the date range" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.ending[style*=left:88px]", true, @response.body + end + end + + context "status content" do + should "appear at the far left, even if it's far in the past" do + @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) + + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.label", /#{@project.name}/ + end + + should "show the project name" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.label", /#{@project.name}/ + end + + should_eventually "show the percent complete" do + @response.body = @gantt.line_for_project(@project, {:format => :html, :zoom => 4}) + assert_select "div.project.label", /0%/ + end + end + end + + should "test the PNG format" + should "test the PDF format" + end + + context "#subject_for_version" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + @version = Version.generate!(:effective_date => Date.yesterday) + @project.versions << @version + + @project.issues << Issue.generate!(:fixed_version => @version, + :subject => "gantt#subject_for_version", + :tracker => @tracker, + :project => @project, + :start_date => Date.today) + + end + + context ":html format" do + should "add an absolute positioned div" do + @response.body = @gantt.subject_for_version(@version, {:format => :html}) + assert_select "div[style*=absolute]" + end + + should "use the indent option to move the div to the right" do + @response.body = @gantt.subject_for_version(@version, {:format => :html, :indent => 40}) + assert_select "div[style*=left:40]" + end + + should "include the version name" do + @response.body = @gantt.subject_for_version(@version, {:format => :html}) + assert_select 'div', :text => /#{@version.name}/ + end + + should "include a link to the version" do + @response.body = @gantt.subject_for_version(@version, {:format => :html}) + assert_select 'a[href=?]', Regexp.escape("/versions/#{@version.to_param}"), :text => /#{@version.name}/ + end + + should "style late versions" do + assert @version.overdue?, "Need an overdue version for this test" + @response.body = @gantt.subject_for_version(@version, {:format => :html}) + + assert_select 'div span.version-behind-schedule' + end + + should "style behind schedule versions" do + assert @version.behind_schedule?, "Need a behind schedule version for this test" + @response.body = @gantt.subject_for_version(@version, {:format => :html}) + + assert_select 'div span.version-behind-schedule' + end + end + should "test the PNG format" + should "test the PDF format" + end + + context "#line_for_version" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + @version = Version.generate!(:effective_date => 1.week.from_now.to_date) + @project.versions << @version + + @project.issues << Issue.generate!(:fixed_version => @version, + :subject => "gantt#line_for_project", + :tracker => @tracker, + :project => @project, + :done_ratio => 30, + :start_date => 1.week.ago.to_date, + :due_date => 1.week.from_now.to_date) + end + + context ":html format" do + context "todo line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.task_todo[style*=left:28px]", true, @response.body + end + + should "be the total width of the version" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.task_todo[style*=width:58px]", true, @response.body + end + + end + + context "late line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.task_late[style*=left:28px]", true, @response.body + end + + should "be the total delayed width of the version" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.task_late[style*=width:30px]", true, @response.body + end + end + + context "done line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.task_done[style*=left:28px]", true, @response.body + end + + should "be the total done width of the version" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.task_done[style*=width:16px]", true, @response.body + end + end + + context "starting marker" do + should "not appear if the starting point is off the gantt chart" do + # Shift the date range of the chart + @gantt.instance_variable_set('@date_from', Date.today) + + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.starting", false + end + + should "appear at the starting point" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.starting[style*=left:28px]", true, @response.body + end + end + + context "ending marker" do + should "not appear if the starting point is off the gantt chart" do + # Shift the date range of the chart + @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) + + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.ending", false + + end + + should "appear at the end of the date range" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.ending[style*=left:88px]", true, @response.body + end + end + + context "status content" do + should "appear at the far left, even if it's far in the past" do + @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) + + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.label", /#{@version.name}/ + end + + should "show the version name" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.label", /#{@version.name}/ + end + + should "show the percent complete" do + @response.body = @gantt.line_for_version(@version, {:format => :html, :zoom => 4}) + assert_select "div.version.label", /30%/ + end + end + end + + should "test the PNG format" + should "test the PDF format" + end + + context "#subject_for_issue" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + + @issue = Issue.generate!(:subject => "gantt#subject_for_issue", + :tracker => @tracker, + :project => @project, + :start_date => 3.days.ago.to_date, + :due_date => Date.yesterday) + @project.issues << @issue + + end + + context ":html format" do + should "add an absolute positioned div" do + @response.body = @gantt.subject_for_issue(@issue, {:format => :html}) + assert_select "div[style*=absolute]" + end + + should "use the indent option to move the div to the right" do + @response.body = @gantt.subject_for_issue(@issue, {:format => :html, :indent => 40}) + assert_select "div[style*=left:40]" + end + + should "include the issue subject" do + @response.body = @gantt.subject_for_issue(@issue, {:format => :html}) + assert_select 'div', :text => /#{@issue.subject}/ + end + + should "include a link to the issue" do + @response.body = @gantt.subject_for_issue(@issue, {:format => :html}) + assert_select 'a[href=?]', Regexp.escape("/issues/#{@issue.to_param}"), :text => /#{@tracker.name} ##{@issue.id}/ + end + + should "style overdue issues" do + assert @issue.overdue?, "Need an overdue issue for this test" + @response.body = @gantt.subject_for_issue(@issue, {:format => :html}) + + assert_select 'div span.issue-overdue' + end + + end + should "test the PNG format" + should "test the PDF format" + end + + context "#line_for_issue" do + setup do + create_gantt + @project.enabled_module_names = [:issue_tracking] + @tracker = Tracker.generate! + @project.trackers << @tracker + @version = Version.generate!(:effective_date => 1.week.from_now.to_date) + @project.versions << @version + @issue = Issue.generate!(:fixed_version => @version, + :subject => "gantt#line_for_project", + :tracker => @tracker, + :project => @project, + :done_ratio => 30, + :start_date => 1.week.ago.to_date, + :due_date => 1.week.from_now.to_date) + @project.issues << @issue + end + + context ":html format" do + context "todo line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_todo[style*=left:28px]", true, @response.body + end + + should "be the total width of the issue" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_todo[style*=width:58px]", true, @response.body + end + + end + + context "late line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_late[style*=left:28px]", true, @response.body + end + + should "be the total delayed width of the issue" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_late[style*=width:30px]", true, @response.body + end + end + + context "done line" do + should "start from the starting point on the left" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_done[style*=left:28px]", true, @response.body + end + + should "be the total done width of the issue" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + # 15 days * 4 px * 30% - 2 px for borders = 16 px + assert_select "div.task_done[style*=width:16px]", true, @response.body + end + + should "not be the total done width if the chart starts after issue start date" do + create_gantt(@project, :date_from => 5.days.ago.to_date) + + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_done[style*=left:0px]", true, @response.body + assert_select "div.task_done[style*=width:8px]", true, @response.body + end + + context "for completed issue" do + setup do + @issue.done_ratio = 100 + end + + should "be the total width of the issue" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_done[style*=width:58px]", true, @response.body + end + + should "be the total width of the issue with due_date=start_date" do + @issue.due_date = @issue.start_date + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task_done[style*=width:2px]", true, @response.body + end + end + end + + context "status content" do + should "appear at the far left, even if it's far in the past" do + @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) + + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task.label", true, @response.body + end + + should "show the issue status" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task.label", /#{@issue.status.name}/ + end + + should "show the percent complete" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.task.label", /30%/ + end + end + end + + should "have an issue tooltip" do + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) + assert_select "div.tooltip", /#{@issue.subject}/ + end + + should "test the PNG format" + should "test the PDF format" + end + + context "#to_image" do + should "be tested" + end + + context "#to_pdf" do + should "be tested" + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/08/087233ae24090110720dcc34ab0239f28dfbf416.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/08/087233ae24090110720dcc34ab0239f28dfbf416.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +

<%=l(:label_member_plural)%>

+ +<% if @members.empty? %>

<%= l(:label_no_data) %>

<% end %> + +<% members = @members.group_by {|m| m.role } %> +<% members.keys.sort{|x,y| x.position <=> y.position}.each do |role| %> +

<%= h(role.name) %>

+
    +<% members[role].each do |m| %> +
  • <%= link_to_user m.user %> (<%= format_date m.created_on %>)
  • +<% end %> +
+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/08/087ac3ba0dd90a493f814e49e635e06136a040ab.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/08/087ac3ba0dd90a493f814e49e635e06136a040ab.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +template from plugin \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/08/08ad7bd6a34b90904a67a548c4d4b4a71f849da8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/08/08ad7bd6a34b90904a67a548c4d4b4a71f849da8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +To: +Subject: New ticket on a given project +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris. Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque +sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. +Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, +dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, +massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo +pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. + +Project: onlinestore +Status: Resolved + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/0950951344735156104a9fd2df5df66fc9bd2194.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/0950951344735156104a9fd2df5df66fc9bd2194.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Views + module Builders + def self.for(format, &block) + builder = case format + when 'xml', :xml; Builders::Xml.new + when 'json', :json; Builders::Json.new + else; raise "No builder for format #{format}" + end + if block + block.call(builder) + else + builder + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/095b395fcfe029ccbb2acac47d6cc8ef84b80f97.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/095b395fcfe029ccbb2acac47d6cc8ef84b80f97.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +syntax: glob + +.project +.loadpath +config/additional_environment.rb +config/configuration.yml +config/database.yml +config/email.yml +config/initializers/session_store.rb +coverage +db/*.db +db/*.sqlite3 +db/schema.rb +files/* +lib/redmine/scm/adapters/mercurial/redminehelper.pyc +lib/redmine/scm/adapters/mercurial/redminehelper.pyo +log/*.log* +log/mongrel_debug +public/dispatch.* +public/plugin_assets +tmp/* +tmp/cache/* +tmp/sessions/* +tmp/sockets/* +tmp/test/* +vendor/rails +*.rbc + +.svn/ +.git/ + +.bundle +Gemfile.lock +Gemfile.local + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/097724d3314bf3e712b2c86215bd2f8b4ddf2b45.svn-base Binary file .svn/pristine/09/097724d3314bf3e712b2c86215bd2f8b4ddf2b45.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/09843d45a0a3ac966e4fda0bad80ec81990f71bb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/09843d45a0a3ac966e4fda0bad80ec81990f71bb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +Net::LDAP is copyrighted free software by Francis Cianfrocca +. You can redistribute it and/or modify it under either +the terms of the GPL (see the file COPYING), or the conditions below: + +1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + +2. You may modify your copy of the software in any way, provided that you do + at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or by allowing the author to include your + modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) rename any non-standard executables so the names do not conflict with + standard executables, which must also be provided. + + d) make other distribution arrangements with the author. + +3. You may distribute the software in object code or executable form, + provided that you do at least ONE of the following: + + a) distribute the executables and library files of the software, together + with instructions (in the manual page or equivalent) on where to get + the original distribution. + + b) accompany the distribution with the machine-readable source of the + software. + + c) give non-standard executables non-standard names, with instructions on + where to get the original software distribution. + + d) make other distribution arrangements with the author. + +4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution are + not written by the author, so that they are not under this terms. + + They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some + files under the ./missing directory. See each file for the copying + condition. + +5. The scripts and library files supplied as input to or produced as output + from the software do not automatically fall under the copyright of the + software, but belong to whomever generated them, and may be sold + commercially, and may be aggregated with this software. + +6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/09aef7f6ca17199f5fead2083da8308be0ce20bb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/09aef7f6ca17199f5fead2083da8308be0ce20bb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMessagesSticky < ActiveRecord::Migration + def self.up + add_column :messages, :sticky, :integer, :default => 0 + end + + def self.down + remove_column :messages, :sticky + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/09e9cff44f8552801f81cd9959399327d07f5275.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/09e9cff44f8552801f81cd9959399327d07f5275.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Extra nadruk'; +jsToolBar.strings['Italic'] = 'Cursief'; +jsToolBar.strings['Underline'] = 'Onderstreept'; +jsToolBar.strings['Deleted'] = 'Verwijderd'; +jsToolBar.strings['Code'] = 'Computercode'; +jsToolBar.strings['Heading 1'] = 'Kop 1'; +jsToolBar.strings['Heading 2'] = 'Kop 2'; +jsToolBar.strings['Heading 3'] = 'Kop 3'; +jsToolBar.strings['Unordered list'] = 'Ongeordende lijst'; +jsToolBar.strings['Ordered list'] = 'Geordende lijst'; +jsToolBar.strings['Quote'] = 'Citaat'; +jsToolBar.strings['Unquote'] = 'Verwijder citaat'; +jsToolBar.strings['Preformatted text'] = 'Voor-geformateerde tekst'; +jsToolBar.strings['Wiki link'] = 'Link naar een Wiki pagina'; +jsToolBar.strings['Image'] = 'Afbeelding'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/09ee2f48a5aafa2ec6da3a021e076cc86af61f01.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/09ee2f48a5aafa2ec6da3a021e076cc86af61f01.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

<%= l(:label_board_new) %>

+ +<% labelled_tabular_form_for :board, @board, :url => {:action => 'new'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/09/09fd6db0926bf35a4db846796898a3efe70dfa6f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/09/09fd6db0926bf35a4db846796898a3efe70dfa6f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ + + + + + + + + + <% for new_status in @statuses %> + + <% end %> + + + + <% for old_status in @statuses %> + "> + + <% for new_status in @statuses -%> + + <% end -%> + + <% end %> + +
+ <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%=l(:label_current_status)%> + <%=l(:label_new_statuses_allowed)%>
+ <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.new-status-#{new_status.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%=h new_status.name %> +
+ <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + + <%=h old_status.name %> + + <%= check_box_tag "issue_status[#{ old_status.id }][#{new_status.id}][]", name, workflows.detect {|w| w.old_status_id == old_status.id && w.new_status_id == new_status.id}, + :class => "old-status-#{old_status.id} new-status-#{new_status.id}" %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a08b8bce6631efd08e47030eee4cad9d864deab.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a08b8bce6631efd08e47030eee4cad9d864deab.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddHideMailPref < ActiveRecord::Migration + def self.up + add_column :user_preferences, :hide_mail, :boolean, :default => false + end + + def self.down + remove_column :user_preferences, :hide_mail + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a0af350ccda1e24c957ac2e637711c7c13afce3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a0af350ccda1e24c957ac2e637711c7c13afce3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class AddSearchPermission < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "search", :description => "label_search", :sort => 130, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('projects', 'search').destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a2012ccc071b135723fea48195cee80c8c91dc5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a2012ccc071b135723fea48195cee80c8c91dc5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class RemoveEnumerationsOpt < ActiveRecord::Migration + def self.up + remove_column :enumerations, :opt + end + + def self.down + add_column :enumerations, :opt, :string, :limit => 4, :default => '', :null => false + Enumeration.update_all("opt = 'IPRI'", "type = 'IssuePriority'") + Enumeration.update_all("opt = 'DCAT'", "type = 'DocumentCategory'") + Enumeration.update_all("opt = 'ACTI'", "type = 'TimeEntryActivity'") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a371b310545389947180083feb53371bb868f67.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a371b310545389947180083feb53371bb868f67.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +module CodeRay +module Encoders + + map \ + :loc => :lines_of_code, + :plain => :text, + :plaintext => :text, + :remove_comments => :comment_filter, + :stats => :statistic, + :term => :terminal, + :tty => :terminal, + :yml => :yaml + + # No default because Tokens#nonsense should raise NoMethodError. + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a62a3ae28a4f2df93a63c650d603c29ff087559.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a62a3ae28a4f2df93a63c650d603c29ff087559.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +<% form_tag({:action => 'edit', :tab => 'mail_handler'}) do %> + +
+

+ <%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %> +
<%= l(:text_line_separated) %> +

+
+ +
+

<%= setting_check_box :mail_handler_api_enabled, + :onclick => "if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }"%>

+ +

<%= setting_text_field :mail_handler_api_key, :size => 30, + :id => 'settings_mail_handler_api_key', + :disabled => !Setting.mail_handler_api_enabled? %> + <%= link_to_function l(:label_generate_key), "if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }" %> +

+
+ +<%= submit_tag l(:button_save) %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a7b1df77f27f5a19675ef17aa746a136c7168e4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a7b1df77f27f5a19675ef17aa746a136c7168e4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +// translated by Dzintars Bergs (dzintars.bergs@gmail.com) +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Treknraksts'; +jsToolBar.strings['Italic'] = 'Slīpraksts'; +jsToolBar.strings['Underline'] = 'Pasvītrojums'; +jsToolBar.strings['Deleted'] = 'Dzēsts'; +jsToolBar.strings['Code'] = 'Iekļauts kods'; +jsToolBar.strings['Heading 1'] = 'Virsraksts 1'; +jsToolBar.strings['Heading 2'] = 'Virsraksts 2'; +jsToolBar.strings['Heading 3'] = 'Virsraksts 3'; +jsToolBar.strings['Unordered list'] = 'Nesakārtots saraksts'; +jsToolBar.strings['Ordered list'] = 'Sakārtots saraksts'; +jsToolBar.strings['Quote'] = 'Citēt'; +jsToolBar.strings['Unquote'] = 'Noņemt citātu'; +jsToolBar.strings['Preformatted text'] = 'Iepriekš formatēts teksts'; +jsToolBar.strings['Wiki link'] = 'Saite uz Wiki lapu'; +jsToolBar.strings['Image'] = 'Attēls'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0a884b128ca03268f26234e1c96b240bce5a6e1b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0a884b128ca03268f26234e1c96b240bce5a6e1b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,101 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class EnumerationsControllerTest < ActionController::TestCase + fixtures :enumerations, :issues, :users + + def setup + @request.session[:user_id] = 1 # admin + end + + def test_index + get :index + assert_response :success + assert_template 'index' + end + + def test_new + get :new, :type => 'IssuePriority' + assert_response :success + assert_template 'new' + assert_kind_of IssuePriority, assigns(:enumeration) + end + + def test_create + assert_difference 'IssuePriority.count' do + post :create, :enumeration => {:type => 'IssuePriority', :name => 'Lowest'} + end + assert_redirected_to '/enumerations?type=IssuePriority' + e = IssuePriority.first(:order => 'id DESC') + assert_equal 'Lowest', e.name + end + + def test_create_with_failure + assert_no_difference 'IssuePriority.count' do + post :create, :enumeration => {:type => 'IssuePriority', :name => ''} + end + assert_response :success + assert_template 'new' + end + + def test_edit + get :edit, :id => 6 + assert_response :success + assert_template 'edit' + end + + def test_update + assert_no_difference 'IssuePriority.count' do + post :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => 'New name'} + end + assert_redirected_to '/enumerations?type=IssuePriority' + e = IssuePriority.find(6) + assert_equal 'New name', e.name + end + + def test_update_with_failure + assert_no_difference 'IssuePriority.count' do + post :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => ''} + end + assert_response :success + assert_template 'edit' + end + + def test_destroy_enumeration_not_in_use + post :destroy, :id => 7 + assert_redirected_to :controller => 'enumerations', :action => 'index' + assert_nil Enumeration.find_by_id(7) + end + + def test_destroy_enumeration_in_use + post :destroy, :id => 4 + assert_response :success + assert_template 'destroy' + assert_not_nil Enumeration.find_by_id(4) + end + + def test_destroy_enumeration_in_use_with_reassignment + issue = Issue.find(:first, :conditions => {:priority_id => 4}) + post :destroy, :id => 4, :reassign_to_id => 6 + assert_redirected_to :controller => 'enumerations', :action => 'index' + assert_nil Enumeration.find_by_id(4) + # check that the issue was reassign + assert_equal 6, issue.reload.priority_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0a/0ade634c1e3a74f500a2549a2decba896fa1c7ee.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0a/0ade634c1e3a74f500a2549a2decba896fa1c7ee.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +Copyright (c) 2005 Rick Olson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0b13a0dbdeb0aee1463dd68405cf36eb915fdb6c.svn-base Binary file .svn/pristine/0b/0b13a0dbdeb0aee1463dd68405cf36eb915fdb6c.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0b184ad51ba2a79e85d2288d5fcf8a1ea0481ea4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0b/0b184ad51ba2a79e85d2288d5fcf8a1ea0481ea4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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. + + + Copyright (C) + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + , 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 Library General +Public License instead of this License. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0b26e69e5ae731de14e1272a803c5ca8472b3a28.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0b/0b26e69e5ae731de14e1272a803c5ca8472b3a28.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +class AddRepositoriesPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "repositories", :action => "show", :description => "button_view", :sort => 1450, :is_public => true + Permission.create :controller => "repositories", :action => "browse", :description => "label_browse", :sort => 1460, :is_public => true + Permission.create :controller => "repositories", :action => "entry", :description => "entry", :sort => 1462, :is_public => true + Permission.create :controller => "repositories", :action => "revisions", :description => "label_view_revisions", :sort => 1470, :is_public => true + Permission.create :controller => "repositories", :action => "revision", :description => "label_view_revisions", :sort => 1472, :is_public => true + Permission.create :controller => "repositories", :action => "diff", :description => "diff", :sort => 1480, :is_public => true + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'repositories', 'show']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'repositories', 'browse']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'repositories', 'entry']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'repositories', 'revisions']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'repositories', 'revision']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'repositories', 'diff']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0b5c22ea9dff7e86156bbe2c3f813307405010ea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0b/0b5c22ea9dff7e86156bbe2c3f813307405010ea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class UpdateEnumerationsToSti < ActiveRecord::Migration + def self.up + Enumeration.update_all("type = 'IssuePriority'", "opt = 'IPRI'") + Enumeration.update_all("type = 'DocumentCategory'", "opt = 'DCAT'") + Enumeration.update_all("type = 'TimeEntryActivity'", "opt = 'ACTI'") + end + + def self.down + # no-op + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0b97b483eed443a57933ffcafedb4eb971db5cf5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0b/0b97b483eed443a57933ffcafedb4eb971db5cf5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,325 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class ScmFetchError < Exception; end + +class Repository < ActiveRecord::Base + include Redmine::Ciphering + + belongs_to :project + has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC" + has_many :changes, :through => :changesets + + serialize :extra_info + + # Raw SQL to delete changesets and changes in the database + # has_many :changesets, :dependent => :destroy is too slow for big repositories + before_destroy :clear_changesets + + validates_length_of :password, :maximum => 255, :allow_nil => true + # Checks if the SCM is enabled when creating a repository + validate :repo_create_validation, :on => :create + + def repo_create_validation + unless Setting.enabled_scm.include?(self.class.name.demodulize) + errors.add(:type, :invalid) + end + end + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == "log_encoding" + attr_name = "commit_logs_encoding" + end + super(attr_name) + end + + # Removes leading and trailing whitespace + def url=(arg) + write_attribute(:url, arg ? arg.to_s.strip : nil) + end + + # Removes leading and trailing whitespace + def root_url=(arg) + write_attribute(:root_url, arg ? arg.to_s.strip : nil) + end + + def password + read_ciphered_attribute(:password) + end + + def password=(arg) + write_ciphered_attribute(:password, arg) + end + + def scm_adapter + self.class.scm_adapter_class + end + + def scm + @scm ||= self.scm_adapter.new(url, root_url, + login, password, path_encoding) + update_attribute(:root_url, @scm.root_url) if root_url.blank? + @scm + end + + def scm_name + self.class.scm_name + end + + def merge_extra_info(arg) + h = extra_info || {} + return h if arg.nil? + h.merge!(arg) + write_attribute(:extra_info, h) + end + + def report_last_commit + true + end + + def supports_cat? + scm.supports_cat? + end + + def supports_annotate? + scm.supports_annotate? + end + + def supports_all_revisions? + true + end + + def supports_directory_revisions? + false + end + + def supports_revision_graph? + false + end + + def entry(path=nil, identifier=nil) + scm.entry(path, identifier) + end + + def entries(path=nil, identifier=nil) + scm.entries(path, identifier) + end + + def branches + scm.branches + end + + def tags + scm.tags + end + + def default_branch + nil + end + + def properties(path, identifier=nil) + scm.properties(path, identifier) + end + + def cat(path, identifier=nil) + scm.cat(path, identifier) + end + + def diff(path, rev, rev_to) + scm.diff(path, rev, rev_to) + end + + def diff_format_revisions(cs, cs_to, sep=':') + text = "" + text << cs_to.format_identifier + sep if cs_to + text << cs.format_identifier if cs + text + end + + # Returns a path relative to the url of the repository + def relative_path(path) + path + end + + # Finds and returns a revision with a number or the beginning of a hash + def find_changeset_by_name(name) + return nil if name.blank? + changesets.find(:first, :conditions => (name.match(/^\d*$/) ? + ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%'])) + end + + def latest_changeset + @latest_changeset ||= changesets.find(:first) + end + + # Returns the latest changesets for +path+ + # Default behaviour is to search in cached changesets + def latest_changesets(path, rev, limit=10) + if path.blank? + changesets.find( + :all, + :include => :user, + :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", + :limit => limit) + else + changes.find( + :all, + :include => {:changeset => :user}, + :conditions => ["path = ?", path.with_leading_slash], + :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", + :limit => limit + ).collect(&:changeset) + end + end + + def scan_changesets_for_issue_ids + self.changesets.each(&:scan_comment_for_issue_ids) + end + + # Returns an array of committers usernames and associated user_id + def committers + @committers ||= Changeset.connection.select_rows( + "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") + end + + # Maps committers username to a user ids + def committer_ids=(h) + if h.is_a?(Hash) + committers.each do |committer, user_id| + new_user_id = h[committer] + if new_user_id && (new_user_id.to_i != user_id.to_i) + new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil) + Changeset.update_all( + "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", + ["repository_id = ? AND committer = ?", id, committer]) + end + end + @committers = nil + @found_committer_users = nil + true + else + false + end + end + + # Returns the Redmine User corresponding to the given +committer+ + # It will return nil if the committer is not yet mapped and if no User + # with the same username or email was found + def find_committer_user(committer) + unless committer.blank? + @found_committer_users ||= {} + return @found_committer_users[committer] if @found_committer_users.has_key?(committer) + + user = nil + c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) + if c && c.user + user = c.user + elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + user = u + end + @found_committer_users[committer] = user + user + end + end + + def repo_log_encoding + encoding = log_encoding.to_s.strip + encoding.blank? ? 'UTF-8' : encoding + end + + # Fetches new changesets for all repositories of active projects + # Can be called periodically by an external script + # eg. ruby script/runner "Repository.fetch_changesets" + def self.fetch_changesets + Project.active.has_module(:repository).find(:all, :include => :repository).each do |project| + if project.repository + begin + project.repository.fetch_changesets + rescue Redmine::Scm::Adapters::CommandFailed => e + logger.error "scm: error during fetching changesets: #{e.message}" + end + end + end + end + + # scan changeset comments to find related and fixed issues for all repositories + def self.scan_changesets_for_issue_ids + find(:all).each(&:scan_changesets_for_issue_ids) + end + + def self.scm_name + 'Abstract' + end + + def self.available_scm + subclasses.collect {|klass| [klass.scm_name, klass.name]} + end + + def self.factory(klass_name, *args) + klass = "Repository::#{klass_name}".constantize + klass.new(*args) + rescue + nil + end + + def self.scm_adapter_class + nil + end + + def self.scm_command + ret = "" + begin + ret = self.scm_adapter_class.client_command if self.scm_adapter_class + rescue Exception => e + logger.error "scm: error during get command: #{e.message}" + end + ret + end + + def self.scm_version_string + ret = "" + begin + ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class + rescue Exception => e + logger.error "scm: error during get version string: #{e.message}" + end + ret + end + + def self.scm_available + ret = false + begin + ret = self.scm_adapter_class.client_available if self.scm_adapter_class + rescue Exception => e + logger.error "scm: error during get scm available: #{e.message}" + end + ret + end + + private + + def clear_changesets + cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}" + connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") + connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") + connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0bb37bada66e59ca10b2c73a99ba22c8f3a2bb29.svn-base Binary file .svn/pristine/0b/0bb37bada66e59ca10b2c73a99ba22c8f3a2bb29.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0beba908a316302bd0ca691f7555fdce76127696.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0b/0beba908a316302bd0ca691f7555fdce76127696.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,129 @@ +--- +wiki_contents_001: + text: |- + h1. CookBook documentation + + {{child_pages}} + + Some updated [[documentation]] here with gzipped history + updated_on: 2007-03-07 00:10:51 +01:00 + page_id: 1 + id: 1 + version: 3 + author_id: 1 + comments: Gzip compression activated +wiki_contents_002: + text: |- + h1. Another page + + This is a link to a ticket: #2 + And this is an included page: + {{include(Page with an inline image)}} + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 2 + id: 2 + version: 1 + author_id: 1 + comments: +wiki_contents_003: + text: |- + h1. Start page + + E-commerce web site start page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 3 + id: 3 + version: 1 + author_id: 1 + comments: +wiki_contents_004: + text: |- + h1. Page with an inline image + + This is an inline image: + + !logo.gif! + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 4 + id: 4 + version: 1 + author_id: 1 + comments: +wiki_contents_005: + text: |- + h1. Child page 1 + + This is a child page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 5 + id: 5 + version: 1 + author_id: 1 + comments: +wiki_contents_006: + text: |- + h1. Child page 2 + + This is a child page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 6 + id: 6 + version: 1 + author_id: 1 + comments: +wiki_contents_007: + text: This is a child page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 7 + id: 7 + version: 1 + author_id: 1 + comments: +wiki_contents_008: + text: This is a parent page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 8 + id: 8 + version: 1 + author_id: 1 + comments: +wiki_contents_009: + text: This is a child page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 9 + id: 9 + version: 1 + author_id: 1 + comments: +wiki_contents_010: + text: Page with cyrillic title + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 10 + id: 10 + version: 1 + author_id: 1 + comments: +wiki_contents_011: + text: |- + h1. Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + + h2. Heading 1 + + @WHATEVER@ + + Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + + Cras ipsum felis, ultrices at porttitor vel, faucibus eu nunc. + + h2. Heading 2 + + Morbi facilisis accumsan orci non pharetra. + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 11 + id: 11 + version: 3 + author_id: 1 + comments: + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0b/0bfbd6508bed6a33543df0df9a316455bb2e521a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0b/0bfbd6508bed6a33543df0df9a316455bb2e521a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +

<%=h @attachment.filename %>

+ +
+

<%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> + <%= link_to_user(@attachment.author) %>, <%= format_time(@attachment.created_on) %>

+

<%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> + (<%= number_to_human_size @attachment.filesize %>)

+
+

+<% form_tag({}, :method => 'get') do %> + + <%= select_tag 'type', + options_for_select( + [[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), + :onchange => "if (this.value != '') {this.form.submit()}" %> +<% end %> +

+<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %> + +<% html_title @attachment.filename %> + +<% content_for :header_tags do -%> + <%= stylesheet_link_tag "scm" -%> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0c/0c07ac7fadf7713b8982de217779de9a2084825c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0c/0c07ac7fadf7713b8982de217779de9a2084825c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,70 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Group < Principal + has_and_belongs_to_many :users, :after_add => :user_added, + :after_remove => :user_removed + + acts_as_customizable + + validates_presence_of :lastname + validates_uniqueness_of :lastname, :case_sensitive => false + validates_length_of :lastname, :maximum => 30 + + before_destroy :remove_references_before_destroy + + def to_s + lastname.to_s + end + + alias :name :to_s + + def user_added(user) + members.each do |member| + next if member.project.nil? + user_member = Member.find_by_project_id_and_user_id(member.project_id, user.id) || Member.new(:project_id => member.project_id, :user_id => user.id) + member.member_roles.each do |member_role| + user_member.member_roles << MemberRole.new(:role => member_role.role, :inherited_from => member_role.id) + end + user_member.save! + end + end + + def user_removed(user) + members.each do |member| + MemberRole.find(:all, :include => :member, + :conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy) + end + end + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == 'lastname' + attr_name = "name" + end + super(attr_name) + end + + private + + # Removes references that are not handled by associations + def remove_references_before_destroy + return if self.id.nil? + + Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0c/0c29497a56078e0463be76e7192d98e2c38a77c5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0c/0c29497a56078e0463be76e7192d98e2c38a77c5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +// Translated by: Alexandre da Silva + +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negrito'; +jsToolBar.strings['Italic'] = 'Itálico'; +jsToolBar.strings['Underline'] = 'Sublinhado'; +jsToolBar.strings['Deleted'] = 'Excluído'; +jsToolBar.strings['Code'] = 'Código Inline'; +jsToolBar.strings['Heading 1'] = 'Cabeçalho 1'; +jsToolBar.strings['Heading 2'] = 'Cabeçalho 2'; +jsToolBar.strings['Heading 3'] = 'Cabeçalho 3'; +jsToolBar.strings['Unordered list'] = 'Lista não ordenada'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Texto pré-formatado'; +jsToolBar.strings['Wiki link'] = 'Link para uma página Wiki'; +jsToolBar.strings['Image'] = 'Imagem'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0c/0c3d44b905a542240e7c616a63f74580e8cbbb9d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0c/0c3d44b905a542240e7c616a63f74580e8cbbb9d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,67 @@ +<% diff = Redmine::UnifiedDiff.new( + diff, :type => diff_type, + :max_lines => Setting.diff_max_lines_displayed.to_i) -%> + +<% diff.each do |table_file| -%> +
+<% if diff.diff_type == 'sbs' -%> + + + + + + + +<% table_file.each_line do |spacing, line| -%> +<% if spacing -%> + + + +<% end -%> + + + + + + +<% end -%> + +
+ <%= h(Redmine::CodesetUtil.to_utf8_by_setting(table_file.file_name)) %> +
......
<%= line.nb_line_left %> +
<%= Redmine::CodesetUtil.to_utf8_by_setting(line.html_line_left) %>
+
<%= line.nb_line_right %> +
<%= Redmine::CodesetUtil.to_utf8_by_setting(line.html_line_right) %>
+
+ +<% else -%> + + + + + + + +<% table_file.each_line do |spacing, line| %> +<% if spacing -%> + + + +<% end -%> + + + + + +<% end -%> + +
+ <%= h(Redmine::CodesetUtil.to_utf8_by_setting(table_file.file_name)) %> +
......
<%= line.nb_line_left %><%= line.nb_line_right %> +
<%= Redmine::CodesetUtil.to_utf8_by_setting(line.html_line) %>
+
+<% end -%> +
+<% end -%> + +<%= l(:text_diff_truncated) if diff.truncated? %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0c/0c6f26d5801bada7f2273619e6e9418ef98266f4.svn-base Binary file .svn/pristine/0c/0c6f26d5801bada7f2273619e6e9418ef98266f4.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0c/0c7edc475b37b33857cc262660c5a82535a455e8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0c/0c7edc475b37b33857cc262660c5a82535a455e8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,71 @@ +--- +versions_001: + created_on: 2006-07-19 21:00:07 +02:00 + name: "0.1" + project_id: 1 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 1 + description: Beta + effective_date: 2006-07-01 + status: closed + sharing: 'none' +versions_002: + created_on: 2006-07-19 21:00:33 +02:00 + name: "1.0" + project_id: 1 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 2 + description: Stable release + effective_date: <%= 20.day.from_now.to_date.to_s(:db) %> + status: locked + sharing: 'none' +versions_003: + created_on: 2006-07-19 21:00:33 +02:00 + name: "2.0" + project_id: 1 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 3 + description: Future version + effective_date: + status: open + sharing: 'none' +versions_004: + created_on: 2006-07-19 21:00:33 +02:00 + name: "2.0" + project_id: 3 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 4 + description: Future version on subproject + effective_date: + status: open + sharing: 'tree' +versions_005: + created_on: 2006-07-19 21:00:07 +02:00 + name: "Alpha" + project_id: 2 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 5 + description: Private Alpha + effective_date: 2006-07-01 + status: open + sharing: 'none' +versions_006: + created_on: 2006-07-19 21:00:07 +02:00 + name: "Private Version of public subproject" + project_id: 5 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 6 + description: "Should be done any day now..." + effective_date: + status: open + sharing: 'tree' +versions_007: + created_on: 2006-07-19 21:00:07 +02:00 + name: "Systemwide visible version" + project_id: 2 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 7 + description: + effective_date: + status: open + sharing: 'system' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0c/0cd8ee527e2f2ff13b3817238dc6eed2ab240c57.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0c/0cd8ee527e2f2ff13b3817238dc6eed2ab240c57.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class <%= class_name %>Controller < ApplicationController + unloadable + +<% actions.each do |action| -%> + + def <%= action %> + end +<% end -%> +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0d106c8ee2a99b8daf9a6d87887284bdd099fa19.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0d106c8ee2a99b8daf9a6d87887284bdd099fa19.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class SettingTest < ActiveSupport::TestCase + + def test_read_default + assert_equal "Redmine", Setting.app_title + assert Setting.self_registration? + assert !Setting.login_required? + end + + def test_update + Setting.app_title = "My title" + assert_equal "My title", Setting.app_title + # make sure db has been updated (INSERT) + assert_equal "My title", Setting.find_by_name('app_title').value + + Setting.app_title = "My other title" + assert_equal "My other title", Setting.app_title + # make sure db has been updated (UPDATE) + assert_equal "My other title", Setting.find_by_name('app_title').value + end + + def test_serialized_setting + Setting.notified_events = ['issue_added', 'issue_updated', 'news_added'] + assert_equal ['issue_added', 'issue_updated', 'news_added'], Setting.notified_events + assert_equal ['issue_added', 'issue_updated', 'news_added'], Setting.find_by_name('notified_events').value + end + + def test_setting_should_be_reloaded_after_clear_cache + Setting.app_title = "My title" + assert_equal "My title", Setting.app_title + + s = Setting.find_by_name("app_title") + s.value = 'New title' + s.save! + assert_equal "My title", Setting.app_title + + Setting.clear_cache + assert_equal "New title", Setting.app_title + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0d2311ec4452abd2d98cbb99aaf512d8571b9e28.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0d2311ec4452abd2d98cbb99aaf512d8571b9e28.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class IssuePriority < Enumeration + generator_for :name, :start => 'IssuePriority0' + generator_for :type => 'IssuePriority' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0d2b0871cc92cdf1758e46df7708e3b5a4ed473c.svn-base Binary file .svn/pristine/0d/0d2b0871cc92cdf1758e46df7708e3b5a4ed473c.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0d581e597497e894acf26342b5cf129e84f325db.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0d581e597497e894acf26342b5cf129e84f325db.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +module Redmine + module Info + class << self + def app_name; 'Redmine' end + def url; 'http://www.redmine.org/' end + def help_url; 'http://www.redmine.org/guide' end + def versioned_name; "#{app_name} #{Redmine::VERSION}" end + + # Creates the url string to a specific Redmine issue + def issue(issue_id) + url + 'issues/' + issue_id.to_s + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0d6663388ad2e1df81d9f7719fa0c144a5b76d99.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0d6663388ad2e1df81d9f7719fa0c144a5b76d99.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/runner' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0da01fc24e804fb2e15e93cbb542b0add78e1cbc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0da01fc24e804fb2e15e93cbb542b0add78e1cbc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +<%= "#{issue.tracker.name} ##{issue.id}: #{issue.subject}" %> +<%= issue_url %> + +<%=l(:field_author)%>: <%= issue.author %> +<%=l(:field_status)%>: <%= issue.status %> +<%=l(:field_priority)%>: <%= issue.priority %> +<%=l(:field_assigned_to)%>: <%= issue.assigned_to %> +<%=l(:field_category)%>: <%= issue.category %> +<%=l(:field_fixed_version)%>: <%= issue.fixed_version %> +<% issue.custom_field_values.each do |c| %><%= c.custom_field.name %>: <%= show_value(c) %> +<% end %> + +<%= issue.description %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0dc6f2999aebfb473b433b9a22bddd8917c60616.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0dc6f2999aebfb473b433b9a22bddd8917c60616.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +# $Id: ldif.rb 78 2006-04-26 02:57:34Z blackhedd $ +# +# Net::LDIF for Ruby +# +# +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Gmail: garbagecat10 +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +# + +# THIS FILE IS A STUB. + +module Net + + class LDIF + + + end # class LDIF + + +end # module Net + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0d/0dec78f36b0f6507c2aa4e50dcd86ca0850c844a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0d/0dec78f36b0f6507c2aa4e50dcd86ca0850c844a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/test_helper' + +class OpenIdAuthenticationTest < Test::Unit::TestCase + def setup + @controller = Class.new do + include OpenIdAuthentication + def params() {} end + end.new + end + + def test_authentication_should_fail_when_the_identity_server_is_missing + open_id_consumer = mock() + open_id_consumer.expects(:begin).raises(OpenID::OpenIDError) + @controller.expects(:open_id_consumer).returns(open_id_consumer) + @controller.expects(:logger).returns(mock(:error => true)) + + @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| + assert result.missing? + assert_equal "Sorry, the OpenID server couldn't be found", result.message + end + end + + def test_authentication_should_be_invalid_when_the_identity_url_is_invalid + @controller.send(:authenticate_with_open_id, "!") do |result, identity_url| + assert result.invalid?, "Result expected to be invalid but was not" + assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message + end + end + + def test_authentication_should_fail_when_the_identity_server_times_out + open_id_consumer = mock() + open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.") + @controller.expects(:open_id_consumer).returns(open_id_consumer) + @controller.expects(:logger).returns(mock(:error => true)) + + @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| + assert result.missing? + assert_equal "Sorry, the OpenID server couldn't be found", result.message + end + end + + def test_authentication_should_begin_when_the_identity_server_is_present + @controller.expects(:begin_open_id_authentication) + @controller.send(:authenticate_with_open_id, "http://someone.example.com") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0e08d9f41b8e44a9cd63aac9bdb04868977fcdc7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0e/0e08d9f41b8e44a9cd63aac9bdb04868977fcdc7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRolesPermissions < ActiveRecord::Migration + def self.up + add_column :roles, :permissions, :text + end + + def self.down + remove_column :roles, :permissions + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0e34c14e6f20fb9c76bdc9d68c85bc777df8e1a9.svn-base Binary file .svn/pristine/0e/0e34c14e6f20fb9c76bdc9d68c85bc777df8e1a9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0e9e1072226f562ac691c9b0e43850580a4d42a6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0e/0e9e1072226f562ac691c9b0e43850580a4d42a6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +

<%= l(:label_spent_time) %>

+ +<% labelled_tabular_form_for(:time_entry, @time_entry, :url => { + :action => (@time_entry.new_record? ? 'create' : 'update'), + :id => @time_entry, + :project_id => @time_entry.project + }, + :html => {:method => @time_entry.new_record? ? :post : :put}) do |f| %> +<%= error_messages_for 'time_entry' %> +<%= back_url_hidden_field_tag %> + +
+

<%= f.text_field :issue_id, :size => 6 %> <%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %>

+

<%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %>

+

<%= f.text_field :hours, :size => 6, :required => true %>

+

<%= f.text_field :comments, :size => 100 %>

+

<%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %>

+<% @time_entry.custom_field_values.each do |value| %> +

<%= custom_field_tag_with_label :time_entry, value %>

+<% end %> +<%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %> +
+ +<%= submit_tag l(:button_save) %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0eacf75b8b3e6c5870bf462661ff3ac98d37c872.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0e/0eacf75b8b3e6c5870bf462661ff3ac98d37c872.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,143 @@ +-*-text-*- +$Id: AUTHORS,v 1.5 2003/10/08 12:22:24 peterlin Exp $ + +The free UCS scalable font collection is being maintained by Primo +Peterlin . The folowing list +cites the other contributors that contributed to particular ISO 10646 +blocks. + +# URW++ Design & Development GmbH + + Basic Latin (U+0041-U+007A) + Latin-1 Supplement (U+00C0-U+00FF) (most) + Latin Extended-A (U+0100-U+017F) + Spacing Modifier Letters (U+02B0-U+02FF) + Mathematical Operators (U+2200-U+22FF) (parts) + Block Elements (U+2580-U+259F) + Dingbats (U+2700-U+27BF) + +# Yannis Haralambous and John + Plaice + + Latin Extended-B (U+0180-U+024F) + IPA Extensions (U+0250-U+02AF) + Greek (U+0370-U+03FF) + Armenian (U+0530-U+058F) + Hebrew (U+0590-U+05FF) + Arabic (U+0600-U+06FF) + Currency Symbols (U+20A0-U+20CF) + Arabic Presentation Forms-A (U+FB50-U+FDFF) + Arabic Presentation Forms-B (U+FE70-U+FEFF) + +# Young U. Ryu + + Arrows (U+2190-U+21FF) + Mathematical Symbols (U+2200-U+22FF) + +# Valek Filippov + + Cyrillic (U+0400-U+04FF) + +# Wadalab Kanji Comittee + + Hiragana (U+3040-U+309F) + Katakana (U+30A0-U+30FF) + +# Angelo Haritsis + + Greek (U+0370-U+03FF) + +# Yannis Haralambous and Virach Sornlertlamvanich + + Thai (U+0E00-U+0E7F) + +# Shaheed R. Haque + + Bengali (U+0980-U+09FF) + +# Sam Stepanyan + + Armenian (U+0530-U+058F) + +# Mohamed Ishan + + Thaana (U+0780-U+07BF) + +# Sushant Kumar Dash + + Oriya (U+0B00-U+0B7F) + +# Harsh Kumar + + Devanagari (U+0900-U+097F) + Bengali (U+0980-U+09FF) + Gurmukhi (U+0A00-U+0A7F) + Gujarati (U+0A80-U+0AFF) + +# Prasad A. Chodavarapu + + Telugu (U+0C00-U+0C7F) + +# Frans Velthuis and Anshuman Pandey + + + Devanagari (U+0900-U+097F) + +# Hardip Singh Pannu + + Gurmukhi (U+0A00-U+0A7F) + +# Jeroen Hellingman + + Oriya (U+0B00-U+0B7F) + Malayalam (U+0D00-U+0D7F) + +# Thomas Ridgeway + + Tamil (U+0B80-U+0BFF) + +# Berhanu Beyene <1beyene AT informatik.uni-hamburg.de>, + Prof. Dr. Manfred Kudlek , Olaf + Kummer , and Jochen Metzinger < + + Ethiopic (U+1200-U+137F) + +# Maxim Iorsh + + Hebrew (U+0590-U+05FF) + + +# Vyacheslav Dikonov + + Syriac (U+0700-U+074A) + Braille (U+2800-U+28FF) + +# M.S. Sridhar + + Devanagari (U+0900-U+097F) + Bengali (U+0980-U+09FF) + Gurmukhi (U+0A00-U+0A7F) + Gujarati (U+0A80-U+0AFF) + Oriya (U+0B00-U+0B7F) + Tamil (U+0B80-U+0BFF) + Telugu (U+0C00-U+0C7F) + Kannada (U+0C80-U+0CFF) + Malayalam (U+0D00-U+0D7F) + +# DMS Electronics, The Sri Lanka Tipitaka Project, and Noah Levitt + + + Sinhala (U+0D80-U+0DFF) + +# Dan Shurovich Chirkov + + Cyrillic (U+0400-U+04FF) + +# Abbas Izad + + Arabic (U+0600-U+06FF) + Arabic Presentation Forms-A (U+FB50-U+FDFF) + Arabic Presentation Forms-B (U+FE70-U+FEFF) + +Please see the CREDITS file for details on who contributed particular +subsets of the glyphs in font files. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0eb7cc8a4d0dacf34d7ebb20ac1b776d16812b39.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0e/0eb7cc8a4d0dacf34d7ebb20ac1b776d16812b39.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,225 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!85 U+2026 ellipsis +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0ee15adcf36536c48b6695748041d2c5e43cb26a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0e/0ee15adcf36536c48b6695748041d2c5e43cb26a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,255 @@ +module CodeRay +module Scanners + + load :java + + # Scanner for Groovy. + class Groovy < Java + + register_for :groovy + + # TODO: check list of keywords + GROOVY_KEYWORDS = %w[ + as assert def in + ] # :nodoc: + KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ + case instanceof new return throw typeof while as assert in + ] # :nodoc: + GROOVY_MAGIC_VARIABLES = %w[ it ] # :nodoc: + + IDENT_KIND = Java::IDENT_KIND.dup. + add(GROOVY_KEYWORDS, :keyword). + add(GROOVY_MAGIC_VARIABLES, :local_variable) # :nodoc: + + ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: no 4-byte unicode chars? U[a-fA-F0-9]{8} + REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x # :nodoc: + + # TODO: interpretation inside ', ", / + STRING_CONTENT_PATTERN = { + "'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/, + '"' => /[^\\$"\n]+/, + "'''" => /(?>[^\\']+|'(?!''))+/, + '"""' => /(?>[^\\$"]+|"(?!""))+/, + '/' => /[^\\$\/\n]+/, + } # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + inline_block_stack = [] + inline_block_paren_depth = nil + string_delimiter = nil + import_clause = class_name_follows = last_token = after_def = false + value_expected = true + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + if match.index ?\n + import_clause = after_def = false + value_expected = true unless value_expected + end + next + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + value_expected = true + after_def = false + encoder.text_token match, :comment + + elsif bol? && match = scan(/ \#!.* /x) + encoder.text_token match, :doctype + + elsif import_clause && match = scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox) + after_def = value_expected = false + encoder.text_token match, :include + + elsif match = scan(/ #{IDENT} | \[\] /ox) + kind = IDENT_KIND[match] + value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] + if last_token == '.' + kind = :ident + elsif class_name_follows + kind = :class + class_name_follows = false + elsif after_def && check(/\s*[({]/) + kind = :method + after_def = false + elsif kind == :ident && last_token != '?' && check(/:/) + kind = :key + else + class_name_follows = true if match == 'class' || (import_clause && match == 'as') + import_clause = match == 'import' + after_def = true if match == 'def' + end + encoder.text_token match, kind + + elsif match = scan(/;/) + import_clause = after_def = false + value_expected = true + encoder.text_token match, :operator + + elsif match = scan(/\{/) + class_name_follows = after_def = false + value_expected = true + encoder.text_token match, :operator + if !inline_block_stack.empty? + inline_block_paren_depth += 1 + end + + # TODO: ~'...', ~"..." and ~/.../ style regexps + elsif match = scan(/ \.\.] | \+\+ | + && | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<>>?=? /x) + value_expected = true + value_expected = :regexp if match == '~' + after_def = false + encoder.text_token match, :operator + + elsif match = scan(/ [)\]}] /x) + value_expected = after_def = false + if !inline_block_stack.empty? && match == '}' + inline_block_paren_depth -= 1 + if inline_block_paren_depth == 0 # closing brace of inline block reached + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop + next + end + end + encoder.text_token match, :operator + + elsif check(/[\d.]/) + after_def = value_expected = false + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) + encoder.text_token match, :float + elsif match = scan(/\d+[lLgG]?/) + encoder.text_token match, :integer + end + + elsif match = scan(/'''|"""/) + after_def = value_expected = false + state = :multiline_string + encoder.begin_group :string + string_delimiter = match + encoder.text_token match, :delimiter + + # TODO: record.'name' syntax + elsif match = scan(/["']/) + after_def = value_expected = false + state = match == '/' ? :regexp : :string + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif value_expected && match = scan(/\//) + after_def = value_expected = false + encoder.begin_group :regexp + state = :regexp + string_delimiter = '/' + encoder.text_token match, :delimiter + + elsif match = scan(/ @ #{IDENT} /ox) + after_def = value_expected = false + encoder.text_token match, :annotation + + elsif match = scan(/\//) + after_def = false + value_expected = true + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + when :string, :regexp, :multiline_string + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + + elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/) + encoder.text_token match, :delimiter + if state == :regexp + # TODO: regexp modifiers? s, m, x, i? + modifiers = scan(/[ix]+/) + encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty? + end + state = :string if state == :multiline_string + encoder.end_group state + string_delimiter = nil + after_def = value_expected = false + state = :initial + next + + elsif (state == :string || state == :multiline_string) && + (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif state == :regexp && match = scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + + elsif match = scan(/ \$ #{IDENT} /mox) + encoder.begin_group :inline + encoder.text_token '$', :inline_delimiter + match = match[1..-1] + encoder.text_token match, IDENT_KIND[match] + encoder.end_group :inline + next + elsif match = scan(/ \$ \{ /x) + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + inline_block_stack << [state, string_delimiter, inline_block_paren_depth] + inline_block_paren_depth = 1 + state = :initial + next + + elsif match = scan(/ \$ /mx) + encoder.text_token match, :content + + elsif match = scan(/ \\. /mx) + encoder.text_token match, :content # TODO: Shouldn't this be :error? + + elsif match = scan(/ \\ | \n /x) + encoder.end_group state + encoder.text_token match, :error + after_def = value_expected = false + state = :initial + + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + + end + + else + raise_inspect 'Unknown state', encoder + + end + + last_token = match unless [:space, :comment, :doctype].include? kind + + end + + if [:multiline_string, :string, :regexp].include? state + encoder.end_group state + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0ee222eff2b16f026f0f817fdf32372447c6e7e8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0e/0ee222eff2b16f026f0f817fdf32372447c6e7e8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class ProjectsTest < ActionController::IntegrationTest + fixtures :projects, :users, :members + + def test_archive_project + subproject = Project.find(1).children.first + log_user("admin", "admin") + get "admin/projects" + assert_response :success + assert_template "admin/projects" + post "projects/archive", :id => 1 + assert_redirected_to "/admin/projects" + assert !Project.find(1).active? + + get 'projects/1' + assert_response 403 + get "projects/#{subproject.id}" + assert_response 403 + + post "projects/unarchive", :id => 1 + assert_redirected_to "/admin/projects" + assert Project.find(1).active? + get "projects/1" + assert_response :success + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0e/0ef99b09fb86deecc2f7d49dd96b01429edf06cb.svn-base Binary file .svn/pristine/0e/0ef99b09fb86deecc2f7d49dd96b01429edf06cb.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0f12084a6a3192cb0d61cbd2f3ef681df419cac4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0f12084a6a3192cb0d61cbd2f3ef681df419cac4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,104 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Message < ActiveRecord::Base + belongs_to :board + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" + acts_as_attachable + belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id' + + acts_as_searchable :columns => ['subject', 'content'], + :include => {:board => :project}, + :project_key => "#{Board.table_name}.project_id", + :date_column => "#{table_name}.created_on" + acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, + :description => :content, + :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'}, + :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} : + {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})} + + acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}, + :author_key => :author_id + acts_as_watchable + + attr_protected :locked, :sticky + validates_presence_of :board, :subject, :content + validates_length_of :subject, :maximum => 255 + validate :cannot_reply_to_locked_topic, :on => :create + + after_create :add_author_as_watcher, :update_parent_last_reply + after_update :update_messages_board + after_destroy :reset_board_counters + + named_scope :visible, lambda {|*args| { :include => {:board => :project}, + :conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } } + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_messages, project) + end + + def cannot_reply_to_locked_topic + # Can not reply to a locked topic + errors.add :base, 'Topic is locked' if root.locked? && self != root + end + + def update_parent_last_reply + if parent + parent.reload.update_attribute(:last_reply_id, self.id) + end + board.reset_counters! + end + + def update_messages_board + if board_id_changed? + Message.update_all("board_id = #{board_id}", ["id = ? OR parent_id = ?", root.id, root.id]) + Board.reset_counters!(board_id_was) + Board.reset_counters!(board_id) + end + end + + def reset_board_counters + board.reset_counters! + end + + def sticky=(arg) + write_attribute :sticky, (arg == true || arg.to_s == '1' ? 1 : 0) + end + + def sticky? + sticky == 1 + end + + def project + board.project + end + + def editable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project))) + end + + def destroyable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:delete_messages, project) || (self.author == usr && usr.allowed_to?(:delete_own_messages, project))) + end + + private + + def add_author_as_watcher + Watcher.create(:watchable => self.root, :user => author) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0f55ca10803bce4cf5a650e17d0e04f01a9b964d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0f55ca10803bce4cf5a650e17d0e04f01a9b964d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,48 @@ +
+<% if @group.users.any? %> + + + + + + + <% @group.users.sort.each do |user| %> + + + + + <% end %> + +
<%= l(:label_user) %>
<%= link_to_user user %> + <%= link_to_remote l(:button_delete), { :url => group_user_path(@group, :user_id => user), :method => :delete }, :class => 'icon icon-del' %> +
+<% else %> +

<%= l(:label_no_data) %>

+<% end %> +
+ +
+<% users = User.active.not_in_group(@group).all(:limit => 100) %> +<% if users.any? %> + <% remote_form_for(@group, :url => group_users_path(@group), :html => {:method => :post}) do |f| %> +
<%=l(:label_user_new)%> + +

<%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

+ <%= observe_field(:user_search, + :frequency => 0.5, + :update => :users, + :url => autocomplete_for_user_group_path(@group), + :method => :get, + :with => 'q') + %> + +
+ <%= principals_check_box_tags 'user_ids[]', users %> +
+ +

<%= submit_tag l(:button_add) %>

+
+ <% end %> +<% end %> + +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0f5d0b28aa88dc0b634f0aed6c20653f95af7206.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0f5d0b28aa88dc0b634f0aed6c20653f95af7206.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,141 @@ +module CodeRay + + # = FileType + # + # A simple filetype recognizer. + # + # == Usage + # + # # determine the type of the given + # lang = FileType[file_name] + # + # # return :text if the file type is unknown + # lang = FileType.fetch file_name, :text + # + # # try the shebang line, too + # lang = FileType.fetch file_name, :text, true + module FileType + + UnknownFileType = Class.new Exception + + class << self + + # Try to determine the file type of the file. + # + # +filename+ is a relative or absolute path to a file. + # + # The file itself is only accessed when +read_shebang+ is set to true. + # That means you can get filetypes from files that don't exist. + def [] filename, read_shebang = false + name = File.basename filename + ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot + ext2 = filename.to_s[/\.(.*)/, 1] # from first dot + + type = + TypeFromExt[ext] || + TypeFromExt[ext.downcase] || + (TypeFromExt[ext2] if ext2) || + (TypeFromExt[ext2.downcase] if ext2) || + TypeFromName[name] || + TypeFromName[name.downcase] + type ||= shebang(filename) if read_shebang + + type + end + + # This works like Hash#fetch. + # + # If the filetype cannot be found, the +default+ value + # is returned. + def fetch filename, default = nil, read_shebang = false + if default && block_given? + warn 'Block supersedes default value argument; use either.' + end + + if type = self[filename, read_shebang] + type + else + return yield if block_given? + return default if default + raise UnknownFileType, 'Could not determine type of %p.' % filename + end + end + + protected + + def shebang filename + return unless File.exist? filename + File.open filename, 'r' do |f| + if first_line = f.gets + if type = first_line[TypeFromShebang] + type.to_sym + end + end + end + end + + end + + TypeFromExt = { + 'c' => :c, + 'cfc' => :xml, + 'cfm' => :xml, + 'clj' => :clojure, + 'css' => :css, + 'diff' => :diff, + 'dpr' => :delphi, + 'gemspec' => :ruby, + 'groovy' => :groovy, + 'gvy' => :groovy, + 'h' => :c, + 'haml' => :haml, + 'htm' => :page, + 'html' => :page, + 'html.erb' => :erb, + 'java' => :java, + 'js' => :java_script, + 'json' => :json, + 'mab' => :ruby, + 'pas' => :delphi, + 'patch' => :diff, + 'php' => :php, + 'php3' => :php, + 'php4' => :php, + 'php5' => :php, + 'prawn' => :ruby, + 'py' => :python, + 'py3' => :python, + 'pyw' => :python, + 'rake' => :ruby, + 'raydebug' => :raydebug, + 'rb' => :ruby, + 'rbw' => :ruby, + 'rhtml' => :erb, + 'rjs' => :ruby, + 'rpdf' => :ruby, + 'ru' => :ruby, + 'rxml' => :ruby, + # 'sch' => :scheme, + 'sql' => :sql, + # 'ss' => :scheme, + 'xhtml' => :page, + 'xml' => :xml, + 'yaml' => :yaml, + 'yml' => :yaml, + } + for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu] + TypeFromExt[cpp_alias] = :cpp + end + + TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/ + + TypeFromName = { + 'Capfile' => :ruby, + 'Rakefile' => :ruby, + 'Rantfile' => :ruby, + 'Gemfile' => :ruby, + } + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0f71516e3a6532ada8045e94e42972a11451afc4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0f71516e3a6532ada8045e94e42972a11451afc4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,36 @@ +class CommentsController < ApplicationController + default_search_scope :news + model_object News + before_filter :find_model_object + before_filter :find_project_from_association + before_filter :authorize + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create + @comment = Comment.new(params[:comment]) + @comment.author = User.current + if @news.comments << @comment + flash[:notice] = l(:label_comment_added) + end + + redirect_to :controller => 'news', :action => 'show', :id => @news + end + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } + def destroy + @news.comments.find(params[:comment_id]).destroy + redirect_to :controller => 'news', :action => 'show', :id => @news + end + + private + + # ApplicationController's find_model_object sets it based on the controller + # name so it needs to be overriden and set to @news instead + def find_model_object + super + @news = @object + @comment = nil + @news + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0f842304e58a7a419abba90bd185840b383c9907.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0f842304e58a7a419abba90bd185840b383c9907.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +module Engines + class Plugin + class FileSystemLocator < Rails::Plugin::FileSystemLocator + def create_plugin(path) + plugin = Engines::Plugin.new(path) + plugin.valid? ? plugin : nil + end + end + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0f8c9a445e6d91ddf83b84884895ce07bce0d526.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0f8c9a445e6d91ddf83b84884895ce07bce0d526.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddProjectStatus < ActiveRecord::Migration + def self.up + add_column :projects, :status, :integer, :default => 1, :null => false + end + + def self.down + remove_column :projects, :status + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0fa8b994f508f388585e802196325aae4a4107f7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0fa8b994f508f388585e802196325aae4a4107f7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +<%= error_messages_for 'user' %> + +
+ +
+
+ <%=l(:label_information_plural)%> +

<%= f.text_field :login, :required => true, :size => 25 %>

+

<%= f.text_field :firstname, :required => true %>

+

<%= f.text_field :lastname, :required => true %>

+

<%= f.text_field :mail, :required => true %>

+

<%= f.select :language, lang_options_for_select %>

+ <% if Setting.openid? %> +

<%= f.text_field :identity_url %>

+ <% end %> + + <% @user.custom_field_values.each do |value| %> +

<%= custom_field_tag_with_label :user, value %>

+ <% end %> + +

<%= f.check_box :admin, :disabled => (@user == User.current) %>

+ <%= call_hook(:view_users_form, :user => @user, :form => f) %> +
+ +
+ <%=l(:label_authentication)%> + <% unless @auth_sources.empty? %> +

<%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {Element.show('password_fields');} else {Element.hide('password_fields');}" %>

+ <% end %> +
+

<%= f.password_field :password, :required => true, :size => 25 %>
+ <%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

+

<%= f.password_field :password_confirmation, :required => true, :size => 25 %>

+
+
+
+ +
+
+ <%=l(:field_mail_notification)%> + <%= render :partial => 'users/mail_notifications' %> +
+ +
+ <%=l(:label_preferences)%> + <%= render :partial => 'users/preferences' %> +
+
+
+
+ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0fd45ffc205637b86a8a066d7efda723815c1464.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0fd45ffc205637b86a8a066d7efda723815c1464.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,61 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'settings_controller' + +# Re-raise errors caught by the controller. +class SettingsController; def rescue_action(e) raise e end; end + +class SettingsControllerTest < ActionController::TestCase + fixtures :users + + def setup + @controller = SettingsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 1 # admin + end + + def test_index + get :index + assert_response :success + assert_template 'edit' + end + + def test_get_edit + get :edit + assert_response :success + assert_template 'edit' + + assert_tag 'input', :attributes => {:name => 'settings[enabled_scm][]', :value => ''} + end + + def test_post_edit_notifications + post :edit, :settings => {:mail_from => 'functional@test.foo', + :bcc_recipients => '0', + :notified_events => %w(issue_added issue_updated news_added), + :emails_footer => 'Test footer' + } + assert_redirected_to '/settings/edit' + assert_equal 'functional@test.foo', Setting.mail_from + assert !Setting.bcc_recipients? + assert_equal %w(issue_added issue_updated news_added), Setting.notified_events + assert_equal 'Test footer', Setting.emails_footer + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/0f/0ff0bfae04ec7a8241921bdb8bb6771c6ffcd5d9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/0f/0ff0bfae04ec7a8241921bdb8bb6771c6ffcd5d9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +api.version do + api.id @version.id + api.project(:id => @version.project_id, :name => @version.project.name) unless @version.project.nil? + + api.name @version.name + api.description @version.description + api.status @version.status + api.due_date @version.effective_date + + render_api_custom_values @version.custom_field_values, api + + api.created_on @version.created_on + api.updated_on @version.updated_on +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/1048cea83e08be09288d325f5a2d1908b807f592.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/1048cea83e08be09288d325f5a2d1908b807f592.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,860 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Helpers + # Simple class to handle gantt chart data + class Gantt + include ERB::Util + include Redmine::I18n + + # :nodoc: + # Some utility methods for the PDF export + class PDF + MaxCharactorsForSubject = 45 + TotalWidth = 280 + LeftPaneWidth = 100 + + def self.right_pane_width + TotalWidth - LeftPaneWidth + end + end + + attr_reader :year_from, :month_from, :date_from, :date_to, :zoom, :months, :truncated, :max_rows + attr_accessor :query + attr_accessor :project + attr_accessor :view + + def initialize(options={}) + options = options.dup + + if options[:year] && options[:year].to_i >0 + @year_from = options[:year].to_i + if options[:month] && options[:month].to_i >=1 && options[:month].to_i <= 12 + @month_from = options[:month].to_i + else + @month_from = 1 + end + else + @month_from ||= Date.today.month + @year_from ||= Date.today.year + end + + zoom = (options[:zoom] || User.current.pref[:gantt_zoom]).to_i + @zoom = (zoom > 0 && zoom < 5) ? zoom : 2 + months = (options[:months] || User.current.pref[:gantt_months]).to_i + @months = (months > 0 && months < 25) ? months : 6 + + # Save gantt parameters as user preference (zoom and months count) + if (User.current.logged? && (@zoom != User.current.pref[:gantt_zoom] || @months != User.current.pref[:gantt_months])) + User.current.pref[:gantt_zoom], User.current.pref[:gantt_months] = @zoom, @months + User.current.preference.save + end + + @date_from = Date.civil(@year_from, @month_from, 1) + @date_to = (@date_from >> @months) - 1 + + @subjects = '' + @lines = '' + @number_of_rows = nil + + @issue_ancestors = [] + + @truncated = false + if options.has_key?(:max_rows) + @max_rows = options[:max_rows] + else + @max_rows = Setting.gantt_items_limit.blank? ? nil : Setting.gantt_items_limit.to_i + end + end + + def common_params + { :controller => 'gantts', :action => 'show', :project_id => @project } + end + + def params + common_params.merge({ :zoom => zoom, :year => year_from, :month => month_from, :months => months }) + end + + def params_previous + common_params.merge({:year => (date_from << months).year, :month => (date_from << months).month, :zoom => zoom, :months => months }) + end + + def params_next + common_params.merge({:year => (date_from >> months).year, :month => (date_from >> months).month, :zoom => zoom, :months => months }) + end + + # Returns the number of rows that will be rendered on the Gantt chart + def number_of_rows + return @number_of_rows if @number_of_rows + + rows = projects.inject(0) {|total, p| total += number_of_rows_on_project(p)} + rows > @max_rows ? @max_rows : rows + end + + # Returns the number of rows that will be used to list a project on + # the Gantt chart. This will recurse for each subproject. + def number_of_rows_on_project(project) + return 0 unless projects.include?(project) + + count = 1 + count += project_issues(project).size + count += project_versions(project).size + count + end + + # Renders the subjects of the Gantt chart, the left side. + def subjects(options={}) + render(options.merge(:only => :subjects)) unless @subjects_rendered + @subjects + end + + # Renders the lines of the Gantt chart, the right side + def lines(options={}) + render(options.merge(:only => :lines)) unless @lines_rendered + @lines + end + + # Returns issues that will be rendered + def issues + @issues ||= @query.issues( + :include => [:assigned_to, :tracker, :priority, :category, :fixed_version], + :order => "#{Project.table_name}.lft ASC, #{Issue.table_name}.id ASC", + :limit => @max_rows + ) + end + + # Return all the project nodes that will be displayed + def projects + return @projects if @projects + + ids = issues.collect(&:project).uniq.collect(&:id) + if ids.any? + # All issues projects and their visible ancestors + @projects = Project.visible.all( + :joins => "LEFT JOIN #{Project.table_name} child ON #{Project.table_name}.lft <= child.lft AND #{Project.table_name}.rgt >= child.rgt", + :conditions => ["child.id IN (?)", ids], + :order => "#{Project.table_name}.lft ASC" + ).uniq + else + @projects = [] + end + end + + # Returns the issues that belong to +project+ + def project_issues(project) + @issues_by_project ||= issues.group_by(&:project) + @issues_by_project[project] || [] + end + + # Returns the distinct versions of the issues that belong to +project+ + def project_versions(project) + project_issues(project).collect(&:fixed_version).compact.uniq + end + + # Returns the issues that belong to +project+ and are assigned to +version+ + def version_issues(project, version) + project_issues(project).select {|issue| issue.fixed_version == version} + end + + def render(options={}) + options = {:top => 0, :top_increment => 20, :indent_increment => 20, :render => :subject, :format => :html}.merge(options) + indent = options[:indent] || 4 + + @subjects = '' unless options[:only] == :lines + @lines = '' unless options[:only] == :subjects + @number_of_rows = 0 + + Project.project_tree(projects) do |project, level| + options[:indent] = indent + level * options[:indent_increment] + render_project(project, options) + break if abort? + end + + @subjects_rendered = true unless options[:only] == :lines + @lines_rendered = true unless options[:only] == :subjects + + render_end(options) + end + + def render_project(project, options={}) + subject_for_project(project, options) unless options[:only] == :lines + line_for_project(project, options) unless options[:only] == :subjects + + options[:top] += options[:top_increment] + options[:indent] += options[:indent_increment] + @number_of_rows += 1 + return if abort? + + issues = project_issues(project).select {|i| i.fixed_version.nil?} + sort_issues!(issues) + if issues + render_issues(issues, options) + return if abort? + end + + versions = project_versions(project) + versions.each do |version| + render_version(project, version, options) + end + + # Remove indent to hit the next sibling + options[:indent] -= options[:indent_increment] + end + + def render_issues(issues, options={}) + @issue_ancestors = [] + + issues.each do |i| + subject_for_issue(i, options) unless options[:only] == :lines + line_for_issue(i, options) unless options[:only] == :subjects + + options[:top] += options[:top_increment] + @number_of_rows += 1 + break if abort? + end + + options[:indent] -= (options[:indent_increment] * @issue_ancestors.size) + end + + def render_version(project, version, options={}) + # Version header + subject_for_version(version, options) unless options[:only] == :lines + line_for_version(version, options) unless options[:only] == :subjects + + options[:top] += options[:top_increment] + @number_of_rows += 1 + return if abort? + + issues = version_issues(project, version) + if issues + sort_issues!(issues) + # Indent issues + options[:indent] += options[:indent_increment] + render_issues(issues, options) + options[:indent] -= options[:indent_increment] + end + end + + def render_end(options={}) + case options[:format] + when :pdf + options[:pdf].Line(15, options[:top], PDF::TotalWidth, options[:top]) + end + end + + def subject_for_project(project, options) + case options[:format] + when :html + subject = "".html_safe + subject << view.link_to_project(project).html_safe + subject << ''.html_safe + html_subject(options, subject, :css => "project-name") + when :image + image_subject(options, project.name) + when :pdf + pdf_new_page?(options) + pdf_subject(options, project.name) + end + end + + def line_for_project(project, options) + # Skip versions that don't have a start_date or due date + if project.is_a?(Project) && project.start_date && project.due_date + options[:zoom] ||= 1 + options[:g_width] ||= (self.date_to - self.date_from + 1) * options[:zoom] + + coords = coordinates(project.start_date, project.due_date, nil, options[:zoom]) + label = h(project) + + case options[:format] + when :html + html_task(options, coords, :css => "project task", :label => label, :markers => true) + when :image + image_task(options, coords, :label => label, :markers => true, :height => 3) + when :pdf + pdf_task(options, coords, :label => label, :markers => true, :height => 0.8) + end + else + ActiveRecord::Base.logger.debug "Gantt#line_for_project was not given a project with a start_date" + '' + end + end + + def subject_for_version(version, options) + case options[:format] + when :html + subject = "".html_safe + subject << view.link_to_version(version).html_safe + subject << ''.html_safe + html_subject(options, subject, :css => "version-name") + when :image + image_subject(options, version.to_s_with_project) + when :pdf + pdf_new_page?(options) + pdf_subject(options, version.to_s_with_project) + end + end + + def line_for_version(version, options) + # Skip versions that don't have a start_date + if version.is_a?(Version) && version.start_date && version.due_date + options[:zoom] ||= 1 + options[:g_width] ||= (self.date_to - self.date_from + 1) * options[:zoom] + + coords = coordinates(version.start_date, version.due_date, version.completed_pourcent, options[:zoom]) + label = "#{h version } #{h version.completed_pourcent.to_i.to_s}%" + label = h("#{version.project} -") + label unless @project && @project == version.project + + case options[:format] + when :html + html_task(options, coords, :css => "version task", :label => label, :markers => true) + when :image + image_task(options, coords, :label => label, :markers => true, :height => 3) + when :pdf + pdf_task(options, coords, :label => label, :markers => true, :height => 0.8) + end + else + ActiveRecord::Base.logger.debug "Gantt#line_for_version was not given a version with a start_date" + '' + end + end + + def subject_for_issue(issue, options) + while @issue_ancestors.any? && !issue.is_descendant_of?(@issue_ancestors.last) + @issue_ancestors.pop + options[:indent] -= options[:indent_increment] + end + + output = case options[:format] + when :html + css_classes = '' + css_classes << ' issue-overdue' if issue.overdue? + css_classes << ' issue-behind-schedule' if issue.behind_schedule? + css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to + + subject = "".html_safe + if issue.assigned_to.present? + assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name + subject << view.avatar(issue.assigned_to, :class => 'gravatar icon-gravatar', :size => 10, :title => assigned_string).to_s.html_safe + end + subject << view.link_to_issue(issue).html_safe + subject << ''.html_safe + html_subject(options, subject, :css => "issue-subject", :title => issue.subject) + "\n" + when :image + image_subject(options, issue.subject) + when :pdf + pdf_new_page?(options) + pdf_subject(options, issue.subject) + end + + unless issue.leaf? + @issue_ancestors << issue + options[:indent] += options[:indent_increment] + end + + output + end + + def line_for_issue(issue, options) + # Skip issues that don't have a due_before (due_date or version's due_date) + if issue.is_a?(Issue) && issue.due_before + coords = coordinates(issue.start_date, issue.due_before, issue.done_ratio, options[:zoom]) + label = "#{ issue.status.name } #{ issue.done_ratio }%" + + case options[:format] + when :html + html_task(options, coords, :css => "task " + (issue.leaf? ? 'leaf' : 'parent'), :label => label, :issue => issue, :markers => !issue.leaf?) + when :image + image_task(options, coords, :label => label) + when :pdf + pdf_task(options, coords, :label => label) + end + else + ActiveRecord::Base.logger.debug "GanttHelper#line_for_issue was not given an issue with a due_before" + '' + end + end + + # Generates a gantt image + # Only defined if RMagick is avalaible + def to_image(format='PNG') + date_to = (@date_from >> @months)-1 + show_weeks = @zoom > 1 + show_days = @zoom > 2 + + subject_width = 400 + header_height = 18 + # width of one day in pixels + zoom = @zoom*2 + g_width = (@date_to - @date_from + 1)*zoom + g_height = 20 * number_of_rows + 30 + headers_height = (show_weeks ? 2*header_height : header_height) + height = g_height + headers_height + + imgl = Magick::ImageList.new + imgl.new_image(subject_width+g_width+1, height) + gc = Magick::Draw.new + + # Subjects + gc.stroke('transparent') + subjects(:image => gc, :top => (headers_height + 20), :indent => 4, :format => :image) + + # Months headers + month_f = @date_from + left = subject_width + @months.times do + width = ((month_f >> 1) - month_f) * zoom + gc.fill('white') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(left, 0, left + width, height) + gc.fill('black') + gc.stroke('transparent') + gc.stroke_width(1) + gc.text(left.round + 8, 14, "#{month_f.year}-#{month_f.month}") + left = left + width + month_f = month_f >> 1 + end + + # Weeks headers + if show_weeks + left = subject_width + height = header_height + if @date_from.cwday == 1 + # date_from is monday + week_f = date_from + else + # find next monday after date_from + week_f = @date_from + (7 - @date_from.cwday + 1) + width = (7 - @date_from.cwday + 1) * zoom + gc.fill('white') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(left, header_height, left + width, 2*header_height + g_height-1) + left = left + width + end + while week_f <= date_to + width = (week_f + 6 <= date_to) ? 7 * zoom : (date_to - week_f + 1) * zoom + gc.fill('white') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(left.round, header_height, left.round + width, 2*header_height + g_height-1) + gc.fill('black') + gc.stroke('transparent') + gc.stroke_width(1) + gc.text(left.round + 2, header_height + 14, week_f.cweek.to_s) + left = left + width + week_f = week_f+7 + end + end + + # Days details (week-end in grey) + if show_days + left = subject_width + height = g_height + header_height - 1 + wday = @date_from.cwday + (date_to - @date_from + 1).to_i.times do + width = zoom + gc.fill(wday == 6 || wday == 7 ? '#eee' : 'white') + gc.stroke('#ddd') + gc.stroke_width(1) + gc.rectangle(left, 2*header_height, left + width, 2*header_height + g_height-1) + left = left + width + wday = wday + 1 + wday = 1 if wday > 7 + end + end + + # border + gc.fill('transparent') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(0, 0, subject_width+g_width, headers_height) + gc.stroke('black') + gc.rectangle(0, 0, subject_width+g_width, g_height+ headers_height-1) + + # content + top = headers_height + 20 + + gc.stroke('transparent') + lines(:image => gc, :top => top, :zoom => zoom, :subject_width => subject_width, :format => :image) + + # today red line + if Date.today >= @date_from and Date.today <= date_to + gc.stroke('red') + x = (Date.today-@date_from+1)*zoom + subject_width + gc.line(x, headers_height, x, headers_height + g_height-1) + end + + gc.draw(imgl) + imgl.format = format + imgl.to_blob + end if Object.const_defined?(:Magick) + + def to_pdf + pdf = ::Redmine::Export::PDF::ITCPDF.new(current_language) + pdf.SetTitle("#{l(:label_gantt)} #{project}") + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage("L") + pdf.SetFontStyle('B',12) + pdf.SetX(15) + pdf.RDMCell(PDF::LeftPaneWidth, 20, project.to_s) + pdf.Ln + pdf.SetFontStyle('B',9) + + subject_width = PDF::LeftPaneWidth + header_height = 5 + + headers_height = header_height + show_weeks = false + show_days = false + + if self.months < 7 + show_weeks = true + headers_height = 2*header_height + if self.months < 3 + show_days = true + headers_height = 3*header_height + end + end + + g_width = PDF.right_pane_width + zoom = (g_width) / (self.date_to - self.date_from + 1) + g_height = 120 + t_height = g_height + headers_height + + y_start = pdf.GetY + + # Months headers + month_f = self.date_from + left = subject_width + height = header_height + self.months.times do + width = ((month_f >> 1) - month_f) * zoom + pdf.SetY(y_start) + pdf.SetX(left) + pdf.RDMCell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") + left = left + width + month_f = month_f >> 1 + end + + # Weeks headers + if show_weeks + left = subject_width + height = header_height + if self.date_from.cwday == 1 + # self.date_from is monday + week_f = self.date_from + else + # find next monday after self.date_from + week_f = self.date_from + (7 - self.date_from.cwday + 1) + width = (7 - self.date_from.cwday + 1) * zoom-1 + pdf.SetY(y_start + header_height) + pdf.SetX(left) + pdf.RDMCell(width + 1, height, "", "LTR") + left = left + width+1 + end + while week_f <= self.date_to + width = (week_f + 6 <= self.date_to) ? 7 * zoom : (self.date_to - week_f + 1) * zoom + pdf.SetY(y_start + header_height) + pdf.SetX(left) + pdf.RDMCell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C") + left = left + width + week_f = week_f+7 + end + end + + # Days headers + if show_days + left = subject_width + height = header_height + wday = self.date_from.cwday + pdf.SetFontStyle('B',7) + (self.date_to - self.date_from + 1).to_i.times do + width = zoom + pdf.SetY(y_start + 2 * header_height) + pdf.SetX(left) + pdf.RDMCell(width, height, day_name(wday).first, "LTR", 0, "C") + left = left + width + wday = wday + 1 + wday = 1 if wday > 7 + end + end + + pdf.SetY(y_start) + pdf.SetX(15) + pdf.RDMCell(subject_width+g_width-15, headers_height, "", 1) + + # Tasks + top = headers_height + y_start + options = { + :top => top, + :zoom => zoom, + :subject_width => subject_width, + :g_width => g_width, + :indent => 0, + :indent_increment => 5, + :top_increment => 5, + :format => :pdf, + :pdf => pdf + } + render(options) + pdf.Output + end + + private + + def coordinates(start_date, end_date, progress, zoom=nil) + zoom ||= @zoom + + coords = {} + if start_date && end_date && start_date < self.date_to && end_date > self.date_from + if start_date > self.date_from + coords[:start] = start_date - self.date_from + coords[:bar_start] = start_date - self.date_from + else + coords[:bar_start] = 0 + end + if end_date < self.date_to + coords[:end] = end_date - self.date_from + coords[:bar_end] = end_date - self.date_from + 1 + else + coords[:bar_end] = self.date_to - self.date_from + 1 + end + + if progress + progress_date = start_date + (end_date - start_date + 1) * (progress / 100.0) + if progress_date > self.date_from && progress_date > start_date + if progress_date < self.date_to + coords[:bar_progress_end] = progress_date - self.date_from + else + coords[:bar_progress_end] = self.date_to - self.date_from + 1 + end + end + + if progress_date < Date.today + late_date = [Date.today, end_date].min + if late_date > self.date_from && late_date > start_date + if late_date < self.date_to + coords[:bar_late_end] = late_date - self.date_from + 1 + else + coords[:bar_late_end] = self.date_to - self.date_from + 1 + end + end + end + end + end + + # Transforms dates into pixels witdh + coords.keys.each do |key| + coords[key] = (coords[key] * zoom).floor + end + coords + end + + # Sorts a collection of issues by start_date, due_date, id for gantt rendering + def sort_issues!(issues) + issues.sort! { |a, b| gantt_issue_compare(a, b, issues) } + end + + # TODO: top level issues should be sorted by start date + def gantt_issue_compare(x, y, issues) + if x.root_id == y.root_id + x.lft <=> y.lft + else + x.root_id <=> y.root_id + end + end + + def current_limit + if @max_rows + @max_rows - @number_of_rows + else + nil + end + end + + def abort? + if @max_rows && @number_of_rows >= @max_rows + @truncated = true + end + end + + def pdf_new_page?(options) + if options[:top] > 180 + options[:pdf].Line(15, options[:top], PDF::TotalWidth, options[:top]) + options[:pdf].AddPage("L") + options[:top] = 15 + options[:pdf].Line(15, options[:top] - 0.1, PDF::TotalWidth, options[:top] - 0.1) + end + end + + def html_subject(params, subject, options={}) + style = "position: absolute;top:#{params[:top]}px;left:#{params[:indent]}px;" + style << "width:#{params[:subject_width] - params[:indent]}px;" if params[:subject_width] + + output = view.content_tag 'div', subject, :class => options[:css], :style => style, :title => options[:title] + @subjects << output + output + end + + def pdf_subject(params, subject, options={}) + params[:pdf].SetY(params[:top]) + params[:pdf].SetX(15) + + char_limit = PDF::MaxCharactorsForSubject - params[:indent] + params[:pdf].RDMCell(params[:subject_width]-15, 5, (" " * params[:indent]) + subject.to_s.sub(/^(.{#{char_limit}}[^\s]*\s).*$/, '\1 (...)'), "LR") + + params[:pdf].SetY(params[:top]) + params[:pdf].SetX(params[:subject_width]) + params[:pdf].RDMCell(params[:g_width], 5, "", "LR") + end + + def image_subject(params, subject, options={}) + params[:image].fill('black') + params[:image].stroke('transparent') + params[:image].stroke_width(1) + params[:image].text(params[:indent], params[:top] + 2, subject) + end + + def html_task(params, coords, options={}) + output = '' + # Renders the task bar, with progress and late + if coords[:bar_start] && coords[:bar_end] + output << "
 
".html_safe + + if coords[:bar_late_end] + output << "
 
".html_safe + end + if coords[:bar_progress_end] + output << "
 
".html_safe + end + end + # Renders the markers + if options[:markers] + if coords[:start] + output << "
 
".html_safe + end + if coords[:end] + output << "
 
".html_safe + end + end + # Renders the label on the right + if options[:label] + output << "
".html_safe + output << options[:label] + output << "
".html_safe + end + # Renders the tooltip + if options[:issue] && coords[:bar_start] && coords[:bar_end] + output << "
".html_safe + output << ''.html_safe + output << view.render_issue_tooltip(options[:issue]).html_safe + output << "
".html_safe + end + @lines << output + output + end + + def pdf_task(params, coords, options={}) + height = options[:height] || 2 + + # Renders the task bar, with progress and late + if coords[:bar_start] && coords[:bar_end] + params[:pdf].SetY(params[:top]+1.5) + params[:pdf].SetX(params[:subject_width] + coords[:bar_start]) + params[:pdf].SetFillColor(200,200,200) + params[:pdf].RDMCell(coords[:bar_end] - coords[:bar_start], height, "", 0, 0, "", 1) + + if coords[:bar_late_end] + params[:pdf].SetY(params[:top]+1.5) + params[:pdf].SetX(params[:subject_width] + coords[:bar_start]) + params[:pdf].SetFillColor(255,100,100) + params[:pdf].RDMCell(coords[:bar_late_end] - coords[:bar_start], height, "", 0, 0, "", 1) + end + if coords[:bar_progress_end] + params[:pdf].SetY(params[:top]+1.5) + params[:pdf].SetX(params[:subject_width] + coords[:bar_start]) + params[:pdf].SetFillColor(90,200,90) + params[:pdf].RDMCell(coords[:bar_progress_end] - coords[:bar_start], height, "", 0, 0, "", 1) + end + end + # Renders the markers + if options[:markers] + if coords[:start] + params[:pdf].SetY(params[:top] + 1) + params[:pdf].SetX(params[:subject_width] + coords[:start] - 1) + params[:pdf].SetFillColor(50,50,200) + params[:pdf].RDMCell(2, 2, "", 0, 0, "", 1) + end + if coords[:end] + params[:pdf].SetY(params[:top] + 1) + params[:pdf].SetX(params[:subject_width] + coords[:end] - 1) + params[:pdf].SetFillColor(50,50,200) + params[:pdf].RDMCell(2, 2, "", 0, 0, "", 1) + end + end + # Renders the label on the right + if options[:label] + params[:pdf].SetX(params[:subject_width] + (coords[:bar_end] || 0) + 5) + params[:pdf].RDMCell(30, 2, options[:label]) + end + end + + def image_task(params, coords, options={}) + height = options[:height] || 6 + + # Renders the task bar, with progress and late + if coords[:bar_start] && coords[:bar_end] + params[:image].fill('#aaa') + params[:image].rectangle(params[:subject_width] + coords[:bar_start], params[:top], params[:subject_width] + coords[:bar_end], params[:top] - height) + + if coords[:bar_late_end] + params[:image].fill('#f66') + params[:image].rectangle(params[:subject_width] + coords[:bar_start], params[:top], params[:subject_width] + coords[:bar_late_end], params[:top] - height) + end + if coords[:bar_progress_end] + params[:image].fill('#00c600') + params[:image].rectangle(params[:subject_width] + coords[:bar_start], params[:top], params[:subject_width] + coords[:bar_progress_end], params[:top] - height) + end + end + # Renders the markers + if options[:markers] + if coords[:start] + x = params[:subject_width] + coords[:start] + y = params[:top] - height / 2 + params[:image].fill('blue') + params[:image].polygon(x-4, y, x, y-4, x+4, y, x, y+4) + end + if coords[:end] + x = params[:subject_width] + coords[:end] + params[:zoom] + y = params[:top] - height / 2 + params[:image].fill('blue') + params[:image].polygon(x-4, y, x, y-4, x+4, y, x, y+4) + end + end + # Renders the label on the right + if options[:label] + params[:image].fill('black') + params[:image].text(params[:subject_width] + (coords[:bar_end] || 0) + 5,params[:top] + 1, options[:label]) + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/105e4bad4371b49c4e052cc65ba6a1fae7edd15b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/105e4bad4371b49c4e052cc65ba6a1fae7edd15b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1009 @@ +# Serbian translations for Redmine +# by Vladimir Medarović (vlada@medarovic.com) +sr: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y." + short: "%e %b" + long: "%B %e, %Y" + + day_names: [недеља, понедељак, уторак, среда, четвртак, петак, субота] + abbr_day_names: [нед, пон, уто, сре, чет, пет, суб] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, јануар, фебруар, март, април, мај, јун, јул, август, септембар, октобар, новембар, децембар] + abbr_month_names: [~, јан, феб, мар, апр, мај, јун, јул, авг, сеп, окт, нов, дец] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d.%m.%Y. у %H:%M" + time: "%H:%M" + short: "%d. %b у %H:%M" + long: "%d. %B %Y у %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "пола минута" + less_than_x_seconds: + one: "мање од једне секунде" + other: "мање од %{count} сек." + x_seconds: + one: "једна секунда" + other: "%{count} сек." + less_than_x_minutes: + one: "мање од минута" + other: "мање од %{count} мин." + x_minutes: + one: "један минут" + other: "%{count} мин." + about_x_hours: + one: "приближно један сат" + other: "приближно %{count} сати" + x_days: + one: "један дан" + other: "%{count} дана" + about_x_months: + one: "приближно један месец" + other: "приближно %{count} месеци" + x_months: + one: "један месец" + other: "%{count} месеци" + about_x_years: + one: "приближно годину дана" + other: "приближно %{count} год." + over_x_years: + one: "преко годину дана" + other: "преко %{count} год." + almost_x_years: + one: "скоро годину дана" + other: "скоро %{count} год." + + number: + format: + separator: "," + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "и" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "није укључен у списак" + exclusion: "је резервисан" + invalid: "је неисправан" + confirmation: "потврда не одговара" + accepted: "мора бити прихваћен" + empty: "не може бити празно" + blank: "не може бити празно" + too_long: "је предугачка (максимум знакова је %{count})" + too_short: "је прекратка (минимум знакова је %{count})" + wrong_length: "је погрешне дужине (број знакова мора бити %{count})" + taken: "је већ у употреби" + not_a_number: "није број" + not_a_date: "није исправан датум" + greater_than: "мора бити већи од %{count}" + greater_than_or_equal_to: "мора бити већи или једнак %{count}" + equal_to: "мора бити једнак %{count}" + less_than: "мора бити мањи од %{count}" + less_than_or_equal_to: "мора бити мањи или једнак %{count}" + odd: "мора бити паран" + even: "мора бити непаран" + greater_than_start_date: "мора бити већи од почетног датума" + not_same_project: "не припада истом пројекту" + circular_dependency: "Ова веза ће створити кружну референцу" + cant_link_an_issue_with_a_descendant: "Проблем не може бити повезан са једним од својих подзадатака" + + actionview_instancetag_blank_option: Молим одаберите + + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Српски' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Налог је успешно ажуриран. + notice_account_invalid_creditentials: Неисправно корисничко име или лозинка. + notice_account_password_updated: Лозинка је успешно ажурирана. + notice_account_wrong_password: Погрешна лозинка + notice_account_register_done: Кориснички налог је успешно креиран. Кликните на линк који сте добили у е-поруци за активацију. + notice_account_unknown_email: Непознат корисник. + notice_can_t_change_password: Овај кориснички налог за потврду идентитета користи спољни извор. Немогуће је променити лозинку. + notice_account_lost_email_sent: Послата вам је е-порука са упутством за избор нове лозинке + notice_account_activated: Ваш кориснички налог је активиран. Сада се можете пријавити. + notice_successful_create: Успешно креирање. + notice_successful_update: Успешно ажурирање. + notice_successful_delete: Успешно брисање. + notice_successful_connection: Успешно повезивање. + notice_file_not_found: Страна којој желите приступити не постоји или је уклоњена. + notice_locking_conflict: Податак је ажуриран од стране другог корисника. + notice_not_authorized: Нисте овлашћени за приступ овој страни. + notice_email_sent: "E-порука је послата на %{value}" + notice_email_error: "Догодила се грешка приликом слања е-поруке (%{value})" + notice_feeds_access_key_reseted: Ваш RSS приступни кључ је поништен. + notice_api_access_key_reseted: Ваш API приступни кључ је поништен. + notice_failed_to_save_issues: "Неуспешно снимање %{count} проблема од %{total} одабраних: %{ids}." + notice_failed_to_save_members: "Неуспешно снимање члана(ова): %{errors}." + notice_no_issue_selected: "Ни један проблем није одабран! Молимо, одаберите проблем који желите да мењате." + notice_account_pending: "Ваш налог је креиран и чека на одобрење администратора." + notice_default_data_loaded: Подразумевано конфигурисање је успешно учитано. + notice_unable_delete_version: Верзију је немогуће избрисати. + notice_unable_delete_time_entry: Ставку евиденције времена је немогуће избрисати. + notice_issue_done_ratios_updated: Однос решених проблема је ажуриран. + + error_can_t_load_default_data: "Подразумевано конфигурисање је немогуће учитати: %{value}" + error_scm_not_found: "Ставка или исправка нису пронађене у спремишту." + error_scm_command_failed: "Грешка се јавила приликом покушаја приступа спремишту: %{value}" + error_scm_annotate: "Ставка не постоји или не може бити означена." + error_issue_not_found_in_project: 'Проблем није пронађен или не припада овом пројекту.' + error_no_tracker_in_project: 'Ни једно праћење није повезано са овим пројектом. Молимо проверите подешавања пројекта.' + error_no_default_issue_status: 'Подразумевани статус проблема није дефинисан. Молимо проверите ваше конфигурисање (идите на "Администрација -> Статуси проблема").' + error_can_not_delete_custom_field: Немогуће је избрисати прилагођено поље + error_can_not_delete_tracker: "Ово праћење садржи проблеме и не може бити обрисано." + error_can_not_remove_role: "Ова улога је у употреби и не може бити обрисана." + error_can_not_reopen_issue_on_closed_version: 'Проблем додељен затвореној верзији не може бити поново отворен' + error_can_not_archive_project: Овај пројекат се не може архивирати + error_issue_done_ratios_not_updated: "Однос решених проблема није ажуриран." + error_workflow_copy_source: 'Молимо одаберите изворно праћење или улогу' + error_workflow_copy_target: 'Молимо одаберите одредишно праћење и улогу' + error_unable_delete_issue_status: 'Статус проблема је немогуће обрисати' + error_unable_to_connect: "Повезивање са (%{value}) је немогуће" + warning_attachments_not_saved: "%{count} датотека не може бити снимљена." + + mail_subject_lost_password: "Ваша %{value} лозинка" + mail_body_lost_password: 'За промену ваше лозинке, кликните на следећи линк:' + mail_subject_register: "Активација вашег %{value} налога" + mail_body_register: 'За активацију вашег налога, кликните на следећи линк:' + mail_body_account_information_external: "Ваш налог %{value} можете користити за пријаву." + mail_body_account_information: Информације о вашем налогу + mail_subject_account_activation_request: "Захтев за активацију налога %{value}" + mail_body_account_activation_request: "Нови корисник (%{value}) је регистрован. Налог чека на ваше одобрење:" + mail_subject_reminder: "%{count} проблема доспева наредних %{days} дана" + mail_body_reminder: "%{count} проблема додељених вама доспева у наредних %{days} дана:" + mail_subject_wiki_content_added: "Wiki страница '%{id}' је додата" + mail_body_wiki_content_added: "%{author} је додао wiki страницу '%{id}'." + mail_subject_wiki_content_updated: "Wiki страница '%{id}' је ажурирана" + mail_body_wiki_content_updated: "%{author} је ажурирао wiki страницу '%{id}'." + + gui_validation_error: једна грешка + gui_validation_error_plural: "%{count} грешака" + + field_name: Назив + field_description: Опис + field_summary: Резиме + field_is_required: Обавезно + field_firstname: Име + field_lastname: Презиме + field_mail: Е-адреса + field_filename: Датотека + field_filesize: Величина + field_downloads: Преузимања + field_author: Аутор + field_created_on: Креирано + field_updated_on: Ажурирано + field_field_format: Формат + field_is_for_all: За све пројекте + field_possible_values: Могуће вредности + field_regexp: Регуларан израз + field_min_length: Минимална дужина + field_max_length: Максимална дужина + field_value: Вредност + field_category: Категорија + field_title: Наслов + field_project: Пројекат + field_issue: Проблем + field_status: Статус + field_notes: Белешке + field_is_closed: Затворен проблем + field_is_default: Подразумевана вредност + field_tracker: Праћење + field_subject: Предмет + field_due_date: Крајњи рок + field_assigned_to: Додељено + field_priority: Приоритет + field_fixed_version: Одредишна верзија + field_user: Корисник + field_principal: Главни + field_role: Улога + field_homepage: Почетна страница + field_is_public: Јавно објављивање + field_parent: Потпројекат од + field_is_in_roadmap: Проблеми приказани у плану рада + field_login: Корисничко име + field_mail_notification: Обавештења путем е-поште + field_admin: Администратор + field_last_login_on: Последње повезивање + field_language: Језик + field_effective_date: Датум + field_password: Лозинка + field_new_password: Нова лозинка + field_password_confirmation: Потврда лозинке + field_version: Верзија + field_type: Тип + field_host: Главни рачунар + field_port: Порт + field_account: Кориснички налог + field_base_dn: Базни DN + field_attr_login: Атрибут пријављивања + field_attr_firstname: Атрибут имена + field_attr_lastname: Атрибут презимена + field_attr_mail: Атрибут е-адресе + field_onthefly: Креирање корисника у току рада + field_start_date: Почетак + field_done_ratio: "% урађено" + field_auth_source: Режим потврде идентитета + field_hide_mail: Сакриј моју е-адресу + field_comments: Коментар + field_url: URL + field_start_page: Почетна страница + field_subproject: Потпројекат + field_hours: сати + field_activity: Активност + field_spent_on: Датум + field_identifier: Идентификатор + field_is_filter: Употреби као филтер + field_issue_to: Сродни проблеми + field_delay: Кашњење + field_assignable: Проблем може бити додељен овој улози + field_redirect_existing_links: Преусмери постојеће везе + field_estimated_hours: Протекло време + field_column_names: Колоне + field_time_zone: Временска зона + field_searchable: Може да се претражује + field_default_value: Подразумевана вредност + field_comments_sorting: Прикажи коментаре + field_parent_title: Матична страница + field_editable: Изменљиво + field_watcher: Посматрач + field_identity_url: OpenID URL + field_content: Садржај + field_group_by: Груписање резултата по + field_sharing: Дељење + field_parent_issue: Матични задатак + + setting_app_title: Наслов апликације + setting_app_subtitle: Поднаслов апликације + setting_welcome_text: Текст добродошлице + setting_default_language: Подразумевани језик + setting_login_required: Обавезна потврда идентитета + setting_self_registration: Саморегистрација + setting_attachment_max_size: Макс. величина приложене датотеке + setting_issues_export_limit: Ограничење извоза „проблема“ + setting_mail_from: Е-адреса пошиљаоца + setting_bcc_recipients: Примаоци „Bcc“ копије + setting_plain_text_mail: Порука са чистим текстом (без HTML-а) + setting_host_name: Путања и назив главног рачунара + setting_text_formatting: Обликовање текста + setting_wiki_compression: Компресија Wiki историје + setting_feeds_limit: Ограничење садржаја извора вести + setting_default_projects_public: Подразумева се јавно приказивање нових пројеката + setting_autofetch_changesets: Извршавање аутоматског преузимања + setting_sys_api_enabled: Омогућавање WS за управљање спремиштем + setting_commit_ref_keywords: Референцирање кључних речи + setting_commit_fix_keywords: Поправљање кључних речи + setting_autologin: Аутоматска пријава + setting_date_format: Формат датума + setting_time_format: Формат времена + setting_cross_project_issue_relations: Дозволи повезивање проблема из унакрсних пројеката + setting_issue_list_default_columns: Подразумеване колоне приказане на списку проблема + setting_emails_footer: Подножје странице е-поруке + setting_protocol: Протокол + setting_per_page_options: Опције приказа објеката по страници + setting_user_format: Формат приказа корисника + setting_activity_days_default: Број дана приказаних на пројектној активности + setting_display_subprojects_issues: Приказуј проблеме из потпројеката на главном пројекту, уколико није другачије наведено + setting_enabled_scm: Омогућавање SCM + setting_mail_handler_body_delimiters: "Скраћивање е-поруке након једне од ових линија" + setting_mail_handler_api_enabled: Омогућавање WS долазне е-поруке + setting_mail_handler_api_key: API кључ + setting_sequential_project_identifiers: Генерисање секвенцијалног имена пројекта + setting_gravatar_enabled: Користи Gravatar корисничке иконе + setting_gravatar_default: Подразумевана Gravatar слика + setting_diff_max_lines_displayed: Макс. број приказаних различитих линија + setting_file_max_size_displayed: Макс. величина текст. датотека приказаних уметнуто + setting_repository_log_display_limit: Макс. број ревизија приказаних у датотеци за евиденцију + setting_openid: Дозволи OpenID пријаву и регистрацију + setting_password_min_length: Минимална дужина лозинке + setting_new_project_user_role_id: Креатору пројекта (који није администратор) додељује је улога + setting_default_projects_modules: Подразумевано омогућени модули за нове пројекте + setting_issue_done_ratio: Израчунај однос решених проблема + setting_issue_done_ratio_issue_field: користећи поље проблема + setting_issue_done_ratio_issue_status: користећи статус проблема + setting_start_of_week: Први дан у седмици + setting_rest_api_enabled: Омогући REST web услуге + setting_cache_formatted_text: Кеширање обрађеног текста + + permission_add_project: Креирање пројекта + permission_add_subprojects: Креирање потпојекта + permission_edit_project: Измена пројеката + permission_select_project_modules: Одабирање модула пројекта + permission_manage_members: Управљање члановима + permission_manage_project_activities: Управљање пројектним активностима + permission_manage_versions: Управљање верзијама + permission_manage_categories: Управљање категоријама проблема + permission_view_issues: Преглед проблема + permission_add_issues: Додавање проблема + permission_edit_issues: Измена проблема + permission_manage_issue_relations: Управљање везама између проблема + permission_add_issue_notes: Додавање белешки + permission_edit_issue_notes: Измена белешки + permission_edit_own_issue_notes: Измена сопствених белешки + permission_move_issues: Померање проблема + permission_delete_issues: Брисање проблема + permission_manage_public_queries: Управљање јавним упитима + permission_save_queries: Снимање упита + permission_view_gantt: Прегледање Гантовог дијаграма + permission_view_calendar: Прегледање календара + permission_view_issue_watchers: Прегледање списка посматрача + permission_add_issue_watchers: Додавање посматрача + permission_delete_issue_watchers: Брисање посматрача + permission_log_time: Бележење утрошеног времена + permission_view_time_entries: Прегледање утрошеног времена + permission_edit_time_entries: Измена утрошеног времена + permission_edit_own_time_entries: Измена сопственог утрошеног времена + permission_manage_news: Управљање вестима + permission_comment_news: Коментарисање вести + permission_manage_documents: Управљање документима + permission_view_documents: Прегледање докумената + permission_manage_files: Управљање датотекама + permission_view_files: Прегледање датотека + permission_manage_wiki: Управљање wiki страницама + permission_rename_wiki_pages: Промена имена wiki страницама + permission_delete_wiki_pages: Брисање wiki страница + permission_view_wiki_pages: Прегледање wiki страница + permission_view_wiki_edits: Прегледање wiki историје + permission_edit_wiki_pages: Измена wiki страница + permission_delete_wiki_pages_attachments: Брисање приложених датотека + permission_protect_wiki_pages: Заштита wiki страница + permission_manage_repository: Управљање спремиштем + permission_browse_repository: Прегледање спремишта + permission_view_changesets: Прегледање скупа промена + permission_commit_access: Потврда приступа + permission_manage_boards: Управљање форумима + permission_view_messages: Прегледање порука + permission_add_messages: Слање порука + permission_edit_messages: Измена порука + permission_edit_own_messages: Измена сопствених порука + permission_delete_messages: Брисање порука + permission_delete_own_messages: Брисање сопствених порука + permission_export_wiki_pages: Извоз wiki страница + permission_manage_subtasks: Управљање подзадацима + + project_module_issue_tracking: Праћење проблема + project_module_time_tracking: Праћење времена + project_module_news: Вести + project_module_documents: Документи + project_module_files: Датотеке + project_module_wiki: Wiki + project_module_repository: Спремиште + project_module_boards: Форуми + + label_user: Корисник + label_user_plural: Корисници + label_user_new: Нови корисник + label_user_anonymous: Анониман + label_project: Пројекат + label_project_new: Нови пројекат + label_project_plural: Пројекти + label_x_projects: + zero: нема пројеката + one: један пројекат + other: "%{count} пројеката" + label_project_all: Сви пројекти + label_project_latest: Последњи пројекти + label_issue: Проблем + label_issue_new: Нови проблем + label_issue_plural: Проблеми + label_issue_view_all: Приказ свих проблема + label_issues_by: "Проблеми (%{value})" + label_issue_added: Проблем је додат + label_issue_updated: Проблем је ажуриран + label_document: Документ + label_document_new: Нови документ + label_document_plural: Документи + label_document_added: Документ је додат + label_role: Улога + label_role_plural: Улоге + label_role_new: Нова улога + label_role_and_permissions: Улоге и дозволе + label_member: Члан + label_member_new: Нови члан + label_member_plural: Чланови + label_tracker: Праћење + label_tracker_plural: Праћења + label_tracker_new: Ново праћење + label_workflow: Ток посла + label_issue_status: Статус проблема + label_issue_status_plural: Статуси проблема + label_issue_status_new: Нови статус + label_issue_category: Категорија проблема + label_issue_category_plural: Категорије проблема + label_issue_category_new: Нова категорија + label_custom_field: Прилагођено поље + label_custom_field_plural: Прилагођена поља + label_custom_field_new: Ново прилагођено поље + label_enumerations: Набројива листа + label_enumeration_new: Нова вредност + label_information: Информација + label_information_plural: Информације + label_please_login: Молимо, пријавите се + label_register: Регистрација + label_login_with_open_id_option: или пријава са OpenID + label_password_lost: Изгубљена лозинка + label_home: Почетак + label_my_page: Моја страница + label_my_account: Мој налог + label_my_projects: Моји пројекти + label_my_page_block: My page block + label_administration: Администрација + label_login: Пријава + label_logout: Одјава + label_help: Помоћ + label_reported_issues: Пријављени проблеми + label_assigned_to_me_issues: Проблеми додељени мени + label_last_login: Последње повезивање + label_registered_on: Регистрован + label_activity: Активност + label_overall_activity: Целокупна активност + label_user_activity: "Активност корисника %{value}" + label_new: Ново + label_logged_as: Пријављени сте као + label_environment: Окружење + label_authentication: Потврда идентитета + label_auth_source: Режим потврде идентитета + label_auth_source_new: Нови режим потврде идентитета + label_auth_source_plural: Режими потврде идентитета + label_subproject_plural: Потпројекти + label_subproject_new: Нови потпројекат + label_and_its_subprojects: "%{value} и његови потпројекти" + label_min_max_length: Мин. - Макс. дужина + label_list: Списак + label_date: Датум + label_integer: Цео број + label_float: Са покретним зарезом + label_boolean: Логички оператор + label_string: Текст + label_text: Дуги текст + label_attribute: Особина + label_attribute_plural: Особине + label_download: "%{count} преузимање" + label_download_plural: "%{count} преузимања" + label_no_data: Нема података за приказивање + label_change_status: Промена статуса + label_history: Историја + label_attachment: Датотека + label_attachment_new: Нова датотека + label_attachment_delete: Брисање датотеке + label_attachment_plural: Датотеке + label_file_added: Датотека је додата + label_report: Извештај + label_report_plural: Извештаји + label_news: Вести + label_news_new: Додавање вести + label_news_plural: Вести + label_news_latest: Последње вести + label_news_view_all: Приказ свих вести + label_news_added: Вести су додате + label_settings: Подешавања + label_overview: Преглед + label_version: Верзија + label_version_new: Нова верзија + label_version_plural: Верзије + label_close_versions: Затвори завршене верзије + label_confirmation: Потврда + label_export_to: 'Такође доступно и у варијанти:' + label_read: Читање... + label_public_projects: Јавни пројекти + label_open_issues: отворен + label_open_issues_plural: отворених + label_closed_issues: затворен + label_closed_issues_plural: затворених + label_x_open_issues_abbr_on_total: + zero: 0 отворених / %{total} + one: 1 отворен / %{total} + other: "%{count} отворених / %{total}" + label_x_open_issues_abbr: + zero: 0 отворених + one: 1 отворен + other: "%{count} отворених" + label_x_closed_issues_abbr: + zero: 0 затворених + one: 1 затворен + other: "%{count} затворених" + label_total: Укупно + label_permissions: Дозволе + label_current_status: Тренутни статус + label_new_statuses_allowed: Нови статуси дозвољени + label_all: сви + label_none: ниједан + label_nobody: никоме + label_next: Следеће + label_previous: Претходно + label_used_by: Користио + label_details: Детаљи + label_add_note: Додај белешку + label_per_page: По страни + label_calendar: Календар + label_months_from: месеци од + label_gantt: Гантов дијаграм + label_internal: Унутрашњи + label_last_changes: "последњих %{count} промена" + label_change_view_all: Прикажи све промене + label_personalize_page: Персонализуј ову страну + label_comment: Коментар + label_comment_plural: Коментари + label_x_comments: + zero: без коментара + one: један коментар + other: "%{count} коментара" + label_comment_add: Додај коментар + label_comment_added: Коментар додат + label_comment_delete: Обриши коментаре + label_query: Прилагођен упит + label_query_plural: Прилагођени упити + label_query_new: Нови упит + label_filter_add: Додавање филтера + label_filter_plural: Филтери + label_equals: је + label_not_equals: није + label_in_less_than: мање од + label_in_more_than: више од + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: у + label_today: данас + label_all_time: све време + label_yesterday: јуче + label_this_week: ове седмице + label_last_week: последње седмице + label_last_n_days: "последњих %{count} дана" + label_this_month: овог месеца + label_last_month: последњег месеца + label_this_year: ове године + label_date_range: Временски период + label_less_than_ago: пре мање од неколико дана + label_more_than_ago: пре више од неколико дана + label_ago: пре неколико дана + label_contains: садржи + label_not_contains: не садржи + label_day_plural: дана + label_repository: Спремиште + label_repository_plural: Спремишта + label_browse: Прегледање + label_modification: "%{count} промена" + label_modification_plural: "%{count} промена" + label_branch: Грана + label_tag: Ознака + label_revision: Ревизија + label_revision_plural: Ревизије + label_revision_id: "Ревизија %{value}" + label_associated_revisions: Придружене ревизије + label_added: додато + label_modified: промењено + label_copied: копирано + label_renamed: преименовано + label_deleted: избрисано + label_latest_revision: Последња ревизија + label_latest_revision_plural: Последње ревизије + label_view_revisions: Преглед ревизија + label_view_all_revisions: Преглед свих ревизија + label_max_size: Максимална величина + label_sort_highest: Премештање на врх + label_sort_higher: Премештање на горе + label_sort_lower: Премештање на доле + label_sort_lowest: Премештање на дно + label_roadmap: План рада + label_roadmap_due_in: "Доспева %{value}" + label_roadmap_overdue: "%{value} најкасније" + label_roadmap_no_issues: Нема проблема за ову верзију + label_search: Претрага + label_result_plural: Резултати + label_all_words: Све речи + label_wiki: Wiki + label_wiki_edit: Wiki измена + label_wiki_edit_plural: Wiki измене + label_wiki_page: Wiki страница + label_wiki_page_plural: Wiki странице + label_index_by_title: Индексирање по наслову + label_index_by_date: Индексирање по датуму + label_current_version: Тренутна верзија + label_preview: Преглед + label_feed_plural: Извори вести + label_changes_details: Детаљи свих промена + label_issue_tracking: Праћење проблема + label_spent_time: Утрошено време + label_overall_spent_time: Целокупно утрошено време + label_f_hour: "%{value} сат" + label_f_hour_plural: "%{value} сати" + label_time_tracking: Праћење времена + label_change_plural: Промене + label_statistics: Статистика + label_commits_per_month: Извршења месечно + label_commits_per_author: Извршења по аутору + label_view_diff: Погледај разлике + label_diff_inline: унутра + label_diff_side_by_side: упоредо + label_options: Опције + label_copy_workflow_from: Копирање тока посла од + label_permissions_report: Извештај о дозволама + label_watched_issues: Посматрани проблеми + label_related_issues: Сродни проблеми + label_applied_status: Примењени статуси + label_loading: Учитавање... + label_relation_new: Нова релација + label_relation_delete: Брисање релације + label_relates_to: сродних са + label_duplicates: дуплираних + label_duplicated_by: дуплираних од + label_blocks: одбијених + label_blocked_by: одбијених од + label_precedes: претходи + label_follows: праћених + label_end_to_start: од краја до почетка + label_end_to_end: од краја до краја + label_start_to_start: од почетка до почетка + label_start_to_end: од почетка до краја + label_stay_logged_in: Останите пријављени + label_disabled: онемогућено + label_show_completed_versions: Приказивање завршене верзије + label_me: мени + label_board: Форум + label_board_new: Нови форум + label_board_plural: Форуми + label_board_locked: Закључана + label_board_sticky: Лепљива + label_topic_plural: Теме + label_message_plural: Поруке + label_message_last: Последња порука + label_message_new: Нова порука + label_message_posted: Порука је додата + label_reply_plural: Одговори + label_send_information: Пошаљи кориснику детаље налога + label_year: Година + label_month: Месец + label_week: Седмица + label_date_from: Шаље + label_date_to: Прима + label_language_based: Базирано на језику корисника + label_sort_by: "Сортирано по %{value}" + label_send_test_email: Слање пробне е-поруке + label_feeds_access_key: RSS приступни кључ + label_missing_feeds_access_key: RSS приступни кључ недостаје + label_feeds_access_key_created_on: "RSS приступни кључ је направљен пре %{value}" + label_module_plural: Модули + label_added_time_by: "Додао %{author} пре %{age}" + label_updated_time_by: "Ажурирао %{author} пре %{age}" + label_updated_time: "Ажурирано пре %{value}" + label_jump_to_a_project: Скок на пројекат... + label_file_plural: Датотеке + label_changeset_plural: Скупови промена + label_default_columns: Подразумеване колоне + label_no_change_option: (Без промена) + label_bulk_edit_selected_issues: Групна измена одабраних проблема + label_theme: Тема + label_default: Подразумевано + label_search_titles_only: Претражуј само наслове + label_user_mail_option_all: "За било који догађај на свим мојим пројектима" + label_user_mail_option_selected: "За било који догађај на само одабраним пројектима..." + label_user_mail_no_self_notified: "Не желим бити обавештаван за промене које сам правим" + label_registration_activation_by_email: активација налога путем е-поруке + label_registration_manual_activation: ручна активација налога + label_registration_automatic_activation: аутоматска активација налога + label_display_per_page: "Број ставки по страници: %{value}" + label_age: Старост + label_change_properties: Промени својства + label_general: Општи + label_more: Више + label_scm: SCM + label_plugins: Додатне компоненте + label_ldap_authentication: LDAP потврда идентитета + label_downloads_abbr: D/L + label_optional_description: Опционо опис + label_add_another_file: Додај још једну датотеку + label_preferences: Подешавања + label_chronological_order: по хронолошком редоследу + label_reverse_chronological_order: по обрнутом хронолошком редоследу + label_planning: Планирање + label_incoming_emails: Долазне е-поруке + label_generate_key: Генерисање кључа + label_issue_watchers: Посматрачи + label_example: Пример + label_display: Приказ + label_sort: Сортирање + label_ascending: Растући низ + label_descending: Опадајући низ + label_date_from_to: Од %{start} до %{end} + label_wiki_content_added: Wiki страница је додата + label_wiki_content_updated: Wiki страница је ажурирана + label_group: Група + label_group_plural: Групе + label_group_new: Нова група + label_time_entry_plural: Утрошено време + label_version_sharing_none: Није дељено + label_version_sharing_descendants: Са потпројектима + label_version_sharing_hierarchy: Са хијерархијом пројекта + label_version_sharing_tree: Са стаблом пројекта + label_version_sharing_system: Са свим пројектима + label_update_issue_done_ratios: Ажурирај однос решених проблема + label_copy_source: Извор + label_copy_target: Одредиште + label_copy_same_as_target: Исто као одредиште + label_display_used_statuses_only: Приказуј статусе коришћене само од стране овог праћења + label_api_access_key: API приступни кључ + label_missing_api_access_key: Недостаје API приступни кључ + label_api_access_key_created_on: "API приступни кључ је креиран пре %{value}" + label_profile: Профил + label_subtask_plural: Подзадатак + label_project_copy_notifications: Пошаљи е-поруку са обавештењем приликом копирања пројекта + + button_login: Пријава + button_submit: Пошаљи + button_save: Сними + button_check_all: Укључи све + button_uncheck_all: Искључи све + button_delete: Избриши + button_create: Креирај + button_create_and_continue: Креирај и настави + button_test: Тест + button_edit: Измени + button_add: Додај + button_change: Промени + button_apply: Примени + button_clear: Обриши + button_lock: Закључај + button_unlock: Откључај + button_download: Преузми + button_list: Списак + button_view: Прикажи + button_move: Помери + button_move_and_follow: Помери и прати + button_back: Назад + button_cancel: Поништи + button_activate: Активирај + button_sort: Сортирај + button_log_time: Евидентирај време + button_rollback: Повратак на ову верзију + button_watch: Прати + button_unwatch: Не прати више + button_reply: Одговори + button_archive: Архивирај + button_unarchive: Врати из архиве + button_reset: Поништи + button_rename: Преименуј + button_change_password: Промени лозинку + button_copy: Копирај + button_copy_and_follow: Копирај и прати + button_annotate: Прибележи + button_update: Ажурирај + button_configure: Подеси + button_quote: Под наводницима + button_duplicate: Дуплирај + button_show: Прикажи + + status_active: активни + status_registered: регистровани + status_locked: закључани + + version_status_open: отворен + version_status_locked: закључан + version_status_closed: затворен + + field_active: Активан + + text_select_mail_notifications: Одабери акције за које ће обавештење бити послато путем е-поште. + text_regexp_info: нпр. ^[A-Z0-9]+$ + text_min_max_length_info: 0 значи без ограничења + text_project_destroy_confirmation: Јесте ли сигурни да желите да избришете овај пројекат и све припадајуће податке? + text_subprojects_destroy_warning: "Потпројекти: %{value} ће такође бити избрисан." + text_workflow_edit: Одаберите улогу и праћење за измену тока посла + text_are_you_sure: Јесте ли сигурни? + text_journal_changed: "%{label} промењен од %{old} у %{new}" + text_journal_set_to: "%{label} постављен у %{value}" + text_journal_deleted: "%{label} избрисано (%{old})" + text_journal_added: "%{label} %{value} додато" + text_tip_issue_begin_day: задатак почиње овог дана + text_tip_issue_end_day: задатак се завршава овог дана + text_tip_issue_begin_end_day: задатак почиње и завршава овог дана + text_project_identifier_info: 'Дозвољена су само мала слова (a-ш), бројеви и цртице.
Једном снимљен идентификатор више се не може променити.' + text_caracters_maximum: "Највише %{count} знак(ова)." + text_caracters_minimum: "Број знакова мора бити најмање %{count}." + text_length_between: "Број знакова мора бити између %{min} и %{max}." + text_tracker_no_workflow: Ово праћење нема дефинисан ток посла + text_unallowed_characters: Недозвољени знакови + text_comma_separated: Дозвољене су вишеструке вредности (одвојене зарезом). + text_line_separated: Дозвољене су вишеструке вредности (један ред за сваку вредност). + text_issues_ref_in_commit_messages: Референцирање и поправљање проблема у извршним порукама + text_issue_added: "%{author} је пријавио проблем %{id}." + text_issue_updated: "%{author} је ажурирао проблем %{id}." + text_wiki_destroy_confirmation: Јесте ли сигурни да желите да обришете wiki и сав садржај? + text_issue_category_destroy_question: "Неколико проблема (%{count}) је додељено овој категорији. Шта желите да урадите?" + text_issue_category_destroy_assignments: Уклони додељене категорије + text_issue_category_reassign_to: Додели поново проблеме овој категорији + text_user_mail_option: "За неизабране пројекте, добићете само обавештење о стварима које пратите или сте укључени (нпр. проблеми чији сте ви аутор или заступник)." + text_no_configuration_data: "Улоге, праћења, статуси проблема и тока посла још увек нису подешени.\nПрепоручљиво је да учитате подразумевано конфигурисање. Измена је могућа након првог учитавања." + text_load_default_configuration: Учитај подразумевано конфигурисање + text_status_changed_by_changeset: "Примењено у скупу са променама %{value}." + text_issues_destroy_confirmation: 'Јесте ли сигурни да желите да избришете одабране проблеме?' + text_select_project_modules: 'Одаберите модуле које желите омогућити за овај пројекат:' + text_default_administrator_account_changed: Подразумевани администраторски налог је промењен + text_file_repository_writable: Фасцикла приложених датотека је уписива + text_plugin_assets_writable: Фасцикла елемената додатних компоненти је уписива + text_rmagick_available: RMagick је доступан (опционо) + text_destroy_time_entries_question: "%{hours} сати је пријављено за овај проблем који желите избрисати. Шта желите да урадите?" + text_destroy_time_entries: Избриши пријављене сате + text_assign_time_entries_to_project: Додели пријављене сате пројекту + text_reassign_time_entries: 'Додели поново пријављене сате овом проблему:' + text_user_wrote: "%{value} је написао:" + text_enumeration_destroy_question: "%{count} објекат(а) је додељено овој вредности." + text_enumeration_category_reassign_to: 'Додели их поново овој вредности:' + text_email_delivery_not_configured: "Испорука е-порука није конфигурисана и обавештења су онемогућена.\nПодесите ваш SMTP сервер у config/configuration.yml и покрените поново апликацију за њихово омогућавање." + text_repository_usernames_mapping: "Одаберите или ажурирајте Redmine кориснике мапирањем сваког корисничког имена пронађеног у евиденцији спремишта.\nКорисници са истим Redmine именом и именом спремишта или е-адресом су аутоматски мапирани." + text_diff_truncated: '... Ова разлика је исечена јер је достигнута максимална величина приказа.' + text_custom_field_possible_values_info: 'Један ред за сваку вредност' + text_wiki_page_destroy_question: "Ова страница има %{descendants} подређених страница и подстраница. Шта желите да урадите?" + text_wiki_page_nullify_children: "Задржи подређене странице као корене странице" + text_wiki_page_destroy_children: "Избриши подређене странице и све њихове подстранице" + text_wiki_page_reassign_children: "Додели поново подређене странице овој матичној страници" + text_own_membership_delete_confirmation: "Након уклањања појединих или свих ваших дозвола нећете више моћи да уређујете овај пројекат.\nЖелите ли да наставите?" + text_zoom_in: Увећај + text_zoom_out: Умањи + + default_role_manager: Менаџер + default_role_developer: Програмер + default_role_reporter: Извештач + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Подршка + default_issue_status_new: Ново + default_issue_status_in_progress: У току + default_issue_status_resolved: Решено + default_issue_status_feedback: Повратна информација + default_issue_status_closed: Затворено + default_issue_status_rejected: Одбијено + default_doc_category_user: Корисничка документација + default_doc_category_tech: Техничка документација + default_priority_low: Низак + default_priority_normal: Нормалан + default_priority_high: Висок + default_priority_urgent: Хитно + default_priority_immediate: Непосредно + default_activity_design: Дизајн + default_activity_development: Развој + + enumeration_issue_priorities: Приоритети проблема + enumeration_doc_categories: Категорије документа + enumeration_activities: Активности (праћење времена) + enumeration_system_activity: Системска активност + + field_time_entries: Време евиденције + project_module_gantt: Гантов дијаграм + project_module_calendar: Календар + + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Кодирање извршних порука + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/10941a48faa924ece3034ab7920a0b4ae65e5ad0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/10941a48faa924ece3034ab7920a0b4ae65e5ad0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +# 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. + +desc <<-END_DESC +Send reminders about issues due in the next days. + +Available options: + * days => number of days to remind about (defaults to 7) + * tracker => id of tracker (defaults to all trackers) + * project => id or identifier of project (defaults to all projects) + * users => comma separated list of user ids who should be reminded + +Example: + rake redmine:send_reminders days=7 users="1,23, 56" RAILS_ENV="production" +END_DESC + +namespace :redmine do + task :send_reminders => :environment do + options = {} + options[:days] = ENV['days'].to_i if ENV['days'] + options[:project] = ENV['project'] if ENV['project'] + options[:tracker] = ENV['tracker'].to_i if ENV['tracker'] + options[:users] = (ENV['users'] || '').split(',').each(&:strip!) + + Mailer.reminders(options) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/10ba38f34a4375a656d65a1e3f8a1b3bc519f3f1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/10ba38f34a4375a656d65a1e3f8a1b3bc519f3f1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class WikiContentObserver < ActiveRecord::Observer + def after_create(wiki_content) + Mailer.deliver_wiki_content_added(wiki_content) if Setting.notified_events.include?('wiki_content_added') + end + + def after_update(wiki_content) + if wiki_content.text_changed? + Mailer.deliver_wiki_content_updated(wiki_content) if Setting.notified_events.include?('wiki_content_updated') + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/10ba4b3e5a7a93b2f988725561d5c82a7bd53485.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/10ba4b3e5a7a93b2f988725561d5c82a7bd53485.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +class CreateComments < ActiveRecord::Migration + def self.up + create_table :comments do |t| + t.column :commented_type, :string, :limit => 30, :default => "", :null => false + t.column :commented_id, :integer, :default => 0, :null => false + t.column :author_id, :integer, :default => 0, :null => false + t.column :comments, :text + t.column :created_on, :datetime, :null => false + t.column :updated_on, :datetime, :null => false + end + end + + def self.down + drop_table :comments + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/10f74e3a18ae17108789fde8071c8bf836627534.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/10f74e3a18ae17108789fde8071c8bf836627534.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class CreateChangesetParents < ActiveRecord::Migration + def self.up + create_table :changeset_parents, :id => false do |t| + t.column :changeset_id, :integer, :null => false + t.column :parent_id, :integer, :null => false + end + add_index :changeset_parents, [:changeset_id], :unique => false, :name => :changeset_parents_changeset_ids + add_index :changeset_parents, [:parent_id], :unique => false, :name => :changeset_parents_parent_ids + end + + def self.down + drop_table :changeset_parents + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/10/10fa798bfd4dc35b558fd0502d1cd4f15f26285c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/10/10fa798bfd4dc35b558fd0502d1cd4f15f26285c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,118 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class ProjectNestedSetTest < ActiveSupport::TestCase + + context "nested set" do + setup do + Project.delete_all + + @a = Project.create!(:name => 'Project A', :identifier => 'projecta') + @a1 = Project.create!(:name => 'Project A1', :identifier => 'projecta1') + @a1.set_parent!(@a) + @a2 = Project.create!(:name => 'Project A2', :identifier => 'projecta2') + @a2.set_parent!(@a) + + @b = Project.create!(:name => 'Project B', :identifier => 'projectb') + @b1 = Project.create!(:name => 'Project B1', :identifier => 'projectb1') + @b1.set_parent!(@b) + @b11 = Project.create!(:name => 'Project B11', :identifier => 'projectb11') + @b11.set_parent!(@b1) + @b2 = Project.create!(:name => 'Project B2', :identifier => 'projectb2') + @b2.set_parent!(@b) + + @c = Project.create!(:name => 'Project C', :identifier => 'projectc') + @c1 = Project.create!(:name => 'Project C1', :identifier => 'projectc1') + @c1.set_parent!(@c) + + [@a, @a1, @a2, @b, @b1, @b11, @b2, @c, @c1].each(&:reload) + end + + context "#create" do + should "build valid tree" do + assert_nested_set_values({ + @a => [nil, 1, 6], + @a1 => [@a.id, 2, 3], + @a2 => [@a.id, 4, 5], + @b => [nil, 7, 14], + @b1 => [@b.id, 8, 11], + @b11 => [@b1.id,9, 10], + @b2 => [@b.id,12, 13], + @c => [nil, 15, 18], + @c1 => [@c.id,16, 17] + }) + end + end + + context "#set_parent!" do + should "keep valid tree" do + assert_no_difference 'Project.count' do + Project.find_by_name('Project B1').set_parent!(Project.find_by_name('Project A2')) + end + assert_nested_set_values({ + @a => [nil, 1, 10], + @a2 => [@a.id, 4, 9], + @b1 => [@a2.id,5, 8], + @b11 => [@b1.id,6, 7], + @b => [nil, 11, 14], + @c => [nil, 15, 18] + }) + end + end + + context "#destroy" do + context "a root with children" do + should "not mess up the tree" do + assert_difference 'Project.count', -4 do + Project.find_by_name('Project B').destroy + end + assert_nested_set_values({ + @a => [nil, 1, 6], + @a1 => [@a.id, 2, 3], + @a2 => [@a.id, 4, 5], + @c => [nil, 7, 10], + @c1 => [@c.id, 8, 9] + }) + end + end + + context "a child with children" do + should "not mess up the tree" do + assert_difference 'Project.count', -2 do + Project.find_by_name('Project B1').destroy + end + assert_nested_set_values({ + @a => [nil, 1, 6], + @b => [nil, 7, 10], + @b2 => [@b.id, 8, 9], + @c => [nil, 11, 14] + }) + end + end + end + end + + def assert_nested_set_values(h) + assert Project.valid? + h.each do |project, expected| + project.reload + assert_equal expected, [project.parent_id, project.lft, project.rgt], "Unexpected nested set values for #{project.name}" + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/111782291673fa0d25a1477bea1c5d346d154c35.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/111782291673fa0d25a1477bea1c5d346d154c35.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +# Copyright (c) 2009 Michael Koziarski +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +require 'bigdecimal' + +alias BigDecimalUnsafe BigDecimal + + +# This fixes CVE-2009-1904 however it removes legitimate functionality that your +# application may depend on. You are *strongly* advised to upgrade your ruby +# rather than relying on this fix for an extended period of time. + +def BigDecimal(initial, digits=0) + if initial.size > 255 || initial =~ /e/i + raise "Invalid big Decimal Value" + end + BigDecimalUnsafe(initial, digits) +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/1126b71d1361e2719f05011613589ea2d0df072c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/1126b71d1361e2719f05011613589ea2d0df072c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,564 @@ +# Copyright (c) 2005 Rick Olson +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module ActiveRecord #:nodoc: + module Acts #:nodoc: + # Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a + # versioned table ready and that your model has a version field. This works with optimistic locking if the lock_version + # column is present as well. + # + # The class for the versioned model is derived the first time it is seen. Therefore, if you change your database schema you have to restart + # your container for the changes to be reflected. In development mode this usually means restarting WEBrick. + # + # class Page < ActiveRecord::Base + # # assumes pages_versions table + # acts_as_versioned + # end + # + # Example: + # + # page = Page.create(:title => 'hello world!') + # page.version # => 1 + # + # page.title = 'hello world' + # page.save + # page.version # => 2 + # page.versions.size # => 2 + # + # page.revert_to(1) # using version number + # page.title # => 'hello world!' + # + # page.revert_to(page.versions.last) # using versioned instance + # page.title # => 'hello world' + # + # page.versions.earliest # efficient query to find the first version + # page.versions.latest # efficient query to find the most recently created version + # + # + # Simple Queries to page between versions + # + # page.versions.before(version) + # page.versions.after(version) + # + # Access the previous/next versions from the versioned model itself + # + # version = page.versions.latest + # version.previous # go back one version + # version.next # go forward one version + # + # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options + module Versioned + CALLBACKS = [:set_new_version, :save_version_on_create, :save_version?, :clear_altered_attributes] + def self.included(base) # :nodoc: + base.extend ClassMethods + end + + module ClassMethods + # == Configuration options + # + # * class_name - versioned model class name (default: PageVersion in the above example) + # * table_name - versioned model table name (default: page_versions in the above example) + # * foreign_key - foreign key used to relate the versioned model to the original model (default: page_id in the above example) + # * inheritance_column - name of the column to save the model's inheritance_column value for STI. (default: versioned_type) + # * version_column - name of the column in the model that keeps the version number (default: version) + # * sequence_name - name of the custom sequence to be used by the versioned model. + # * limit - number of revisions to keep, defaults to unlimited + # * if - symbol of method to check before saving a new version. If this method returns false, a new version is not saved. + # For finer control, pass either a Proc or modify Model#version_condition_met? + # + # acts_as_versioned :if => Proc.new { |auction| !auction.expired? } + # + # or... + # + # class Auction + # def version_condition_met? # totally bypasses the :if option + # !expired? + # end + # end + # + # * if_changed - Simple way of specifying attributes that are required to be changed before saving a model. This takes + # either a symbol or array of symbols. WARNING - This will attempt to overwrite any attribute setters you may have. + # Use this instead if you want to write your own attribute setters (and ignore if_changed): + # + # def name=(new_name) + # write_changed_attribute :name, new_name + # end + # + # * extend - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block + # to create an anonymous mixin: + # + # class Auction + # acts_as_versioned do + # def started? + # !started_at.nil? + # end + # end + # end + # + # or... + # + # module AuctionExtension + # def started? + # !started_at.nil? + # end + # end + # class Auction + # acts_as_versioned :extend => AuctionExtension + # end + # + # Example code: + # + # @auction = Auction.find(1) + # @auction.started? + # @auction.versions.first.started? + # + # == Database Schema + # + # The model that you're versioning needs to have a 'version' attribute. The model is versioned + # into a table called #{model}_versions where the model name is singlular. The _versions table should + # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field. + # + # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance, + # then that field is reflected in the versioned model as 'versioned_type' by default. + # + # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table + # method, perfect for a migration. It will also create the version column if the main model does not already have it. + # + # class AddVersions < ActiveRecord::Migration + # def self.up + # # create_versioned_table takes the same options hash + # # that create_table does + # Post.create_versioned_table + # end + # + # def self.down + # Post.drop_versioned_table + # end + # end + # + # == Changing What Fields Are Versioned + # + # By default, acts_as_versioned will version all but these fields: + # + # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column] + # + # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols. + # + # class Post < ActiveRecord::Base + # acts_as_versioned + # self.non_versioned_columns << 'comments_count' + # end + # + def acts_as_versioned(options = {}, &extension) + # don't allow multiple calls + return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods) + + send :include, ActiveRecord::Acts::Versioned::ActMethods + + cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, + :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns, + :version_association_options + + # legacy + alias_method :non_versioned_fields, :non_versioned_columns + alias_method :non_versioned_fields=, :non_versioned_columns= + + class << self + alias_method :non_versioned_fields, :non_versioned_columns + alias_method :non_versioned_fields=, :non_versioned_columns= + end + + send :attr_accessor, :altered_attributes + + self.versioned_class_name = options[:class_name] || "Version" + self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key + self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}" + self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" + self.version_column = options[:version_column] || 'version' + self.version_sequence_name = options[:sequence_name] + self.max_version_limit = options[:limit].to_i + self.version_condition = options[:if] || true + self.non_versioned_columns = [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column] + self.version_association_options = { + :class_name => "#{self.to_s}::#{versioned_class_name}", + :foreign_key => versioned_foreign_key, + :dependent => :delete_all + }.merge(options[:association_options] || {}) + + if block_given? + extension_module_name = "#{versioned_class_name}Extension" + silence_warnings do + self.const_set(extension_module_name, Module.new(&extension)) + end + + options[:extend] = self.const_get(extension_module_name) + end + + class_eval do + has_many :versions, version_association_options do + # finds earliest version of this record + def earliest + @earliest ||= find(:first, :order => 'version') + end + + # find latest version of this record + def latest + @latest ||= find(:first, :order => 'version desc') + end + end + before_save :set_new_version + after_create :save_version_on_create + after_update :save_version + after_save :clear_old_versions + after_save :clear_altered_attributes + + unless options[:if_changed].nil? + self.track_altered_attributes = true + options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array) + options[:if_changed].each do |attr_name| + define_method("#{attr_name}=") do |value| + write_changed_attribute attr_name, value + end + end + end + + include options[:extend] if options[:extend].is_a?(Module) + end + + # create the dynamic versioned model + const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do + def self.reloadable? ; false ; end + # find first version before the given version + def self.before(version) + find :first, :order => 'version desc', + :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version] + end + + # find first version after the given version. + def self.after(version) + find :first, :order => 'version', + :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version] + end + + def previous + self.class.before(self) + end + + def next + self.class.after(self) + end + + def versions_count + page.version + end + end + + versioned_class.cattr_accessor :original_class + versioned_class.original_class = self + versioned_class.set_table_name versioned_table_name + versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym, + :class_name => "::#{self.to_s}", + :foreign_key => versioned_foreign_key + versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module) + versioned_class.set_sequence_name version_sequence_name if version_sequence_name + end + end + + module ActMethods + def self.included(base) # :nodoc: + base.extend ClassMethods + end + + # Finds a specific version of this record + def find_version(version = nil) + self.class.find_version(id, version) + end + + # Saves a version of the model if applicable + def save_version + save_version_on_create if save_version? + end + + # Saves a version of the model in the versioned table. This is called in the after_save callback by default + def save_version_on_create + rev = self.class.versioned_class.new + self.clone_versioned_model(self, rev) + rev.version = send(self.class.version_column) + rev.send("#{self.class.versioned_foreign_key}=", self.id) + rev.save + end + + # Clears old revisions if a limit is set with the :limit option in acts_as_versioned. + # Override this method to set your own criteria for clearing old versions. + def clear_old_versions + return if self.class.max_version_limit == 0 + excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit + if excess_baggage > 0 + sql = "DELETE FROM #{self.class.versioned_table_name} WHERE version <= #{excess_baggage} AND #{self.class.versioned_foreign_key} = #{self.id}" + self.class.versioned_class.connection.execute sql + end + end + + def versions_count + version + end + + # Reverts a model to a given version. Takes either a version number or an instance of the versioned model + def revert_to(version) + if version.is_a?(self.class.versioned_class) + return false unless version.send(self.class.versioned_foreign_key) == self.id and !version.new_record? + else + return false unless version = versions.find_by_version(version) + end + self.clone_versioned_model(version, self) + self.send("#{self.class.version_column}=", version.version) + true + end + + # Reverts a model to a given version and saves the model. + # Takes either a version number or an instance of the versioned model + def revert_to!(version) + revert_to(version) ? save_without_revision : false + end + + # Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created. + def save_without_revision + save_without_revision! + true + rescue + false + end + + def save_without_revision! + without_locking do + without_revision do + save! + end + end + end + + # Returns an array of attribute keys that are versioned. See non_versioned_columns + def versioned_attributes + self.attributes.keys.select { |k| !self.class.non_versioned_columns.include?(k) } + end + + # If called with no parameters, gets whether the current model has changed and needs to be versioned. + # If called with a single parameter, gets whether the parameter has changed. + def changed?(attr_name = nil) + attr_name.nil? ? + (!self.class.track_altered_attributes || (altered_attributes && altered_attributes.length > 0)) : + (altered_attributes && altered_attributes.include?(attr_name.to_s)) + end + + # keep old dirty? method + alias_method :dirty?, :changed? + + # Clones a model. Used when saving a new version or reverting a model's version. + def clone_versioned_model(orig_model, new_model) + self.versioned_attributes.each do |key| + new_model.send("#{key}=", orig_model.send(key)) if orig_model.has_attribute?(key) + end + + if orig_model.is_a?(self.class.versioned_class) + new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] + elsif new_model.is_a?(self.class.versioned_class) + new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column] + end + end + + # Checks whether a new version shall be saved or not. Calls version_condition_met? and changed?. + def save_version? + version_condition_met? && changed? + end + + # Checks condition set in the :if option to check whether a revision should be created or not. Override this for + # custom version condition checking. + def version_condition_met? + case + when version_condition.is_a?(Symbol) + send(version_condition) + when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1) + version_condition.call(self) + else + version_condition + end + end + + # Executes the block with the versioning callbacks disabled. + # + # @foo.without_revision do + # @foo.save + # end + # + def without_revision(&block) + self.class.without_revision(&block) + end + + # Turns off optimistic locking for the duration of the block + # + # @foo.without_locking do + # @foo.save + # end + # + def without_locking(&block) + self.class.without_locking(&block) + end + + def empty_callback() end #:nodoc: + + protected + # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version. + def set_new_version + self.send("#{self.class.version_column}=", self.next_version) if new_record? || (!locking_enabled? && save_version?) + end + + # Gets the next available version for the current record, or 1 for a new record + def next_version + return 1 if new_record? + (versions.calculate(:max, :version) || 0) + 1 + end + + # clears current changed attributes. Called after save. + def clear_altered_attributes + self.altered_attributes = [] + end + + def write_changed_attribute(attr_name, attr_value) + # Convert to db type for comparison. Avoids failing Float<=>String comparisons. + attr_value_for_db = self.class.columns_hash[attr_name.to_s].type_cast(attr_value) + (self.altered_attributes ||= []) << attr_name.to_s unless self.changed?(attr_name) || self.send(attr_name) == attr_value_for_db + write_attribute(attr_name, attr_value_for_db) + end + + module ClassMethods + # Finds a specific version of a specific row of this model + def find_version(id, version = nil) + return find(id) unless version + + conditions = ["#{versioned_foreign_key} = ? AND version = ?", id, version] + options = { :conditions => conditions, :limit => 1 } + + if result = find_versions(id, options).first + result + else + raise RecordNotFound, "Couldn't find #{name} with ID=#{id} and VERSION=#{version}" + end + end + + # Finds versions of a specific model. Takes an options hash like find + def find_versions(id, options = {}) + versioned_class.find :all, { + :conditions => ["#{versioned_foreign_key} = ?", id], + :order => 'version' }.merge(options) + end + + # Returns an array of columns that are versioned. See non_versioned_columns + def versioned_columns + self.columns.select { |c| !non_versioned_columns.include?(c.name) } + end + + # Returns an instance of the dynamic versioned model + def versioned_class + const_get versioned_class_name + end + + # Rake migration task to create the versioned table using options passed to acts_as_versioned + def create_versioned_table(create_table_options = {}) + # create version column in main table if it does not exist + if !self.content_columns.find { |c| %w(version lock_version).include? c.name } + self.connection.add_column table_name, :version, :integer + end + + self.connection.create_table(versioned_table_name, create_table_options) do |t| + t.column versioned_foreign_key, :integer + t.column :version, :integer + end + + updated_col = nil + self.versioned_columns.each do |col| + updated_col = col if !updated_col && %(updated_at updated_on).include?(col.name) + self.connection.add_column versioned_table_name, col.name, col.type, + :limit => col.limit, + :default => col.default, + :scale => col.scale, + :precision => col.precision + end + + if type_col = self.columns_hash[inheritance_column] + self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type, + :limit => type_col.limit, + :default => type_col.default, + :scale => type_col.scale, + :precision => type_col.precision + end + + if updated_col.nil? + self.connection.add_column versioned_table_name, :updated_at, :timestamp + end + end + + # Rake migration task to drop the versioned table + def drop_versioned_table + self.connection.drop_table versioned_table_name + end + + # Executes the block with the versioning callbacks disabled. + # + # Foo.without_revision do + # @foo.save + # end + # + def without_revision(&block) + class_eval do + CALLBACKS.each do |attr_name| + alias_method "orig_#{attr_name}".to_sym, attr_name + alias_method attr_name, :empty_callback + end + end + block.call + ensure + class_eval do + CALLBACKS.each do |attr_name| + alias_method attr_name, "orig_#{attr_name}".to_sym + end + end + end + + # Turns off optimistic locking for the duration of the block + # + # Foo.without_locking do + # @foo.save + # end + # + def without_locking(&block) + current = ActiveRecord::Base.lock_optimistically + ActiveRecord::Base.lock_optimistically = false if current + result = block.call + ActiveRecord::Base.lock_optimistically = true if current + result + end + end + end + end + end +end + +ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/114393c547ad97cfcaa80a6e77c3315b6cf82431.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/114393c547ad97cfcaa80a6e77c3315b6cf82431.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +module MailHelper + def do_something_helpful(var) + var.to_s.reverse + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/114804002a97fae230bf3b7bfcc60886698c2dd0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/114804002a97fae230bf3b7bfcc60886698c2dd0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +<% if @deliveries %> +<% form_tag({:action => 'edit', :tab => 'notifications'}) do %> + +
+

<%= setting_text_field :mail_from, :size => 60 %>

+ +

<%= setting_check_box :bcc_recipients %>

+ +

<%= setting_check_box :plain_text_mail %>

+ +

<%= setting_select(:default_notification_option, User.valid_notification_options.collect {|o| [l(o.last), o.first.to_s]}) %>

+ +
+ +
<%=l(:text_select_mail_notifications)%> +<%= hidden_field_tag 'settings[notified_events][]', '' %> +<% @notifiables.each do |notifiable| %> +<%= notification_field notifiable %> +
+<% end %> +

<%= check_all_links('notified_events') %>

+
+ +
<%= l(:setting_emails_header) %> +<%= setting_text_area :emails_header, :label => false, :class => 'wiki-edit', :rows => 5 %> +
+ +
<%= l(:setting_emails_footer) %> +<%= setting_text_area :emails_footer, :label => false, :class => 'wiki-edit', :rows => 5 %> +
+ +
+<%= link_to l(:label_send_test_email), :controller => 'admin', :action => 'test_email' %> +
+ +<%= submit_tag l(:button_save) %> +<% end %> +<% else %> +
+<%= simple_format(l(:text_email_delivery_not_configured)) %> +
+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/114bca33e13814e69bb30791d00e3851d89cb11c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/114bca33e13814e69bb30791d00e3851d89cb11c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +documents_001: + created_on: 2007-01-27 15:08:27 +01:00 + project_id: 1 + title: "Test document" + id: 1 + description: "Document description" + category_id: 1 +documents_002: + created_on: 2007-02-12 15:08:27 +01:00 + project_id: 1 + title: "An other document" + id: 2 + description: "" + category_id: 1 \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/116cfd340b5f6c9c6323607765d15102ca0bece3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/116cfd340b5f6c9c6323607765d15102ca0bece3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class IssueStartDate < ActiveRecord::Migration + def self.up + add_column :issues, :start_date, :date + add_column :issues, :done_ratio, :integer, :default => 0, :null => false + end + + def self.down + remove_column :issues, :start_date + remove_column :issues, :done_ratio + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/119d49f6464bf67d20c576180ecf3171b1346824.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/119d49f6464bf67d20c576180ecf3171b1346824.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Gampol Thitinilnithi, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("อาทิตย์", + "จันทร์", + "อังคาร", + "พุธ", + "พฤหัสบดี", + "ศุกร์", + "เสาร์", + "อาทิตย์"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("อา.", + "จ.", + "อ.", + "พ.", + "พฤ.", + "ศ.", + "ส.", + "อา."); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("มกราคม", + "กุมภาพันธ์", + "มีนาคม", + "เมษายน", + "พฤษภาคม", + "มิถุนายน", + "กรกฎาคม", + "สิงหาคม", + "กันยายน", + "ตุลาคม", + "พฤศจิกายน", + "ธันวาคม"); + +// short month names +Calendar._SMN = new Array +("ม.ค.", + "ก.พ.", + "มี.ค.", + "เม.ย.", + "พ.ค.", + "มิ.ย.", + "ก.ค.", + "ส.ค.", + "ก.ย.", + "ต.ค.", + "พ.ย.", + "ธ.ค."); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "เกี่ยวกับปฏิทิน"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "ปีที่แล้ว (ถ้ากดค้างจะมีเมนู)"; +Calendar._TT["PREV_MONTH"] = "เดือนที่แล้ว (ถ้ากดค้างจะมีเมนู)"; +Calendar._TT["GO_TODAY"] = "ไปที่วันนี้"; +Calendar._TT["NEXT_MONTH"] = "เดือนหน้า (ถ้ากดค้างจะมีเมนู)"; +Calendar._TT["NEXT_YEAR"] = "ปีหน้า (ถ้ากดค้างจะมีเมนู)"; +Calendar._TT["SEL_DATE"] = "เลือกวัน"; +Calendar._TT["DRAG_TO_MOVE"] = "กดแล้วลากเพื่อย้าย"; +Calendar._TT["PART_TODAY"] = " (วันนี้)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "แสดง %s เป็นวันแรก"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "ปิด"; +Calendar._TT["TODAY"] = "วันนี้"; +Calendar._TT["TIME_PART"] = "(Shift-)กดหรือกดแล้วลากเพื่อเปลี่ยนค่า"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a %e %b"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "เวลา:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/11caec7ba0e56486601495ed3e744468ec15f734.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/11caec7ba0e56486601495ed3e744468ec15f734.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,48 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 VersionsHelper + + STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to) + + def render_issue_status_by(version, criteria) + criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria) + + h = Hash.new {|k,v| k[v] = [0, 0]} + begin + # Total issue count + Issue.count(:group => criteria, + :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s} + # Open issues count + Issue.count(:group => criteria, + :include => :status, + :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s} + rescue ActiveRecord::RecordNotFound + # When grouping by an association, Rails throws this exception if there's no result (bug) + end + counts = h.keys.compact.sort.collect {|k| {:group => k, :total => h[k][0], :open => h[k][1], :closed => (h[k][0] - h[k][1])}} + max = counts.collect {|c| c[:total]}.max + + render :partial => 'issue_counts', :locals => {:version => version, :criteria => criteria, :counts => counts, :max => max} + end + + def status_by_options_for_select(value) + options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/11/11f49f2c53a5591216f2864d819f2860ef3e3885.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/11/11f49f2c53a5591216f2864d819f2860ef3e3885.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +<% if @user.auth_source %><%= l(:mail_body_account_information_external, @user.auth_source.name) %> +<% else %><%= l(:mail_body_account_information) %>: +* <%= l(:field_login) %>: <%= @user.login %> +* <%= l(:field_password) %>: <%= @password %> +<% end %> +<%= l(:label_login) %>: <%= @login_url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/12/124c8ea6c27371f24076da94e97c521fc176d638.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/12/124c8ea6c27371f24076da94e97c521fc176d638.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,77 @@ +require File.expand_path('../../test_helper', __FILE__) + +class FilesControllerTest < ActionController::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :journals, :journal_details, + :attachments, + :versions + + def setup + @controller = FilesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @request.session[:user_id] = nil + Setting.default_language = 'en' + end + + def test_index + get :index, :project_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:containers) + + # file attached to the project + assert_tag :a, :content => 'project_file.zip', + :attributes => { :href => '/attachments/download/8/project_file.zip' } + + # file attached to a project's version + assert_tag :a, :content => 'version_file.zip', + :attributes => { :href => '/attachments/download/9/version_file.zip' } + end + + def test_create_file + set_tmp_attachments_directory + @request.session[:user_id] = 2 + Setting.notified_events = ['file_added'] + ActionMailer::Base.deliveries.clear + + assert_difference 'Attachment.count' do + post :create, :project_id => 1, :version_id => '', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} + assert_response :redirect + end + assert_redirected_to '/projects/ecookbook/files' + a = Attachment.find(:first, :order => 'created_on DESC') + assert_equal 'testfile.txt', a.filename + assert_equal Project.find(1), a.container + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert_equal "[eCookbook] New file", mail.subject + assert mail.body.include?('testfile.txt') + end + + def test_create_version_file + set_tmp_attachments_directory + @request.session[:user_id] = 2 + Setting.notified_events = ['file_added'] + + assert_difference 'Attachment.count' do + post :create, :project_id => 1, :version_id => '2', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} + assert_response :redirect + end + assert_redirected_to '/projects/ecookbook/files' + a = Attachment.find(:first, :order => 'created_on DESC') + assert_equal 'testfile.txt', a.filename + assert_equal Version.find(2), a.container + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/12/129a1be9ab4fb00e9e24a4a97d3003da6c507962.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/12/129a1be9ab4fb00e9e24a4a97d3003da6c507962.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ +<% if @project.boards.any? %> + + + + + + + + +<% @project.boards.each do |board| + next if board.new_record? %> + + + + + + +<% end %> + +
<%= l(:label_board) %><%= l(:field_description) %>
<%=h board.name %><%=h board.description %> + <% if authorize_for("boards", "edit") %> + <%= reorder_links('board', {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}) %> + <% end %> + + <%= link_to_if_authorized l(:button_edit), {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}, :class => 'icon icon-edit' %> + <%= link_to_if_authorized l(:button_delete), {:controller => 'boards', :action => 'destroy', :project_id => @project, :id => board}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> +
+<% else %> +

<%= l(:label_no_data) %>

+<% end %> + +

<%= link_to_if_authorized l(:label_board_new), {:controller => 'boards', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %>

diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/12/12d2aa017b97ff487eca5cc334afe4f6ec1d0dc6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/12/12d2aa017b97ff487eca5cc334afe4f6ec1d0dc6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +class NotifyMail < ActionMailer::Base + + helper :mail + + def signup(txt) + body(:name => txt) + end + + def multipart + recipients 'some_address@email.com' + subject 'multi part email' + from "another_user@email.com" + content_type 'multipart/alternative' + + part :content_type => "text/html", :body => render_message("multipart_html", {}) + part "text/plain" do |p| + p.body = render_message("multipart_plain", {}) + end + end + + def implicit_multipart + recipients 'some_address@email.com' + subject 'multi part email' + from "another_user@email.com" + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/12/12deb41d009d058f51dd523cc9acb26b734732d9.svn-base Binary file .svn/pristine/12/12deb41d009d058f51dd523cc9acb26b734732d9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/130043bdfae755b8a2fcb2b00201feff2d982de9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/130043bdfae755b8a2fcb2b00201feff2d982de9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +default: + somesetting: foo + +production: + +development: + +test: + somesetting: bar diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/134682aa67acff21c24711968698972a9dfb0d8a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/134682aa67acff21c24711968698972a9dfb0d8a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

<%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=l(:label_role_new)%>

+ +<% labelled_tabular_form_for :role, @role, :url => { :action => 'new' }, :html => {:id => 'role_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/134abc8208803badec34f77d9e7dc1b2f4a0df2f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/134abc8208803badec34f77d9e7dc1b2f4a0df2f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

<%=l(:label_settings)%>

+ +<%= render_tabs project_settings_tabs %> + +<% html_title(l(:label_settings)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/1360db03d113fb07eff0808c5131dd75d05da3fd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/1360db03d113fb07eff0808c5131dd75d05da3fd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar DE language +// Author: Jack (tR), +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sonntag", + "Montag", + "Dienstag", + "Mittwoch", + "Donnerstag", + "Freitag", + "Samstag", + "Sonntag"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// short day names +Calendar._SDN = new Array +("So", + "Mo", + "Di", + "Mi", + "Do", + "Fr", + "Sa", + "So"); + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "M\u00e4rz", + "April", + "Mai", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "Dezember"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "M\u00e4r", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Dez"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "\u00DCber dieses Kalendarmodul"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Datum ausw\u00e4hlen:\n" + +"- Benutzen Sie die \xab, \xbb Buttons um das Jahr zu w\u00e4hlen\n" + +"- Benutzen Sie die " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " Buttons um den Monat zu w\u00e4hlen\n" + +"- F\u00fcr eine Schnellauswahl halten Sie die Maustaste \u00fcber diesen Buttons fest."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Zeit ausw\u00e4hlen:\n" + +"- Klicken Sie auf die Teile der Uhrzeit, um diese zu erh\u00F6hen\n" + +"- oder klicken Sie mit festgehaltener Shift-Taste um diese zu verringern\n" + +"- oder klicken und festhalten f\u00fcr Schnellauswahl."; + +Calendar._TT["TOGGLE"] = "Ersten Tag der Woche w\u00e4hlen"; +Calendar._TT["PREV_YEAR"] = "Voriges Jahr (Festhalten f\u00fcr Schnellauswahl)"; +Calendar._TT["PREV_MONTH"] = "Voriger Monat (Festhalten f\u00fcr Schnellauswahl)"; +Calendar._TT["GO_TODAY"] = "Heute ausw\u00e4hlen"; +Calendar._TT["NEXT_MONTH"] = "N\u00e4chst. Monat (Festhalten f\u00fcr Schnellauswahl)"; +Calendar._TT["NEXT_YEAR"] = "N\u00e4chst. Jahr (Festhalten f\u00fcr Schnellauswahl)"; +Calendar._TT["SEL_DATE"] = "Datum ausw\u00e4hlen"; +Calendar._TT["DRAG_TO_MOVE"] = "Zum Bewegen festhalten"; +Calendar._TT["PART_TODAY"] = " (Heute)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Woche beginnt mit %s "; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Schlie\u00dfen"; +Calendar._TT["TODAY"] = "Heute"; +Calendar._TT["TIME_PART"] = "(Shift-)Klick oder Festhalten und Ziehen um den Wert zu \u00e4ndern"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Zeit:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/137331c94a623d300b9797520d5d31b04bbcafd5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/137331c94a623d300b9797520d5d31b04bbcafd5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class AdminTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def test_add_user + log_user("admin", "admin") + get "/users/new" + assert_response :success + assert_template "users/new" + post "/users/create", + :user => { :login => "psmith", :firstname => "Paul", + :lastname => "Smith", :mail => "psmith@somenet.foo", + :language => "en", :password => "psmith09", + :password_confirmation => "psmith09" } + + user = User.find_by_login("psmith") + assert_kind_of User, user + assert_redirected_to "/users/#{ user.id }/edit" + + logged_user = User.try_to_login("psmith", "psmith09") + assert_kind_of User, logged_user + assert_equal "Paul", logged_user.firstname + + put "users/#{user.id}", :id => user.id, :user => { :status => User::STATUS_LOCKED } + assert_redirected_to "/users/#{ user.id }/edit" + locked_user = User.try_to_login("psmith", "psmith09") + assert_equal nil, locked_user + end + + test "Add a user as an anonymous user should fail" do + post '/users/create', + :user => { :login => 'psmith', :firstname => 'Paul'}, + :password => "psmith09", :password_confirmation => "psmith09" + assert_response :redirect + assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fusers" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/138f43d777efffd6ecf4f9d5f88f24c526eb7287.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/138f43d777efffd6ecf4f9d5f88f24c526eb7287.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,135 @@ +module ActionView + module Helpers + # Provides methods for linking to ActionController::Pagination objects using a simple generator API. You can optionally + # also build your links manually using ActionView::Helpers::AssetHelper#link_to like so: + # + # <%= link_to "Previous page", { :page => paginator.current.previous } if paginator.current.previous %> + # <%= link_to "Next page", { :page => paginator.current.next } if paginator.current.next %> + module PaginationHelper + unless const_defined?(:DEFAULT_OPTIONS) + DEFAULT_OPTIONS = { + :name => :page, + :window_size => 2, + :always_show_anchors => true, + :link_to_current_page => false, + :params => {} + } + end + + # Creates a basic HTML link bar for the given +paginator+. Links will be created + # for the next and/or previous page and for a number of other pages around the current + # pages position. The +html_options+ hash is passed to +link_to+ when the links are created. + # + # ==== Options + # :name:: the routing name for this paginator + # (defaults to +page+) + # :prefix:: prefix for pagination links + # (i.e. Older Pages: 1 2 3 4) + # :suffix:: suffix for pagination links + # (i.e. 1 2 3 4 <- Older Pages) + # :window_size:: the number of pages to show around + # the current page (defaults to 2) + # :always_show_anchors:: whether or not the first and last + # pages should always be shown + # (defaults to +true+) + # :link_to_current_page:: whether or not the current page + # should be linked to (defaults to + # +false+) + # :params:: any additional routing parameters + # for page URLs + # + # ==== Examples + # # We'll assume we have a paginator setup in @person_pages... + # + # pagination_links(@person_pages) + # # => 1 2 3 ... 10 + # + # pagination_links(@person_pages, :link_to_current_page => true) + # # => 1 2 3 ... 10 + # + # pagination_links(@person_pages, :always_show_anchors => false) + # # => 1 2 3 + # + # pagination_links(@person_pages, :window_size => 1) + # # => 1 2 ... 10 + # + # pagination_links(@person_pages, :params => { :viewer => "flash" }) + # # => 1 2 3 ... + # # 10 + def pagination_links(paginator, options={}, html_options={}) + name = options[:name] || DEFAULT_OPTIONS[:name] + params = (options[:params] || DEFAULT_OPTIONS[:params]).clone + + prefix = options[:prefix] || '' + suffix = options[:suffix] || '' + + pagination_links_each(paginator, options, prefix, suffix) do |n| + params[name] = n + link_to(n.to_s, params, html_options) + end + end + + # Iterate through the pages of a given +paginator+, invoking a + # block for each page number that needs to be rendered as a link. + # + # ==== Options + # :window_size:: the number of pages to show around + # the current page (defaults to +2+) + # :always_show_anchors:: whether or not the first and last + # pages should always be shown + # (defaults to +true+) + # :link_to_current_page:: whether or not the current page + # should be linked to (defaults to + # +false+) + # + # ==== Example + # # Turn paginated links into an Ajax call + # pagination_links_each(paginator, page_options) do |link| + # options = { :url => {:action => 'list'}, :update => 'results' } + # html_options = { :href => url_for(:action => 'list') } + # + # link_to_remote(link.to_s, options, html_options) + # end + def pagination_links_each(paginator, options, prefix = nil, suffix = nil) + options = DEFAULT_OPTIONS.merge(options) + link_to_current_page = options[:link_to_current_page] + always_show_anchors = options[:always_show_anchors] + + current_page = paginator.current_page + window_pages = current_page.window(options[:window_size]).pages + return if window_pages.length <= 1 unless link_to_current_page + + first, last = paginator.first, paginator.last + + html = '' + + html << prefix if prefix + + if always_show_anchors and not (wp_first = window_pages[0]).first? + html << yield(first.number) + html << ' ... ' if wp_first.number - first.number > 1 + html << ' ' + end + + window_pages.each do |page| + if current_page == page && !link_to_current_page + html << page.number.to_s + else + html << yield(page.number) + end + html << ' ' + end + + if always_show_anchors and not (wp_last = window_pages[-1]).last? + html << ' ... ' if last.number - wp_last.number > 1 + html << yield(last.number) + end + + html << suffix if suffix + + html + end + + end # PaginationHelper + end # Helpers +end # ActionView diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/13a9de4a4790249b88f8367228e59b3e03f18775.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/13a9de4a4790249b88f8367228e59b3e03f18775.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +
+<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %> +
+ +<%= render_timelog_breadcrumb %> + +

<%= l(:label_spent_time) %>

+ +<% form_tag({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> + <% @criterias.each do |criteria| %> + <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> + <% end %> + <%= render :partial => 'timelog/date_range' %> + +

: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], + [l(:label_month), 'month'], + [l(:label_week), 'week'], + [l(:label_day_plural).titleize, 'day']], @columns), + :onchange => "this.form.onsubmit();" %> + + : <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l_or_humanize(@available_criterias[k][:label]), k]}), + :onchange => "this.form.submit();", + :style => 'width: 200px', + :id => nil, + :disabled => (@criterias.length >= 3), :id => "criterias") %> + <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, :class => 'icon icon-reload' %>

+<% end %> + +<% unless @criterias.empty? %> +
+

<%= l(:label_total) %>: <%= html_hours(l_hours(@total_hours)) %>

+
+ +<% unless @hours.empty? %> +
+ + + +<% @criterias.each do |criteria| %> + +<% end %> +<% columns_width = (40 / (@periods.length+1)).to_i %> +<% @periods.each do |period| %> + +<% end %> + + + + +<%= render :partial => 'report_criteria', :locals => {:criterias => @criterias, :hours => @hours, :level => 0} %> + + + <%= '' * (@criterias.size - 1) %> + <% total = 0 -%> + <% @periods.each do |period| -%> + <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%> + + <% end -%> + + + +
<%= l_or_humanize(@available_criterias[criteria][:label]) %><%= period %><%= l(:label_total) %>
<%= l(:label_total) %><%= html_hours("%.2f" % sum) if sum > 0 %><%= html_hours("%.2f" % total) if total > 0 %>
+
+ +<% other_formats_links do |f| %> + <%= f.link_to 'CSV', :url => params %> +<% end %> +<% end %> +<% end %> + +<% html_title l(:label_spent_time), l(:label_report) %> + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/13/13d58fac9d8f76e7061c50c043e9ceb3e590857c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/13/13d58fac9d8f76e7061c50c043e9ceb3e590857c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Namespace::SharedPluginController < ApplicationController + def an_action + render_class_and_action 'from beta_plugin' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/1416b352c6fb64d06513cc44f62b6e1f359f63c7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/1416b352c6fb64d06513cc44f62b6e1f359f63c7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<%= error_messages_for 'board' %> + + +
+

<%= f.text_field :name, :required => true %>

+

<%= f.text_field :description, :required => true, :size => 80 %>

+
+ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/142eda77e7e23817ff1c9eecae08c12f33882ae4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/142eda77e7e23817ff1c9eecae08c12f33882ae4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +en: + hello: "Hello from beta" + plugin: "beta" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/144ab265c109ceacc45d40d62097ae53d47da1fc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/144ab265c109ceacc45d40d62097ae53d47da1fc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +require 'acts_as_versioned' \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/144d87a484de2d989cccbe9e992e92ab12eacca5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/144d87a484de2d989cccbe9e992e92ab12eacca5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +class PopulateChangesetsUserId < ActiveRecord::Migration + def self.up + committers = Changeset.connection.select_values("SELECT DISTINCT committer FROM #{Changeset.table_name}") + committers.each do |committer| + next if committer.blank? + if committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + Changeset.update_all("user_id = #{u.id}", ["committer = ?", committer]) unless u.nil? + end + end + end + + def self.down + Changeset.update_all('user_id = NULL') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/147267197c59e4171e424ec83498747a79bcc270.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/147267197c59e4171e424ec83498747a79bcc270.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,74 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class WikiRedirectTest < ActiveSupport::TestCase + fixtures :projects, :wikis, :wiki_pages + + def setup + @wiki = Wiki.find(1) + @original = WikiPage.create(:wiki => @wiki, :title => 'Original title') + end + + def test_create_redirect + @original.title = 'New title' + assert @original.save + @original.reload + + assert_equal 'New_title', @original.title + assert @wiki.redirects.find_by_title('Original_title') + assert @wiki.find_page('Original title') + assert @wiki.find_page('ORIGINAL title') + end + + def test_update_redirect + # create a redirect that point to this page + assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title') + + @original.title = 'New title' + @original.save + # make sure the old page now points to the new page + assert_equal 'New_title', @wiki.find_page('An old page').title + end + + def test_reverse_rename + # create a redirect that point to this page + assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title') + + @original.title = 'An old page' + @original.save + assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'An_old_page') + assert @wiki.redirects.find_by_title_and_redirects_to('Original_title', 'An_old_page') + end + + def test_rename_to_already_redirected + assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Other_page') + + @original.title = 'An old page' + @original.save + # this redirect have to be removed since 'An old page' page now exists + assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'Other_page') + end + + def test_redirects_removed_when_deleting_page + assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title') + + @original.destroy + assert !@wiki.redirects.find(:first) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/148dc94f440c0c6c1fdf948749c8c6f100698d2e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/148dc94f440c0c6c1fdf948749c8c6f100698d2e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +module OpenIdAuthentication + class Nonce < ActiveRecord::Base + set_table_name :open_id_authentication_nonces + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/149151b89e5659b8d56fd85ed72924a5e1708683.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/149151b89e5659b8d56fd85ed72924a5e1708683.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +<% changesets.each do |changeset| %> +
+

<%= link_to_revision(changeset, changeset.project, + :text => "#{l(:label_revision)} #{changeset.format_identifier}") %>
+ <%= authoring(changeset.committed_on, changeset.author) %>

+
+ <%= textilizable(changeset, :comments) %> +
+
+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/14d47feeb8d09d5c60a469b92e31b17db8244cde.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/14d47feeb8d09d5c60a469b92e31b17db8244cde.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 WikiHelper + + def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0) + pages = pages.group_by(&:parent) unless pages.is_a?(Hash) + s = '' + if pages.has_key?(parent) + pages[parent].each do |page| + attrs = "value='#{page.id}'" + attrs << " selected='selected'" if selected == page + indent = (level > 0) ? (' ' * level * 2 + '» ') : nil + + s << "\n" + + wiki_page_options_for_select(pages, selected, page, level + 1) + end + end + s + end + + def wiki_page_breadcrumb(page) + breadcrumb(page.ancestors.reverse.collect {|parent| + link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project}) + }) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/14ee5b2fb5a9f9c39e2c17ac2573da976e834e55.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/14ee5b2fb5a9f9c39e2c17ac2573da976e834e55.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +<% fields_for :pref, @user.pref, :builder => TabularFormBuilder, :lang => current_language do |pref_fields| %> +

<%= pref_fields.check_box :hide_mail %>

+

<%= pref_fields.select :time_zone, ActiveSupport::TimeZone.all.collect {|z| [ z.to_s, z.name ]}, :include_blank => true %>

+

<%= pref_fields.select :comments_sorting, [[l(:label_chronological_order), 'asc'], [l(:label_reverse_chronological_order), 'desc']] %>

+

<%= pref_fields.check_box :warn_on_leaving_unsaved %>

+<% end %> + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/14/14f249183ef33935d6a7aa11b5f44b945eb0da01.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/14/14f249183ef33935d6a7aa11b5f44b945eb0da01.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +<%= error_messages_for 'document' %> +
+ +

+<%= select('document', 'category_id', DocumentCategory.active.collect {|c| [c.name, c.id]}) %>

+ +

+<%= text_field 'document', 'title', :size => 60 %>

+ +

+<%= text_area 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %>

+ +
+ +<%= wikitoolbar_for 'document_description' %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/15/150305318b29a9433291a10fc5660acea2682a2e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/15/150305318b29a9433291a10fc5660acea2682a2e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar BG language +// Author: Nikolay Solakov, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Неделя", + "Понеделник", + "Вторник", + "Сряда", + "Четвъртък", + "Петък", + "Събота", + "Неделя"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Нед", + "Пон", + "Вто", + "Сря", + "Чет", + "Пет", + "Съб", + "Нед"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Януари", + "Февруари", + "Март", + "Април", + "Май", + "Юни", + "Юли", + "Август", + "Септември", + "Октомври", + "Ноември", + "Декември"); + +// short month names +Calendar._SMN = new Array +("Яну", + "Фев", + "Мар", + "Апр", + "Май", + "Юни", + "Юли", + "Авг", + "Сеп", + "Окт", + "Ное", + "Дек"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "За календара"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Избор на дата:\n" + +"- Използвайте \xab, \xbb за избор на година\n" + +"- Използвайте " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " за избор на месец\n" + +"- Задръжте натиснат бутона за списък с години/месеци."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Избор на час:\n" + +"- Кликнете на числата от часа за да ги увеличите\n" + +"- или Shift-click за намаляването им\n" + +"- или кликнете и влачете за по-бърза промяна."; + +Calendar._TT["PREV_YEAR"] = "Предишна година (задръжте за списък)"; +Calendar._TT["PREV_MONTH"] = "Предишен месец (задръжте за списък)"; +Calendar._TT["GO_TODAY"] = "Днешна дата"; +Calendar._TT["NEXT_MONTH"] = "Следващ месец (задръжте за списък)"; +Calendar._TT["NEXT_YEAR"] = "Следваща година (задръжте за списък)"; +Calendar._TT["SEL_DATE"] = "Избор на дата"; +Calendar._TT["DRAG_TO_MOVE"] = "Дръпнете за преместване"; +Calendar._TT["PART_TODAY"] = " (днес)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Седмицата започва с %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Затвори"; +Calendar._TT["TODAY"] = "Днес"; +Calendar._TT["TIME_PART"] = "(Shift-)Click или влачене за промяна на стойност"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "седм"; +Calendar._TT["TIME"] = "Час:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/15/15d21a1706eae546ce61d70441487ce11c1bb585.svn-base Binary file .svn/pristine/15/15d21a1706eae546ce61d70441487ce11c1bb585.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/160ac2451e31892432ba296457c74729e5d47d98.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/16/160ac2451e31892432ba296457c74729e5d47d98.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> + +<% for detail in @journal.details -%> +<%= show_detail(detail, true) %> +<% end -%> + +<%= @journal.notes if @journal.notes? %> +---------------------------------------- +<%= render :partial => "issue.text.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/1665bbb2717b49de68649a3ba32e9deb6f26e40f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/16/1665bbb2717b49de68649a3ba32e9deb6f26e40f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6082 @@ +/* Prototype JavaScript framework, version 1.7 + * (c) 2005-2010 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + + Version: '1.7', + + Browser: (function(){ + var ua = navigator.userAgent; + var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; + return { + IE: !!window.attachEvent && !isOpera, + Opera: isOpera, + WebKit: ua.indexOf('AppleWebKit/') > -1, + Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, + MobileSafari: /Apple.*Mobile/.test(ua) + } + })(), + + BrowserFeatures: { + XPath: !!document.evaluate, + + SelectorsAPI: !!document.querySelector, + + ElementExtensions: (function() { + var constructor = window.Element || window.HTMLElement; + return !!(constructor && constructor.prototype); + })(), + SpecificElementExtensions: (function() { + if (typeof window.HTMLDivElement !== 'undefined') + return true; + + var div = document.createElement('div'), + form = document.createElement('form'), + isSupported = false; + + if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { + isSupported = true; + } + + div = form = null; + + return isSupported; + })() + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +var Abstract = { }; + + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +/* Based on Alex Arnell's inheritance implementation. */ + +var Class = (function() { + + var IS_DONTENUM_BUGGY = (function(){ + for (var p in { toString: 1 }) { + if (p === 'toString') return false; + } + return true; + })(); + + function subclass() {}; + function create() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0, length = properties.length; i < length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype, + properties = Object.keys(source); + + if (IS_DONTENUM_BUGGY) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames()[0] == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); +(function() { + + var _toString = Object.prototype.toString, + NULL_TYPE = 'Null', + UNDEFINED_TYPE = 'Undefined', + BOOLEAN_TYPE = 'Boolean', + NUMBER_TYPE = 'Number', + STRING_TYPE = 'String', + OBJECT_TYPE = 'Object', + FUNCTION_CLASS = '[object Function]', + BOOLEAN_CLASS = '[object Boolean]', + NUMBER_CLASS = '[object Number]', + STRING_CLASS = '[object String]', + ARRAY_CLASS = '[object Array]', + DATE_CLASS = '[object Date]', + NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && + typeof JSON.stringify === 'function' && + JSON.stringify(0) === '0' && + typeof JSON.stringify(Prototype.K) === 'undefined'; + + function Type(o) { + switch(o) { + case null: return NULL_TYPE; + case (void 0): return UNDEFINED_TYPE; + } + var type = typeof o; + switch(type) { + case 'boolean': return BOOLEAN_TYPE; + case 'number': return NUMBER_TYPE; + case 'string': return STRING_TYPE; + } + return OBJECT_TYPE; + } + + function extend(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; + } + + function inspect(object) { + try { + if (isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + } + + function toJSON(value) { + return Str('', { '': value }, []); + } + + function Str(key, holder, stack) { + var value = holder[key], + type = typeof value; + + if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + + var _class = _toString.call(value); + + switch (_class) { + case NUMBER_CLASS: + case BOOLEAN_CLASS: + case STRING_CLASS: + value = value.valueOf(); + } + + switch (value) { + case null: return 'null'; + case true: return 'true'; + case false: return 'false'; + } + + type = typeof value; + switch (type) { + case 'string': + return value.inspect(true); + case 'number': + return isFinite(value) ? String(value) : 'null'; + case 'object': + + for (var i = 0, length = stack.length; i < length; i++) { + if (stack[i] === value) { throw new TypeError(); } + } + stack.push(value); + + var partial = []; + if (_class === ARRAY_CLASS) { + for (var i = 0, length = value.length; i < length; i++) { + var str = Str(i, value, stack); + partial.push(typeof str === 'undefined' ? 'null' : str); + } + partial = '[' + partial.join(',') + ']'; + } else { + var keys = Object.keys(value); + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i], str = Str(key, value, stack); + if (typeof str !== "undefined") { + partial.push(key.inspect(true)+ ':' + str); + } + } + partial = '{' + partial.join(',') + '}'; + } + stack.pop(); + return partial; + } + } + + function stringify(object) { + return JSON.stringify(object); + } + + function toQueryString(object) { + return $H(object).toQueryString(); + } + + function toHTML(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + } + + function keys(object) { + if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } + var results = []; + for (var property in object) { + if (object.hasOwnProperty(property)) { + results.push(property); + } + } + return results; + } + + function values(object) { + var results = []; + for (var property in object) + results.push(object[property]); + return results; + } + + function clone(object) { + return extend({ }, object); + } + + function isElement(object) { + return !!(object && object.nodeType == 1); + } + + function isArray(object) { + return _toString.call(object) === ARRAY_CLASS; + } + + var hasNativeIsArray = (typeof Array.isArray == 'function') + && Array.isArray([]) && !Array.isArray({}); + + if (hasNativeIsArray) { + isArray = Array.isArray; + } + + function isHash(object) { + return object instanceof Hash; + } + + function isFunction(object) { + return _toString.call(object) === FUNCTION_CLASS; + } + + function isString(object) { + return _toString.call(object) === STRING_CLASS; + } + + function isNumber(object) { + return _toString.call(object) === NUMBER_CLASS; + } + + function isDate(object) { + return _toString.call(object) === DATE_CLASS; + } + + function isUndefined(object) { + return typeof object === "undefined"; + } + + extend(Object, { + extend: extend, + inspect: inspect, + toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, + toQueryString: toQueryString, + toHTML: toHTML, + keys: Object.keys || keys, + values: values, + clone: clone, + isElement: isElement, + isArray: isArray, + isHash: isHash, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isDate: isDate, + isUndefined: isUndefined + }); +})(); +Object.extend(Function.prototype, (function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + } + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + } + + function argumentNames() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + } + + function bind(context) { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + + function bindAsEventListener(context) { + var __method = this, args = slice.call(arguments, 1); + return function(event) { + var a = update([event || window.event], args); + return __method.apply(context, a); + } + } + + function curry() { + if (!arguments.length) return this; + var __method = this, args = slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } + + function delay(timeout) { + var __method = this, args = slice.call(arguments, 1); + timeout = timeout * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + } + + function defer() { + var args = update([0.01], arguments); + return this.delay.apply(this, args); + } + + function wrap(wrapper) { + var __method = this; + return function() { + var a = update([__method.bind(this)], arguments); + return wrapper.apply(this, a); + } + } + + function methodize() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + var a = update([this], arguments); + return __method.apply(null, a); + }; + } + + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})()); + + + +(function(proto) { + + + function toISOString() { + return this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z'; + } + + + function toJSON() { + return this.toISOString(); + } + + if (!proto.toISOString) proto.toISOString = toISOString; + if (!proto.toJSON) proto.toJSON = toJSON; + +})(Date.prototype); + + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + this.currentlyExecuting = false; + } catch(e) { + this.currentlyExecuting = false; + throw e; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, (function() { + var NATIVE_JSON_PARSE_SUPPORT = window.JSON && + typeof JSON.parse === 'function' && + JSON.parse('{"test": true}').test; + + function prepareReplacement(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; + } + + function gsub(pattern, replacement) { + var result = '', source = this, match; + replacement = prepareReplacement(replacement); + + if (Object.isString(pattern)) + pattern = RegExp.escape(pattern); + + if (!(pattern.length || pattern.source)) { + replacement = replacement(''); + return replacement + source.split('').join(replacement) + replacement; + } + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + } + + function sub(pattern, replacement, count) { + replacement = prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + } + + function scan(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + } + + function truncate(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + } + + function strip() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + function stripTags() { + return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); + } + + function stripScripts() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + } + + function extractScripts() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), + matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + } + + function evalScripts() { + return this.extractScripts().map(function(script) { return eval(script) }); + } + + function escapeHTML() { + return this.replace(/&/g,'&').replace(//g,'>'); + } + + function unescapeHTML() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + } + + + function toQueryParams(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()), + value = pair.length > 1 ? pair.join('=') : pair[0]; + + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + } + + function toArray() { + return this.split(''); + } + + function succ() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + } + + function times(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + } + + function camelize() { + return this.replace(/-+(.)?/g, function(match, chr) { + return chr ? chr.toUpperCase() : ''; + }); + } + + function capitalize() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + } + + function underscore() { + return this.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/-/g, '_') + .toLowerCase(); + } + + function dasherize() { + return this.replace(/_/g, '-'); + } + + function inspect(useDoubleQuotes) { + var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { + if (character in String.specialChar) { + return String.specialChar[character]; + } + return '\\u00' + character.charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } + + function unfilterJSON(filter) { + return this.replace(filter || Prototype.JSONFilter, '$1'); + } + + function isJSON() { + var str = this; + if (str.blank()) return false; + str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); + str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); + str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); + return (/^[\],:{}\s]*$/).test(str); + } + + function evalJSON(sanitize) { + var json = this.unfilterJSON(), + cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + if (cx.test(json)) { + json = json.replace(cx, function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + } + + function parseJSON() { + var json = this.unfilterJSON(); + return JSON.parse(json); + } + + function include(pattern) { + return this.indexOf(pattern) > -1; + } + + function startsWith(pattern) { + return this.lastIndexOf(pattern, 0) === 0; + } + + function endsWith(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.indexOf(pattern, d) === d; + } + + function empty() { + return this == ''; + } + + function blank() { + return /^\s*$/.test(this); + } + + function interpolate(object, pattern) { + return new Template(this, pattern).evaluate(object); + } + + return { + gsub: gsub, + sub: sub, + scan: scan, + truncate: truncate, + strip: String.prototype.trim || strip, + stripTags: stripTags, + stripScripts: stripScripts, + extractScripts: extractScripts, + evalScripts: evalScripts, + escapeHTML: escapeHTML, + unescapeHTML: unescapeHTML, + toQueryParams: toQueryParams, + parseQuery: toQueryParams, + toArray: toArray, + succ: succ, + times: times, + camelize: camelize, + capitalize: capitalize, + underscore: underscore, + dasherize: dasherize, + inspect: inspect, + unfilterJSON: unfilterJSON, + isJSON: isJSON, + evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, + include: include, + startsWith: startsWith, + endsWith: endsWith, + empty: empty, + blank: blank, + interpolate: interpolate + }; +})()); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (object && Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return (match[1] + ''); + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3], + pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = (function() { + function each(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + } + + function eachSlice(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + } + + function all(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + } + + function any(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + } + + function collect(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function detect(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + } + + function findAll(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function grep(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(RegExp.escape(filter)); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function include(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + } + + function inGroupsOf(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + } + + function inject(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + } + + function invoke(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + } + + function max(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + } + + function min(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + } + + function partition(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + } + + function pluck(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + } + + function reject(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function sortBy(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + } + + function toArray() { + return this.map(); + } + + function zip() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + } + + function size() { + return this.toArray().length; + } + + function inspect() { + return '#'; + } + + + + + + + + + + return { + each: each, + eachSlice: eachSlice, + all: all, + every: all, + any: any, + some: any, + collect: collect, + map: collect, + detect: detect, + findAll: findAll, + select: findAll, + filter: findAll, + grep: grep, + include: include, + member: include, + inGroupsOf: inGroupsOf, + inject: inject, + invoke: invoke, + max: max, + min: min, + partition: partition, + pluck: pluck, + reject: reject, + sortBy: sortBy, + toArray: toArray, + entries: toArray, + zip: zip, + size: size, + inspect: inspect, + find: detect + }; +})(); + +function $A(iterable) { + if (!iterable) return []; + if ('toArray' in Object(iterable)) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +Array.from = $A; + + +(function() { + var arrayProto = Array.prototype, + slice = arrayProto.slice, + _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available + + function each(iterator, context) { + for (var i = 0, length = this.length >>> 0; i < length; i++) { + if (i in this) iterator.call(context, this[i], i, this); + } + } + if (!_each) _each = each; + + function clear() { + this.length = 0; + return this; + } + + function first() { + return this[0]; + } + + function last() { + return this[this.length - 1]; + } + + function compact() { + return this.select(function(value) { + return value != null; + }); + } + + function flatten() { + return this.inject([], function(array, value) { + if (Object.isArray(value)) + return array.concat(value.flatten()); + array.push(value); + return array; + }); + } + + function without() { + var values = slice.call(arguments, 0); + return this.select(function(value) { + return !values.include(value); + }); + } + + function reverse(inline) { + return (inline === false ? this.toArray() : this)._reverse(); + } + + function uniq(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + } + + function intersect(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + } + + + function clone() { + return slice.call(this, 0); + } + + function size() { + return this.length; + } + + function inspect() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } + + function indexOf(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; + } + + function lastIndexOf(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; + } + + function concat() { + var array = slice.call(this, 0), item; + for (var i = 0, length = arguments.length; i < length; i++) { + item = arguments[i]; + if (Object.isArray(item) && !('callee' in item)) { + for (var j = 0, arrayLength = item.length; j < arrayLength; j++) + array.push(item[j]); + } else { + array.push(item); + } + } + return array; + } + + Object.extend(arrayProto, Enumerable); + + if (!arrayProto._reverse) + arrayProto._reverse = arrayProto.reverse; + + Object.extend(arrayProto, { + _each: _each, + clear: clear, + first: first, + last: last, + compact: compact, + flatten: flatten, + without: without, + reverse: reverse, + uniq: uniq, + intersect: intersect, + clone: clone, + toArray: clone, + size: size, + inspect: inspect + }); + + var CONCAT_ARGUMENTS_BUGGY = (function() { + return [].concat(arguments)[0][0] !== 1; + })(1,2) + + if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; + + if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; + if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})(); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + function initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + } + + + function _each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + + function set(key, value) { + return this._object[key] = value; + } + + function get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + } + + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + } + + function toObject() { + return Object.clone(this._object); + } + + + + function keys() { + return this.pluck('key'); + } + + function values() { + return this.pluck('value'); + } + + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + } + + function merge(object) { + return this.clone().update(object); + } + + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + function toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) { + var queryValues = []; + for (var i = 0, len = values.length, value; i < len; i++) { + value = values[i]; + queryValues.push(toQueryPair(key, value)); + } + return results.concat(queryValues); + } + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + } + + function inspect() { + return '#'; + } + + function clone() { + return new Hash(this); + } + + return { + initialize: initialize, + _each: _each, + set: set, + get: get, + unset: unset, + toObject: toObject, + toTemplateReplacements: toObject, + keys: keys, + values: values, + index: index, + merge: merge, + update: update, + toQueryString: toQueryString, + inspect: inspect, + toJSON: toObject, + clone: clone + }; +})()); + +Hash.from = $H; +Object.extend(Number.prototype, (function() { + function toColorPart() { + return this.toPaddedString(2, 16); + } + + function succ() { + return this + 1; + } + + function times(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + } + + function toPaddedString(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + } + + function abs() { + return Math.abs(this); + } + + function round() { + return Math.round(this); + } + + function ceil() { + return Math.ceil(this); + } + + function floor() { + return Math.floor(this); + } + + return { + toColorPart: toColorPart, + succ: succ, + times: times, + toPaddedString: toPaddedString, + abs: abs, + round: round, + ceil: ceil, + floor: floor + }; +})()); + +function $R(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { + function initialize(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + } + + function _each(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + } + + function include(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } + + return { + initialize: initialize, + _each: _each, + include: include + }; +})()); + + + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.isString(this.options.parameters) ? + this.options.parameters : + Object.toQueryString(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + params += (params ? '&' : '') + "_method=" + this.method; + this.method = 'post'; + } + + if (params && this.method === 'get') { + this.url += (this.url.include('?') ? '&' : '?') + params; + } + + this.parameters = params.toQueryParams(); + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300) || status == 304; + }, + + getStatus: function() { + try { + if (this.transport.status === 1223) return 204; + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null; } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + + + + + + + + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if (readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); + + +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + + + +(function(global) { + function shouldUseCache(tagName, attributes) { + if (tagName === 'select') return false; + if ('type' in attributes) return false; + return true; + } + + var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ + try { + var el = document.createElement(''); + return el.tagName.toLowerCase() === 'input' && el.name === 'x'; + } + catch(err) { + return false; + } + })(); + + var element = global.Element; + + global.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + + if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + + var node = shouldUseCache(tagName, attributes) ? + cache[tagName].cloneNode(false) : document.createElement(tagName); + + return Element.writeAttribute(node, attributes); + }; + + Object.extend(global.Element, element || { }); + if (element) global.Element.prototype = element.prototype; + +})(this); + +Element.idCounter = 1; +Element.cache = { }; + +Element._purgeElement = function(element) { + var uid = element._prototypeUID; + if (uid) { + Element.stopObserving(element); + element._prototypeUID = void 0; + delete Element.Storage[uid]; + } +} + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: (function(){ + + var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ + var el = document.createElement("select"), + isBuggy = true; + el.innerHTML = ""; + if (el.options && el.options[0]) { + isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; + } + el = null; + return isBuggy; + })(); + + var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ + try { + var el = document.createElement("table"); + if (el && el.tBodies) { + el.innerHTML = "test"; + var isBuggy = typeof el.tBodies[0] == "undefined"; + el = null; + return isBuggy; + } + } catch (e) { + return true; + } + })(); + + var LINK_ELEMENT_INNERHTML_BUGGY = (function() { + try { + var el = document.createElement('div'); + el.innerHTML = ""; + var isBuggy = (el.childNodes.length === 0); + el = null; + return isBuggy; + } catch(e) { + return true; + } + })(); + + var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY || + TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY; + + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { + var s = document.createElement("script"), + isBuggy = false; + try { + s.appendChild(document.createTextNode("")); + isBuggy = !s.firstChild || + s.firstChild && s.firstChild.nodeType !== 3; + } catch (e) { + isBuggy = true; + } + s = null; + return isBuggy; + })(); + + + function update(element, content) { + element = $(element); + var purgeElement = Element._purgeElement; + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + while (i--) purgeElement(descendants[i]); + + if (content && content.toElement) + content = content.toElement(); + + if (Object.isElement(content)) + return element.update().insert(content); + + content = Object.toHTML(content); + + var tagName = element.tagName.toUpperCase(); + + if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { + element.text = content; + return element; + } + + if (ANY_INNERHTML_BUGGY) { + if (tagName in Element._insertionTranslations.tags) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { + element.appendChild(node) + }); + } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf(' -1) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true); + nodes.each(function(node) { element.appendChild(node) }); + } + else { + element.innerHTML = content.stripScripts(); + } + } + else { + element.innerHTML = content.stripScripts(); + } + + content.evalScripts.bind(content).defer(); + return element; + } + + return update; + })(), + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), + attribute = pair.last(), + value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property, maximumLength) { + element = $(element); + maximumLength = maximumLength || -1; + var elements = []; + + while (element = element[property]) { + if (element.nodeType == 1) + elements.push(Element.extend(element)); + if (elements.length == maximumLength) + break; + } + + return elements; + }, + + ancestors: function(element) { + return Element.recursivelyCollect(element, 'parentNode'); + }, + + descendants: function(element) { + return Element.select(element, "*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + var results = [], child = $(element).firstChild; + while (child) { + if (child.nodeType === 1) { + results.push(Element.extend(child)); + } + child = child.nextSibling; + } + return results; + }, + + previousSiblings: function(element, maximumLength) { + return Element.recursivelyCollect(element, 'previousSibling'); + }, + + nextSiblings: function(element) { + return Element.recursivelyCollect(element, 'nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return Element.previousSiblings(element).reverse() + .concat(Element.nextSiblings(element)); + }, + + match: function(element, selector) { + element = $(element); + if (Object.isString(selector)) + return Prototype.Selector.match(element, selector); + return selector.match(element); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = Element.ancestors(element); + return Object.isNumber(expression) ? ancestors[expression] : + Prototype.Selector.find(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return Element.firstDescendant(element); + return Object.isNumber(expression) ? Element.descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.previousSiblings(), expression, index); + } else { + return element.recursivelyCollect("previousSibling", index + 1)[index]; + } + }, + + next: function(element, expression, index) { + element = $(element); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.nextSiblings(), expression, index); + } else { + var maximumLength = Object.isNumber(index) ? index + 1 : 1; + return element.recursivelyCollect("nextSibling", index + 1)[index]; + } + }, + + + select: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element); + }, + + adjacent: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element.parentNode).without(element); + }, + + identify: function(element) { + element = $(element); + var id = Element.readAttribute(element, 'id'); + if (id) return id; + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + Element.writeAttribute(element, 'id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return Element.getDimensions(element).height; + }, + + getWidth: function(element) { + return Element.getDimensions(element).width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!Element.hasClassName(element, className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return Element[Element.hasClassName(element, className) ? + 'removeClassName' : 'addClassName'](element, className); + }, + + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Element.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + source = $(source); + var p = Element.viewportOffset(source), delta = [0, 0], parent = null; + + element = $(element); + + if (Element.getStyle(element, 'position') == 'absolute') { + parent = Element.getOffsetParent(element); + delta = Element.viewportOffset(parent); + } + + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'height': case 'width': + if (!Element.visible(element)) return null; + + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = (function(){ + + var classProp = 'className', + forProp = 'for', + el = document.createElement('div'); + + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': forProp, + 'htmlFor': forProp + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute); + }, + _getAttr2: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'), f; + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + + if (String(value).indexOf('{') > -1) { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }; + } + else if (value === '') { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + }; + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + } + })(); + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr2, + src: v._getAttr2, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if (element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; +} + +if ('outerHTML' in document.documentElement) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(), + fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html, force) { + var div = new Element('div'), + t = Element._insertionTranslations.tags[tagName]; + + var workaround = false; + if (t) workaround = true; + else if (force) { + workaround = true; + t = ['', '', 0]; + } + + if (workaround) { + div.innerHTML = ' ' + t[0] + html + t[1]; + div.removeChild(div.firstChild); + for (var i = t[2]; i--; ) { + div = div.firstChild; + } + } + else { + div.innerHTML = html; + } + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
', 1], + TBODY: ['', '
', 2], + TR: ['', '
', 3], + TD: ['
', '
', 4], + SELECT: ['', 1] + } +}; + +(function() { + var tags = Element._insertionTranslations.tags; + Object.extend(tags, { + THEAD: tags.TBODY, + TFOOT: tags.TBODY, + TH: tags.TD + }); +})(); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')); + +Element.extend = (function() { + + function checkDeficiency(tagName) { + if (typeof window.Element != 'undefined') { + var proto = window.Element.prototype; + if (proto) { + var id = '_' + (Math.random()+'').slice(2), + el = document.createElement(tagName); + proto[id] = 'x'; + var isBuggy = (el[id] !== 'x'); + delete proto[id]; + el = null; + return isBuggy; + } + } + return false; + } + + function extendElementWith(element, methods) { + for (var property in methods) { + var value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + } + + var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + + if (Prototype.BrowserFeatures.SpecificElementExtensions) { + if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { + return function(element) { + if (element && typeof element._extendedByPrototype == 'undefined') { + var t = element.tagName; + if (t && (/^(?:object|applet|embed)$/i.test(t))) { + extendElementWith(element, Element.Methods); + extendElementWith(element, Element.Methods.Simulated); + extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); + } + } + return element; + } + } + return Prototype.K; + } + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || typeof element._extendedByPrototype != 'undefined' || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(); + + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + extendElementWith(element, methods); + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +if (document.documentElement.hasAttribute) { + Element.hasAttribute = function(element, attribute) { + return element.hasAttribute(attribute); + }; +} +else { + Element.hasAttribute = Element.Methods.Simulated.hasAttribute; +} + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods), + "BUTTON": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + var element = document.createElement(tagName), + proto = element['__proto__'] || element.constructor.prototype; + + element = null; + return proto; + } + + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + + if (F.ElementExtensions) { + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + + +document.viewport = { + + getDimensions: function() { + return { width: this.getWidth(), height: this.getHeight() }; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; + +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; + + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; + } else { + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = Element.Storage.UID++; + uid = element._prototypeUID; + } + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); + } + + return element; + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + }, + + clone: function(element, deep) { + if (!(element = $(element))) return; + var clone = element.cloneNode(deep); + clone._prototypeUID = void 0; + if (deep) { + var descendants = Element.select(clone, '*'), + i = descendants.length; + while (i--) { + descendants[i]._prototypeUID = void 0; + } + } + return Element.extend(clone); + }, + + purge: function(element) { + if (!(element = $(element))) return; + var purgeElement = Element._purgeElement; + + purgeElement(element); + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + + while (i--) purgeElement(descendants[i]); + + return null; + } +}); + +(function() { + + function toDecimal(pctString) { + var match = pctString.match(/^(\d+)%?$/i); + if (!match) return null; + return (Number(match[1]) / 100); + } + + function getPixelValue(value, property, context) { + var element = null; + if (Object.isElement(value)) { + element = value; + value = element.getStyle(property); + } + + if (value === null) { + return null; + } + + if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { + return window.parseFloat(value); + } + + var isPercentage = value.include('%'), isViewport = (context === document.viewport); + + if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) { + var style = element.style.left, rStyle = element.runtimeStyle.left; + element.runtimeStyle.left = element.currentStyle.left; + element.style.left = value || 0; + value = element.style.pixelLeft; + element.style.left = style; + element.runtimeStyle.left = rStyle; + + return value; + } + + if (element && isPercentage) { + context = context || element.parentNode; + var decimal = toDecimal(value); + var whole = null; + var position = element.getStyle('position'); + + var isHorizontal = property.include('left') || property.include('right') || + property.include('width'); + + var isVertical = property.include('top') || property.include('bottom') || + property.include('height'); + + if (context === document.viewport) { + if (isHorizontal) { + whole = document.viewport.getWidth(); + } else if (isVertical) { + whole = document.viewport.getHeight(); + } + } else { + if (isHorizontal) { + whole = $(context).measure('width'); + } else if (isVertical) { + whole = $(context).measure('height'); + } + } + + return (whole === null) ? 0 : whole * decimal; + } + + return 0; + } + + function toCSSPixels(number) { + if (Object.isString(number) && number.endsWith('px')) { + return number; + } + return number + 'px'; + } + + function isDisplayed(element) { + var originalElement = element; + while (element && element.parentNode) { + var display = element.getStyle('display'); + if (display === 'none') { + return false; + } + element = $(element.parentNode); + } + return true; + } + + var hasLayout = Prototype.K; + if ('currentStyle' in document.documentElement) { + hasLayout = function(element) { + if (!element.currentStyle.hasLayout) { + element.style.zoom = 1; + } + return element; + }; + } + + function cssNameFor(key) { + if (key.include('border')) key = key + '-width'; + return key.camelize(); + } + + Element.Layout = Class.create(Hash, { + initialize: function($super, element, preCompute) { + $super(); + this.element = $(element); + + Element.Layout.PROPERTIES.each( function(property) { + this._set(property, null); + }, this); + + if (preCompute) { + this._preComputing = true; + this._begin(); + Element.Layout.PROPERTIES.each( this._compute, this ); + this._end(); + this._preComputing = false; + } + }, + + _set: function(property, value) { + return Hash.prototype.set.call(this, property, value); + }, + + set: function(property, value) { + throw "Properties of Element.Layout are read-only."; + }, + + get: function($super, property) { + var value = $super(property); + return value === null ? this._compute(property) : value; + }, + + _begin: function() { + if (this._prepared) return; + + var element = this.element; + if (isDisplayed(element)) { + this._prepared = true; + return; + } + + var originalStyles = { + position: element.style.position || '', + width: element.style.width || '', + visibility: element.style.visibility || '', + display: element.style.display || '' + }; + + element.store('prototype_original_styles', originalStyles); + + var position = element.getStyle('position'), + width = element.getStyle('width'); + + if (width === "0px" || width === null) { + element.style.display = 'block'; + width = element.getStyle('width'); + } + + var context = (position === 'fixed') ? document.viewport : + element.parentNode; + + element.setStyle({ + position: 'absolute', + visibility: 'hidden', + display: 'block' + }); + + var positionedWidth = element.getStyle('width'); + + var newWidth; + if (width && (positionedWidth === width)) { + newWidth = getPixelValue(element, 'width', context); + } else if (position === 'absolute' || position === 'fixed') { + newWidth = getPixelValue(element, 'width', context); + } else { + var parent = element.parentNode, pLayout = $(parent).getLayout(); + + newWidth = pLayout.get('width') - + this.get('margin-left') - + this.get('border-left') - + this.get('padding-left') - + this.get('padding-right') - + this.get('border-right') - + this.get('margin-right'); + } + + element.setStyle({ width: newWidth + 'px' }); + + this._prepared = true; + }, + + _end: function() { + var element = this.element; + var originalStyles = element.retrieve('prototype_original_styles'); + element.store('prototype_original_styles', null); + element.setStyle(originalStyles); + this._prepared = false; + }, + + _compute: function(property) { + var COMPUTATIONS = Element.Layout.COMPUTATIONS; + if (!(property in COMPUTATIONS)) { + throw "Property not found."; + } + + return this._set(property, COMPUTATIONS[property].call(this, this.element)); + }, + + toObject: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var obj = {}; + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + var value = this.get(key); + if (value != null) obj[key] = value; + }, this); + return obj; + }, + + toHash: function() { + var obj = this.toObject.apply(this, arguments); + return new Hash(obj); + }, + + toCSS: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var css = {}; + + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; + + var value = this.get(key); + if (value != null) css[cssNameFor(key)] = value + 'px'; + }, this); + return css; + }, + + inspect: function() { + return "#"; + } + }); + + Object.extend(Element.Layout, { + PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), + + COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), + + COMPUTATIONS: { + 'height': function(element) { + if (!this._preComputing) this._begin(); + + var bHeight = this.get('border-box-height'); + if (bHeight <= 0) { + if (!this._preComputing) this._end(); + return 0; + } + + var bTop = this.get('border-top'), + bBottom = this.get('border-bottom'); + + var pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + if (!this._preComputing) this._end(); + + return bHeight - bTop - bBottom - pTop - pBottom; + }, + + 'width': function(element) { + if (!this._preComputing) this._begin(); + + var bWidth = this.get('border-box-width'); + if (bWidth <= 0) { + if (!this._preComputing) this._end(); + return 0; + } + + var bLeft = this.get('border-left'), + bRight = this.get('border-right'); + + var pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + if (!this._preComputing) this._end(); + + return bWidth - bLeft - bRight - pLeft - pRight; + }, + + 'padding-box-height': function(element) { + var height = this.get('height'), + pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + return height + pTop + pBottom; + }, + + 'padding-box-width': function(element) { + var width = this.get('width'), + pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + return width + pLeft + pRight; + }, + + 'border-box-height': function(element) { + if (!this._preComputing) this._begin(); + var height = element.offsetHeight; + if (!this._preComputing) this._end(); + return height; + }, + + 'border-box-width': function(element) { + if (!this._preComputing) this._begin(); + var width = element.offsetWidth; + if (!this._preComputing) this._end(); + return width; + }, + + 'margin-box-height': function(element) { + var bHeight = this.get('border-box-height'), + mTop = this.get('margin-top'), + mBottom = this.get('margin-bottom'); + + if (bHeight <= 0) return 0; + + return bHeight + mTop + mBottom; + }, + + 'margin-box-width': function(element) { + var bWidth = this.get('border-box-width'), + mLeft = this.get('margin-left'), + mRight = this.get('margin-right'); + + if (bWidth <= 0) return 0; + + return bWidth + mLeft + mRight; + }, + + 'top': function(element) { + var offset = element.positionedOffset(); + return offset.top; + }, + + 'bottom': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pHeight = parent.measure('height'); + + var mHeight = this.get('border-box-height'); + + return pHeight - mHeight - offset.top; + }, + + 'left': function(element) { + var offset = element.positionedOffset(); + return offset.left; + }, + + 'right': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pWidth = parent.measure('width'); + + var mWidth = this.get('border-box-width'); + + return pWidth - mWidth - offset.left; + }, + + 'padding-top': function(element) { + return getPixelValue(element, 'paddingTop'); + }, + + 'padding-bottom': function(element) { + return getPixelValue(element, 'paddingBottom'); + }, + + 'padding-left': function(element) { + return getPixelValue(element, 'paddingLeft'); + }, + + 'padding-right': function(element) { + return getPixelValue(element, 'paddingRight'); + }, + + 'border-top': function(element) { + return getPixelValue(element, 'borderTopWidth'); + }, + + 'border-bottom': function(element) { + return getPixelValue(element, 'borderBottomWidth'); + }, + + 'border-left': function(element) { + return getPixelValue(element, 'borderLeftWidth'); + }, + + 'border-right': function(element) { + return getPixelValue(element, 'borderRightWidth'); + }, + + 'margin-top': function(element) { + return getPixelValue(element, 'marginTop'); + }, + + 'margin-bottom': function(element) { + return getPixelValue(element, 'marginBottom'); + }, + + 'margin-left': function(element) { + return getPixelValue(element, 'marginLeft'); + }, + + 'margin-right': function(element) { + return getPixelValue(element, 'marginRight'); + } + } + }); + + if ('getBoundingClientRect' in document.documentElement) { + Object.extend(Element.Layout.COMPUTATIONS, { + 'right': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.right - rect.right).round(); + }, + + 'bottom': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.bottom - rect.bottom).round(); + } + }); + } + + Element.Offset = Class.create({ + initialize: function(left, top) { + this.left = left.round(); + this.top = top.round(); + + this[0] = this.left; + this[1] = this.top; + }, + + relativeTo: function(offset) { + return new Element.Offset( + this.left - offset.left, + this.top - offset.top + ); + }, + + inspect: function() { + return "#".interpolate(this); + }, + + toString: function() { + return "[#{left}, #{top}]".interpolate(this); + }, + + toArray: function() { + return [this.left, this.top]; + } + }); + + function getLayout(element, preCompute) { + return new Element.Layout(element, preCompute); + } + + function measure(element, property) { + return $(element).getLayout().get(property); + } + + function getDimensions(element) { + element = $(element); + var display = Element.getStyle(element, 'display'); + + if (display && display !== 'none') { + return { width: element.offsetWidth, height: element.offsetHeight }; + } + + var style = element.style; + var originalStyles = { + visibility: style.visibility, + position: style.position, + display: style.display + }; + + var newStyles = { + visibility: 'hidden', + display: 'block' + }; + + if (originalStyles.position !== 'fixed') + newStyles.position = 'absolute'; + + Element.setStyle(element, newStyles); + + var dimensions = { + width: element.offsetWidth, + height: element.offsetHeight + }; + + Element.setStyle(element, originalStyles); + + return dimensions; + } + + function getOffsetParent(element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var isInline = (Element.getStyle(element, 'display') === 'inline'); + if (!isInline && element.offsetParent) return $(element.offsetParent); + + while ((element = element.parentNode) && element !== document.body) { + if (Element.getStyle(element, 'position') !== 'static') { + return isHtml(element) ? $(document.body) : $(element); + } + } + + return $(document.body); + } + + + function cumulativeOffset(element) { + element = $(element); + var valueT = 0, valueL = 0; + if (element.parentNode) { + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + } + return new Element.Offset(valueL, valueT); + } + + function positionedOffset(element) { + element = $(element); + + var layout = element.getLayout(); + + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (isBody(element)) break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + + valueL -= layout.get('margin-top'); + valueT -= layout.get('margin-left'); + + return new Element.Offset(valueL, valueT); + } + + function cumulativeScrollOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return new Element.Offset(valueL, valueT); + } + + function viewportOffset(forElement) { + element = $(element); + var valueT = 0, valueL = 0, docBody = document.body; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == docBody && + Element.getStyle(element, 'position') == 'absolute') break; + } while (element = element.offsetParent); + + element = forElement; + do { + if (element != docBody) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + return new Element.Offset(valueL, valueT); + } + + function absolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } + + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), + pOffset = offsetParent.viewportOffset(); + + var offset = eOffset.relativeTo(pOffset); + var layout = element.getLayout(); + + element.store('prototype_absolutize_original_styles', { + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') + }); + + element.setStyle({ + position: 'absolute', + top: offset.top + 'px', + left: offset.left + 'px', + width: layout.get('width') + 'px', + height: layout.get('height') + 'px' + }); + + return element; + } + + function relativize(element) { + element = $(element); + if (Element.getStyle(element, 'position') === 'relative') { + return element; + } + + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + + if (Prototype.Browser.IE) { + getOffsetParent = getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + positionedOffset = positionedOffset.wrap(function(proceed, element) { + element = $(element); + if (!element.parentNode) return new Element.Offset(0, 0); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + hasLayout(offsetParent); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + }); + } else if (Prototype.Browser.Webkit) { + cumulativeOffset = function(element) { + element = $(element); + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return new Element.Offset(valueL, valueT); + }; + } + + + Element.addMethods({ + getLayout: getLayout, + measure: measure, + getDimensions: getDimensions, + getOffsetParent: getOffsetParent, + cumulativeOffset: cumulativeOffset, + positionedOffset: positionedOffset, + cumulativeScrollOffset: cumulativeScrollOffset, + viewportOffset: viewportOffset, + absolutize: absolutize, + relativize: relativize + }); + + function isBody(element) { + return element.nodeName.toUpperCase() === 'BODY'; + } + + function isHtml(element) { + return element.nodeName.toUpperCase() === 'HTML'; + } + + function isDocument(element) { + return element.nodeType === Node.DOCUMENT_NODE; + } + + function isDetached(element) { + return element !== document.body && + !Element.descendantOf(element, document.body); + } + + if ('getBoundingClientRect' in document.documentElement) { + Element.addMethods({ + viewportOffset: function(element) { + element = $(element); + if (isDetached(element)) return new Element.Offset(0, 0); + + var rect = element.getBoundingClientRect(), + docEl = document.documentElement; + return new Element.Offset(rect.left - docEl.clientLeft, + rect.top - docEl.clientTop); + } + }); + } +})(); +window.$$ = function() { + var expression = $A(arguments).join(', '); + return Prototype.Selector.select(expression, document); +}; + +Prototype.Selector = (function() { + + function select() { + throw new Error('Method "Prototype.Selector.select" must be defined.'); + } + + function match() { + throw new Error('Method "Prototype.Selector.match" must be defined.'); + } + + function find(elements, expression, index) { + index = index || 0; + var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; + + for (i = 0; i < length; i++) { + if (match(elements[i], expression) && index == matchIndex++) { + return Element.extend(elements[i]); + } + } + } + + function extendElements(elements) { + for (var i = 0, length = elements.length; i < length; i++) { + Element.extend(elements[i]); + } + return elements; + } + + + var K = Prototype.K; + + return { + select: select, + match: match, + find: find, + extendElements: (Element.extend === K) ? K : extendElements, + extendElement: Element.extend + }; +})(); +Prototype._original_property = window.Sizzle; +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +(function(){ + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
"; + + if ( div.getElementsByClassName("e").length === 0 ) + return; + + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + + +window.Sizzle = Sizzle; + +})(); + +;(function(engine) { + var extendElements = Prototype.Selector.extendElements; + + function select(selector, scope) { + return extendElements(engine(selector, scope || document)); + } + + function match(element, selector) { + return engine.matches(selector, [element]).length == 1; + } + + Prototype.Selector.engine = engine; + Prototype.Selector.select = select; + Prototype.Selector.match = match; +})(Sizzle); + +window.Sizzle = Prototype._original_property; +delete Prototype._original_property; + +var Form = { + reset: function(form) { + form = $(form); + form.reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit, accumulator, initial; + + if (options.hash) { + initial = {}; + accumulator = function(result, key, value) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } else result[key] = value; + return result; + }; + } else { + initial = ''; + accumulator = function(result, key, value) { + return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value); + } + } + + return elements.inject(initial, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + result = accumulator(result, key, value); + } + } + return result; + }); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + var elements = $(form).getElementsByTagName('*'), + element, + arr = [ ], + serializers = Form.Element.Serializers; + for (var i = 0; element = elements[i]; i++) { + arr.push(element); + } + return arr.inject([], function(elements, child) { + if (serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + }) + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return /^(?:input|select|textarea)$/i.test(element.tagName); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + var element = form.findFirstElement(); + if (element) element.activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !(/^(?:button|reset|submit)$/i.test(element.type)))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; + +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = (function() { + function input(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return inputSelector(element, value); + default: + return valueSelector(element, value); + } + } + + function inputSelector(element, value) { + if (Object.isUndefined(value)) + return element.checked ? element.value : null; + else element.checked = !!value; + } + + function valueSelector(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + } + + function select(element, value) { + if (Object.isUndefined(value)) + return (element.type === 'select-one' ? selectOne : selectMany)(element); + + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + + function selectOne(element) { + var index = element.selectedIndex; + return index >= 0 ? optionValue(element.options[index]) : null; + } + + function selectMany(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(optionValue(opt)); + } + return values; + } + + function optionValue(opt) { + return Element.hasAttribute(opt, 'value') ? opt.value : opt.text; + } + + return { + input: input, + inputSelector: inputSelector, + textarea: valueSelector, + select: select, + selectOne: selectOne, + selectMany: selectMany, + optionValue: optionValue, + button: valueSelector + }; +})(); + +/*--------------------------------------------------------------------------*/ + + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +(function() { + + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: {} + }; + + var docEl = document.documentElement; + var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl + && 'onmouseleave' in docEl; + + + + var isIELegacyEvent = function(event) { return false; }; + + if (window.attachEvent) { + if (window.addEventListener) { + isIELegacyEvent = function(event) { + return !(event instanceof window.Event); + }; + } else { + isIELegacyEvent = function(event) { return true; }; + } + } + + var _isButton; + + function _isButtonForDOMEvents(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + } + + var legacyButtonMap = { 0: 1, 1: 4, 2: 2 }; + function _isButtonForLegacyEvents(event, code) { + return event.button === legacyButtonMap[code]; + } + + function _isButtonForWebKit(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 2 || (event.which == 1 && event.metaKey); + case 2: return event.which == 3; + default: return false; + } + } + + if (window.attachEvent) { + if (!window.addEventListener) { + _isButton = _isButtonForLegacyEvents; + } else { + _isButton = function(event, code) { + return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) : + _isButtonForDOMEvents(event, code); + } + } + } else if (Prototype.Browser.WebKit) { + _isButton = _isButtonForWebKit; + } else { + _isButton = _isButtonForDOMEvents; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + + if (!expression) return element; + while (element) { + if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { + return Element.extend(element); + } + element = element.parentNode; + } + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop + }; + + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (window.attachEvent) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': + case 'mouseenter': + element = event.fromElement; + break; + case 'mouseout': + case 'mouseleave': + element = event.toElement; + break; + default: + return null; + } + return Element.extend(element); + } + + var additionalMethods = { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return '[object Event]' } + }; + + Event.extend = function(event, element) { + if (!event) return false; + + if (!isIELegacyEvent(event)) return event; + + if (event._extendedByPrototype) return event; + event._extendedByPrototype = Prototype.emptyFunction; + + var pointer = Event.pointer(event); + + Object.extend(event, { + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + + Object.extend(event, methods); + Object.extend(event, additionalMethods); + + return event; + }; + } else { + Event.extend = Prototype.K; + } + + if (window.addEventListener) { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; + Object.extend(Event.prototype, methods); + } + + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } + + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined(respondersForEvent)) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } + + if (respondersForEvent.pluck('handler').include(handler)) return false; + + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) + return false; + + if (event.eventName !== eventName) + return false; + + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); + + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } + + if (parent === element) return; + + handler.call(element, event); + }; + } + } else { + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; + } + } + + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } + + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } + + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K, + translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { + _getDOMEventName = function(eventName) { + return (translations[eventName] || eventName); + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onlosecapture", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + if (!registry) return element; + + if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key; + stopObserving(element, eventName); + }); + return element; + } + + var responders = registry.get(eventName); + if (!responders) return element; + + if (!handler) { + responders.each(function(r) { + stopObserving(element, eventName, r.handler); + }); + return element; + } + + var i = responders.length, responder; + while (i--) { + if (responders[i].handler === handler) { + responder = responders[i]; + break; + } + } + if (!responder) return element; + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onlosecapture", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', bubble, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onlosecapture'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + Event.Handler = Class.create({ + initialize: function(element, eventName, selector, callback) { + this.element = $(element); + this.eventName = eventName; + this.selector = selector; + this.callback = callback; + this.handler = this.handleEvent.bind(this); + }, + + start: function() { + Event.observe(this.element, this.eventName, this.handler); + return this; + }, + + stop: function() { + Event.stopObserving(this.element, this.eventName, this.handler); + return this; + }, + + handleEvent: function(event) { + var element = Event.findElement(event, this.selector); + if (element) this.callback.call(this.element, event, element); + } + }); + + function on(element, eventName, selector, callback) { + element = $(element); + if (Object.isFunction(selector) && Object.isUndefined(callback)) { + callback = selector, selector = null; + } + + return new Event.Handler(element, eventName, selector, callback).start(); + } + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving, + on: on + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving, + + on: on + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + on: on.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearTimeout(timer); + document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); + } else { + document.observe('readystatechange', checkReadyState); + if (window == top) + timer = pollDoScroll.defer(); + } + + Event.observe(window, 'load', fireContentLoadedEvent); +})(); + +Element.addMethods(); + +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +var Position = { + includeScrollOffsets: false, + + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ + +(function() { + window.Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + }, + + findElements: function(rootElement) { + return Prototype.Selector.select(this.expression, rootElement); + }, + + match: function(element) { + return Prototype.Selector.match(element, this.expression); + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#"; + } + }); + + Object.extend(Selector, { + matchElements: function(elements, expression) { + var match = Prototype.Selector.match, + results = []; + + for (var i = 0, length = elements.length; i < length; i++) { + var element = elements[i]; + if (match(element, expression)) { + results.push(Element.extend(element)); + } + } + return results; + }, + + findElement: function(elements, expression, index) { + index = index || 0; + var matchIndex = 0, element; + for (var i = 0, length = elements.length; i < length; i++) { + element = elements[i]; + if (Prototype.Selector.match(element, expression) && index === matchIndex++) { + return Element.extend(element); + } + } + }, + + findChildElements: function(element, expressions) { + var selector = expressions.toArray().join(', '); + return Prototype.Selector.select(selector, element || document); + } + }); +})(); diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/1687a877ada07f6d55e8625e14dc03b6de8d81a1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/16/1687a877ada07f6d55e8625e14dc03b6de8d81a1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2219 periodcentered +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+2553 SF520000 +!A5 U+2554 SF390000 +!A6 U+2555 SF220000 +!A7 U+2556 SF210000 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+255C SF270000 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+2562 SF200000 +!B5 U+2563 SF230000 +!B6 U+2564 SF470000 +!B7 U+2565 SF480000 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+256B SF530000 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/168f4b43a0af41730c1515591777202042d2e467.svn-base Binary file .svn/pristine/16/168f4b43a0af41730c1515591777202042d2e467.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/16917481a33c59388ad3557840898620ac722576.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/16/16917481a33c59388ad3557840898620ac722576.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= l(:mail_body_lost_password) %> +<%= @url %> + +<%= l(:field_login) %>: <%= @token.user.login %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/16a4737934df277bfc00665b78c7abfb7118a5ef.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/16/16a4737934df277bfc00665b78c7abfb7118a5ef.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= @message_url %> +<%= @message.author %> + +<%= @message.content %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/16/16c33740f5a772b206a960577ab56df891c0f33f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/16/16c33740f5a772b206a960577ab56df891c0f33f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +CREATE TABLE 'companies' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL, + 'rating' INTEGER DEFAULT 1 +); + +CREATE TABLE 'replies' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'content' text, + 'created_at' datetime, + 'updated_at' datetime, + 'topic_id' integer +); + +CREATE TABLE 'topics' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'title' varchar(255), + 'subtitle' varchar(255), + 'content' text, + 'created_at' datetime, + 'updated_at' datetime +); + +CREATE TABLE 'developers' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL, + 'salary' INTEGER DEFAULT 70000, + 'created_at' DATETIME DEFAULT NULL, + 'updated_at' DATETIME DEFAULT NULL +); + +CREATE TABLE 'projects' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL +); + +CREATE TABLE 'developers_projects' ( + 'developer_id' INTEGER NOT NULL, + 'project_id' INTEGER NOT NULL, + 'joined_on' DATE DEFAULT NULL, + 'access_level' INTEGER DEFAULT 1 +); diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/175ce98d0f45b612d93a4554fb4f76c1be18c0ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/175ce98d0f45b612d93a4554fb4f76c1be18c0ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../../config/boot', __FILE__) +require 'commands/performance/benchmarker' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17973741c668d43d267b734fcb018ab64a0d87f9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17973741c668d43d267b734fcb018ab64a0d87f9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +

<%= l(:label_plugins) %>

+ +<% if @plugins.any? %> + + <% @plugins.each do |plugin| %> + + + + + + + <% end %> +
<%=h plugin.name %> + <%= content_tag('span', h(plugin.description), :class => 'description') unless plugin.description.blank? %> + <%= content_tag('span', link_to(h(plugin.url), plugin.url), :class => 'url') unless plugin.url.blank? %> + <%= plugin.author_url.blank? ? h(plugin.author) : link_to(h(plugin.author), plugin.author_url) %><%=h plugin.version %><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.id) if plugin.configurable? %>
+<% else %> +

<%= l(:label_no_data) %>

+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17c033d2aba8bd48a0c5240eb040a0c6c95834ea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17c033d2aba8bd48a0c5240eb040a0c6c95834ea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class IssueMove < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "move_issues", :description => "button_move", :sort => 1061, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'move_issues']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17c53021398a51ccae878d86cdd4f0a66880e996.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17c53021398a51ccae878d86cdd4f0a66880e996.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class AddCommentsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "news", :action => "add_comment", :description => "label_comment_add", :sort => 1130, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "news", :action => "destroy_comment", :description => "label_comment_delete", :sort => 1133, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'news', 'add_comment']).destroy + Permission.find(:first, :conditions => ["controller=? and action=?", 'news', 'destroy_comment']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17d43ea055a7a8001dad09ba9decc118c095d5fe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17d43ea055a7a8001dad09ba9decc118c095d5fe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +<% labelled_tabular_form_for :issue, @issue, + :url => {:action => 'update', :id => @issue}, + :html => {:id => 'issue-form', + :class => nil, + :method => :put, + :multipart => true} do |f| %> + <%= error_messages_for 'issue', 'time_entry' %> +
+ <% if @edit_allowed || !@allowed_statuses.empty? %> +
<%= l(:label_change_properties) %> + <% if !@issue.new_record? && !@issue.errors.any? && @edit_allowed %> + (<%= link_to l(:label_more), {}, :onclick => 'Effect.toggle("issue_descr_fields", "appear", {duration:0.3}); return false;' %>) + <% end %> + + <%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %> +
+ <% end %> + <% if User.current.allowed_to?(:log_time, @project) %> +
<%= l(:button_log_time) %> + <% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %> +
+

<%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %>

+
+
+

<%= time_entry.select :activity_id, activity_collection_for_select_options %>

+
+

<%= time_entry.text_field :comments, :size => 60 %>

+ <% @time_entry.custom_field_values.each do |value| %> +

<%= custom_field_tag_with_label :time_entry, value %>

+ <% end %> + <% end %> +
+ <% end %> + +
<%= l(:field_notes) %> + <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'notes' %> + <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> + +

<%=l(:label_attachment_plural)%>
<%= render :partial => 'attachments/form' %>

+
+
+ + <%= f.hidden_field :lock_version %> + <%= submit_tag l(:button_submit) %> + <%= link_to_remote l(:label_preview), + { :url => preview_issue_path(:project_id => @project, :id => @issue), + :method => 'post', + :update => 'preview', + :with => 'Form.serialize("issue-form")', + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> +<% end %> + +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17e6519b50da04ce88ce18f460d2215c425cc034.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17e6519b50da04ce88ce18f460d2215c425cc034.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +
+ <%= yield %> +
\ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17f362b58e5928588fba117c59a1faaa4e2cd401.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17f362b58e5928588fba117c59a1faaa4e2cd401.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negriña'; +jsToolBar.strings['Italic'] = 'Itálica'; +jsToolBar.strings['Underline'] = 'Suliñado'; +jsToolBar.strings['Deleted'] = 'Tachado'; +jsToolBar.strings['Code'] = 'Código fonte'; +jsToolBar.strings['Heading 1'] = 'Encabezado 1'; +jsToolBar.strings['Heading 2'] = 'Encabezado 2'; +jsToolBar.strings['Heading 3'] = 'Encabezado 3'; +jsToolBar.strings['Unordered list'] = 'Lista sen ordenar'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citar'; +jsToolBar.strings['Unquote'] = 'Quitar cita'; +jsToolBar.strings['Preformatted text'] = 'Texto con formato'; +jsToolBar.strings['Wiki link'] = 'Enlace a páxina Wiki'; +jsToolBar.strings['Image'] = 'Imaxe'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/17/17f782f3ce13f8d3847651a0f8efc45b475de826.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/17/17f782f3ce13f8d3847651a0f8efc45b475de826.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +# Sample plugin +en: + label_plugin_example: Sample Plugin + label_meeting_plural: Meetings + text_say_hello: Plugin say 'Hello' + text_say_goodbye: Plugin say 'Good bye' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/182b1b357cf2d5daa1faf5abe56eab7ea9d5bbd5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/182b1b357cf2d5daa1faf5abe56eab7ea9d5bbd5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,155 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'messages_controller' + +# Re-raise errors caught by the controller. +class MessagesController; def rescue_action(e) raise e end; end + +class MessagesControllerTest < ActionController::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, :boards, :messages, :enabled_modules + + def setup + @controller = MessagesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_show + get :show, :board_id => 1, :id => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:board) + assert_not_nil assigns(:project) + assert_not_nil assigns(:topic) + end + + def test_show_should_contain_reply_field_tags_for_quoting + @request.session[:user_id] = 2 + get :show, :board_id => 1, :id => 1 + assert_response :success + + # tags required by MessagesController#quote + assert_tag 'input', :attributes => {:id => 'message_subject'} + assert_tag 'textarea', :attributes => {:id => 'message_content'} + assert_tag 'div', :attributes => {:id => 'reply'} + end + + def test_show_with_pagination + message = Message.find(1) + assert_difference 'Message.count', 30 do + 30.times do + message.children << Message.new(:subject => 'Reply', :content => 'Reply body', :author_id => 2, :board_id => 1) + end + end + get :show, :board_id => 1, :id => 1, :r => message.children.last(:order => 'id').id + assert_response :success + assert_template 'show' + replies = assigns(:replies) + assert_not_nil replies + assert !replies.include?(message.children.first(:order => 'id')) + assert replies.include?(message.children.last(:order => 'id')) + end + + def test_show_with_reply_permission + @request.session[:user_id] = 2 + get :show, :board_id => 1, :id => 1 + assert_response :success + assert_template 'show' + assert_tag :div, :attributes => { :id => 'reply' }, + :descendant => { :tag => 'textarea', :attributes => { :id => 'message_content' } } + end + + def test_show_message_not_found + get :show, :board_id => 1, :id => 99999 + assert_response 404 + end + + def test_get_new + @request.session[:user_id] = 2 + get :new, :board_id => 1 + assert_response :success + assert_template 'new' + end + + def test_post_new + @request.session[:user_id] = 2 + ActionMailer::Base.deliveries.clear + Setting.notified_events = ['message_posted'] + + post :new, :board_id => 1, + :message => { :subject => 'Test created message', + :content => 'Message body'} + message = Message.find_by_subject('Test created message') + assert_not_nil message + assert_redirected_to "/boards/1/topics/#{message.to_param}" + assert_equal 'Message body', message.content + assert_equal 2, message.author_id + assert_equal 1, message.board_id + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert_equal "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] Test created message", mail.subject + assert mail.body.include?('Message body') + # author + assert mail.bcc.include?('jsmith@somenet.foo') + # project member + assert mail.bcc.include?('dlopper@somenet.foo') + end + + def test_get_edit + @request.session[:user_id] = 2 + get :edit, :board_id => 1, :id => 1 + assert_response :success + assert_template 'edit' + end + + def test_post_edit + @request.session[:user_id] = 2 + post :edit, :board_id => 1, :id => 1, + :message => { :subject => 'New subject', + :content => 'New body'} + assert_redirected_to '/boards/1/topics/1' + message = Message.find(1) + assert_equal 'New subject', message.subject + assert_equal 'New body', message.content + end + + def test_reply + @request.session[:user_id] = 2 + post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' } + reply = Message.find(:first, :order => 'id DESC') + assert_redirected_to "/boards/1/topics/1?r=#{reply.id}" + assert Message.find_by_subject('Test reply') + end + + def test_destroy_topic + @request.session[:user_id] = 2 + post :destroy, :board_id => 1, :id => 1 + assert_redirected_to '/projects/ecookbook/boards/1' + assert_nil Message.find_by_id(1) + end + + def test_quote + @request.session[:user_id] = 2 + xhr :get, :quote, :board_id => 1, :id => 3 + assert_response :success + assert_select_rjs :show, 'reply' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/1837a3f2f42f82f9bc5eb90baf90fd0294b359c7.svn-base Binary file .svn/pristine/18/1837a3f2f42f82f9bc5eb90baf90fd0294b359c7.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/184f4ab8262b15ef30593558775a40495e198999.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/184f4ab8262b15ef30593558775a40495e198999.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +api.array :news, api_meta(:total_count => @news_count, :offset => @offset, :limit => @limit) do + @newss.each do |news| + api.news do + api.id news.id + api.project(:id => news.project_id, :name => news.project.name) unless news.project.nil? + api.author(:id => news.author_id, :name => news.author.name) unless news.author.nil? + + api.title news.title + api.summary news.summary + api.description news.description + api.created_on news.created_on + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/185ae4625d7d985009b3be79f0d708b104a00d0b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/185ae4625d7d985009b3be79f0d708b104a00d0b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +
+<%= link_to(l(:label_news_new), + new_project_news_path(@project), + :class => 'icon icon-add', + :onclick => 'Element.show("add-news"); Form.Element.focus("news_title"); return false;') if @project && User.current.allowed_to?(:manage_news, @project) %> +
+ + + +

<%=l(:label_news_plural)%>

+ +<% if @newss.empty? %> +

<%= l(:label_no_data) %>

+<% else %> +<% @newss.each do |news| %> +

<%= avatar(news.author, :size => "24") %><%= link_to_project(news.project) + ': ' unless news.project == @project %> + <%= link_to h(news.title), news_path(news) %> + <%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>

+

<%= authoring news.created_on, news.author %>

+
+ <%= textilizable(news.description) %> +
+<% end %> +<% end %> +

<%= pagination_links_full @news_pages %>

+ +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% html_title(l(:label_news_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18852f098b25cd84eb6339e96750fe88239d356c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18852f098b25cd84eb6339e96750fe88239d356c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,178 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'pp' +class RepositoryCvsTest < ActiveSupport::TestCase + fixtures :projects + + REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s + REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? + # CVS module + MODULE_NAME = 'test' + CHANGESETS_NUM = 7 + + def setup + @project = Project.find(3) + @repository = Repository::Cvs.create(:project => @project, + :root_url => REPOSITORY_PATH, + :url => MODULE_NAME, + :log_encoding => 'UTF-8') + assert @repository + end + + if File.directory?(REPOSITORY_PATH) + def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + + assert_equal CHANGESETS_NUM, @repository.changesets.count + assert_equal 16, @repository.changes.count + assert_not_nil @repository.changesets.find_by_comments('Two files changed') + + r2 = @repository.changesets.find_by_revision('2') + assert_equal 'v1-20071213-162510', r2.scmid + end + + def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + # Remove changesets with revision > 3 + @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3} + @repository.reload + assert_equal 3, @repository.changesets.count + assert_equal %w|3 2 1|, @repository.changesets.collect(&:revision) + + rev3_commit = @repository.changesets.find(:first, :order => 'committed_on DESC') + assert_equal '3', rev3_commit.revision + # 2007-12-14 01:27:22 +0900 + rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22) + assert_equal 'HEAD-20071213-162722', rev3_commit.scmid + assert_equal rev3_committed_on, rev3_commit.committed_on + latest_rev = @repository.latest_changeset + assert_equal rev3_committed_on, latest_rev.committed_on + + @repository.fetch_changesets + @repository.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + + assert_equal %w|7 6 5 4 3 2 1|, @repository.changesets.collect(&:revision) + rev5_commit = @repository.changesets.find_by_revision('5') + assert_equal 'HEAD-20071213-163001', rev5_commit.scmid + # 2007-12-14 01:30:01 +0900 + rev5_committed_on = Time.gm(2007, 12, 13, 16, 30, 1) + assert_equal rev5_committed_on, rev5_commit.committed_on + end + + def test_deleted_files_should_not_be_listed + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + + entries = @repository.entries('sources') + assert entries.detect {|e| e.name == 'watchers_controller.rb'} + assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'} + end + + def test_entries_rev3 + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + entries = @repository.entries('', '3') + assert_equal 3, entries.size + assert_equal entries[2].name, "README" + assert_equal entries[2].lastrev.time, Time.gm(2007, 12, 13, 16, 27, 22) + assert_equal entries[2].lastrev.identifier, '3' + assert_equal entries[2].lastrev.revision, '3' + assert_equal entries[2].lastrev.author, 'LANG' + end + + def test_entries_invalid_path + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + assert_nil @repository.entries('missing') + assert_nil @repository.entries('missing', '3') + end + + def test_entries_invalid_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + assert_nil @repository.entries('', '123') + end + + def test_cat + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + buf = @repository.cat('README') + assert buf + lines = buf.split("\n") + assert_equal 3, lines.length + buf = lines[1].gsub(/\r$/, "") + assert_equal 'with one change', buf + buf = @repository.cat('README', '1') + assert buf + lines = buf.split("\n") + assert_equal 1, lines.length + buf = lines[0].gsub(/\r$/, "") + assert_equal 'CVS test repository', buf + assert_nil @repository.cat('missing.rb') + + # sources/welcome_controller.rb is removed at revision 5. + assert @repository.cat('sources/welcome_controller.rb', '4') + assert @repository.cat('sources/welcome_controller.rb', '5').blank? + + # invalid revision + assert @repository.cat('README', '123').blank? + end + + def test_annotate + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count + ann = @repository.annotate('README') + assert ann + assert_equal 3, ann.revisions.length + assert_equal '1.2', ann.revisions[1].revision + assert_equal 'LANG', ann.revisions[1].author + assert_equal 'with one change', ann.lines[1] + + ann = @repository.annotate('README', '1') + assert ann + assert_equal 1, ann.revisions.length + assert_equal '1.1', ann.revisions[0].revision + assert_equal 'LANG', ann.revisions[0].author + assert_equal 'CVS test repository', ann.lines[0] + + # invalid revision + assert_nil @repository.annotate('README', '123') + end + + else + puts "CVS test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/1885ce921d043d16f90840164f06199bb85e23a9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/1885ce921d043d16f90840164f06199bb85e23a9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,114 @@ +require File.expand_path('../../test_helper', __FILE__) + +class ActivitiesControllerTest < ActionController::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :groups_users, + :enabled_modules, + :workflows, + :auth_sources, + :journals, :journal_details + + + def test_project_index + get :index, :id => 1, :with_subprojects => 0 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:events_by_day) + + assert_tag :tag => "h3", + :content => /#{2.days.ago.to_date.day}/, + :sibling => { :tag => "dl", + :child => { :tag => "dt", + :attributes => { :class => /issue-edit/ }, + :child => { :tag => "a", + :content => /(#{IssueStatus.find(2).name})/, + } + } + } + end + + def test_project_index_with_invalid_project_id_should_respond_404 + get :index, :id => 299 + assert_response 404 + end + + def test_previous_project_index + get :index, :id => 1, :from => 3.days.ago.to_date + assert_response :success + assert_template 'index' + assert_not_nil assigns(:events_by_day) + + assert_tag :tag => "h3", + :content => /#{3.day.ago.to_date.day}/, + :sibling => { :tag => "dl", + :child => { :tag => "dt", + :attributes => { :class => /issue/ }, + :child => { :tag => "a", + :content => /#{Issue.find(1).subject}/, + } + } + } + end + + def test_global_index + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:events_by_day) + + assert_tag :tag => "h3", + :content => /#{5.day.ago.to_date.day}/, + :sibling => { :tag => "dl", + :child => { :tag => "dt", + :attributes => { :class => /issue/ }, + :child => { :tag => "a", + :content => /#{Issue.find(5).subject}/, + } + } + } + end + + def test_user_index + get :index, :user_id => 2 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:events_by_day) + + assert_tag :tag => "h3", + :content => /#{3.day.ago.to_date.day}/, + :sibling => { :tag => "dl", + :child => { :tag => "dt", + :attributes => { :class => /issue/ }, + :child => { :tag => "a", + :content => /#{Issue.find(1).subject}/, + } + } + } + end + + def test_user_index_with_invalid_user_id_should_respond_404 + get :index, :user_id => 299 + assert_response 404 + end + + def test_index_atom_feed + get :index, :format => 'atom' + assert_response :success + assert_template 'common/feed.atom' + assert_tag :tag => 'entry', :child => { + :tag => 'link', + :attributes => {:href => 'http://test.host/issues/11'}} + end + + def test_index_atom_feed_with_one_item_type + get :index, :format => 'atom', :show_issues => '1' + assert_response :success + assert_template 'common/feed.atom' + assert_tag :tag => 'title', :content => /Issues/ + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/189e42fe562dc8e6777fdc048ca3ef1e55e522e9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/189e42fe562dc8e6777fdc048ca3ef1e55e522e9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +the implicit html part of the email <%= do_something_helpful("semaj") %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18a09954a05a5ec15a7caae7ea49a3f1f212aec3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18a09954a05a5ec15a7caae7ea49a3f1f212aec3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,81 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../../test_helper', __FILE__) + +class Redmine::Views::Builders::JsonTest < ActiveSupport::TestCase + + def test_hash + assert_json_output({'person' => {'name' => 'Ryan', 'age' => 32}}) do |b| + b.person do + b.name 'Ryan' + b.age 32 + end + end + end + + def test_hash_hash + assert_json_output({'person' => {'name' => 'Ryan', 'birth' => {'city' => 'London', 'country' => 'UK'}}}) do |b| + b.person do + b.name 'Ryan' + b.birth :city => 'London', :country => 'UK' + end + end + + assert_json_output({'person' => {'id' => 1, 'name' => 'Ryan', 'birth' => {'city' => 'London', 'country' => 'UK'}}}) do |b| + b.person :id => 1 do + b.name 'Ryan' + b.birth :city => 'London', :country => 'UK' + end + end + end + + def test_array + assert_json_output({'books' => [{'title' => 'Book 1', 'author' => 'B. Smith'}, {'title' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b| + b.array :books do |b| + b.book :title => 'Book 1', :author => 'B. Smith' + b.book :title => 'Book 2', :author => 'G. Cooper' + end + end + + assert_json_output({'books' => [{'title' => 'Book 1', 'author' => 'B. Smith'}, {'title' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b| + b.array :books do |b| + b.book :title => 'Book 1' do + b.author 'B. Smith' + end + b.book :title => 'Book 2' do + b.author 'G. Cooper' + end + end + end + end + + def test_array_with_content_tags + assert_json_output({'books' => [{'value' => 'Book 1', 'author' => 'B. Smith'}, {'value' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b| + b.array :books do |b| + b.book 'Book 1', :author => 'B. Smith' + b.book 'Book 2', :author => 'G. Cooper' + end + end + end + + def assert_json_output(expected, &block) + builder = Redmine::Views::Builders::Json.new + block.call(builder) + assert_equal(expected, ActiveSupport::JSON.decode(builder.output)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18c59fd3cf0be9bce51b1494294c8021fdeabf7d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18c59fd3cf0be9bce51b1494294c8021fdeabf7d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

<%=h "#{@issue.tracker.name} ##{@issue.id}" %>

+ +<%= render :partial => 'edit' %> +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18cc4e49160ae0034ae73ed153f32f0bc91339cb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18cc4e49160ae0034ae73ed153f32f0bc91339cb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= image_tag 'image.png', :plugin => 'test_assets' %> +<%= javascript_include_tag 'file.1.js', 'file2', :plugin => "test_assets" %> +<%= stylesheet_link_tag 'file.1.css', 'file2', :plugin => "test_assets" %> +<%= image_submit_tag 'image.png', :plugin => "test_assets" %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18d3632a00930fda235a1df851a99c522ae0e846.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18d3632a00930fda235a1df851a99c522ae0e846.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +require 'rails_generator/base' +require 'rails_generator/generators/components/model/model_generator' + +class RedminePluginModelGenerator < ModelGenerator + attr_accessor :plugin_path, :plugin_name, :plugin_pretty_name + + def initialize(runtime_args, runtime_options = {}) + runtime_args = runtime_args.dup + usage if runtime_args.empty? + @plugin_name = "redmine_" + runtime_args.shift.underscore + @plugin_pretty_name = plugin_name.titleize + @plugin_path = "vendor/plugins/#{plugin_name}" + super(runtime_args, runtime_options) + end + + def destination_root + File.join(Rails.root, plugin_path) + end + + def manifest + record do |m| + # Check for class naming collisions. + m.class_collisions class_path, class_name, "#{class_name}Test" + + # Model, test, and fixture directories. + m.directory File.join('app/models', class_path) + m.directory File.join('test/unit', class_path) + m.directory File.join('test/fixtures', class_path) + + # Model class, unit test, and fixtures. + m.template 'model.rb.erb', File.join('app/models', class_path, "#{file_name}.rb") + m.template 'unit_test.rb.erb', File.join('test/unit', class_path, "#{file_name}_test.rb") + + unless options[:skip_fixture] + m.template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml") + end + + unless options[:skip_migration] + m.migration_template 'migration.rb.erb', 'db/migrate', :assigns => { + :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}" + }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18e26e4ca682c923302a583348c469fa140f4223.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18e26e4ca682c923302a583348c469fa140f4223.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +# The Greeter class +class Greeter + def initialize(name) + @name = name.capitalize + end + + def salute + puts "Hello #{@name}!" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/18/18e8c38332487b5baaa2a884c66c256e8b7f9e68.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/18/18e8c38332487b5baaa2a884c66c256e8b7f9e68.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +require File.expand_path('../../../test_helper', __FILE__) + +class ApiTest::HttpBasicLoginWithApiTokenTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def setup + Setting.rest_api_enabled = '1' + Setting.login_required = '1' + end + + def teardown + Setting.rest_api_enabled = '0' + Setting.login_required = '0' + end + + # Using the NewsController because it's a simple API. + context "get /news" do + + context "in :xml format" do + should_allow_http_basic_auth_with_key(:get, "/news.xml") + end + + context "in :json format" do + should_allow_http_basic_auth_with_key(:get, "/news.json") + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/19/1933646523012d974bcce0affad6dacd2e7a9322.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/19/1933646523012d974bcce0affad6dacd2e7a9322.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,182 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 DefaultData + class DataAlreadyLoaded < Exception; end + + module Loader + include Redmine::I18n + + class << self + # Returns true if no data is already loaded in the database + # otherwise false + def no_data? + !Role.find(:first, :conditions => {:builtin => 0}) && + !Tracker.find(:first) && + !IssueStatus.find(:first) && + !Enumeration.find(:first) + end + + # Loads the default data + # Raises a RecordNotSaved exception if something goes wrong + def load(lang=nil) + raise DataAlreadyLoaded.new("Some configuration data is already loaded.") unless no_data? + set_language_if_valid(lang) + + Role.transaction do + # Roles + manager = Role.create! :name => l(:default_role_manager), + :issues_visibility => 'all', + :position => 1 + manager.permissions = manager.setable_permissions.collect {|p| p.name} + manager.save! + + developer = Role.create! :name => l(:default_role_developer), + :position => 2, + :permissions => [:manage_versions, + :manage_categories, + :view_issues, + :add_issues, + :edit_issues, + :manage_issue_relations, + :manage_subtasks, + :add_issue_notes, + :save_queries, + :view_gantt, + :view_calendar, + :log_time, + :view_time_entries, + :comment_news, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :edit_wiki_pages, + :delete_wiki_pages, + :add_messages, + :edit_own_messages, + :view_files, + :manage_files, + :browse_repository, + :view_changesets, + :commit_access] + + reporter = Role.create! :name => l(:default_role_reporter), + :position => 3, + :permissions => [:view_issues, + :add_issues, + :add_issue_notes, + :save_queries, + :view_gantt, + :view_calendar, + :log_time, + :view_time_entries, + :comment_news, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :add_messages, + :edit_own_messages, + :view_files, + :browse_repository, + :view_changesets] + + Role.non_member.update_attribute :permissions, [:view_issues, + :add_issues, + :add_issue_notes, + :save_queries, + :view_gantt, + :view_calendar, + :view_time_entries, + :comment_news, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :add_messages, + :view_files, + :browse_repository, + :view_changesets] + + Role.anonymous.update_attribute :permissions, [:view_issues, + :view_gantt, + :view_calendar, + :view_time_entries, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :view_files, + :browse_repository, + :view_changesets] + + # Trackers + Tracker.create!(:name => l(:default_tracker_bug), :is_in_chlog => true, :is_in_roadmap => false, :position => 1) + Tracker.create!(:name => l(:default_tracker_feature), :is_in_chlog => true, :is_in_roadmap => true, :position => 2) + Tracker.create!(:name => l(:default_tracker_support), :is_in_chlog => false, :is_in_roadmap => false, :position => 3) + + # Issue statuses + new = IssueStatus.create!(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :position => 1) + in_progress = IssueStatus.create!(:name => l(:default_issue_status_in_progress), :is_closed => false, :is_default => false, :position => 2) + resolved = IssueStatus.create!(:name => l(:default_issue_status_resolved), :is_closed => false, :is_default => false, :position => 3) + feedback = IssueStatus.create!(:name => l(:default_issue_status_feedback), :is_closed => false, :is_default => false, :position => 4) + closed = IssueStatus.create!(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :position => 5) + rejected = IssueStatus.create!(:name => l(:default_issue_status_rejected), :is_closed => true, :is_default => false, :position => 6) + + # Workflow + Tracker.find(:all).each { |t| + IssueStatus.find(:all).each { |os| + IssueStatus.find(:all).each { |ns| + Workflow.create!(:tracker_id => t.id, :role_id => manager.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + } + + Tracker.find(:all).each { |t| + [new, in_progress, resolved, feedback].each { |os| + [in_progress, resolved, feedback, closed].each { |ns| + Workflow.create!(:tracker_id => t.id, :role_id => developer.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + } + + Tracker.find(:all).each { |t| + [new, in_progress, resolved, feedback].each { |os| + [closed].each { |ns| + Workflow.create!(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + Workflow.create!(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => resolved.id, :new_status_id => feedback.id) + } + + # Enumerations + DocumentCategory.create!(:name => l(:default_doc_category_user), :position => 1) + DocumentCategory.create!(:name => l(:default_doc_category_tech), :position => 2) + + IssuePriority.create!(:name => l(:default_priority_low), :position => 1) + IssuePriority.create!(:name => l(:default_priority_normal), :position => 2, :is_default => true) + IssuePriority.create!(:name => l(:default_priority_high), :position => 3) + IssuePriority.create!(:name => l(:default_priority_urgent), :position => 4) + IssuePriority.create!(:name => l(:default_priority_immediate), :position => 5) + + TimeEntryActivity.create!(:name => l(:default_activity_design), :position => 1) + TimeEntryActivity.create!(:name => l(:default_activity_development), :position => 2) + end + true + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/19/199fc9952c2ae576aa633fca73f2902df9432ab7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/19/199fc9952c2ae576aa633fca73f2902df9432ab7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,332 @@ +require 'test/unit' + +require 'rubygems' +gem 'activerecord', '>= 1.15.4.7794' +require 'active_record' + +require "#{File.dirname(__FILE__)}/../init" + +ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:") + +def setup_db + ActiveRecord::Schema.define(:version => 1) do + create_table :mixins do |t| + t.column :pos, :integer + t.column :parent_id, :integer + t.column :created_at, :datetime + t.column :updated_at, :datetime + end + end +end + +def teardown_db + ActiveRecord::Base.connection.tables.each do |table| + ActiveRecord::Base.connection.drop_table(table) + end +end + +class Mixin < ActiveRecord::Base +end + +class ListMixin < Mixin + acts_as_list :column => "pos", :scope => :parent + + def self.table_name() "mixins" end +end + +class ListMixinSub1 < ListMixin +end + +class ListMixinSub2 < ListMixin +end + +class ListWithStringScopeMixin < ActiveRecord::Base + acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}' + + def self.table_name() "mixins" end +end + + +class ListTest < Test::Unit::TestCase + + def setup + setup_db + (1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 5 } + end + + def teardown + teardown_db + end + + def test_reordering + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(2).move_lower + assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(2).move_higher + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(1).move_to_bottom + assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(1).move_to_top + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(2).move_to_bottom + assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(4).move_to_top + assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + end + + def test_move_to_bottom_with_next_to_last_item + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + ListMixin.find(3).move_to_bottom + assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + end + + def test_next_prev + assert_equal ListMixin.find(2), ListMixin.find(1).lower_item + assert_nil ListMixin.find(1).higher_item + assert_equal ListMixin.find(3), ListMixin.find(4).higher_item + assert_nil ListMixin.find(4).lower_item + end + + def test_injection + item = ListMixin.new(:parent_id => 1) + assert_equal "parent_id = 1", item.scope_condition + assert_equal "pos", item.position_column + end + + def test_insert + new = ListMixin.create(:parent_id => 20) + assert_equal 1, new.pos + assert new.first? + assert new.last? + + new = ListMixin.create(:parent_id => 20) + assert_equal 2, new.pos + assert !new.first? + assert new.last? + + new = ListMixin.create(:parent_id => 20) + assert_equal 3, new.pos + assert !new.first? + assert new.last? + + new = ListMixin.create(:parent_id => 0) + assert_equal 1, new.pos + assert new.first? + assert new.last? + end + + def test_insert_at + new = ListMixin.create(:parent_id => 20) + assert_equal 1, new.pos + + new = ListMixin.create(:parent_id => 20) + assert_equal 2, new.pos + + new = ListMixin.create(:parent_id => 20) + assert_equal 3, new.pos + + new4 = ListMixin.create(:parent_id => 20) + assert_equal 4, new4.pos + + new4.insert_at(3) + assert_equal 3, new4.pos + + new.reload + assert_equal 4, new.pos + + new.insert_at(2) + assert_equal 2, new.pos + + new4.reload + assert_equal 4, new4.pos + + new5 = ListMixin.create(:parent_id => 20) + assert_equal 5, new5.pos + + new5.insert_at(1) + assert_equal 1, new5.pos + + new4.reload + assert_equal 5, new4.pos + end + + def test_delete_middle + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(2).destroy + + assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + assert_equal 1, ListMixin.find(1).pos + assert_equal 2, ListMixin.find(3).pos + assert_equal 3, ListMixin.find(4).pos + + ListMixin.find(1).destroy + + assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + assert_equal 1, ListMixin.find(3).pos + assert_equal 2, ListMixin.find(4).pos + end + + def test_with_string_based_scope + new = ListWithStringScopeMixin.create(:parent_id => 500) + assert_equal 1, new.pos + assert new.first? + assert new.last? + end + + def test_nil_scope + new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create + new2.move_higher + assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos') + end + + + def test_remove_from_list_should_then_fail_in_list? + assert_equal true, ListMixin.find(1).in_list? + ListMixin.find(1).remove_from_list + assert_equal false, ListMixin.find(1).in_list? + end + + def test_remove_from_list_should_set_position_to_nil + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(2).remove_from_list + + assert_equal [2, 1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + assert_equal 1, ListMixin.find(1).pos + assert_equal nil, ListMixin.find(2).pos + assert_equal 2, ListMixin.find(3).pos + assert_equal 3, ListMixin.find(4).pos + end + + def test_remove_before_destroy_does_not_shift_lower_items_twice + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + ListMixin.find(2).remove_from_list + ListMixin.find(2).destroy + + assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id) + + assert_equal 1, ListMixin.find(1).pos + assert_equal 2, ListMixin.find(3).pos + assert_equal 3, ListMixin.find(4).pos + end + +end + +class ListSubTest < Test::Unit::TestCase + + def setup + setup_db + (1..4).each { |i| ((i % 2 == 1) ? ListMixinSub1 : ListMixinSub2).create! :pos => i, :parent_id => 5000 } + end + + def teardown + teardown_db + end + + def test_reordering + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(2).move_lower + assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(2).move_higher + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(1).move_to_bottom + assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(1).move_to_top + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(2).move_to_bottom + assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(4).move_to_top + assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + end + + def test_move_to_bottom_with_next_to_last_item + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + ListMixin.find(3).move_to_bottom + assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + end + + def test_next_prev + assert_equal ListMixin.find(2), ListMixin.find(1).lower_item + assert_nil ListMixin.find(1).higher_item + assert_equal ListMixin.find(3), ListMixin.find(4).higher_item + assert_nil ListMixin.find(4).lower_item + end + + def test_injection + item = ListMixin.new("parent_id"=>1) + assert_equal "parent_id = 1", item.scope_condition + assert_equal "pos", item.position_column + end + + def test_insert_at + new = ListMixin.create("parent_id" => 20) + assert_equal 1, new.pos + + new = ListMixinSub1.create("parent_id" => 20) + assert_equal 2, new.pos + + new = ListMixinSub2.create("parent_id" => 20) + assert_equal 3, new.pos + + new4 = ListMixin.create("parent_id" => 20) + assert_equal 4, new4.pos + + new4.insert_at(3) + assert_equal 3, new4.pos + + new.reload + assert_equal 4, new.pos + + new.insert_at(2) + assert_equal 2, new.pos + + new4.reload + assert_equal 4, new4.pos + + new5 = ListMixinSub1.create("parent_id" => 20) + assert_equal 5, new5.pos + + new5.insert_at(1) + assert_equal 1, new5.pos + + new4.reload + assert_equal 5, new4.pos + end + + def test_delete_middle + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + ListMixin.find(2).destroy + + assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + assert_equal 1, ListMixin.find(1).pos + assert_equal 2, ListMixin.find(3).pos + assert_equal 3, ListMixin.find(4).pos + + ListMixin.find(1).destroy + + assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id) + + assert_equal 1, ListMixin.find(3).pos + assert_equal 2, ListMixin.find(4).pos + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/19/19b6be5d688e189fd6e317c5eb9f45e401793fef.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/19/19b6be5d688e189fd6e317c5eb9f45e401793fef.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +Fixtures are only copied from plugins with an +app+ directory, but git needs this directory to be non-empty \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1a82d923d734db1f664f7d362dd31d181914982f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1a82d923d734db1f664f7d362dd31d181914982f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +
+<%= link_to_remote l(:button_add), + :url => {:controller => 'watchers', + :action => 'new', + :object_type => watched.class.name.underscore, + :object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %> +
+ +

<%= l(:label_issue_watchers) %> (<%= watched.watcher_users.size %>)

+ +<% unless @watcher.nil? %> + <% remote_form_for(:watcher, @watcher, + :url => {:controller => 'watchers', + :action => 'new', + :object_type => watched.class.name.underscore, + :object_id => watched}, + :method => :post, + :html => {:id => 'new-watcher-form'}) do |f| %> +

<%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %> + + <%= submit_tag l(:button_add) %> + <%= toggle_link l(:button_cancel), 'new-watcher-form'%>

+ <% end %> +<% end %> + +<%= watchers_list(watched) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1a8a501f625f400265586ffe68a1c06c8affc4fc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1a8a501f625f400265586ffe68a1c06c8affc4fc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) + +class CalendarTest < ActiveSupport::TestCase + + def test_monthly + c = Redmine::Helpers::Calendar.new(Date.today, :fr, :month) + assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday] + + c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :month) + assert_equal ['2007-06-25'.to_date, '2007-08-05'.to_date], [c.startdt, c.enddt] + + c = Redmine::Helpers::Calendar.new(Date.today, :en, :month) + assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday] + end + + def test_weekly + c = Redmine::Helpers::Calendar.new(Date.today, :fr, :week) + assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday] + + c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :week) + assert_equal ['2007-07-09'.to_date, '2007-07-15'.to_date], [c.startdt, c.enddt] + + c = Redmine::Helpers::Calendar.new(Date.today, :en, :week) + assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday] + end + + def test_monthly_start_day + [1, 6, 7].each do |day| + with_settings :start_of_week => day do + c = Redmine::Helpers::Calendar.new(Date.today, :en, :month) + assert_equal day , c.startdt.cwday + assert_equal (day + 5) % 7 + 1, c.enddt.cwday + end + end + end + + def test_weekly_start_day + [1, 6, 7].each do |day| + with_settings :start_of_week => day do + c = Redmine::Helpers::Calendar.new(Date.today, :en, :week) + assert_equal day, c.startdt.cwday + assert_equal (day + 5) % 7 + 1, c.enddt.cwday + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1a8da3d8148fac23b4f5825f6ac868a10f01d12f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1a8da3d8148fac23b4f5825f6ac868a10f01d12f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToUserPreferences < ActiveRecord::Migration + def self.up + add_index :user_preferences, :user_id + end + + def self.down + remove_index :user_preferences, :user_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1ab06441767b89700eccb7f62767523259a141ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1ab06441767b89700eccb7f62767523259a141ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class Company < ActiveRecord::Base + attr_protected :rating + set_sequence_name :companies_nonstd_seq + + validates_presence_of :name + def validate + errors.add('rating', 'rating should not be 2') if rating == 2 + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1abc7d9bb63cfe6a27d8a0852d2c50e8db93327c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1abc7d9bb63cfe6a27d8a0852d2c50e8db93327c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,502 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class MailerTest < ActiveSupport::TestCase + include Redmine::I18n + include ActionController::Assertions::SelectorAssertions + fixtures :projects, :enabled_modules, :issues, :users, :members, + :member_roles, :roles, :documents, :attachments, :news, + :tokens, :journals, :journal_details, :changesets, :trackers, + :issue_statuses, :enumerations, :messages, :boards, :repositories, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :versions, + :comments + + def setup + ActionMailer::Base.deliveries.clear + Setting.host_name = 'mydomain.foo' + Setting.protocol = 'http' + Setting.plain_text_mail = '0' + end + + def test_generated_links_in_emails + Setting.host_name = 'mydomain.foo' + Setting.protocol = 'https' + + journal = Journal.find(2) + assert Mailer.deliver_issue_edit(journal) + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + + assert_select_email do + # link to the main ticket + assert_select "a[href=?]", + "https://mydomain.foo/issues/1#change-2", + :text => "Bug #1: Can't print recipes" + # link to a referenced ticket + assert_select "a[href=?][title=?]", + "https://mydomain.foo/issues/2", + "Add ingredients categories (Assigned)", + :text => "#2" + # link to a changeset + assert_select "a[href=?][title=?]", + "https://mydomain.foo/projects/ecookbook/repository/revisions/2", + "This commit fixes #1, #2 and references #1 & #3", + :text => "r2" + end + end + + def test_generated_links_with_prefix + relative_url_root = Redmine::Utils.relative_url_root + Setting.host_name = 'mydomain.foo/rdm' + Setting.protocol = 'http' + Redmine::Utils.relative_url_root = '/rdm' + + journal = Journal.find(2) + assert Mailer.deliver_issue_edit(journal) + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + + assert_select_email do + # link to the main ticket + assert_select "a[href=?]", + "http://mydomain.foo/rdm/issues/1#change-2", + :text => "Bug #1: Can't print recipes" + # link to a referenced ticket + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/issues/2", + "Add ingredients categories (Assigned)", + :text => "#2" + # link to a changeset + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", + "This commit fixes #1, #2 and references #1 & #3", + :text => "r2" + end + ensure + # restore it + Redmine::Utils.relative_url_root = relative_url_root + end + + def test_generated_links_with_prefix_and_no_relative_url_root + relative_url_root = Redmine::Utils.relative_url_root + Setting.host_name = 'mydomain.foo/rdm' + Setting.protocol = 'http' + Redmine::Utils.relative_url_root = nil + + journal = Journal.find(2) + assert Mailer.deliver_issue_edit(journal) + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + + assert_select_email do + # link to the main ticket + assert_select "a[href=?]", + "http://mydomain.foo/rdm/issues/1#change-2", + :text => "Bug #1: Can't print recipes" + # link to a referenced ticket + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/issues/2", + "Add ingredients categories (Assigned)", + :text => "#2" + # link to a changeset + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", + "This commit fixes #1, #2 and references #1 & #3", + :text => "r2" + end + ensure + # restore it + Redmine::Utils.relative_url_root = relative_url_root + end + + def test_email_headers + issue = Issue.find(1) + Mailer.deliver_issue_add(issue) + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal 'OOF', mail.header_string('X-Auto-Response-Suppress') + assert_equal 'auto-generated', mail.header_string('Auto-Submitted') + end + + def test_plain_text_mail + Setting.plain_text_mail = 1 + journal = Journal.find(2) + Mailer.deliver_issue_edit(journal) + mail = ActionMailer::Base.deliveries.last + assert_equal "text/plain", mail.content_type + assert_equal 0, mail.parts.size + assert !mail.encoded.include?('href') + end + + def test_html_mail + Setting.plain_text_mail = 0 + journal = Journal.find(2) + Mailer.deliver_issue_edit(journal) + mail = ActionMailer::Base.deliveries.last + assert_equal 2, mail.parts.size + assert mail.encoded.include?('href') + end + + def test_from_header + with_settings :mail_from => 'redmine@example.net' do + Mailer.deliver_test(User.find(1)) + end + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal 'redmine@example.net', mail.from_addrs.first.address + end + + def test_from_header_with_phrase + with_settings :mail_from => 'Redmine app ' do + Mailer.deliver_test(User.find(1)) + end + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal 'redmine@example.net', mail.from_addrs.first.address + assert_equal 'Redmine app', mail.from_addrs.first.name + end + + def test_should_not_send_email_without_recipient + news = News.find(:first) + user = news.author + # Remove members except news author + news.project.memberships.each {|m| m.destroy unless m.user == user} + + user.pref[:no_self_notified] = false + user.pref.save + User.current = user + Mailer.deliver_news_added(news.reload) + assert_equal 1, last_email.bcc.size + + # nobody to notify + user.pref[:no_self_notified] = true + user.pref.save + User.current = user + ActionMailer::Base.deliveries.clear + Mailer.deliver_news_added(news.reload) + assert ActionMailer::Base.deliveries.empty? + end + + def test_issue_add_message_id + issue = Issue.find(1) + Mailer.deliver_issue_add(issue) + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal Mailer.message_id_for(issue), mail.message_id + assert_nil mail.references + end + + def test_issue_edit_message_id + journal = Journal.find(1) + Mailer.deliver_issue_edit(journal) + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal Mailer.message_id_for(journal), mail.message_id + assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s + assert_select_email do + # link to the update + assert_select "a[href=?]", + "http://mydomain.foo/issues/#{journal.journalized_id}#change-#{journal.id}" + end + end + + def test_message_posted_message_id + message = Message.find(1) + Mailer.deliver_message_posted(message) + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal Mailer.message_id_for(message), mail.message_id + assert_nil mail.references + assert_select_email do + # link to the message + assert_select "a[href=?]", + "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}", + :text => message.subject + end + end + + def test_reply_posted_message_id + message = Message.find(3) + Mailer.deliver_message_posted(message) + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal Mailer.message_id_for(message), mail.message_id + assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s + assert_select_email do + # link to the reply + assert_select "a[href=?]", + "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}", + :text => message.subject + end + end + + context("#issue_add") do + setup do + ActionMailer::Base.deliveries.clear + Setting.bcc_recipients = '1' + @issue = Issue.find(1) + end + + should "notify project members" do + assert Mailer.deliver_issue_add(@issue) + assert last_email.bcc.include?('dlopper@somenet.foo') + end + + should "not notify project members that are not allow to view the issue" do + Role.find(2).remove_permission!(:view_issues) + assert Mailer.deliver_issue_add(@issue) + assert !last_email.bcc.include?('dlopper@somenet.foo') + end + + should "notify issue watchers" do + user = User.find(9) + # minimal email notification options + user.pref[:no_self_notified] = '1' + user.pref.save + user.mail_notification = false + user.save + + Watcher.create!(:watchable => @issue, :user => user) + assert Mailer.deliver_issue_add(@issue) + assert last_email.bcc.include?(user.mail) + end + + should "not notify watchers not allowed to view the issue" do + user = User.find(9) + Watcher.create!(:watchable => @issue, :user => user) + Role.non_member.remove_permission!(:view_issues) + assert Mailer.deliver_issue_add(@issue) + assert !last_email.bcc.include?(user.mail) + end + end + + # test mailer methods for each language + def test_issue_add + issue = Issue.find(1) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_issue_add(issue) + end + end + + def test_issue_edit + journal = Journal.find(1) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_issue_edit(journal) + end + end + + def test_document_added + document = Document.find(1) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_document_added(document) + end + end + + def test_attachments_added + attachements = [ Attachment.find_by_container_type('Document') ] + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_attachments_added(attachements) + end + end + + def test_version_file_added + attachements = [ Attachment.find_by_container_type('Version') ] + assert Mailer.deliver_attachments_added(attachements) + assert_not_nil last_email.bcc + assert last_email.bcc.any? + assert_select_email do + assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" + end + end + + def test_project_file_added + attachements = [ Attachment.find_by_container_type('Project') ] + assert Mailer.deliver_attachments_added(attachements) + assert_not_nil last_email.bcc + assert last_email.bcc.any? + assert_select_email do + assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" + end + end + + def test_news_added + news = News.find(:first) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_news_added(news) + end + end + + def test_news_comment_added + comment = Comment.find(2) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_news_comment_added(comment) + end + end + + def test_message_posted + message = Message.find(:first) + recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} + recipients = recipients.compact.uniq + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_message_posted(message) + end + end + + def test_wiki_content_added + content = WikiContent.find(:first) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert_difference 'ActionMailer::Base.deliveries.size' do + assert Mailer.deliver_wiki_content_added(content) + end + end + end + + def test_wiki_content_updated + content = WikiContent.find(:first) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert_difference 'ActionMailer::Base.deliveries.size' do + assert Mailer.deliver_wiki_content_updated(content) + end + end + end + + def test_account_information + user = User.find(2) + valid_languages.each do |lang| + user.update_attribute :language, lang.to_s + user.reload + assert Mailer.deliver_account_information(user, 'pAsswORd') + end + end + + def test_lost_password + token = Token.find(2) + valid_languages.each do |lang| + token.user.update_attribute :language, lang.to_s + token.reload + assert Mailer.deliver_lost_password(token) + end + end + + def test_register + token = Token.find(1) + Setting.host_name = 'redmine.foo' + Setting.protocol = 'https' + + valid_languages.each do |lang| + token.user.update_attribute :language, lang.to_s + token.reload + ActionMailer::Base.deliveries.clear + assert Mailer.deliver_register(token) + mail = ActionMailer::Base.deliveries.last + assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}") + end + end + + def test_test + user = User.find(1) + valid_languages.each do |lang| + user.update_attribute :language, lang.to_s + assert Mailer.deliver_test(user) + end + end + + def test_reminders + Mailer.reminders(:days => 42) + assert_equal 1, ActionMailer::Base.deliveries.size + mail = ActionMailer::Base.deliveries.last + assert mail.bcc.include?('dlopper@somenet.foo') + assert mail.body.include?('Bug #3: Error 281 when updating a recipe') + assert_equal '1 issue(s) due in the next 42 days', mail.subject + end + + def test_reminders_for_users + Mailer.reminders(:days => 42, :users => ['5']) + assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper + Mailer.reminders(:days => 42, :users => ['3']) + assert_equal 1, ActionMailer::Base.deliveries.size # No mail for dlopper + mail = ActionMailer::Base.deliveries.last + assert mail.bcc.include?('dlopper@somenet.foo') + assert mail.body.include?('Bug #3: Error 281 when updating a recipe') + end + + def last_email + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + mail + end + + def test_mailer_should_not_change_locale + Setting.default_language = 'en' + # Set current language to italian + set_language_if_valid 'it' + # Send an email to a french user + user = User.find(1) + user.language = 'fr' + Mailer.deliver_account_activated(user) + mail = ActionMailer::Base.deliveries.last + assert mail.body.include?('Votre compte') + + assert_equal :it, current_language + end + + def test_with_deliveries_off + Mailer.with_deliveries false do + Mailer.deliver_test(User.find(1)) + end + assert ActionMailer::Base.deliveries.empty? + # should restore perform_deliveries + assert ActionMailer::Base.perform_deliveries + end + + def test_tmail_to_header_field_should_not_include_blank_lines + mail = TMail::Mail.new + mail.to = ["a.user@example.com", "v.user2@example.com", "e.smith@example.com", "info@example.com", "v.pupkin@example.com", + "b.user@example.com", "w.user2@example.com", "f.smith@example.com", "info2@example.com", "w.pupkin@example.com"] + + assert !mail.encoded.strip.split("\r\n").detect(&:blank?), "#{mail.encoded} malformed" + end + + context "layout" do + should "include the emails_header" do + with_settings(:emails_header => "*Header content*") do + assert Mailer.deliver_test(User.find(1)) + + assert_select_email do + assert_select ".header" do + assert_select "strong", :text => "Header content" + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1ac0b480a0ea95f3c0f18bf5dcf4e88a3d541be7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1ac0b480a0ea95f3c0f18bf5dcf4e88a3d541be7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,149 @@ +TCPDFFontDescriptor.define('freesans') do |font| + font[:type]='TrueTypeUnicode'; + font[:name]='FreeSans'; + font[:desc]={'Ascent'=>1141,'Descent'=>-459,'CapHeight'=>1141,'Flags'=>32,'FontBBox'=>'[-797 -459 1632 1141]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600} + font[:up]=-151; + font[:ut]=50; + font[:cw]={ + 13=>333, 32=>278, 33=>278, 34=>355, 35=>556, 36=>556, 37=>889, 38=>667, 39=>191, 40=>333, 41=>333, 42=>389, 43=>584, 44=>278, 45=>333, 46=>278, + 47=>278, 48=>556, 49=>556, 50=>556, 51=>556, 52=>556, 53=>556, 54=>556, 55=>556, 56=>556, 57=>556, 58=>278, 59=>278, 60=>584, 61=>584, 62=>584, + 63=>556, 64=>1015, 65=>667, 66=>667, 67=>722, 68=>722, 69=>667, 70=>611, 71=>778, 72=>722, 73=>278, 74=>500, 75=>667, 76=>556, 77=>833, 78=>722, + 79=>778, 80=>667, 81=>778, 82=>722, 83=>667, 84=>611, 85=>722, 86=>667, 87=>944, 88=>667, 89=>667, 90=>611, 91=>278, 92=>278, 93=>278, 94=>469, + 95=>556, 96=>333, 97=>556, 98=>556, 99=>500, 100=>556, 101=>556, 102=>278, 103=>556, 104=>556, 105=>222, 106=>222, 107=>500, 108=>222, 109=>833, 110=>556, + 111=>556, 112=>556, 113=>556, 114=>333, 115=>500, 116=>278, 117=>556, 118=>500, 119=>722, 120=>500, 121=>500, 122=>500, 123=>334, 124=>260, 125=>334, 126=>584, + 8364=>556, 1027=>611, 8218=>222, 402=>556, 8222=>333, 8230=>1000, 8224=>556, 8225=>556, 710=>333, 8240=>1000, 352=>667, 8249=>333, 338=>1000, 1036=>667, 381=>611, 1039=>722, + 8216=>222, 8217=>221, 8220=>333, 8221=>333, 8226=>350, 8211=>556, 8212=>1000, 732=>333, 8482=>1000, 353=>500, 8250=>333, 339=>944, 1116=>500, 382=>500, 376=>667, 160=>278, + 161=>333, 162=>556, 163=>556, 164=>556, 165=>556, 166=>260, 167=>556, 168=>333, 169=>737, 170=>370, 171=>556, 172=>584, 173=>333, 174=>737, 175=>333, 176=>606, + 177=>584, 178=>351, 179=>351, 180=>333, 181=>556, 182=>537, 183=>278, 184=>333, 185=>351, 186=>365, 187=>556, 188=>869, 189=>869, 190=>869, 191=>611, 192=>667, + 193=>667, 194=>667, 195=>667, 196=>667, 197=>667, 198=>1000, 199=>722, 200=>667, 201=>667, 202=>667, 203=>667, 204=>278, 205=>278, 206=>278, 207=>278, 208=>722, + 209=>722, 210=>778, 211=>778, 212=>778, 213=>778, 214=>778, 215=>584, 216=>778, 217=>722, 218=>722, 219=>722, 220=>722, 221=>666, 222=>666, 223=>611, 224=>556, + 225=>556, 226=>556, 227=>556, 228=>556, 229=>556, 230=>889, 231=>500, 232=>556, 233=>556, 234=>556, 235=>556, 236=>278, 237=>278, 238=>278, 239=>278, 240=>556, + 241=>556, 242=>556, 243=>556, 244=>556, 245=>556, 246=>556, 247=>584, 248=>611, 249=>556, 250=>556, 251=>556, 252=>556, 253=>500, 254=>555, 255=>500, 256=>667, + 257=>556, 258=>667, 259=>556, 260=>667, 261=>556, 262=>722, 263=>500, 264=>722, 265=>500, 266=>722, 267=>500, 268=>722, 269=>500, 270=>722, 271=>635, 272=>722, + 273=>556, 274=>667, 275=>556, 276=>667, 277=>556, 278=>667, 279=>556, 280=>667, 281=>556, 282=>667, 283=>556, 284=>778, 285=>556, 286=>778, 287=>556, 288=>778, + 289=>556, 290=>778, 291=>556, 292=>722, 293=>556, 294=>722, 295=>556, 296=>278, 297=>278, 298=>278, 299=>222, 300=>278, 301=>278, 302=>278, 303=>222, 304=>278, + 305=>278, 306=>700, 307=>374, 308=>500, 309=>222, 310=>667, 311=>500, 312=>500, 313=>556, 314=>222, 315=>556, 316=>222, 317=>556, 318=>292, 319=>556, 320=>500, + 321=>556, 322=>222, 323=>722, 324=>556, 325=>722, 326=>556, 327=>722, 328=>556, 329=>556, 330=>722, 331=>556, 332=>778, 333=>556, 334=>778, 335=>556, 336=>778, + 337=>556, 340=>722, 341=>333, 342=>722, 343=>333, 344=>722, 345=>333, 346=>667, 347=>500, 348=>667, 349=>500, 350=>667, 351=>500, 354=>611, 355=>278, 356=>611, + 357=>308, 358=>611, 359=>278, 360=>722, 361=>556, 362=>722, 363=>556, 364=>722, 365=>556, 366=>722, 367=>556, 368=>722, 369=>556, 370=>722, 371=>556, 372=>944, + 373=>722, 374=>667, 375=>500, 377=>611, 378=>500, 379=>611, 380=>500, 383=>278, 384=>556, 386=>667, 387=>556, 388=>667, 389=>556, 390=>722, 391=>722, 392=>500, + 393=>722, 395=>667, 396=>556, 398=>667, 399=>778, 400=>667, 401=>611, 403=>778, 409=>500, 413=>722, 414=>556, 415=>778, 421=>556, 423=>667, 424=>500, 425=>611, + 427=>278, 429=>278, 430=>611, 452=>1311, 453=>1208, 454=>1056, 455=>1056, 456=>778, 457=>444, 458=>1158, 459=>944, 460=>778, 461=>667, 462=>556, 463=>278, 464=>278, + 465=>778, 466=>556, 467=>722, 468=>556, 469=>722, 470=>556, 471=>722, 472=>556, 473=>722, 474=>556, 475=>722, 476=>556, 477=>556, 478=>667, 479=>556, 480=>667, + 481=>556, 482=>1000, 483=>889, 486=>778, 487=>556, 488=>667, 489=>500, 490=>778, 491=>556, 492=>778, 493=>556, 496=>222, 497=>1333, 498=>1222, 499=>1056, 500=>778, + 501=>556, 504=>722, 505=>556, 506=>667, 507=>556, 508=>1000, 509=>889, 510=>778, 511=>611, 512=>667, 513=>556, 514=>667, 515=>556, 516=>667, 517=>556, 518=>667, + 519=>556, 520=>278, 521=>278, 522=>278, 523=>278, 524=>778, 525=>556, 526=>778, 527=>556, 528=>722, 529=>333, 530=>722, 531=>333, 532=>722, 533=>556, 534=>722, + 535=>556, 536=>667, 537=>500, 538=>611, 539=>278, 542=>722, 543=>556, 550=>667, 551=>556, 552=>667, 553=>556, 554=>778, 555=>556, 556=>778, 557=>556, 558=>778, + 559=>556, 560=>778, 561=>556, 562=>667, 563=>500, 592=>556, 593=>556, 594=>556, 595=>556, 596=>500, 598=>556, 599=>556, 600=>556, 601=>556, 603=>500, 604=>500, + 608=>556, 609=>556, 613=>556, 614=>556, 615=>556, 616=>222, 617=>222, 618=>278, 621=>222, 623=>833, 624=>833, 625=>833, 626=>556, 627=>556, 629=>556, 633=>333, + 634=>333, 635=>333, 636=>333, 637=>333, 638=>278, 639=>278, 642=>500, 643=>278, 644=>278, 645=>278, 647=>278, 648=>278, 649=>556, 652=>500, 653=>722, 654=>500, + 656=>500, 668=>500, 670=>500, 672=>556, 711=>333, 714=>333, 715=>333, 728=>333, 729=>333, 730=>333, 731=>333, 733=>333, 768=>0, 769=>0, 770=>0, 771=>0, + 772=>0, 774=>0, 775=>0, 776=>0, 778=>0, 779=>0, 780=>0, 783=>0, 785=>0, 786=>0, 787=>0, 788=>0, 806=>0, 807=>0, 808=>0, 884=>199, + 885=>199, 890=>332, 894=>278, 900=>414, 901=>747, 902=>730, 903=>278, 904=>664, 905=>681, 906=>230, 908=>792, 910=>710, 911=>758, 912=>286, 913=>684, 914=>628, + 915=>582, 916=>684, 917=>650, 918=>628, 919=>683, 920=>750, 921=>236, 922=>684, 923=>684, 924=>800, 925=>654, 926=>630, 927=>750, 928=>721, 929=>638, 931=>628, + 932=>628, 933=>684, 934=>717, 935=>723, 936=>745, 937=>720, 938=>236, 939=>684, 940=>608, 941=>528, 942=>547, 943=>307, 944=>515, 945=>596, 946=>516, 947=>531, + 948=>560, 949=>510, 950=>462, 951=>526, 952=>526, 953=>286, 954=>516, 955=>560, 956=>574, 957=>504, 958=>470, 959=>550, 960=>661, 961=>566, 962=>535, 963=>616, + 964=>532, 965=>515, 966=>741, 967=>572, 968=>662, 969=>740, 970=>286, 971=>515, 972=>553, 973=>518, 974=>740, 1024=>667, 1025=>667, 1026=>766, 1028=>722, 1029=>667, + 1030=>278, 1031=>278, 1032=>500, 1033=>1080, 1034=>1014, 1035=>766, 1037=>722, 1038=>650, 1040=>667, 1041=>667, 1042=>667, 1043=>611, 1044=>812, 1045=>667, 1046=>1023, 1047=>667, + 1048=>728, 1049=>728, 1050=>667, 1051=>673, 1052=>844, 1053=>719, 1054=>778, 1055=>719, 1056=>667, 1057=>722, 1058=>611, 1059=>650, 1060=>936, 1061=>667, 1062=>741, 1063=>648, + 1064=>828, 1065=>850, 1066=>897, 1067=>872, 1068=>667, 1069=>722, 1070=>1032, 1071=>702, 1072=>556, 1073=>556, 1074=>522, 1075=>430, 1076=>602, 1077=>556, 1078=>837, 1079=>500, + 1080=>567, 1081=>567, 1082=>510, 1083=>557, 1084=>618, 1085=>558, 1086=>556, 1087=>557, 1088=>576, 1089=>500, 1090=>496, 1091=>500, 1092=>912, 1093=>500, 1094=>578, 1095=>520, + 1096=>692, 1097=>712, 1098=>734, 1099=>690, 1100=>552, 1101=>500, 1102=>758, 1103=>543, 1104=>556, 1105=>556, 1106=>568, 1107=>430, 1108=>500, 1109=>500, 1110=>222, 1111=>278, + 1112=>222, 1113=>840, 1114=>850, 1115=>568, 1117=>556, 1118=>500, 1119=>556, 1164=>667, 1165=>552, 1166=>667, 1167=>556, 1168=>611, 1169=>430, 1170=>611, 1171=>430, 1172=>611, + 1173=>430, 1174=>1023, 1175=>837, 1176=>667, 1177=>500, 1178=>667, 1179=>500, 1180=>667, 1181=>500, 1182=>667, 1183=>500, 1184=>667, 1185=>500, 1186=>722, 1187=>556, 1188=>1060, + 1189=>764, 1190=>722, 1191=>556, 1192=>722, 1193=>500, 1194=>722, 1195=>500, 1196=>611, 1197=>496, 1198=>667, 1199=>500, 1200=>667, 1201=>500, 1202=>667, 1203=>500, 1204=>774, + 1205=>608, 1206=>642, 1207=>508, 1208=>642, 1209=>508, 1210=>642, 1211=>508, 1212=>778, 1213=>556, 1214=>688, 1215=>556, 1216=>278, 1217=>1023, 1218=>837, 1219=>667, 1220=>500, + 1223=>722, 1224=>556, 1227=>642, 1228=>508, 1232=>667, 1233=>556, 1234=>667, 1235=>556, 1236=>1000, 1237=>889, 1238=>667, 1239=>556, 1240=>778, 1241=>556, 1242=>778, 1243=>556, + 1244=>1023, 1245=>837, 1246=>667, 1247=>500, 1248=>667, 1249=>500, 1250=>728, 1251=>567, 1252=>728, 1253=>567, 1254=>778, 1255=>556, 1256=>778, 1257=>556, 1258=>778, 1259=>556, + 1260=>722, 1261=>500, 1262=>650, 1263=>500, 1264=>650, 1265=>500, 1266=>650, 1267=>500, 1268=>648, 1269=>520, 1272=>872, 1273=>690, 1329=>722, 1330=>705, 1331=>774, 1332=>754, + 1333=>722, 1334=>751, 1335=>485, 1336=>722, 1337=>782, 1338=>655, 1339=>699, 1340=>417, 1341=>853, 1342=>791, 1343=>711, 1344=>588, 1345=>663, 1346=>665, 1347=>665, 1348=>756, + 1349=>623, 1350=>773, 1351=>603, 1352=>722, 1353=>648, 1354=>722, 1355=>751, 1356=>750, 1357=>722, 1358=>748, 1359=>667, 1360=>699, 1361=>623, 1362=>417, 1363=>785, 1364=>638, + 1365=>778, 1366=>716, 1370=>222, 1371=>133, 1372=>325, 1373=>333, 1374=>344, 1377=>833, 1378=>556, 1379=>572, 1380=>581, 1381=>550, 1382=>588, 1383=>448, 1384=>556, 1385=>568, + 1386=>582, 1387=>545, 1388=>301, 1389=>799, 1390=>556, 1391=>554, 1392=>533, 1393=>548, 1394=>552, 1395=>552, 1396=>544, 1397=>222, 1398=>544, 1399=>456, 1400=>556, 1401=>390, + 1402=>833, 1403=>509, 1404=>547, 1405=>533, 1406=>610, 1407=>887, 1408=>556, 1409=>545, 1410=>352, 1411=>853, 1412=>588, 1413=>579, 1414=>690, 1415=>545, 1417=>278, 1418=>367, + 1456=>70, 1457=>335, 1458=>329, 1459=>329, 1460=>70, 1461=>200, 1462=>200, 1463=>188, 1464=>188, 1465=>70, 1467=>329, 1468=>70, 1469=>70, 1470=>488, 1471=>200, 1472=>212, + 1473=>0, 1474=>0, 1475=>278, 1476=>70, 1488=>640, 1489=>591, 1490=>466, 1491=>598, 1492=>622, 1493=>212, 1494=>351, 1495=>623, 1496=>608, 1497=>200, 1498=>526, 1499=>550, + 1500=>600, 1501=>623, 1502=>621, 1503=>212, 1504=>378, 1505=>607, 1506=>587, 1507=>575, 1508=>568, 1509=>540, 1510=>590, 1511=>606, 1512=>547, 1513=>776, 1514=>687, 1792=>600, + 1793=>201, 1794=>201, 1795=>201, 1796=>201, 1797=>500, 1798=>500, 1799=>500, 1800=>370, 1801=>370, 1802=>574, 1803=>574, 1804=>645, 1805=>574, 1808=>452, 1809=>452, 1810=>574, + 1811=>645, 1812=>645, 1813=>509, 1814=>509, 1815=>682, 1816=>585, 1817=>404, 1818=>627, 1819=>718, 1820=>718, 1821=>484, 1822=>682, 1823=>600, 1824=>660, 1825=>682, 1826=>538, + 1827=>718, 1828=>718, 1829=>718, 1830=>574, 1831=>574, 1832=>638, 1833=>585, 1834=>509, 1835=>682, 1836=>682, 1840=>1, 1841=>1, 1842=>1, 1843=>1, 1844=>1, 1845=>1, + 1846=>1, 1847=>1, 1848=>1, 1849=>1, 1850=>1, 1851=>1, 1852=>1, 1853=>1, 1854=>1, 1855=>1, 1856=>1, 1857=>1, 1858=>1, 1859=>1, 1860=>1, 1861=>1, + 1862=>1, 1863=>1, 1864=>1, 1865=>1, 1866=>1, 2305=>6, 2306=>6, 2309=>644, 2310=>816, 2311=>392, 2312=>392, 2313=>459, 2314=>661, 2315=>641, 2317=>423, 2320=>423, + 2321=>816, 2323=>816, 2324=>816, 2325=>393, 2326=>622, 2327=>424, 2328=>472, 2329=>508, 2330=>517, 2331=>583, 2332=>549, 2333=>503, 2334=>538, 2335=>444, 2336=>480, 2337=>519, + 2338=>479, 2339=>504, 2340=>439, 2341=>542, 2342=>427, 2343=>520, 2344=>415, 2345=>415, 2346=>401, 2347=>401, 2348=>442, 2349=>520, 2350=>463, 2351=>451, 2352=>319, 2353=>319, + 2354=>549, 2355=>641, 2357=>442, 2358=>589, 2359=>398, 2360=>506, 2361=>430, 2364=>6, 2365=>438, 2366=>172, 2367=>172, 2368=>172, 2369=>6, 2370=>6, 2371=>6, 2373=>6, + 2375=>6, 2376=>6, 2377=>172, 2379=>172, 2380=>172, 2381=>6, 2384=>898, 2385=>6, 2406=>584, 2407=>584, 2408=>584, 2409=>584, 2410=>584, 2411=>584, 2412=>584, 2413=>584, + 2414=>584, 2415=>584, 2416=>898, 2433=>300, 2434=>400, 2435=>300, 2437=>640, 2438=>780, 2439=>520, 2440=>520, 2441=>530, 2442=>550, 2443=>620, 2444=>420, 2447=>480, 2448=>620, + 2451=>620, 2452=>720, 2453=>652, 2454=>500, 2455=>490, 2456=>466, 2457=>540, 2458=>490, 2459=>540, 2460=>630, 2461=>590, 2462=>680, 2463=>510, 2464=>490, 2465=>520, 2466=>520, + 2467=>470, 2468=>540, 2469=>490, 2470=>470, 2471=>490, 2472=>452, 2474=>560, 2475=>650, 2476=>480, 2477=>588, 2478=>480, 2479=>470, 2480=>480, 2482=>472, 2486=>512, 2487=>470, + 2488=>470, 2489=>520, 2492=>160, 2494=>180, 2495=>180, 2496=>180, 2497=>320, 2498=>329, 2499=>195, 2500=>260, 2503=>340, 2504=>340, 2507=>740, 2508=>740, 2509=>400, 2519=>180, + 2524=>540, 2525=>520, 2527=>470, 2528=>612, 2529=>420, 2530=>234, 2531=>360, 2534=>460, 2535=>420, 2536=>520, 2537=>540, 2538=>400, 2539=>400, 2540=>560, 2541=>390, 2542=>480, + 2543=>420, 2544=>480, 2545=>470, 2546=>400, 2547=>470, 2548=>400, 2549=>400, 2550=>400, 2551=>120, 2552=>440, 2553=>420, 2554=>420, 2565=>744, 2566=>914, 2567=>690, 2568=>670, + 2569=>596, 2570=>596, 2575=>498, 2576=>744, 2579=>596, 2580=>744, 2581=>550, 2582=>534, 2583=>618, 2584=>690, 2585=>546, 2586=>518, 2587=>592, 2588=>492, 2589=>574, 2590=>514, + 2591=>526, 2592=>556, 2593=>524, 2594=>528, 2595=>574, 2596=>484, 2597=>534, 2598=>504, 2599=>534, 2600=>538, 2602=>534, 2603=>506, 2604=>562, 2605=>516, 2606=>546, 2607=>670, + 2608=>538, 2610=>726, 2611=>726, 2613=>514, 2614=>546, 2616=>546, 2617=>517, 2620=>286, 2622=>172, 2623=>190, 2624=>190, 2625=>1, 2626=>1, 2631=>1, 2632=>1, 2635=>1, + 2636=>1, 2637=>1, 2649=>534, 2650=>618, 2651=>492, 2652=>484, 2654=>506, 2662=>616, 2663=>480, 2664=>560, 2665=>480, 2666=>468, 2667=>492, 2668=>514, 2669=>538, 2670=>572, + 2671=>560, 2672=>1, 2674=>498, 2675=>596, 2676=>900, 2689=>33, 2690=>33, 2693=>767, 2694=>961, 2695=>500, 2696=>495, 2697=>528, 2698=>702, 2699=>885, 2709=>501, 2710=>612, + 2711=>619, 2712=>569, 2713=>532, 2714=>358, 2715=>620, 2716=>606, 2717=>602, 2718=>631, 2719=>495, 2720=>528, 2721=>531, 2722=>511, 2723=>614, 2724=>294, 2725=>344, 2726=>425, + 2727=>345, 2728=>611, 2730=>512, 2731=>578, 2732=>428, 2733=>423, 2734=>231, 2735=>582, 2736=>344, 2738=>558, 2739=>670, 2741=>537, 2742=>592, 2743=>568, 2744=>600, 2745=>544, + 2749=>531, 2750=>232, 2751=>232, 2752=>232, 2753=>33, 2754=>33, 2755=>33, 2759=>33, 2760=>33, 2763=>232, 2764=>232, 2768=>903, 2790=>479, 2791=>416, 2792=>465, 2793=>469, + 2794=>498, 2795=>463, 2796=>451, 2797=>510, 2798=>455, 2799=>488, 2818=>131, 2819=>302, 2821=>560, 2822=>644, 2823=>632, 2825=>630, 2827=>553, 2831=>604, 2835=>520, 2837=>572, + 2838=>570, 2839=>580, 2840=>565, 2842=>580, 2844=>564, 2845=>575, 2847=>565, 2848=>565, 2849=>524, 2858=>572, 2859=>700, 2863=>655, 2864=>620, 2866=>652, 2867=>560, 2870=>565, + 2871=>565, 2872=>545, 2873=>524, 2878=>128, 2879=>1, 2880=>190, 2881=>1, 2882=>1, 2883=>1, 2887=>396, 2912=>563, 2918=>508, 2919=>424, 2920=>440, 2921=>600, 2922=>600, + 2923=>600, 2924=>600, 2925=>600, 2926=>511, 2927=>483, 2946=>479, 2947=>893, 2949=>1018, 2950=>1170, 2951=>916, 2952=>676, 2953=>836, 2954=>1225, 2958=>744, 2959=>744, 2960=>848, + 2962=>813, 2963=>813, 2964=>813, 2965=>688, 2969=>744, 2970=>676, 2972=>848, 2974=>984, 2975=>777, 2979=>1338, 2980=>664, 2984=>561, 2985=>1029, 2986=>607, 2990=>697, 2991=>697, + 2992=>434, 2993=>617, 2994=>869, 2995=>859, 2996=>697, 2997=>869, 2999=>1145, 3000=>1064, 3001=>1316, 3006=>424, 3007=>125, 3008=>596, 3009=>539, 3014=>596, 3015=>650, 3016=>973, + 3018=>1286, 3019=>1286, 3020=>1706, 3021=>333, 3031=>859, 3034=>778, 3035=>881, 3036=>876, 3037=>648, 3041=>744, 3203=>342, 3205=>620, 3206=>591, 3207=>600, 3208=>776, 3209=>1138, + 3210=>1464, 3214=>574, 3215=>570, 3216=>580, 3218=>589, 3219=>597, 3220=>625, 3221=>256, 3222=>565, 3223=>326, 3224=>604, 3225=>651, 3226=>408, 3228=>611, 3230=>843, 3231=>610, + 3232=>258, 3233=>317, 3234=>328, 3235=>803, 3236=>317, 3237=>328, 3238=>352, 3239=>352, 3240=>317, 3248=>248, 3249=>621, 3250=>620, 3251=>620, 3302=>649, 3303=>550, 3304=>573, + 3305=>567, 3306=>562, 3307=>557, 3308=>562, 3309=>567, 3310=>557, 3311=>557, 3458=>468, 3459=>318, 3461=>660, 3465=>778, 3466=>807, 3467=>830, 3473=>838, 3476=>860, 3481=>1000, + 3482=>973, 3483=>860, 3484=>997, 3486=>740, 3488=>838, 3489=>886, 3490=>886, 3492=>1295, 3493=>1295, 3495=>838, 3496=>860, 3497=>860, 3498=>860, 3499=>1403, 3501=>973, 3502=>838, + 3503=>660, 3504=>860, 3505=>973, 3507=>660, 3508=>886, 3509=>838, 3510=>860, 3511=>973, 3512=>838, 3513=>860, 3514=>886, 3515=>807, 3517=>830, 3520=>838, 3521=>973, 3522=>886, + 3523=>886, 3524=>973, 3525=>830, 3526=>973, 3530=>0, 3535=>432, 3536=>380, 3537=>420, 3538=>0, 3539=>0, 3540=>0, 3542=>0, 3544=>501, 3545=>652, 3551=>648, 7936=>596, + 7937=>596, 7938=>596, 7939=>596, 7940=>596, 7941=>596, 7942=>596, 7943=>596, 7944=>684, 7945=>684, 7946=>684, 7947=>684, 7948=>684, 7949=>684, 7950=>684, 7951=>684, 7952=>510, + 7953=>510, 7954=>510, 7955=>510, 7956=>510, 7957=>510, 7960=>650, 7961=>650, 7962=>650, 7963=>650, 7964=>650, 7965=>650, 7968=>526, 7969=>526, 7970=>526, 7971=>526, 7972=>526, + 7973=>526, 7974=>526, 7975=>526, 7976=>683, 7977=>683, 7978=>683, 7979=>683, 7980=>683, 7981=>683, 7982=>683, 7983=>683, 7984=>286, 7985=>286, 7986=>286, 7987=>286, 7988=>286, + 7989=>286, 7990=>286, 7991=>286, 7992=>236, 7993=>236, 7994=>236, 7995=>236, 7996=>236, 7997=>236, 7998=>236, 7999=>236, 8000=>550, 8001=>550, 8002=>550, 8003=>550, 8004=>550, + 8005=>550, 8008=>750, 8009=>750, 8010=>750, 8011=>750, 8012=>750, 8013=>750, 8016=>515, 8017=>515, 8018=>515, 8019=>515, 8020=>515, 8021=>515, 8022=>515, 8023=>515, 8025=>684, + 8027=>684, 8029=>684, 8031=>684, 8032=>740, 8033=>740, 8034=>740, 8035=>740, 8036=>740, 8037=>740, 8038=>740, 8039=>740, 8040=>720, 8041=>720, 8042=>720, 8043=>720, 8044=>720, + 8045=>720, 8046=>720, 8047=>720, 8048=>596, 8049=>596, 8050=>510, 8051=>510, 8052=>526, 8053=>526, 8054=>286, 8055=>286, 8056=>550, 8057=>550, 8058=>515, 8059=>515, 8060=>740, + 8061=>740, 8064=>596, 8065=>596, 8066=>596, 8067=>596, 8068=>596, 8069=>596, 8070=>596, 8071=>596, 8072=>882, 8073=>882, 8074=>882, 8075=>882, 8076=>882, 8077=>882, 8078=>882, + 8079=>882, 8080=>526, 8081=>526, 8082=>526, 8083=>526, 8084=>526, 8085=>526, 8086=>526, 8087=>526, 8088=>857, 8089=>857, 8090=>857, 8091=>857, 8092=>857, 8093=>857, 8094=>857, + 8095=>857, 8096=>740, 8097=>740, 8098=>740, 8099=>740, 8100=>740, 8101=>740, 8102=>740, 8103=>740, 8104=>945, 8105=>945, 8106=>945, 8107=>945, 8108=>945, 8109=>945, 8110=>945, + 8111=>945, 8112=>596, 8113=>596, 8114=>596, 8115=>596, 8116=>596, 8118=>596, 8119=>596, 8120=>684, 8121=>684, 8122=>684, 8123=>684, 8124=>882, 8125=>278, 8126=>201, 8127=>333, + 8128=>278, 8129=>333, 8130=>526, 8131=>526, 8132=>536, 8134=>526, 8135=>526, 8136=>650, 8137=>650, 8138=>683, 8139=>683, 8140=>857, 8141=>582, 8142=>582, 8143=>333, 8144=>286, + 8145=>286, 8146=>286, 8147=>286, 8150=>286, 8151=>312, 8152=>236, 8153=>236, 8154=>236, 8155=>236, 8157=>582, 8158=>582, 8159=>333, 8160=>515, 8161=>515, 8162=>515, 8163=>515, + 8164=>566, 8165=>566, 8166=>515, 8167=>515, 8168=>684, 8169=>684, 8170=>684, 8171=>684, 8172=>638, 8173=>333, 8174=>393, 8175=>333, 8178=>740, 8179=>740, 8180=>740, 8182=>740, + 8183=>740, 8184=>750, 8185=>750, 8186=>720, 8187=>720, 8188=>939, 8189=>333, 8190=>333, 8208=>333, 8219=>221, 8223=>333, 8227=>350, 8241=>1360, 8242=>278, 8243=>469, 8244=>680, + 8245=>278, 8246=>469, 8247=>680, 8251=>622, 8252=>556, 8253=>556, 8260=>167, 8263=>1112, 8264=>834, 8265=>834, 8267=>537, 8304=>351, 8305=>351, 8308=>351, 8309=>351, 8310=>351, + 8311=>351, 8312=>351, 8313=>351, 8320=>351, 8321=>351, 8322=>351, 8323=>351, 8324=>351, 8325=>353, 8326=>351, 8327=>351, 8328=>351, 8329=>351, 8359=>1445, 8360=>1222, 8362=>869, + 8459=>969, 8460=>615, 8464=>809, 8465=>519, 8466=>874, 8470=>1008, 8475=>850, 8476=>644, 8486=>720, 8487=>720, 8488=>512, 8490=>667, 8491=>667, 8492=>908, 8493=>623, 8496=>562, + 8497=>611, 8498=>611, 8499=>1080, 8531=>869, 8532=>869, 8533=>869, 8534=>869, 8535=>869, 8536=>869, 8537=>869, 8538=>869, 8539=>869, 8540=>869, 8541=>869, 8542=>869, 8543=>869, + 8544=>278, 8545=>556, 8546=>834, 8547=>945, 8548=>667, 8549=>945, 8550=>1223, 8551=>1501, 8552=>945, 8553=>667, 8554=>945, 8555=>1223, 8556=>556, 8557=>722, 8558=>722, 8559=>833, + 8560=>222, 8561=>444, 8562=>666, 8563=>722, 8564=>500, 8565=>722, 8566=>944, 8567=>1166, 8568=>722, 8569=>500, 8570=>722, 8571=>944, 8572=>222, 8573=>500, 8574=>556, 8575=>833, + 8592=>987, 8593=>603, 8594=>987, 8595=>603, 8596=>1042, 8597=>1042, 8629=>658, 8656=>987, 8657=>603, 8658=>987, 8659=>603, 8660=>1042, 8704=>667, 8706=>556, 8707=>667, 8709=>556, + 8710=>711, 8711=>711, 8712=>713, 8713=>713, 8719=>823, 8720=>823, 8721=>804, 8722=>584, 8723=>584, 8727=>500, 8730=>542, 8733=>713, 8734=>713, 8736=>768, 8743=>603, 8744=>603, + 8745=>768, 8746=>768, 8747=>556, 8748=>796, 8749=>956, 8750=>556, 8756=>863, 8764=>549, 8766=>584, 8769=>584, 8770=>584, 8771=>584, 8777=>636, 8800=>548, 8804=>584, 8805=>584, + 8853=>768, 8854=>768, 8855=>768, 8869=>658, 8960=>823, 9674=>489, 9834=>555, 12289=>1000, 12290=>1000, 12291=>1000, 12293=>1000, 12295=>1000, 12296=>1000, 12297=>1000, 12298=>1000, 12299=>1000, + 12300=>1000, 12301=>1000, 12302=>1000, 12303=>1000, 12304=>1000, 12305=>1000, 12308=>1000, 12309=>1000, 12353=>1000, 12354=>1000, 12355=>1000, 12356=>1000, 12357=>1000, 12358=>1000, 12359=>1000, 12360=>1000, + 12361=>1000, 12362=>1000, 12363=>1000, 12364=>1000, 12365=>1000, 12366=>1000, 12367=>1000, 12368=>1000, 12369=>1000, 12370=>1000, 12371=>1000, 12372=>1000, 12373=>1000, 12374=>1000, 12375=>1000, 12376=>1000, + 12377=>1000, 12378=>1000, 12379=>1000, 12380=>1000, 12381=>1000, 12382=>1000, 12383=>1000, 12384=>1000, 12385=>1000, 12386=>1000, 12387=>1000, 12388=>1000, 12389=>1000, 12390=>1000, 12391=>1000, 12392=>1000, + 12393=>1000, 12394=>1000, 12395=>1000, 12396=>1000, 12397=>1000, 12398=>1000, 12399=>1000, 12400=>1000, 12401=>1000, 12402=>1000, 12403=>1000, 12404=>1000, 12405=>1000, 12406=>1000, 12407=>1000, 12408=>1000, + 12409=>1000, 12410=>1000, 12411=>1000, 12412=>1000, 12413=>1000, 12414=>1000, 12415=>1000, 12416=>1000, 12417=>1000, 12418=>1000, 12419=>1000, 12420=>1000, 12421=>1000, 12422=>1000, 12423=>1000, 12424=>1000, + 12425=>1000, 12426=>1000, 12427=>1000, 12428=>1000, 12429=>1000, 12430=>1000, 12431=>1000, 12432=>1000, 12433=>1000, 12434=>1000, 12435=>1000, 12441=>1000, 12443=>1000, 12449=>1000, 12450=>1000, 12451=>1000, + 12452=>1000, 12453=>1000, 12454=>1000, 12455=>1000, 12456=>1000, 12457=>1000, 12458=>1000, 12459=>1000, 12460=>1000, 12461=>1000, 12462=>1000, 12463=>1000, 12464=>1000, 12465=>1000, 12466=>1000, 12467=>1000, + 12468=>1000, 12469=>1000, 12470=>1000, 12471=>1000, 12472=>1000, 12473=>1000, 12474=>1000, 12475=>1000, 12476=>1000, 12477=>1000, 12478=>1000, 12479=>1000, 12480=>1000, 12481=>1000, 12482=>1000, 12483=>1000, + 12484=>1000, 12485=>1000, 12486=>1000, 12487=>1000, 12488=>1000, 12489=>1000, 12490=>1000, 12491=>1000, 12492=>1000, 12493=>1000, 12494=>1000, 12495=>1000, 12496=>1000, 12497=>1000, 12498=>1000, 12499=>1000, + 12500=>1000, 12501=>1000, 12502=>1000, 12503=>1000, 12504=>1000, 12505=>1000, 12506=>1000, 12507=>1000, 12508=>1000, 12509=>1000, 12510=>1000, 12511=>1000, 12512=>1000, 12513=>1000, 12514=>1000, 12515=>1000, + 12516=>1000, 12517=>1000, 12518=>1000, 12519=>1000, 12520=>1000, 12521=>1000, 12522=>1000, 12523=>1000, 12524=>1000, 12525=>1000, 12526=>1000, 12527=>1000, 12528=>1000, 12529=>1000, 12530=>1000, 12531=>1000, + 12532=>1000, 12533=>1000, 12534=>1000, 12535=>1000, 12536=>1000, 12537=>1000, 12538=>1000, 12539=>278, 12540=>1000, 12541=>1000, 12542=>1000, 63033=>556, 63034=>556, 63035=>556, 63036=>556, 63037=>556, + 63038=>556, 63039=>556, 63040=>556, 63041=>556, 63166=>222, 63171=>333, 63196=>556, 64256=>556, 64257=>500, 64258=>500, 64259=>778, 64260=>778, 64261=>556, 64262=>778, 64285=>200, 64286=>305, + 64287=>400, 64288=>587, 64289=>890, 64290=>848, 64291=>872, 64292=>800, 64293=>850, 64294=>873, 64295=>797, 64296=>937, 64297=>584, 64298=>776, 64299=>776, 64300=>776, 64301=>776, 64302=>640, + 64303=>640, 64304=>640, 64305=>591, 64306=>466, 64307=>598, 64308=>622, 64309=>262, 64310=>351, 64312=>608, 64313=>270, 64314=>526, 64315=>550, 64316=>600, 64318=>621, 64320=>378, 64321=>607, + 64323=>575, 64324=>568, 64326=>590, 64327=>606, 64328=>547, 64329=>776, 64330=>687, 64331=>212, 64332=>591, 64333=>550, 64334=>568, 64335=>640, 65533=>788} + font[:enc]=''; + font[:diff]=''; + font[:file]='FreeSans.z'; + font[:ctg]='FreeSans.ctg.z'; + font[:originalsize]=264072; +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1a/1ac4dbb6341375ce31f3dc814df9fd5800c3148d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1a/1ac4dbb6341375ce31f3dc814df9fd5800c3148d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +# Mocks out OpenID +# +# http://www.northpub.com/articles/2007/04/02/testing-openid-support +module OpenIdAuthentication + + EXTENSION_FIELDS = {'email' => 'user@somedomain.com', + 'nickname' => 'cool_user', + 'country' => 'US', + 'postcode' => '12345', + 'fullname' => 'Cool User', + 'dob' => '1970-04-01', + 'language' => 'en', + 'timezone' => 'America/New_York'} + + protected + + def authenticate_with_open_id(identity_url = params[:openid_url], options = {}) #:doc: + if User.find_by_identity_url(identity_url) || identity_url.include?('good') + # Don't process registration fields unless it is requested. + unless identity_url.include?('blank') || (options[:required].nil? && options[:optional].nil?) + extension_response_fields = {} + + options[:required].each do |field| + extension_response_fields[field.to_s] = EXTENSION_FIELDS[field.to_s] + end unless options[:required].nil? + + options[:optional].each do |field| + extension_response_fields[field.to_s] = EXTENSION_FIELDS[field.to_s] + end unless options[:optional].nil? + end + + yield Result[:successful], identity_url , extension_response_fields + else + logger.info "OpenID authentication failed: #{identity_url}" + yield Result[:failed], identity_url, nil + end + end + + private + + def add_simple_registration_fields(open_id_response, fields) + open_id_response.add_extension_arg('sreg', 'required', [ fields[:required] ].flatten * ',') if fields[:required] + open_id_response.add_extension_arg('sreg', 'optional', [ fields[:optional] ].flatten * ',') if fields[:optional] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1b/1b0ed23201303f160d7d4495d1661d066db9d987.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1b/1b0ed23201303f160d7d4495d1661d066db9d987.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +
+
+ +<%= l(:label_issues_by, + select_tag('status_by', + status_by_options_for_select(criteria), + :id => 'status_by_select', + :onchange => remote_function(:url => status_by_version_path(version), + :with => "Form.serialize('status_by_form')"))) %> + +<% if counts.empty? %> +

<%= l(:label_no_data) %>

+<% else %> + + <% counts.each do |count| %> + + + + + <% end %> +
+ <%= link_to h(count[:group]), {:controller => 'issues', + :action => 'index', + :project_id => version.project, + :set_filter => 1, + :status_id => '*', + :fixed_version_id => version}.merge("#{criteria}_id".to_sym => count[:group]) %> + + <%= progress_bar((count[:closed].to_f / count[:total])*100, + :legend => "#{count[:closed]}/#{count[:total]}", + :width => "#{(count[:total].to_f / max * 200).floor}px;") %> +
+<% end %> +
+
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1b/1b578055102e356a87f5f77cb58bb01b760471f9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1b/1b578055102e356a87f5f77cb58bb01b760471f9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +plain template \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1b/1b72750fe3e10ec61029653a70e90ded5cedc32d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1b/1b72750fe3e10ec61029653a70e90ded5cedc32d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +api.array :issue_categories, api_meta(:total_count => @categories.size) do + @categories.each do |category| + api.issue_category do + api.id category.id + api.project(:id => category.project_id, :name => category.project.name) unless category.project.nil? + api.name category.name + api.assigned_to(:id => category.assigned_to_id, :name => category.assigned_to.name) unless category.assigned_to.nil? + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1b/1ba2c6ffd62ba44a997d21f2258fab77c2264196.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1b/1ba2c6ffd62ba44a997d21f2258fab77c2264196.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +ActiveRecord::Schema.define(:version => 0) do + + create_table :categories, :force => true do |t| + t.column :name, :string + t.column :parent_id, :integer + t.column :lft, :integer + t.column :rgt, :integer + t.column :organization_id, :integer + end + + create_table :departments, :force => true do |t| + t.column :name, :string + end + + create_table :notes, :force => true do |t| + t.column :body, :text + t.column :parent_id, :integer + t.column :lft, :integer + t.column :rgt, :integer + t.column :notable_id, :integer + t.column :notable_type, :string + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1b/1bf322e40d14051308bb92bbfb41fdba8ea03c74.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1b/1bf322e40d14051308bb92bbfb41fdba8ea03c74.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 BoardsHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1c/1c133f685ba1e7aa677a1a8d5d646e268fcc08fc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1c/1c133f685ba1e7aa677a1a8d5d646e268fcc08fc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,206 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +begin + require 'mocha' +rescue + # Won't run some tests +end + +class AccountTest < ActionController::IntegrationTest + fixtures :users, :roles + + # Replace this with your real tests. + def test_login + get "my/page" + assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fmy%2Fpage" + log_user('jsmith', 'jsmith') + + get "my/account" + assert_response :success + assert_template "my/account" + end + + def test_autologin + user = User.find(1) + Setting.autologin = "7" + Token.delete_all + + # User logs in with 'autologin' checked + post '/login', :username => user.login, :password => 'admin', :autologin => 1 + assert_redirected_to '/my/page' + token = Token.find :first + assert_not_nil token + assert_equal user, token.user + assert_equal 'autologin', token.action + assert_equal user.id, session[:user_id] + assert_equal token.value, cookies['autologin'] + + # Session is cleared + reset! + User.current = nil + # Clears user's last login timestamp + user.update_attribute :last_login_on, nil + assert_nil user.reload.last_login_on + + # User comes back with his autologin cookie + cookies[:autologin] = token.value + get '/my/page' + assert_response :success + assert_template 'my/page' + assert_equal user.id, session[:user_id] + assert_not_nil user.reload.last_login_on + assert user.last_login_on.utc > 10.second.ago.utc + end + + def test_lost_password + Token.delete_all + + get "account/lost_password" + assert_response :success + assert_template "account/lost_password" + + post "account/lost_password", :mail => 'jSmith@somenet.foo' + assert_redirected_to "/login" + + token = Token.find(:first) + assert_equal 'recovery', token.action + assert_equal 'jsmith@somenet.foo', token.user.mail + assert !token.expired? + + get "account/lost_password", :token => token.value + assert_response :success + assert_template "account/password_recovery" + + post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass' + assert_redirected_to "/login" + assert_equal 'Password was successfully updated.', flash[:notice] + + log_user('jsmith', 'newpass') + assert_equal 0, Token.count + end + + def test_register_with_automatic_activation + Setting.self_registration = '3' + + get 'account/register' + assert_response :success + assert_template 'account/register' + + post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, + :password => "newpass", :password_confirmation => "newpass" + assert_redirected_to '/my/account' + follow_redirect! + assert_response :success + assert_template 'my/account' + + user = User.find_by_login('newuser') + assert_not_nil user + assert user.active? + assert_not_nil user.last_login_on + end + + def test_register_with_manual_activation + Setting.self_registration = '2' + + post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, + :password => "newpass", :password_confirmation => "newpass" + assert_redirected_to '/login' + assert !User.find_by_login('newuser').active? + end + + def test_register_with_email_activation + Setting.self_registration = '1' + Token.delete_all + + post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, + :password => "newpass", :password_confirmation => "newpass" + assert_redirected_to '/login' + assert !User.find_by_login('newuser').active? + + token = Token.find(:first) + assert_equal 'register', token.action + assert_equal 'newuser@foo.bar', token.user.mail + assert !token.expired? + + get 'account/activate', :token => token.value + assert_redirected_to '/login' + log_user('newuser', 'newpass') + end + + if Object.const_defined?(:Mocha) + + def test_onthefly_registration + # disable registration + Setting.self_registration = '0' + AuthSource.expects(:authenticate).returns({:login => 'foo', :firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com', :auth_source_id => 66}) + + post 'account/login', :username => 'foo', :password => 'bar' + assert_redirected_to '/my/page' + + user = User.find_by_login('foo') + assert user.is_a?(User) + assert_equal 66, user.auth_source_id + assert user.hashed_password.blank? + end + + def test_onthefly_registration_with_invalid_attributes + # disable registration + Setting.self_registration = '0' + AuthSource.expects(:authenticate).returns({:login => 'foo', :lastname => 'Smith', :auth_source_id => 66}) + + post 'account/login', :username => 'foo', :password => 'bar' + assert_response :success + assert_template 'account/register' + assert_tag :input, :attributes => { :name => 'user[firstname]', :value => '' } + assert_tag :input, :attributes => { :name => 'user[lastname]', :value => 'Smith' } + assert_no_tag :input, :attributes => { :name => 'user[login]' } + assert_no_tag :input, :attributes => { :name => 'user[password]' } + + post 'account/register', :user => {:firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com'} + assert_redirected_to '/my/account' + + user = User.find_by_login('foo') + assert user.is_a?(User) + assert_equal 66, user.auth_source_id + assert user.hashed_password.blank? + end + + def test_login_and_logout_should_clear_session + get '/login' + sid = session[:session_id] + + post '/login', :username => 'admin', :password => 'admin' + assert_redirected_to '/my/page' + assert_not_equal sid, session[:session_id], "login should reset session" + assert_equal 1, session[:user_id] + sid = session[:session_id] + + get '/' + assert_equal sid, session[:session_id] + + get '/logout' + assert_not_equal sid, session[:session_id], "logout should reset session" + assert_nil session[:user_id] + end + + else + puts 'Mocha is missing. Skipping tests.' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1c/1c4d5064dd3462653f5b23a0aeda5a3d982312be.svn-base Binary file .svn/pristine/1c/1c4d5064dd3462653f5b23a0aeda5a3d982312be.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1c/1c5257cafbf7d7508949bf6ef73182b08b1fa87d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1c/1c5257cafbf7d7508949bf6ef73182b08b1fa87d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1585 @@ +# +# setup.rb +# +# Copyright (c) 2000-2005 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# + +unless Enumerable.method_defined?(:map) # Ruby 1.4.6 + module Enumerable + alias map collect + end +end + +unless File.respond_to?(:read) # Ruby 1.6 + def File.read(fname) + open(fname) {|f| + return f.read + } + end +end + +unless Errno.const_defined?(:ENOTEMPTY) # Windows? + module Errno + class ENOTEMPTY + # We do not raise this exception, implementation is not needed. + end + end +end + +def File.binread(fname) + open(fname, 'rb') {|f| + return f.read + } +end + +# for corrupted Windows' stat(2) +def File.dir?(path) + File.directory?((path[-1,1] == '/') ? path : path + '/') +end + + +class ConfigTable + + include Enumerable + + def initialize(rbconfig) + @rbconfig = rbconfig + @items = [] + @table = {} + # options + @install_prefix = nil + @config_opt = nil + @verbose = true + @no_harm = false + end + + attr_accessor :install_prefix + attr_accessor :config_opt + + attr_writer :verbose + + def verbose? + @verbose + end + + attr_writer :no_harm + + def no_harm? + @no_harm + end + + def [](key) + lookup(key).resolve(self) + end + + def []=(key, val) + lookup(key).set val + end + + def names + @items.map {|i| i.name } + end + + def each(&block) + @items.each(&block) + end + + def key?(name) + @table.key?(name) + end + + def lookup(name) + @table[name] or setup_rb_error "no such config item: #{name}" + end + + def add(item) + @items.push item + @table[item.name] = item + end + + def remove(name) + item = lookup(name) + @items.delete_if {|i| i.name == name } + @table.delete_if {|name, i| i.name == name } + item + end + + def load_script(path, inst = nil) + if File.file?(path) + MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path + end + end + + def savefile + '.config' + end + + def load_savefile + begin + File.foreach(savefile()) do |line| + k, v = *line.split(/=/, 2) + self[k] = v.strip + end + rescue Errno::ENOENT + setup_rb_error $!.message + "\n#{File.basename($0)} config first" + end + end + + def save + @items.each {|i| i.value } + File.open(savefile(), 'w') {|f| + @items.each do |i| + f.printf "%s=%s\n", i.name, i.value if i.value? and i.value + end + } + end + + def load_standard_entries + standard_entries(@rbconfig).each do |ent| + add ent + end + end + + def standard_entries(rbconfig) + c = rbconfig + + rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) + + major = c['MAJOR'].to_i + minor = c['MINOR'].to_i + teeny = c['TEENY'].to_i + version = "#{major}.#{minor}" + + # ruby ver. >= 1.4.4? + newpath_p = ((major >= 2) or + ((major == 1) and + ((minor >= 5) or + ((minor == 4) and (teeny >= 4))))) + + if c['rubylibdir'] + # V > 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = c['rubylibdir'] + librubyverarch = c['archdir'] + siteruby = c['sitedir'] + siterubyver = c['sitelibdir'] + siterubyverarch = c['sitearchdir'] + elsif newpath_p + # 1.4.4 <= V <= 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = c['sitedir'] + siterubyver = "$siteruby/#{version}" + siterubyverarch = "$siterubyver/#{c['arch']}" + else + # V < 1.4.4 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" + siterubyver = siteruby + siterubyverarch = "$siterubyver/#{c['arch']}" + end + parameterize = lambda {|path| + path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') + } + + if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } + makeprog = arg.sub(/'/, '').split(/=/, 2)[1] + else + makeprog = 'make' + end + + [ + ExecItem.new('installdirs', 'std/site/home', + 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ + {|val, table| + case val + when 'std' + table['rbdir'] = '$librubyver' + table['sodir'] = '$librubyverarch' + when 'site' + table['rbdir'] = '$siterubyver' + table['sodir'] = '$siterubyverarch' + when 'home' + setup_rb_error '$HOME was not set' unless ENV['HOME'] + table['prefix'] = ENV['HOME'] + table['rbdir'] = '$libdir/ruby' + table['sodir'] = '$libdir/ruby' + end + }, + PathItem.new('prefix', 'path', c['prefix'], + 'path prefix of target environment'), + PathItem.new('bindir', 'path', parameterize.call(c['bindir']), + 'the directory for commands'), + PathItem.new('libdir', 'path', parameterize.call(c['libdir']), + 'the directory for libraries'), + PathItem.new('datadir', 'path', parameterize.call(c['datadir']), + 'the directory for shared data'), + PathItem.new('mandir', 'path', parameterize.call(c['mandir']), + 'the directory for man pages'), + PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), + 'the directory for system configuration files'), + PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), + 'the directory for local state data'), + PathItem.new('libruby', 'path', libruby, + 'the directory for ruby libraries'), + PathItem.new('librubyver', 'path', librubyver, + 'the directory for standard ruby libraries'), + PathItem.new('librubyverarch', 'path', librubyverarch, + 'the directory for standard ruby extensions'), + PathItem.new('siteruby', 'path', siteruby, + 'the directory for version-independent aux ruby libraries'), + PathItem.new('siterubyver', 'path', siterubyver, + 'the directory for aux ruby libraries'), + PathItem.new('siterubyverarch', 'path', siterubyverarch, + 'the directory for aux ruby binaries'), + PathItem.new('rbdir', 'path', '$siterubyver', + 'the directory for ruby scripts'), + PathItem.new('sodir', 'path', '$siterubyverarch', + 'the directory for ruby extentions'), + PathItem.new('rubypath', 'path', rubypath, + 'the path to set to #! line'), + ProgramItem.new('rubyprog', 'name', rubypath, + 'the ruby program using for installation'), + ProgramItem.new('makeprog', 'name', makeprog, + 'the make program to compile ruby extentions'), + SelectItem.new('shebang', 'all/ruby/never', 'ruby', + 'shebang line (#!) editing mode'), + BoolItem.new('without-ext', 'yes/no', 'no', + 'does not compile/install ruby extentions') + ] + end + private :standard_entries + + def load_multipackage_entries + multipackage_entries().each do |ent| + add ent + end + end + + def multipackage_entries + [ + PackageSelectionItem.new('with', 'name,name...', '', 'ALL', + 'package names that you want to install'), + PackageSelectionItem.new('without', 'name,name...', '', 'NONE', + 'package names that you do not want to install') + ] + end + private :multipackage_entries + + ALIASES = { + 'std-ruby' => 'librubyver', + 'stdruby' => 'librubyver', + 'rubylibdir' => 'librubyver', + 'archdir' => 'librubyverarch', + 'site-ruby-common' => 'siteruby', # For backward compatibility + 'site-ruby' => 'siterubyver', # For backward compatibility + 'bin-dir' => 'bindir', + 'bin-dir' => 'bindir', + 'rb-dir' => 'rbdir', + 'so-dir' => 'sodir', + 'data-dir' => 'datadir', + 'ruby-path' => 'rubypath', + 'ruby-prog' => 'rubyprog', + 'ruby' => 'rubyprog', + 'make-prog' => 'makeprog', + 'make' => 'makeprog' + } + + def fixup + ALIASES.each do |ali, name| + @table[ali] = @table[name] + end + @items.freeze + @table.freeze + @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ + end + + def parse_opt(opt) + m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" + m.to_a[1,2] + end + + def dllext + @rbconfig['DLEXT'] + end + + def value_config?(name) + lookup(name).value? + end + + class Item + def initialize(name, template, default, desc) + @name = name.freeze + @template = template + @value = default + @default = default + @description = desc + end + + attr_reader :name + attr_reader :description + + attr_accessor :default + alias help_default default + + def help_opt + "--#{@name}=#{@template}" + end + + def value? + true + end + + def value + @value + end + + def resolve(table) + @value.gsub(%r<\$([^/]+)>) { table[$1] } + end + + def set(val) + @value = check(val) + end + + private + + def check(val) + setup_rb_error "config: --#{name} requires argument" unless val + val + end + end + + class BoolItem < Item + def config_type + 'bool' + end + + def help_opt + "--#{@name}" + end + + private + + def check(val) + return 'yes' unless val + case val + when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' + when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' + else + setup_rb_error "config: --#{@name} accepts only yes/no for argument" + end + end + end + + class PathItem < Item + def config_type + 'path' + end + + private + + def check(path) + setup_rb_error "config: --#{@name} requires argument" unless path + path[0,1] == '$' ? path : File.expand_path(path) + end + end + + class ProgramItem < Item + def config_type + 'program' + end + end + + class SelectItem < Item + def initialize(name, selection, default, desc) + super + @ok = selection.split('/') + end + + def config_type + 'select' + end + + private + + def check(val) + unless @ok.include?(val.strip) + setup_rb_error "config: use --#{@name}=#{@template} (#{val})" + end + val.strip + end + end + + class ExecItem < Item + def initialize(name, selection, desc, &block) + super name, selection, nil, desc + @ok = selection.split('/') + @action = block + end + + def config_type + 'exec' + end + + def value? + false + end + + def resolve(table) + setup_rb_error "$#{name()} wrongly used as option value" + end + + undef set + + def evaluate(val, table) + v = val.strip.downcase + unless @ok.include?(v) + setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" + end + @action.call v, table + end + end + + class PackageSelectionItem < Item + def initialize(name, template, default, help_default, desc) + super name, template, default, desc + @help_default = help_default + end + + attr_reader :help_default + + def config_type + 'package' + end + + private + + def check(val) + unless File.dir?("packages/#{val}") + setup_rb_error "config: no such package: #{val}" + end + val + end + end + + class MetaConfigEnvironment + def initialize(config, installer) + @config = config + @installer = installer + end + + def config_names + @config.names + end + + def config?(name) + @config.key?(name) + end + + def bool_config?(name) + @config.lookup(name).config_type == 'bool' + end + + def path_config?(name) + @config.lookup(name).config_type == 'path' + end + + def value_config?(name) + @config.lookup(name).config_type != 'exec' + end + + def add_config(item) + @config.add item + end + + def add_bool_config(name, default, desc) + @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) + end + + def add_path_config(name, default, desc) + @config.add PathItem.new(name, 'path', default, desc) + end + + def set_config_default(name, default) + @config.lookup(name).default = default + end + + def remove_config(name) + @config.remove(name) + end + + # For only multipackage + def packages + raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer + @installer.packages + end + + # For only multipackage + def declare_packages(list) + raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer + @installer.packages = list + end + end + +end # class ConfigTable + + +# This module requires: #verbose?, #no_harm? +module FileOperations + + def mkdir_p(dirname, prefix = nil) + dirname = prefix + File.expand_path(dirname) if prefix + $stderr.puts "mkdir -p #{dirname}" if verbose? + return if no_harm? + + # Does not check '/', it's too abnormal. + dirs = File.expand_path(dirname).split(%r<(?=/)>) + if /\A[a-z]:\z/i =~ dirs[0] + disk = dirs.shift + dirs[0] = disk + dirs[0] + end + dirs.each_index do |idx| + path = dirs[0..idx].join('') + Dir.mkdir path unless File.dir?(path) + end + end + + def rm_f(path) + $stderr.puts "rm -f #{path}" if verbose? + return if no_harm? + force_remove_file path + end + + def rm_rf(path) + $stderr.puts "rm -rf #{path}" if verbose? + return if no_harm? + remove_tree path + end + + def remove_tree(path) + if File.symlink?(path) + remove_file path + elsif File.dir?(path) + remove_tree0 path + else + force_remove_file path + end + end + + def remove_tree0(path) + Dir.foreach(path) do |ent| + next if ent == '.' + next if ent == '..' + entpath = "#{path}/#{ent}" + if File.symlink?(entpath) + remove_file entpath + elsif File.dir?(entpath) + remove_tree0 entpath + else + force_remove_file entpath + end + end + begin + Dir.rmdir path + rescue Errno::ENOTEMPTY + # directory may not be empty + end + end + + def move_file(src, dest) + force_remove_file dest + begin + File.rename src, dest + rescue + File.open(dest, 'wb') {|f| + f.write File.binread(src) + } + File.chmod File.stat(src).mode, dest + File.unlink src + end + end + + def force_remove_file(path) + begin + remove_file path + rescue + end + end + + def remove_file(path) + File.chmod 0777, path + File.unlink path + end + + def install(from, dest, mode, prefix = nil) + $stderr.puts "install #{from} #{dest}" if verbose? + return if no_harm? + + realdest = prefix ? prefix + File.expand_path(dest) : dest + realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) + str = File.binread(from) + if diff?(str, realdest) + verbose_off { + rm_f realdest if File.exist?(realdest) + } + File.open(realdest, 'wb') {|f| + f.write str + } + File.chmod mode, realdest + + File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| + if prefix + f.puts realdest.sub(prefix, '') + else + f.puts realdest + end + } + end + end + + def diff?(new_content, path) + return true unless File.exist?(path) + new_content != File.binread(path) + end + + def command(*args) + $stderr.puts args.join(' ') if verbose? + system(*args) or raise RuntimeError, + "system(#{args.map{|a| a.inspect }.join(' ')}) failed" + end + + def ruby(*args) + command config('rubyprog'), *args + end + + def make(task = nil) + command(*[config('makeprog'), task].compact) + end + + def extdir?(dir) + File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") + end + + def files_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.file?("#{dir}/#{ent}") } + } + end + + DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) + + def directories_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT + } + end + +end + + +# This module requires: #srcdir_root, #objdir_root, #relpath +module HookScriptAPI + + def get_config(key) + @config[key] + end + + alias config get_config + + # obsolete: use metaconfig to change configuration + def set_config(key, val) + @config[key] = val + end + + # + # srcdir/objdir (works only in the package directory) + # + + def curr_srcdir + "#{srcdir_root()}/#{relpath()}" + end + + def curr_objdir + "#{objdir_root()}/#{relpath()}" + end + + def srcfile(path) + "#{curr_srcdir()}/#{path}" + end + + def srcexist?(path) + File.exist?(srcfile(path)) + end + + def srcdirectory?(path) + File.dir?(srcfile(path)) + end + + def srcfile?(path) + File.file?(srcfile(path)) + end + + def srcentries(path = '.') + Dir.open("#{curr_srcdir()}/#{path}") {|d| + return d.to_a - %w(. ..) + } + end + + def srcfiles(path = '.') + srcentries(path).select {|fname| + File.file?(File.join(curr_srcdir(), path, fname)) + } + end + + def srcdirectories(path = '.') + srcentries(path).select {|fname| + File.dir?(File.join(curr_srcdir(), path, fname)) + } + end + +end + + +class ToplevelInstaller + + Version = '3.4.1' + Copyright = 'Copyright (c) 2000-2005 Minero Aoki' + + TASKS = [ + [ 'all', 'do config, setup, then install' ], + [ 'config', 'saves your configurations' ], + [ 'show', 'shows current configuration' ], + [ 'setup', 'compiles ruby extentions and others' ], + [ 'install', 'installs files' ], + [ 'test', 'run all tests in test/' ], + [ 'clean', "does `make clean' for each extention" ], + [ 'distclean',"does `make distclean' for each extention" ] + ] + + def ToplevelInstaller.invoke + config = ConfigTable.new(load_rbconfig()) + config.load_standard_entries + config.load_multipackage_entries if multipackage? + config.fixup + klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) + klass.new(File.dirname($0), config).invoke + end + + def ToplevelInstaller.multipackage? + File.dir?(File.dirname($0) + '/packages') + end + + def ToplevelInstaller.load_rbconfig + if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } + ARGV.delete(arg) + load File.expand_path(arg.split(/=/, 2)[1]) + $".push 'rbconfig.rb' + else + require 'rbconfig' + end + ::Config::CONFIG + end + + def initialize(ardir_root, config) + @ardir = File.expand_path(ardir_root) + @config = config + # cache + @valid_task_re = nil + end + + def config(key) + @config[key] + end + + def inspect + "#<#{self.class} #{__id__()}>" + end + + def invoke + run_metaconfigs + case task = parsearg_global() + when nil, 'all' + parsearg_config + init_installers + exec_config + exec_setup + exec_install + else + case task + when 'config', 'test' + ; + when 'clean', 'distclean' + @config.load_savefile if File.exist?(@config.savefile) + else + @config.load_savefile + end + __send__ "parsearg_#{task}" + init_installers + __send__ "exec_#{task}" + end + end + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig" + end + + def init_installers + @installer = Installer.new(@config, @ardir, File.expand_path('.')) + end + + # + # Hook Script API bases + # + + def srcdir_root + @ardir + end + + def objdir_root + '.' + end + + def relpath + '.' + end + + # + # Option Parsing + # + + def parsearg_global + while arg = ARGV.shift + case arg + when /\A\w+\z/ + setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) + return arg + when '-q', '--quiet' + @config.verbose = false + when '--verbose' + @config.verbose = true + when '--help' + print_usage $stdout + exit 0 + when '--version' + puts "#{File.basename($0)} version #{Version}" + exit 0 + when '--copyright' + puts Copyright + exit 0 + else + setup_rb_error "unknown global option '#{arg}'" + end + end + nil + end + + def valid_task?(t) + valid_task_re() =~ t + end + + def valid_task_re + @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ + end + + def parsearg_no_options + unless ARGV.empty? + task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) + setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" + end + end + + alias parsearg_show parsearg_no_options + alias parsearg_setup parsearg_no_options + alias parsearg_test parsearg_no_options + alias parsearg_clean parsearg_no_options + alias parsearg_distclean parsearg_no_options + + def parsearg_config + evalopt = [] + set = [] + @config.config_opt = [] + while i = ARGV.shift + if /\A--?\z/ =~ i + @config.config_opt = ARGV.dup + break + end + name, value = *@config.parse_opt(i) + if @config.value_config?(name) + @config[name] = value + else + evalopt.push [name, value] + end + set.push name + end + evalopt.each do |name, value| + @config.lookup(name).evaluate value, @config + end + # Check if configuration is valid + set.each do |n| + @config[n] if @config.value_config?(n) + end + end + + def parsearg_install + @config.no_harm = false + @config.install_prefix = '' + while a = ARGV.shift + case a + when '--no-harm' + @config.no_harm = true + when /\A--prefix=/ + path = a.split(/=/, 2)[1] + path = File.expand_path(path) unless path[0,1] == '/' + @config.install_prefix = path + else + setup_rb_error "install: unknown option #{a}" + end + end + end + + def print_usage(out) + out.puts 'Typical Installation Procedure:' + out.puts " $ ruby #{File.basename $0} config" + out.puts " $ ruby #{File.basename $0} setup" + out.puts " # ruby #{File.basename $0} install (may require root privilege)" + out.puts + out.puts 'Detailed Usage:' + out.puts " ruby #{File.basename $0} " + out.puts " ruby #{File.basename $0} [] []" + + fmt = " %-24s %s\n" + out.puts + out.puts 'Global options:' + out.printf fmt, '-q,--quiet', 'suppress message outputs' + out.printf fmt, ' --verbose', 'output messages verbosely' + out.printf fmt, ' --help', 'print this message' + out.printf fmt, ' --version', 'print version and quit' + out.printf fmt, ' --copyright', 'print copyright and quit' + out.puts + out.puts 'Tasks:' + TASKS.each do |name, desc| + out.printf fmt, name, desc + end + + fmt = " %-24s %s [%s]\n" + out.puts + out.puts 'Options for CONFIG or ALL:' + @config.each do |item| + out.printf fmt, item.help_opt, item.description, item.help_default + end + out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" + out.puts + out.puts 'Options for INSTALL:' + out.printf fmt, '--no-harm', 'only display what to do if given', 'off' + out.printf fmt, '--prefix=path', 'install path prefix', '' + out.puts + end + + # + # Task Handlers + # + + def exec_config + @installer.exec_config + @config.save # must be final + end + + def exec_setup + @installer.exec_setup + end + + def exec_install + @installer.exec_install + end + + def exec_test + @installer.exec_test + end + + def exec_show + @config.each do |i| + printf "%-20s %s\n", i.name, i.value if i.value? + end + end + + def exec_clean + @installer.exec_clean + end + + def exec_distclean + @installer.exec_distclean + end + +end # class ToplevelInstaller + + +class ToplevelInstallerMulti < ToplevelInstaller + + include FileOperations + + def initialize(ardir_root, config) + super + @packages = directories_of("#{@ardir}/packages") + raise 'no package exists' if @packages.empty? + @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) + end + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig", self + @packages.each do |name| + @config.load_script "#{@ardir}/packages/#{name}/metaconfig" + end + end + + attr_reader :packages + + def packages=(list) + raise 'package list is empty' if list.empty? + list.each do |name| + raise "directory packages/#{name} does not exist"\ + unless File.dir?("#{@ardir}/packages/#{name}") + end + @packages = list + end + + def init_installers + @installers = {} + @packages.each do |pack| + @installers[pack] = Installer.new(@config, + "#{@ardir}/packages/#{pack}", + "packages/#{pack}") + end + with = extract_selection(config('with')) + without = extract_selection(config('without')) + @selected = @installers.keys.select {|name| + (with.empty? or with.include?(name)) \ + and not without.include?(name) + } + end + + def extract_selection(list) + a = list.split(/,/) + a.each do |name| + setup_rb_error "no such package: #{name}" unless @installers.key?(name) + end + a + end + + def print_usage(f) + super + f.puts 'Inluded packages:' + f.puts ' ' + @packages.sort.join(' ') + f.puts + end + + # + # Task Handlers + # + + def exec_config + run_hook 'pre-config' + each_selected_installers {|inst| inst.exec_config } + run_hook 'post-config' + @config.save # must be final + end + + def exec_setup + run_hook 'pre-setup' + each_selected_installers {|inst| inst.exec_setup } + run_hook 'post-setup' + end + + def exec_install + run_hook 'pre-install' + each_selected_installers {|inst| inst.exec_install } + run_hook 'post-install' + end + + def exec_test + run_hook 'pre-test' + each_selected_installers {|inst| inst.exec_test } + run_hook 'post-test' + end + + def exec_clean + rm_f @config.savefile + run_hook 'pre-clean' + each_selected_installers {|inst| inst.exec_clean } + run_hook 'post-clean' + end + + def exec_distclean + rm_f @config.savefile + run_hook 'pre-distclean' + each_selected_installers {|inst| inst.exec_distclean } + run_hook 'post-distclean' + end + + # + # lib + # + + def each_selected_installers + Dir.mkdir 'packages' unless File.dir?('packages') + @selected.each do |pack| + $stderr.puts "Processing the package `#{pack}' ..." if verbose? + Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") + Dir.chdir "packages/#{pack}" + yield @installers[pack] + Dir.chdir '../..' + end + end + + def run_hook(id) + @root_installer.run_hook id + end + + # module FileOperations requires this + def verbose? + @config.verbose? + end + + # module FileOperations requires this + def no_harm? + @config.no_harm? + end + +end # class ToplevelInstallerMulti + + +class Installer + + FILETYPES = %w( bin lib ext data conf man ) + + include FileOperations + include HookScriptAPI + + def initialize(config, srcroot, objroot) + @config = config + @srcdir = File.expand_path(srcroot) + @objdir = File.expand_path(objroot) + @currdir = '.' + end + + def inspect + "#<#{self.class} #{File.basename(@srcdir)}>" + end + + def noop(rel) + end + + # + # Hook Script API base methods + # + + def srcdir_root + @srcdir + end + + def objdir_root + @objdir + end + + def relpath + @currdir + end + + # + # Config Access + # + + # module FileOperations requires this + def verbose? + @config.verbose? + end + + # module FileOperations requires this + def no_harm? + @config.no_harm? + end + + def verbose_off + begin + save, @config.verbose = @config.verbose?, false + yield + ensure + @config.verbose = save + end + end + + # + # TASK config + # + + def exec_config + exec_task_traverse 'config' + end + + alias config_dir_bin noop + alias config_dir_lib noop + + def config_dir_ext(rel) + extconf if extdir?(curr_srcdir()) + end + + alias config_dir_data noop + alias config_dir_conf noop + alias config_dir_man noop + + def extconf + ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt + end + + # + # TASK setup + # + + def exec_setup + exec_task_traverse 'setup' + end + + def setup_dir_bin(rel) + files_of(curr_srcdir()).each do |fname| + update_shebang_line "#{curr_srcdir()}/#{fname}" + end + end + + alias setup_dir_lib noop + + def setup_dir_ext(rel) + make if extdir?(curr_srcdir()) + end + + alias setup_dir_data noop + alias setup_dir_conf noop + alias setup_dir_man noop + + def update_shebang_line(path) + return if no_harm? + return if config('shebang') == 'never' + old = Shebang.load(path) + if old + $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 + new = new_shebang(old) + return if new.to_s == old.to_s + else + return unless config('shebang') == 'all' + new = Shebang.new(config('rubypath')) + end + $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? + open_atomic_writer(path) {|output| + File.open(path, 'rb') {|f| + f.gets if old # discard + output.puts new.to_s + output.print f.read + } + } + end + + def new_shebang(old) + if /\Aruby/ =~ File.basename(old.cmd) + Shebang.new(config('rubypath'), old.args) + elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' + Shebang.new(config('rubypath'), old.args[1..-1]) + else + return old unless config('shebang') == 'all' + Shebang.new(config('rubypath')) + end + end + + def open_atomic_writer(path, &block) + tmpfile = File.basename(path) + '.tmp' + begin + File.open(tmpfile, 'wb', &block) + File.rename tmpfile, File.basename(path) + ensure + File.unlink tmpfile if File.exist?(tmpfile) + end + end + + class Shebang + def Shebang.load(path) + line = nil + File.open(path) {|f| + line = f.gets + } + return nil unless /\A#!/ =~ line + parse(line) + end + + def Shebang.parse(line) + cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') + new(cmd, args) + end + + def initialize(cmd, args = []) + @cmd = cmd + @args = args + end + + attr_reader :cmd + attr_reader :args + + def to_s + "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") + end + end + + # + # TASK install + # + + def exec_install + rm_f 'InstalledFiles' + exec_task_traverse 'install' + end + + def install_dir_bin(rel) + install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 + end + + def install_dir_lib(rel) + install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 + end + + def install_dir_ext(rel) + return unless extdir?(curr_srcdir()) + install_files rubyextentions('.'), + "#{config('sodir')}/#{File.dirname(rel)}", + 0555 + end + + def install_dir_data(rel) + install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 + end + + def install_dir_conf(rel) + # FIXME: should not remove current config files + # (rename previous file to .old/.org) + install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 + end + + def install_dir_man(rel) + install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 + end + + def install_files(list, dest, mode) + mkdir_p dest, @config.install_prefix + list.each do |fname| + install fname, dest, mode, @config.install_prefix + end + end + + def libfiles + glob_reject(%w(*.y *.output), targetfiles()) + end + + def rubyextentions(dir) + ents = glob_select("*.#{@config.dllext}", targetfiles()) + if ents.empty? + setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" + end + ents + end + + def targetfiles + mapdir(existfiles() - hookfiles()) + end + + def mapdir(ents) + ents.map {|ent| + if File.exist?(ent) + then ent # objdir + else "#{curr_srcdir()}/#{ent}" # srcdir + end + } + end + + # picked up many entries from cvs-1.11.1/src/ignore.c + JUNK_FILES = %w( + core RCSLOG tags TAGS .make.state + .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb + *~ *.old *.bak *.BAK *.orig *.rej _$* *$ + + *.org *.in .* + ) + + def existfiles + glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) + end + + def hookfiles + %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| + %w( config setup install clean ).map {|t| sprintf(fmt, t) } + }.flatten + end + + def glob_select(pat, ents) + re = globs2re([pat]) + ents.select {|ent| re =~ ent } + end + + def glob_reject(pats, ents) + re = globs2re(pats) + ents.reject {|ent| re =~ ent } + end + + GLOB2REGEX = { + '.' => '\.', + '$' => '\$', + '#' => '\#', + '*' => '.*' + } + + def globs2re(pats) + /\A(?:#{ + pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') + })\z/ + end + + # + # TASK test + # + + TESTDIR = 'test' + + def exec_test + unless File.directory?('test') + $stderr.puts 'no test in this package' if verbose? + return + end + $stderr.puts 'Running tests...' if verbose? + begin + require 'test/unit' + rescue LoadError + setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' + end + runner = Test::Unit::AutoRunner.new(true) + runner.to_run << TESTDIR + runner.run + end + + # + # TASK clean + # + + def exec_clean + exec_task_traverse 'clean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias clean_dir_bin noop + alias clean_dir_lib noop + alias clean_dir_data noop + alias clean_dir_conf noop + alias clean_dir_man noop + + def clean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'clean' if File.file?('Makefile') + end + + # + # TASK distclean + # + + def exec_distclean + exec_task_traverse 'distclean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias distclean_dir_bin noop + alias distclean_dir_lib noop + + def distclean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'distclean' if File.file?('Makefile') + end + + alias distclean_dir_data noop + alias distclean_dir_conf noop + alias distclean_dir_man noop + + # + # Traversing + # + + def exec_task_traverse(task) + run_hook "pre-#{task}" + FILETYPES.each do |type| + if type == 'ext' and config('without-ext') == 'yes' + $stderr.puts 'skipping ext/* by user option' if verbose? + next + end + traverse task, type, "#{task}_dir_#{type}" + end + run_hook "post-#{task}" + end + + def traverse(task, rel, mid) + dive_into(rel) { + run_hook "pre-#{task}" + __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') + directories_of(curr_srcdir()).each do |d| + traverse task, "#{rel}/#{d}", mid + end + run_hook "post-#{task}" + } + end + + def dive_into(rel) + return unless File.dir?("#{@srcdir}/#{rel}") + + dir = File.basename(rel) + Dir.mkdir dir unless File.dir?(dir) + prevdir = Dir.pwd + Dir.chdir dir + $stderr.puts '---> ' + rel if verbose? + @currdir = rel + yield + Dir.chdir prevdir + $stderr.puts '<--- ' + rel if verbose? + @currdir = File.dirname(rel) + end + + def run_hook(id) + path = [ "#{curr_srcdir()}/#{id}", + "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } + return unless path + begin + instance_eval File.read(path), path, 1 + rescue + raise if $DEBUG + setup_rb_error "hook #{path} failed:\n" + $!.message + end + end + +end # class Installer + + +class SetupError < StandardError; end + +def setup_rb_error(msg) + raise SetupError, msg +end + +if $0 == __FILE__ + begin + ToplevelInstaller.invoke + rescue SetupError + raise if $DEBUG + $stderr.puts $!.message + $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." + exit 1 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1c/1c54dc3cdf978b1fe38453669a82173306d7c28a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1c/1c54dc3cdf978b1fe38453669a82173306d7c28a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,94 @@ +body, #wrapper { direction: rtl;} + +#quick-search { float: left; } +#main-menu { margin-left: -500px; left: auto; right: 6px; margin-right: 0px;} +#main-menu li { float: right; } +#top-menu ul { float: right; } +#account { float: left; } +#top-menu #loggedas { float: left; } +#top-menu li { float: right; } +.tabular label.floating +{ + margin-right: 0; + margin-left: auto; + text-align: right; +} +.tabular label +{ + float: right; + margin-left: auto; +} +.tabular p +{ + clear: right; +} +.tabular label.block { text-align: right; } +.icon +{ + background-position: 100% 40%; + padding-right: 20px; + padding-left: 0px; +} +div#activity dt, #search-results dt +{ + background-position: 100% 50%; + padding-right: 20px; + padding-left: 0px; +} +#content .tabs ul li { float: right; } +#content .tabs ul { padding-left: auto; padding-right: 1em; } +table.progress { float: right; } +.contextual { float: left; } +.icon22 { background-position: 100% 40%; padding-right: 26px; padding-left: auto; } +h3, .wiki h2 { padding: 10px 2px 1px 0; } +.tooltip span.tip { text-align: right; } +tr.issue td.subject { text-align: right; } +tr.time-entry td.subject, tr.time-entry td.comments { text-align: right; } +#sidebar { float: left; } +#main.nosidebar #content { border-width: 1px; border-style: solid; border-color: #D7D7D7 #BBBBBB #BBBBBB #D7D7D7;} +.tabular.settings label { margin-left: auto; } +.splitcontentleft { float: right; } +.splitcontentright { float: left; } +p.progress-info { clear: right; } +table.list td.buttons a { padding-right: 20px; } +.filecontent { direction: ltr; } +.entries { direction: ltr; } +.changeset-changes { direction: ltr; padding-left: 2em } +.changesets { direction: ltr; } +div#issue-changesets { float: left; margin-right: 1em; margin-left: 0 } +div#issue-changesets div.wiki { direction: ltr; padding-left: 2em } +#activity dt, .journal { clear: right; } +.journal-link { float: left; } +div.wiki pre { direction: ltr; } + +ul.projects { padding-right: 1em; padding-left: 0; } +ul.projects ul.projects { border-right: 3px solid #e0e0e0; border-left: 0; } +.my-project { padding-right: 18px; padding-left: 0; background-position: 100% 50%; } + +#admin-menu a { background-position: 100% 40%; padding-right: 20px; padding-left: 0;} +input#openid_url { background-position: 100% 50%; padding-right: 18px; padding-left: 0; } + +tr.project.idnt td.name span { background: url(../images/bullet_arrow_left.png) no-repeat 100% 50%; padding-right: 16px; padding-left: 0; } +tr.project.idnt-1 td.name { padding-right: 0.5em; } +tr.project.idnt-2 td.name { padding-right: 2em; } +tr.project.idnt-3 td.name { padding-right: 3.5em; } +tr.project.idnt-4 td.name { padding-right: 5em; } +tr.project.idnt-5 td.name { padding-right: 6.5em; } +tr.project.idnt-6 td.name { padding-right: 8em; } +tr.project.idnt-7 td.name { padding-right: 9.5em; } +tr.project.idnt-8 td.name { padding-right: 11em; } +tr.project.idnt-9 td.name { padding-right: 12.5em; } + +tr.issue.idnt td.subject a { background: url(../images/bullet_arrow_left.png) no-repeat 100% 50%; padding-right: 16px; padding-left: 0; } +tr.issue.idnt-1 td.subject { padding-right: 0.5em; } +tr.issue.idnt-2 td.subject { padding-right: 2em; } +tr.issue.idnt-3 td.subject { padding-right: 3.5em; } +tr.issue.idnt-4 td.subject { padding-right: 5em; } +tr.issue.idnt-5 td.subject { padding-right: 6.5em; } +tr.issue.idnt-6 td.subject { padding-right: 8em; } +tr.issue.idnt-7 td.subject { padding-right: 9.5em; } +tr.issue.idnt-8 td.subject { padding-right: 11em; } +tr.issue.idnt-9 td.subject { padding-right: 12.5em; } + +div.wiki ul.toc { margin-right: 0; margin-left: 12px; } +div.wiki ul.toc li li { margin-right: 1.5em; margin-left: 0; } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1c/1c96e8748cd2bab0b547b070c39e7264886284c8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1c/1c96e8748cd2bab0b547b070c39e7264886284c8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddActiveFieldToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :active, :boolean, :default => true, :null => false + end + + def self.down + remove_column :enumerations, :active + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d27e55302983310e1f42ffc59d4c81eba90edc6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d27e55302983310e1f42ffc59d4c81eba90edc6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar ES (spanish) language +// Author: Mihai Bazon, +// Updater: Servilio Afre Puentes +// Updated: 2004-06-03 +// Encoding: utf-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Lunes", + "Martes", + "Miércoles", + "Jueves", + "Viernes", + "Sábado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Lun", + "Mar", + "Mié", + "Jue", + "Vie", + "Sáb", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Enero", + "Febrero", + "Marzo", + "Abril", + "Mayo", + "Junio", + "Julio", + "Agosto", + "Septiembre", + "Octubre", + "Noviembre", + "Diciembre"); + +// short month names +Calendar._SMN = new Array +("Ene", + "Feb", + "Mar", + "Abr", + "May", + "Jun", + "Jul", + "Ago", + "Sep", + "Oct", + "Nov", + "Dic"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Acerca del calendario"; + +Calendar._TT["ABOUT"] = +"Selector DHTML de Fecha/Hora\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Para conseguir la última versión visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuido bajo licencia GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para más detalles." + +"\n\n" + +"Selección de fecha:\n" + +"- Use los botones \xab, \xbb para seleccionar el año\n" + +"- Use los botones " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar el mes\n" + +"- Mantenga pulsado el ratón en cualquiera de estos botones para una selección rápida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selección de hora:\n" + +"- Pulse en cualquiera de las partes de la hora para incrementarla\n" + +"- o pulse las mayúsculas mientras hace clic para decrementarla\n" + +"- o haga clic y arrastre el ratón para una selección más rápida."; + +Calendar._TT["PREV_YEAR"] = "Año anterior (mantener para menú)"; +Calendar._TT["PREV_MONTH"] = "Mes anterior (mantener para menú)"; +Calendar._TT["GO_TODAY"] = "Ir a hoy"; +Calendar._TT["NEXT_MONTH"] = "Mes siguiente (mantener para menú)"; +Calendar._TT["NEXT_YEAR"] = "Año siguiente (mantener para menú)"; +Calendar._TT["SEL_DATE"] = "Seleccionar fecha"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar para mover"; +Calendar._TT["PART_TODAY"] = " (hoy)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Hacer %s primer día de la semana"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Cerrar"; +Calendar._TT["TODAY"] = "Hoy"; +Calendar._TT["TIME_PART"] = "(Mayúscula-)Clic o arrastre para cambiar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; + +Calendar._TT["WK"] = "sem"; +Calendar._TT["TIME"] = "Hora:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d4501e489efd6d8ed1d23023b3b3b28fa284bd3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d4501e489efd6d8ed1d23023b3b3b28fa284bd3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +class AddIssuesNestedSetsColumns < ActiveRecord::Migration + def self.up + add_column :issues, :parent_id, :integer, :default => nil + add_column :issues, :root_id, :integer, :default => nil + add_column :issues, :lft, :integer, :default => nil + add_column :issues, :rgt, :integer, :default => nil + + Issue.update_all("parent_id = NULL, root_id = id, lft = 1, rgt = 2") + end + + def self.down + remove_column :issues, :parent_id + remove_column :issues, :root_id + remove_column :issues, :lft + remove_column :issues, :rgt + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d511a07201f732ef6d8b4edd5fe52d3844b42ce.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d511a07201f732ef6d8b4edd5fe52d3844b42ce.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/destroy' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d53493a3b6f86fc88f7ad446a14e1fb98681f83.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d53493a3b6f86fc88f7ad446a14e1fb98681f83.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ += Net::LDAP Changelog + +== Net::LDAP 0.0.4: August 15, 2006 +* Undeprecated Net::LDAP#modify. Thanks to Justin Forder for + providing the rationale for this. +* Added a much-expanded set of special characters to the parser + for RFC-2254 filters. Thanks to Andre Nathan. +* Changed Net::LDAP#search so you can pass it a filter in string form. + The conversion to a Net::LDAP::Filter now happens automatically. +* Implemented Net::LDAP#bind_as (preliminary and subject to change). + Thanks for Simon Claret for valuable suggestions and for helping test. +* Fixed bug in Net::LDAP#open that was preventing #open from being + called more than one on a given Net::LDAP object. + +== Net::LDAP 0.0.3: July 26, 2006 +* Added simple TLS encryption. + Thanks to Garett Shulman for suggestions and for helping test. + +== Net::LDAP 0.0.2: July 12, 2006 +* Fixed malformation in distro tarball and gem. +* Improved documentation. +* Supported "paged search control." +* Added a range of API improvements. +* Thanks to Andre Nathan, andre@digirati.com.br, for valuable + suggestions. +* Added support for LE and GE search filters. +* Added support for Search referrals. +* Fixed a regression with openldap 2.2.x and higher caused + by the introduction of RFC-2696 controls. Thanks to Andre + Nathan for reporting the problem. +* Added support for RFC-2254 filter syntax. + +== Net::LDAP 0.0.1: May 1, 2006 +* Initial release. +* Client functionality is near-complete, although the APIs + are not guaranteed and may change depending on feedback + from the community. +* We're internally working on a Ruby-based implementation + of a full-featured, production-quality LDAP server, + which will leverage the underlying LDAP and BER functionality + in Net::LDAP. +* Please tell us if you would be interested in seeing a public + release of the LDAP server. +* Grateful acknowledgement to Austin Ziegler, who reviewed + this code and provided the release framework, including + minitar. + +#-- +# Net::LDAP for Ruby. +# http://rubyforge.org/projects/net-ldap/ +# Copyright (C) 2006 by Francis Cianfrocca +# +# Available under the same terms as Ruby. See LICENCE in the main +# distribution for full licensing information. +# +# $Id: ChangeLog,v 1.17.2.4 2005/09/09 12:36:42 austin Exp $ +#++ +# vim: sts=2 sw=2 ts=4 et ai tw=77 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d5de2a1ef017a12eb407c0c43e77ba879705fe3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d5de2a1ef017a12eb407c0c43e77ba879705fe3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,509 @@ +module CodeRay +module Scanners + + load :html + + # Scanner for PHP. + # + # Original by Stefan Walk. + class PHP < Scanner + + register_for :php + file_extension 'php' + encoding 'BINARY' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + protected + + def setup + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true + end + + def reset_instance + super + @html_scanner.reset + end + + module Words # :nodoc: + + # according to http://www.php.net/manual/en/reserved.keywords.php + KEYWORDS = %w[ + abstract and array as break case catch class clone const continue declare default do else elseif + enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global + goto if implements interface instanceof namespace new or private protected public static switch + throw try use var while xor + cfunction old_function + ] + + TYPES = %w[ int integer float double bool boolean string array object resource ] + + LANGUAGE_CONSTRUCTS = %w[ + die echo empty exit eval include include_once isset list + require require_once return print unset + ] + + CLASSES = %w[ Directory stdClass __PHP_Incomplete_Class exception php_user_filter Closure ] + + # according to http://php.net/quickref.php on 2009-04-21; + # all functions with _ excluded (module functions) and selected additional functions + BUILTIN_FUNCTIONS = %w[ + abs acos acosh addcslashes addslashes aggregate array arsort ascii2ebcdic asin asinh asort assert atan atan2 + atanh basename bcadd bccomp bcdiv bcmod bcmul bcpow bcpowmod bcscale bcsqrt bcsub bin2hex bindec + bindtextdomain bzclose bzcompress bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite + calculhmac ceil chdir checkdate checkdnsrr chgrp chmod chop chown chr chroot clearstatcache closedir closelog + compact constant copy cos cosh count crc32 crypt current date dcgettext dcngettext deaggregate decbin dechex + decoct define defined deg2rad delete dgettext die dirname diskfreespace dl dngettext doubleval each + ebcdic2ascii echo empty end ereg eregi escapeshellarg escapeshellcmd eval exec exit exp explode expm1 extract + fclose feof fflush fgetc fgetcsv fgets fgetss file fileatime filectime filegroup fileinode filemtime fileowner + fileperms filepro filesize filetype floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv + fputs fread frenchtojd fscanf fseek fsockopen fstat ftell ftok ftruncate fwrite getallheaders getcwd getdate + getenv gethostbyaddr gethostbyname gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid + getmyuid getopt getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext + gettimeofday gettype glob gmdate gmmktime gmstrftime gregoriantojd gzclose gzcompress gzdecode gzdeflate + gzencode gzeof gzfile gzgetc gzgets gzgetss gzinflate gzopen gzpassthru gzputs gzread gzrewind gzseek gztell + gzuncompress gzwrite hash header hebrev hebrevc hexdec htmlentities htmlspecialchars hypot iconv idate + implode include intval ip2long iptcembed iptcparse isset + jddayofweek jdmonthname jdtofrench jdtogregorian jdtojewish jdtojulian jdtounix jewishtojd join jpeg2wbmp + juliantojd key krsort ksort lcfirst lchgrp lchown levenshtein link linkinfo list localeconv localtime log + log10 log1p long2ip lstat ltrim mail main max md5 metaphone mhash microtime min mkdir mktime msql natcasesort + natsort next ngettext nl2br nthmac octdec opendir openlog + ord overload pack passthru pathinfo pclose pfsockopen phpcredits phpinfo phpversion pi png2wbmp popen pos pow + prev print printf putenv quotemeta rad2deg rand range rawurldecode rawurlencode readdir readfile readgzfile + readline readlink realpath recode rename require reset rewind rewinddir rmdir round rsort rtrim scandir + serialize setcookie setlocale setrawcookie settype sha1 shuffle signeurlpaiement sin sinh sizeof sleep snmpget + snmpgetnext snmprealwalk snmpset snmpwalk snmpwalkoid sort soundex split spliti sprintf sqrt srand sscanf stat + strcasecmp strchr strcmp strcoll strcspn strftime stripcslashes stripos stripslashes stristr strlen + strnatcasecmp strnatcmp strncasecmp strncmp strpbrk strpos strptime strrchr strrev strripos strrpos strspn + strstr strtok strtolower strtotime strtoupper strtr strval substr symlink syslog system tan tanh tempnam + textdomain time tmpfile touch trim uasort ucfirst ucwords uksort umask uniqid unixtojd unlink unpack + unserialize unset urldecode urlencode usleep usort vfprintf virtual vprintf vsprintf wordwrap + array_change_key_case array_chunk array_combine array_count_values array_diff array_diff_assoc + array_diff_key array_diff_uassoc array_diff_ukey array_fill array_fill_keys array_filter array_flip + array_intersect array_intersect_assoc array_intersect_key array_intersect_uassoc array_intersect_ukey + array_key_exists array_keys array_map array_merge array_merge_recursive array_multisort array_pad + array_pop array_product array_push array_rand array_reduce array_reverse array_search array_shift + array_slice array_splice array_sum array_udiff array_udiff_assoc array_udiff_uassoc array_uintersect + array_uintersect_assoc array_uintersect_uassoc array_unique array_unshift array_values array_walk + array_walk_recursive + assert_options base_convert base64_decode base64_encode + chunk_split class_exists class_implements class_parents + count_chars debug_backtrace debug_print_backtrace debug_zval_dump + error_get_last error_log error_reporting extension_loaded + file_exists file_get_contents file_put_contents load_file + func_get_arg func_get_args func_num_args function_exists + get_browser get_called_class get_cfg_var get_class get_class_methods get_class_vars + get_current_user get_declared_classes get_declared_interfaces get_defined_constants + get_defined_functions get_defined_vars get_extension_funcs get_headers get_html_translation_table + get_include_path get_included_files get_loaded_extensions get_magic_quotes_gpc get_magic_quotes_runtime + get_meta_tags get_object_vars get_parent_class get_required_filesget_resource_type + gc_collect_cycles gc_disable gc_enable gc_enabled + halt_compiler headers_list headers_sent highlight_file highlight_string + html_entity_decode htmlspecialchars_decode + in_array include_once inclued_get_data + is_a is_array is_binary is_bool is_buffer is_callable is_dir is_double is_executable is_file is_finite + is_float is_infinite is_int is_integer is_link is_long is_nan is_null is_numeric is_object is_readable + is_real is_resource is_scalar is_soap_fault is_string is_subclass_of is_unicode is_uploaded_file + is_writable is_writeable + locale_get_default locale_set_default + number_format override_function parse_str parse_url + php_check_syntax php_ini_loaded_file php_ini_scanned_files php_logo_guid php_sapi_name + php_strip_whitespace php_uname + preg_filter preg_grep preg_last_error preg_match preg_match_all preg_quote preg_replace + preg_replace_callback preg_split print_r + require_once register_shutdown_function register_tick_function + set_error_handler set_exception_handler set_file_buffer set_include_path + set_magic_quotes_runtime set_time_limit shell_exec + str_getcsv str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split str_word_count + strip_tags substr_compare substr_count substr_replace + time_nanosleep time_sleep_until + token_get_all token_name trigger_error + unregister_tick_function use_soap_error_handler user_error + utf8_decode utf8_encode var_dump var_export + version_compare + zend_logo_guid zend_thread_id zend_version + create_function call_user_func_array + posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid + posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups + posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid + posix_getpwnam posix_getpwuid posix_getrlimit posix_getsid posix_getuid + posix_initgroups posix_isatty posix_kill posix_mkfifo posix_mknod + posix_setegid posix_seteuid posix_setgid posix_setpgid posix_setsid + posix_setuid posix_strerror posix_times posix_ttyname posix_uname + pcntl_alarm pcntl_exec pcntl_fork pcntl_getpriority pcntl_setpriority + pcntl_signal pcntl_signal_dispatch pcntl_sigprocmask pcntl_sigtimedwait + pcntl_sigwaitinfo pcntl_wait pcntl_waitpid pcntl_wexitstatus pcntl_wifexited + pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig + ] + # TODO: more built-in PHP functions? + + EXCEPTIONS = %w[ + E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING + E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT + ] + + CONSTANTS = %w[ + null true false self parent + __LINE__ __DIR__ __FILE__ __LINE__ + __CLASS__ __NAMESPACE__ __METHOD__ __FUNCTION__ + PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION PHP_ZTS + PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_SIZE DEFAULT_INCLUDE_PATH + PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_LIBDIR PHP_DATADIR + PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX + PHP_OUTPUT_HANDLER_START PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END + __COMPILER_HALT_OFFSET__ + EXTR_OVERWRITE EXTR_SKIP EXTR_PREFIX_SAME EXTR_PREFIX_ALL EXTR_PREFIX_INVALID EXTR_PREFIX_IF_EXISTS + EXTR_IF_EXISTS SORT_ASC SORT_DESC SORT_REGULAR SORT_NUMERIC SORT_STRING CASE_LOWER CASE_UPPER COUNT_NORMAL + COUNT_RECURSIVE ASSERT_ACTIVE ASSERT_CALLBACK ASSERT_BAIL ASSERT_WARNING ASSERT_QUIET_EVAL CONNECTION_ABORTED + CONNECTION_NORMAL CONNECTION_TIMEOUT INI_USER INI_PERDIR INI_SYSTEM INI_ALL M_E M_LOG2E M_LOG10E M_LN2 M_LN10 + M_PI M_PI_2 M_PI_4 M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2 CRYPT_SALT_LENGTH CRYPT_STD_DES CRYPT_EXT_DES + CRYPT_MD5 CRYPT_BLOWFISH DIRECTORY_SEPARATOR SEEK_SET SEEK_CUR SEEK_END LOCK_SH LOCK_EX LOCK_UN LOCK_NB + HTML_SPECIALCHARS HTML_ENTITIES ENT_COMPAT ENT_QUOTES ENT_NOQUOTES INFO_GENERAL INFO_CREDITS + INFO_CONFIGURATION INFO_MODULES INFO_ENVIRONMENT INFO_VARIABLES INFO_LICENSE INFO_ALL CREDITS_GROUP + CREDITS_GENERAL CREDITS_SAPI CREDITS_MODULES CREDITS_DOCS CREDITS_FULLPAGE CREDITS_QA CREDITS_ALL STR_PAD_LEFT + STR_PAD_RIGHT STR_PAD_BOTH PATHINFO_DIRNAME PATHINFO_BASENAME PATHINFO_EXTENSION PATH_SEPARATOR CHAR_MAX + LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_ALL LC_MESSAGES ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 + ABDAY_6 ABDAY_7 DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 ABMON_1 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 + ABMON_7 ABMON_8 ABMON_9 ABMON_10 ABMON_11 ABMON_12 MON_1 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 + MON_10 MON_11 MON_12 AM_STR PM_STR D_T_FMT D_FMT T_FMT T_FMT_AMPM ERA ERA_YEAR ERA_D_T_FMT ERA_D_FMT ERA_T_FMT + ALT_DIGITS INT_CURR_SYMBOL CURRENCY_SYMBOL CRNCYSTR MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING + POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES + N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN DECIMAL_POINT RADIXCHAR THOUSANDS_SEP THOUSEP GROUPING YESEXPR NOEXPR + YESSTR NOSTR CODESET LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG LOG_KERN + LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_LOCAL0 + LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_PID LOG_CONS LOG_ODELAY + LOG_NDELAY LOG_NOWAIT LOG_PERROR + ] + + PREDEFINED = %w[ + $GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV + $_COOKIE $php_errormsg $HTTP_RAW_POST_DATA $http_response_header + $argc $argv + ] + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(TYPES, :predefined_type). + add(LANGUAGE_CONSTRUCTS, :keyword). + add(BUILTIN_FUNCTIONS, :predefined). + add(CLASSES, :predefined_constant). + add(EXCEPTIONS, :exception). + add(CONSTANTS, :predefined_constant) + + VARIABLE_KIND = WordList.new(:local_variable). + add(PREDEFINED, :predefined) + end + + module RE # :nodoc: + + PHP_START = / + ]*?language\s*=\s*"php"[^>]*?> | + ]*?language\s*=\s*'php'[^>]*?> | + <\?php\d? | + <\?(?!xml) + /xi + + PHP_END = %r! + | + \?> + !xi + + HTML_INDICATOR = / ]/i + + IDENTIFIER = /[a-z_\x7f-\xFF][a-z0-9_\x7f-\xFF]*/i + VARIABLE = /\$#{IDENTIFIER}/ + + OPERATOR = / + \.(?!\d)=? | # dot that is not decimal point, string concatenation + && | \|\| | # logic + :: | -> | => | # scope, member, dictionary + \\(?!\n) | # namespace + \+\+ | -- | # increment, decrement + [,;?:()\[\]{}] | # simple delimiters + [-+*\/%&|^]=? | # ordinary math, binary logic, assignment shortcuts + [~$] | # whatever + =& | # reference assignment + [=!]=?=? | <> | # comparison and assignment + <<=? | >>=? | [<>]=? # comparison and shift + /x + + end + + protected + + def scan_tokens encoder, options + + if check(RE::PHP_START) || # starts with #{RE::IDENTIFIER}/o) + encoder.begin_group :inline + encoder.text_token match, :local_variable + encoder.text_token scan(/->/), :operator + encoder.text_token scan(/#{RE::IDENTIFIER}/o), :ident + encoder.end_group :inline + elsif check(/->/) + match << scan(/->/) + encoder.text_token match, :error + else + encoder.text_token match, :local_variable + end + elsif match = scan(/\{/) + if check(/\$/) + encoder.begin_group :inline + states[-1] = [states.last, delimiter] + delimiter = nil + states.push :php + encoder.text_token match, :delimiter + else + encoder.text_token match, :content + end + elsif match = scan(/\$\{#{RE::IDENTIFIER}\}/o) + encoder.text_token match, :local_variable + elsif match = scan(/\$/) + encoder.text_token match, :content + else + states.pop + end + + when :class_expected + if match = scan(/\s+/) + encoder.text_token match, :space + elsif match = scan(/#{RE::IDENTIFIER}/o) + encoder.text_token match, :class + states.pop + else + states.pop + end + + when :function_expected + if match = scan(/\s+/) + encoder.text_token match, :space + elsif match = scan(/&/) + encoder.text_token match, :operator + elsif match = scan(/#{RE::IDENTIFIER}/o) + encoder.text_token match, :function + states.pop + else + states.pop + end + + else + raise_inspect 'Unknown state!', encoder, states + end + + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d7df9d1ff373f2acfb6f78a21a20fbfce6e12d2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d7df9d1ff373f2acfb6f78a21a20fbfce6e12d2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +Index: trunk/app/controllers/issues_controller.rb +=================================================================== +--- trunk/app/controllers/issues_controller.rb (révision 1483) ++++ trunk/app/controllers/issues_controller.rb (révision 1484) +@@ -149,7 +149,7 @@ + attach_files(@issue, params[:attachments]) + flash[:notice] = 'Demande créée avec succès' + Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added') +- redirect_to :controller => 'issues', :action => 'show', :id => @issue, :project_id => @project ++ redirect_to :controller => 'issues', :action => 'show', :id => @issue + return + end + end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1d/1d952075666a23da2dea08dd30f78ec9dfb67366.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1d/1d952075666a23da2dea08dd30f78ec9dfb67366.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +api.array :issue_statuses do + @issue_statuses.each do |status| + api.issue_status do + api.id status.id + api.name status.name + api.is_default status.is_default + api.is_closed status.is_closed + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1e1c56f7bb0dfd476519c5d677856963c19b1ee5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1e1c56f7bb0dfd476519c5d677856963c19b1ee5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToWikiPages < ActiveRecord::Migration + def self.up + add_index :wiki_pages, :wiki_id + add_index :wiki_pages, :parent_id + end + + def self.down + remove_index :wiki_pages, :wiki_id + remove_index :wiki_pages, :parent_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1e2449c4fd0e3e6354042c9b7f5d7df6cbbaf256.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1e2449c4fd0e3e6354042c9b7f5d7df6cbbaf256.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +--- +news_001: + created_on: 2006-07-19 22:40:26 +02:00 + project_id: 1 + title: eCookbook first release ! + id: 1 + description: |- + eCookbook 1.0 has been released. + + Visit http://ecookbook.somenet.foo/ + summary: First version was released... + author_id: 2 + comments_count: 1 +news_002: + created_on: 2006-07-19 22:42:58 +02:00 + project_id: 1 + title: 100,000 downloads for eCookbook + id: 2 + description: eCookbook 1.0 have downloaded 100,000 times + summary: eCookbook 1.0 have downloaded 100,000 times + author_id: 2 + comments_count: 0 +news_003: + created_on: 2006-07-19 22:42:58 +02:00 + project_id: 2 + title: News on a private project + id: 3 + description: This is a private news + summary: + author_id: 2 + comments_count: 0 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1e483084ac442168a4ba45984a0f145a415a7cad.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1e483084ac442168a4ba45984a0f145a415a7cad.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class DocumentObserver < ActiveRecord::Observer + def after_create(document) + Mailer.deliver_document_added(document) if Setting.notified_events.include?('document_added') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1e6be947d792b95e6881bfbd4ea45738a1aaae9e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1e6be947d792b95e6881bfbd4ea45738a1aaae9e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +# Tests in this file ensure that: +# +# * the application /app/[controllers|helpers|models] and /lib +# paths preceed the corresponding plugin paths +# * the plugin paths are added to $LOAD_PATH in the order in which plugins are +# loaded + +require File.dirname(__FILE__) + '/../test_helper' + +class LoadPathTest < Test::Unit::TestCase + def setup + @load_path = expand_paths($LOAD_PATH) + end + + # Not sure if these test actually make sense as this now essentially tests + # Rails core functionality. On the other hand Engines relies on this to some + # extend so this will choke if something important changes in Rails. + + # the application app/... and lib/ directories should appear + # before any plugin directories + + def test_application_app_libs_should_precede_all_plugin_app_libs + types = %w(app/controllers app/helpers app/models lib) + types.each do |t| + app_index = load_path_index(File.join(RAILS_ROOT, t)) + assert_not_nil app_index, "#{t} is missing in $LOAD_PATH" + Engines.plugins.each do |plugin| + first_plugin_index = load_path_index(File.join(plugin.directory, t)) + assert(app_index < first_plugin_index) unless first_plugin_index.nil? + end + end + end + + # the engine directories should appear in the proper order based on + # the order they were started + + def test_plugin_dirs_should_appear_in_reverse_plugin_loading_order + app_paths = %w(app/controllers/ app app/models app/helpers lib) + app_paths.map { |p| File.join(RAILS_ROOT, p)} + plugin_paths = Engines.plugins.reverse.collect { |plugin| plugin.load_paths.reverse }.flatten + + expected_paths = expand_paths(app_paths + plugin_paths) + # only look at those paths that are also present in expected_paths so + # the only difference would be in the order of the paths + actual_paths = @load_path & expected_paths + + assert_equal expected_paths, actual_paths + end + + protected + def expand_paths(paths) + paths.collect { |p| File.expand_path(p) } + end + + def load_path_index(dir) + @load_path.index(File.expand_path(dir)) + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1eb877098762b00295b58cbc0f60b9348d2b88a3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1eb877098762b00295b58cbc0f60b9348d2b88a3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +<%= link_to h(@added_to), @added_to_url %>
+ +
    <% @attachments.each do |attachment | %> +
  • <%=h attachment.filename %>
  • +<% end %>
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1ee7b5168bf92e876c9f4c10698beed4d4ba3f9d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1ee7b5168bf92e876c9f4c10698beed4d4ba3f9d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1011 @@ +fa: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: rtl + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [یک‌شنبه, دوشنبه, سه‌شنبه, چهارشنبه, پنج‌شنبه, آدینه, شنبه] + abbr_day_names: [یک, دو, سه, چهار, پنج, آدینه, شنبه] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, ژانویه, فوریه, مارس, آوریل, مه, ژوئن, ژوئیه, اوت, سپتامبر, اکتبر, نوامبر, دسامبر] + abbr_month_names: [~, ژان, فور, مار, آور, مه, ژوئن, ژوئیه, اوت, سپت, اکت, نوا, دسا] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d - %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B %Y ساعت %H:%M" + am: "صبح" + pm: "عصر" + + datetime: + distance_in_words: + half_a_minute: "نیم دقیقه" + less_than_x_seconds: + one: "کمتر از 1 ثانیه" + other: "کمتر از %{count} ثانیه" + x_seconds: + one: "1 ثانیه" + other: "%{count} ثانیه" + less_than_x_minutes: + one: "کمتر از 1 دقیقه" + other: "کمتر از %{count} دقیقه" + x_minutes: + one: "1 دقیقه" + other: "%{count} دقیقه" + about_x_hours: + one: "نزدیک 1 ساعت" + other: "نزدیک %{count} ساعت" + x_days: + one: "1 روز" + other: "%{count} روز" + about_x_months: + one: "نزدیک 1 ماه" + other: "نزدیک %{count} ماه" + x_months: + one: "1 ماه" + other: "%{count} ماه" + about_x_years: + one: "نزدیک 1 سال" + other: "نزدیک %{count} سال" + over_x_years: + one: "بیش از 1 سال" + other: "بیش از %{count} سال" + almost_x_years: + one: "نزدیک 1 سال" + other: "نزدیک %{count} سال" + + number: + # Default format for numbers + format: + separator: "٫" + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "بایت" + other: "بایت" + kb: "کیلوبایت" + mb: "مگابایت" + gb: "گیگابایت" + tb: "ترابایت" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "و" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 ایراد از ذخیره سازی این %{model} جلوگیری کرد" + other: "%{count} ایراد از ذخیره سازی این %{model} جلوگیری کرد" + messages: + inclusion: "در فهرست نیامده است" + exclusion: "رزرو شده است" + invalid: "نادرست است" + confirmation: "با بررسی سازگاری ندارد" + accepted: "باید پذیرفته شود" + empty: "نمی‌تواند تهی باشد" + blank: "نمی‌تواند تهی باشد" + too_long: "خیلی بلند است (بیشترین اندازه %{count} نویسه است)" + too_short: "خیلی کوتاه است (کمترین اندازه %{count} نویسه است)" + wrong_length: "اندازه نادرست است (باید %{count} نویسه باشد)" + taken: "پیش از این گرفته شده است" + not_a_number: "شماره درستی نیست" + not_a_date: "تاریخ درستی نیست" + greater_than: "باید بزرگتر از %{count} باشد" + greater_than_or_equal_to: "باید بزرگتر از یا برابر با %{count} باشد" + equal_to: "باید برابر با %{count} باشد" + less_than: "باید کمتر از %{count} باشد" + less_than_or_equal_to: "باید کمتر از یا برابر با %{count} باشد" + odd: "باید فرد باشد" + even: "باید زوج باشد" + greater_than_start_date: "باید از تاریخ آغاز بزرگتر باشد" + not_same_project: "به همان پروژه وابسته نیست" + circular_dependency: "این وابستگی یک وابستگی دایره وار خواهد ساخت" + cant_link_an_issue_with_a_descendant: "یک پیامد نمی‌تواند به یکی از زیر کارهایش پیوند بخورد" + + actionview_instancetag_blank_option: گزینش کنید + + general_text_No: 'خیر' + general_text_Yes: 'آری' + general_text_no: 'خیر' + general_text_yes: 'آری' + general_lang_name: 'Persian (پارسی)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '6' + + notice_account_updated: حساب شما بروز شد. + notice_account_invalid_creditentials: نام کاربری یا گذرواژه نادرست است + notice_account_password_updated: گذرواژه بروز شد + notice_account_wrong_password: گذرواژه نادرست است + notice_account_register_done: حساب ساخته شد. برای فعال نمودن آن، روی پیوندی که به شما ایمیل شده کلیک کنید. + notice_account_unknown_email: کاربر شناخته نشد. + notice_can_t_change_password: این حساب یک روش شناسایی بیرونی را به کار گرفته است. گذرواژه را نمی‌توان جایگزین کرد. + notice_account_lost_email_sent: یک ایمیل با راهنمایی درباره گزینش گذرواژه تازه برای شما فرستاده شد. + notice_account_activated: حساب شما فعال شده است. اکنون می‌توانید وارد شوید. + notice_successful_create: با موفقیت ساخته شد. + notice_successful_update: با موفقیت بروز شد. + notice_successful_delete: با موفقیت برداشته شد. + notice_successful_connection: با موفقیت متصل شد. + notice_file_not_found: برگه درخواستی شما در دسترس نیست یا پاک شده است. + notice_locking_conflict: داده‌ها را کاربر دیگری بروز کرده است. + notice_not_authorized: شما به این برگه دسترسی ندارید. + notice_not_authorized_archived_project: پروژه درخواستی شما بایگانی شده است. + notice_email_sent: "یک ایمیل به %{value} فرستاده شد." + notice_email_error: "یک ایراد در فرستادن ایمیل پیش آمد (%{value})." + notice_feeds_access_key_reseted: کلید دسترسی RSS شما بازنشانی شد. + notice_api_access_key_reseted: کلید دسترسی API شما بازنشانی شد. + notice_failed_to_save_issues: "ذخیره سازی %{count} پیامد از %{total} پیامد گزینش شده شکست خورد: %{ids}." + notice_failed_to_save_members: "ذخیره سازی اعضا شکست خورد: %{errors}." + notice_no_issue_selected: "هیچ پیامدی برگزیده نشده است! پیامدهایی که می‌خواهید ویرایش کنید را برگزینید." + notice_account_pending: "حساب شما ساخته شد و اکنون چشم به راه روادید سرپرست است." + notice_default_data_loaded: پیکربندی پیش‌گزیده با موفقیت بار شد. + notice_unable_delete_version: نگارش را نمی‌توان پاک کرد. + notice_unable_delete_time_entry: زمان گزارش شده را نمی‌توان پاک کرد. + notice_issue_done_ratios_updated: اندازه انجام شده پیامد بروز شد. + notice_gantt_chart_truncated: "نمودار بریده شد چون از بیشترین شماری که می‌توان نشان داد بزگتر است (%{max})." + + error_can_t_load_default_data: "پیکربندی پیش‌گزیده نمی‌تواند بار شود: %{value}" + error_scm_not_found: "بخش یا نگارش در انباره پیدا نشد." + error_scm_command_failed: "ایرادی در دسترسی به انباره پیش آمد: %{value}" + error_scm_annotate: "بخش پیدا نشد یا نمی‌توان برای آن یادداشت نوشت." + error_issue_not_found_in_project: 'پیامد پیدا نشد یا به این پروژه وابسته نیست.' + error_no_tracker_in_project: 'هیچ پیگردی به این پروژه پیوسته نشده است. پیکربندی پروژه را بررسی کنید.' + error_no_default_issue_status: 'هیچ وضعیت پیامد پیش‌گزیده‌ای مشخص نشده است. پیکربندی را بررسی کنید (به «پیکربندی -> وضعیت‌های پیامد» بروید).' + error_can_not_delete_custom_field: فیلد سفارشی را نمی‌توان پاک کرد. + error_can_not_delete_tracker: "این پیگرد دارای پیامد است و نمی‌توان آن را پاک کرد." + error_can_not_remove_role: "این نقش به کار گرفته شده است و نمی‌توان آن را پاک کرد." + error_can_not_reopen_issue_on_closed_version: 'یک پیامد که به یک نگارش بسته شده وابسته است را نمی‌توان باز کرد.' + error_can_not_archive_project: این پروژه را نمی‌توان بایگانی کرد. + error_issue_done_ratios_not_updated: "اندازه انجام شده پیامد بروز نشد." + error_workflow_copy_source: 'یک پیگرد یا نقش منبع را برگزینید.' + error_workflow_copy_target: 'پیگردها یا نقش‌های مقصد را برگزینید.' + error_unable_delete_issue_status: 'وضعیت پیامد را نمی‌توان پاک کرد.' + error_unable_to_connect: "نمی‌توان متصل شد (%{value})" + warning_attachments_not_saved: "%{count} پرونده ذخیره نشد." + + mail_subject_lost_password: "گذرواژه حساب %{value} شما" + mail_body_lost_password: 'برای جایگزینی گذرواژه خود، بر روی پیوند زیر کلیک کنید:' + mail_subject_register: "فعالسازی حساب %{value} شما" + mail_body_register: 'برای فعالسازی حساب خود، بر روی پیوند زیر کلیک کنید:' + mail_body_account_information_external: "شما می‌توانید حساب %{value} خود را برای ورود به کار برید." + mail_body_account_information: داده‌های حساب شما + mail_subject_account_activation_request: "درخواست فعالسازی حساب %{value}" + mail_body_account_activation_request: "یک کاربر تازه (%{value}) نامنویسی کرده است. این حساب چشم به راه روادید شماست:" + mail_subject_reminder: "زمان رسیدگی به %{count} پیامد در %{days} روز آینده سر می‌رسد" + mail_body_reminder: "زمان رسیدگی به %{count} پیامد که به شما واگذار شده است، در %{days} روز آینده سر می‌رسد:" + mail_subject_wiki_content_added: "برگه ویکی «%{id}» افزوده شد" + mail_body_wiki_content_added: "برگه ویکی «%{id}» به دست %{author} افزوده شد." + mail_subject_wiki_content_updated: "برگه ویکی «%{id}» بروز شد" + mail_body_wiki_content_updated: "برگه ویکی «%{id}» به دست %{author} بروز شد." + + gui_validation_error: 1 ایراد + gui_validation_error_plural: "%{count} ایراد" + + field_name: نام + field_description: یادداشت + field_summary: خلاصه + field_is_required: الزامی + field_firstname: نام کوچک + field_lastname: نام خانوادگی + field_mail: ایمیل + field_filename: پرونده + field_filesize: اندازه + field_downloads: دریافت‌ها + field_author: نویسنده + field_created_on: ساخته شده در + field_updated_on: بروز شده در + field_field_format: قالب + field_is_for_all: برای همه پروژه‌ها + field_possible_values: مقادیر ممکن + field_regexp: عبارت منظم + field_min_length: کمترین اندازه + field_max_length: بیشترین اندازه + field_value: مقدار + field_category: دسته + field_title: عنوان + field_project: پروژه + field_issue: پیامد + field_status: وضعیت + field_notes: یادداشت + field_is_closed: پیامد بسته شده + field_is_default: مقدار پیش‌گزیده + field_tracker: پیگرد + field_subject: موضوع + field_due_date: زمان سررسید + field_assigned_to: واگذار شده به + field_priority: برتری + field_fixed_version: نگارش هدف + field_user: کاربر + field_principal: دستور دهنده + field_role: نقش + field_homepage: برگه خانه + field_is_public: همگانی + field_parent: پروژه پدر + field_is_in_roadmap: این پیامدها در چشم‌انداز نشان داده شوند + field_login: ورود + field_mail_notification: آگاه سازی‌های ایمیلی + field_admin: سرپرست + field_last_login_on: آخرین ورود + field_language: زبان + field_effective_date: تاریخ + field_password: گذرواژه + field_new_password: گذرواژه تازه + field_password_confirmation: بررسی گذرواژه + field_version: نگارش + field_type: گونه + field_host: میزبان + field_port: درگاه + field_account: حساب + field_base_dn: DN پایه + field_attr_login: نشانه ورود + field_attr_firstname: نشانه نام کوچک + field_attr_lastname: نشانه نام خانوادگی + field_attr_mail: نشانه ایمیل + field_onthefly: ساخت کاربر بیدرنگ + field_start_date: تاریخ آغاز + field_done_ratio: ٪ انجام شده + field_auth_source: روش شناسایی + field_hide_mail: ایمیل من پنهان شود + field_comments: دیدگاه + field_url: نشانی + field_start_page: برگه آغاز + field_subproject: زیر پروژه + field_hours: ساعت‌ + field_activity: گزارش + field_spent_on: در تاریخ + field_identifier: شناسه + field_is_filter: پالایش پذیر + field_issue_to: پیامد وابسته + field_delay: دیرکرد + field_assignable: پیامدها می‌توانند به این نقش واگذار شوند + field_redirect_existing_links: پیوندهای پیشین به پیوند تازه راهنمایی شوند + field_estimated_hours: زمان برآورد شده + field_column_names: ستون‌ها + field_time_entries: زمان نوشتن + field_time_zone: پهنه زمانی + field_searchable: جستجو پذیر + field_default_value: مقدار پیش‌گزیده + field_comments_sorting: نمایش دیدگاه‌ها + field_parent_title: برگه پدر + field_editable: ویرایش پذیر + field_watcher: دیده‌بان + field_identity_url: نشانی OpenID + field_content: محتوا + field_group_by: دسته بندی با + field_sharing: اشتراک گذاری + field_parent_issue: کار پدر + field_member_of_group: "دسته واگذار شونده" + field_assigned_to_role: "نقش واگذار شونده" + field_text: فیلد متنی + field_visible: آشکار + + setting_app_title: نام برنامه + setting_app_subtitle: زیرنام برنامه + setting_welcome_text: نوشتار خوش‌آمد گویی + setting_default_language: زبان پیش‌گزیده + setting_login_required: الزامی بودن ورود + setting_self_registration: خود نام نویسی + setting_attachment_max_size: بیشترین اندازه پیوست + setting_issues_export_limit: کرانه صدور پییامدها + setting_mail_from: نشانی فرستنده ایمیل + setting_bcc_recipients: گیرندگان ایمیل دیده نشوند (bcc) + setting_plain_text_mail: ایمیل نوشته ساده (بدون HTML) + setting_host_name: نام میزبان و نشانی + setting_text_formatting: قالب بندی نوشته + setting_wiki_compression: فشرده‌سازی پیشینه ویکی + setting_feeds_limit: کرانه محتوای خوراک + setting_default_projects_public: حالت پیش‌گزیده پروژه‌های تازه، همگانی است + setting_autofetch_changesets: دریافت خودکار تغییرات + setting_sys_api_enabled: فعال سازی وب سرویس برای سرپرستی انباره + setting_commit_ref_keywords: کلیدواژه‌های نشانه + setting_commit_fix_keywords: کلیدواژه‌های انجام + setting_autologin: ورود خودکار + setting_date_format: قالب تاریخ + setting_time_format: قالب زمان + setting_cross_project_issue_relations: توانایی وابستگی میان پروژه‌ای پیامدها + setting_issue_list_default_columns: ستون‌های پیش‌گزیده نمایش داده شده در فهرست پیامدها + setting_emails_header: سرنویس ایمیل‌ها + setting_emails_footer: پانویس ایمیل‌ها + setting_protocol: پیوندنامه + setting_per_page_options: گزینه‌های اندازه داده‌های هر برگ + setting_user_format: قالب نمایشی کاربران + setting_activity_days_default: روزهای نمایش داده شده در گزارش پروژه + setting_display_subprojects_issues: پیش‌گزیده نمایش پیامدهای زیرپروژه در پروژه پدر + setting_enabled_scm: فعالسازی SCM + setting_mail_handler_body_delimiters: "بریدن ایمیل‌ها پس از یکی از این ردیف‌ها" + setting_mail_handler_api_enabled: فعالسازی وب سرویس برای ایمیل‌های آمده + setting_mail_handler_api_key: کلید API + setting_sequential_project_identifiers: ساخت پشت سر هم شناسه پروژه + setting_gravatar_enabled: کاربرد Gravatar برای عکس کاربر + setting_gravatar_default: عکس Gravatar پیش‌گزیده + setting_diff_max_lines_displayed: بیشترین اندازه ردیف‌های تفاوت نشان داده شده + setting_file_max_size_displayed: بیشترین اندازه پرونده‌های نمایش داده شده درون خطی + setting_repository_log_display_limit: بیشترین شمار نگارش‌های نمایش داده شده در گزارش پرونده + setting_openid: پذیرش ورود و نام نویسی با OpenID + setting_password_min_length: کمترین اندازه گذرواژه + setting_new_project_user_role_id: نقش داده شده به کاربری که سرپرست نیست و پروژه می‌سازد + setting_default_projects_modules: پیمانه‌های پیش‌گزیده فعال برای پروژه‌های تازه + setting_issue_done_ratio: برآورد اندازه انجام شده پیامد با + setting_issue_done_ratio_issue_field: کاربرد فیلد پیامد + setting_issue_done_ratio_issue_status: کاربرد وضعیت پیامد + setting_start_of_week: آغاز گاهشمار از + setting_rest_api_enabled: فعالسازی وب سرویس‌های REST + setting_cache_formatted_text: نهان سازی نوشته‌های قالب بندی شده + setting_default_notification_option: آگاه سازی پیش‌گزیده + setting_commit_logtime_enabled: فعالسازی زمان گذاشته شده + setting_commit_logtime_activity_id: کار زمان گذاشته شده + setting_gantt_items_limit: بیشترین شمار بخش‌های نمایش داده شده در نمودار گانت + + permission_add_project: ساخت پروژه + permission_add_subprojects: ساخت زیرپروژه + permission_edit_project: ویرایش پروژه + permission_select_project_modules: گزینش پیمانه‌های پروژه + permission_manage_members: سرپرستی اعضا + permission_manage_project_activities: سرپرستی کارهای پروژه + permission_manage_versions: سرپرستی نگارش‌ها + permission_manage_categories: سرپرستی دسته‌های پیامد + permission_view_issues: دیدن پیامدها + permission_add_issues: افزودن پیامدها + permission_edit_issues: ویرایش پیامدها + permission_manage_issue_relations: سرپرستی وابستگی پیامدها + permission_add_issue_notes: افزودن یادداشت + permission_edit_issue_notes: ویرایش یادداشت + permission_edit_own_issue_notes: ویرایش یادداشت خود + permission_move_issues: جابجایی پیامدها + permission_delete_issues: پاک کردن پیامدها + permission_manage_public_queries: سرپرستی پرس‌وجوهای همگانی + permission_save_queries: ذخیره سازی پرس‌وجوها + permission_view_gantt: دیدن نمودار گانت + permission_view_calendar: دیدن گاهشمار + permission_view_issue_watchers: دیدن فهرست دیده‌بان‌ها + permission_add_issue_watchers: افزودن دیده‌بان‌ها + permission_delete_issue_watchers: پاک کردن دیده‌بان‌ها + permission_log_time: نوشتن زمان گذاشته شده + permission_view_time_entries: دیدن زمان گذاشته شده + permission_edit_time_entries: ویرایش زمان گذاشته شده + permission_edit_own_time_entries: ویرایش زمان گذاشته شده خود + permission_manage_news: سرپرستی رویدادها + permission_comment_news: گذاشتن دیدگاه روی رویدادها + permission_manage_documents: سرپرستی نوشتارها + permission_view_documents: دیدن نوشتارها + permission_manage_files: سرپرستی پرونده‌ها + permission_view_files: دیدن پرونده‌ها + permission_manage_wiki: سرپرستی ویکی + permission_rename_wiki_pages: نامگذاری برگه ویکی + permission_delete_wiki_pages: پاک کردن برگه ویکی + permission_view_wiki_pages: دیدن ویکی + permission_view_wiki_edits: دیدن پیشینه ویکی + permission_edit_wiki_pages: ویرایش برگه‌های ویکی + permission_delete_wiki_pages_attachments: پاک کردن پیوست‌های برگه ویکی + permission_protect_wiki_pages: نگه‌داری برگه‌های ویکی + permission_manage_repository: سرپرستی انباره + permission_browse_repository: چریدن در انباره + permission_view_changesets: دیدن تغییرات + permission_commit_access: دسترسی تغییر انباره + permission_manage_boards: سرپرستی انجمن‌ها + permission_view_messages: دیدن پیام‌ها + permission_add_messages: فرستادن پیام‌ها + permission_edit_messages: ویرایش پیام‌ها + permission_edit_own_messages: ویرایش پیام خود + permission_delete_messages: پاک کردن پیام‌ها + permission_delete_own_messages: پاک کردن پیام خود + permission_export_wiki_pages: صدور برگه‌های ویکی + permission_manage_subtasks: سرپرستی زیرکارها + + project_module_issue_tracking: پیگیری پیامدها + project_module_time_tracking: پیگیری زمان + project_module_news: رویدادها + project_module_documents: نوشتارها + project_module_files: پرونده‌ها + project_module_wiki: ویکی + project_module_repository: انباره + project_module_boards: انجمن‌ها + project_module_calendar: گاهشمار + project_module_gantt: گانت + + label_user: کاربر + label_user_plural: کاربر + label_user_new: کاربر تازه + label_user_anonymous: ناشناس + label_project: پروژه + label_project_new: پروژه تازه + label_project_plural: پروژه + label_x_projects: + zero: بدون پروژه + one: "1 پروژه" + other: "%{count} پروژه" + label_project_all: همه پروژه‌ها + label_project_latest: آخرین پروژه‌ها + label_issue: پیامد + label_issue_new: پیامد تازه + label_issue_plural: پیامد + label_issue_view_all: دیدن همه پیامدها + label_issues_by: "دسته‌بندی پیامدها با %{value}" + label_issue_added: پیامد افزوده شد + label_issue_updated: پیامد بروز شد + label_document: نوشتار + label_document_new: نوشتار تازه + label_document_plural: نوشتار + label_document_added: نوشتار افزوده شد + label_role: نقش + label_role_plural: نقش + label_role_new: نقش تازه + label_role_and_permissions: نقش‌ها و پروانه‌ها + label_member: عضو + label_member_new: عضو تازه + label_member_plural: عضو + label_tracker: پیگرد + label_tracker_plural: پیگرد + label_tracker_new: پیگرد تازه + label_workflow: گردش کار + label_issue_status: وضعیت پیامد + label_issue_status_plural: وضعیت پیامد + label_issue_status_new: وضعیت تازه + label_issue_category: دسته پیامد + label_issue_category_plural: دسته پیامد + label_issue_category_new: دسته تازه + label_custom_field: فیلد سفارشی + label_custom_field_plural: فیلد سفارشی + label_custom_field_new: فیلد سفارشی تازه + label_enumerations: برشمردنی‌ها + label_enumeration_new: مقدار تازه + label_information: داده + label_information_plural: داده + label_please_login: وارد شوید + label_register: نام نویسی کنید + label_login_with_open_id_option: یا با OpenID وارد شوید + label_password_lost: بازیافت گذرواژه + label_home: سرآغاز + label_my_page: برگه من + label_my_account: حساب من + label_my_projects: پروژه‌های من + label_my_page_block: بخش برگه من + label_administration: سرپرستی + label_login: ورود + label_logout: خروج + label_help: راهنما + label_reported_issues: پیامدهای گزارش شده + label_assigned_to_me_issues: پیامدهای واگذار شده به من + label_last_login: آخرین ورود + label_registered_on: نام نویسی شده در + label_activity: گزارش + label_overall_activity: گزارش روی هم رفته + label_user_activity: "گزارش %{value}" + label_new: تازه + label_logged_as: "نام کاربری:" + label_environment: محیط + label_authentication: شناسایی + label_auth_source: روش شناسایی + label_auth_source_new: روش شناسایی تازه + label_auth_source_plural: روش شناسایی + label_subproject_plural: زیرپروژه + label_subproject_new: زیرپروژه تازه + label_and_its_subprojects: "%{value} و زیرپروژه‌هایش" + label_min_max_length: کمترین و بیشترین اندازه + label_list: فهرست + label_date: تاریخ + label_integer: شماره درست + label_float: شماره شناور + label_boolean: درست/نادرست + label_string: نوشته + label_text: نوشته بلند + label_attribute: نشانه + label_attribute_plural: نشانه + label_download: "%{count} بار دریافت شده" + label_download_plural: "%{count} بار دریافت شده" + label_no_data: هیچ داده‌ای برای نمایش نیست + label_change_status: جایگزینی وضعیت + label_history: پیشینه + label_attachment: پرونده + label_attachment_new: پرونده تازه + label_attachment_delete: پاک کردن پرونده + label_attachment_plural: پرونده + label_file_added: پرونده افزوده شد + label_report: گزارش + label_report_plural: گزارش + label_news: رویداد + label_news_new: افزودن رویداد + label_news_plural: رویداد + label_news_latest: آخرین رویدادها + label_news_view_all: دیدن همه رویدادها + label_news_added: رویداد افزوده شد + label_settings: پیکربندی + label_overview: در یک نگاه + label_version: نگارش + label_version_new: نگارش تازه + label_version_plural: نگارش + label_close_versions: بستن نگارش‌های انجام شده + label_confirmation: بررسی + label_export_to: 'قالب‌های دیگر:' + label_read: خواندن... + label_public_projects: پروژه‌های همگانی + label_open_issues: باز + label_open_issues_plural: باز + label_closed_issues: بسته + label_closed_issues_plural: بسته + label_x_open_issues_abbr_on_total: + zero: 0 باز از %{total} + one: 1 باز از %{total} + other: "%{count} باز از %{total}" + label_x_open_issues_abbr: + zero: 0 باز + one: 1 باز + other: "%{count} باز" + label_x_closed_issues_abbr: + zero: 0 بسته + one: 1 بسته + other: "%{count} بسته" + label_total: جمله + label_permissions: پروانه‌ها + label_current_status: وضعیت کنونی + label_new_statuses_allowed: وضعیت‌های پذیرفتنی تازه + label_all: همه + label_none: هیچ + label_nobody: هیچکس + label_next: پسین + label_previous: پیشین + label_used_by: به کار رفته در + label_details: ریزه‌کاری + label_add_note: افزودن یادداشت + label_per_page: ردیف‌ها در هر برگه + label_calendar: گاهشمار + label_months_from: از ماه + label_gantt: گانت + label_internal: درونی + label_last_changes: "%{count} تغییر آخر" + label_change_view_all: دیدن همه تغییرات + label_personalize_page: سفارشی نمودن این برگه + label_comment: دیدگاه + label_comment_plural: دیدگاه + label_x_comments: + zero: بدون دیدگاه + one: 1 دیدگاه + other: "%{count} دیدگاه" + label_comment_add: افزودن دیدگاه + label_comment_added: دیدگاه افزوده شد + label_comment_delete: پاک کردن دیدگاه‌ها + label_query: پرس‌وجوی سفارشی + label_query_plural: پرس‌وجوی سفارشی + label_query_new: پرس‌وجوی تازه + label_filter_add: افزودن پالایه + label_filter_plural: پالایه + label_equals: برابر است با + label_not_equals: برابر نیست با + label_in_less_than: کمتر است از + label_in_more_than: بیشتر است از + label_greater_or_equal: بیشتر یا برابر است با + label_less_or_equal: کمتر یا برابر است با + label_in: در + label_today: امروز + label_all_time: همیشه + label_yesterday: دیروز + label_this_week: این هفته + label_last_week: هفته پیشین + label_last_n_days: "%{count} روز گذشته" + label_this_month: این ماه + label_last_month: ماه پیشین + label_this_year: امسال + label_date_range: بازه تاریخ + label_less_than_ago: کمتر از چند روز پیشین + label_more_than_ago: بیشتر از چند روز پیشین + label_ago: روز پیشین + label_contains: دارد + label_not_contains: ندارد + label_day_plural: روز + label_repository: انباره + label_repository_plural: انباره + label_browse: چریدن + label_modification: "%{count} جایگذاری" + label_modification_plural: "%{count} جایگذاری" + label_branch: شاخه + label_tag: برچسب + label_revision: بازبینی + label_revision_plural: بازبینی + label_revision_id: "بازبینی %{value}" + label_associated_revisions: بازبینی‌های وابسته + label_added: افزوده شده + label_modified: پیراسته شده + label_copied: رونویسی شده + label_renamed: نامگذاری شده + label_deleted: پاکسازی شده + label_latest_revision: آخرین بازبینی + label_latest_revision_plural: آخرین بازبینی + label_view_revisions: دیدن بازبینی‌ها + label_view_all_revisions: دیدن همه بازبینی‌ها + label_max_size: بیشترین اندازه + label_sort_highest: بردن به آغاز + label_sort_higher: بردن به بالا + label_sort_lower: بردن به پایین + label_sort_lowest: بردن به پایان + label_roadmap: چشم‌انداز + label_roadmap_due_in: "سررسید در %{value}" + label_roadmap_overdue: "%{value} دیرکرد" + label_roadmap_no_issues: هیچ پیامدی برای این نگارش نیست + label_search: جستجو + label_result_plural: دست‌آورد + label_all_words: همه واژه‌ها + label_wiki: ویکی + label_wiki_edit: ویرایش ویکی + label_wiki_edit_plural: ویرایش ویکی + label_wiki_page: برگه ویکی + label_wiki_page_plural: برگه ویکی + label_index_by_title: شاخص بر اساس نام + label_index_by_date: شاخص بر اساس تاریخ + label_current_version: نگارش کنونی + label_preview: پیش‌نمایش + label_feed_plural: خوراک + label_changes_details: ریز همه جایگذاری‌ها + label_issue_tracking: پیگیری پیامد + label_spent_time: زمان گذاشته شده + label_overall_spent_time: زمان گذاشته شده روی هم + label_f_hour: "%{value} ساعت" + label_f_hour_plural: "%{value} ساعت" + label_time_tracking: پیگیری زمان + label_change_plural: جایگذاری + label_statistics: سرشماری + label_commits_per_month: تغییر در هر ماه + label_commits_per_author: تغییر هر نویسنده + label_view_diff: دیدن تفاوت‌ها + label_diff_inline: همراستا + label_diff_side_by_side: کنار به کنار + label_options: گزینه‌ها + label_copy_workflow_from: رونویسی گردش کار از روی + label_permissions_report: گزارش پروانه‌ها + label_watched_issues: پیامدهای دیده‌بانی شده + label_related_issues: پیامدهای وابسته + label_applied_status: وضعیت به کار رفته + label_loading: بار گذاری... + label_relation_new: وابستگی تازه + label_relation_delete: پاک کردن وابستگی + label_relates_to: وابسته به + label_duplicates: نگارش دیگری از + label_duplicated_by: نگارشی دیگر در + label_blocks: بازداشت‌ها + label_blocked_by: بازداشت به دست + label_precedes: جلوتر است از + label_follows: پستر است از + label_end_to_start: پایان به آغاز + label_end_to_end: پایان به پایان + label_start_to_start: آغاز به آغاز + label_start_to_end: آغاز به پایان + label_stay_logged_in: وارد شده بمانید + label_disabled: غیرفعال + label_show_completed_versions: نمایش نگارش‌های انجام شده + label_me: من + label_board: انجمن + label_board_new: انجمن تازه + label_board_plural: انجمن + label_board_locked: قفل شده + label_board_sticky: چسبناک + label_topic_plural: سرفصل + label_message_plural: پیام + label_message_last: آخرین پیام + label_message_new: پیام تازه + label_message_posted: پیام افزوده شد + label_reply_plural: پاسخ + label_send_information: فرستادن داده‌های حساب به کاربر + label_year: سال + label_month: ماه + label_week: هفته + label_date_from: از + label_date_to: تا + label_language_based: بر اساس زبان کاربر + label_sort_by: "جور کرد با %{value}" + label_send_test_email: فرستادن ایمیل آزمایشی + label_feeds_access_key: کلید دسترسی RSS + label_missing_feeds_access_key: کلید دسترسی RSS در دسترس نیست + label_feeds_access_key_created_on: "کلید دسترسی RSS %{value} پیش ساخته شده است" + label_module_plural: پیمانه + label_added_time_by: "افزوده شده به دست %{author} در %{age} پیش" + label_updated_time_by: "بروز شده به دست %{author} در %{age} پیش" + label_updated_time: "بروز شده در %{value} پیش" + label_jump_to_a_project: پرش به یک پروژه... + label_file_plural: پرونده + label_changeset_plural: تغییر + label_default_columns: ستون‌های پیش‌گزیده + label_no_change_option: (بدون تغییر) + label_bulk_edit_selected_issues: ویرایش دسته‌ای پیامدهای گزینش شده + label_theme: پوسته + label_default: پیش‌گزیده + label_search_titles_only: تنها نام‌ها جستجو شود + label_user_mail_option_all: "برای هر رویداد در همه پروژه‌ها" + label_user_mail_option_selected: "برای هر رویداد تنها در پروژه‌های گزینش شده..." + label_user_mail_option_none: "هیچ رویدادی" + label_user_mail_option_only_my_events: "تنها برای چیزهایی که دیده‌بان هستم یا در آن‌ها درگیر هستم" + label_user_mail_option_only_assigned: "تنها برای چیزهایی که به من واگذار شده" + label_user_mail_option_only_owner: "تنها برای چیزهایی که من دارنده آن‌ها هستم" + label_user_mail_no_self_notified: "نمی‌خواهم از تغییراتی که خودم می‌دهم آگاه شوم" + label_registration_activation_by_email: فعالسازی حساب با ایمیل + label_registration_manual_activation: فعالسازی حساب دستی + label_registration_automatic_activation: فعالسازی حساب خودکار + label_display_per_page: "ردیف‌ها در هر برگه: %{value}" + label_age: سن + label_change_properties: ویرایش ویژگی‌ها + label_general: همگانی + label_more: بیشتر + label_scm: SCM + label_plugins: افزونه‌ها + label_ldap_authentication: شناساییLDAP + label_downloads_abbr: دریافت + label_optional_description: یادداشت دلخواه + label_add_another_file: افزودن پرونده دیگر + label_preferences: پسندها + label_chronological_order: به ترتیب تاریخ + label_reverse_chronological_order: برعکس ترتیب تاریخ + label_planning: برنامه ریزی + label_incoming_emails: ایمیل‌های آمده + label_generate_key: ساخت کلید + label_issue_watchers: دیده‌بان‌ها + label_example: نمونه + label_display: نمایش + label_sort: جور کرد + label_ascending: افزایشی + label_descending: کاهشی + label_date_from_to: از %{start} تا %{end} + label_wiki_content_added: برگه ویکی افزوده شد + label_wiki_content_updated: برگه ویکی بروز شد + label_group: دسته + label_group_plural: دسته + label_group_new: دسته تازه + label_time_entry_plural: زمان گذاشته شده + label_version_sharing_none: بدون اشتراک + label_version_sharing_descendants: با زیر پروژه‌ها + label_version_sharing_hierarchy: با رشته پروژه‌ها + label_version_sharing_tree: با درخت پروژه + label_version_sharing_system: با همه پروژه‌ها + label_update_issue_done_ratios: بروز رسانی اندازه انجام شده پیامد + label_copy_source: منبع + label_copy_target: مقصد + label_copy_same_as_target: مانند مقصد + label_display_used_statuses_only: تنها وضعیت‌هایی نشان داده شوند که در این پیگرد به کار رفته‌اند + label_api_access_key: کلید دسترسی API + label_missing_api_access_key: کلید دسترسی API در دسترس نیست + label_api_access_key_created_on: "کلید دسترسی API %{value} پیش ساخته شده است" + label_profile: نمایه + label_subtask_plural: زیرکار + label_project_copy_notifications: در هنگام رونویسی پروژه ایمیل‌های آگاه‌سازی را بفرست + label_principal_search: "جستجو برای کاربر یا دسته:" + label_user_search: "جستجو برای کاربر:" + + button_login: ورود + button_submit: واگذاری + button_save: نگهداری + button_check_all: گزینش همه + button_uncheck_all: گزینش هیچ + button_delete: پاک + button_create: ساخت + button_create_and_continue: ساخت و ادامه + button_test: آزمایش + button_edit: ویرایش + button_edit_associated_wikipage: "ویرایش برگه ویکی وابسته: %{page_title}" + button_add: افزودن + button_change: ویرایش + button_apply: انجام + button_clear: پاک + button_lock: گذاشتن قفل + button_unlock: برداشتن قفل + button_download: دریافت + button_list: فهرست + button_view: دیدن + button_move: جابجایی + button_move_and_follow: جابجایی و ادامه + button_back: برگشت + button_cancel: بازگشت + button_activate: فعالسازی + button_sort: جور کرد + button_log_time: زمان‌نویسی + button_rollback: برگرد به این نگارش + button_watch: دیده‌بانی + button_unwatch: نا‌دیده‌بانی + button_reply: پاسخ + button_archive: بایگانی + button_unarchive: برگشت از بایگانی + button_reset: بازنشانی + button_rename: نامگذاری + button_change_password: جایگزینی گذرواژه + button_copy: رونوشت + button_copy_and_follow: رونوشت و ادامه + button_annotate: یادداشت + button_update: بروز رسانی + button_configure: پیکربندی + button_quote: نقل قول + button_duplicate: نگارش دیگر + button_show: نمایش + + status_active: فعال + status_registered: نام‌نویسی شده + status_locked: قفل + + version_status_open: باز + version_status_locked: قفل + version_status_closed: بسته + + field_active: فعال + + text_select_mail_notifications: فرمان‌هایی که برای آن‌ها باید ایمیل فرستاده شود را برگزینید. + text_regexp_info: برای نمونه ^[A-Z0-9]+$ + text_min_max_length_info: 0 یعنی بدون کران + text_project_destroy_confirmation: آیا براستی می‌خواهید این پروژه و همه داده‌های آن را پاک کنید؟ + text_subprojects_destroy_warning: "زیرپروژه‌های آن: %{value} هم پاک خواهند شد." + text_workflow_edit: یک نقش و یک پیگرد را برای ویرایش گردش کار برگزینید + text_are_you_sure: آیا این کار انجام شود؟ + text_are_you_sure_with_children: "آیا پیامد و همه زیرپیامدهای آن پاک شوند؟" + text_journal_changed: "«%{label}» از «%{old}» به «%{new}» جایگزین شد" + text_journal_set_to: "«%{label}» به «%{value}» نشانده شد" + text_journal_deleted: "«%{label}» پاک شد (%{old})" + text_journal_added: "«%{label}»، «%{value}» را افزود" + text_tip_task_begin_day: روز آغاز پیامد + text_tip_task_end_day: روز پایان پیامد + text_tip_task_begin_end_day: روز آغاز و پایان پیامد + text_project_identifier_info: 'تنها نویسه‌های کوچک (a-z)، شماره‌ها و خط تیره پذیرفتنی است.
پس از ذخیره سازی، شناسه نمی‌تواند جایگزین شود.' + text_caracters_maximum: "بیشترین اندازه %{count} است." + text_caracters_minimum: "کمترین اندازه %{count} است." + text_length_between: "باید میان %{min} و %{max} نویسه باشد." + text_tracker_no_workflow: هیچ گردش کاری برای این پیگرد مشخص نشده است + text_unallowed_characters: نویسه‌های ناپسند + text_comma_separated: چند مقدار پذیرفتنی است (با «,» از هم جدا شوند). + text_line_separated: چند مقدار پذیرفتنی است (هر مقدار در یک خط). + text_issues_ref_in_commit_messages: نشانه روی و بستن پیامدها در پیام‌های انباره + text_issue_added: "پیامد %{id} به دست %{author} گزارش شد." + text_issue_updated: "پیامد %{id} به دست %{author} بروز شد." + text_wiki_destroy_confirmation: آیا براستی می‌خواهید این ویکی و همه محتوای آن را پاک کنید؟ + text_issue_category_destroy_question: "برخی پیامدها (%{count}) به این دسته واگذار شده‌اند. می‌خواهید چه کنید؟" + text_issue_category_destroy_assignments: پاک کردن واگذاری به دسته + text_issue_category_reassign_to: واگذاری دوباره پیامدها به این دسته + text_user_mail_option: "برای پروژه‌های گزینش نشده، تنها ایمیل‌هایی درباره چیزهایی که دیده‌بان یا درگیر آن‌ها هستید دریافت خواهید کرد (مانند پیامدهایی که نویسنده آن‌ها هستید یا به شما واگذار شده‌اند)." + text_no_configuration_data: "نقش‌ها، پیگردها، وضعیت‌های پیامد و گردش کار هنوز پیکربندی نشده‌اند. \nبه سختی پیشنهاد می‌شود که پیکربندی پیش‌گزیده را بار کنید. سپس می‌توانید آن را ویرایش کنید." + text_load_default_configuration: بارگذاری پیکربندی پیش‌گزیده + text_status_changed_by_changeset: "در تغییر %{value} بروز شده است." + text_time_logged_by_changeset: "در تغییر %{value} نوشته شده است." + text_issues_destroy_confirmation: 'آیا براستی می‌خواهید پیامدهای گزینش شده را پاک کنید؟' + text_select_project_modules: 'پیمانه‌هایی که باید برای این پروژه فعال شوند را برگزینید:' + text_default_administrator_account_changed: حساب سرپرستی پیش‌گزیده جایگزین شد + text_file_repository_writable: پوشه پیوست‌ها نوشتنی است + text_plugin_assets_writable: پوشه دارایی‌های افزونه‌ها نوشتنی است + text_rmagick_available: RMagick در دسترس است (اختیاری) + text_destroy_time_entries_question: "%{hours} ساعت روی پیامدهایی که می‌خواهید پاک کنید کار گزارش شده است. می‌خواهید چه کنید؟" + text_destroy_time_entries: ساعت‌های گزارش شده پاک شوند + text_assign_time_entries_to_project: ساعت‌های گزارش شده به پروژه واگذار شوند + text_reassign_time_entries: 'ساعت‌های گزارش شده به این پیامد واگذار شوند:' + text_user_wrote: "%{value} نوشت:" + text_enumeration_destroy_question: "%{count} داده به این برشمردنی وابسته شده‌اند." + text_enumeration_category_reassign_to: 'به این برشمردنی وابسته شوند:' + text_email_delivery_not_configured: "دریافت ایمیل پیکربندی نشده است و آگاه‌سازی‌ها غیر فعال هستند.\nکارگزار SMTP خود را در config/configuration.yml پیکربندی کنید و برنامه را بازنشانی کنید تا فعال شوند." + text_repository_usernames_mapping: "کاربر Redmine که به هر نام کاربری پیام‌های انباره نگاشت می‌شود را برگزینید.\nکاربرانی که نام کاربری یا ایمیل همسان دارند، خود به خود نگاشت می‌شوند." + text_diff_truncated: '... این تفاوت بریده شده چون بیشتر از بیشترین اندازه نمایش دادنی است.' + text_custom_field_possible_values_info: 'یک خط برای هر مقدار' + text_wiki_page_destroy_question: "این برگه %{descendants} زیربرگه دارد.می‌خواهید چه کنید؟" + text_wiki_page_nullify_children: "زیربرگه‌ها برگه ریشه شوند" + text_wiki_page_destroy_children: "زیربرگه‌ها و زیربرگه‌های آن‌ها پاک شوند" + text_wiki_page_reassign_children: "زیربرگه‌ها به زیر این برگه پدر بروند" + text_own_membership_delete_confirmation: "شما دارید برخی یا همه پروانه‌های خود را برمی‌دارید و شاید پس از این دیگر نتوانید این پروژه را ویرایش کنید.\nآیا می‌خواهید این کار را بکنید؟" + text_zoom_in: درشتنمایی + text_zoom_out: ریزنمایی + + default_role_manager: سرپرست + default_role_developer: برنامه‌نویس + default_role_reporter: گزارش‌دهنده + default_tracker_bug: ایراد + default_tracker_feature: ویژگی + default_tracker_support: پشتیبانی + default_issue_status_new: تازه + default_issue_status_in_progress: در گردش + default_issue_status_resolved: درست شده + default_issue_status_feedback: بازخورد + default_issue_status_closed: بسته + default_issue_status_rejected: برگشت خورده + default_doc_category_user: نوشتار کاربر + default_doc_category_tech: نوشتار فنی + default_priority_low: پایین + default_priority_normal: میانه + default_priority_high: بالا + default_priority_urgent: زود + default_priority_immediate: بیدرنگ + default_activity_design: طراحی + default_activity_development: ساخت + + enumeration_issue_priorities: برتری‌های پیامد + enumeration_doc_categories: دسته‌های نوشتار + enumeration_activities: کارها (پیگیری زمان) + enumeration_system_activity: کار سامانه + + text_tip_issue_begin_day: پیامد در این روز آغاز می‌شود + field_warn_on_leaving_unsaved: هنگام ترک برگه‌ای که نوشته‌های آن نگهداری نشده، به من هشدار بده + text_tip_issue_begin_end_day: پیامد در این روز آغاز می‌شود و پایان می‌پذیرد + text_tip_issue_end_day: پیامد در این روز پایان می‌پذیرد + text_warn_on_leaving_unsaved: این برگه دارای نوشته‌های نگهداری نشده است که اگر آن را ترک کنید، از میان می‌روند. + label_my_queries: جستارهای سفارشی من + text_journal_changed_no_detail: "%{label} بروز شد" + label_news_comment_added: دیدگاه به یک رویداد افزوده شد + button_expand_all: باز کردن همه + button_collapse_all: بستن همه + label_additional_workflow_transitions_for_assignee: زمانی که به کاربر واگذار شده، گذارهای بیشتر پذیرفته می‌شود + label_additional_workflow_transitions_for_author: زمانی که کاربر نویسنده است، گذارهای بیشتر پذیرفته می‌شود + label_bulk_edit_selected_time_entries: ویرایش دسته‌ای زمان‌های گزارش شده گزینش شده + text_time_entries_destroy_confirmation: آیا می‌خواهید زمان‌های گزارش شده گزینش شده پاک شوند؟ + label_role_anonymous: ناشناس + label_role_non_member: غیر عضو + label_issue_note_added: یادداشت افزوده شد + label_issue_status_updated: وضعیت بروز شد + label_issue_priority_updated: برتری بروز شد + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: کدگذاری پیام‌های انباره + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1eeb2d3cf254cdaa3fced154da1af384e6d301db.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1eeb2d3cf254cdaa3fced154da1af384e6d301db.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,186 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'workflows_controller' + +# Re-raise errors caught by the controller. +class WorkflowsController; def rescue_action(e) raise e end; end + +class WorkflowsControllerTest < ActionController::TestCase + fixtures :roles, :trackers, :workflows, :users, :issue_statuses + + def setup + @controller = WorkflowsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 1 # admin + end + + def test_index + get :index + assert_response :success + assert_template 'index' + + count = Workflow.count(:all, :conditions => 'role_id = 1 AND tracker_id = 2') + assert_tag :tag => 'a', :content => count.to_s, + :attributes => { :href => '/workflows/edit?role_id=1&tracker_id=2' } + end + + def test_get_edit + get :edit + assert_response :success + assert_template 'edit' + assert_not_nil assigns(:roles) + assert_not_nil assigns(:trackers) + end + + def test_get_edit_with_role_and_tracker + Workflow.delete_all + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3) + Workflow.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5) + + get :edit, :role_id => 2, :tracker_id => 1 + assert_response :success + assert_template 'edit' + + # used status only + assert_not_nil assigns(:statuses) + assert_equal [2, 3, 5], assigns(:statuses).collect(&:id) + + # allowed transitions + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'issue_status[3][5][]', + :value => 'always', + :checked => 'checked' } + # not allowed + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'issue_status[3][2][]', + :value => 'always', + :checked => nil } + # unused + assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'issue_status[1][1][]' } + end + + def test_get_edit_with_role_and_tracker_and_all_statuses + Workflow.delete_all + + get :edit, :role_id => 2, :tracker_id => 1, :used_statuses_only => '0' + assert_response :success + assert_template 'edit' + + assert_not_nil assigns(:statuses) + assert_equal IssueStatus.count, assigns(:statuses).size + + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'issue_status[1][1][]', + :value => 'always', + :checked => nil } + end + + def test_post_edit + post :edit, :role_id => 2, :tracker_id => 1, + :issue_status => { + '4' => {'5' => ['always']}, + '3' => {'1' => ['always'], '2' => ['always']} + } + assert_redirected_to '/workflows/edit?role_id=2&tracker_id=1' + + assert_equal 3, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) + assert_not_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2}) + assert_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4}) + end + + def test_post_edit_with_additional_transitions + post :edit, :role_id => 2, :tracker_id => 1, + :issue_status => { + '4' => {'5' => ['always']}, + '3' => {'1' => ['author'], '2' => ['assignee'], '4' => ['author', 'assignee']} + } + assert_redirected_to '/workflows/edit?role_id=2&tracker_id=1' + + assert_equal 4, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) + + w = Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 4, :new_status_id => 5}) + assert ! w.author + assert ! w.assignee + w = Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 1}) + assert w.author + assert ! w.assignee + w = Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2}) + assert ! w.author + assert w.assignee + w = Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 4}) + assert w.author + assert w.assignee + end + + def test_clear_workflow + assert Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) > 0 + + post :edit, :role_id => 2, :tracker_id => 1 + assert_equal 0, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) + end + + def test_get_copy + get :copy + assert_response :success + assert_template 'copy' + end + + def test_post_copy_one_to_one + source_transitions = status_transitions(:tracker_id => 1, :role_id => 2) + + post :copy, :source_tracker_id => '1', :source_role_id => '2', + :target_tracker_ids => ['3'], :target_role_ids => ['1'] + assert_response 302 + assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1) + end + + def test_post_copy_one_to_many + source_transitions = status_transitions(:tracker_id => 1, :role_id => 2) + + post :copy, :source_tracker_id => '1', :source_role_id => '2', + :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3'] + assert_response 302 + assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 1) + assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1) + assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 3) + assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 3) + end + + def test_post_copy_many_to_many + source_t2 = status_transitions(:tracker_id => 2, :role_id => 2) + source_t3 = status_transitions(:tracker_id => 3, :role_id => 2) + + post :copy, :source_tracker_id => 'any', :source_role_id => '2', + :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3'] + assert_response 302 + assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 1) + assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 1) + assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 3) + assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 3) + end + + # Returns an array of status transitions that can be compared + def status_transitions(conditions) + Workflow.find(:all, :conditions => conditions, + :order => 'tracker_id, role_id, old_status_id, new_status_id').collect {|w| [w.old_status, w.new_status_id]} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1e/1ef1c1b3db8e0ec86373a9f847e88d0b2afb5d10.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1e/1ef1c1b3db8e0ec86373a9f847e88d0b2afb5d10.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +class AssetsController < ApplicationController +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1f039e61af20ed2590d883654934758a80b24377.svn-base Binary file .svn/pristine/1f/1f039e61af20ed2590d883654934758a80b24377.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1f53e8d7ebf25765e9e5ca0866b0f757ad1aea9a.svn-base Binary file .svn/pristine/1f/1f53e8d7ebf25765e9e5ca0866b0f757ad1aea9a.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1f572940b49da993424874b4b9bed1d524fcea35.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1f572940b49da993424874b4b9bed1d524fcea35.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +module CodeRay + + # A little hack to enable CodeRay highlighting in RedCloth. + # + # Usage: + # require 'coderay' + # require 'coderay/for_redcloth' + # RedCloth.new('@[ruby]puts "Hello, World!"@').to_html + # + # Make sure you have RedCloth 4.0.3 activated, for example by calling + # require 'rubygems' + # before RedCloth is loaded and before calling CodeRay.for_redcloth. + module ForRedCloth + + def self.install + gem 'RedCloth', '>= 4.0.3' if defined? gem + require 'redcloth' + unless RedCloth::VERSION.to_s >= '4.0.3' + if defined? gem + raise 'CodeRay.for_redcloth needs RedCloth version 4.0.3 or later. ' + + "You have #{RedCloth::VERSION}. Please gem install RedCloth." + else + $".delete 'redcloth.rb' # sorry, but it works + require 'rubygems' + return install # retry + end + end + unless RedCloth::VERSION.to_s >= '4.2.2' + warn 'CodeRay.for_redcloth works best with RedCloth version 4.2.2 or later.' + end + RedCloth::TextileDoc.send :include, ForRedCloth::TextileDoc + RedCloth::Formatters::HTML.module_eval do + def unescape(html) # :nodoc: + replacements = { + '&' => '&', + '"' => '"', + '>' => '>', + '<' => '<', + } + html.gsub(/&(?:amp|quot|[gl]t);/) { |entity| replacements[entity] } + end + undef code, bc_open, bc_close, escape_pre + def code(opts) # :nodoc: + opts[:block] = true + if !opts[:lang] && RedCloth::VERSION.to_s >= '4.2.0' + # simulating pre-4.2 behavior + if opts[:text].sub!(/\A\[(\w+)\]/, '') + if CodeRay::Scanners[$1].lang == :text + opts[:text] = $& + opts[:text] + else + opts[:lang] = $1 + end + end + end + if opts[:lang] && !filter_coderay + require 'coderay' + @in_bc ||= nil + format = @in_bc ? :div : :span + opts[:text] = unescape(opts[:text]) unless @in_bc + highlighted_code = CodeRay.encode opts[:text], opts[:lang], format + highlighted_code.sub!(/\A<(span|div)/) { |m| m + pba(@in_bc || opts) } + highlighted_code + else + "#{opts[:text]}" + end + end + def bc_open(opts) # :nodoc: + opts[:block] = true + @in_bc = opts + opts[:lang] ? '' : "" + end + def bc_close(opts) # :nodoc: + opts = @in_bc + @in_bc = nil + opts[:lang] ? '' : "\n" + end + def escape_pre(text) # :nodoc: + if @in_bc ||= nil + text + else + html_esc(text, :html_escape_preformatted) + end + end + end + end + + module TextileDoc # :nodoc: + attr_accessor :filter_coderay + end + + end + +end + +CodeRay::ForRedCloth.install \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1f78c9cd9879f6fcb3d4c7ae2bf80de5b578d42c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1f78c9cd9879f6fcb3d4c7ae2bf80de5b578d42c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +<% show_revision_graph = ( @repository.supports_revision_graph? && path.blank? ) %> +<% form_tag({:controller => 'repositories', :action => 'diff', :id => @project, :path => to_path_param(path)}, :method => :get) do %> + + +<% if show_revision_graph %> + +<% end %> + + + + + + + + +<% show_diff = revisions.size > 1 %> +<% line_num = 1 %> +<% revisions.each do |changeset| %> + +<% if show_revision_graph %> + <% if line_num == 1 %> + + <% end %> +<% end %> + + + + + +<% if show_revision_graph %> + +<% else %> + +<% end %> + +<% line_num += 1 %> +<% end %> + +
#<%= l(:label_date) %><%= l(:field_author) %><%= l(:field_comments) %>
+ <% href_base = Proc.new {|x| url_for(:controller => 'repositories', + :action => 'revision', + :id => project, + :rev => x) } %> + <%= render :partial => 'revision_graph', + :locals => { + :commits => index_commits( + revisions, + @repository.branches, + href_base + ) + } %> + <%= link_to_revision(changeset, project) %><%= radio_button_tag('rev', changeset.identifier, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %><%= radio_button_tag('rev_to', changeset.identifier, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %><%= format_time(changeset.committed_on) %><%= h truncate(changeset.author.to_s, :length => 30) %> + <%= textilizable(truncate(truncate_at_line_break(changeset.comments, 0), :length => 90)) %> + <%= textilizable(truncate_at_line_break(changeset.comments)) %>
+<%= submit_tag(l(:label_view_diff), :name => nil) if show_diff %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1f7f86dc321cbe0fcb94878fe50d5b529000cd57.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1f7f86dc321cbe0fcb94878fe50d5b529000cd57.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,152 @@ +* Exported the changelog of Pagination code for historical reference. + +* Imported some patches from Rails Trac (others closed as "wontfix"): + #8176, #7325, #7028, #4113. Documentation is much cleaner now and there + are some new unobtrusive features! + +* Extracted Pagination from Rails trunk (r6795) + +# +# ChangeLog for /trunk/actionpack/lib/action_controller/pagination.rb +# +# Generated by Trac 0.10.3 +# 05/20/07 23:48:02 +# + +09/03/06 23:28:54 david [4953] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Docs and deprecation + +08/07/06 12:40:14 bitsweat [4715] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Deprecate direct usage of @params. Update ActionView::Base for + instance var deprecation. + +06/21/06 02:16:11 rick [4476] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Fix indent in pagination documentation. Closes #4990. [Kevin Clark] + +04/25/06 17:42:48 marcel [4268] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Remove all remaining references to @params in the documentation. + +03/16/06 06:38:08 rick [3899] + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + trivial documentation patch for #pagination_links [Francois + Beausoleil] closes #4258 + +02/20/06 03:15:22 david [3620] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/actionpack/test/activerecord/pagination_test.rb (modified) + * trunk/activerecord/CHANGELOG (modified) + * trunk/activerecord/lib/active_record/base.rb (modified) + * trunk/activerecord/test/base_test.rb (modified) + Added :count option to pagination that'll make it possible for the + ActiveRecord::Base.count call to using something else than * for the + count. Especially important for count queries using DISTINCT #3839 + [skaes]. Added :select option to Base.count that'll allow you to + select something else than * to be counted on. Especially important + for count queries using DISTINCT (closes #3839) [skaes]. + +02/09/06 09:17:40 nzkoz [3553] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/actionpack/test/active_record_unit.rb (added) + * trunk/actionpack/test/activerecord (added) + * trunk/actionpack/test/activerecord/active_record_assertions_test.rb (added) + * trunk/actionpack/test/activerecord/pagination_test.rb (added) + * trunk/actionpack/test/controller/active_record_assertions_test.rb (deleted) + * trunk/actionpack/test/fixtures/companies.yml (added) + * trunk/actionpack/test/fixtures/company.rb (added) + * trunk/actionpack/test/fixtures/db_definitions (added) + * trunk/actionpack/test/fixtures/db_definitions/sqlite.sql (added) + * trunk/actionpack/test/fixtures/developer.rb (added) + * trunk/actionpack/test/fixtures/developers_projects.yml (added) + * trunk/actionpack/test/fixtures/developers.yml (added) + * trunk/actionpack/test/fixtures/project.rb (added) + * trunk/actionpack/test/fixtures/projects.yml (added) + * trunk/actionpack/test/fixtures/replies.yml (added) + * trunk/actionpack/test/fixtures/reply.rb (added) + * trunk/actionpack/test/fixtures/topic.rb (added) + * trunk/actionpack/test/fixtures/topics.yml (added) + * Fix pagination problems when using include + * Introduce Unit Tests for pagination + * Allow count to work with :include by using count distinct. + + [Kevin Clark & Jeremy Hopple] + +11/05/05 02:10:29 bitsweat [2878] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Update paginator docs. Closes #2744. + +10/16/05 15:42:03 minam [2649] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Update/clean up AP documentation (rdoc) + +08/31/05 00:13:10 ulysses [2078] + * trunk/actionpack/CHANGELOG (modified) + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Add option to specify the singular name used by pagination. Closes + #1960 + +08/23/05 14:24:15 minam [2041] + * trunk/actionpack/CHANGELOG (modified) + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + Add support for :include with pagination (subject to existing + constraints for :include with :limit and :offset) #1478 + [michael@schubert.cx] + +07/15/05 20:27:38 david [1839] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + More pagination speed #1334 [Stefan Kaes] + +07/14/05 08:02:01 david [1832] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + * trunk/actionpack/test/controller/addresses_render_test.rb (modified) + Made pagination faster #1334 [Stefan Kaes] + +04/13/05 05:40:22 david [1159] + * trunk/actionpack/CHANGELOG (modified) + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/activerecord/lib/active_record/base.rb (modified) + Fixed pagination to work with joins #1034 [scott@sigkill.org] + +04/02/05 09:11:17 david [1067] + * trunk/actionpack/CHANGELOG (modified) + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/actionpack/lib/action_controller/scaffolding.rb (modified) + * trunk/actionpack/lib/action_controller/templates/scaffolds/list.rhtml (modified) + * trunk/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb (modified) + * trunk/railties/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml (modified) + Added pagination for scaffolding (10 items per page) #964 + [mortonda@dgrmm.net] + +03/31/05 14:46:11 david [1048] + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + Improved the message display on the exception handler pages #963 + [Johan Sorensen] + +03/27/05 00:04:07 david [1017] + * trunk/actionpack/CHANGELOG (modified) + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + Fixed that pagination_helper would ignore :params #947 [Sebastian + Kanthak] + +03/22/05 13:09:44 david [976] + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + Fixed documentation and prepared for 0.11.0 release + +03/21/05 14:35:36 david [967] + * trunk/actionpack/lib/action_controller/pagination.rb (modified) + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified) + Tweaked the documentation + +03/20/05 23:12:05 david [949] + * trunk/actionpack/CHANGELOG (modified) + * trunk/actionpack/lib/action_controller.rb (modified) + * trunk/actionpack/lib/action_controller/pagination.rb (added) + * trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (added) + * trunk/activesupport/lib/active_support/core_ext/kernel.rb (added) + Added pagination support through both a controller and helper add-on + #817 [Sam Stephenson] diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1fa67dac1aa9c162206c0f56eb10970df326cd79.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1fa67dac1aa9c162206c0f56eb10970df326cd79.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +
+<%= watcher_tag(@wiki, User.current) %> +
+ +

<%= l(:label_index_by_title) %>

+ +<% if @pages.empty? %> +

<%= l(:label_no_data) %>

+<% end %> + +<%= render_page_hierarchy(@pages_by_parent_id, nil, :timestamp => true) %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% unless @pages.empty? %> +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> + <%= f.link_to('HTML', :url => {:action => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %> +<% end %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1fb867d43b925bd44b6fa06a149ecabad4787c36.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1fb867d43b925bd44b6fa06a149ecabad4787c36.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,141 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'admin_controller' + +# Re-raise errors caught by the controller. +class AdminController; def rescue_action(e) raise e end; end + +class AdminControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles + + def setup + @controller = AdminController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 1 # admin + end + + def test_index + get :index + assert_no_tag :tag => 'div', + :attributes => { :class => /nodata/ } + end + + def test_index_with_no_configuration_data + delete_configuration_data + get :index + assert_tag :tag => 'div', + :attributes => { :class => /nodata/ } + end + + def test_projects + get :projects + assert_response :success + assert_template 'projects' + assert_not_nil assigns(:projects) + # active projects only + assert_nil assigns(:projects).detect {|u| !u.active?} + end + + def test_projects_with_name_filter + get :projects, :name => 'store', :status => '' + assert_response :success + assert_template 'projects' + projects = assigns(:projects) + assert_not_nil projects + assert_equal 1, projects.size + assert_equal 'OnlineStore', projects.first.name + end + + def test_load_default_configuration_data + delete_configuration_data + post :default_configuration, :lang => 'fr' + assert_response :redirect + assert_nil flash[:error] + assert IssueStatus.find_by_name('Nouveau') + end + + def test_test_email + get :test_email + assert_redirected_to '/settings/edit?tab=notifications' + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + user = User.find(1) + assert_equal [user.mail], mail.bcc + end + + def test_no_plugins + Redmine::Plugin.clear + + get :plugins + assert_response :success + assert_template 'plugins' + end + + def test_plugins + # Register a few plugins + Redmine::Plugin.register :foo do + name 'Foo plugin' + author 'John Smith' + description 'This is a test plugin' + version '0.0.1' + settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings' + end + Redmine::Plugin.register :bar do + end + + get :plugins + assert_response :success + assert_template 'plugins' + + assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' } + assert_tag :td, :child => { :tag => 'span', :content => 'Bar' } + end + + def test_info + get :info + assert_response :success + assert_template 'info' + end + + def test_admin_menu_plugin_extension + Redmine::MenuManager.map :admin_menu do |menu| + menu.push :test_admin_menu_plugin_extension, '/foo/bar', :caption => 'Test' + end + + get :index + assert_response :success + assert_tag :a, :attributes => { :href => '/foo/bar' }, + :content => 'Test' + + Redmine::MenuManager.map :admin_menu do |menu| + menu.delete :test_admin_menu_plugin_extension + end + end + + private + + def delete_configuration_data + Role.delete_all('builtin = 0') + Tracker.delete_all + IssueStatus.delete_all + Enumeration.delete_all + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1fcb69836707f0f2797567ced5c5da34d64949eb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1fcb69836707f0f2797567ced5c5da34d64949eb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +
+ <%= link_to l(:label_version_new), new_project_version_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_versions, @project) %> +
+ +

<%=l(:label_roadmap)%>

+ +<% if @versions.empty? %> +

<%= l(:label_no_data) %>

+<% else %> +
+<% @versions.each do |version| %> +

<%= tag 'a', :name => h(version.name) %><%= link_to_version version %>

+ <%= render :partial => 'versions/overview', :locals => {:version => version} %> + <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %> + + <% if (issues = @issues_by_version[version]) && issues.size > 0 %> + <% form_tag({}) do -%> + + + <% issues.each do |issue| -%> + + + + + <% end -%> + + <% end %> + <% end %> + <%= call_hook :view_projects_roadmap_version_bottom, :version => version %> +<% end %> +
+<% end %> + +<% content_for :sidebar do %> +<% form_tag({}, :method => :get) do %> +

<%= l(:label_roadmap) %>

+<% @trackers.each do |tracker| %> +
+<% end %> +
+ +<% if @project.descendants.active.any? %> + <%= hidden_field_tag 'with_subprojects', 0 %> +
+<% end %> +

<%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %>

+<% end %> + +

<%= l(:label_version_plural) %>

+<% @versions.each do |version| %> +<%= link_to format_version_name(version), "##{version.name}" %>
+<% end %> +<% end %> + +<% html_title(l(:label_roadmap)) %> + +<%= context_menu issues_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/1f/1feeecc995893880348eca32af1a4a9f7f1dfb97.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/1f/1feeecc995893880348eca32af1a4a9f7f1dfb97.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the classic_pagination plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the classic_pagination plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'Pagination' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/202b3d81f943caf51ec23281dde3cf26313ba319.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/202b3d81f943caf51ec23281dde3cf26313ba319.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

<%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=l(:label_enumeration_new)%>

+ +<% form_tag({:action => 'create'}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/203354fef0dd03fc1221f8cc6deebda05ad78e34.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/203354fef0dd03fc1221f8cc6deebda05ad78e34.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,248 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/208e5f65518788d2e8e359431914f6d85fea6a8a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/208e5f65518788d2e8e359431914f6d85fea6a8a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class Change < ActiveRecord::Base + generator_for :action => 'A' + generator_for :path, :start => 'test/dir/aaa0001' + generator_for :changeset, :method => :generate_changeset + + def self.generate_changeset + Changeset.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/2098d41250dd6484652b4b39b955e37f96aa4bb6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/2098d41250dd6484652b4b39b955e37f96aa4bb6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,114 @@ + +require 'active_record' + +module ActiveRecord + class Base + include Redmine::I18n + + # Translate attribute names for validation errors display + def self.human_attribute_name(attr) + l("field_#{attr.to_s.gsub(/_id$/, '')}", :default => attr) + end + end +end + +module ActiveRecord + class Errors + def full_messages(options = {}) + full_messages = [] + + @errors.each_key do |attr| + @errors[attr].each do |message| + next unless message + + if attr == "base" + full_messages << message + elsif attr == "custom_values" + # Replace the generic "custom values is invalid" + # with the errors on custom values + @base.custom_values.each do |value| + value.errors.each do |attr, msg| + full_messages << value.custom_field.name + ' ' + msg + end + end + else + attr_name = @base.class.human_attribute_name(attr) + full_messages << attr_name + ' ' + message.to_s + end + end + end + full_messages + end + end +end + +module ActionView + module Helpers + module DateHelper + # distance_of_time_in_words breaks when difference is greater than 30 years + def distance_of_date_in_words(from_date, to_date = 0, options = {}) + from_date = from_date.to_date if from_date.respond_to?(:to_date) + to_date = to_date.to_date if to_date.respond_to?(:to_date) + distance_in_days = (to_date - from_date).abs + + I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale| + case distance_in_days + when 0..60 then locale.t :x_days, :count => distance_in_days.round + when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round + else locale.t :over_x_years, :count => (distance_in_days / 365).floor + end + end + end + end + end +end + +ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } + +module AsynchronousMailer + # Adds :async_smtp and :async_sendmail delivery methods + # to perform email deliveries asynchronously + %w(smtp sendmail).each do |type| + define_method("perform_delivery_async_#{type}") do |mail| + Thread.start do + send "perform_delivery_#{type}", mail + end + end + end + + # Adds a delivery method that writes emails in tmp/emails for testing purpose + def perform_delivery_tmp_file(mail) + dest_dir = File.join(Rails.root, 'tmp', 'emails') + Dir.mkdir(dest_dir) unless File.directory?(dest_dir) + File.open(File.join(dest_dir, mail.message_id.gsub(/[<>]/, '') + '.eml'), 'wb') {|f| f.write(mail.encoded) } + end +end + +ActionMailer::Base.send :include, AsynchronousMailer + +module TMail + # TMail::Unquoter.convert_to_with_fallback_on_iso_8859_1 introduced in TMail 1.2.7 + # triggers a test failure in test_add_issue_with_japanese_keywords(MailHandlerTest) + class Unquoter + class << self + alias_method :convert_to, :convert_to_without_fallback_on_iso_8859_1 + end + end + + # Patch for TMail 1.2.7. See http://www.redmine.org/issues/8751 + class Encoder + def puts_meta(str) + add_text str + end + end +end + +module ActionController + module MimeResponds + class Responder + def api(&block) + any(:xml, :json, &block) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/209fcd763bfca52abf9e73764eaee81d9b518614.svn-base Binary file .svn/pristine/20/209fcd763bfca52abf9e73764eaee81d9b518614.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/20a7321b833bdd91a5023c5357f95fd8e6250105.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/20a7321b833bdd91a5023c5357f95fd8e6250105.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class CreateMemberRoles < ActiveRecord::Migration + def self.up + create_table :member_roles do |t| + t.column :member_id, :integer, :null => false + t.column :role_id, :integer, :null => false + end + end + + def self.down + drop_table :member_roles + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/20a8f32ebf22a3e29b295b2e4b3d7f7f733c27fa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/20a8f32ebf22a3e29b295b2e4b3d7f7f733c27fa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +#!/usr/bin/env ruby \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/20/20bbceb95e51f40dbb36d0ff4569d0437a37f449.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/20/20bbceb95e51f40dbb36d0ff4569d0437a37f449.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar SL language +// Author: Jernej Vidmar, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Nedelja", + "Ponedeljek", + "Torek", + "Sreda", + "Četrtek", + "Petek", + "Sobota", + "Nedelja"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ned", + "Pon", + "Tor", + "Sre", + "Čet", + "Pet", + "Sob", + "Ned"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Marec", + "April", + "Maj", + "Junij", + "Julij", + "Avgust", + "September", + "Oktober", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Maj", + "Jun", + "Jul", + "Avg", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O koledarju"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Izbira datuma:\n" + +"- Uporabite \xab, \xbb gumbe za izbiro leta\n" + +"- Uporabite " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " gumbe za izbiro meseca\n" + +"- Za hitrejšo izbiro držite miškin gumb nad enim od zgornjih gumbov."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Izbira časa:\n" + +"- Kliknite na katerikoli del časa da ga povečate\n" + +"- oziroma kliknite s Shiftom za znižanje\n" + +"- ali kliknite in vlecite za hitrejšo izbiro."; + +Calendar._TT["PREV_YEAR"] = "Prejšnje leto (držite za meni)"; +Calendar._TT["PREV_MONTH"] = "Prejšnji mesec (držite za meni)"; +Calendar._TT["GO_TODAY"] = "Pojdi na danes"; +Calendar._TT["NEXT_MONTH"] = "Naslednji mesec (držite za meni)"; +Calendar._TT["NEXT_YEAR"] = "Naslednje leto (držite za meni)"; +Calendar._TT["SEL_DATE"] = "Izberite datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Povlecite za premik"; +Calendar._TT["PART_TODAY"] = " (danes)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Najprej prikaži %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zapri"; +Calendar._TT["TODAY"] = "Danes"; +Calendar._TT["TIME_PART"] = "(Shift-)klik ali povleči, da spremeniš vrednost"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Time:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/210ed78bd5324335e5f6bf0efa5404a9438fd74c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/210ed78bd5324335e5f6bf0efa5404a9438fd74c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +
+<% i = 0 %> +<% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %> +<% @issue.custom_field_values.each do |value| %> +

<%= custom_field_tag_with_label :issue, value %>

+<% if i == split_on -%> +
+<% end -%> +<% i += 1 -%> +<% end -%> +
+
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/21220872c05ed094a0e17dfec9147a1d8f235a7a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/21220872c05ed094a0e17dfec9147a1d8f235a7a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class Meeting < ActiveRecord::Base + belongs_to :project + + acts_as_event :title => Proc.new {|o| "#{o.scheduled_on} Meeting"}, + :datetime => :scheduled_on, + :author => nil, + :url => Proc.new {|o| {:controller => 'meetings', :action => 'show', :id => o.id}} + + acts_as_activity_provider :timestamp => 'scheduled_on', + :find_options => { :include => :project } +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/217d8edc342d8c96ea1e479a7157b0c862da5448.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/217d8edc342d8c96ea1e479a7157b0c862da5448.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,110 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'members_controller' + +# Re-raise errors caught by the controller. +class MembersController; def rescue_action(e) raise e end; end + + +class MembersControllerTest < ActionController::TestCase + fixtures :projects, :members, :member_roles, :roles, :users + + def setup + @controller = MembersController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 2 + end + + def test_create + assert_difference 'Member.count' do + post :new, :id => 1, :member => {:role_ids => [1], :user_id => 7} + end + assert_redirected_to '/projects/ecookbook/settings/members' + assert User.find(7).member_of?(Project.find(1)) + end + + def test_create_multiple + assert_difference 'Member.count', 3 do + post :new, :id => 1, :member => {:role_ids => [1], :user_ids => [7, 8, 9]} + end + assert_redirected_to '/projects/ecookbook/settings/members' + assert User.find(7).member_of?(Project.find(1)) + end + + def test_xhr_create + assert_difference 'Member.count', 3 do + post :new, :format => "js", :id => 1, :member => {:role_ids => [1], :user_ids => [7, 8, 9]} + end + assert_select_rjs :replace_html, 'tab-content-members' + assert User.find(7).member_of?(Project.find(1)) + assert User.find(8).member_of?(Project.find(1)) + assert User.find(9).member_of?(Project.find(1)) + end + + def test_xhr_create_with_failure + assert_no_difference 'Member.count' do + post :new, :format => "js", :id => 1, :member => {:role_ids => [], :user_ids => [7, 8, 9]} + end + assert_select '#tab-content-members', 0 + assert @response.body.match(/alert/i), "Alert message not sent" + end + + def test_edit + assert_no_difference 'Member.count' do + post :edit, :id => 2, :member => {:role_ids => [1], :user_id => 3} + end + assert_redirected_to '/projects/ecookbook/settings/members' + end + + def test_xhr_edit + assert_no_difference 'Member.count' do + xhr :post, :edit, :id => 2, :member => {:role_ids => [1], :user_id => 3} + end + assert_select_rjs :replace_html, 'tab-content-members' + member = Member.find(2) + assert_equal [1], member.role_ids + assert_equal 3, member.user_id + end + + def test_destroy + assert_difference 'Member.count', -1 do + post :destroy, :id => 2 + end + assert_redirected_to '/projects/ecookbook/settings/members' + assert !User.find(3).member_of?(Project.find(1)) + end + + def test_xhr_destroy + assert_difference 'Member.count', -1 do + xhr :post, :destroy, :id => 2 + end + assert_select_rjs :replace_html, 'tab-content-members' + end + + def test_autocomplete_for_member + get :autocomplete_for_member, :id => 1, :q => 'mis' + assert_response :success + assert_template 'autocomplete_for_member' + + assert_tag :label, :content => /User Misc/, + :child => { :tag => 'input', :attributes => { :name => 'member[user_ids][]', :value => '8' } } + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/21b3541d41cf9ffb7dea58d79751f0eb3553a55b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/21b3541d41cf9ffb7dea58d79751f0eb3553a55b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +#context-menu li.folder ul { left:auto; right:168px; } +#context-menu li.folder>ul { left:auto; right:148px; } +#context-menu li a.submenu { background:url("../images/bullet_arrow_left.png") left no-repeat; } + +#context-menu a { + background-position: 100% 40%; + padding-right: 20px; + padding-left: 0px; +} diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/21bb59308736cf64ef50e8df95a55241d5b3beeb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/21bb59308736cf64ef50e8df95a55241d5b3beeb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +
+<%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> +
+ +

<%=l(:label_user_plural)%>

+ +<% form_tag({}, :method => :get) do %> +
<%= l(:label_filter_plural) %> + +<%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + +<% if @groups.present? %> + +<%= select_tag 'group_id', '' + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %> +<% end %> + + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %> +<%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %> +
+<% end %> +  + +
+ + + <%= sort_header_tag('login', :caption => l(:field_login)) %> + <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> + <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> + <%= sort_header_tag('mail', :caption => l(:field_mail)) %> + <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %> + <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> + <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %> + + + +<% for user in @users -%> + <%= %w(anon active registered locked)[user.status] %>"> + + + + + + + + + +<% end -%> + +
<%= avatar(user, :size => "14") %><%= link_to h(user.login), edit_user_path(user) %><%= h(user.firstname) %><%= h(user.lastname) %><%= checked_image user.admin? %><%= format_time(user.created_on) %> + <%= change_status_link(user) %> + <%= link_to(l(:button_delete), user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') unless User.current == user %> +
+
+

<%= pagination_links_full @user_pages, @user_count %>

+ +<% html_title(l(:label_user_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/21e12c0e1e71e0c4f94a4c58d91a04399075123a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/21e12c0e1e71e0c4f94a4c58d91a04399075123a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new +config.log_level = :info + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable mail delivery +config.action_mailer.perform_deliveries = false +config.action_mailer.raise_delivery_errors = false + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/21/21f67f445a6c5a2512b4712ac66209391d37efdc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/21/21f67f445a6c5a2512b4712ac66209391d37efdc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,241 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/abstract_adapter' +require 'rexml/document' + +module Redmine + module Scm + module Adapters + class DarcsAdapter < AbstractAdapter + # Darcs executable name + DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs" + + class << self + def client_command + @@bin ||= DARCS_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (darcs_binary_version || []) + end + + def client_available + !client_version.empty? + end + + def darcs_binary_version + darcsversion = darcs_binary_version_from_command_line.dup + if darcsversion.respond_to?(:force_encoding) + darcsversion.force_encoding('ASCII-8BIT') + end + if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def darcs_binary_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @url = url + @root_url = url + end + + def supports_cat? + # cat supported in darcs 2.0.0 and higher + self.class.client_version_above?([2, 0, 0]) + end + + # Get info about the darcs repository + def info + rev = revisions(nil,nil,nil,{:limit => 1}) + rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + path_prefix = (path.blank? ? '' : "#{path}/") + if path.blank? + path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' ) + end + entries = Entries.new + cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --xml-output" + cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier + cmd << " #{shell_quote path}" + shellout(cmd) do |io| + begin + doc = REXML::Document.new(io) + if doc.root.name == 'directory' + doc.elements.each('directory/*') do |element| + next unless ['file', 'directory'].include? element.name + entries << entry_from_xml(element, path_prefix) + end + elsif doc.root.name == 'file' + entries << entry_from_xml(doc.root, path_prefix) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + entries.compact.sort_by_name + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path = '.' if path.blank? + revisions = Revisions.new + cmd = "#{self.class.sq_bin} changes --repodir #{shell_quote @url} --xml-output" + cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from + cmd << " --last #{options[:limit].to_i}" if options[:limit] + shellout(cmd) do |io| + begin + doc = REXML::Document.new(io) + doc.elements.each("changelog/patch") do |patch| + message = patch.elements['name'].text + message << "\n" + patch.elements['comment'].text.gsub(/\*\*\*END OF DESCRIPTION\*\*\*.*\z/m, '') if patch.elements['comment'] + revisions << Revision.new({:identifier => nil, + :author => patch.attributes['author'], + :scmid => patch.attributes['hash'], + :time => Time.parse(patch.attributes['local_date']), + :message => message, + :paths => (options[:with_path] ? get_paths_for_patch(patch.attributes['hash']) : nil) + }) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + revisions + end + + def diff(path, identifier_from, identifier_to=nil) + path = '*' if path.blank? + cmd = "#{self.class.sq_bin} diff --repodir #{shell_quote @url}" + if identifier_to.nil? + cmd << " --match #{shell_quote("hash #{identifier_from}")}" + else + cmd << " --to-match #{shell_quote("hash #{identifier_from}")}" + cmd << " --from-match #{shell_quote("hash #{identifier_to}")}" + end + cmd << " -u #{shell_quote path}" + diff = [] + shellout(cmd) do |io| + io.each_line do |line| + diff << line + end + end + return nil if $? && $?.exitstatus != 0 + diff + end + + def cat(path, identifier=nil) + cmd = "#{self.class.sq_bin} show content --repodir #{shell_quote @url}" + cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier + cmd << " #{shell_quote path}" + cat = nil + shellout(cmd) do |io| + io.binmode + cat = io.read + end + return nil if $? && $?.exitstatus != 0 + cat + end + + private + + # Returns an Entry from the given XML element + # or nil if the entry was deleted + def entry_from_xml(element, path_prefix) + modified_element = element.elements['modified'] + if modified_element.elements['modified_how'].text.match(/removed/) + return nil + end + + Entry.new({:name => element.attributes['name'], + :path => path_prefix + element.attributes['name'], + :kind => element.name == 'file' ? 'file' : 'dir', + :size => nil, + :lastrev => Revision.new({ + :identifier => nil, + :scmid => modified_element.elements['patch'].attributes['hash'] + }) + }) + end + + def get_paths_for_patch(hash) + paths = get_paths_for_patch_raw(hash) + if self.class.client_version_above?([2, 4]) + orig_paths = paths + paths = [] + add_paths = [] + add_paths_name = [] + mod_paths = [] + other_paths = [] + orig_paths.each do |path| + if path[:action] == 'A' + add_paths << path + add_paths_name << path[:path] + elsif path[:action] == 'M' + mod_paths << path + else + other_paths << path + end + end + add_paths_name.each do |add_path| + mod_paths.delete_if { |m| m[:path] == add_path } + end + paths.concat add_paths + paths.concat mod_paths + paths.concat other_paths + end + paths + end + + # Retrieve changed paths for a single patch + def get_paths_for_patch_raw(hash) + cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --summary --xml-output" + cmd << " --match #{shell_quote("hash #{hash}")} " + paths = [] + shellout(cmd) do |io| + begin + # Darcs xml output has multiple root elements in this case (tested with darcs 1.0.7) + # A root element is added so that REXML doesn't raise an error + doc = REXML::Document.new("" + io.read + "") + doc.elements.each('fake_root/summary/*') do |modif| + paths << {:action => modif.name[0,1].upcase, + :path => "/" + modif.text.chomp.gsub(/^\s*/, '') + } + end + rescue + end + end + paths + rescue CommandFailed + paths + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/22/2239f10ea5e4bc85a8ddbe53928f7d28bb9ad174.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/22/2239f10ea5e4bc85a8ddbe53928f7d28bb9ad174.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class Tracker < ActiveRecord::Base + generator_for :name, :start => 'Tracker 0' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/22/22b9b82e18b167082c2226e7df0cb9180f63ea6e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/22/22b9b82e18b167082c2226e7df0cb9180f63ea6e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,80 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sat, 21 Jun 2008 18:41:39 +0200 +Message-ID: <006a01c8d3bd$ad9baec0$0a00a8c0@osiris> +From: "John Smith" +To: +References: <485d0ad366c88_d7014663a025f@osiris.tmail> +Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories +Date: Sat, 21 Jun 2008 18:41:39 +0200 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_NextPart_000_0067_01C8D3CE.711F9CC0" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +This is a multi-part message in MIME format. + +------=_NextPart_000_0067_01C8D3CE.711F9CC0 +Content-Type: text/plain; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +This is reply + +Status: Resolved +due date: 2010-12-31 +Start Date:2010-01-01 +Assigned to: jsmith@somenet.foo +float field: 52.6 + +------=_NextPart_000_0067_01C8D3CE.711F9CC0 +Content-Type: text/html; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +=EF=BB=BF + + + + + + +
This is=20 +reply Status: Resolved
+ +------=_NextPart_000_0067_01C8D3CE.711F9CC0-- + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/23/2330bc88f1bd2ce1c1b2bfa4d60a6eb823530bd2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/23/2330bc88f1bd2ce1c1b2bfa4d60a6eb823530bd2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,182 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) + +class Redmine::MenuManager::MapperTest < ActiveSupport::TestCase + context "Mapper#initialize" do + should "be tested" + end + + def test_push_onto_root + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + + menu_mapper.exists?(:test_overview) + end + + def test_push_onto_parent + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent => :test_overview} + + assert menu_mapper.exists?(:test_child) + assert_equal :test_child, menu_mapper.find(:test_child).name + end + + def test_push_onto_grandparent + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent => :test_overview} + menu_mapper.push :test_grandchild, { :controller => 'projects', :action => 'show'}, {:parent => :test_child} + + assert menu_mapper.exists?(:test_grandchild) + grandchild = menu_mapper.find(:test_grandchild) + assert_equal :test_grandchild, grandchild.name + assert_equal :test_child, grandchild.parent.name + end + + def test_push_first + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {:first => true} + + root = menu_mapper.find(:root) + assert_equal 5, root.children.size + {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name| + assert_not_nil root.children[position] + assert_equal name, root.children[position].name + end + + end + + def test_push_before + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {:before => :test_fourth} + + root = menu_mapper.find(:root) + assert_equal 5, root.children.size + {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name| + assert_not_nil root.children[position] + assert_equal name, root.children[position].name + end + + end + + def test_push_after + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {:after => :test_third} + + root = menu_mapper.find(:root) + assert_equal 5, root.children.size + {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name| + assert_not_nil root.children[position] + assert_equal name, root.children[position].name + end + + end + + def test_push_last + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_second, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_third, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {:last => true} + menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {} + + root = menu_mapper.find(:root) + assert_equal 5, root.children.size + {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name| + assert_not_nil root.children[position] + assert_equal name, root.children[position].name + end + + end + + def test_exists_for_child_node + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + menu_mapper.push :test_child, { :controller => 'projects', :action => 'show'}, {:parent => :test_overview } + + assert menu_mapper.exists?(:test_child) + end + + def test_exists_for_invalid_node + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + + assert !menu_mapper.exists?(:nothing) + end + + def test_find + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + + item = menu_mapper.find(:test_overview) + assert_equal :test_overview, item.name + assert_equal({:controller => 'projects', :action => 'show'}, item.url) + end + + def test_find_missing + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + + item = menu_mapper.find(:nothing) + assert_equal nil, item + end + + def test_delete + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + assert_not_nil menu_mapper.delete(:test_overview) + + assert_nil menu_mapper.find(:test_overview) + end + + def test_delete_missing + menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) + assert_nil menu_mapper.delete(:test_missing) + end + + test 'deleting all items' do + # Exposed by deleting :last items + Redmine::MenuManager.map :test_menu do |menu| + menu.push :not_last, Redmine::Info.help_url + menu.push :administration, { :controller => 'projects', :action => 'show'}, {:last => true} + menu.push :help, Redmine::Info.help_url, :last => true + end + + assert_nothing_raised do + Redmine::MenuManager.map :test_menu do |menu| + menu.delete(:administration) + menu.delete(:help) + menu.push :test_overview, { :controller => 'projects', :action => 'show'}, {} + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/23/234b87239a907c3661f562d48ce5a22b13fe4163.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/23/234b87239a907c3661f562d48ce5a22b13fe4163.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,99 @@ +# Translation of the bookmark class from the PHP FPDF script from Olivier Plathey +# Translated by Sylvain Lafleur and ?? with the help of Brian Ollenberger +# +# First added in 1.53b +# +# Usage is as follows: +# +# require 'fpdf' +# require 'bookmark' +# pdf = FPDF.new +# pdf.extend(PDF_Bookmark) +# +# This allows it to be combined with other extensions, such as the Chinese +# module. + +module PDF_Bookmark + def PDF_Bookmark.extend_object(o) + o.instance_eval('@outlines,@OutlineRoot=[],0') + super(o) + end + + def Bookmark(txt,level=0,y=0) + y=self.GetY() if y==-1 + @outlines.push({'t'=>txt,'l'=>level,'y'=>y,'p'=>self.PageNo()}) + end + + def putbookmarks + @nb=@outlines.size + return if @nb==0 + lru=[] + level=0 + @outlines.each_index do |i| + o=@outlines[i] + if o['l']>0 + parent=lru[o['l']-1] + # Set parent and last pointers + @outlines[i]['parent']=parent + @outlines[parent]['last']=i + if o['l']>level + # Level increasing: set first pointer + @outlines[parent]['first']=i + end + else + @outlines[i]['parent']=@nb + end + if o['l']<=level and i>0 + # Set prev and next pointers + prev=lru[o['l']] + @outlines[prev]['next']=i + @outlines[i]['prev']=prev + end + lru[o['l']]=i + level=o['l'] + end + # Outline items + n=@n+1 + @outlines.each_index do |i| + o=@outlines[i] + newobj + out('<>') + out('endobj') + end + # Outline root + newobj + @OutlineRoot=@n + out('<>') + out('endobj') + end + + def putresources + super + putbookmarks + end + + def putcatalog + super + if not @outlines.empty? + out('/Outlines '+@OutlineRoot.to_s+' 0 R') + out('/PageMode /UseOutlines') + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/23/239f83d29fc7b11e5679dea8261085d9a0c7a621.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/23/239f83d29fc7b11e5679dea8261085d9a0c7a621.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,49 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 #:nodoc: + module CoreExtensions #:nodoc: + module String #:nodoc: + # Custom string conversions + module Conversions + # Parses hours format and returns a float + def to_hours + s = self.dup + s.strip! + if s =~ %r{^(\d+([.,]\d+)?)h?$} + s = $1 + else + # 2:30 => 2.5 + s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 } + # 2h30, 2h, 30m => 2.5, 2, 0.5 + s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] } + end + # 2,5 => 2.5 + s.gsub!(',', '.') + begin; Kernel.Float(s); rescue; nil; end + end + + # Object#to_a removed in ruby1.9 + if RUBY_VERSION > '1.9' + def to_a + [self.dup] + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/23/23b009231ec6aa90fecfe01522aea6ff2ac84fb3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/23/23b009231ec6aa90fecfe01522aea6ff2ac84fb3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +

<%= l(:label_home) %>

+ +
+ <%= textilizable Setting.welcome_text %> + <% if @news.any? %> +
+

<%=l(:label_news_latest)%>

+ <%= render :partial => 'news/news', :collection => @news %> + <%= link_to l(:label_news_view_all), :controller => 'news' %> +
+ <% end %> + <%= call_hook(:view_welcome_index_left, :projects => @projects) %> +
+ +
+ <% if @projects.any? %> +
+

<%=l(:label_project_latest)%>

+
    + <% for project in @projects %> + <% @project = project %> +
  • + <%= link_to_project project %> (<%= format_time(project.created_on) %>) + <%= textilizable project.short_description, :project => project %> +
  • + <% end %> + <% @project = nil %> +
+
+ <% end %> + <%= call_hook(:view_welcome_index_right, :projects => @projects) %> +
+ +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<%= auto_discovery_link_tag(:atom, {:controller => 'news', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, + :title => "#{Setting.app_title}: #{l(:label_news_latest)}") %> +<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, + :title => "#{Setting.app_title}: #{l(:label_activity)}") %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/23/23ef48c3079c4ad7ff9c6850f3a7bce6b2c94752.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/23/23ef48c3079c4ad7ff9c6850f3a7bce6b2c94752.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +<% form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params) %> +
+ + + + +<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %> +<%= sort_header_tag('user', :caption => l(:label_member)) %> +<%= sort_header_tag('activity', :caption => l(:label_activity)) %> +<%= sort_header_tag('project', :caption => l(:label_project)) %> +<%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %> + +<%= sort_header_tag('hours', :caption => l(:field_hours)) %> + + + + +<% entries.each do |entry| -%> + hascontextmenu"> + + + + + + + + + + +<% end -%> + +
+ <%= link_to image_tag('toggle_check.png'), + {}, + :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> +<%= l(:field_comments) %>
<%= check_box_tag("ids[]", entry.id, false, :id => nil) %><%= format_date(entry.spent_on) %><%= link_to_user(entry.user) %><%=h entry.activity %><%= link_to_project(entry.project) %> +<% if entry.issue -%> +<%= entry.issue.visible? ? link_to_issue(entry.issue, :truncate => 50) : "##{entry.issue.id}" -%> +<% end -%> +<%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> +<% if entry.editable_by?(User.current) -%> + <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry, :project_id => nil}, + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry, :project_id => nil}, + :confirm => l(:text_are_you_sure), + :method => :delete, + :title => l(:button_delete) %> +<% end -%> +
+
+<% end -%> + +<%= context_menu time_entries_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/23/23f71ac728c941d3ffe5e3105dc856980b211079.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/23/23f71ac728c941d3ffe5e3105dc856980b211079.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +plugin mail template loaded from application \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/243de4e756633dfdaa9bf4c362c62553c376fead.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/243de4e756633dfdaa9bf4c362c62553c376fead.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 GanttHelper + + def gantt_zoom_link(gantt, in_or_out) + case in_or_out + when :in + if gantt.zoom < 4 + link_to_content_update l(:text_zoom_in), + params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), + :class => 'icon icon-zoom-in' + else + content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe + end + + when :out + if gantt.zoom > 1 + link_to_content_update l(:text_zoom_out), + params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), + :class => 'icon icon-zoom-out' + else + content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/244393349ccf9a5e6e3ea60c976d07e62fd15de2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/244393349ccf9a5e6e3ea60c976d07e62fd15de2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +

<%= l(:mail_body_wiki_content_added, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), + :author => h(@wiki_content.author)) %>
+<%=h @wiki_content.comments %>

diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/244c888e0b10e75677f5d843ff3bbb49ca914d36.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/244c888e0b10e75677f5d843ff3bbb49ca914d36.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1013 @@ +# Hebrew translation for Redmine +# Initiated by Dotan Nahum (dipidi@gmail.com) +# Jul 2010 - Updated by Orgad Shaneh (orgads@gmail.com) + +he: + direction: rtl + date: + formats: + default: "%d/%m/%Y" + short: "%d/%m" + long: "%d/%m/%Y" + only_day: "%e" + + day_names: [ראשון, שני, שלישי, רביעי, חמישי, שישי, שבת] + abbr_day_names: ["א'", "ב'", "ג'", "ד'", "ה'", "ו'", "ש'"] + month_names: [~, ינואר, פברואר, מרץ, אפריל, מאי, יוני, יולי, אוגוסט, ספטמבר, אוקטובר, נובמבר, דצמבר] + abbr_month_names: [~, יאנ, פבר, מרץ, אפר, מאי, יונ, יול, אוג, ספט, אוק, נוב, דצמ] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a %d/%m/%Y %H:%M:%S" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + only_second: "%S" + + datetime: + formats: + default: "%d-%m-%YT%H:%M:%S%Z" + + am: 'am' + pm: 'pm' + + datetime: + distance_in_words: + half_a_minute: 'חצי דקה' + less_than_x_seconds: + zero: 'פחות משניה' + one: 'פחות משניה' + other: 'פחות מ־%{count} שניות' + x_seconds: + one: 'שניה אחת' + other: '%{count} שניות' + less_than_x_minutes: + zero: 'פחות מדקה אחת' + one: 'פחות מדקה אחת' + other: 'פחות מ־%{count} דקות' + x_minutes: + one: 'דקה אחת' + other: '%{count} דקות' + about_x_hours: + one: 'בערך שעה אחת' + other: 'בערך %{count} שעות' + x_days: + one: 'יום אחד' + other: '%{count} ימים' + about_x_months: + one: 'בערך חודש אחד' + other: 'בערך %{count} חודשים' + x_months: + one: 'חודש אחד' + other: '%{count} חודשים' + about_x_years: + one: 'בערך שנה אחת' + other: 'בערך %{count} שנים' + over_x_years: + one: 'מעל שנה אחת' + other: 'מעל %{count} שנים' + almost_x_years: + one: "כמעט שנה" + other: "כמעט %{count} שנים" + + number: + format: + precision: 3 + separator: '.' + delimiter: ',' + currency: + format: + unit: 'ש"ח' + precision: 2 + format: '%u %n' + human: + storage_units: + format: "%n %u" + units: + byte: + one: "בייט" + other: "בתים" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "וגם" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "לא נכלל ברשימה" + exclusion: "לא זמין" + invalid: "לא ולידי" + confirmation: "לא תואם לאישור" + accepted: "חייב באישור" + empty: "חייב להכלל" + blank: "חייב להכלל" + too_long: "ארוך מדי (לא יותר מ־%{count} תוים)" + too_short: "קצר מדי (לא יותר מ־%{count} תוים)" + wrong_length: "לא באורך הנכון (חייב להיות %{count} תוים)" + taken: "לא זמין" + not_a_number: "הוא לא מספר" + greater_than: "חייב להיות גדול מ־%{count}" + greater_than_or_equal_to: "חייב להיות גדול או שווה ל־%{count}" + equal_to: "חייב להיות שווה ל־%{count}" + less_than: "חייב להיות קטן מ־%{count}" + less_than_or_equal_to: "חייב להיות קטן או שווה ל־%{count}" + odd: "חייב להיות אי זוגי" + even: "חייב להיות זוגי" + greater_than_start_date: "חייב להיות מאוחר יותר מתאריך ההתחלה" + not_same_project: "לא שייך לאותו הפרויקט" + circular_dependency: "קשר זה יצור תלות מעגלית" + cant_link_an_issue_with_a_descendant: "לא ניתן לקשר נושא לתת־משימה שלו" + + actionview_instancetag_blank_option: בחר בבקשה + + general_text_No: 'לא' + general_text_Yes: 'כן' + general_text_no: 'לא' + general_text_yes: 'כן' + general_lang_name: 'Hebrew (עברית)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: החשבון עודכן בהצלחה! + notice_account_invalid_creditentials: שם משתמש או סיסמה שגויים + notice_account_password_updated: הסיסמה עודכנה בהצלחה! + notice_account_wrong_password: סיסמה שגויה + notice_account_register_done: החשבון נוצר בהצלחה. להפעלת החשבון לחץ על הקישור שנשלח לדוא"ל שלך. + notice_account_unknown_email: משתמש לא מוכר. + notice_can_t_change_password: החשבון הזה משתמש במקור הזדהות חיצוני. שינוי סיסמה הינו בילתי אפשר + notice_account_lost_email_sent: דוא"ל עם הוראות לבחירת סיסמה חדשה נשלח אליך. + notice_account_activated: חשבונך הופעל. אתה יכול להתחבר כעת. + notice_successful_create: יצירה מוצלחת. + notice_successful_update: עידכון מוצלח. + notice_successful_delete: מחיקה מוצלחת. + notice_successful_connection: חיבור מוצלח. + notice_file_not_found: הדף שאתה מנסה לגשת אליו אינו קיים או שהוסר. + notice_locking_conflict: המידע עודכן על ידי משתמש אחר. + notice_not_authorized: אינך מורשה לראות דף זה. + notice_not_authorized_archived_project: הפרויקט שאתה מנסה לגשת אליו נמצא בארכיון. + notice_email_sent: "דואל נשלח לכתובת %{value}" + notice_email_error: "ארעה שגיאה בעת שליחת הדואל (%{value})" + notice_feeds_access_key_reseted: מפתח ה־RSS שלך אופס. + notice_api_access_key_reseted: מפתח הגישה שלך ל־API אופס. + notice_failed_to_save_issues: "נכשרת בשמירת %{count} נושאים ב %{total} נבחרו: %{ids}." + notice_failed_to_save_members: "כשלון בשמירת חבר(ים): %{errors}." + notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך." + notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת." + notice_default_data_loaded: אפשרויות ברירת מחדל מופעלות. + notice_unable_delete_version: לא ניתן למחוק גירסה + notice_unable_delete_time_entry: לא ניתן למחוק רשומת זמן. + notice_issue_done_ratios_updated: אחוזי התקדמות לנושא עודכנו. + + error_can_t_load_default_data: "אפשרויות ברירת המחדל לא הצליחו להיטען: %{value}" + error_scm_not_found: כניסה ו\או מהדורה אינם קיימים במאגר. + error_scm_command_failed: "ארעה שגיאה בעת ניסון גישה למאגר: %{value}" + error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." + error_issue_not_found_in_project: 'הנושאים לא נמצאו או אינם שיכים לפרויקט' + error_no_tracker_in_project: לא הוגדר סיווג לפרויקט זה. נא בדוק את הגדרות הפרויקט. + error_no_default_issue_status: לא מוגדר מצב ברירת מחדל לנושאים. נא בדוק את התצורה ("ניהול -> מצבי נושא"). + error_can_not_delete_custom_field: לא ניתן למחוק שדה מותאם אישית + error_can_not_delete_tracker: קיימים נושאים בסיווג זה, ולא ניתן למחוק אותו. + error_can_not_remove_role: תפקיד זה נמצא בשימוש, ולא ניתן למחוק אותו. + error_can_not_reopen_issue_on_closed_version: לא ניתן לפתוח מחדש נושא שמשויך לגירסה סגורה + error_can_not_archive_project: לא ניתן לארכב פרויקט זה + error_issue_done_ratios_not_updated: אחוז התקדמות לנושא לא עודכן. + error_workflow_copy_source: נא בחר סיווג או תפקיד מקור + error_workflow_copy_target: נא בחר תפקיד(ים) וסיווג(ים) + error_unable_delete_issue_status: לא ניתן למחוק מצב נושא + error_unable_to_connect: לא ניתן להתחבר (%{value}) + warning_attachments_not_saved: "כשלון בשמירת %{count} קבצים." + + mail_subject_lost_password: "סיסמת ה־%{value} שלך" + mail_body_lost_password: 'לשינו סיסמת ה־Redmine שלך, לחץ על הקישור הבא:' + mail_subject_register: "הפעלת חשבון %{value}" + mail_body_register: 'להפעלת חשבון ה־Redmine שלך, לחץ על הקישור הבא:' + mail_body_account_information_external: "אתה יכול להשתמש בחשבון %{value} כדי להתחבר" + mail_body_account_information: פרטי החשבון שלך + mail_subject_account_activation_request: "בקשת הפעלה לחשבון %{value}" + mail_body_account_activation_request: "משתמש חדש (%{value}) נרשם. החשבון שלו מחכה לאישור שלך:" + mail_subject_reminder: "%{count} נושאים מיועדים להגשה בימים הקרובים (%{days})" + mail_body_reminder: "%{count} נושאים שמיועדים אליך מיועדים להגשה בתוך %{days} ימים:" + mail_subject_wiki_content_added: "דף ה־wiki ‏'%{id}' נוסף" + mail_body_wiki_content_added: דף ה־wiki ‏'%{id}' נוסף ע"י %{author}. + mail_subject_wiki_content_updated: "דף ה־wiki ‏'%{id}' עודכן" + mail_body_wiki_content_updated: דף ה־wiki ‏'%{id}' עודכן ע"י %{author}. + + gui_validation_error: שגיאה 1 + gui_validation_error_plural: "%{count} שגיאות" + + field_name: שם + field_description: תיאור + field_summary: תקציר + field_is_required: נדרש + field_firstname: שם פרטי + field_lastname: שם משפחה + field_mail: דוא"ל + field_filename: קובץ + field_filesize: גודל + field_downloads: הורדות + field_author: כותב + field_created_on: נוצר + field_updated_on: עודכן + field_field_format: פורמט + field_is_for_all: לכל הפרויקטים + field_possible_values: ערכים אפשריים + field_regexp: ביטוי רגיל + field_min_length: אורך מינימאלי + field_max_length: אורך מקסימאלי + field_value: ערך + field_category: קטגוריה + field_title: כותרת + field_project: פרויקט + field_issue: נושא + field_status: מצב + field_notes: הערות + field_is_closed: נושא סגור + field_is_default: ערך ברירת מחדל + field_tracker: סיווג + field_subject: שם נושא + field_due_date: תאריך סיום + field_assigned_to: אחראי + field_priority: עדיפות + field_fixed_version: גירסת יעד + field_user: מתשמש + field_principal: מנהל + field_role: תפקיד + field_homepage: דף הבית + field_is_public: פומבי + field_parent: תת פרויקט של + field_is_in_roadmap: נושאים המוצגים במפת הדרכים + field_login: שם משתמש + field_mail_notification: הודעות דוא"ל + field_admin: ניהול + field_last_login_on: התחברות אחרונה + field_language: שפה + field_effective_date: תאריך + field_password: סיסמה + field_new_password: סיסמה חדשה + field_password_confirmation: אישור + field_version: גירסה + field_type: סוג + field_host: שרת + field_port: פורט + field_account: חשבון + field_base_dn: בסיס DN + field_attr_login: תכונת התחברות + field_attr_firstname: תכונת שם פרטים + field_attr_lastname: תכונת שם משפחה + field_attr_mail: תכונת דוא"ל + field_onthefly: יצירת משתמשים זריזה + field_start_date: תאריך התחלה + field_done_ratio: "% גמור" + field_auth_source: מקור הזדהות + field_hide_mail: החבא את כתובת הדוא"ל שלי + field_comments: הערות + field_url: URL + field_start_page: דף התחלתי + field_subproject: תת־פרויקט + field_hours: שעות + field_activity: פעילות + field_spent_on: תאריך + field_identifier: מזהה + field_is_filter: משמש כמסנן + field_issue_to: נושאים קשורים + field_delay: עיקוב + field_assignable: ניתן להקצות נושאים לתפקיד זה + field_redirect_existing_links: העבר קישורים קיימים + field_estimated_hours: זמן משוער + field_column_names: עמודות + field_time_entries: רישום זמנים + field_time_zone: איזור זמן + field_searchable: ניתן לחיפוש + field_default_value: ערך ברירת מחדל + field_comments_sorting: הצג הערות + field_parent_title: דף אב + field_editable: ניתן לעריכה + field_watcher: צופה + field_identity_url: כתובת OpenID + field_content: תוכן + field_group_by: קבץ את התוצאות לפי + field_sharing: שיתוף + field_parent_issue: משימת אב + field_text: שדה טקסט + + setting_app_title: כותרת ישום + setting_app_subtitle: תת־כותרת ישום + setting_welcome_text: טקסט "ברוך הבא" + setting_default_language: שפת ברירת מחדל + setting_login_required: דרושה הזדהות + setting_self_registration: אפשר הרשמה עצמית + setting_attachment_max_size: גודל דבוקה מקסימאלי + setting_issues_export_limit: גבול יצוא נושאים + setting_mail_from: כתובת שליחת דוא"ל + setting_bcc_recipients: מוסתר (bcc) + setting_plain_text_mail: טקסט פשוט בלבד (ללא HTML) + setting_host_name: שם שרת + setting_text_formatting: עיצוב טקסט + setting_wiki_compression: כיווץ היסטורית wiki + setting_feeds_limit: גבול תוכן הזנות + setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל + setting_autofetch_changesets: משיכה אוטומטית של שינויים + setting_sys_api_enabled: אפשר שירות רשת לניהול המאגר + setting_commit_ref_keywords: מילות מפתח מקשרות + setting_commit_fix_keywords: מילות מפתח מתקנות + setting_autologin: התחברות אוטומטית + setting_date_format: פורמט תאריך + setting_time_format: פורמט זמן + setting_cross_project_issue_relations: הרשה קישור נושאים בין פרויקטים + setting_issue_list_default_columns: עמודות ברירת מחדל המוצגות ברשימת הנושאים + setting_emails_footer: תחתית דוא"ל + setting_protocol: פרוטוקול + setting_per_page_options: אפשרויות אוביקטים לפי דף + setting_user_format: פורמט הצגת משתמשים + setting_activity_days_default: ימים המוצגים על פעילות הפרויקט + setting_display_subprojects_issues: הצג נושאים של תתי־פרויקטים כברירת מחדל + setting_enabled_scm: אפשר ניהול תצורה + setting_mail_handler_body_delimiters: חתוך כתובות דואר אחרי אחת משורות אלה + setting_mail_handler_api_enabled: אפשר שירות רשת לדואר נכנס + setting_mail_handler_api_key: מפתח API + setting_sequential_project_identifiers: השתמש במספרים עוקבים למזהי פרויקט + setting_gravatar_enabled: שימוש בצלמיות משתמשים מ־Gravatar + setting_gravatar_default: תמונת Gravatar ברירת מחדל + setting_diff_max_lines_displayed: מספר מירבי של שורות בתצוגת שינויים + setting_file_max_size_displayed: גודל מירבי של מלל המוצג בתוך השורה + setting_repository_log_display_limit: מספר מירבי של מהדורות המוצגות ביומן קובץ + setting_openid: אפשר התחברות ורישום באמצעות OpenID + setting_password_min_length: אורך סיסמה מינימאלי + setting_new_project_user_role_id: התפקיד שמוגדר למשתמש פשוט אשר יוצר פרויקט + setting_default_projects_modules: מודולים מאופשרים בברירת מחדל עבור פרויקטים חדשים + setting_issue_done_ratio: חשב אחוז התקדמות בנושא עם + setting_issue_done_ratio_issue_field: השתמש בשדה הנושא + setting_issue_done_ratio_issue_status: השתמש במצב הנושא + setting_start_of_week: השבוע מתחיל ביום + setting_rest_api_enabled: אפשר שירות רשת REST + setting_cache_formatted_text: שמור טקסט מעוצב במטמון + setting_default_notification_option: אפשרות התראה ברירת־מחדל + + permission_add_project: יצירת פרויקט + permission_add_subprojects: יצירת תתי־פרויקט + permission_edit_project: עריכת פרויקט + permission_select_project_modules: בחירת מודולי פרויקט + permission_manage_members: ניהול חברים + permission_manage_project_activities: נהל פעילויות פרויקט + permission_manage_versions: ניהול גירסאות + permission_manage_categories: ניהול קטגוריות נושאים + permission_view_issues: צפיה בנושאים + permission_add_issues: הוספת נושא + permission_edit_issues: עריכת נושאים + permission_manage_issue_relations: ניהול קשרים בין נושאים + permission_add_issue_notes: הוספת הערות לנושאים + permission_edit_issue_notes: עריכת רשימות + permission_edit_own_issue_notes: עריכת הערות של עצמו + permission_move_issues: הזזת נושאים + permission_delete_issues: מחיקת נושאים + permission_manage_public_queries: ניהול שאילתות פומביות + permission_save_queries: שמירת שאילתות + permission_view_gantt: צפיה בגאנט + permission_view_calendar: צפיה בלוח השנה + permission_view_issue_watchers: צפיה ברשימת צופים + permission_add_issue_watchers: הוספת צופים + permission_delete_issue_watchers: הסרת צופים + permission_log_time: תיעוד זמן שהושקע + permission_view_time_entries: צפיה ברישום זמנים + permission_edit_time_entries: עריכת רישום זמנים + permission_edit_own_time_entries: עריכת רישום הזמנים של עצמו + permission_manage_news: ניהול חדשות + permission_comment_news: תגובה לחדשות + permission_manage_documents: ניהול מסמכים + permission_view_documents: צפיה במסמכים + permission_manage_files: ניהול קבצים + permission_view_files: צפיה בקבצים + permission_manage_wiki: ניהול wiki + permission_rename_wiki_pages: שינוי שם של דפי wiki + permission_delete_wiki_pages: מחיקת דפי wiki + permission_view_wiki_pages: צפיה ב־wiki + permission_view_wiki_edits: צפיה בהיסטורית wiki + permission_edit_wiki_pages: עריכת דפי wiki + permission_delete_wiki_pages_attachments: מחיקת דבוקות + permission_protect_wiki_pages: הגנה על כל דפי wiki + permission_manage_repository: ניהול מאגר + permission_browse_repository: סיור במאגר + permission_view_changesets: צפיה בסדרות שינויים + permission_commit_access: אישור הפקדות + permission_manage_boards: ניהול לוחות + permission_view_messages: צפיה בהודעות + permission_add_messages: הצבת הודעות + permission_edit_messages: עריכת הודעות + permission_edit_own_messages: עריכת הודעות של עצמו + permission_delete_messages: מחיקת הודעות + permission_delete_own_messages: מחיקת הודעות של עצמו + permission_export_wiki_pages: יצא דפי wiki + permission_manage_subtasks: נהל תתי־משימות + + project_module_issue_tracking: מעקב נושאים + project_module_time_tracking: מעקב אחר זמנים + project_module_news: חדשות + project_module_documents: מסמכים + project_module_files: קבצים + project_module_wiki: Wiki + project_module_repository: מאגר + project_module_boards: לוחות + project_module_calendar: לוח שנה + project_module_gantt: גאנט + + label_user: משתמש + label_user_plural: משתמשים + label_user_new: משתמש חדש + label_user_anonymous: אלמוני + label_project: פרויקט + label_project_new: פרויקט חדש + label_project_plural: פרויקטים + label_x_projects: + zero: ללא פרויקטים + one: פרויקט אחד + other: "%{count} פרויקטים" + label_project_all: כל הפרויקטים + label_project_latest: הפרויקטים החדשים ביותר + label_issue: נושא + label_issue_new: נושא חדש + label_issue_plural: נושאים + label_issue_view_all: צפה בכל הנושאים + label_issues_by: "נושאים לפי %{value}" + label_issue_added: נושא נוסף + label_issue_updated: נושא עודכן + label_document: מסמך + label_document_new: מסמך חדש + label_document_plural: מסמכים + label_document_added: מסמך נוסף + label_role: תפקיד + label_role_plural: תפקידים + label_role_new: תפקיד חדש + label_role_and_permissions: תפקידים והרשאות + label_member: חבר + label_member_new: חבר חדש + label_member_plural: חברים + label_tracker: סיווג + label_tracker_plural: סיווגים + label_tracker_new: סיווג חדש + label_workflow: זרימת עבודה + label_issue_status: מצב נושא + label_issue_status_plural: מצבי נושא + label_issue_status_new: מצב חדש + label_issue_category: קטגורית נושא + label_issue_category_plural: קטגוריות נושא + label_issue_category_new: קטגוריה חדשה + label_custom_field: שדה אישי + label_custom_field_plural: שדות אישיים + label_custom_field_new: שדה אישי חדש + label_enumerations: אינומרציות + label_enumeration_new: ערך חדש + label_information: מידע + label_information_plural: מידע + label_please_login: נא התחבר + label_register: הרשמה + label_login_with_open_id_option: או התחבר באמצעות OpenID + label_password_lost: אבדה הסיסמה? + label_home: דף הבית + label_my_page: הדף שלי + label_my_account: החשבון שלי + label_my_projects: הפרויקטים שלי + label_my_page_block: בלוק הדף שלי + label_administration: ניהול + label_login: התחבר + label_logout: התנתק + label_help: עזרה + label_reported_issues: נושאים שדווחו + label_assigned_to_me_issues: נושאים שהוצבו לי + label_last_login: התחברות אחרונה + label_registered_on: נרשם בתאריך + label_activity: פעילות + label_overall_activity: פעילות כוללת + label_user_activity: "הפעילות של %{value}" + label_new: חדש + label_logged_as: מחובר כ + label_environment: סביבה + label_authentication: הזדהות + label_auth_source: מקור הזדהות + label_auth_source_new: מקור הזדהות חדש + label_auth_source_plural: מקורות הזדהות + label_subproject_plural: תת־פרויקטים + label_subproject_new: תת־פרויקט חדש + label_and_its_subprojects: "%{value} וכל תתי־הפרויקטים שלו" + label_min_max_length: אורך מינימאלי - מקסימאלי + label_list: רשימה + label_date: תאריך + label_integer: מספר שלם + label_float: צף + label_boolean: ערך בוליאני + label_string: טקסט + label_text: טקסט ארוך + label_attribute: תכונה + label_attribute_plural: תכונות + label_download: "הורדה %{count}" + label_download_plural: "%{count} הורדות" + label_no_data: אין מידע להציג + label_change_status: שנה מצב + label_history: היסטוריה + label_attachment: קובץ + label_attachment_new: קובץ חדש + label_attachment_delete: מחק קובץ + label_attachment_plural: קבצים + label_file_added: קובץ נוסף + label_report: דו"ח + label_report_plural: דו"חות + label_news: חדשות + label_news_new: הוסף חדשות + label_news_plural: חדשות + label_news_latest: חדשות אחרונות + label_news_view_all: צפה בכל החדשות + label_news_added: חדשות נוספו + label_settings: הגדרות + label_overview: מבט רחב + label_version: גירסה + label_version_new: גירסה חדשה + label_version_plural: גירסאות + label_close_versions: סגור גירסאות שהושלמו + label_confirmation: אישור + label_export_to: יצא ל + label_read: קרא... + label_public_projects: פרויקטים פומביים + label_open_issues: פתוח + label_open_issues_plural: פתוחים + label_closed_issues: סגור + label_closed_issues_plural: סגורים + label_x_open_issues_abbr_on_total: + zero: 0 פתוחים / %{total} + one: 1 פתוח / %{total} + other: "%{count} פתוחים / %{total}" + label_x_open_issues_abbr: + zero: 0 פתוחים + one: 1 פתוח + other: "%{count} פתוחים" + label_x_closed_issues_abbr: + zero: 0 סגורים + one: 1 סגור + other: "%{count} סגורים" + label_total: סה"כ + label_permissions: הרשאות + label_current_status: מצב נוכחי + label_new_statuses_allowed: מצבים חדשים אפשריים + label_all: הכל + label_none: כלום + label_nobody: אף אחד + label_next: הבא + label_previous: הקודם + label_used_by: בשימוש ע"י + label_details: פרטים + label_add_note: הוסף הערה + label_per_page: לכל דף + label_calendar: לוח שנה + label_months_from: חודשים מ + label_gantt: גאנט + label_internal: פנימי + label_last_changes: "%{count} שינוים אחרונים" + label_change_view_all: צפה בכל השינוים + label_personalize_page: התאם אישית דף זה + label_comment: תגובה + label_comment_plural: תגובות + label_x_comments: + zero: אין הערות + one: הערה אחת + other: "%{count} הערות" + label_comment_add: הוסף תגובה + label_comment_added: תגובה נוספה + label_comment_delete: מחק תגובות + label_query: שאילתה אישית + label_query_plural: שאילתות אישיות + label_query_new: שאילתה חדשה + label_filter_add: הוסף מסנן + label_filter_plural: מסננים + label_equals: הוא + label_not_equals: הוא לא + label_in_less_than: בפחות מ + label_in_more_than: ביותר מ + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_in: ב + label_today: היום + label_all_time: תמיד + label_yesterday: אתמול + label_this_week: השבוע + label_last_week: השבוע שעבר + label_last_n_days: "ב־%{count} ימים אחרונים" + label_this_month: החודש + label_last_month: חודש שעבר + label_this_year: השנה + label_date_range: טווח תאריכים + label_less_than_ago: פחות מ + label_more_than_ago: יותר מ + label_ago: לפני + label_contains: מכיל + label_not_contains: לא מכיל + label_day_plural: ימים + label_repository: מאגר + label_repository_plural: מאגרים + label_browse: סייר + label_modification: "שינוי %{count}" + label_modification_plural: "%{count} שינויים" + label_branch: ענף + label_tag: סימון + label_revision: מהדורה + label_revision_plural: מהדורות + label_revision_id: מהדורה %{value} + label_associated_revisions: מהדורות קשורות + label_added: נוסף + label_modified: שונה + label_copied: הועתק + label_renamed: השם שונה + label_deleted: נמחק + label_latest_revision: מהדורה אחרונה + label_latest_revision_plural: מהדורות אחרונות + label_view_revisions: צפה במהדורות + label_view_all_revisions: צפה בכל המהדורות + label_max_size: גודל מקסימאלי + label_sort_highest: הזז לראשית + label_sort_higher: הזז למעלה + label_sort_lower: הזז למטה + label_sort_lowest: הזז לתחתית + label_roadmap: מפת הדרכים + label_roadmap_due_in: "נגמר בעוד %{value}" + label_roadmap_overdue: "%{value} מאחר" + label_roadmap_no_issues: אין נושאים לגירסה זו + label_search: חפש + label_result_plural: תוצאות + label_all_words: כל המילים + label_wiki: Wiki + label_wiki_edit: ערוך wiki + label_wiki_edit_plural: עריכות wiki + label_wiki_page: דף Wiki + label_wiki_page_plural: דפי wiki + label_index_by_title: סדר על פי כותרת + label_index_by_date: סדר על פי תאריך + label_current_version: גירסה נוכחית + label_preview: תצוגה מקדימה + label_feed_plural: הזנות + label_changes_details: פירוט כל השינויים + label_issue_tracking: מעקב אחר נושאים + label_spent_time: זמן שהושקע + label_overall_spent_time: זמן שהושקע סה"כ + label_f_hour: "%{value} שעה" + label_f_hour_plural: "%{value} שעות" + label_time_tracking: מעקב זמנים + label_change_plural: שינויים + label_statistics: סטטיסטיקות + label_commits_per_month: הפקדות לפי חודש + label_commits_per_author: הפקדות לפי כותב + label_view_diff: צפה בשינויים + label_diff_inline: בתוך השורה + label_diff_side_by_side: צד לצד + label_options: אפשרויות + label_copy_workflow_from: העתק זירמת עבודה מ + label_permissions_report: דו"ח הרשאות + label_watched_issues: נושאים שנצפו + label_related_issues: נושאים קשורים + label_applied_status: מצב מוחל + label_loading: טוען... + label_relation_new: קשר חדש + label_relation_delete: מחק קשר + label_relates_to: קשור ל + label_duplicates: מכפיל את + label_duplicated_by: שוכפל ע"י + label_blocks: חוסם את + label_blocked_by: חסום ע"י + label_precedes: מקדים את + label_follows: עוקב אחרי + label_end_to_start: מהתחלה לסוף + label_end_to_end: מהסוף לסוף + label_start_to_start: מהתחלה להתחלה + label_start_to_end: מהתחלה לסוף + label_stay_logged_in: השאר מחובר + label_disabled: מבוטל + label_show_completed_versions: הצג גירסאות גמורות + label_me: אני + label_board: פורום + label_board_new: פורום חדש + label_board_plural: פורומים + label_board_locked: נעול + label_board_sticky: דביק + label_topic_plural: נושאים + label_message_plural: הודעות + label_message_last: הודעה אחרונה + label_message_new: הודעה חדשה + label_message_posted: הודעה נוספה + label_reply_plural: השבות + label_send_information: שלח מידע על חשבון למשתמש + label_year: שנה + label_month: חודש + label_week: שבוע + label_date_from: מתאריך + label_date_to: עד + label_language_based: מבוסס שפה + label_sort_by: "מיין לפי %{value}" + label_send_test_email: שלח דוא"ל בדיקה + label_feeds_access_key: מפתח גישה ל־RSS + label_missing_feeds_access_key: חסר מפתח גישה ל־RSS + label_feeds_access_key_created_on: "מפתח הזנת RSS נוצר לפני%{value}" + label_module_plural: מודולים + label_added_time_by: 'נוסף ע"י %{author} לפני %{age}' + label_updated_time_by: 'עודכן ע"י %{author} לפני %{age}' + label_updated_time: "עודכן לפני %{value} " + label_jump_to_a_project: קפוץ לפרויקט... + label_file_plural: קבצים + label_changeset_plural: סדרות שינויים + label_default_columns: עמודת ברירת מחדל + label_no_change_option: (אין שינוים) + label_bulk_edit_selected_issues: ערוך את הנושאים המסומנים + label_theme: ערכת נושא + label_default: ברירת מחדל + label_search_titles_only: חפש בכותרות בלבד + label_user_mail_option_all: "לכל אירוע בכל הפרויקטים שלי" + label_user_mail_option_selected: "לכל אירוע בפרויקטים שבחרתי בלבד..." + label_user_mail_option_only_my_events: עבור דברים שאני צופה או מעורב בהם בלבד + label_user_mail_option_only_assigned: עבור דברים שאני אחראי עליהם בלבד + label_user_mail_option_only_owner: עבור דברים שאני הבעלים שלהם בלבד + label_user_mail_no_self_notified: "אני לא רוצה שיודיעו לי על שינויים שאני מבצע" + label_registration_activation_by_email: הפעל חשבון באמצעות דוא"ל + label_registration_manual_activation: הפעלת חשבון ידנית + label_registration_automatic_activation: הפעלת חשבון אוטומטית + label_display_per_page: "בכל דף: %{value} תוצאות" + label_age: גיל + label_change_properties: שנה מאפיינים + label_general: כללי + label_more: עוד + label_scm: מערכת ניהול תצורה + label_plugins: תוספים + label_ldap_authentication: הזדהות LDAP + label_downloads_abbr: D/L + label_optional_description: תיאור רשות + label_add_another_file: הוסף עוד קובץ + label_preferences: העדפות + label_chronological_order: בסדר כרונולוגי + label_reverse_chronological_order: בסדר כרונולוגי הפוך + label_planning: תכנון + label_incoming_emails: דוא"ל נכנס + label_generate_key: צור מפתח + label_issue_watchers: צופים + label_example: דוגמא + label_display: תצוגה + label_sort: מיון + label_ascending: בסדר עולה + label_descending: בסדר יורד + label_date_from_to: 'מתאריך %{start} ועד תאריך %{end}' + label_wiki_content_added: נוסף דף ל־wiki + label_wiki_content_updated: דף wiki עודכן + label_group: קבוצה + label_group_plural: קבוצות + label_group_new: קבוצה חדשה + label_time_entry_plural: זמן שהושקע + label_version_sharing_none: לא משותף + label_version_sharing_descendants: עם פרויקטים בנים + label_version_sharing_hierarchy: עם היררכית הפרויקטים + label_version_sharing_tree: עם עץ הפרויקט + label_version_sharing_system: עם כל הפרויקטים + label_update_issue_done_ratios: עדכן אחוז התקדמות לנושא + label_copy_source: מקור + label_copy_target: יעד + label_copy_same_as_target: זהה ליעד + label_display_used_statuses_only: הצג רק את המצבים בשימוש לסיווג זה + label_api_access_key: מפתח גישה ל־API + label_missing_api_access_key: חסר מפתח גישה ל־API + label_api_access_key_created_on: 'מפתח גישה ל־API נוצר לפני %{value}' + label_profile: פרופיל + label_subtask_plural: תתי־משימות + label_project_copy_notifications: שלח התראות דואר במהלך העתקת הפרויקט + + button_login: התחבר + button_submit: אשר + button_save: שמור + button_check_all: בחר הכל + button_uncheck_all: בחר כלום + button_delete: מחק + button_create: צור + button_create_and_continue: צור ופתח חדש + button_test: בדוק + button_edit: ערוך + button_edit_associated_wikipage: "ערוך דף wiki מקושר: %{page_title}" + button_add: הוסף + button_change: שנה + button_apply: החל + button_clear: נקה + button_lock: נעל + button_unlock: בטל נעילה + button_download: הורד + button_list: רשימה + button_view: צפה + button_move: הזז + button_move_and_follow: העבר ועקוב + button_back: הקודם + button_cancel: בטל + button_activate: הפעל + button_sort: מיין + button_log_time: רישום זמנים + button_rollback: חזור למהדורה זו + button_watch: צפה + button_unwatch: בטל צפיה + button_reply: השב + button_archive: ארכיון + button_unarchive: הוצא מהארכיון + button_reset: אפס + button_rename: שנה שם + button_change_password: שנה סיסמה + button_copy: העתק + button_copy_and_follow: העתק ועקוב + button_annotate: הוסף תיאור מסגרת + button_update: עדכן + button_configure: אפשרויות + button_quote: צטט + button_duplicate: שכפל + button_show: הצג + + status_active: פעיל + status_registered: רשום + status_locked: נעול + + version_status_open: פתוח + version_status_locked: נעול + version_status_closed: סגור + + field_active: פעיל + + text_select_mail_notifications: בחר פעולת שבגללן ישלח דוא"ל. + text_regexp_info: כגון. ^[A-Z0-9]+$ + text_min_max_length_info: 0 משמעו ללא הגבלות + text_project_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הפרויקט ואת כל המידע הקשור אליו? + text_subprojects_destroy_warning: "תת־הפרויקטים: %{value} ימחקו גם כן." + text_workflow_edit: בחר תפקיד וסיווג כדי לערוך את זרימת העבודה + text_are_you_sure: האם אתה בטוח? + text_are_you_sure_with_children: האם למחוק את הנושא ואת כל בניו? + text_journal_changed: "%{label} השתנה מ%{old} ל%{new}" + text_journal_set_to: "%{label} נקבע ל%{value}" + text_journal_deleted: "%{label} נמחק (%{old})" + text_journal_added: "%{label} %{value} נוסף" + text_tip_issue_begin_day: מטלה המתחילה היום + text_tip_issue_end_day: מטלה המסתיימת היום + text_tip_issue_begin_end_day: מטלה המתחילה ומסתיימת היום + text_project_identifier_info: 'אותיות לטיניות (a-z), מספרים ומקפים.
ברגע שנשמר, לא ניתן לשנות את המזהה.' + text_caracters_maximum: "מקסימום %{count} תווים." + text_caracters_minimum: "חייב להיות לפחות באורך של %{count} תווים." + text_length_between: "אורך בין %{min} ל %{max} תווים." + text_tracker_no_workflow: זרימת עבודה לא הוגדרה עבור סיווג זה + text_unallowed_characters: תווים לא מורשים + text_comma_separated: הכנסת ערכים מרובים מותרת (מופרדים בפסיקים). + text_line_separated: ניתן להזין מספר ערכים (שורה אחת לכל ערך). + text_issues_ref_in_commit_messages: קישור ותיקום נושאים בהודעות הפקדה + text_issue_added: "הנושא %{id} דווח (בידי %{author})." + text_issue_updated: "הנושא %{id} עודכן (בידי %{author})." + text_wiki_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הWIKI הזה ואת כל תוכנו? + text_issue_category_destroy_question: "כמה נושאים (%{count}) מוצבים לקטגוריה הזו. מה ברצונך לעשות?" + text_issue_category_destroy_assignments: הסר הצבת קטגוריה + text_issue_category_reassign_to: הצב מחדש את הקטגוריה לנושאים + text_user_mail_option: "בפרויקטים שלא בחרת, אתה רק תקבל התרעות על שאתה צופה או קשור אליהם (לדוגמא:נושאים שאתה היוצר שלהם או אחראי עליהם)." + text_no_configuration_data: "לא הוגדרה תצורה עבור תפקידים, סיווגים, מצבי נושא וזרימת עבודה.\nמומלץ מאד לטעון את תצורת ברירת המחדל. תוכל לשנותה מאוחר יותר." + text_load_default_configuration: טען את אפשרויות ברירת המחדל + text_status_changed_by_changeset: "הוחל בסדרת השינויים %{value}." + text_issues_destroy_confirmation: 'האם אתה בטוח שברצונך למחוק את הנושאים?' + text_select_project_modules: 'בחר מודולים להחיל על פרויקט זה:' + text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה + text_file_repository_writable: מאגר הקבצים ניתן לכתיבה + text_plugin_assets_writable: ספרית נכסי תוספים ניתנת לכתיבה + text_rmagick_available: RMagick זמין (רשות) + text_destroy_time_entries_question: "%{hours} שעות דווחו על הנושאים שאתה עומד למחוק. מה ברצונך לעשות?" + text_destroy_time_entries: מחק שעות שדווחו + text_assign_time_entries_to_project: הצב שעות שדווחו לפרויקט הזה + text_reassign_time_entries: 'הצב מחדש שעות שדווחו לפרויקט הזה:' + text_user_wrote: "%{value} כתב:" + text_enumeration_destroy_question: "%{count} אוביקטים מוצבים לערך זה." + text_enumeration_category_reassign_to: 'הצב מחדש לערך הזה:' + text_email_delivery_not_configured: 'לא נקבעה תצורה לשליחת דואר, וההתראות כבויות.\nקבע את תצורת שרת ה־SMTP בקובץ /etc/redmine/<instance>/configuration.yml והתחל את האפליקציה מחדש ע"מ לאפשר אותם.' + text_repository_usernames_mapping: "בחר או עדכן את משתמש Redmine הממופה לכל שם משתמש ביומן המאגר.\nמשתמשים בעלי שם או כתובת דואר זהה ב־Redmine ובמאגר ממופים באופן אוטומטי." + text_diff_truncated: '... השינויים עוברים את מספר השורות המירבי לתצוגה, ולכן הם קוצצו.' + text_custom_field_possible_values_info: שורה אחת לכל ערך + text_wiki_page_destroy_question: לדף זה יש %{descendants} דפים בנים ותלויים. מה ברצונך לעשות? + text_wiki_page_nullify_children: השאר דפים בנים כדפים ראשיים + text_wiki_page_destroy_children: מחק את הדפים הבנים ואת כל התלויים בהם + text_wiki_page_reassign_children: הצב מחדש דפים בנים לדף האב הנוכחי + text_own_membership_delete_confirmation: |- + בכוונתך למחוק חלק או את כל ההרשאות שלך. לאחר מכן לא תוכל יותר לערוך פרויקט זה. + האם אתה בטוח שברצונך להמשיך? + text_zoom_in: התקרב + text_zoom_out: התרחק + + default_role_manager: מנהל + default_role_developer: מפתח + default_role_reporter: מדווח + default_tracker_bug: תקלה + default_tracker_feature: יכולת + default_tracker_support: תמיכה + default_issue_status_new: חדש + default_issue_status_in_progress: בעבודה + default_issue_status_resolved: נפתר + default_issue_status_feedback: משוב + default_issue_status_closed: סגור + default_issue_status_rejected: נדחה + default_doc_category_user: תיעוד משתמש + default_doc_category_tech: תיעוד טכני + default_priority_low: נמוכה + default_priority_normal: רגילה + default_priority_high: גבוהה + default_priority_urgent: דחופה + default_priority_immediate: מידית + default_activity_design: עיצוב + default_activity_development: פיתוח + + enumeration_issue_priorities: עדיפות נושאים + enumeration_doc_categories: קטגוריות מסמכים + enumeration_activities: פעילויות (מעקב אחר זמנים) + enumeration_system_activity: פעילות מערכת + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: קידוד הודעות הפקדה + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/246272ecf77e9e146775d6173c7c910bea9ac736.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/246272ecf77e9e146775d6173c7c910bea9ac736.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class ReportsController < ApplicationController + menu_item :issues + before_filter :find_project, :authorize, :find_issue_statuses + + def issue_report + @trackers = @project.trackers + @versions = @project.shared_versions.sort + @priorities = IssuePriority.all + @categories = @project.issue_categories + @assignees = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort + @authors = @project.users.sort + @subprojects = @project.descendants.visible + + @issues_by_tracker = Issue.by_tracker(@project) + @issues_by_version = Issue.by_version(@project) + @issues_by_priority = Issue.by_priority(@project) + @issues_by_category = Issue.by_category(@project) + @issues_by_assigned_to = Issue.by_assigned_to(@project) + @issues_by_author = Issue.by_author(@project) + @issues_by_subproject = Issue.by_subproject(@project) || [] + + render :template => "reports/issue_report" + end + + def issue_report_details + case params[:detail] + when "tracker" + @field = "tracker_id" + @rows = @project.trackers + @data = Issue.by_tracker(@project) + @report_title = l(:field_tracker) + when "version" + @field = "fixed_version_id" + @rows = @project.shared_versions.sort + @data = Issue.by_version(@project) + @report_title = l(:field_version) + when "priority" + @field = "priority_id" + @rows = IssuePriority.all + @data = Issue.by_priority(@project) + @report_title = l(:field_priority) + when "category" + @field = "category_id" + @rows = @project.issue_categories + @data = Issue.by_category(@project) + @report_title = l(:field_category) + when "assigned_to" + @field = "assigned_to_id" + @rows = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort + @data = Issue.by_assigned_to(@project) + @report_title = l(:field_assigned_to) + when "author" + @field = "author_id" + @rows = @project.users.sort + @data = Issue.by_author(@project) + @report_title = l(:field_author) + when "subproject" + @field = "project_id" + @rows = @project.descendants.visible + @data = Issue.by_subproject(@project) || [] + @report_title = l(:field_subproject) + end + + respond_to do |format| + if @field + format.html {} + else + format.html { redirect_to :action => 'issue_report', :id => @project } + end + end + end + + private + + def find_issue_statuses + @statuses = IssueStatus.find(:all, :order => 'position') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/246874006236597325557c0bf816ad53110aa1a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/246874006236597325557c0bf816ad53110aa1a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class DocumentCategoryCustomField < CustomField + def type_name + :enumeration_doc_categories + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/2471bc30fc61272951a43cf6db1dd453fdafb1e4.svn-base Binary file .svn/pristine/24/2471bc30fc61272951a43cf6db1dd453fdafb1e4.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/2471e93efea942bf9d4041debddb77820f273e27.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/2471e93efea942bf9d4041debddb77820f273e27.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,36 @@ +--- +journal_details_001: + old_value: "1" + property: attr + id: 1 + value: "2" + prop_key: status_id + journal_id: 1 +journal_details_002: + old_value: "40" + property: attr + id: 2 + value: "30" + prop_key: done_ratio + journal_id: 1 +journal_details_003: + old_value: nil + property: attr + id: 3 + value: "6" + prop_key: fixed_version_id + journal_id: 4 +journal_details_004: + old_value: "This word was removed and an other was" + property: attr + id: 4 + value: "This word was and an other was added" + prop_key: description + journal_id: 3 +journal_details_005: + old_value: Old value + property: cf + id: 5 + value: New value + prop_key: 2 + journal_id: 3 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/24caa70f1e5fda792b6f057bf6078667c181a5ac.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/24caa70f1e5fda792b6f057bf6078667c181a5ac.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddProjectIdentifier < ActiveRecord::Migration + def self.up + add_column :projects, :identifier, :string, :limit => 20 + end + + def self.down + remove_column :projects, :identifier + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/24f7f0414301f421feaefeee3ae3bf564c315361.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/24f7f0414301f421feaefeee3ae3bf564c315361.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,217 @@ +# encoding: utf-8 +module CodeRay + module Scanners + + # Clojure scanner by Licenser. + class Clojure < Scanner + + register_for :clojure + file_extension 'clj' + + SPECIAL_FORMS = %w[ + def if do let quote var fn loop recur throw try catch monitor-enter monitor-exit . + new + ] # :nodoc: + + CORE_FORMS = %w[ + + - -> ->> .. / * <= < = == >= > accessor aclone add-classpath add-watch + agent agent-error agent-errors aget alength alias all-ns alter alter-meta! + alter-var-root amap ancestors and apply areduce array-map aset aset-boolean + aset-byte aset-char aset-double aset-float aset-int aset-long aset-short + assert assoc assoc! assoc-in associative? atom await await-for bases bean + bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or + bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array + booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char + char-array char-escape-string char-name-string char? chars class class? + clear-agent-errors clojure-version coll? comment commute comp comparator + compare compare-and-set! compile complement concat cond condp conj conj! + cons constantly construct-proxy contains? count counted? create-ns + create-struct cycle dec decimal? declare definline defmacro defmethod defmulti + defn defn- defonce defprotocol defrecord defstruct deftype delay delay? + deliver denominator deref derive descendants disj disj! dissoc dissoc! + distinct distinct? doall doc dorun doseq dosync dotimes doto double + double-array doubles drop drop-last drop-while empty empty? ensure + enumeration-seq error-handler error-mode eval even? every? extend + extend-protocol extend-type extenders extends? false? ffirst file-seq + filter find find-doc find-ns find-var first float float-array float? + floats flush fn fn? fnext for force format future future-call future-cancel + future-cancelled? future-done? future? gen-class gen-interface gensym get + get-in get-method get-proxy-class get-thread-bindings get-validator hash + hash-map hash-set identical? identity if-let if-not ifn? import in-ns + inc init-proxy instance? int int-array integer? interleave intern + interpose into into-array ints io! isa? iterate iterator-seq juxt key + keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* + list? load load-file load-reader load-string loaded-libs locking long + long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy + map map? mapcat max max-key memfn memoize merge merge-with meta methods + min min-key mod name namespace neg? newline next nfirst nil? nnext not + not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns + ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth + nthnext num number? numerator object-array odd? or parents partial + partition pcalls peek persistent! pmap pop pop! pop-thread-bindings + pos? pr pr-str prefer-method prefers print print-namespace-doc + print-str printf println println-str prn prn-str promise proxy + proxy-mappings proxy-super push-thread-bindings pvalues quot rand + rand-int range ratio? rationalize re-find re-groups re-matcher + re-matches re-pattern re-seq read read-line read-string reduce ref + ref-history-count ref-max-history ref-min-history ref-set refer + refer-clojure reify release-pending-sends rem remove remove-all-methods + remove-method remove-ns remove-watch repeat repeatedly replace replicate + require reset! reset-meta! resolve rest restart-agent resultset-seq + reverse reversible? rseq rsubseq satisfies? second select-keys send + send-off seq seq? seque sequence sequential? set set-error-handler! + set-error-mode! set-validator! set? short short-array shorts + shutdown-agents slurp some sort sort-by sorted-map sorted-map-by + sorted-set sorted-set-by sorted? special-form-anchor special-symbol? + split-at split-with str string? struct struct-map subs subseq subvec + supers swap! symbol symbol? sync syntax-symbol-anchor take take-last + take-nth take-while test the-ns thread-bound? time to-array to-array-2d + trampoline transient tree-seq true? type unchecked-add unchecked-dec + unchecked-divide unchecked-inc unchecked-multiply unchecked-negate + unchecked-remainder unchecked-subtract underive update-in update-proxy + use val vals var-get var-set var? vary-meta vec vector vector-of vector? + when when-first when-let when-not while with-bindings with-bindings* + with-in-str with-local-vars with-meta with-open with-out-str + with-precision xml-seq zero? zipmap + ] # :nodoc: + + PREDEFINED_CONSTANTS = %w[ + true false nil *1 *2 *3 *agent* *clojure-version* *command-line-args* + *compile-files* *compile-path* *e *err* *file* *flush-on-newline* + *in* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* + *print-readably* *read-eval* *warn-on-reflection* + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(SPECIAL_FORMS, :keyword). + add(CORE_FORMS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant) + + KEYWORD_NEXT_TOKEN_KIND = WordList.new(nil). + add(%w[ def defn defn- definline defmacro defmulti defmethod defstruct defonce declare ], :function). + add(%w[ ns ], :namespace). + add(%w[ defprotocol defrecord ], :class) + + BASIC_IDENTIFIER = /[a-zA-Z$%*\/_+!?&<>\-=]=?[a-zA-Z0-9$&*+!\/_?<>\-\#]*/ + IDENTIFIER = /(?!-\d)(?:(?:#{BASIC_IDENTIFIER}\.)*#{BASIC_IDENTIFIER}(?:\/#{BASIC_IDENTIFIER})?\.?)|\.\.?/ + SYMBOL = /::?#{IDENTIFIER}/o + DIGIT = /\d/ + DIGIT10 = DIGIT + DIGIT16 = /[0-9a-f]/i + DIGIT8 = /[0-7]/ + DIGIT2 = /[01]/ + RADIX16 = /\#x/i + RADIX8 = /\#o/i + RADIX2 = /\#b/i + RADIX10 = /\#d/i + EXACTNESS = /#i|#e/i + SIGN = /[\+-]?/ + EXP_MARK = /[esfdl]/i + EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/ + SUFFIX = /#{EXP}?/ + PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/ + PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/ + PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/ + PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/ + UINT10 = /#{DIGIT10}+#*/ + UINT16 = /#{DIGIT16}+#*/ + UINT8 = /#{DIGIT8}+#*/ + UINT2 = /#{DIGIT2}+#*/ + DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/ + UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/ + UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/ + UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/ + UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/ + REAL10 = /#{SIGN}#{UREAL10}/ + REAL16 = /#{SIGN}#{UREAL16}/ + REAL8 = /#{SIGN}#{UREAL8}/ + REAL2 = /#{SIGN}#{UREAL2}/ + IMAG10 = /i|#{UREAL10}i/ + IMAG16 = /i|#{UREAL16}i/ + IMAG8 = /i|#{UREAL8}i/ + IMAG2 = /i|#{UREAL2}i/ + COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/ + COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/ + COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/ + COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/ + NUM10 = /#{PREFIX10}?#{COMPLEX10}/ + NUM16 = /#{PREFIX16}#{COMPLEX16}/ + NUM8 = /#{PREFIX8}#{COMPLEX8}/ + NUM2 = /#{PREFIX2}#{COMPLEX2}/ + NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/ + + protected + + def scan_tokens encoder, options + + state = :initial + kind = nil + + until eos? + + case state + when :initial + if match = scan(/ \s+ | \\\n | , /x) + encoder.text_token match, :space + elsif match = scan(/['`\(\[\)\]\{\}]|\#[({]|~@?|[@\^]/) + encoder.text_token match, :operator + elsif match = scan(/;.*/) + encoder.text_token match, :comment # TODO: recognize (comment ...) too + elsif match = scan(/\#?\\(?:newline|space|.?)/) + encoder.text_token match, :char + elsif match = scan(/\#[ft]/) + encoder.text_token match, :predefined_constant + elsif match = scan(/#{IDENTIFIER}/o) + kind = IDENT_KIND[match] + encoder.text_token match, kind + if rest? && kind == :keyword + if kind = KEYWORD_NEXT_TOKEN_KIND[match] + encoder.text_token match, :space if match = scan(/\s+/o) + encoder.text_token match, kind if match = scan(/#{IDENTIFIER}/o) + end + end + elsif match = scan(/#{SYMBOL}/o) + encoder.text_token match, :symbol + elsif match = scan(/\./) + encoder.text_token match, :operator + elsif match = scan(/ \# \^ #{IDENTIFIER} /ox) + encoder.text_token match, :type + elsif match = scan(/ (\#)? " /x) + state = self[1] ? :regexp : :string + encoder.begin_group state + encoder.text_token match, :delimiter + elsif match = scan(/#{NUM}/o) and not matched.empty? + encoder.text_token match, match[/[.e\/]/i] ? :float : :integer + else + encoder.text_token getch, :error + end + + when :string, :regexp + if match = scan(/[^"\\]+|\\.?/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), + encoder, state + end + + else + raise 'else case reached' + + end + + end + + if [:string, :regexp].include? state + encoder.end_group state + end + + encoder + + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/24/24fd863445a2712cd9a393b27cdffed3e37f7b4d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/24/24fd863445a2712cd9a393b27cdffed3e37f7b4d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +top: + id: 1 + name: Top \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/25/25113ec5e4b14337a78af5200fc4c9451ad1548e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/25/25113ec5e4b14337a78af5200fc4c9451ad1548e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +<% @entries.each do |entry| %> +<% tr_id = Digest::MD5.hexdigest(entry.path) + depth = params[:depth].to_i %> +<% ent_path = Redmine::CodesetUtil.replace_invalid_utf8(entry.path) %> +<% ent_name = Redmine::CodesetUtil.replace_invalid_utf8(entry.name) %> + +";> +<% if entry.is_dir? %> + "scmEntryClick('#{tr_id}')" + ) %>">  +<% end %> +<%= link_to h(ent_name), + {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(ent_path), :rev => @rev}, + :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(ent_name)}")%> + +<%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> +<% changeset = @project.repository.find_changeset_by_name(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> +<% if @repository.report_last_commit %> +<%= link_to_revision(changeset, @project) if changeset %> +<%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> +<%= changeset.nil? ? h(Redmine::CodesetUtil.replace_invalid_utf8(entry.lastrev.author.to_s.split('<').first)) : h(changeset.author) if entry.lastrev %> +<%=h truncate(changeset.comments, :length => 50) unless changeset.nil? %> +<% end %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/25/255266b575a05c827ef4f774350844e8580977f9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/25/255266b575a05c827ef4f774350844e8580977f9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +<%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)
+
+<%= textilizable(@document, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/25/25a248b972bed2adf3bfae26d2e777b6d1e986f8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/25/25a248b972bed2adf3bfae26d2e777b6d1e986f8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 TrackersHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/25/25d4952bfbaae981a133d8dd1a03f09c8dcd8dbf.svn-base Binary file .svn/pristine/25/25d4952bfbaae981a133d8dd1a03f09c8dcd8dbf.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/25/25e20e75adcb2337c7b7589449cc334604a57456.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/25/25e20e75adcb2337c7b7589449cc334604a57456.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,64 @@ +# $Id: psw.rb 73 2006-04-24 21:59:35Z blackhedd $ +# +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Gmail: garbagecat10 +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +#--------------------------------------------------------------------------- +# +# + + +module Net +class LDAP + + +class Password + class << self + + # Generate a password-hash suitable for inclusion in an LDAP attribute. + # Pass a hash type (currently supported: :md5 and :sha) and a plaintext + # password. This function will return a hashed representation. + # STUB: This is here to fulfill the requirements of an RFC, which one? + # TODO, gotta do salted-sha and (maybe) salted-md5. + # Should we provide sha1 as a synonym for sha1? I vote no because then + # should you also provide ssha1 for symmetry? + def generate( type, str ) + case type + when :md5 + require 'md5' + "{MD5}#{ [MD5.new( str.to_s ).digest].pack("m").chomp }" + when :sha + require 'sha1' + "{SHA}#{ [SHA1.new( str.to_s ).digest].pack("m").chomp }" + # when ssha + else + raise Net::LDAP::LdapError.new( "unsupported password-hash type (#{type})" ) + end + end + + end +end + + +end # class LDAP +end # module Net + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/25/25e2b9b227cb6f18e371c2b9f54071b5c31827f3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/25/25e2b9b227cb6f18e371c2b9f54071b5c31827f3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,106 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::CipheringTest < ActiveSupport::TestCase + + def test_password_should_be_encrypted + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + r = Repository::Subversion.generate!(:password => 'foo') + assert_equal 'foo', r.password + assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/) + end + end + + def test_password_should_be_clear_with_blank_key + Redmine::Configuration.with 'database_cipher_key' => '' do + r = Repository::Subversion.generate!(:password => 'foo') + assert_equal 'foo', r.password + assert_equal 'foo', r.read_attribute(:password) + end + end + + def test_password_should_be_clear_with_nil_key + Redmine::Configuration.with 'database_cipher_key' => nil do + r = Repository::Subversion.generate!(:password => 'foo') + assert_equal 'foo', r.password + assert_equal 'foo', r.read_attribute(:password) + end + end + + def test_blank_password_should_be_clear + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + r = Repository::Subversion.generate!(:password => '') + assert_equal '', r.password + assert_equal '', r.read_attribute(:password) + end + end + + def test_unciphered_password_should_be_readable + Redmine::Configuration.with 'database_cipher_key' => nil do + r = Repository::Subversion.generate!(:password => 'clear') + end + + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + r = Repository.first(:order => 'id DESC') + assert_equal 'clear', r.password + end + end + + def test_ciphered_password_with_no_cipher_key_configured_should_be_returned_ciphered + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + r = Repository::Subversion.generate!(:password => 'clear') + end + + Redmine::Configuration.with 'database_cipher_key' => '' do + r = Repository.first(:order => 'id DESC') + # password can not be deciphered + assert_nothing_raised do + assert r.password.match(/\Aaes-256-cbc:.+\Z/) + end + end + end + + def test_encrypt_all + Repository.delete_all + Redmine::Configuration.with 'database_cipher_key' => nil do + Repository::Subversion.generate!(:password => 'foo') + Repository::Subversion.generate!(:password => 'bar') + end + + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + assert Repository.encrypt_all(:password) + r = Repository.first(:order => 'id DESC') + assert_equal 'bar', r.password + assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/) + end + end + + def test_decrypt_all + Repository.delete_all + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + Repository::Subversion.generate!(:password => 'foo') + Repository::Subversion.generate!(:password => 'bar') + + assert Repository.decrypt_all(:password) + r = Repository.first(:order => 'id DESC') + assert_equal 'bar', r.password + assert_equal 'bar', r.read_attribute(:password) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/26/2671f6e5821e0f33ebda94781641aa4c51e44a69.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/26/2671f6e5821e0f33ebda94781641aa4c51e44a69.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +<%= wiki_page_breadcrumb(@page) %> + +

<%=h @original_title %>

+ +<%= error_messages_for 'page' %> + +<% labelled_tabular_form_for :wiki_page, @page, :url => { :action => 'rename' } do |f| %> +
+

<%= f.text_field :title, :required => true, :size => 100 %>

+

<%= f.check_box :redirect_existing_links %>

+

<%= f.select :parent_id, "" + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - @page.self_and_descendants, @page.parent), :label => :field_parent_title %>

+
+<%= submit_tag l(:button_rename) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/26/269ba2765067adff083d346c53c1c4aac3a7ed83.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/26/269ba2765067adff083d346c53c1c4aac3a7ed83.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,90 @@ +module CodeRay + + # A Hash of all known token kinds and their associated CSS classes. + TokenKinds = Hash.new do |h, k| + warn 'Undefined Token kind: %p' % [k] if $CODERAY_DEBUG + false + end + + # speedup + TokenKinds.compare_by_identity if TokenKinds.respond_to? :compare_by_identity + + TokenKinds.update( # :nodoc: + :annotation => 'annotation', + :attribute_name => 'attribute-name', + :attribute_value => 'attribute-value', + :binary => 'bin', + :char => 'char', + :class => 'class', + :class_variable => 'class-variable', + :color => 'color', + :comment => 'comment', + :complex => 'complex', + :constant => 'constant', + :content => 'content', + :debug => 'debug', + :decorator => 'decorator', + :definition => 'definition', + :delimiter => 'delimiter', + :directive => 'directive', + :doc => 'doc', + :doctype => 'doctype', + :doc_string => 'doc-string', + :entity => 'entity', + :error => 'error', + :escape => 'escape', + :exception => 'exception', + :filename => 'filename', + :float => 'float', + :function => 'function', + :global_variable => 'global-variable', + :hex => 'hex', + :imaginary => 'imaginary', + :important => 'important', + :include => 'include', + :inline => 'inline', + :inline_delimiter => 'inline-delimiter', + :instance_variable => 'instance-variable', + :integer => 'integer', + :key => 'key', + :keyword => 'keyword', + :label => 'label', + :local_variable => 'local-variable', + :modifier => 'modifier', + :namespace => 'namespace', + :octal => 'octal', + :predefined => 'predefined', + :predefined_constant => 'predefined-constant', + :predefined_type => 'predefined-type', + :preprocessor => 'preprocessor', + :pseudo_class => 'pseudo-class', + :regexp => 'regexp', + :reserved => 'reserved', + :shell => 'shell', + :string => 'string', + :symbol => 'symbol', + :tag => 'tag', + :type => 'type', + :value => 'value', + :variable => 'variable', + + :change => 'change', + :delete => 'delete', + :head => 'head', + :insert => 'insert', + + :eyecatcher => 'eyecatcher', + + :ident => false, + :operator => false, + + :space => false, + :plain => false + ) + + TokenKinds[:method] = TokenKinds[:function] + TokenKinds[:escape] = TokenKinds[:delimiter] + TokenKinds[:docstring] = TokenKinds[:comment] + + TokenKinds.freeze +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/26/26b129aaf0142d0284cf85c4dcc060c09b8d918d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/26/26b129aaf0142d0284cf85c4dcc060c09b8d918d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,347 @@ +require File.join(File.dirname(__FILE__), 'abstract_unit') +require File.join(File.dirname(__FILE__), 'fixtures/page') +require File.join(File.dirname(__FILE__), 'fixtures/widget') + +class VersionedTest < Test::Unit::TestCase + fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions, :authors, :landmarks, :landmark_versions + set_fixture_class :page_versions => Page::Version + + def test_saves_versioned_copy + p = Page.create! :title => 'first title', :body => 'first body' + assert !p.new_record? + assert_equal 1, p.versions.size + assert_equal 1, p.version + assert_instance_of Page.versioned_class, p.versions.first + end + + def test_saves_without_revision + p = pages(:welcome) + old_versions = p.versions.count + + p.save_without_revision + + p.without_revision do + p.update_attributes :title => 'changed' + end + + assert_equal old_versions, p.versions.count + end + + def test_rollback_with_version_number + p = pages(:welcome) + assert_equal 24, p.version + assert_equal 'Welcome to the weblog', p.title + + assert p.revert_to!(p.versions.first.version), "Couldn't revert to 23" + assert_equal 23, p.version + assert_equal 'Welcome to the weblg', p.title + end + + def test_versioned_class_name + assert_equal 'Version', Page.versioned_class_name + assert_equal 'LockedPageRevision', LockedPage.versioned_class_name + end + + def test_versioned_class + assert_equal Page::Version, Page.versioned_class + assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class + end + + def test_special_methods + assert_nothing_raised { pages(:welcome).feeling_good? } + assert_nothing_raised { pages(:welcome).versions.first.feeling_good? } + assert_nothing_raised { locked_pages(:welcome).hello_world } + assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world } + end + + def test_rollback_with_version_class + p = pages(:welcome) + assert_equal 24, p.version + assert_equal 'Welcome to the weblog', p.title + + assert p.revert_to!(p.versions.first), "Couldn't revert to 23" + assert_equal 23, p.version + assert_equal 'Welcome to the weblg', p.title + end + + def test_rollback_fails_with_invalid_revision + p = locked_pages(:welcome) + assert !p.revert_to!(locked_pages(:thinking)) + end + + def test_saves_versioned_copy_with_options + p = LockedPage.create! :title => 'first title' + assert !p.new_record? + assert_equal 1, p.versions.size + assert_instance_of LockedPage.versioned_class, p.versions.first + end + + def test_rollback_with_version_number_with_options + p = locked_pages(:welcome) + assert_equal 'Welcome to the weblog', p.title + assert_equal 'LockedPage', p.versions.first.version_type + + assert p.revert_to!(p.versions.first.version), "Couldn't revert to 23" + assert_equal 'Welcome to the weblg', p.title + assert_equal 'LockedPage', p.versions.first.version_type + end + + def test_rollback_with_version_class_with_options + p = locked_pages(:welcome) + assert_equal 'Welcome to the weblog', p.title + assert_equal 'LockedPage', p.versions.first.version_type + + assert p.revert_to!(p.versions.first), "Couldn't revert to 1" + assert_equal 'Welcome to the weblg', p.title + assert_equal 'LockedPage', p.versions.first.version_type + end + + def test_saves_versioned_copy_with_sti + p = SpecialLockedPage.create! :title => 'first title' + assert !p.new_record? + assert_equal 1, p.versions.size + assert_instance_of LockedPage.versioned_class, p.versions.first + assert_equal 'SpecialLockedPage', p.versions.first.version_type + end + + def test_rollback_with_version_number_with_sti + p = locked_pages(:thinking) + assert_equal 'So I was thinking', p.title + + assert p.revert_to!(p.versions.first.version), "Couldn't revert to 1" + assert_equal 'So I was thinking!!!', p.title + assert_equal 'SpecialLockedPage', p.versions.first.version_type + end + + def test_lock_version_works_with_versioning + p = locked_pages(:thinking) + p2 = LockedPage.find(p.id) + + p.title = 'fresh title' + p.save + assert_equal 2, p.versions.size # limit! + + assert_raises(ActiveRecord::StaleObjectError) do + p2.title = 'stale title' + p2.save + end + end + + def test_version_if_condition + p = Page.create! :title => "title" + assert_equal 1, p.version + + Page.feeling_good = false + p.save + assert_equal 1, p.version + Page.feeling_good = true + end + + def test_version_if_condition2 + # set new if condition + Page.class_eval do + def new_feeling_good() title[0..0] == 'a'; end + alias_method :old_feeling_good, :feeling_good? + alias_method :feeling_good?, :new_feeling_good + end + + p = Page.create! :title => "title" + assert_equal 1, p.version # version does not increment + assert_equal 1, p.versions(true).size + + p.update_attributes(:title => 'new title') + assert_equal 1, p.version # version does not increment + assert_equal 1, p.versions(true).size + + p.update_attributes(:title => 'a title') + assert_equal 2, p.version + assert_equal 2, p.versions(true).size + + # reset original if condition + Page.class_eval { alias_method :feeling_good?, :old_feeling_good } + end + + def test_version_if_condition_with_block + # set new if condition + old_condition = Page.version_condition + Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' } + + p = Page.create! :title => "title" + assert_equal 1, p.version # version does not increment + assert_equal 1, p.versions(true).size + + p.update_attributes(:title => 'a title') + assert_equal 1, p.version # version does not increment + assert_equal 1, p.versions(true).size + + p.update_attributes(:title => 'b title') + assert_equal 2, p.version + assert_equal 2, p.versions(true).size + + # reset original if condition + Page.version_condition = old_condition + end + + def test_version_no_limit + p = Page.create! :title => "title", :body => 'first body' + p.save + p.save + 5.times do |i| + assert_page_title p, i + end + end + + def test_version_max_limit + p = LockedPage.create! :title => "title" + p.update_attributes(:title => "title1") + p.update_attributes(:title => "title2") + 5.times do |i| + assert_page_title p, i, :lock_version + assert p.versions(true).size <= 2, "locked version can only store 2 versions" + end + end + + def test_track_altered_attributes_default_value + assert !Page.track_altered_attributes + assert LockedPage.track_altered_attributes + assert SpecialLockedPage.track_altered_attributes + end + + def test_version_order + assert_equal 23, pages(:welcome).versions.first.version + assert_equal 24, pages(:welcome).versions.last.version + end + + def test_track_altered_attributes + p = LockedPage.create! :title => "title" + assert_equal 1, p.lock_version + assert_equal 1, p.versions(true).size + + p.title = 'title' + assert !p.save_version? + p.save + assert_equal 2, p.lock_version # still increments version because of optimistic locking + assert_equal 1, p.versions(true).size + + p.title = 'updated title' + assert p.save_version? + p.save + assert_equal 3, p.lock_version + assert_equal 1, p.versions(true).size # version 1 deleted + + p.title = 'updated title!' + assert p.save_version? + p.save + assert_equal 4, p.lock_version + assert_equal 2, p.versions(true).size # version 1 deleted + end + + def assert_page_title(p, i, version_field = :version) + p.title = "title#{i}" + p.save + assert_equal "title#{i}", p.title + assert_equal (i+4), p.send(version_field) + end + + def test_find_versions + assert_equal 2, locked_pages(:welcome).versions.size + assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).length + assert_equal 2, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length + assert_equal 0, locked_pages(:thinking).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length + assert_equal 2, locked_pages(:welcome).versions.length + end + + def test_find_version + assert_equal page_versions(:welcome_1), Page.find_version(pages(:welcome).id, 23) + assert_equal page_versions(:welcome_2), Page.find_version(pages(:welcome).id, 24) + assert_equal pages(:welcome), Page.find_version(pages(:welcome).id) + + assert_equal page_versions(:welcome_1), pages(:welcome).find_version(23) + assert_equal page_versions(:welcome_2), pages(:welcome).find_version(24) + assert_equal pages(:welcome), pages(:welcome).find_version + + assert_raise(ActiveRecord::RecordNotFound) { Page.find_version(pages(:welcome).id, 1) } + assert_raise(ActiveRecord::RecordNotFound) { Page.find_version(0, 23) } + end + + def test_with_sequence + assert_equal 'widgets_seq', Widget.versioned_class.sequence_name + 3.times { Widget.create! :name => 'new widget' } + assert_equal 3, Widget.count + assert_equal 3, Widget.versioned_class.count + end + + def test_has_many_through + assert_equal [authors(:caged), authors(:mly)], pages(:welcome).authors + end + + def test_has_many_through_with_custom_association + assert_equal [authors(:caged), authors(:mly)], pages(:welcome).revisors + end + + def test_referential_integrity + pages(:welcome).destroy + assert_equal 0, Page.count + assert_equal 0, Page::Version.count + end + + def test_association_options + association = Page.reflect_on_association(:versions) + options = association.options + assert_equal :delete_all, options[:dependent] + assert_equal 'version', options[:order] + + association = Widget.reflect_on_association(:versions) + options = association.options + assert_equal :nullify, options[:dependent] + assert_equal 'version desc', options[:order] + assert_equal 'widget_id', options[:foreign_key] + + widget = Widget.create! :name => 'new widget' + assert_equal 1, Widget.count + assert_equal 1, Widget.versioned_class.count + widget.destroy + assert_equal 0, Widget.count + assert_equal 1, Widget.versioned_class.count + end + + def test_versioned_records_should_belong_to_parent + page = pages(:welcome) + page_version = page.versions.last + assert_equal page, page_version.page + end + + def test_unaltered_attributes + landmarks(:washington).attributes = landmarks(:washington).attributes.except("id") + assert !landmarks(:washington).changed? + end + + def test_unchanged_string_attributes + landmarks(:washington).attributes = landmarks(:washington).attributes.except("id").inject({}) { |params, (key, value)| params.update(key => value.to_s) } + assert !landmarks(:washington).changed? + end + + def test_should_find_earliest_version + assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest + end + + def test_should_find_latest_version + assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest + end + + def test_should_find_previous_version + assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous + assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2)) + end + + def test_should_find_next_version + assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next + assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1)) + end + + def test_should_find_version_count + assert_equal 24, pages(:welcome).versions_count + assert_equal 24, page_versions(:welcome_1).versions_count + assert_equal 24, page_versions(:welcome_2).versions_count + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/26/26bdda62d4b587261b27b313063059d6973d310e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/26/26bdda62d4b587261b27b313063059d6973d310e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/lib/acts_as_event' +ActiveRecord::Base.send(:include, Redmine::Acts::Event) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/26/26f2b8dec33ec3e8eb2d5b55094ac09d33160993.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/26/26f2b8dec33ec3e8eb2d5b55094ac09d33160993.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,603 @@ +require File.dirname(__FILE__) + '/test_helper' + +class Note < ActiveRecord::Base + acts_as_nested_set :scope => [:notable_id, :notable_type] +end + +class AwesomeNestedSetTest < Test::Unit::TestCase + + class Default < ActiveRecord::Base + acts_as_nested_set + set_table_name 'categories' + end + class Scoped < ActiveRecord::Base + acts_as_nested_set :scope => :organization + set_table_name 'categories' + end + + def test_left_column_default + assert_equal 'lft', Default.acts_as_nested_set_options[:left_column] + end + + def test_right_column_default + assert_equal 'rgt', Default.acts_as_nested_set_options[:right_column] + end + + def test_parent_column_default + assert_equal 'parent_id', Default.acts_as_nested_set_options[:parent_column] + end + + def test_scope_default + assert_nil Default.acts_as_nested_set_options[:scope] + end + + def test_left_column_name + assert_equal 'lft', Default.left_column_name + assert_equal 'lft', Default.new.left_column_name + end + + def test_right_column_name + assert_equal 'rgt', Default.right_column_name + assert_equal 'rgt', Default.new.right_column_name + end + + def test_parent_column_name + assert_equal 'parent_id', Default.parent_column_name + assert_equal 'parent_id', Default.new.parent_column_name + end + + def test_quoted_left_column_name + quoted = Default.connection.quote_column_name('lft') + assert_equal quoted, Default.quoted_left_column_name + assert_equal quoted, Default.new.quoted_left_column_name + end + + def test_quoted_right_column_name + quoted = Default.connection.quote_column_name('rgt') + assert_equal quoted, Default.quoted_right_column_name + assert_equal quoted, Default.new.quoted_right_column_name + end + + def test_left_column_protected_from_assignment + assert_raises(ActiveRecord::ActiveRecordError) { Category.new.lft = 1 } + end + + def test_right_column_protected_from_assignment + assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 } + end + + def test_parent_column_protected_from_assignment + assert_raises(ActiveRecord::ActiveRecordError) { Category.new.parent_id = 1 } + end + + def test_colums_protected_on_initialize + c = Category.new(:lft => 1, :rgt => 2, :parent_id => 3) + assert_nil c.lft + assert_nil c.rgt + assert_nil c.parent_id + end + + def test_scoped_appends_id + assert_equal :organization_id, Scoped.acts_as_nested_set_options[:scope] + end + + def test_roots_class_method + assert_equal Category.find_all_by_parent_id(nil), Category.roots + end + + def test_root_class_method + assert_equal categories(:top_level), Category.root + end + + def test_root + assert_equal categories(:top_level), categories(:child_3).root + end + + def test_root? + assert categories(:top_level).root? + assert categories(:top_level_2).root? + end + + def test_leaves_class_method + assert_equal Category.find(:all, :conditions => "#{Category.right_column_name} - #{Category.left_column_name} = 1"), Category.leaves + assert_equal Category.leaves.count, 4 + assert (Category.leaves.include? categories(:child_1)) + assert (Category.leaves.include? categories(:child_2_1)) + assert (Category.leaves.include? categories(:child_3)) + assert (Category.leaves.include? categories(:top_level_2)) + end + + def test_leaf + assert categories(:child_1).leaf? + assert categories(:child_2_1).leaf? + assert categories(:child_3).leaf? + assert categories(:top_level_2).leaf? + + assert !categories(:top_level).leaf? + assert !categories(:child_2).leaf? + end + + def test_parent + assert_equal categories(:child_2), categories(:child_2_1).parent + end + + def test_self_and_ancestors + child = categories(:child_2_1) + self_and_ancestors = [categories(:top_level), categories(:child_2), child] + assert_equal self_and_ancestors, child.self_and_ancestors + end + + def test_ancestors + child = categories(:child_2_1) + ancestors = [categories(:top_level), categories(:child_2)] + assert_equal ancestors, child.ancestors + end + + def test_self_and_siblings + child = categories(:child_2) + self_and_siblings = [categories(:child_1), child, categories(:child_3)] + assert_equal self_and_siblings, child.self_and_siblings + assert_nothing_raised do + tops = [categories(:top_level), categories(:top_level_2)] + assert_equal tops, categories(:top_level).self_and_siblings + end + end + + def test_siblings + child = categories(:child_2) + siblings = [categories(:child_1), categories(:child_3)] + assert_equal siblings, child.siblings + end + + def test_leaves + leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3), categories(:top_level_2)] + assert categories(:top_level).leaves, leaves + end + + def test_level + assert_equal 0, categories(:top_level).level + assert_equal 1, categories(:child_1).level + assert_equal 2, categories(:child_2_1).level + end + + def test_has_children? + assert categories(:child_2_1).children.empty? + assert !categories(:child_2).children.empty? + assert !categories(:top_level).children.empty? + end + + def test_self_and_descendents + parent = categories(:top_level) + self_and_descendants = [parent, categories(:child_1), categories(:child_2), + categories(:child_2_1), categories(:child_3)] + assert_equal self_and_descendants, parent.self_and_descendants + assert_equal self_and_descendants, parent.self_and_descendants.count + end + + def test_descendents + lawyers = Category.create!(:name => "lawyers") + us = Category.create!(:name => "United States") + us.move_to_child_of(lawyers) + patent = Category.create!(:name => "Patent Law") + patent.move_to_child_of(us) + lawyers.reload + + assert_equal 1, lawyers.children.size + assert_equal 1, us.children.size + assert_equal 2, lawyers.descendants.size + end + + def test_self_and_descendents + parent = categories(:top_level) + descendants = [categories(:child_1), categories(:child_2), + categories(:child_2_1), categories(:child_3)] + assert_equal descendants, parent.descendants + end + + def test_children + category = categories(:top_level) + category.children.each {|c| assert_equal category.id, c.parent_id } + end + + def test_is_or_is_ancestor_of? + assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_1)) + assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1)) + assert categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1)) + assert !categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2)) + assert !categories(:child_1).is_or_is_ancestor_of?(categories(:child_2)) + assert categories(:child_1).is_or_is_ancestor_of?(categories(:child_1)) + end + + def test_is_ancestor_of? + assert categories(:top_level).is_ancestor_of?(categories(:child_1)) + assert categories(:top_level).is_ancestor_of?(categories(:child_2_1)) + assert categories(:child_2).is_ancestor_of?(categories(:child_2_1)) + assert !categories(:child_2_1).is_ancestor_of?(categories(:child_2)) + assert !categories(:child_1).is_ancestor_of?(categories(:child_2)) + assert !categories(:child_1).is_ancestor_of?(categories(:child_1)) + end + + def test_is_or_is_ancestor_of_with_scope + root = Scoped.root + child = root.children.first + assert root.is_or_is_ancestor_of?(child) + child.update_attribute :organization_id, 'different' + assert !root.is_or_is_ancestor_of?(child) + end + + def test_is_or_is_descendant_of? + assert categories(:child_1).is_or_is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2)) + assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1)) + assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_1)) + assert categories(:child_1).is_or_is_descendant_of?(categories(:child_1)) + end + + def test_is_descendant_of? + assert categories(:child_1).is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_descendant_of?(categories(:child_2)) + assert !categories(:child_2).is_descendant_of?(categories(:child_2_1)) + assert !categories(:child_2).is_descendant_of?(categories(:child_1)) + assert !categories(:child_1).is_descendant_of?(categories(:child_1)) + end + + def test_is_or_is_descendant_of_with_scope + root = Scoped.root + child = root.children.first + assert child.is_or_is_descendant_of?(root) + child.update_attribute :organization_id, 'different' + assert !child.is_or_is_descendant_of?(root) + end + + def test_same_scope? + root = Scoped.root + child = root.children.first + assert child.same_scope?(root) + child.update_attribute :organization_id, 'different' + assert !child.same_scope?(root) + end + + def test_left_sibling + assert_equal categories(:child_1), categories(:child_2).left_sibling + assert_equal categories(:child_2), categories(:child_3).left_sibling + end + + def test_left_sibling_of_root + assert_nil categories(:top_level).left_sibling + end + + def test_left_sibling_without_siblings + assert_nil categories(:child_2_1).left_sibling + end + + def test_left_sibling_of_leftmost_node + assert_nil categories(:child_1).left_sibling + end + + def test_right_sibling + assert_equal categories(:child_3), categories(:child_2).right_sibling + assert_equal categories(:child_2), categories(:child_1).right_sibling + end + + def test_right_sibling_of_root + assert_equal categories(:top_level_2), categories(:top_level).right_sibling + assert_nil categories(:top_level_2).right_sibling + end + + def test_right_sibling_without_siblings + assert_nil categories(:child_2_1).right_sibling + end + + def test_right_sibling_of_rightmost_node + assert_nil categories(:child_3).right_sibling + end + + def test_move_left + categories(:child_2).move_left + assert_nil categories(:child_2).left_sibling + assert_equal categories(:child_1), categories(:child_2).right_sibling + assert Category.valid? + end + + def test_move_right + categories(:child_2).move_right + assert_nil categories(:child_2).right_sibling + assert_equal categories(:child_3), categories(:child_2).left_sibling + assert Category.valid? + end + + def test_move_to_left_of + categories(:child_3).move_to_left_of(categories(:child_1)) + assert_nil categories(:child_3).left_sibling + assert_equal categories(:child_1), categories(:child_3).right_sibling + assert Category.valid? + end + + def test_move_to_right_of + categories(:child_1).move_to_right_of(categories(:child_3)) + assert_nil categories(:child_1).right_sibling + assert_equal categories(:child_3), categories(:child_1).left_sibling + assert Category.valid? + end + + def test_move_to_root + categories(:child_2).move_to_root + assert_nil categories(:child_2).parent + assert_equal 0, categories(:child_2).level + assert_equal 1, categories(:child_2_1).level + assert_equal 1, categories(:child_2).left + assert_equal 4, categories(:child_2).right + assert Category.valid? + end + + def test_move_to_child_of + categories(:child_1).move_to_child_of(categories(:child_3)) + assert_equal categories(:child_3).id, categories(:child_1).parent_id + assert Category.valid? + end + + def test_move_to_child_of_appends_to_end + child = Category.create! :name => 'New Child' + child.move_to_child_of categories(:top_level) + assert_equal child, categories(:top_level).children.last + end + + def test_subtree_move_to_child_of + assert_equal 4, categories(:child_2).left + assert_equal 7, categories(:child_2).right + + assert_equal 2, categories(:child_1).left + assert_equal 3, categories(:child_1).right + + categories(:child_2).move_to_child_of(categories(:child_1)) + assert Category.valid? + assert_equal categories(:child_1).id, categories(:child_2).parent_id + + assert_equal 3, categories(:child_2).left + assert_equal 6, categories(:child_2).right + assert_equal 2, categories(:child_1).left + assert_equal 7, categories(:child_1).right + end + + def test_slightly_difficult_move_to_child_of + assert_equal 11, categories(:top_level_2).left + assert_equal 12, categories(:top_level_2).right + + # create a new top-level node and move single-node top-level tree inside it. + new_top = Category.create(:name => 'New Top') + assert_equal 13, new_top.left + assert_equal 14, new_top.right + + categories(:top_level_2).move_to_child_of(new_top) + + assert Category.valid? + assert_equal new_top.id, categories(:top_level_2).parent_id + + assert_equal 12, categories(:top_level_2).left + assert_equal 13, categories(:top_level_2).right + assert_equal 11, new_top.left + assert_equal 14, new_top.right + end + + def test_difficult_move_to_child_of + assert_equal 1, categories(:top_level).left + assert_equal 10, categories(:top_level).right + assert_equal 5, categories(:child_2_1).left + assert_equal 6, categories(:child_2_1).right + + # create a new top-level node and move an entire top-level tree inside it. + new_top = Category.create(:name => 'New Top') + categories(:top_level).move_to_child_of(new_top) + categories(:child_2_1).reload + assert Category.valid? + assert_equal new_top.id, categories(:top_level).parent_id + + assert_equal 4, categories(:top_level).left + assert_equal 13, categories(:top_level).right + assert_equal 8, categories(:child_2_1).left + assert_equal 9, categories(:child_2_1).right + end + + #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent + def test_move_to_child_more_than_once_per_parent_rebuild + root1 = Category.create(:name => 'Root1') + root2 = Category.create(:name => 'Root2') + root3 = Category.create(:name => 'Root3') + + root2.move_to_child_of root1 + root3.move_to_child_of root1 + + output = Category.roots.last.to_text + Category.update_all('lft = null, rgt = null') + Category.rebuild! + + assert_equal Category.roots.last.to_text, output + end + + # doing move_to_child twice onto same parent from the furthest right first + def test_move_to_child_more_than_once_per_parent_outside_in + node1 = Category.create(:name => 'Node-1') + node2 = Category.create(:name => 'Node-2') + node3 = Category.create(:name => 'Node-3') + + node2.move_to_child_of node1 + node3.move_to_child_of node1 + + output = Category.roots.last.to_text + Category.update_all('lft = null, rgt = null') + Category.rebuild! + + assert_equal Category.roots.last.to_text, output + end + + + def test_valid_with_null_lefts + assert Category.valid? + Category.update_all('lft = null') + assert !Category.valid? + end + + def test_valid_with_null_rights + assert Category.valid? + Category.update_all('rgt = null') + assert !Category.valid? + end + + def test_valid_with_missing_intermediate_node + # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree. + assert Category.valid? + Category.delete(categories(:child_2).id) + assert Category.valid? + end + + def test_valid_with_overlapping_and_rights + assert Category.valid? + categories(:top_level_2)['lft'] = 0 + categories(:top_level_2).save + assert !Category.valid? + end + + def test_rebuild + assert Category.valid? + before_text = Category.root.to_text + Category.update_all('lft = null, rgt = null') + Category.rebuild! + assert Category.valid? + assert_equal before_text, Category.root.to_text + end + + def test_move_possible_for_sibling + assert categories(:child_2).move_possible?(categories(:child_1)) + end + + def test_move_not_possible_to_self + assert !categories(:top_level).move_possible?(categories(:top_level)) + end + + def test_move_not_possible_to_parent + categories(:top_level).descendants.each do |descendant| + assert !categories(:top_level).move_possible?(descendant) + assert descendant.move_possible?(categories(:top_level)) + end + end + + def test_is_or_is_ancestor_of? + [:child_1, :child_2, :child_2_1, :child_3].each do |c| + assert categories(:top_level).is_or_is_ancestor_of?(categories(c)) + end + assert !categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2)) + end + + def test_left_and_rights_valid_with_blank_left + assert Category.left_and_rights_valid? + categories(:child_2)[:lft] = nil + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_blank_right + assert Category.left_and_rights_valid? + categories(:child_2)[:rgt] = nil + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_equal + assert Category.left_and_rights_valid? + categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt] + categories(:top_level_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_left_equal_to_parent + assert Category.left_and_rights_valid? + categories(:child_2)[:lft] = categories(:top_level)[:lft] + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_right_equal_to_parent + assert Category.left_and_rights_valid? + categories(:child_2)[:rgt] = categories(:top_level)[:rgt] + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_moving_dirty_objects_doesnt_invalidate_tree + r1 = Category.create + r2 = Category.create + r3 = Category.create + r4 = Category.create + nodes = [r1, r2, r3, r4] + + r2.move_to_child_of(r1) + assert Category.valid? + + r3.move_to_child_of(r1) + assert Category.valid? + + r4.move_to_child_of(r2) + assert Category.valid? + end + + def test_multi_scoped_no_duplicates_for_columns? + assert_nothing_raised do + Note.no_duplicates_for_columns? + end + end + + def test_multi_scoped_all_roots_valid? + assert_nothing_raised do + Note.all_roots_valid? + end + end + + def test_multi_scoped + note1 = Note.create!(:body => "A", :notable_id => 2, :notable_type => 'Category') + note2 = Note.create!(:body => "B", :notable_id => 2, :notable_type => 'Category') + note3 = Note.create!(:body => "C", :notable_id => 2, :notable_type => 'Default') + + assert_equal [note1, note2], note1.self_and_siblings + assert_equal [note3], note3.self_and_siblings + end + + def test_multi_scoped_rebuild + root = Note.create!(:body => "A", :notable_id => 3, :notable_type => 'Category') + child1 = Note.create!(:body => "B", :notable_id => 3, :notable_type => 'Category') + child2 = Note.create!(:body => "C", :notable_id => 3, :notable_type => 'Category') + + child1.move_to_child_of root + child2.move_to_child_of root + + Note.update_all('lft = null, rgt = null') + Note.rebuild! + + assert_equal Note.roots.find_by_body('A'), root + assert_equal [child1, child2], Note.roots.find_by_body('A').children + end + + def test_same_scope_with_multi_scopes + assert_nothing_raised do + notes(:scope1).same_scope?(notes(:child_1)) + end + assert notes(:scope1).same_scope?(notes(:child_1)) + assert notes(:child_1).same_scope?(notes(:scope1)) + assert !notes(:scope1).same_scope?(notes(:scope2)) + end + + def test_quoting_of_multi_scope_column_names + assert_equal ["\"notable_id\"", "\"notable_type\""], Note.quoted_scope_column_names + end + + def test_equal_in_same_scope + assert_equal notes(:scope1), notes(:scope1) + assert_not_equal notes(:scope1), notes(:child_1) + end + + def test_equal_in_different_scopes + assert_not_equal notes(:scope1), notes(:scope2) + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/26/26f86ae1682862e19961fc81b57435b3f97dc14a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/26/26f86ae1682862e19961fc81b57435b3f97dc14a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToCustomValues < ActiveRecord::Migration + def self.up + add_index :custom_values, :custom_field_id + end + + def self.down + remove_index :custom_values, :custom_field_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/2700680223a9a6a9345e7969115cf8bb271e9f2a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/2700680223a9a6a9345e7969115cf8bb271e9f2a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToChangesets < ActiveRecord::Migration + def self.up + add_index :changesets, :user_id + add_index :changesets, :repository_id + end + + def self.down + remove_index :changesets, :user_id + remove_index :changesets, :repository_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/273ac825eb891aaec6af1c5e2e94f14d0663c303.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/273ac825eb891aaec6af1c5e2e94f14d0663c303.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,61 @@ +module CodeRay +module Encoders + + # = Debug Encoder + # + # Fast encoder producing simple debug output. + # + # It is readable and diff-able and is used for testing. + # + # You cannot fully restore the tokens information from the + # output, because consecutive :space tokens are merged. + # Use Tokens#dump for caching purposes. + # + # See also: Scanners::Debug + class Debug < Encoder + + register_for :debug + + FILE_EXTENSION = 'raydebug' + + def initialize options = {} + super + @opened = [] + end + + def text_token text, kind + if kind == :space + @out << text + else + # TODO: Escape ( + text = text.gsub(/[)\\]/, '\\\\\0') # escape ) and \ + @out << kind.to_s << '(' << text << ')' + end + end + + def begin_group kind + @opened << kind + @out << kind.to_s << '<' + end + + def end_group kind + if @opened.last != kind + puts @out + raise "we are inside #{@opened.inspect}, not #{kind}" + end + @opened.pop + @out << '>' + end + + def begin_line kind + @out << kind.to_s << '[' + end + + def end_line kind + @out << ']' + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/274fb7590cee2a1c0d94dfbcc4c004e94678fa88.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/274fb7590cee2a1c0d94dfbcc4c004e94678fa88.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +sqlite3: + adapter: sqlite3 + dbfile: awesome_nested_set.sqlite3.db +sqlite3mem: + :adapter: sqlite3 + :dbfile: ":memory:" +postgresql: + :adapter: postgresql + :username: postgres + :password: postgres + :database: awesome_nested_set_plugin_test + :min_messages: ERROR +mysql: + :adapter: mysql + :host: localhost + :username: root + :password: + :database: awesome_nested_set_plugin_test \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/275a63d95374044297ed252103e82089ce4c9a74.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/275a63d95374044297ed252103e82089ce4c9a74.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,86 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::AttachmentsTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :attachments + + def setup + Setting.rest_api_enabled = '1' + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + end + + context "/attachments/:id" do + context "GET" do + should "return the attachment" do + get '/attachments/7.xml', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'attachment', + :child => { + :tag => 'id', + :content => '7', + :sibling => { + :tag => 'filename', + :content => 'archive.zip', + :sibling => { + :tag => 'content_url', + :content => 'http://www.example.com/attachments/download/7/archive.zip' + } + } + } + end + + should "deny access without credentials" do + get '/attachments/7.xml' + assert_response 401 + set_tmp_attachments_directory + end + end + end + + context "/attachments/download/:id/:filename" do + context "GET" do + should "return the attachment content" do + get '/attachments/download/7/archive.zip', + {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/octet-stream', @response.content_type + set_tmp_attachments_directory + end + + should "deny access without credentials" do + get '/attachments/download/7/archive.zip' + assert_response 302 + set_tmp_attachments_directory + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/27952988c7b2ad95ea1ef729436ace0c3896dd74.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/27952988c7b2ad95ea1ef729436ace0c3896dd74.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) + +# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like: +# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired +require "dispatcher" + +ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun) +Dispatcher.dispatch \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/2798cf8bdb60e5a48dc833a97dea5cc70e29382c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/2798cf8bdb60e5a48dc833a97dea5cc70e29382c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,76 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ProjectsHelperTest < ActionView::TestCase + include ApplicationHelper + include ProjectsHelper + + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :versions, + :projects_trackers, + :member_roles, + :members, + :groups_users, + :enabled_modules, + :workflows + + def setup + super + set_language_if_valid('en') + User.current = nil + end + + def test_link_to_version_within_project + @project = Project.find(2) + User.current = User.find(1) + assert_equal 'Alpha', link_to_version(Version.find(5)) + end + + def test_link_to_version + User.current = User.find(1) + assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5)) + end + + def test_link_to_private_version + assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5)) + end + + def test_link_to_version_invalid_version + assert_equal '', link_to_version(Object) + end + + def test_format_version_name_within_project + @project = Project.find(1) + assert_equal "0.1", format_version_name(Version.find(1)) + end + + def test_format_version_name + assert_equal "eCookbook - 0.1", format_version_name(Version.find(1)) + end + + def test_format_version_name_for_system_version + assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7)) + end + + def test_version_options_for_select_with_no_versions + assert_equal '', version_options_for_select([]) + assert_equal '', version_options_for_select([], Version.find(1)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/27ca0e4d3dcbae405bcd6b8ff364b70b5542b197.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/27/27ca0e4d3dcbae405bcd6b8ff364b70b5542b197.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class CustomFieldsHelperTest < ActionView::TestCase + include CustomFieldsHelper + include Redmine::I18n + + def test_format_boolean_value + I18n.locale = 'en' + assert_equal 'Yes', format_value('1', 'bool') + assert_equal 'No', format_value('0', 'bool') + end + + def test_unknow_field_format_should_be_edited_as_string + field = CustomField.new(:field_format => 'foo') + value = CustomValue.new(:value => 'bar', :custom_field => field) + field.id = 52 + + assert_equal '', + custom_field_tag('object', value) + end + + def test_unknow_field_format_should_be_bulk_edited_as_string + field = CustomField.new(:field_format => 'foo') + field.id = 52 + + assert_equal '', + custom_field_tag_for_bulk_edit('object', field) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/27/27dc3cba8b2ec907452d51cff92911de04b8d96f.svn-base Binary file .svn/pristine/27/27dc3cba8b2ec907452d51cff92911de04b8d96f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/28/2806c2e1c64e92f9ca9d69815ab933298ecbeb25.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/28/2806c2e1c64e92f9ca9d69815ab933298ecbeb25.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +module OpenIdAuthentication + class Association < ActiveRecord::Base + set_table_name :open_id_authentication_associations + + def from_record + OpenID::Association.new(handle, secret, issued, lifetime, assoc_type) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/28/2864783005a4ba0460d387fef08dd617a059d205.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/28/2864783005a4ba0460d387fef08dd617a059d205.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,61 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::ConfigurationTest < ActiveSupport::TestCase + def setup + @conf = Redmine::Configuration + end + + def test_empty + assert_kind_of Hash, load_conf('empty.yml', 'test') + end + + def test_default + assert_kind_of Hash, load_conf('default.yml', 'test') + assert_equal 'foo', @conf['somesetting'] + end + + def test_no_default + assert_kind_of Hash, load_conf('no_default.yml', 'test') + assert_equal 'foo', @conf['somesetting'] + end + + def test_overrides + assert_kind_of Hash, load_conf('overrides.yml', 'test') + assert_equal 'bar', @conf['somesetting'] + end + + def test_with + load_conf('default.yml', 'test') + assert_equal 'foo', @conf['somesetting'] + @conf.with 'somesetting' => 'bar' do + assert_equal 'bar', @conf['somesetting'] + end + assert_equal 'foo', @conf['somesetting'] + end + + private + + def load_conf(file, env) + @conf.load( + :file => File.join(Rails.root, 'test', 'fixtures', 'configuration', file), + :env => env + ) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/28/28ac0f519eb9b5a961e5bcb8825c18def371a932.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/28/28ac0f519eb9b5a961e5bcb8825c18def371a932.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= @note %> (from application) \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/28/28c55237005397dcf3a85d298cbf8e75ea928379.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/28/28c55237005397dcf3a85d298cbf8e75ea928379.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeProjectsHomepageLimit < ActiveRecord::Migration + def self.up + change_column :projects, :homepage, :string, :limit => nil, :default => '' + end + + def self.down + change_column :projects, :homepage, :string, :limit => 60, :default => '' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/28/28e4e2427d2a8e8bd98db1e2c7317b6c662eb82a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/28/28e4e2427d2a8e8bd98db1e2c7317b6c662eb82a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +

<%=l(:label_news)%>

+ +<% labelled_tabular_form_for @news, :html => { :id => 'news-form', :method => :put } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<%= link_to_remote l(:label_preview), + { :url => preview_news_path(:project_id => @project), + :method => 'get', + :update => 'preview', + :with => "Form.serialize('news-form')" + }, :accesskey => accesskey(:preview) %> +<% end %> +
+ +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/28/28f61d6f82da16a79bf305217d0869e0a3170794.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/28/28f61d6f82da16a79bf305217d0869e0a3170794.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +
+<%= link_to_if_authorized l(:label_document_new), + {:controller => 'documents', :action => 'new', :project_id => @project}, + :class => 'icon icon-add', + :onclick => 'Element.show("add-document"); Form.Element.focus("document_title"); return false;' %> +
+ + + +

<%=l(:label_document_plural)%>

+ +<% if @grouped.empty? %>

<%= l(:label_no_data) %>

<% end %> + +<% @grouped.keys.sort.each do |group| %> +

<%= group %>

+ <%= render :partial => 'documents/document', :collection => @grouped[group] %> +<% end %> + +<% content_for :sidebar do %> +

<%= l(:label_sort_by, '') %>

+ <% form_tag({}, :method => :get) do %> +
+
+
+ + <% end %> +<% end %> + +<% html_title(l(:label_document_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/29/2916f748eef73ff691bcfc74e7c1ac23960d090b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/29/2916f748eef73ff691bcfc74e7c1ac23960d090b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,294 @@ +# $Id: ber.rb 142 2006-07-26 12:20:33Z blackhedd $ +# +# NET::BER +# Mixes ASN.1/BER convenience methods into several standard classes. +# Also provides BER parsing functionality. +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Gmail: garbagecat10 +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +#--------------------------------------------------------------------------- +# +# + + + + +module Net + + module BER + + class BerError < Exception; end + + + # This module is for mixing into IO and IO-like objects. + module BERParser + + # The order of these follows the class-codes in BER. + # Maybe this should have been a hash. + TagClasses = [:universal, :application, :context_specific, :private] + + BuiltinSyntax = { + :universal => { + :primitive => { + 1 => :boolean, + 2 => :integer, + 4 => :string, + 10 => :integer, + }, + :constructed => { + 16 => :array, + 17 => :array + } + } + } + + # + # read_ber + # TODO: clean this up so it works properly with partial + # packets coming from streams that don't block when + # we ask for more data (like StringIOs). At it is, + # this can throw TypeErrors and other nasties. + # + def read_ber syntax=nil + return nil if (StringIO == self.class) and eof? + + id = getc # don't trash this value, we'll use it later + tag = id & 31 + tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" ) + tagclass = TagClasses[ id >> 6 ] + encoding = (id & 0x20 != 0) ? :constructed : :primitive + + n = getc + lengthlength,contentlength = if n <= 127 + [1,n] + else + j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc} + [1 + (n & 127), j] + end + + newobj = read contentlength + + objtype = nil + [syntax, BuiltinSyntax].each {|syn| + if syn && (ot = syn[tagclass]) && (ot = ot[encoding]) && ot[tag] + objtype = ot[tag] + break + end + } + + obj = case objtype + when :boolean + newobj != "\000" + when :string + (newobj || "").dup + when :integer + j = 0 + newobj.each_byte {|b| j = (j << 8) + b} + j + when :array + seq = [] + sio = StringIO.new( newobj || "" ) + # Interpret the subobject, but note how the loop + # is built: nil ends the loop, but false (a valid + # BER value) does not! + while (e = sio.read_ber(syntax)) != nil + seq << e + end + seq + else + raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" ) + end + + # Add the identifier bits into the object if it's a String or an Array. + # We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway. + obj and ([String,Array].include? obj.class) and obj.instance_eval "def ber_identifier; #{id}; end" + obj + + end + + end # module BERParser + end # module BER + +end # module Net + + +class IO + include Net::BER::BERParser +end + +require "stringio" +class StringIO + include Net::BER::BERParser +end + +begin + require 'openssl' + class OpenSSL::SSL::SSLSocket + include Net::BER::BERParser + end +rescue LoadError +# Ignore LoadError. +# DON'T ignore NameError, which means the SSLSocket class +# is somehow unavailable on this implementation of Ruby's openssl. +# This may be WRONG, however, because we don't yet know how Ruby's +# openssl behaves on machines with no OpenSSL library. I suppose +# it's possible they do not fail to require 'openssl' but do not +# create the classes. So this code is provisional. +# Also, you might think that OpenSSL::SSL::SSLSocket inherits from +# IO so we'd pick it up above. But you'd be wrong. +end + +class String + def read_ber syntax=nil + StringIO.new(self).read_ber(syntax) + end +end + + + +#---------------------------------------------- + + +class FalseClass + # + # to_ber + # + def to_ber + "\001\001\000" + end +end + + +class TrueClass + # + # to_ber + # + def to_ber + "\001\001\001" + end +end + + + +class Fixnum + # + # to_ber + # + def to_ber + i = [self].pack('w') + [2, i.length].pack("CC") + i + end + + # + # to_ber_enumerated + # + def to_ber_enumerated + i = [self].pack('w') + [10, i.length].pack("CC") + i + end + + # + # to_ber_length_encoding + # + def to_ber_length_encoding + if self <= 127 + [self].pack('C') + else + i = [self].pack('N').sub(/^[\0]+/,"") + [0x80 + i.length].pack('C') + i + end + end + +end # class Fixnum + + +class Bignum + + def to_ber + i = [self].pack('w') + i.length > 126 and raise Net::BER::BerError.new( "range error in bignum" ) + [2, i.length].pack("CC") + i + end + +end + + + +class String + # + # to_ber + # A universal octet-string is tag number 4, + # but others are possible depending on the context, so we + # let the caller give us one. + # The preferred way to do this in user code is via to_ber_application_sring + # and to_ber_contextspecific. + # + def to_ber code = 4 + [code].pack('C') + length.to_ber_length_encoding + self + end + + # + # to_ber_application_string + # + def to_ber_application_string code + to_ber( 0x40 + code ) + end + + # + # to_ber_contextspecific + # + def to_ber_contextspecific code + to_ber( 0x80 + code ) + end + +end # class String + + + +class Array + # + # to_ber_appsequence + # An application-specific sequence usually gets assigned + # a tag that is meaningful to the particular protocol being used. + # This is different from the universal sequence, which usually + # gets a tag value of 16. + # Now here's an interesting thing: We're adding the X.690 + # "application constructed" code at the top of the tag byte (0x60), + # but some clients, notably ldapsearch, send "context-specific + # constructed" (0xA0). The latter would appear to violate RFC-1777, + # but what do I know? We may need to change this. + # + + def to_ber id = 0; to_ber_seq_internal( 0x30 + id ); end + def to_ber_set id = 0; to_ber_seq_internal( 0x31 + id ); end + def to_ber_sequence id = 0; to_ber_seq_internal( 0x30 + id ); end + def to_ber_appsequence id = 0; to_ber_seq_internal( 0x60 + id ); end + def to_ber_contextspecific id = 0; to_ber_seq_internal( 0xA0 + id ); end + + private + def to_ber_seq_internal code + s = self.to_s + [code].pack('C') + s.length.to_ber_length_encoding + s + end + +end # class Array + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/29/298a0f40cd69f5addffe2e18d1097c3dc9aa6c75.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/29/298a0f40cd69f5addffe2e18d1097c3dc9aa6c75.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,789 @@ +Changes from 2.14 to 2.15 + +- improved hinting in Sans Oblique to deal with some spacing and inconsistency + issues (by Ben Laenen) +- added anchors to Mono Book, and added GPOS rules for combining diacritics to + show up as zero width glyphs (by Ben Laenen) +- removed U+F21C (PUA), it was copy of U+2C64 from Latin Extended C (by Eugeniy + Meshcheryakov) +- added U+27E6-U+27E7 to Sans (by Gee Fung Sit) +- added U+1407, U+1409, U+140C-U+141B, U+141D-U+1425, U+1427-U+142E, + U+1435-U+1438, U+143A-U+1449, U+1452, U+1454, U+1457-U+1465, U+1467-U+146A, + U+1471, U+1474-U+1482, U+1484-U+1488, U+148F, U+1492, U+14A0, U+14A2, U+14A9, + U+14AC-U+14BA, U+14BC, U+14BD, U+14C6, U+14C9-U+14CF, U+14D1, U+14D2, U+14D9, + U+14DC-U+14E9, U+14EC, U+14F3, U+14F6-U+1504, U+1506, U+1507, U+1510-U+1525, + U+152C, U+152F-U+153D, U+1540, U+1541, U+154E, U+154F, U+1552, U+155B, U+155C, + U+1568, U+1569, U+1574-U+157B, U+157D, U+15A7-U+15AE, U+1646, U+1647 (by + Eugeniy Meshcheryakov) +- fixed several contours to not intersect, use horizontal or vertical tangents, + use integer coordinates, etc in Sans Book (by Denis Jacquerye) +- added U+0496-U+0497 in Serif (by Andrey V. Panov) + +Changes from 2.13 to 2.14 + +- added Philippine peso glyph U+20B1 (by Clayborne Arevalo) +- made U+2012 have the same width as digits, according to Unicode 5.0, + page 206 (by Roozbeh Pournader) +- made all of the "above" combining characters remove the dot of "i", + "j", etc (Soft_Dotted characters), according to Unicode 5.0, + page 228 (by Roozbeh Pournader) +- made U+012F, U+03F3, U+0456, U+0458, U+1E2D, and U+1ECB (all fonts + except Mono), U+0249, U+2148, and U+2149 (Sans and Sans Condensed), + U+0268 (Sans ExtraLight, Serif and Serif Condensed), and U+029D (Serif + and Serif Condensed) respect the Soft_Dotted property (by Roozbeh + Pournader) +- added U+223E, U+223F, U+2240, U+22C2, U+22C3 to Sans (by Rémy Oudompheng) +- added U+203D to Serif (by Gee Fung Sit) +- added zero-width glyphs for U+2061-U+2063 to Sans and Serif (by Gee + Fung Sit) +- changed isolated forms of Arabic waw (U+0648, U+0624 and U+06C6) (bug #9432) + (by Ben Laenen) +- added Lao consonants U+0E81, U+0E82, U+0E84, U+0E87, U+0E88, U+0E8A, + U+0E8D, U+0E94-0E97, U+0E99-0E9F, U+0EA1-0EA3, U+0EA5, U+0EA7, U+0EAA, + U+0EAB, U+0EAD-0EAF to Sans Mono (by Rémy Oudompheng) +- added U+0200-U+0217, U+0226-U+0229, U+02F3, U+1E00-U+1E07, + U+1E0A-U+1E0B, U+1E18-U+1E1F, U+1E22-U+1E23, U+1E28-U+1E2D, + U+1E3A-U+1E3B, U+1E40, U+1E48-U+1E49, U+1E56, U+1E58-U+1E59, + U+1E5E-U+1E5F, U+1E60, U+1E68-U+1E6B, U+1E6E-U+1E6F, U+1E72-U+1E77, + U+1E86-U+1E8B, U+1E92-U+1E96, U+1EA0-U+1EA1, U+1EF4-U+1EF5 to Mono + (by Ben Laenen) +- renamed uppercase variants of diacritics (macron, breve, double grave, + double acute, inverted breve, dot above) to "uni03XX.case" in Mono + (by Ben Laenen) +- moved uppercase variants of diacritics up in Mono so they properly + vertically align on capitals (by Ben Laenen) +- precomposed glyphs with macron, breve, double grave, double acute, + inverted breve, dot above, macron below, breve below, inverted breve + below, dot below, cedilla, caron below, circumflex below, diaeresis + below, tilde below now reference to combining diacritics instead of + space modifiers in Mono (by Ben Laenen) +- made ring below (U+0325), and half rings below (U+031C and U+0339) + smaller in Mono (by Ben Laenen) +- added U+205F to all fonts (by Roozbeh Pournader) +- added U+035E-U+035F to Sans (by Roozbeh Pournader) +- added empty glyphs for U+034F, U+202A-U+202E, U+2060, U+206A-206F, + U+FE00-U+FE0F to non-Mono fonts (by Roozbeh Pournader) +- added U+2101, U+2107-U+2108, U+210B, U+210C, U+2110, U+2112, U+211B, + U+211F, U+2123, U+2125, U+2128-U+2129, U+212C-U+212D, U+212F, + U+2130-U+2131, U+2133, U+2136-U+213A, U+2141-U+2144, U+2B00-U+2B11, + U+2B20-U+2B23 to Sans (by John Karp) +- reshaped omega (U+03C9) in Mono (by Ben Laenen) +- added U+2205, U+22C6, U+2300-U+2301, U+2303-U+2306, U+230C-U+230F, + U+2312-U+2315, U+231C-U+231F, U+2335, U+2337-U+233E, U+2341-U+2344, + U+2347-U+2348, U+234B-U+234D, U+2349-U+2350, U+2352-U+2354, + U+2357-U+2359, U+235A-U+235C, U+235E-U+2360, U+2363-U+2365, + U+2368-U+2369, U+236B-U+2370, U+2373-U+237A, U+2380-U+2383, + U+2388-U+238B, U+2395 in Mono (by Ben Laenen) + +Changes from 2.12 to 2.13 + +- adjusted U+0198B, U+01B3-U+01B4 in Sans, hinted U+01B4 in Sans Book + (by Denis Jacquerye) +- added U+27F0-U+27FF, U+2906-U+2907, U+290A-U+290B, U+2940-U+2941 to Sans + (by Denis Jacquerye) +- added U+01E6-U+01E9, U+01EE-U+01EF, U+01F4-U+01F5, U+01FC-U+01FF, + U+021E-U+021F, U+0245, U+02BD, U+02C9, U+1E9B, U+2045-U+2046, U+2213, U+22C5, + U+22EF to Sans Mono (by Roozbeh Pournader) +- added U+04FA-U+04FD to Sans (by Michael Everson) +- removed U+2329 and U+232A because of their CJK properties, added U+27E8 + and U+27E9 in their stead, fixing part of bug #9038 (by Roozbeh Pournader) +- corrected and improvised U+0466-U+0469, U+046E-U+0471, U+047C-U+047D, U+0482, + U+0484-U+0486, U+0492-U+0493, U+04B0-U+04B1, U+050C-U+050D, and U+204A + in Sans (by Michael Everson) +- added instructions for U+0402, U+0409, U+040A, U+040B, U+044D, U+040F, + U+0452, U+0459-U+045B, U+045F to Sans Book (by Eugeniy Meshcheryakov) +- made italic shape for U+431, U+432, U+437, U+43B, U+43C, U+43D, U+444, U+447, + U+44D, U+44F, U+459, U+45A in SerifOblique and SerifBoldOblique + (by Andrey V. Panov) +- modified U+024C to match glyph in Unicode chart, fixing bug #9039 + (by Denis Jacquerye) +- made some canonically equivalent characters share the same glyph: + U+02B9 = U+0374, U+0343 = U+0313, and U+0387 = U+00B7 also adjusting U+02BA + to look like double U+02B9, fixing parts of bug #9038 (by Roozbeh Pournader) +- changed shapes for U+0478 and U+0479 in Sans to those in the Unicode charts, + based on a recent decision by Unicode Technical Committee to only use + the digraph form (by Michael Everson) +- adjusted width of NBSP U+00A0 and NNBSP U+202F, fixing bug #8401 + (by Denis Jacquerye) +- fixed several contours to not intersect, use horizontal or vertical tangents, + use integer coordinates, etc (by Roozbeh Pournader and Denis Jacquerye) +- added U+1402, U+1430, U+144D, U+146C, U+148A, U+14A4, U+14C1, U+14D4, U+14EE, + U+1527, U+1545, U+157E, U+158E, U+15AF to Sans (by Eugeniy Meshcheryakov) +- enlarged width of U+459 and U+45A in Serif (by Andrey V. Panov) +- made traditional shape for U+452, U+45B (by Andrey V. Panov) +- added euro sign U+20AC to Sans ExtraLight, making fontconfig recognize + the font as supporting English (by Denis Jacquerye) + +Changes from 2.11 to 2.12 + +- added U+0180 to Serif (by Denis Jacquerye) +- improved and/or hinted Armenian letters U+0542, U+0546, U+0562, + U+0563, U+0564, U+0577, U+0582 in Sans (by Ben Laenen) +- added U+4FE-U+4FF, U+512-U+513, U+2114, U+214E, U+26B2 to Sans + (by Gee Fung Sit) +- adjusted U+0496-U+0497, U+049A-U+04A1 in Sans to match U+0416, + U+041A, U+0436 and U+043A (by Gee Fung Sit) +- Mathematical Operators in Sans: changed U+22C0-U+22C1 to match + other n-ary operators, adjusted U+2203-U+2204, changed U+2220 in + Sans to match the style of U+2221 (by Gee Fung Sit) +- added U+1401, U+1403-U+1406, U+140A, U+140B, U+1426, U+142F, + U+1431-U+1434, U+1438, U+1439, U+1449, U+144A, U+144C, + U+144E-U+1451, U+1455, U+1456, U+1466, U+146B, U+146D-U+1470, + U+1472, U+1473, U+1483, U+1489, U+148B-U+148E, U+1490, U+1491, + U+14A1, U+14A3, U+14A5-U+14A8, U+14AA, U+14AB, U+14BB, U+14C0, + U+14C2-U+14C5, U+14C7, U+14C8, U+14D0, U+14D3, U+14D5-U+14D8, + U+14DA, U+14DB, U+14EA, U+14ED, U+14EF-U+14F2, U+14F4, U+14F5, + U+1405, U+1526, U+1528-U+152B, U+152D, U+152E, U+153E, + U+1542-U+1544, U+1546-U+154D, U+1550, U+1553, U+1555-U+155A, + U+1567, U+156A, U+157C, U+157F-U+1585, U+158A-U+158D, + U+158F-U+1596, U+15A0-U+15A6, U+15DE, U+15E1, U+166E-U+1676 to + Sans (by Eugeniy Meshcheryakov) +- re-enabled Latin ligatures fi, ffi, fl, ffl and ff in Sans + (by Ben Laenen) +- made italic shape for U+436, U+44A, U+44B, U+44C, U+44E, U+45F, + U+463 in SerifOblique and SerifBoldOblique (by Andrey V. Panov) +- fixed sub- and superscript metrics in Condensed Sans (bug #8848) + (by Ben Laenen) +- added U+474, U+475 in Serif (by Andrey V. Panov) +- hinted Greek glyphs U+03B7, U+30B8, U+03B9, U+03C1, U+03C3, + U+03C6 in Mono Book (by Ben Laenen) + +Changes from 2.10 to 2.11 + +- added instructions for Hebrew glyphs (Sans Book, by Eugeniy + Meshcheryakov) +- changed U+01A6 (Latin Yr) after bug #8212, in Sans, Serif and + Sans Mono fonts (by Denis Jacquerye). +- removed instruction for U+2600-U+26A1 (by Mederic Boquien) +- added U+202F and set width of U+00A0 (nobreakingspace) to the + same as U+0020, space (by Denis Jacquerye). +- added and improved instructions for various Cyrillic letters + (by Eugeniy Meshcheryakov) +- Changed U+416, U+42F, U+427 (non-Bold), U+436, U+447 (non-Bold), + U+44F, U+437 (Bold), corrected U+40F, U+414, U+424, U+426, U+429, + U+434, U+438 (Bold), U+446, U+449, U+44D (non-Bold), U+45F in + Sans Mono (by Andrey V. Panov) +- made small corrections to Cyrillic, most appreciable to U+409, + U+413, U+41B, U+427 and U+433, U+434, U+43B, U+447, U+459 + (upright fonts) to Serif (by Andrey V. Panov) +- adjusted bearings of U+410, U+416, U+41A, U+42F, U+436, U+43A, + U+443, U+44F in Serif (by Andrey V. Panov) +- enlarged width of U+44A, U+44B, U+44C, U+463 in Serif + (by Andrey V. Panov) +- added ligature "iacute" as "afii10103" (U+456) "acutecomb" in + Serif (by Andrey V. Panov) +- made italic shape to U+446, U+448, U+449 in Serif (by Andrey V. + Panov) +- added "afii10831" (U+F6C7), "afii10832" (U+F6C8) in Serif (by + Andrey V. Panov) +- new minimum version of fontforge is 20061014 (by Ben Laenen) + +Changes from 2.9 to 2.10: + +- added U+0242, U+024A-U+024B, U+024E-U+024F, U+037C-U+037D, U+0E3F, + U+1D2C-U+1D2E, U+1D30-U+1D42, U+1D5D-U+1D6A, U+1D78, U+1DB8, + U+2090-U+2094, U+20D0-U+20D1, U+2C60-U+2C66, U+2C6B-U+2C6C, U+2C74 and + U+FB29 to Sans (by Gee Fung Sit) +- added Lao glyphs : U+0E81-0E82, U+E084, U+0E87-0E88, U+0E8A, U+0E8D, + U+0E94-0E97, U+0E99-0E9F, U+0EA1-0EA3, U+0EA5, U+0EA7, U+0EAA-0EAB, + U+0EAD-0EB9, U+0EBB-0EBD, U+0EC0-0EC4, U+0EC6, U+0EC8-0ECD, U+0EDC-0EDD + (by Rémy Oudompheng) +- fixed U+0193 not showing in Windows (bug #7897) (by Ben Laenen) +- changes to U+222B-222D in Sans Mono (by Rémy Oudompheng) +- ported the three remaining currency symbols from Arev (U+20B0, + U+20B2-U+20B3), and replaced one (U+20AF) in Sans (by Lars Naesbye + Christensen) +- corrected U+20A5 in Sans (by Gee Fung Sit) +- merged Double-Struck Letters from Arev: U+2102, U+210D, U+2115, + U+2119-U+211A, U+2124, U+213C-U+2140 (by Gee Fung Sit) +- added U+2308-U+230B and U+2329-U+232A to Sans Mono and Serif faces, + fixed incorrect direction of U+2329 in Sans faces, and improved + U+2308-U+230B in Sans faces per Ben Laenen's suggestions (by David + Lawrence Ramsey) +- added U+06D5 and final form of it (needed for Kurdish) (by Ben Laenen) +- added two special glyphs U+F000 and U+F001 in Sans Book that show the + current ppem size (horizontal and vertical) (by Ben Laenen) +- added U+2318 and U+2325 to Sans Mono faces, based on the Sans versions + (by David Lawrence Ramsey) +- added U+2B14-U+2B1A to all faces except Sans ExtraLight (by David + Lawrence Ramsey) +- respaced all Geometric Shapes characters in Serif faces to match those + in Sans faces again, respaced U+23CF in Sans, Sans ExtraLight, and + Serif faces to match U+25A0 (or Sans in Sans ExtraLight's case) again, + and respaced U+2B12-U+2B13 in Sans and Serif faces to match U+25A1 + again (by David Lawrence Ramsey) +- corrected width of Modifier Small Letters U+1D43-1D5B in Sans Oblique + and U+1D9B-U+1DBF in Sans Oblique and Sans Bold Oblique (by Gee Fung Sit) +- added a bunch of glyphs to Sans ExtraLight (see SVN for details) (by + Gee Fung Sit) +- adjusted Cyrillic descenders in Sans ExtraLight to sync with Sans (by + Gee Fung Sit) +- added U+0242, U+0245 to Serif (by Gee Fung Sit) +- replaced the SHPIX routines which gave them bad spacing at certain + sizes in FreeType for A, V, Z, v and z in Sans Bold (by Ben Laenen) + +Changes from 2.8 to 2.9: + +- DejaVuSansExtraLight.sfd: changed family name from "DejaVu Sans" to + "DejaVu Sans Light" (in case we add a Light weight variant), so legacy + apps that understand only 4 styles are happy. (by Denis Jacquerye) +- added Name ID 16, aka preferred family name, and Name ID 17, aka + preferred style name, so contemporary apps that understand more that 4 + styles can use big fonts families "DejaVu Sans" and "DejaVu Serif". For + those, Extralight and Condensed are just styles not different families. + (by Denis Jacquerye) +- added U+22B6-22BD, U+22C0-22C1, U+22D6-22D7 to Sans. (by Remy Oudompheng) +- added U+037B, U+2184, U+2C67-U+2C6A and U+2C75-U+2C77 to Sans (by Gee + Fung Sit) +- adjusted asteriskmath (U+2217) for consistency with other mathematical + operators in Sans (by Ben Laenen) +- hinted some Armenian capitals in Sans Book (by Ben Laenen) +- added U+0246 - U+0249 (by Ben Laenen) +- BUGFIX : swapped U+224E and U+224F, in Sans, Sans Condensed and Sans Mono + (by Remy Oudompheng) +- adjusted U+20B5 (by Mederic Boquien) +- swapped U+21DA and U+21DB which were in wrong order (by Heikki Lindroos) +- added U+222E-2233, U+239B-23AD, U+2A00-2A02, U+2A0F-2A1C to Sans (by Remy + Oudompheng) +- added U+239B-23AD to Mono (by Remy Oudompheng) +- added U+2024-2025 to Serif (by Mederic Boquien) +- added U+222C-222D, U+2A0C-2A0E to Serif (by Remy Oudompheng) +- added U+2190-21FF to Mono (by Heikki Lindroos) +- added Hebrew glyphs - U+05B0-U+05BD, U+05BF-U+05C3, U+05C6, U+05C7, + U+05D0-U+05EA, U+05F0-U+05F2, U+FB1F, U+FB20, U+FB2A-U+FB36, + U+FB38-U+FB3C, U+FB3E, U+FB40, U+FB41, U+FB43, U+FB44, U+FB46-U+FB4E (by + Gee Fung Sit and Eugeniy Meshcheryakov) +- adjustments for Cyrillic in Sans (by Andrey V. Panov) +- made italic shape for U+0434, U+0456, U+0457 in SerifOblique and Serif + Bold Oblique (by Andrey V. Panov) + +Changes from 2.7 to 2.8: + +- fixed instructions for U+0423, U+0427, U+0447, U+0448 in Serif, so they + look good at large sizes too (by Eugeniy Meshcheryakov) +- added U+FB00 and U+FB03 to U+FB06 to Serif typefaces (by Heikki Lindroos) +- added U+26B0-U+26B1, U+2701-U+2704, U+2706-U+2709, U+270C-U+2727, U+2729 + to U+274B, U+274D, U+274F to U+2752, U+2756, U+2758-U+275E, U+2761 to + U+2775 (by Heikki Lindroos) +- added and improved instructions for Cyrillic letters in Mono and Serif + (Book, by Eugeniy Meshcheryakov) +- rotated U+26B0 (was too small in mono) (by Gee Fung Sit) +- adjusted U+1EDA-U+1EDD, U+1EE8-U+1EEB, capitals using capital specific + accent and moved diacritics to match position on U+00F2 (ograve), etc. + (by Denis Jacquerye) +- added U+20D6, U+20D7 to Sans (by Gee Fung Sit) +- made Armenian ligatures discretionary since the Firefox ligature problem + still isn't fixed (by Ben Laenen) +- moved Armenian hyphen U+058A to a higher position (bug #7436) (by Ben + Laenen) +- hinted Greek glyphs in Sans Bold (by Ben Laenen) +- enabled Arabic lam-alif ligatures when diacritics are used (by Ben Laenen) + +Changes from 2.6 to 2.7: + +- added glyphs needed for Kurdish: U+0695, U+06B5, U+06C6, U+06CE and their + init/medi/fina forms in Sans (by Ben Laenen) +- added U+02CD, U+01F8 - U+01F9, U+1E3E - U+1E3F, U+1E30 - U+1E35, U+1EBC - + U+1EBD, U+1EF8 - U+1EF9 (includes glyphs needed for Yoruba, Maori, Guarani + and Twi) (by Ben Laenen) +- added U+22C8-22CC, U+29CE-29D5, U+2A7D-2AA0, U+2AAE-2ABA, U+2AF9-2AFA to + Sans (by Remy Oudompheng) +- adjusted diacritics on Vietnamese, Pinyin and other characters: + U+01A0-U+01A1, U+01AF-U+01B0, U+01D5-U+01DC, U+01DE-01E1, U+01FA-U+01FB + U+022A-U+022D, U+0230-U+0231, U+1E14-U+1E17, U+1E4C-U+1E53, U+1E78-U+1E7B, + U+1EA4-U+1EF1 in Sans (Book, Bold and Oblique) (by Denis Jacquerye) +- added basic arrows U+2190-U+2193 in Serif, which completes MES-1 compliance + for Serif (by Ben Laenen) +- added U+01E4, U+01E5, U+01FA, U+01FB, U+02BD, U+02C9 and U+02EE to Serif + (by Ben Laenen) +- fixed U+0209 in Serif Bold Oblique (by Ben Laenen) +- adjusted Box Drawing block characters U+2500-257F in Mono to fit character + cell, shifting them up by 416 (Denis Jacquerye) +- redid U+0194 in Sans (by Ben Laenen) +- added U+2217-2218, U+2295-22A1 to Mono (by Remy Oudompheng) +- added U+0462 to Serif (by Andrey V. Panov) +- added U+226C, U+228C-228E, U+2293-2294, U+22F2-22FF to Sans (by Remy + Oudompheng) +- adjusted U+2208-220D in Sans (by Remy Oudompheng) +- improved some Cyrillic glyphs in Mono (by Andrey V. Panov), rewritten + instructions for changed glyphs (by Eugeniy Meshcheryakov) +- added U+1E0E-1E0F, U+1E8E-1E8F to Mono fonts (by Denis Jacquerye). (bug + #7166) +- renamed 'Dotabove' to 'Dotaccent' in Mono Sans Oblique to match other fonts + (by Denis Jacquerye). +- added U+200B-U+200F in Sans faces and Serif faces, U+200B and U+200C were + in Sans already (by Lars Naesbye Christensen) +- added U+2601-U+262F, U+263D, U+263E, U+2648-U+265F, U+2668, U+2670-U+268B, + U+2690-U+269C, U+26A0, U+26A1, U+2794, U+2798-U+27AF, U+27B1-U+27BE to Mono + (by Heikki Lindroos) +- replaced the references with unshifted ones for both κ U+03BA and к U+043A + in Mono Book (by Denis Jacquerye) +- fixing glyph for U+04ED in Mono Book, consisted only of dieresis (by Andrey + V. Panov). + +Changes from 2.5 to 2.6: + +- redid U+2032 - U+2037, U+2057 based on Arev in Sans (by Gee Fung Sit) +- added U+0195, corrected U+039E, U+204B in Sans ExtraLight (by Gee Fung Sit) +- added instructions for some Cyrillic letters in Sans Bold (by Eugeniy + Meshcheryakov) +- added vulgar fractions U+2153-U+215F for Serif, made with references (by + Lars Naesbye Christensen) +- added U+228F-2292, U+2299-22AF, U+22B2-22B5, U+22CD, U+22D8-22ED to Sans + (by Remy Oudompheng) +- added U+2208-220D, U+2238-223D, U+2278-2281, U+228A-228B, U+228F-2292, + U+22CD, U+22DA-22E9 to Mono (by Remy Oudompheng) +- fixed misplaced dot in U+2250 in Mono (by Remy Oudompheng) +- added instructions for some Cyrillic letters in Mono Book and Bold(by + Eugeniy Meshcheryakov) +- minor changes to U+2241, U+2261-2263, U+22A4, U+22A5 in Sans (by Remy + Oudompheng) +- added hinting instructions to lowercase Armenian glyphs in Sans Book (by + Ben Laenen) +- changed U+2208, U+220B to match U+2209 and U+220C in Sans Bold (by Remy + Oudompheng) +- added Braille patterns U+2800-U+28FF to Sans (by Mederic Boquien) +- added instructions for some Cyrillic letters in Serif Book (by Eugeniy + Meshcheryakov) +- renamed BoldOblique fonts to Bold Oblique in TTF Name as originally in + Bitstream Vera fonts (by Denis Jacquerye) +- added hinting instructions to some Latin-B Extended and IPA characters in + Sans Book (by Denis Jacquerye and Ben Laenen) +- adjusted bearings, replaced diacritics, hinted hook and horn for + Vietnamese in Sans Book (by Denis Jacquerye) +- made FAX, TM, TEL, etc. discritionary ligatures in Sans and Serif fonts + (by Denis Jacquerye) +- removed ligatures of precomposed characters in Sans and Serif fonts (by + Denis Jacquerye) +- added U+F208, U+F20A, U+F215-F217, U+F21A-F21B, U+F25F in PUA (from SIL's + PUA, probably in Unicode 5.0): U+0243, U+0244, U+0245, U+024C, U+024D, + U+2C64, (U+2C6D), (U+2C71) +- modified some glyphs in Serif Oblique to make them more italic (by Denis + Jacquerye) + +Changes from 2.4 to 2.5: + +- fixed excessive kerning bug that occurs with Pango (by Denis Jacquerye) +- added U+20AF to Sans and Serif (by Lars Naesbye Christensen) +- regenerated Condensed faces (by Ben Laenen) +- added U+035C-U+035D to Sans, fixed U+0361 (by Denis Jacquerye) +- integrated 255 characters from Arev fonts: Latin Extended-B, Spacing + Modifiers, Combining Diacritical Marks, Cyrillic, Cyrillic supplement, + General Punctuation, Letterlike Symbols, Arrows, Mathematical Operators, + Miscellaneous Technical, Dingbats, Alphabetic Presentation Forms (by Denis + Jacquerye) +- added basic Cyrillic and basic Greek to Sans ExtraLight (by Denis Jacquerye) +- added U+0498, U+049A, U+04AA, U+04AB, U+04AF to Serif (by Eugeniy + Meshcheryakov) +- added U+0494, U+0495, U+0498, U+0499, U+04AA, U+04AB, U+04C3, U+04C4, + U+04C7, U+04C8 to Mono (by Eugeniy Meshcheryakov) +- adjusted weight of U+0256, U+0257, U+0260, U+0272, U+0273, U+0277, U+029B, + U+02A0 and modifed U+028B and U+027A in Mono (by Denis Jacquerye) +- added U+2000-200A to Mono (by Denis Jacquerye) +- added vulgar fractions U+2153 - U+215F to Mono (by Gee Fung Sit) +- adapted metrics of Arabic glyphs so they stay above cut-off height in Sans + (by Ben Laenen) +- fixed mkmk anchors for Arabic diacritics so they stack properly in Sans (by + Ben Laenen) +- fixed weight of lowercase upsilon in Sans Bold, make small adjustment to + lowercase omega in Sans (by Ben Laenen) +- added U+210E (by Mederic Boquien) +- unslanted U+2201, U+221B and U+221C in Sans Oblique (by Mederic Boquien) +- added several mathematical relation symbols to Sans and Mono (U+2241-224C, + U+2250-2255, U+2260-2269, U+226E-2277, U+2282-2287) modified U+223C to match + other tildes, and U+2282-2284 to have the same shape. (by Remy Oudompheng) +- made U+2234-U+2237 refer to U+2219 instead of U+00B7 in Sans (by Mederic + Boquien) +- added U+2238-223B, U+226A-226B, U+2278-2281, U+2288-228B to Sans (by Remy + Oudompheng) +- unslanted and changed reference of U+22C5 from U+00B7 to U+2219 in Sans (by + Mederic Boquien) +- added U+224D-225F, U+226D, U+22C6 to Sans and unslanted U+2219 in Sans + Oblique. (by Remy Oudompheng) +- added U+224D-225F, U+226D to Mono, shifted U+2266-2269 higher upwards and + unslanted U+2219 in Oblique. (by Remy Oudompheng) +- merged Coptic glyphs from Arev 0.2 (by Lars Naesbye Christensen) +- fixed and adjusted various Cyrillic glyphs in Serif (by Andrey V. Panov) +- made fi, fl... ligatures discretionary ligatures (by Ben Laenen) + +Changes from 2.3 to 2.4: + +- added U+04A2, U+04A3, U+04AC - U+04AF, U+04BA, U+04BB, U+04C0 - + U+04C2, U+04CB, U+04CD, U+04D8 - U+04DF, U+04E2 - U+04E5, U+04E8 - U+04F5, + U+04F6 - U+04F9 to Mono (by Eugeniy Meshcheryakov) +- added U+048C, U+048D, U+0494, U+0495, U+049E - U+04A7, U+04AC - + U+04AE, U+04B4- U+04B7, U+04BA, U+04BB, U+04C0 - U+04C4, U+04C7, U+04C8, + U+04CB, U+04CC, U+04D8 - U+04DF, U+04E2 - U+04E5, U+04EC - U+04F9 to Serif + (by Eugeniy Meshcheryakov) +- added U+2134 to Sans (by Gee Fung Sit) +- added U+2080 - U+2089 to all faces (by Gee Fung Sit) +- several minor corrections to Sans (by Gee Fung Sit) +- major corrections to Sans Condensed (by Gee Fung Sit) +- corrected Superscripts and Subscripts in Sans (by Gee Fung Sit) +- corrected anchors of U+0316-U+0319 (by Denis Jacquerye) +- Verajja integrated (by Stepan Roh) +- copied U+2328, U+2600, U+2639-U+263C, U+263F-U+2647, U+2660-U+2667, + and U+2669-U+266F from Sans to Serif, and copied scaled-down versions of + them to Sans Mono (by David Lawrence Ramsey) +- added U+20B4 to all faces (by Eugeniy Meshcheryakov) +- added more minor positional adjustments to U+2638 in all faces to + match the other miscellaneous symbols in Verajja, and rescale it in Sans + Mono so that it looks better (by David Lawrence Ramsey) +- added U+2242, U+2243 and U+22A4 (by Mederic Boquien) +- corrected U+2245 in Sans (by Mederic Boquien) +- added U+0221, U+0234-0236 (by Denis Jacquerye) +- added in Arabic block to Sans: U+060C, U+0615, U+061B, U+061F, U+0621 +- U+063A, U+0640 - U+0655, U+0660 - U+066F, U+0679 - U+0687, U+0698, U+06A1, + U+06A9, U+06AF, U+06BA, U+06BF, U+06CC, U+06F0 - U+06F9 (by Ben Laenen) +- added in Arabic Presentation Forms A to Sans: U+FB52 - U+FB81, U+FB8A +- U+FB95, U+FB9E - U+FB9F, U+FBE8 - U+FBE9, U+FBFC - U+FBFF (by Ben Laenen) +- added complete Arabic Presentation Forms B to Sans: U+FE70 - U+FE74, + U+FE76 - U+FEFC, U+FEFF (by Ben Laenen) +- added complete Greek Extended block to Mono (by Ben Laenen) +- modified Greek capitals with tonos in Mono (by Ben Laenen) +- added U+01C4-01CC, U+01D5, U+01DE, U+01E0-U+01E1, U+01E6-U+01E9, + U+01EE-U+01F5, U+01F8-U+0217, U+021E-U+021F, U+0226-U+022A, U+022C to Serif + (by Denis Jacquerye) +- adjusted U+043B and U+044F in Serif (by Denis Jacquerye) +- added U+2000-U+200A (by Denis Jacquerye) +- added U+1E00-U+1E0B, U+1E0E-U+1E11, U+1E14-U+1E1C, U+1E1E-U+1E23, + U+1E26-U+1E2D, U+1E30-U+1E35, U+1E3A-U+1E3B, U+1E3E-U+1E40, U+1E48-U+1E49, + U+1E50-U+1E56, U+1E58-U+1E59, U+1E5E-U+1E60, U+1E68-U+1E6B, U+1E6E-U+1E6F, + U+1E72-U+1E7D, U+1E86-U+1E9B, U+1EA0-U+1EA3, U+1EAC-U+1EB7, U+1EBA-U+1EBD, + U+1EC6-U+1ECF, U+1ED8-U+1ED9, U+1EE6-U+1EE7, U+1EF4-U+1EF9 to Serif (by + Denis Jacquerye) +- added U+048E, U+048F, U+049C-U+049F, U+04B8, U+04B9, U+04BC-U+04BF, + U+04C3, U+04C4 to Sans (by Eugeniy Meshcheryakov) +- added DejaVu Sans Extra Light (by Denis Jacquerye) +- Adjusted underline position for (hopefully) improved legibility in + Sans, Serif, Mono (Tim May) +- added auto-generated DejaVu LGC (by Stepan Roh) + +Changes from 2.2 to 2.3: + +- fixed bug U+042B and U+044B behave badly in Sans Bold or Oblique (by + Keenan Pepper) +- added and improved TrueType instructions and related settings (by + Keenan Pepper) +- added U+04D0-U+04D7, U+04E6, U+04E7 to Mono (by Eugeniy Meshcheryakov) +- added U+048A - U+048D, U+0498, U+0499, U+04AA, U+04AB, U+04B0, U+04B1, + U+04C0, U+04C9, U+04CA, U+04CE, U+04CD, U+04DA, U+04DB, U+04DE, U+04DF, + U+04E2 - U+04E5, U+04EC - U+04F8, U+04F9 to Sans (by Eugeniy Meshcheryakov) +- added U+04E0, U+04E1 to all faces (by Eugeniy Meshcheryakov) +- added Greek Extended to Sans and Serif: U+1F00-U+1F15, U+1F18-U+1F1D, + U+1F20-U+1F45, U+1F48-U+1F4D, U+1F50-U+1F57, U+1F59, U+1F5B, U+1F5D, + U+1F5F-U+1F7D, U+1F80-U+1FB4, U+1FB6-U+1FC4, U+1FC6-U+1FD3, U+1FD6-U+1FDB, + U+1FDD-U+1FEF, U+1FF2-U+1FF4, U+1FF6-U+1FFE (by Ben Laenen) +- added Greek variant letterforms, archaic letters and symbols to Mono: + U+03D0-U+03E1, U+03F0-U+03FF (by Ben Laenen) +- added Armenian block and Armenian ligatures to Sans (U+0531 - U+0556, + U+0559 - U+055F, U+0561 - U+0587, U+0589 - U+058A, U+FB13 - U+FB17) (by Ben + Laenen) +- redid some Greek characters in Sans and Mono to make them look better + and to correct some errors (by Ben Laenen) +- added U+27E0 to all faces (by David Lawrence Ramsey) +- added underscore (U+005F) consistency fixes: extended the Sans Mono + and Sans Mono Oblique underscores to touch both horizontal edges, and + reduced the height of the Sans Bold Oblique underscore to match the Sans + Bold underscore (by David Lawrence Ramsey) +- added underscore (U+005F) derivatives and consistency fixes for them: + made U+0332 a reference to underscore at Denis Jacquerye's suggestion; made + U+0333 two references to underscore; made U+033F two references to U+203E; + added U+2017 as two references to underscore, and made U+0333 a reference to + it; and added U+203E as a reference to underscore, and made U+0305 a + reference to it (by David Lawrence Ramsey) +- added U+201B, U+2220, U+2320-U+2321, U+23AE, U+23CF, all remaining + Geometric Shapes glyphs (U+25A0-U+25C9, U+25CB-U+25D7, U+25D9-U+25E5, + U+25E7-U+25FF), and U+2B12-U+2B13 to all faces (by David Lawrence Ramsey) +- added minor positional adjustments to U+2638 in all faces (by David + Lawrence Ramsey) +- added U+201F to Sans Mono and Serif faces (by David Lawrence Ramsey) +- added U+01B7, U+01F6, U+0464 - U+0465, U+2160 - U+2180, U+2183, + U+220A, U+220D, U+2329, U+232A, U+2422, U+27E8 - U+27EB, U+2680 - U+2685 to + Sans (by Gee Fung Sit ???) +- added U+2116 to Sans and Serif (by Gee Fung Sit) +- changed florin sign U+0192 in Sans (by Gee Fung Sit) +- added anchor points to some glyphs (by Denis Jacquerye) +- adjusted height of IPA superscripts U+02B0-02B8, U+02C0-02C1, + U+02E0-02E4, U+207F to match with height of U+00B2 (by Denis Jacquerye) +- added U+0184-U+0185, U+019C, U+019F, U+01A0-U+01A3, U+01A6, U+01AA, + U+01AF-U+01B0, U+01B2-U+01B4, U+01B7-U+01B8, U+01BC-U+01BC, U+0224-U+0225, + U+023A-U+0240, U+1D16-U+1D17, U+1D1D-U+1D1E, U+1D43-U+1D5B, U+1D7B, + U+1D85,U+1D9B-1DB7, U+1DB9-U+1DBF, U+20A6 to all fonts (by Denis Jacquerye) +- added added U+0182, U+018B, U+018E, U+01A0-U+01A1, U+01B1, U+01B9, + U+01C0-U+01C3, U+0238-U+0239, U+1D02, U+1D08-U+1D09, U+1D14, U+1D1F, U+1D77 + to Serif and Mono (by Denis Jacquerye) +- added U+0181, U+0183, U+0187-U+0188, U+018A-U+018F, U+0191, U+0193, + U+0195-U+019B, U+019D-U+019E, U+01A4-U+01A5, U+01AC-U+01AE, U+01B5-U+01B6, + U+01B9, U+01BB, U+01F6 to Serif (by Denis Jacquerye) +- added U+0181, U+0187-U+0188, U+018A, U+018D, U+018F, U+0191, U+0193, + U+0195-U+019F, U+01A4-01A5, U+01AC-01AD, U+01B5-U+01B6, U+1BB, U+01F6, + U+01D7-U+01DC, U+0238-U+0239, U+0241 to Mono (by Denis Jacquerye) +- added to Mono and Serif (by Denis Jacquerye) + +Changes from 2.1 to 2.2: + +- reworked the vertical orientation of the Blocks Elements characters + in all faces to remove their overly large descenders, in order to fix + problems with e.g. terminal emulators (by David Lawrence Ramsey) +- copied bullet in Sans faces to Serif faces for consistency (by David + Lawrence Ramsey) +- added U+2023, U+25D8, U+25E6, and U+29EB to all faces (by David + Lawrence Ramsey) +- added U+1EB8, U+1EB9, U+1ECA - U+1ECD, U+1EE4, U+1EE5 (by Tim May) +- added U+01DD, U+02BE, U+02BF, U+02D3 to all, changed U+02D2 in + non-Condensed and U+1EE5 in Serif (by Tim May) +- fixed U+01CE, replacing wrong circumflex by caron (by Denis Jacquerye) +- added anchor points to some glyphs (by Denis Jacquerye) +- added U+20B5 (by Denis Jacquerye) +- added U+0181 - U+0183, U+0187, U+0188, U+018A - U+018D, U+0191, + U+0193, U+0195 - U+019B, U+019D, U+019E, U+01A4, U+01A7 - U+01A9, U+01AB - + U+01AE, U+01B1, U+01B5, U+01B6, U+01BB, U+01C0 - U+01C3, U+01F1 - U+01F3, + U+0238, U+0239, U+1D02, U+1D08, U+1D09, U+1D14, U+1D1F, U+1D77, U+2103, + U+2126, U+2127, U+212A, U+212B, U+2132, U+214B, U+2210, U+2217, U+2218, + U+2A0C - U+2A0E, U+FB00, U+FB03 and U+FB04 to Sans (by Gee Fung Sit) +- added U+01A9, U+01C3 and U+2126 to Mono and Serif (by Gee Fung Sit) +- adjusted bearings of U+028B in Sans (by Gee Fung Sit) +- added U+018F, U+0494-U+0497, U+04A0-U+04A7, U+04AC-U+04AF, + U+04B4-U+04B7, U+04BA-U+04BB, U+04C1-U+04C2, U+04C5-U+04C8, U+04CB-U+04CC, + U+04D0-U+04D9, U+04DC-U+04DD, U+04E6-U+04EB to Sans (by Eugeniy + Meshcheryakov) +- replaced with references U+0391-U+0393, U+0395-U+0397, U+0399, U+039A, + U+039C, U+039D, U+039F-U+03A1, U+03A4, U+03A5, U+03A7, U+03BF, U+03DC, + U+0405, U+0406, U+0408, U+0410, U+0412, U+0415, U+0417, U+041A, + U+041C-U+041E, U+0420-U+0422, U+0425, U+0430, U+0435, U+043E, U+0440, + U+0441, U+0443, U+0445, U+0455-U+0458 in Serif and Mono (by Eugeniy + Meshcheryakov) +- added U+04D0-U+04D7, U+04E6-U+04EB to Serif (by Eugeniy Meshcheryakov) +- added U+212A and U+212B to the rest of the faces (by Lars Naesbye + Christensen) +- added U+2318 and U+2325 to Sans and Serif (by Lars Naesbye Christensen) +- added and improved TrueType instructions and related settings (by + Keenan Pepper) +- completed basic Greek alphabet: added U+0374-U+0375, U+037A, U+037E, + U+0384-U+038A, U+038C, U+038E-U+0390, U+03AC-U+03BF, U+03C1-U+03CE (by Ben + Laenen) +- added U+2070 and U+2074-U+2079 (by Mederic Boquien) + +Changes from 2.0 to 2.1: + +**# Be aware that names of some TTF files changed since version 2.0.#** + +- added U+0323, U+1E0C, U+1E0D, U+1E24, U+1E25, U+1E36 - U+1E39, U+1E42, + U+1E43, U+1E46, U+1E47, U+1E5A - U+1E5D, U+1E62, U+1E63, U+1E6C, U+1E6D, + U+1E7E, U+1E7F (by Tim May) +- fixed bug where GNOME applications used Mono Bold Oblique instead of + Mono Oblique (by Keenan Pepper) +- added and improved TrueType instructions and related settings (by + Keenan Pepper) +- added U+1E41, U+1E57, U+1E61 (by Sander Vesik) +- added U+0189, U+0309, U+0313, U+0314, U+031A, U+031B, U+0327, U+0328, + U+032B, U+0333, U+033C (by Denis Jacquerye) +- adjusted and fixed U+0186, U+0254, U+0291, U+0316 - U+0319, U+031C - + U+0320, U+0323 - U+0326, U+0329 - U+032A, U+032C - U+0332, U+0339 - U+033B, + U+033E, U+033F (by Denis Jacquerye) +- fixed U+1E12, U+1E3C, U+1E4A, U+1E70 to have normal below diacritics + (by Denis Jacquerye) +- fixed U+1E82, U+1E84 and U+1EF2 to have uppercase above diacritics (by + Denis Jacquerye) +- added anchor points to some glyphs (by Denis Jacquerye) +- dropped "-Roman" from font names - affects both internal TTF names and + names of generated files (by Stepan Roh) +- attempt to fix bug Vertical spacing too big for Mono by exchanging + LineGap and OS2TypoLinegap values (proofed by Stefan Rank) +- added Greek capitals U+0391 - U+03A1, U+03A3 - U+03A9, U+03AA, U+03AB + in Mono (by Ben Laenen) +- added the per ten thousand sign U+2031 (by Mederic Boquien) +- added U+2207, U+221D, U+221F, U+2227 - U+222A, and U+2261 (by David + Lawrence Ramsey) +- new logo (by Gee Fung Sit) +- added U+0180, U+018E, U+201F, U+2024, U+2025, U+203D, U+2200, U+2203, + U+2213, U+222C, U+222D, U+2263 to Sans (by Gee Fung Sit) + +Changes from 1.15 to 2.0: + +- "Italized" basic glyphs in all Serif Oblique and their Condensed faces + (by David Jez) +- added and improved TrueType instructions and related settings (by Keenan + Pepper) +- added anchor points to some glyphs (by Denis Jacquerye) +- many new spacing and combining accents (by Denis Jacquerye) +- smart substitutions for transforming i and j to dottless form and for + using uppercase diacritics (by Denis Jacquerye) +- fixed remaining erroneously slanted characters in Serif Oblique faces (by + David Lawrence Ramsey) +- copied bullet in Sans faces to Sans Oblique faces for consistency (by + David Lawrence Ramsey) +- added U+203C and U+2047-U+2049 (by David Lawrence Ramsey) +- added Greek glyphs to Serif (by Ben Laenen, Condensed merge by David Jez) +- fixed bug LTR glyphs behaving like RTL (by Ben Laenen) +- fixed wrong glyph directions (by David Jez) +- fixed repositioned accents in Condensed faces (by David Jez) + +Changes from 1.14 to 1.15: + +- added and improved TrueType instructions and related settings (by Keenan + Pepper) +- fixed U+2302, U+2319 (by David Lawrence Ramsey) +- fixed yet another monospace bug (by Stepan Roh) +- fixed potential "too big ascender/descender" bug (by Stepan Roh) +- fixed U+026E and U+028E (by Denis Jacquerye) +- added U+0186, U+0190, U+0300 - U+0304, U+0306 - U+0308, U+030A - U+030C, + U+0321, U+0322 (by Denis Jacquerye) +- added rest of Block Elements: U+2591 - U+2593 (by David Lawrence Ramsey) +- added U+2311, U+237D and U+2638 (by David Lawrence Ramsey) +- added U+01CD - U+01D4 (by Denis Jacquerye) +- fixed accents of U+00F2 - U+00F6 by replacing them with references in Mono + Bold (by David Jez) +- added U+0490, U+0491 (by Eugeniy Meshcheryakov) +- added hints to U+0404 and U+0454 in Sans (by Eugeniy Meshcheryakov) +- completed Greek glyphs from U+0370 to U+03CF in Serif (by Ben Laenen) +- fixed shape of U+0255 in Sans Bold and Sans Bold Oblique (by Denis + Jacquerye) + +Changes from 1.13 to 1.14: + +- fixed bug where Mono faces were not recognized as fixed pitch in Windows + by correcting Venda glyphs (by David Jez) +- added and improved TrueType instructions (by Keenan Pepper) +- added 6 Uzbekian glyphs (by Mashrab Kuvatov) +- added Greek glyphs to Sans and Serif, changed pi and omega to fit in (by + Ben Laenen) +- added IPA and related superscript glyphs (by Denis Jacquerye) +- fixed buggy Venda glyphs (by David Lawrence Ramsey and Stepan Roh) +- added U+2302, U+2310, U+2319 (by David Lawrence Ramsey) +- fixed slanted U+00AC in Serif Oblique faces (by David Lawrence Ramsey) +- added 29 glyphs from Block Elements (by David Lawrence Ramsey) + +Changes from 1.12 to 1.13: + +- removed all stems (PS hints) (requested by David Jez) +- added U+01D6, U+01DF, U+022B, U+022D and U+0231 (by Sander Vesik) +- added 10 Venda glyphs (by Dwayne Bailey) +- fixed bug when fonts had no name on Microsoft Windows (by Stepan Roh) +- updated 'missing' glyph U+FFFD (by David Jez) +- set TTF flag fsType to 'Installable Embedding' (= unrestricted usage) + (idea by C. Tiffany) + +Changes from 1.11 to 1.12: + +- added long s (by James Cloos) +- prettier comma accent in gcommaaccent (by David Jez) +- added Hbar, hbar, kgreenlandic, napostrophe, Eng, eng, Tbar, tbar, + afii57929 (by David Jez) +- changed Iogonek, iogonek, IJ, ij to look better (by David Jez) +- glyph uni0237 renamed to dotlessj (requested by David Jez) +- fixed accents for dcaron, lcaron, tcaron, Uogonek, uogonek in Serif (by + David Jez) +- added U+2500 - U+257F box drawing glyphs to Sans Mono (by David Jez) +- fixed accents in Wcircumflex, Ycircumflex and Zdotaccent (by David Jez) +- extra kerning for F (by Sander Vesik) +- added 'missing' glyph U+FFFD (by David Jez) + +Changes from 1.10 to 1.11: + +- kerning updates (by Sander Vesik) +- added Iogonek, iogonek, IJ, ij, Uogonek, uogonek (from SuSE standard fonts + by Adrian Schroeter, SuSE AG) +- added Gcommaaccent, gcommaaccent, Kcommaaccent, kcommaaccent, + Lcommaaccent, lcommaaccent, Ncommaaccent, ncommaaccent, Rcommaaccent, + rcommaaccent (by Stepan Roh) + +Changes from 1.9 to 1.10: + +- added U+022E, U+022F (by Sander Vesik) +- kerning updates for DejaVu Sans (by Sander Vesik) +- fixed too wide cyrillic glyphs in DejaVu Sans Mono (by Valentin Stoykov) +- fixed ligatures bug in Mono (by Stepan Roh) + +Changes from 1.8 to 1.9: + +- integrated Arev Cyrillics (by Danilo Segan) +- added U+01EA, U+01EB, U+01EC, U+01ED (by Sander Vesik) + +Changes from 1.7 to 1.8: + +- fixed accents in Serif Oblique and Serif Bold Oblique (by Stepan Roh) + +Changes from 1.6 to 1.7: + +- added automatically generated Condensed typefaces (by Stepan Roh) + +Changes from 1.5 to 1.6: + +- monospace bug fixed (by Stepan Roh) +- incorrect Bitstream foundry assigned by fontconfig and KDE Font Installer +fixed (by Stepan Roh) +- added automatically generated Oblique version of Serif typefaces (by +Stepan Roh) +- corrected cyrillic D and d (by Danilo Segan and David Jez) +- fixed accents position in Oblique version of Serif typefaces (by Danilo +Segan and Sander Vesik) +- fixed incorrect computation of OS2Win# fields (by Stepan Roh) +- added visiblespace U+2423 (by David Jez) +- fixed 'line height' bug by fixing ascender and descender values (by David +Jez and Stepan Roh) +- fixed part of 'worse than Vera' bug (by Peter Cernak) +- smaller comma accent U+0326 (by David Jez) + +Changes from 1.4 to 1.5: + +- added Cyrillics (96 characters) and Dcroat to the rest of typefaces (by +Danilo Segan) +- fixed bugs in some Cyrillic characters, some of them reported by Sander +Vesik (by Danilo Segan) +- added U+0100, U+0101, U+0112, U+0113, U+012A, U+012B, U+014C, U+014D, +U+016A, U+016B, U+01E2, U+01E3, U+0232 and U+0233 (by Sander Vesik) +- added Romanian characters (by Misu Moldovan) +- added U+0108, U+0109, U+010A, U+010B, U+0114, U+0115, U+0116, U+0117, +U+011C, U+011D, U+0120, U+0121, U+0124, U+0125, U+0128, U+0129, U+012C, +U+012D, U+0134, U+0135, U+014E, U+014F, U+0150, U+0151, U+015C, U+015D, +U+0168, U+0169, U+016C, U+016D, U+0170, U+0171 and U+0237 (by James +Crippen) +- added U+02BB, U+2010, U+2011, U+2012 and U+2015 (by Stepan Roh) + +Changes from 1.3 to 1.4: + +- added Polish characters (Aogonek, aogonek, Eogonek, eogonek, Nacute, +nacute, Sacute, sacute, Zacute, zacute, Zdotaccent, zdotaccent) (by Stepan +Roh) + +Changes from 1.2 to 1.3: + +- added Cyrillics (96 characters) and Dcroat to Sans typefaces (by Danilo +Segan from his BePa fonts) + +Changes from 1.1 to 1.2: + +- added Ldot, ldot, Wcircumflex, wcircumflex, Ycircumflex, ycircumflex, + Wgrave, wgrave, Wacute, wacute, Wdieresis, wdieresis, Ygrave and ygrave + (from The Olwen Font Family 0.2 by Dafydd Harries) + +Changes from 1.0 to 1.1: + +- added Lacute, lacute, Lcaron, lcaron, Racute and racute (by Peter Cernak) + +Changes from 0.9.4 to 1.0: + +- none, just changed version and updated README + +Changes from 0.9.3 to 0.9.4: + +- fixed TTF generation (kerning tables were missing) + +Changes from 0.9.2 to 0.9.3: + +- kerning of added characters +- proper caron shape for dcaron in Mono (by Ondrej Koala Vacha) +- minor visual changes + +Changes from 0.9.1 to 0.9.2: + +- internal bugged version + +Changes from 0.9 to 0.9.1: + +- proper caron shape for dcaron and tcaron +- minor visual changes + +$Id: NEWS 1587 2007-02-18 16:20:38Z ben_laenen $ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/29/299dc6b637e0f5b3775b92631d240971508c0684.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/29/299dc6b637e0f5b3775b92631d240971508c0684.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,61 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::MimeTypeTest < ActiveSupport::TestCase + + def test_of + to_test = {'test.unk' => nil, + 'test.txt' => 'text/plain', + 'test.c' => 'text/x-c', + } + to_test.each do |name, expected| + assert_equal expected, Redmine::MimeType.of(name) + end + end + + def test_css_class_of + to_test = {'test.unk' => nil, + 'test.txt' => 'text-plain', + 'test.c' => 'text-x-c', + } + to_test.each do |name, expected| + assert_equal expected, Redmine::MimeType.css_class_of(name) + end + end + + def test_main_mimetype_of + to_test = {'test.unk' => nil, + 'test.txt' => 'text', + 'test.c' => 'text', + } + to_test.each do |name, expected| + assert_equal expected, Redmine::MimeType.main_mimetype_of(name) + end + end + + def test_is_type + to_test = {['text', 'test.unk'] => false, + ['text', 'test.txt'] => true, + ['text', 'test.c'] => true, + } + to_test.each do |args, expected| + assert_equal expected, Redmine::MimeType.is_type?(*args) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/29/29d1b7a44a44f4040dd2b8d4fe4b9b40b3383592.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/29/29d1b7a44a44f4040dd2b8d4fe4b9b40b3383592.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,84 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class TrackersController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + + def index + respond_to do |format| + format.html { + @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position' + render :action => "index", :layout => false if request.xhr? + } + format.api { + @trackers = Tracker.all + } + end + end + + def new + @tracker ||= Tracker.new(params[:tracker]) + @trackers = Tracker.find :all, :order => 'position' + @projects = Project.find(:all) + end + + def create + @tracker = Tracker.new(params[:tracker]) + if request.post? and @tracker.save + # workflow copy + if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from])) + @tracker.workflows.copy(copy_from) + end + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'index' + return + end + new + render :action => 'new' + end + + def edit + @tracker ||= Tracker.find(params[:id]) + @projects = Project.find(:all) + end + + def update + @tracker = Tracker.find(params[:id]) + if request.put? and @tracker.update_attributes(params[:tracker]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'index' + return + end + edit + render :action => 'edit' + end + + verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index } + def destroy + @tracker = Tracker.find(params[:id]) + unless @tracker.issues.empty? + flash[:error] = l(:error_can_not_delete_tracker) + else + @tracker.destroy + end + redirect_to :action => 'index' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/29/29fe660e228b4c672e9942d71f9138fc1988a1fe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/29/29fe660e228b4c672e9942d71f9138fc1988a1fe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +

<%= link_to l(:label_group_plural), groups_path %> » <%=h @group %>

+ +
    +<% @group.users.each do |user| %> +
  • <%=h user %>
  • +<% end %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2a/2a26987d3e76c57b6a5ef62d32f7ea30699c2a7e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2a/2a26987d3e76c57b6a5ef62d32f7ea30699c2a7e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class AlphaPluginLibModel < ActiveRecord::Base + def self.report_location; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2a/2a729c60b4face5ae26610fc483b9a2b1f7c2f71.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2a/2a729c60b4face5ae26610fc483b9a2b1f7c2f71.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,102 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class WorkflowsController < ApplicationController + layout 'admin' + + before_filter :require_admin + before_filter :find_roles + before_filter :find_trackers + + def index + @workflow_counts = Workflow.count_by_tracker_and_role + end + + def edit + @role = Role.find_by_id(params[:role_id]) + @tracker = Tracker.find_by_id(params[:tracker_id]) + + if request.post? + Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) + (params[:issue_status] || []).each { |status_id, transitions| + transitions.each { |new_status_id, options| + author = options.is_a?(Array) && options.include?('author') && !options.include?('always') + assignee = options.is_a?(Array) && options.include?('assignee') && !options.include?('always') + @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee) + } + } + if @role.save + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker + return + end + end + + @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) + if @tracker && @used_statuses_only && @tracker.issue_statuses.any? + @statuses = @tracker.issue_statuses + end + @statuses ||= IssueStatus.find(:all, :order => 'position') + + if @tracker && @role && @statuses.any? + workflows = Workflow.all(:conditions => {:role_id => @role.id, :tracker_id => @tracker.id}) + @workflows = {} + @workflows['always'] = workflows.select {|w| !w.author && !w.assignee} + @workflows['author'] = workflows.select {|w| w.author} + @workflows['assignee'] = workflows.select {|w| w.assignee} + end + end + + def copy + + if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' + @source_tracker = nil + else + @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i) + end + if params[:source_role_id].blank? || params[:source_role_id] == 'any' + @source_role = nil + else + @source_role = Role.find_by_id(params[:source_role_id].to_i) + end + + @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids]) + @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids]) + + if request.post? + if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) + flash.now[:error] = l(:error_workflow_copy_source) + elsif @target_trackers.nil? || @target_roles.nil? + flash.now[:error] = l(:error_workflow_copy_target) + else + Workflow.copy(@source_tracker, @source_role, @target_trackers, @target_roles) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'copy', :source_tracker_id => @source_tracker, :source_role_id => @source_role + end + end + end + + private + + def find_roles + @roles = Role.find(:all, :order => 'builtin, position') + end + + def find_trackers + @trackers = Tracker.find(:all, :order => 'position') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2a/2a8a6f95df9c9b5ea1480ac33b5f365836080244.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2a/2a8a6f95df9c9b5ea1480ac33b5f365836080244.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,178 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Setting < ActiveRecord::Base + + DATE_FORMATS = [ + '%Y-%m-%d', + '%d/%m/%Y', + '%d.%m.%Y', + '%d-%m-%Y', + '%m/%d/%Y', + '%d %b %Y', + '%d %B %Y', + '%b %d, %Y', + '%B %d, %Y' + ] + + TIME_FORMATS = [ + '%H:%M', + '%I:%M %p' + ] + + ENCODINGS = %w(US-ASCII + windows-1250 + windows-1251 + windows-1252 + windows-1253 + windows-1254 + windows-1255 + windows-1256 + windows-1257 + windows-1258 + windows-31j + ISO-2022-JP + ISO-2022-KR + ISO-8859-1 + ISO-8859-2 + ISO-8859-3 + ISO-8859-4 + ISO-8859-5 + ISO-8859-6 + ISO-8859-7 + ISO-8859-8 + ISO-8859-9 + ISO-8859-13 + ISO-8859-15 + KOI8-R + UTF-8 + UTF-16 + UTF-16BE + UTF-16LE + EUC-JP + Shift_JIS + CP932 + GB18030 + GBK + ISCII91 + EUC-KR + Big5 + Big5-HKSCS + TIS-620) + + cattr_accessor :available_settings + @@available_settings = YAML::load(File.open("#{Rails.root}/config/settings.yml")) + Redmine::Plugin.all.each do |plugin| + next unless plugin.settings + @@available_settings["plugin_#{plugin.id}"] = {'default' => plugin.settings[:default], 'serialized' => true} + end + + validates_uniqueness_of :name + validates_inclusion_of :name, :in => @@available_settings.keys + validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| @@available_settings[setting.name]['format'] == 'int' } + + # Hash used to cache setting values + @cached_settings = {} + @cached_cleared_on = Time.now + + def value + v = read_attribute(:value) + # Unserialize serialized settings + v = YAML::load(v) if @@available_settings[name]['serialized'] && v.is_a?(String) + v = v.to_sym if @@available_settings[name]['format'] == 'symbol' && !v.blank? + v + end + + def value=(v) + v = v.to_yaml if v && @@available_settings[name] && @@available_settings[name]['serialized'] + write_attribute(:value, v.to_s) + end + + # Returns the value of the setting named name + def self.[](name) + v = @cached_settings[name] + v ? v : (@cached_settings[name] = find_or_default(name).value) + end + + def self.[]=(name, v) + setting = find_or_default(name) + setting.value = (v ? v : "") + @cached_settings[name] = nil + setting.save + setting.value + end + + # Defines getter and setter for each setting + # Then setting values can be read using: Setting.some_setting_name + # or set using Setting.some_setting_name = "some value" + @@available_settings.each do |name, params| + src = <<-END_SRC + def self.#{name} + self[:#{name}] + end + + def self.#{name}? + self[:#{name}].to_i > 0 + end + + def self.#{name}=(value) + self[:#{name}] = value + end + END_SRC + class_eval src, __FILE__, __LINE__ + end + + # Helper that returns an array based on per_page_options setting + def self.per_page_options_array + per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort + end + + def self.openid? + Object.const_defined?(:OpenID) && self[:openid].to_i > 0 + end + + # Checks if settings have changed since the values were read + # and clears the cache hash if it's the case + # Called once per request + def self.check_cache + settings_updated_on = Setting.maximum(:updated_on) + if settings_updated_on && @cached_cleared_on <= settings_updated_on + clear_cache + end + end + + # Clears the settings cache + def self.clear_cache + @cached_settings.clear + @cached_cleared_on = Time.now + logger.info "Settings cache cleared." if logger + end + +private + # Returns the Setting instance for the setting named name + # (record found in database or new record with default value) + def self.find_or_default(name) + name = name.to_s + raise "There's no setting named #{name}" unless @@available_settings.has_key?(name) + setting = find_by_name(name) + unless setting + setting = new(:name => name) + setting.value = @@available_settings[name]['default'] + end + setting + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2b/2b0a9f999f6063790f2925cfcbf5bec32cb0108e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2b/2b0a9f999f6063790f2925cfcbf5bec32cb0108e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,583 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::IssuesTest < ActionController::IntegrationTest + fixtures :projects, + :users, + :roles, + :members, + :member_roles, + :issues, + :issue_statuses, + :versions, + :trackers, + :projects_trackers, + :issue_categories, + :enabled_modules, + :enumerations, + :attachments, + :workflows, + :custom_fields, + :custom_values, + :custom_fields_projects, + :custom_fields_trackers, + :time_entries, + :journals, + :journal_details, + :queries, + :attachments + + def setup + Setting.rest_api_enabled = '1' + end + + context "/issues" do + # Use a private project to make sure auth is really working and not just + # only showing public issues. + should_allow_api_authentication(:get, "/projects/private-child/issues.xml") + + should "contain metadata" do + get '/issues.xml' + + assert_tag :tag => 'issues', + :attributes => { + :type => 'array', + :total_count => assigns(:issue_count), + :limit => 25, + :offset => 0 + } + end + + context "with offset and limit" do + should "use the params" do + get '/issues.xml?offset=2&limit=3' + + assert_equal 3, assigns(:limit) + assert_equal 2, assigns(:offset) + assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}} + end + end + + context "with nometa param" do + should "not contain metadata" do + get '/issues.xml?nometa=1' + + assert_tag :tag => 'issues', + :attributes => { + :type => 'array', + :total_count => nil, + :limit => nil, + :offset => nil + } + end + end + + context "with nometa header" do + should "not contain metadata" do + get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'} + + assert_tag :tag => 'issues', + :attributes => { + :type => 'array', + :total_count => nil, + :limit => nil, + :offset => nil + } + end + end + + context "with relations" do + should "display relations" do + get '/issues.xml?include=relations' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag 'relations', + :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}}, + :children => {:count => 1}, + :child => { + :tag => 'relation', + :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'} + } + assert_tag 'relations', + :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}}, + :children => {:count => 0} + end + end + + context "with invalid query params" do + should "return errors" do + get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}} + + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"} + end + end + + context "with custom field filter" do + should "show only issues with the custom field value" do + get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}} + + expected_ids = Issue.visible.all( + :include => :custom_values, + :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id) + + assert_select 'issues > issue > id', :count => expected_ids.count do |ids| + ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } + end + end + end + + context "with custom field filter (shorthand method)" do + should "show only issues with the custom field value" do + get '/issues.xml', { :cf_1 => 'MySQL' } + + expected_ids = Issue.visible.all( + :include => :custom_values, + :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id) + + assert_select 'issues > issue > id', :count => expected_ids.count do |ids| + ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } + end + end + end + end + + context "/index.json" do + should_allow_api_authentication(:get, "/projects/private-child/issues.json") + end + + context "/index.xml with filter" do + should "show only issues with the status_id" do + get '/issues.xml?status_id=5' + + expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id) + + assert_select 'issues > issue > id', :count => expected_ids.count do |ids| + ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } + end + end + end + + context "/index.json with filter" do + should "show only issues with the status_id" do + get '/issues.json?status_id=5' + + json = ActiveSupport::JSON.decode(response.body) + status_ids_used = json['issues'].collect {|j| j['status']['id'] } + assert_equal 3, status_ids_used.length + assert status_ids_used.all? {|id| id == 5 } + end + + end + + # Issue 6 is on a private project + context "/issues/6.xml" do + should_allow_api_authentication(:get, "/issues/6.xml") + end + + context "/issues/6.json" do + should_allow_api_authentication(:get, "/issues/6.json") + end + + context "GET /issues/:id" do + context "with journals" do + context ".xml" do + should "display journals" do + get '/issues/1.xml?include=journals' + + assert_tag :tag => 'issue', + :child => { + :tag => 'journals', + :attributes => { :type => 'array' }, + :child => { + :tag => 'journal', + :attributes => { :id => '1'}, + :child => { + :tag => 'details', + :attributes => { :type => 'array' }, + :child => { + :tag => 'detail', + :attributes => { :name => 'status_id' }, + :child => { + :tag => 'old_value', + :content => '1', + :sibling => { + :tag => 'new_value', + :content => '2' + } + } + } + } + } + } + end + end + end + + context "with custom fields" do + context ".xml" do + should "display custom fields" do + get '/issues/3.xml' + + assert_tag :tag => 'issue', + :child => { + :tag => 'custom_fields', + :attributes => { :type => 'array' }, + :child => { + :tag => 'custom_field', + :attributes => { :id => '1'}, + :child => { + :tag => 'value', + :content => 'MySQL' + } + } + } + + assert_nothing_raised do + Hash.from_xml(response.body).to_xml + end + end + end + end + + context "with attachments" do + context ".xml" do + should "display attachments" do + get '/issues/3.xml?include=attachments' + + assert_tag :tag => 'issue', + :child => { + :tag => 'attachments', + :children => {:count => 5}, + :child => { + :tag => 'attachment', + :child => { + :tag => 'filename', + :content => 'source.rb', + :sibling => { + :tag => 'content_url', + :content => 'http://www.example.com/attachments/download/4/source.rb' + } + } + } + } + end + end + end + + context "with subtasks" do + setup do + @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1) + @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1) + @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id) + end + + context ".xml" do + should "display children" do + get '/issues/1.xml?include=children' + + assert_tag :tag => 'issue', + :child => { + :tag => 'children', + :children => {:count => 2}, + :child => { + :tag => 'issue', + :attributes => {:id => @c1.id.to_s}, + :child => { + :tag => 'subject', + :content => 'child c1', + :sibling => { + :tag => 'children', + :children => {:count => 1}, + :child => { + :tag => 'issue', + :attributes => {:id => @c3.id.to_s} + } + } + } + } + } + end + + context ".json" do + should "display children" do + get '/issues/1.json?include=children' + + json = ActiveSupport::JSON.decode(response.body) + assert_equal([ + { + 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'}, + 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }] + }, + { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} } + ], + json['issue']['children']) + end + end + end + end + end + + context "POST /issues.xml" do + should_allow_api_authentication(:post, + '/issues.xml', + {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, + {:success_code => :created}) + + should "create an issue with the attributes" do + assert_difference('Issue.count') do + post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith') + end + + issue = Issue.first(:order => 'id DESC') + assert_equal 1, issue.project_id + assert_equal 2, issue.tracker_id + assert_equal 3, issue.status_id + assert_equal 'API test', issue.subject + + assert_response :created + assert_equal 'application/xml', @response.content_type + assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s} + end + end + + context "POST /issues.xml with failure" do + should "have an errors tag" do + assert_no_difference('Issue.count') do + post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith') + end + + assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"} + end + end + + context "POST /issues.json" do + should_allow_api_authentication(:post, + '/issues.json', + {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, + {:success_code => :created}) + + should "create an issue with the attributes" do + assert_difference('Issue.count') do + post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith') + end + + issue = Issue.first(:order => 'id DESC') + assert_equal 1, issue.project_id + assert_equal 2, issue.tracker_id + assert_equal 3, issue.status_id + assert_equal 'API test', issue.subject + end + + end + + context "POST /issues.json with failure" do + should "have an errors element" do + assert_no_difference('Issue.count') do + post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith') + end + + json = ActiveSupport::JSON.decode(response.body) + assert json['errors'].include?(['subject', "can't be blank"]) + end + end + + # Issue 6 is on a private project + context "PUT /issues/6.xml" do + setup do + @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}} + @headers = { :authorization => credentials('jsmith') } + end + + should_allow_api_authentication(:put, + '/issues/6.xml', + {:issue => {:subject => 'API update', :notes => 'A new note'}}, + {:success_code => :ok}) + + should "not create a new issue" do + assert_no_difference('Issue.count') do + put '/issues/6.xml', @parameters, @headers + end + end + + should "create a new journal" do + assert_difference('Journal.count') do + put '/issues/6.xml', @parameters, @headers + end + end + + should "add the note to the journal" do + put '/issues/6.xml', @parameters, @headers + + journal = Journal.last + assert_equal "A new note", journal.notes + end + + should "update the issue" do + put '/issues/6.xml', @parameters, @headers + + issue = Issue.find(6) + assert_equal "API update", issue.subject + end + + end + + context "PUT /issues/3.xml with custom fields" do + setup do + @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}} + @headers = { :authorization => credentials('jsmith') } + end + + should "update custom fields" do + assert_no_difference('Issue.count') do + put '/issues/3.xml', @parameters, @headers + end + + issue = Issue.find(3) + assert_equal '150', issue.custom_value_for(2).value + assert_equal 'PostgreSQL', issue.custom_value_for(1).value + end + end + + context "PUT /issues/6.xml with failed update" do + setup do + @parameters = {:issue => {:subject => ''}} + @headers = { :authorization => credentials('jsmith') } + end + + should "not create a new issue" do + assert_no_difference('Issue.count') do + put '/issues/6.xml', @parameters, @headers + end + end + + should "not create a new journal" do + assert_no_difference('Journal.count') do + put '/issues/6.xml', @parameters, @headers + end + end + + should "have an errors tag" do + put '/issues/6.xml', @parameters, @headers + + assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"} + end + end + + context "PUT /issues/6.json" do + setup do + @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}} + @headers = { :authorization => credentials('jsmith') } + end + + should_allow_api_authentication(:put, + '/issues/6.json', + {:issue => {:subject => 'API update', :notes => 'A new note'}}, + {:success_code => :ok}) + + should "not create a new issue" do + assert_no_difference('Issue.count') do + put '/issues/6.json', @parameters, @headers + end + end + + should "create a new journal" do + assert_difference('Journal.count') do + put '/issues/6.json', @parameters, @headers + end + end + + should "add the note to the journal" do + put '/issues/6.json', @parameters, @headers + + journal = Journal.last + assert_equal "A new note", journal.notes + end + + should "update the issue" do + put '/issues/6.json', @parameters, @headers + + issue = Issue.find(6) + assert_equal "API update", issue.subject + end + + end + + context "PUT /issues/6.json with failed update" do + setup do + @parameters = {:issue => {:subject => ''}} + @headers = { :authorization => credentials('jsmith') } + end + + should "not create a new issue" do + assert_no_difference('Issue.count') do + put '/issues/6.json', @parameters, @headers + end + end + + should "not create a new journal" do + assert_no_difference('Journal.count') do + put '/issues/6.json', @parameters, @headers + end + end + + should "have an errors attribute" do + put '/issues/6.json', @parameters, @headers + + json = ActiveSupport::JSON.decode(response.body) + assert json['errors'].include?(['subject', "can't be blank"]) + end + end + + context "DELETE /issues/1.xml" do + should_allow_api_authentication(:delete, + '/issues/6.xml', + {}, + {:success_code => :ok}) + + should "delete the issue" do + assert_difference('Issue.count',-1) do + delete '/issues/6.xml', {}, :authorization => credentials('jsmith') + end + + assert_nil Issue.find_by_id(6) + end + end + + context "DELETE /issues/1.json" do + should_allow_api_authentication(:delete, + '/issues/6.json', + {}, + {:success_code => :ok}) + + should "delete the issue" do + assert_difference('Issue.count',-1) do + delete '/issues/6.json', {}, :authorization => credentials('jsmith') + end + + assert_nil Issue.find_by_id(6) + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2b/2b0ee259d41451978f73ac2e9b9372c5b4686f27.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2b/2b0ee259d41451978f73ac2e9b9372c5b4686f27.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Version < ActiveRecord::Base + generator_for :name, :start => 'Version 1.0.0' + generator_for :status => 'open' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2b/2b606f996385c04392f5348a349a444f5c1cce23.svn-base Binary file .svn/pristine/2b/2b606f996385c04392f5348a349a444f5c1cce23.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2b/2b7a2bc77572b182843ad0ad8bff542d264bae24.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2b/2b7a2bc77572b182843ad0ad8bff542d264bae24.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +--- +custom_fields_projects_001: + custom_field_id: 9 + project_id: 1 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2b/2b8d3c9c3c263ae7cd6f97cc6dd5f192b92ebd2b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2b/2b8d3c9c3c263ae7cd6f97cc6dd5f192b92ebd2b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,69 @@ +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# This implements native php methods used by tcpdf, which have had to be +# reimplemented within Ruby. + +module RFPDF + + # http://uk2.php.net/getimagesize + def getimagesize(filename) + image = Magick::ImageList.new(filename) + + out = Hash.new + out[0] = image.columns + out[1] = image.rows + + # These are actually meant to return integer values But I couldn't seem to find anything saying what those values are. + # So for now they return strings. The only place that uses this at the moment is the parsejpeg method, so I've changed that too. + case image.mime_type + when "image/gif" + out[2] = "GIF" + when "image/jpeg" + out[2] = "JPEG" + when "image/png" + out[2] = "PNG" + when " image/vnd.wap.wbmp" + out[2] = "WBMP" + when "image/x-xpixmap" + out[2] = "XPM" + end + out[3] = "height=\"#{image.rows}\" width=\"#{image.columns}\"" + out['mime'] = image.mime_type + + # This needs work to cover more situations + # I can't see how to just list the number of channels with ImageMagick / rmagick + if image.colorspace.to_s == "CMYKColorspace" + out['channels'] = 4 + elsif image.colorspace.to_s == "RGBColorspace" + out['channels'] = 3 + end + + out['bits'] = image.channel_depth + File.open( TCPDF.k_path_cache + File::basename(filename), 'w'){|f| + f.binmode + f.print image.to_blob + f.close + } + + out + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2c/2c03b2451a9c38796d0008f31034571e1a5677c0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2c/2c03b2451a9c38796d0008f31034571e1a5677c0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,84 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class AdminController < ApplicationController + layout 'admin' + before_filter :require_admin + helper :sort + include SortHelper + + def index + @no_configuration_data = Redmine::DefaultData::Loader::no_data? + end + + def projects + @status = params[:status] ? params[:status].to_i : 1 + c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) + unless params[:name].blank? + name = "%#{params[:name].strip.downcase}%" + c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name] + end + @projects = Project.find :all, :order => 'lft', + :conditions => c.conditions + + render :action => "projects", :layout => false if request.xhr? + end + + def plugins + @plugins = Redmine::Plugin.all + end + + # Loads the default configuration + # (roles, trackers, statuses, workflow, enumerations) + def default_configuration + if request.post? + begin + Redmine::DefaultData::Loader::load(params[:lang]) + flash[:notice] = l(:notice_default_data_loaded) + rescue Exception => e + flash[:error] = l(:error_can_t_load_default_data, e.message) + end + end + redirect_to :action => 'index' + end + + def test_email + raise_delivery_errors = ActionMailer::Base.raise_delivery_errors + # Force ActionMailer to raise delivery errors so we can catch it + ActionMailer::Base.raise_delivery_errors = true + begin + @test = Mailer.deliver_test(User.current) + flash[:notice] = l(:notice_email_sent, User.current.mail) + rescue Exception => e + flash[:error] = l(:notice_email_error, e.message) + end + ActionMailer::Base.raise_delivery_errors = raise_delivery_errors + redirect_to :controller => 'settings', :action => 'edit', :tab => 'notifications' + end + + def info + @db_adapter_name = ActiveRecord::Base.connection.adapter_name + @checklist = [ + [:text_default_administrator_account_changed, + User.find(:first, + :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?], + [:text_file_repository_writable, File.writable?(Attachment.storage_path)], + [:text_plugin_assets_writable, File.writable?(Engines.public_directory)], + [:text_rmagick_available, Object.const_defined?(:Magick)] + ] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2c/2c27236c8597defd08e66caac19e9d30961716f2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2c/2c27236c8597defd08e66caac19e9d30961716f2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +class SetDocAndFilesNotifications < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.find_by_controller_and_action("projects", "add_file").update_attribute(:mail_option, true) + Permission.find_by_controller_and_action("projects", "add_document").update_attribute(:mail_option, true) + Permission.find_by_controller_and_action("documents", "add_attachment").update_attribute(:mail_option, true) + Permission.find_by_controller_and_action("issues", "add_attachment").update_attribute(:mail_option, true) + end + + def self.down + Permission.find_by_controller_and_action("projects", "add_file").update_attribute(:mail_option, false) + Permission.find_by_controller_and_action("projects", "add_document").update_attribute(:mail_option, false) + Permission.find_by_controller_and_action("documents", "add_attachment").update_attribute(:mail_option, false) + Permission.find_by_controller_and_action("issues", "add_attachment").update_attribute(:mail_option, false) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2c/2c47730001fc0653b0aba66c32df2d2cfeb34051.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2c/2c47730001fc0653b0aba66c32df2d2cfeb34051.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,389 @@ +-*-text-*- +$Id: CREDITS,v 1.4 2003/03/27 08:40:03 peterlin Exp $ + +This file lists the contributors and contributions to the free UCS +scalable font project. + + +# URW++ Design & Development GmbH + +URW++ donated a set of 35 core PostScript Type 1 fonts to the +Ghostscript project , to be available +under the terms of GNU General Public License (GPL). + + Basic Latin (U+0041-U+007A) + Latin-1 Supplement (U+00C0-U+00FF) + Latin Extended-A (U+0100-U+017F) + Spacing Modifier Letters (U+02B0-U+02FF) + Mathematical Operators (U+2200-U+22FF) + Block Elements (U+2580-U+259F) + Dingbats (U+2700-U+27BF) + + +# Yannis Haralambous and John + Plaice + +Yannis Haralambous and John Plaice are the authors of Omega +typesetting system, . Omega is an +extension of TeX. Its first release, aims primarily at improving TeX's +multilingual abilities. In Omega all characters and pointers into +data-structures are 16-bit wide, instead of 8-bit, thereby eliminating +many of the trivial limitations of TeX. Omega also allows multiple +input and output character sets, and uses programmable filters to +translate from one encoding to another, to perform contextual +analysis, etc. Internally, Omega uses the universal 16-bit Unicode +standard character set, based on ISO-10646. These improvements not +only make it a lot easier for TeX users to cope with multiple or +complex languages, like Arabic, Indic, Khmer, Chinese, Japanese or +Korean, in one document, but will also form the basis for future +developments in other areas, such as native color support and +hypertext features. ... Fonts for UT1 (omlgc family) and UT2 (omah +family) are under development: these fonts are in PostScript format +and visually close to Times and Helvetica font families. (from the +Omega WWW site). Omega fonts are available subject to GPL +. + + Latin Extended-B (U+0180-U+024F) + IPA Extensions (U+0250-U+02AF) + Greek (U+0370-U+03FF) + Armenian (U+0530-U+058F) + Hebrew (U+0590-U+05FF) + Arabic (U+0600-U+06FF) + Currency Symbols (U+20A0-U+20CF) + Arabic Presentation Forms-A (U+FB50-U+FDFF) + Arabic Presentation Forms-B (U+FE70-U+FEFF) + + +# Valek Filippov + +Valek Filippov added Cyrillic glyphs and composite Latin Extended A to +the whole set of the abovementioned URW set of 35 PostScript core +fonts, . The fonts are available under +GPL. + + Latin Extended-A (U+0100-U+017F) + Cyrillic (U+0400-U+04FF) + + +# Wadalab Kanji Comittee + +Between April 1990 and March 1992, Wadalab Kanji Comittee put together +a series of scalable font files with Japanese scripts, in four forms: +Sai Micho, Chu Mincho, Cho Kaku and Saimaru. The font files are +written in custom file format, while tools for conversion into +Metafont and PostScript Type 1 are also supplied. The Wadalab Kanji +Comittee has later been dismissed, and the resulting files can be now +found on the FTP server of the Depertment of Mathematical Engineering +and Information Physics, Faculty of Engineering, University of Tokyo +. + + Hiragana (U+3040-U+309F) + Katakana (U+30A0-U+30FF) + + +# Young U. Ryu + +Young Ryu is the author of Txfonts, a set of mathematical symbols +designed to accompany text typeset in Times or its variants. In the +documentation, Young adresses the design of mathematical symbols: "The +Adobe Times fonts are thicker than the CM fonts. Designing math fonts +for Times based on the rule thickness of Times = , , + , / , < , +etc. would result in too thick math symbols, in my opinion. In the TX +fonts, these glyphs are thinner than those of original Times +fonts. That is, the rule thickness of these glyphs is around 85% of +that of the Times fonts, but still thicker than that of the CM fonts." +TX fonts are are distributed under the GNU public license +(GPL). Pointers to their location are available on +. + + Arrows (U+2190-U+21FF) + Mathematical Symbols (U+2200-U+22FF) + + +# Angelo Haritsis + +Angelo Haritsis has compiled a set of Greek Type 1 fonts, available on +. +The glyphs from this source has been used to compose Greek glyphs in +FreeSans and FreeMono. + +Angelo's licence says: "You can enjoy free use of these fonts for +educational or commercial purposes. All derived works should include +this paragraph. If you want to change something please let me have +your changes (via email) so that they can go into the next +version. You can also send comments etc to the above address." + + Greek (U+0370-U+03FF) + + +# Yannis Haralambous and Virach Sornlertlamvanich + +In 1999, Yannis Haralambous and Virach Sornlertlamvanich made a set of +glyphs covering the Thai national standard NF3, in both upright and +slanted shape. The collection of glyphs have been made part of GNU +intlfonts 1.2 package and is available on + under GPL. + + Thai (U+0E00-U+0E7F) + + +# Shaheed R. Haque + +Shaheed Haque has developed a basic set of basic Bengali glyphs +(without ligatures), using ISO10646 encoding. They are available under +the XFree86 license at . + +Copyright (C) 2001 S.R.Haque . All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL S.R.HAQUE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of S.R.Haque shall not be +used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from +S.R.Haque. + + Bengali (U+0980-U+09FF) + + +# Sam Stepanyan + +Sam Stepanyan created a set of Armenian sans serif glyphs visually +compatible with Helvetica or Arial. Available on +. On +2002-01-24, Sam writes: "Arial Armenian font is free for +non-commercial use, so it is OK to use under GPL license." + + Armenian (U+0530-U+058F) + + +# Mohamed Ishan + +Mohamed Ishan has started a Thaana Unicode Project + and among other things created a +couple of Thaana fonts, available under FDL or BDF license. + + Thaana (U+0780-U+07BF) + + +# Sushant Kumar Dash (*) + +Sushant Dash has created a font in his mother tongue, Oriya. As he +states on his web page : +"Please feel free to foreword this mail to your Oriya friends. No +copyright law is applied for this font. It is totally free!!! Feel +free to modify this using any font editing tools. This is designed for +people like me, who are away from Orissa and want to write letters +home using Computers, but suffer due to unavailability of Oriya +fonts.(Or the cost of the available packages are too much)." + + Oriya (U+0B00-U+0B7F) + + +# Harsh Kumar + +Harsh Kumar has started BharatBhasha - +an effort to provide "FREE software, Tutorial, Source Codes +etc. available for working in Hindi, Marathi, Gujarati, Gurmukhi and +Bangla. You can type text, write Web pages or develop Indian Languages +Applications on Windows and on Linux. We also offer FREE help to +users, enthusiasts and software developers for their work in Indian +languages." + + Devanagari (U+0900-U+097F) + Bengali (U+0980-U+09FF) + Gurmukhi (U+0A00-U+0A7F) + Gujarati (U+0A80-U+0AFF) + + +# Prasad A. Chodavarapu + +Prasad A. Chodavarapu created Tikkana, a Telugu font available in Type +1 and TrueType format on . +Tikkana exceeds the Unicode Telugu range with some composite glyphs. +Available under the GNU General Public License. + + Telugu (U+0C00-U+0C7F) + + +# Frans Velthuis and Anshuman Pandey + + +In 1991, Frans Velthuis from the Groningen University, The +Netherlands, released a Devanagari font as Metafont source, available +under the terms of GNU GPL. Later, Anshuman Pandey from the Washington +University, Seattle, USA, took over the maintenance of font. Fonts can +be found on CTAN, . I +converted the font to Type 1 format using Pter Szab's TeXtrace +program and removed some +redundant control points with PfaEdit. + + Devanagari (U+0900-U+097F) + + +# Hardip Singh Pannu + +In 1991, Hardip Singh Pannu has created a free Gurmukhi TrueType font, +available as regular, bold, oblique and bold oblique form. Its license +says "Please remember that these fonts are copyrighted (by me) and are +for non-profit use only." + + Gurmukhi (U+0A00-U+0A7F) + + +# Jeroen Hellingman + +Jeroen Hellingman created a set of Malayalam metafonts in 1994, and a +set of Oriya metafonts in 1996. Malayalam fonts were created as +uniform stroke only, while Oriya metafonts exist in both uniform and +modulated stroke. From private communication: "It is my intention to +release the fonts under GPL, but not all copies around have this +notice on them." Metafonts can be found on CTAN, + and +. + + Oriya (U+0B00-U+0B7F) + Malayalam (U+0D00-U+0D7F) + + +# Thomas Ridgeway <> (*) + +Thomas Ridgeway, then at the Humanities And Arts Computing Center, +Washington University, Seattle, USA, (now defunct), created a Tamil +metafont in 1990. Anshuman Pandey from the same university took over +the maintenance of font. Fonts can be found at CTAN, +. + + Tamil (U+0B80-U+0BFF) + + +# Berhanu Beyene <1beyene AT informatik.uni-hamburg.de>, + Prof. Dr. Manfred Kudlek , Olaf + Kummer , and Jochen Metzinger < + +Beyene, Kudlek, Kummer and Metzinger from the Theoretical Foundations +of Computer Science, University of Hamburg, prepared a set of Ethiopic +metafonts, found on +. They also +maintain home page on the Ethiopic font project, +, +and can be reached at . The current +version of fonts is 0.7 (1998), and they are released under GNU GPL. I +converted the fonts to Type 1 format using Pter Szab's TeXtrace +program and removed some +redundant control points with PfaEdit. + + Ethiopic (U+1200-U+137F) + + +# Maxim Iorsh + +In 2002, Maxim Iorsh started the Culmus project, aiming at providing +Hebrew-speaking Linux and Unix community with a basic collection of +Hebrew fonts for X Windows. The fonts are visually compatible with +URW++ Century Schoolbook L, URW++ Nimbus Sans L and URW++ Nimbus Mono +L families, respectively, and are released under GNU GPL license. See +also . + + Hebrew (U+0590-U+05FF) + + +# Vyacheslav Dikonov + +Vyacheslav Dikonov made a braille unicode font that could be merged +with the UCS fonts to fill the 2800-28FF range completely. (uniform +scaling is possible to adapt it to any cell size). He also contributed +a free syriac font, whose glyphs (about half of them) are borrowed +from the "Carlo Ator" font freely downloadable from +. Vyacheslav also filled in a few missing +spots in the U+2000-U+27FF area, e.g. the box drawing section, sets of +subscript and superscript digits and capital Roman numbers. + + Syriac (U+0700-U+074A) + Box Drawing (U+2500-U+257F) + Braille (U+2800-U+28FF) + + +# M.S. Sridhar + +M/S Cyberscape Multimedia Limited, Mumbai, developers of Akruti +Software for Indian Languages (http://www.akruti.com/), have released +a set of TTF fonts for nine Indian scripts (Devanagari, Gujarati, +Telugu, Tamil, Malayalam, Kannada, Bengali, Oriya, and Gurumukhi) +under the GNU General Public License (GPL). You can download the fonts +from the Free Software Foundation of India WWW site +(http://www.gnu.org.in/software/software.html#akruti) or from the +Akruti website. + +For any further information or assistance regarding these fonts, +please contact mssridhar AT vsnl.com. + + Devanagari (U+0900-U+097F) + Bengali (U+0980-U+09FF) + Gurmukhi (U+0A00-U+0A7F) + Gujarati (U+0A80-U+0AFF) + Oriya (U+0B00-U+0B7F) + Tamil (U+0B80-U+0BFF) + Telugu (U+0C00-U+0C7F) + Kannada (U+0C80-U+0CFF) + Malayalam (U+0D00-U+0D7F) + + +# DMS Electronics, The Sri Lanka Tipitaka Project, and Noah Levitt + + +Noah Levitt found out that the Sinhalese fonts available on the site + are released under GNU GPL, or, +precisely, "Public Domain under GNU Licence + Produced by DMS +Electronics for The Sri Lanka Tipitaka Project" (taken from the font +comment), and took the effort of recoding the font to Unicode. + + Sinhala (U+0D80-U+0DFF) + + +# Daniel Shurovich Chirkov + +Dan Chirkov updated the FreeSerif font with the missing Cyrillic +glyphs needed for conformance to Unicode 3.2. The effort is part of +the Slavjanskij package for Mac OS X, +. + + Cyrillic (U+0400-U+04FF) + + +# Primo Peterlin + +Primo Peterlin filled in missing glyphs here and there (e.g. Latin +Extended-B and IPA Extensions ranges in the FreeMono familiy), and +created the following UCS blocks: + + Latin Extended-B (U+0180-U+024F) + IPA Extensions (U+0250-U+02AF) + Arrows (U+2190-U+21FF) + Box Drawing (U+2500-U+257F) + Block Elements (U+2580-U+259F) + Geometrical Shapes (U+25A0-U+25FF) + + +Notes: + +*: The glyph collection looks license-compatible, but its author has + not yet replied and agreed on his/her work being used in part of + this glyph collection. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2c/2c76b08002398b97784edeca2011d8a77c453847.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2c/2c76b08002398b97784edeca2011d8a77c453847.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

<%=l(:label_news_latest)%>

+ +<%= render(:partial => 'news/news', + :collection => News.find(:all, + :limit => 10, + :order => "#{News.table_name}.created_on DESC", + :conditions => "#{News.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", + :include => [:project, :author])) unless @user.projects.empty? %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2c/2cde7dc8fe86b1b79ab2ee40c054579ef58ee63c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2c/2cde7dc8fe86b1b79ab2ee40c054579ef58ee63c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1015 @@ +# Croatian translations for Ruby on Rails +# by Helix d.o.o. (info@helix.hr) + +hr: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Ponedjeljak, Utorak, Srijeda, Četvrtak, Petak, Subota, Nedjelja] + abbr_day_names: [Ned, Pon, Uto, Sri, Čet, Pet, Sub] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Sijecanj, Veljaca, Ožujak, Travanj, Svibanj, Lipanj, Srpanj, Kolovoz, Rujan, Listopad, Studeni, Prosinac] + abbr_month_names: [~, Sij, Velj, Ožu, Tra, Svi, Lip, Srp, Kol, Ruj, List, Stu, Pro] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pola minute" + less_than_x_seconds: + one: "manje od sekunde" + other: "manje od %{count} sekundi" + x_seconds: + one: "1 sekunda" + other: "%{count} sekundi" + less_than_x_minutes: + one: "manje od minute" + other: "manje od %{count} minuta" + x_minutes: + one: "1 minuta" + other: "%{count} minuta" + about_x_hours: + one: "oko sat vremena" + other: "oko %{count} sati" + x_days: + one: "1 dan" + other: "%{count} dana" + about_x_months: + one: "oko 1 mjesec" + other: "oko %{count} mjeseci" + x_months: + one: "mjesec" + other: "%{count} mjeseci" + about_x_years: + one: "1 godina" + other: "%{count} godina" + over_x_years: + one: "preko 1 godine" + other: "preko %{count} godina" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nije ukljuceno u listu" + exclusion: "je rezervirano" + invalid: "nije ispravno" + confirmation: "ne odgovara za potvrdu" + accepted: "mora biti prihvaćen" + empty: "ne može biti prazno" + blank: "ne može biti razmaka" + too_long: "je predug (maximum is %{count} characters)" + too_short: "je prekratak (minimum is %{count} characters)" + wrong_length: "je pogrešne dužine (should be %{count} characters)" + taken: "već je zauzeto" + not_a_number: "nije broj" + not_a_date: "nije ispravan datum" + greater_than: "mora biti veći od %{count}" + greater_than_or_equal_to: "mora biti veći ili jednak %{count}" + equal_to: "mora biti jednak %{count}" + less_than: "mora biti manji od %{count}" + less_than_or_equal_to: "mora bit manji ili jednak%{count}" + odd: "mora biti neparan" + even: "mora biti paran" + greater_than_start_date: "mora biti veci nego pocetni datum" + not_same_project: "ne pripada istom projektu" + circular_dependency: "Ovaj relacija stvara kružnu ovisnost" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Molimo odaberite + + general_text_No: 'Ne' + general_text_Yes: 'Da' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Hrvatski' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Vaš profil je uspješno promijenjen. + notice_account_invalid_creditentials: Neispravno korisničko ime ili zaporka. + notice_account_password_updated: Zaporka je uspješno promijenjena. + notice_account_wrong_password: Pogrešna zaporka + notice_account_register_done: Racun je uspješno napravljen. Da biste aktivirali svoj račun, kliknite na link koji vam je poslan na e-mail. + notice_account_unknown_email: Nepoznati korisnik. + notice_can_t_change_password: Ovaj račun koristi eksterni izvor prijavljivanja. Nemoguće je promijeniti zaporku. + notice_account_lost_email_sent: E-mail s uputama kako bi odabrali novu zaporku je poslan na na vašu e-mail adresu. + notice_account_activated: Vaš racun je aktiviran. Možete se prijaviti. + notice_successful_create: Uspješno napravljeno. + notice_successful_update: Uspješna promjena. + notice_successful_delete: Uspješno brisanje. + notice_successful_connection: Uspješna veza. + notice_file_not_found: Stranica kojoj ste pokušali pristupiti ne postoji ili je uklonjena. + notice_locking_conflict: Podataci su ažurirani od strane drugog korisnika. + notice_not_authorized: Niste ovlašteni za pristup ovoj stranici. + notice_email_sent: E-mail je poslan %{value}" + notice_email_error: Dogodila se pogreška tijekom slanja E-maila (%{value})" + notice_feeds_access_key_reseted: Vaš RSS pristup je resetovan. + notice_api_access_key_reseted: Vaš API pristup je resetovan. + notice_failed_to_save_issues: "Neuspjelo spremanje %{count} predmeta na %{total} odabrane: %{ids}." + notice_no_issue_selected: "Niti jedan predmet nije odabran! Molim, odaberite predmete koje želite urediti." + notice_account_pending: "Vaš korisnicki račun je otvoren, čeka odobrenje administratora." + notice_default_data_loaded: Konfiguracija je uspješno učitana. + notice_unable_delete_version: Nije moguće izbrisati verziju. + notice_issue_done_ratios_updated: Issue done ratios updated. + + error_can_t_load_default_data: "Zadanu konfiguracija nije učitana: %{value}" + error_scm_not_found: "Unos i/ili revizija nije pronađen." + error_scm_command_failed: "Dogodila se pogreška prilikom pokušaja pristupa: %{value}" + error_scm_annotate: "Ne postoji ili ne može biti obilježen." + error_issue_not_found_in_project: 'Nije pronađen ili ne pripada u ovaj projekt' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version can not be reopened' + error_can_not_archive_project: This project can not be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + + warning_attachments_not_saved: "%{count} Datoteka/e nije mogla biti spremljena." + + mail_subject_lost_password: "Vaša %{value} zaporka" + mail_body_lost_password: 'Kako biste promijenili Vašu zaporku slijedite poveznicu:' + mail_subject_register: "Aktivacija korisničog računa %{value}" + mail_body_register: 'Da biste aktivirali svoj račun, kliknite na sljedeci link:' + mail_body_account_information_external: "Možete koristiti vaš račun %{value} za prijavu." + mail_body_account_information: Vaši korisnički podaci + mail_subject_account_activation_request: "%{value} predmet za aktivaciju korisničkog računa" + mail_body_account_activation_request: "Novi korisnik (%{value}) je registriran. Njegov korisnički račun čeka vaše odobrenje:" + mail_subject_reminder: "%{count} predmet(a) dospijeva sljedećih %{days} dana" + mail_body_reminder: "%{count} vama dodijeljen(ih) predmet(a) dospijeva u sljedećih %{days} dana:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + gui_validation_error: 1 pogreška + gui_validation_error_plural: "%{count} pogrešaka" + + field_name: Ime + field_description: Opis + field_summary: Sažetak + field_is_required: Obavezno + field_firstname: Ime + field_lastname: Prezime + field_mail: E-pošta + field_filename: Datoteka + field_filesize: Veličina + field_downloads: Preuzimanja + field_author: Autor + field_created_on: Napravljen + field_updated_on: Promijenjen + field_field_format: Format + field_is_for_all: Za sve projekte + field_possible_values: Moguće vrijednosti + field_regexp: Regularni izraz + field_min_length: Minimalna dužina + field_max_length: Maksimalna dužina + field_value: Vrijednost + field_category: Kategorija + field_title: Naslov + field_project: Projekt + field_issue: Predmet + field_status: Status + field_notes: Napomene + field_is_closed: Predmet je zatvoren + field_is_default: Zadana vrijednost + field_tracker: Tracker + field_subject: Predmet + field_due_date: Do datuma + field_assigned_to: Dodijeljeno + field_priority: Prioritet + field_fixed_version: Verzija + field_user: Korisnik + field_role: Uloga + field_homepage: Naslovnica + field_is_public: Javni projekt + field_parent: Potprojekt od + field_is_in_chlog: Predmeti se prikazuju u dnevniku promjena + field_is_in_roadmap: Predmeti se prikazuju u Putokazu + field_login: Korisničko ime + field_mail_notification: Obavijest putem e-pošte + field_admin: Administrator + field_last_login_on: Zadnja prijava + field_language: Primarni jezik + field_effective_date: Datum + field_password: Zaporka + field_new_password: Nova zaporka + field_password_confirmation: Potvrda zaporke + field_version: Verzija + field_type: Tip + field_host: Host + field_port: Port + field_account: Racun + field_base_dn: Osnovni DN + field_attr_login: Login atribut + field_attr_firstname: Atribut imena + field_attr_lastname: Atribut prezimena + field_attr_mail: Atribut e-pošte + field_onthefly: "Izrada korisnika \"u hodu\"" + field_start_date: Pocetak + field_done_ratio: "% Učinjeno" + field_auth_source: Vrsta prijavljivanja + field_hide_mail: Sakrij moju adresu e-pošte + field_comments: Komentar + field_url: URL + field_start_page: Početna stranica + field_subproject: Potprojekt + field_hours: Sati + field_activity: Aktivnost + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Korišteno kao filtar + field_issue_to_id: Povezano s predmetom + field_delay: Odgodeno + field_assignable: Predmeti mogu biti dodijeljeni ovoj ulozi + field_redirect_existing_links: Preusmjeravanje postojećih linkova + field_estimated_hours: Procijenjeno vrijeme + field_column_names: Stupci + field_time_zone: Vremenska zona + field_searchable: Pretraživo + field_default_value: Zadana vrijednost + field_comments_sorting: Prikaz komentara + field_parent_title: Parent page + field_editable: Editable + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Content + field_group_by: Group results by + + setting_app_title: Naziv aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Tekst dobrodošlice + setting_default_language: Zadani jezik + setting_login_required: Potrebna je prijava + setting_self_registration: Samoregistracija je dozvoljena + setting_attachment_max_size: Maksimalna veličina privitka + setting_issues_export_limit: Ograničenje izvoza predmeta + setting_mail_from: Izvorna adresa e-pošte + setting_bcc_recipients: Blind carbon copy primatelja (bcc) + setting_plain_text_mail: obični tekst pošte (bez HTML-a) + setting_host_name: Naziv domaćina (host) + setting_text_formatting: Oblikovanje teksta + setting_wiki_compression: Sažimanje + setting_feeds_limit: Ogranicenje unosa sadržaja + setting_default_projects_public: Novi projekti su javni po defaultu + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Omogući WS za upravljanje skladištem + setting_commit_ref_keywords: Referentne ključne riječi + setting_commit_fix_keywords: Fiksne ključne riječi + setting_autologin: Automatska prijava + setting_date_format: Format datuma + setting_time_format: Format vremena + setting_cross_project_issue_relations: Dozvoli povezivanje predmeta izmedu različitih projekata + setting_issue_list_default_columns: Stupci prikazani na listi predmeta + setting_emails_footer: Zaglavlje e-pošte + setting_protocol: Protokol + setting_per_page_options: Objekata po stranici opcija + setting_user_format: Oblik prikaza korisnika + setting_activity_days_default: Dani prikazane aktivnosti na projektu + setting_display_subprojects_issues: Prikaz predmeta potprojekta na glavnom projektu po defaultu + setting_enabled_scm: Omogućen SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Omoguci WS za dolaznu e-poštu + setting_mail_handler_api_key: API ključ + setting_sequential_project_identifiers: Generiraj slijedne identifikatore projekta + setting_gravatar_enabled: Koristi Gravatar korisničke ikone + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Maksimalni broj diff linija za prikazati + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + + permission_add_project: Dodaj projekt + permission_add_subprojects: Dodaj potprojekt + permission_edit_project: Uredi projekt + permission_select_project_modules: Odaberi projektne module + permission_manage_members: Upravljaj članovima + permission_manage_versions: Upravljaj verzijama + permission_manage_categories: Upravljaj kategorijama predmeta + permission_view_issues: Pregledaj zahtjeve + permission_add_issues: Dodaj predmete + permission_edit_issues: Uredi predmete + permission_manage_issue_relations: Upravljaj relacijama predmeta + permission_add_issue_notes: Dodaj bilješke + permission_edit_issue_notes: Uredi bilješke + permission_edit_own_issue_notes: Uredi vlastite bilješke + permission_move_issues: Premjesti predmete + permission_delete_issues: Brisanje predmeta + permission_manage_public_queries: Upravljaj javnim upitima + permission_save_queries: Spremi upite + permission_view_gantt: Pregledaj gantt grafikon + permission_view_calendar: Pregledaj kalendar + permission_view_issue_watchers: Pregledaj listu promatraca + permission_add_issue_watchers: Dodaj promatrača + permission_delete_issue_watchers: Delete watchers + permission_log_time: Dnevnik utrošenog vremena + permission_view_time_entries: Pregledaj utrošeno vrijeme + permission_edit_time_entries: Uredi vremenske dnevnike + permission_edit_own_time_entries: Edit own time logs + permission_manage_news: Upravljaj novostima + permission_comment_news: Komentiraj novosti + permission_manage_documents: Upravljaj dokumentima + permission_view_documents: Pregledaj dokumente + permission_manage_files: Upravljaj datotekama + permission_view_files: Pregledaj datoteke + permission_manage_wiki: Upravljaj wikijem + permission_rename_wiki_pages: Promijeni ime wiki stranicama + permission_delete_wiki_pages: Obriši wiki stranice + permission_view_wiki_pages: Pregledaj wiki + permission_view_wiki_edits: Pregledaj povijest wikija + permission_edit_wiki_pages: Uredi wiki stranice + permission_delete_wiki_pages_attachments: Obriši privitke + permission_protect_wiki_pages: Zaštiti wiki stranice + permission_manage_repository: Upravljaj skladištem + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Mogućnost pohranjivanja + permission_manage_boards: Manage boards + permission_view_messages: Pregledaj poruke + permission_add_messages: Objavi poruke + permission_edit_messages: Uredi poruke + permission_edit_own_messages: Uredi vlastite poruke + permission_delete_messages: Obriši poruke + permission_delete_own_messages: Obriši vlastite poruke + + project_module_issue_tracking: Praćenje predmeta + project_module_time_tracking: Praćenje vremena + project_module_news: Novosti + project_module_documents: Dokumenti + project_module_files: Datoteke + project_module_wiki: Wiki + project_module_repository: Skladište + project_module_boards: Boards + + label_user: Korisnik + label_user_plural: Korisnici + label_user_new: Novi korisnik + label_user_anonymous: Anonymous + label_project: Projekt + label_project_new: Novi projekt + label_project_plural: Projekti + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Svi Projekti + label_project_latest: Najnoviji projekt + label_issue: Predmet + label_issue_new: Novi predmet + label_issue_plural: Predmeti + label_issue_view_all: Pregled svih predmeta + label_issues_by: "Predmeti od %{value}" + label_issue_added: Predmet dodan + label_issue_updated: Predmet promijenjen + label_document: Dokument + label_document_new: Novi dokument + label_document_plural: Dokumenti + label_document_added: Dokument dodan + label_role: Uloga + label_role_plural: Uloge + label_role_new: Nova uloga + label_role_and_permissions: Uloge i ovlasti + label_member: Član + label_member_new: Novi član + label_member_plural: Članovi + label_tracker: Vrsta + label_tracker_plural: Vrste predmeta + label_tracker_new: Nova vrsta + label_workflow: Tijek rada + label_issue_status: Status predmeta + label_issue_status_plural: Status predmeta + label_issue_status_new: Novi status + label_issue_category: Kategorija predmeta + label_issue_category_plural: Kategorije predmeta + label_issue_category_new: Nova kategorija + label_custom_field: Korisnički definirano polje + label_custom_field_plural: Korisnički definirana polja + label_custom_field_new: Novo korisnički definirano polje + label_enumerations: Pobrojenice + label_enumeration_new: Nova vrijednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Molim prijavite se + label_register: Registracija + label_login_with_open_id_option: or login with OpenID + label_password_lost: Izgubljena zaporka + label_home: Početna stranica + label_my_page: Moja stranica + label_my_account: Moj profil + label_my_projects: Moji projekti + label_administration: Administracija + label_login: Korisnik + label_logout: Odjava + label_help: Pomoć + label_reported_issues: Prijavljeni predmeti + label_assigned_to_me_issues: Moji predmeti + label_last_login: Last connection + label_registered_on: Registrirano + label_activity: Aktivnosti + label_overall_activity: Aktivnosti + label_user_activity: "%{value} ova/ina aktivnost" + label_new: Novi + label_logged_as: Prijavljeni ste kao + label_environment: Okolina + label_authentication: Autentikacija + label_auth_source: Način prijavljivanja + label_auth_source_new: Novi način prijavljivanja + label_auth_source_plural: Načini prijavljivanja + label_subproject_plural: Potprojekti + label_subproject_new: Novi potprojekt + label_and_its_subprojects: "%{value} i njegovi potprojekti" + label_min_max_length: Min - Maks veličina + label_list: Liste + label_date: Datum + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Atribut + label_attribute_plural: Atributi + label_download: "%{count} Download" + label_download_plural: "%{count} Downloads" + label_no_data: Nema podataka za prikaz + label_change_status: Promjena statusa + label_history: Povijest + label_attachment: Datoteka + label_attachment_new: Nova datoteka + label_attachment_delete: Brisanje datoteke + label_attachment_plural: Datoteke + label_file_added: Datoteka dodana + label_report: Izvješće + label_report_plural: Izvješća + label_news: Novosti + label_news_new: Dodaj novost + label_news_plural: Novosti + label_news_latest: Novosti + label_news_view_all: Pregled svih novosti + label_news_added: Novosti dodane + label_change_log: Dnevnik promjena + label_settings: Postavke + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_confirmation: Potvrda + label_export_to: 'Izvoz u:' + label_read: Čitaj... + label_public_projects: Javni projekti + label_open_issues: Otvoren + label_open_issues_plural: Otvoreno + label_closed_issues: Zatvoren + label_closed_issues_plural: Zatvoreno + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Ukupno + label_permissions: Dozvole + label_current_status: Trenutni status + label_new_statuses_allowed: Novi status je dozvoljen + label_all: Svi + label_none: nema + label_nobody: nitko + label_next: Naredni + label_previous: Prethodni + label_used_by: Korišten od + label_details: Detalji + label_add_note: Dodaj napomenu + label_per_page: Po stranici + label_calendar: Kalendar + label_months_from: Mjeseci od + label_gantt: Gantt + label_internal: Interno + label_last_changes: "Posljednjih %{count} promjena" + label_change_view_all: Prikaz svih promjena + label_personalize_page: Prilagodite ovu stranicu + label_comment: Komentar + label_comment_plural: Komentari + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Dodaj komentar + label_comment_added: Komentar dodan + label_comment_delete: Brisanje komentara + label_query: Korisnički upit + label_query_plural: Korisnički upiti + label_query_new: Novi upit + label_filter_add: Dodaj filtar + label_filter_plural: Filtri + label_equals: je + label_not_equals: nije + label_in_less_than: za manje od + label_in_more_than: za više od + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: za točno + label_today: danas + label_all_time: sva vremena + label_yesterday: jučer + label_this_week: ovog tjedna + label_last_week: prošlog tjedna + label_last_n_days: "zadnjih %{count} dana" + label_this_month: ovog mjeseca + label_last_month: prošlog mjeseca + label_this_year: ove godine + label_date_range: vremenski raspon + label_less_than_ago: manje od + label_more_than_ago: više od + label_ago: prije + label_contains: Sadrži + label_not_contains: ne sadrži + label_day_plural: dana + label_repository: Skladište + label_repository_plural: Skladišta + label_browse: Pregled + label_modification: "%{count} promjena" + label_modification_plural: "%{count} promjena" + label_branch: Branch + label_tag: Tag + label_revision: Revizija + label_revision_plural: Revizije + label_revision_id: "Revision %{value}" + label_associated_revisions: Dodijeljene revizije + label_added: dodano + label_modified: promijenjen + label_copied: kopirano + label_renamed: preimenovano + label_deleted: obrisano + label_latest_revision: Posljednja revizija + label_latest_revision_plural: Posljednje revizije + label_view_revisions: Pregled revizija + label_view_all_revisions: View all revisions + label_max_size: Maksimalna veličina + label_sort_highest: Premjesti na vrh + label_sort_higher: Premjesti prema gore + label_sort_lower: Premjesti prema dolje + label_sort_lowest: Premjesti na dno + label_roadmap: Putokaz + label_roadmap_due_in: "Završava se za %{value}" + label_roadmap_overdue: "%{value} kasni" + label_roadmap_no_issues: Nema predmeta za ovu verziju + label_search: Traži + label_result_plural: Rezultati + label_all_words: Sve riječi + label_wiki: Wiki + label_wiki_edit: Wiki promjena + label_wiki_edit_plural: Wiki promjene + label_wiki_page: Wiki stranica + label_wiki_page_plural: Wiki stranice + label_index_by_title: Indeks po naslovima + label_index_by_date: Indeks po datumu + label_current_version: Trenutna verzija + label_preview: Brzi pregled + label_feed_plural: Feeds + label_changes_details: Detalji svih promjena + label_issue_tracking: Praćenje predmeta + label_spent_time: Utrošeno vrijeme + label_f_hour: "%{value} sata" + label_f_hour_plural: "%{value} sati" + label_time_tracking: Praćenje vremena + label_change_plural: Promjene + label_statistics: Statistika + label_commits_per_month: Pohrana po mjesecu + label_commits_per_author: Pohrana po autoru + label_view_diff: Pregled razlika + label_diff_inline: uvučeno + label_diff_side_by_side: paralelno + label_options: Opcije + label_copy_workflow_from: Kopiraj tijek rada od + label_permissions_report: Izvješće o dozvolama + label_watched_issues: Praćeni predmeti + label_related_issues: Povezani predmeti + label_applied_status: Primijenjen status + label_loading: Učitavam... + label_relation_new: Nova relacija + label_relation_delete: Brisanje relacije + label_relates_to: u relaciji sa + label_duplicates: Duplira + label_duplicated_by: ponovljen kao + label_blocks: blokira + label_blocked_by: blokiran od strane + label_precedes: prethodi + label_follows: slijedi + label_end_to_start: od kraja do početka + label_end_to_end: od kraja do kraja + label_end_to_start: od kraja do početka + label_end_to_end: od kraja do kraja + label_stay_logged_in: Ostanite prijavljeni + label_disabled: Isključen + label_show_completed_versions: Prikaži završene verzije + label_me: ja + label_board: Forum + label_board_new: Novi forum + label_board_plural: Forumi + label_topic_plural: Teme + label_message_plural: Poruke + label_message_last: Posljednja poruka + label_message_new: Nova poruka + label_message_posted: Poruka dodana + label_reply_plural: Odgovori + label_send_information: Pošalji korisniku informaciju o profilu + label_year: Godina + label_month: Mjesec + label_week: Tjedan + label_date_from: Od + label_date_to: Do + label_language_based: Zasnovano na jeziku + label_sort_by: "Uredi po %{value}" + label_send_test_email: Pošalji testno E-pismo + label_feeds_access_key: RSS access key + label_missing_feeds_access_key: Missing a RSS access key + label_feeds_access_key_created_on: "RSS kljuc za pristup je napravljen prije %{value}" + label_module_plural: Moduli + label_added_time_by: "Promijenio %{author} prije %{age}" + label_updated_time_by: "Dodao/la %{author} prije %{age}" + label_updated_time: "Promijenjeno prije %{value}" + label_jump_to_a_project: Prebaci se na projekt... + label_file_plural: Datoteke + label_changeset_plural: Promjene + label_default_columns: Zadani stupci + label_no_change_option: (Bez promjene) + label_bulk_edit_selected_issues: Zajednička promjena izabranih predmeta + label_theme: Tema + label_default: Zadana + label_search_titles_only: Pretraživanje samo naslova + label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" + label_user_mail_option_selected: "Za bilo koji događaj samo za izabrane projekte..." + label_user_mail_no_self_notified: "Ne želim primati obavijesti o promjenama koje sam napravim" + label_registration_activation_by_email: aktivacija putem e-pošte + label_registration_manual_activation: ručna aktivacija + label_registration_automatic_activation: automatska aktivacija + label_display_per_page: "Po stranici: %{value}" + label_age: Starost + label_change_properties: Promijeni svojstva + label_general: Općenito + label_more: Još + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP autentikacija + label_downloads_abbr: D/L + label_optional_description: Opcije + label_add_another_file: Dodaj još jednu datoteku + label_preferences: Preferences + label_chronological_order: U kronološkom redoslijedu + label_reverse_chronological_order: U obrnutom kronološkom redoslijedu + label_planning: Planiranje + label_incoming_emails: Dolazne poruke e-pošte + label_generate_key: Generiraj ključ + label_issue_watchers: Promatrači + label_example: Primjer + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Grupe + label_group_new: Nova grupa + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + + button_login: Prijavi + button_submit: Pošalji + button_save: Spremi + button_check_all: Označi sve + button_uncheck_all: Isključi sve + button_delete: Obriši + button_create: Napravi + button_create_and_continue: Napravi i nastavi + button_test: Test + button_edit: Uredi + button_add: Dodaj + button_change: Promijeni + button_apply: Primijeni + button_clear: Ukloni + button_lock: Zaključaj + button_unlock: Otključaj + button_download: Preuzmi + button_list: Spisak + button_view: Pregled + button_move: Premjesti + button_move_and_follow: Move and follow + button_back: Nazad + button_cancel: Odustani + button_activate: Aktiviraj + button_sort: Redoslijed + button_log_time: Zapiši vrijeme + button_rollback: Izvrši rollback na ovu verziju + button_watch: Prati + button_unwatch: Prekini pracenje + button_reply: Odgovori + button_archive: Arhiviraj + button_rollback: Dearhiviraj + button_reset: Poništi + button_rename: Promijeni ime + button_change_password: Promjena zaporke + button_copy: Kopiraj + button_copy_and_follow: Copy and follow + button_annotate: Annotate + button_update: Promijeni + button_configure: Konfiguracija + button_quote: Navod + button_duplicate: Duplicate + button_show: Show + + status_active: aktivan + status_registered: Registriran + status_locked: zaključan + + version_status_open: open + version_status_locked: locked + version_status_closed: closed + + field_active: Active + + text_select_mail_notifications: Izbor akcija za koje će biti poslana obavijest e-poštom. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znači bez ograničenja + text_project_destroy_confirmation: Da li ste sigurni da želite izbrisati ovaj projekt i sve njegove podatke? + text_subprojects_destroy_warning: "Njegov(i) potprojekt(i): %{value} će također biti obrisan." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Da li ste sigurni? + text_journal_changed: "%{label} promijenjen iz %{old} u %{new}" + text_journal_set_to: "%{label} postavi na %{value}" + text_journal_deleted: "%{label} izbrisano (%{old})" + text_journal_added: "%{label} %{value} added" + text_tip_issue_begin_day: Zadaci koji počinju ovog dana + text_tip_issue_end_day: zadaci koji se završavaju ovog dana + text_tip_issue_begin_end_day: Zadaci koji počinju i završavaju se ovog dana + text_project_identifier_info: 'mala slova (a-z), brojevi i crtice su dozvoljeni.
Jednom snimljen identifikator se ne može mijenjati!' + text_caracters_maximum: "Najviše %{count} znakova." + text_caracters_minimum: "Mora biti dugačko najmanje %{count} znakova." + text_length_between: "Dužina izmedu %{min} i %{max} znakova." + text_tracker_no_workflow: Tijek rada nije definiran za ovaj tracker + text_unallowed_characters: Nedozvoljeni znakovi + text_comma_separated: Višestruke vrijednosti su dozvoljene (razdvojene zarezom). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_tracker_no_workflow: No workflow defined for this tracker + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Predmet %{id} je prijavljen (prijavio %{author})." + text_issue_updated: "Predmet %{id} je promijenjen %{author})." + text_wiki_destroy_confirmation: Da li ste sigurni da želite izbrisati ovaj wiki i njegov sadržaj? + text_issue_category_destroy_question: "Neke predmeti (%{count}) su dodijeljeni ovoj kategoriji. Što želite uraditi?" + text_issue_category_destroy_assignments: Ukloni dodjeljivanje kategorija + text_issue_category_reassign_to: Ponovo dodijeli predmete ovoj kategoriji + text_user_mail_option: "Za neizabrane projekte, primit ćete obavjesti samo o stvarima koje pratite ili u kojima sudjelujete (npr. predmete koje ste vi napravili ili koje su vama dodjeljeni)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Učitaj početnu konfiguraciju + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Jeste li sigurni da želite obrisati izabrani/e predmet(e)?' + text_select_project_modules: 'Odaberite module koji će biti omogućeni za ovaj projekt:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Dozvoljeno pisanje u direktorij za privitke + text_plugin_assets_writable: Plugin assets directory writable + text_rmagick_available: RMagick dostupan (nije obavezno) + text_destroy_time_entries_question: "%{hours} sati je prijavljeno za predmete koje želite obrisati. Što ćete učiniti?" + text_destroy_time_entries: Obriši prijavljene sate + text_assign_time_entries_to_project: Pridruži prijavljene sate projektu + text_reassign_time_entries: 'Premjesti prijavljene sate ovom predmetu:' + text_user_wrote: "%{value} je napisao/la:" + text_enumeration_destroy_question: "%{count} objekata je pridruženo toj vrijednosti." + text_enumeration_category_reassign_to: 'Premjesti ih ovoj vrijednosti:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... Ovaj diff je odrezan zato što prelazi maksimalnu veličinu koja može biti prikazana.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + default_role_manager: Upravitelj + default_role_developer: Razvojni inženjer + default_role_reporter: Korisnik + default_tracker_bug: Pogreška + default_tracker_feature: Funkcionalnost + default_tracker_support: Podrška + default_issue_status_new: Novo + default_issue_status_assigned: Dodijeljeno + default_issue_status_resolved: Riješeno + default_issue_status_feedback: Povratna informacija + default_issue_status_closed: Zatvoreno + default_issue_status_rejected: Odbaceno + default_doc_category_user: Korisnička dokumentacija + default_doc_category_tech: Tehnička dokumentacija + default_priority_low: Nizak + default_priority_normal: Redovan + default_priority_high: Visok + default_priority_urgent: Hitan + default_priority_immediate: Odmah + default_activity_design: Dizajn + default_activity_development: Razvoj + enumeration_issue_priorities: Prioriteti predmeta + enumeration_doc_categories: Kategorija dokumenata + enumeration_activities: Aktivnosti (po vremenu) + enumeration_system_activity: System Activity + field_sharing: Sharing + text_line_separated: Multiple values allowed (one line for each value). + label_close_versions: Close completed versions + button_unarchive: Unarchive + label_start_to_end: start to end + label_start_to_start: start to start + field_issue_to: Related issue + default_issue_status_in_progress: In Progress + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2d/2d28f189b2d97988268fc59540fff3ecfe6121d1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2d/2d28f189b2d97988268fc59540fff3ecfe6121d1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +== Gravatar Plugin + +This plugin provides a handful of view helpers for displaying gravatars +(globally-recognized avatars). + +Gravatars allow users to configure an avatar to go with their email address at +a central location: http://gravatar.com. Gravatar-aware websites (such +as yours) can then look up and display each user's preferred avatar, without +having to handle avatar management. The user gets the benefit of not having to +set up an avatar for each site that they post on. + +== Installation + + cd ~/myapp + ruby script/plugin install git://github.com/woods/gravatar-plugin.git + +or, if you're using piston[http://piston.rubyforge.org] (worth it!): + + cd ~/myapp/vendor/plugins + piston import git://github.com/woods/gravatar-plugin.git + +== Example + +If you represent your users with a model that has an +email+ method (typical +for most rails authentication setups), then you can simply use this method +in your views: + + <%= gravatar_for @user %> + +This will be replaced with the full HTML +img+ tag necessary for displaying +that user's gravatar. + +Other helpers are documented under GravatarHelper::PublicMethods. + +== Acknowledgments + +Thanks to Magnus Bergmark (http://github.com/Mange), who contributed the SSL +support in this plugin, as well as a few minor fixes. + +The following people have also written gravatar-related Ruby libraries: +* Seth Rasmussen created the gravatar gem[http://gravatar.rubyforge.org] +* Matt McCray has also created a gravatar + plugin[http://mattmccray.com/svn/rails/plugins/gravatar_helper] + +== Author + + Scott A. Woods + West Arete Computing, Inc. + http://westarete.com + scott at westarete dot com + +== TODO + +* Add specs for ssl support +* Finish rdoc documentation \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2d/2d2fc73f05e5360a853859d4a6d6261e16112400.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2d/2d2fc73f05e5360a853859d4a6d6261e16112400.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +
+<%= link_to l(:label_profile), user_path(@user), :class => 'icon icon-user' %> +<%= change_status_link(@user) %> +<%= link_to(l(:button_delete), @user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current != @user %> +
+ +

<%= link_to l(:label_user_plural), users_path %> » <%=h @user.login %>

+ +<%= render_tabs user_settings_tabs %> + +<% html_title(l(:label_user), @user.login, l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2d/2d84dac3d9e6ebc1cf62421fe475b32d70661abb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2d/2d84dac3d9e6ebc1cf62421fe475b32d70661abb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,151 @@ +require File.dirname(__FILE__) + '/test_helper' +require File.dirname(__FILE__) + '/../lib/open_id_authentication/mem_cache_store' + +# Mock MemCacheStore with MemoryStore for testing +class OpenIdAuthentication::MemCacheStore < OpenID::Store::Interface + def initialize(*addresses) + @connection = ActiveSupport::Cache::MemoryStore.new + end +end + +class MemCacheStoreTest < Test::Unit::TestCase + ALLOWED_HANDLE = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' + + def setup + @store = OpenIdAuthentication::MemCacheStore.new + end + + def test_store + server_url = "http://www.myopenid.com/openid" + assoc = gen_assoc(0) + + # Make sure that a missing association returns no result + assert_retrieve(server_url) + + # Check that after storage, getting returns the same result + @store.store_association(server_url, assoc) + assert_retrieve(server_url, nil, assoc) + + # more than once + assert_retrieve(server_url, nil, assoc) + + # Storing more than once has no ill effect + @store.store_association(server_url, assoc) + assert_retrieve(server_url, nil, assoc) + + # Removing an association that does not exist returns not present + assert_remove(server_url, assoc.handle + 'x', false) + + # Removing an association that does not exist returns not present + assert_remove(server_url + 'x', assoc.handle, false) + + # Removing an association that is present returns present + assert_remove(server_url, assoc.handle, true) + + # but not present on subsequent calls + assert_remove(server_url, assoc.handle, false) + + # Put assoc back in the store + @store.store_association(server_url, assoc) + + # More recent and expires after assoc + assoc2 = gen_assoc(1) + @store.store_association(server_url, assoc2) + + # After storing an association with a different handle, but the + # same server_url, the handle with the later expiration is returned. + assert_retrieve(server_url, nil, assoc2) + + # We can still retrieve the older association + assert_retrieve(server_url, assoc.handle, assoc) + + # Plus we can retrieve the association with the later expiration + # explicitly + assert_retrieve(server_url, assoc2.handle, assoc2) + + # More recent, and expires earlier than assoc2 or assoc. Make sure + # that we're picking the one with the latest issued date and not + # taking into account the expiration. + assoc3 = gen_assoc(2, 100) + @store.store_association(server_url, assoc3) + + assert_retrieve(server_url, nil, assoc3) + assert_retrieve(server_url, assoc.handle, assoc) + assert_retrieve(server_url, assoc2.handle, assoc2) + assert_retrieve(server_url, assoc3.handle, assoc3) + + assert_remove(server_url, assoc2.handle, true) + + assert_retrieve(server_url, nil, assoc3) + assert_retrieve(server_url, assoc.handle, assoc) + assert_retrieve(server_url, assoc2.handle, nil) + assert_retrieve(server_url, assoc3.handle, assoc3) + + assert_remove(server_url, assoc2.handle, false) + assert_remove(server_url, assoc3.handle, true) + + assert_retrieve(server_url, nil, assoc) + assert_retrieve(server_url, assoc.handle, assoc) + assert_retrieve(server_url, assoc2.handle, nil) + assert_retrieve(server_url, assoc3.handle, nil) + + assert_remove(server_url, assoc2.handle, false) + assert_remove(server_url, assoc.handle, true) + assert_remove(server_url, assoc3.handle, false) + + assert_retrieve(server_url, nil, nil) + assert_retrieve(server_url, assoc.handle, nil) + assert_retrieve(server_url, assoc2.handle, nil) + assert_retrieve(server_url, assoc3.handle, nil) + + assert_remove(server_url, assoc2.handle, false) + assert_remove(server_url, assoc.handle, false) + assert_remove(server_url, assoc3.handle, false) + end + + def test_nonce + server_url = "http://www.myopenid.com/openid" + + [server_url, ''].each do |url| + nonce1 = OpenID::Nonce::mk_nonce + + assert_nonce(nonce1, true, url, "#{url}: nonce allowed by default") + assert_nonce(nonce1, false, url, "#{url}: nonce not allowed twice") + assert_nonce(nonce1, false, url, "#{url}: nonce not allowed third time") + + # old nonces shouldn't pass + old_nonce = OpenID::Nonce::mk_nonce(3600) + assert_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed") + end + end + + private + def gen_assoc(issued, lifetime = 600) + secret = OpenID::CryptUtil.random_string(20, nil) + handle = OpenID::CryptUtil.random_string(128, ALLOWED_HANDLE) + OpenID::Association.new(handle, secret, Time.now + issued, lifetime, 'HMAC-SHA1') + end + + def assert_retrieve(url, handle = nil, expected = nil) + assoc = @store.get_association(url, handle) + + if expected.nil? + assert_nil(assoc) + else + assert_equal(expected, assoc) + assert_equal(expected.handle, assoc.handle) + assert_equal(expected.secret, assoc.secret) + end + end + + def assert_remove(url, handle, expected) + present = @store.remove_association(url, handle) + assert_equal(expected, present) + end + + def assert_nonce(nonce, expected, server_url, msg = "") + stamp, salt = OpenID::Nonce::split_nonce(nonce) + actual = @store.use_nonce(server_url, stamp, salt) + assert_equal(expected, actual, msg) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2d/2db04b530ec92664ffacb3542bcb86aa7e548ae5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2d/2db04b530ec92664ffacb3542bcb86aa7e548ae5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +This folder contains fonts descriptions for TCPDF. +Please read the documentation on subfolders for copyright, license and other information. \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2d/2de3a87e3fe026c2ba56948a00c54c7c54909e85.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2d/2de3a87e3fe026c2ba56948a00c54c7c54909e85.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,417 @@ +/* redMine - project management software + Copyright (C) 2006-2008 Jean-Philippe Lang */ + +function checkAll (id, checked) { + var els = Element.descendants(id); + for (var i = 0; i < els.length; i++) { + if (els[i].disabled==false) { + els[i].checked = checked; + } + } +} + +function toggleCheckboxesBySelector(selector) { + boxes = $$(selector); + var all_checked = true; + for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } } + for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; } +} + +function setCheckboxesBySelector(checked, selector) { + var boxes = $$(selector); + boxes.each(function(ele) { + ele.checked = checked; + }); +} + +function showAndScrollTo(id, focus) { + Element.show(id); + if (focus!=null) { Form.Element.focus(focus); } + Element.scrollTo(id); +} + +function toggleRowGroup(el) { + var tr = Element.up(el, 'tr'); + var n = Element.next(tr); + tr.toggleClassName('open'); + while (n != undefined && !n.hasClassName('group')) { + Element.toggle(n); + n = Element.next(n); + } +} + +function collapseAllRowGroups(el) { + var tbody = Element.up(el, 'tbody'); + tbody.childElements('tr').each(function(tr) { + if (tr.hasClassName('group')) { + tr.removeClassName('open'); + } else { + tr.hide(); + } + }) +} + +function expandAllRowGroups(el) { + var tbody = Element.up(el, 'tbody'); + tbody.childElements('tr').each(function(tr) { + if (tr.hasClassName('group')) { + tr.addClassName('open'); + } else { + tr.show(); + } + }) +} + +function toggleAllRowGroups(el) { + var tr = Element.up(el, 'tr'); + if (tr.hasClassName('open')) { + collapseAllRowGroups(el); + } else { + expandAllRowGroups(el); + } +} + +function toggleFieldset(el) { + var fieldset = Element.up(el, 'fieldset'); + fieldset.toggleClassName('collapsed'); + Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2}); +} + +function hideFieldset(el) { + var fieldset = Element.up(el, 'fieldset'); + fieldset.toggleClassName('collapsed'); + fieldset.down('div').hide(); +} + +var fileFieldCount = 1; + +function addFileField() { + var fields = $('attachments_fields'); + if (fields.childElements().length >= 10) return false; + fileFieldCount++; + var s = new Element('span'); + s.update(fields.down('span').innerHTML); + s.down('input.file').name = "attachments[" + fileFieldCount + "][file]"; + s.down('input.description').name = "attachments[" + fileFieldCount + "][description]"; + fields.appendChild(s); +} + +function removeFileField(el) { + var fields = $('attachments_fields'); + var s = Element.up(el, 'span'); + if (fields.childElements().length > 1) { + s.remove(); + } else { + s.update(s.innerHTML); + } +} + +function checkFileSize(el, maxSize, message) { + var files = el.files; + if (files) { + for (var i=0; i maxSize) { + alert(message); + el.value = ""; + } + } + } +} + +function showTab(name) { + var f = $$('div#content .tab-content'); + for(var i=0; i0) { + lis[i-1].show(); + } +} + +function displayTabsButtons() { + var lis; + var tabsWidth = 0; + var i; + $$('div.tabs').each(function(el) { + lis = el.down('ul').childElements(); + for (i=0; i 0) { + Element.show('ajax-indicator'); + } + }, + onComplete: function(){ + if ($('ajax-indicator') && Ajax.activeRequestCount == 0) { + Element.hide('ajax-indicator'); + } + } +}); + +function hideOnLoad() { + $$('.hol').each(function(el) { + el.hide(); + }); +} + +Event.observe(window, 'load', hideOnLoad); diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2e/2e890aa88f7d83a47f036e36ee54bac43bb88fbe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2e/2e890aa88f7d83a47f036e36ee54bac43bb88fbe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +require 'rubygems' +require 'erb' # to get "h" +require 'active_support' # to get "returning" +require File.dirname(__FILE__) + '/../lib/gravatar' +include GravatarHelper, GravatarHelper::PublicMethods, ERB::Util + +describe "gravatar_url with a custom default URL" do + before(:each) do + @original_options = DEFAULT_OPTIONS.dup + DEFAULT_OPTIONS[:default] = "no_avatar.png" + @url = gravatar_url("somewhere") + end + + it "should include the \"default\" argument in the result" do + @url.should match(/&default=no_avatar.png/) + end + + after(:each) do + DEFAULT_OPTIONS.merge!(@original_options) + end + +end + +describe "gravatar_url with default settings" do + before(:each) do + @url = gravatar_url("somewhere") + end + + it "should have a nil default URL" do + DEFAULT_OPTIONS[:default].should be_nil + end + + it "should not include the \"default\" argument in the result" do + @url.should_not match(/&default=/) + end + +end + +describe "gravatar with a custom title option" do + it "should include the title in the result" do + gravatar('example@example.com', :title => "This is a title attribute").should match(/This is a title attribute/) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2e/2e8ab6ca66bc443398d2c03adedc96c9efd22353.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2e/2e8ab6ca66bc443398d2c03adedc96c9efd22353.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +ActiveRecord::Base.send :include, ActiveRecord::Acts::Tree diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2e/2ea5f89e9cdf7dee90bc2e9a8ae8722e0e008c22.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2e/2ea5f89e9cdf7dee90bc2e9a8ae8722e0e008c22.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +

<%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %>

+<%=h @message.author %> + +<%= textilizable(@message, :content, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2e/2ead4b542c1572a98594cc0fea49800d47b2ab6d.svn-base Binary file .svn/pristine/2e/2ead4b542c1572a98594cc0fea49800d47b2ab6d.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2e/2ebda56f87fd64effd7b76a628d13941e238c219.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2e/2ebda56f87fd64effd7b76a628d13941e238c219.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToUsers < ActiveRecord::Migration + def self.up + add_index :users, [:id, :type] + add_index :users, :auth_source_id + end + + def self.down + remove_index :users, :column => [:id, :type] + remove_index :users, :auth_source_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2e/2ee21f20a298f9183bcf6da4115281a958daccfb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2e/2ee21f20a298f9183bcf6da4115281a958daccfb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

<%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=h @issue_status %>

+ +<% form_for @issue_status, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2f/2f1f6f8262e47819e2d086a5c6cc0817e0e7d2b5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2f/2f1f6f8262e47819e2d086a5c6cc0817e0e7d2b5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,526 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'uri' +require 'cgi' + +class Unauthorized < Exception; end + +class ApplicationController < ActionController::Base + include Redmine::I18n + + layout 'base' + exempt_from_layout 'builder', 'rsb' + + protect_from_forgery + def handle_unverified_request + super + cookies.delete(:autologin) + end + # Remove broken cookie after upgrade from 0.8.x (#4292) + # See https://rails.lighthouseapp.com/projects/8994/tickets/3360 + # TODO: remove it when Rails is fixed + before_filter :delete_broken_cookies + def delete_broken_cookies + if cookies['_redmine_session'] && cookies['_redmine_session'] !~ /--/ + cookies.delete '_redmine_session' + redirect_to home_path + return false + end + end + + before_filter :user_setup, :check_if_login_required, :set_localization + filter_parameter_logging :password + + rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token + rescue_from ::Unauthorized, :with => :deny_access + + include Redmine::Search::Controller + include Redmine::MenuManager::MenuController + helper Redmine::MenuManager::MenuHelper + + Redmine::Scm::Base.all.each do |scm| + require_dependency "repository/#{scm.underscore}" + end + + def user_setup + # Check the settings cache for each request + Setting.check_cache + # Find the current user + User.current = find_current_user + end + + # Returns the current user or nil if no user is logged in + # and starts a session if needed + def find_current_user + if session[:user_id] + # existing session + (User.active.find(session[:user_id]) rescue nil) + elsif cookies[:autologin] && Setting.autologin? + # auto-login feature starts a new session + user = User.try_to_autologin(cookies[:autologin]) + session[:user_id] = user.id if user + user + elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? + # RSS key authentication does not start a session + User.find_by_rss_key(params[:key]) + elsif Setting.rest_api_enabled? && accept_api_auth? + if (key = api_key_from_request) + # Use API key + User.find_by_api_key(key) + else + # HTTP Basic, either username/password or API key/random + authenticate_with_http_basic do |username, password| + User.try_to_login(username, password) || User.find_by_api_key(username) + end + end + end + end + + # Sets the logged in user + def logged_user=(user) + reset_session + if user && user.is_a?(User) + User.current = user + session[:user_id] = user.id + else + User.current = User.anonymous + end + end + + # check if login is globally required to access the application + def check_if_login_required + # no check needed if user is already logged in + return true if User.current.logged? + require_login if Setting.login_required? + end + + def set_localization + lang = nil + if User.current.logged? + lang = find_language(User.current.language) + end + if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE'] + accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first + if !accept_lang.blank? + accept_lang = accept_lang.downcase + lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) + end + end + lang ||= Setting.default_language + set_language_if_valid(lang) + end + + def require_login + if !User.current.logged? + # Extract only the basic url parameters on non-GET requests + if request.get? + url = url_for(params) + else + url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id]) + end + respond_to do |format| + format.html { redirect_to :controller => "account", :action => "login", :back_url => url } + format.atom { redirect_to :controller => "account", :action => "login", :back_url => url } + format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } + format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } + format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } + end + return false + end + true + end + + def require_admin + return unless require_login + if !User.current.admin? + render_403 + return false + end + true + end + + def deny_access + User.current.logged? ? render_403 : require_login + end + + # Authorize the user for the requested action + def authorize(ctrl = params[:controller], action = params[:action], global = false) + allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project || @projects, :global => global) + if allowed + true + else + if @project && @project.archived? + render_403 :message => :notice_not_authorized_archived_project + else + deny_access + end + end + end + + # Authorize the user for the requested action outside a project + def authorize_global(ctrl = params[:controller], action = params[:action], global = true) + authorize(ctrl, action, global) + end + + # Find project of id params[:id] + def find_project + @project = Project.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Find project of id params[:project_id] + def find_project_by_project_id + @project = Project.find(params[:project_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Find a project based on params[:project_id] + # TODO: some subclasses override this, see about merging their logic + def find_optional_project + @project = Project.find(params[:project_id]) unless params[:project_id].blank? + allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) + allowed ? true : deny_access + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Finds and sets @project based on @object.project + def find_project_from_association + render_404 unless @object.present? + + @project = @object.project + end + + def find_model_object + model = self.class.read_inheritable_attribute('model_object') + if model + @object = model.find(params[:id]) + self.instance_variable_set('@' + controller_name.singularize, @object) if @object + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def self.model_object(model) + write_inheritable_attribute('model_object', model) + end + + # Filter for bulk issue operations + def find_issues + @issues = Issue.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @issues.empty? + if @issues.detect {|issue| !issue.visible?} + deny_access + return + end + @projects = @issues.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Check if project is unique before bulk operations + def check_project_uniqueness + unless @project + # TODO: let users bulk edit/move/destroy issues from different projects + render_error 'Can not bulk edit/move/destroy issues from different projects' + return false + end + end + + # make sure that the user is a member of the project (or admin) if project is private + # used as a before_filter for actions that do not require any particular permission on the project + def check_project_privacy + if @project && @project.active? + if @project.is_public? || User.current.member_of?(@project) || User.current.admin? + true + else + deny_access + end + else + @project = nil + render_404 + false + end + end + + def back_url + params[:back_url] || request.env['HTTP_REFERER'] + end + + def redirect_back_or_default(default) + back_url = CGI.unescape(params[:back_url].to_s) + if !back_url.blank? + begin + uri = URI.parse(back_url) + # do not redirect user to another host or to the login or register page + if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)}) + redirect_to(back_url) + return + end + rescue URI::InvalidURIError + # redirect to default + end + end + redirect_to default + false + end + + def render_403(options={}) + @project = nil + render_error({:message => :notice_not_authorized, :status => 403}.merge(options)) + return false + end + + def render_404(options={}) + render_error({:message => :notice_file_not_found, :status => 404}.merge(options)) + return false + end + + # Renders an error response + def render_error(arg) + arg = {:message => arg} unless arg.is_a?(Hash) + + @message = arg[:message] + @message = l(@message) if @message.is_a?(Symbol) + @status = arg[:status] || 500 + + respond_to do |format| + format.html { + render :template => 'common/error', :layout => use_layout, :status => @status + } + format.atom { head @status } + format.xml { head @status } + format.js { head @status } + format.json { head @status } + end + end + + # Filter for actions that provide an API response + # but have no HTML representation for non admin users + def require_admin_or_api_request + return true if api_request? + if User.current.admin? + true + elsif User.current.logged? + render_error(:status => 406) + else + deny_access + end + end + + # Picks which layout to use based on the request + # + # @return [boolean, string] name of the layout to use or false for no layout + def use_layout + request.xhr? ? false : 'base' + end + + def invalid_authenticity_token + if api_request? + logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)." + end + render_error "Invalid form authenticity token." + end + + def render_feed(items, options={}) + @items = items || [] + @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } + @items = @items.slice(0, Setting.feeds_limit.to_i) + @title = options[:title] || Setting.app_title + render :template => "common/feed.atom", :layout => false, + :content_type => 'application/atom+xml' + end + + # TODO: remove in Redmine 1.4 + def self.accept_key_auth(*actions) + ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead." + accept_rss_auth(*actions) + end + + # TODO: remove in Redmine 1.4 + def accept_key_auth_actions + ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth_actions is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead." + self.class.accept_rss_auth + end + + def self.accept_rss_auth(*actions) + if actions.any? + write_inheritable_attribute('accept_rss_auth_actions', actions) + else + read_inheritable_attribute('accept_rss_auth_actions') || [] + end + end + + def accept_rss_auth?(action=action_name) + self.class.accept_rss_auth.include?(action.to_sym) + end + + def self.accept_api_auth(*actions) + if actions.any? + write_inheritable_attribute('accept_api_auth_actions', actions) + else + read_inheritable_attribute('accept_api_auth_actions') || [] + end + end + + def accept_api_auth?(action=action_name) + self.class.accept_api_auth.include?(action.to_sym) + end + + # Returns the number of objects that should be displayed + # on the paginated list + def per_page_option + per_page = nil + if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i) + per_page = params[:per_page].to_s.to_i + session[:per_page] = per_page + elsif session[:per_page] + per_page = session[:per_page] + else + per_page = Setting.per_page_options_array.first || 25 + end + per_page + end + + # Returns offset and limit used to retrieve objects + # for an API response based on offset, limit and page parameters + def api_offset_and_limit(options=params) + if options[:offset].present? + offset = options[:offset].to_i + if offset < 0 + offset = 0 + end + end + limit = options[:limit].to_i + if limit < 1 + limit = 25 + elsif limit > 100 + limit = 100 + end + if offset.nil? && options[:page].present? + offset = (options[:page].to_i - 1) * limit + offset = 0 if offset < 0 + end + offset ||= 0 + + [offset, limit] + end + + # qvalues http header parser + # code taken from webrick + def parse_qvalues(value) + tmp = [] + if value + parts = value.split(/,\s*/) + parts.each {|part| + if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) + val = m[1] + q = (m[2] or 1).to_f + tmp.push([val, q]) + end + } + tmp = tmp.sort_by{|val, q| -q} + tmp.collect!{|val, q| val} + end + return tmp + rescue + nil + end + + # Returns a string that can be used as filename value in Content-Disposition header + def filename_for_content_disposition(name) + request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name + end + + def api_request? + %w(xml json).include? params[:format] + end + + # Returns the API key present in the request + def api_key_from_request + if params[:key].present? + params[:key] + elsif request.headers["X-Redmine-API-Key"].present? + request.headers["X-Redmine-API-Key"] + end + end + + # Renders a warning flash if obj has unsaved attachments + def render_attachment_warning_if_needed(obj) + flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present? + end + + # Sets the `flash` notice or error based the number of issues that did not save + # + # @param [Array, Issue] issues all of the saved and unsaved Issues + # @param [Array, Integer] unsaved_issue_ids the issue ids that were not saved + def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) + if unsaved_issue_ids.empty? + flash[:notice] = l(:notice_successful_update) unless issues.empty? + else + flash[:error] = l(:notice_failed_to_save_issues, + :count => unsaved_issue_ids.size, + :total => issues.size, + :ids => '#' + unsaved_issue_ids.join(', #')) + end + end + + # Rescues an invalid query statement. Just in case... + def query_statement_invalid(exception) + logger.error "Query::StatementInvalid: #{exception.message}" if logger + session.delete(:query) + sort_clear if respond_to?(:sort_clear) + render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." + end + + # Renders API response on validation failure + def render_validation_errors(object) + options = { :status => :unprocessable_entity, :layout => false } + options.merge!(case params[:format] + when 'xml'; { :xml => object.errors } + when 'json'; { :json => {'errors' => object.errors} } # ActiveResource client compliance + else + raise "Unknown format #{params[:format]} in #render_validation_errors" + end + ) + render options + end + + # Overrides #default_template so that the api template + # is used automatically if it exists + def default_template(action_name = self.action_name) + if api_request? + begin + return self.view_paths.find_template(default_template_name(action_name), 'api') + rescue ::ActionView::MissingTemplate + # the api template was not found + # fallback to the default behaviour + end + end + super + end + + # Overrides #pick_layout so that #render with no arguments + # doesn't use the layout for api requests + def pick_layout(*args) + api_request? ? nil : super + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2f/2f2c80ebd6e33d1fd4e81ae48e2384cbacf46e18.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2f/2f2c80ebd6e33d1fd4e81ae48e2384cbacf46e18.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class MessageObserver < ActiveRecord::Observer + def after_create(message) + Mailer.deliver_message_posted(message) if Setting.notified_events.include?('message_posted') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2f/2f3ef4ed7d4fcc37d2d5c06ce61c1093cb75fa73.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2f/2f3ef4ed7d4fcc37d2d5c06ce61c1093cb75fa73.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +class AlphaPluginController < ApplicationController + def an_action + render_class_and_action + end + def action_with_layout + render_class_and_action(nil, :layout => "plugin_layout") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2f/2fb2c04645c15a567f773c73750f1da4ba45dfba.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2f/2fb2c04645c15a567f773c73750f1da4ba45dfba.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,73 @@ +require 'digest/sha1' +require 'openid/store/interface' + +module OpenIdAuthentication + class MemCacheStore < OpenID::Store::Interface + def initialize(*addresses) + @connection = ActiveSupport::Cache::MemCacheStore.new(addresses) + end + + def store_association(server_url, assoc) + server_key = association_server_key(server_url) + assoc_key = association_key(server_url, assoc.handle) + + assocs = @connection.read(server_key) || {} + assocs[assoc.issued] = assoc_key + + @connection.write(server_key, assocs) + @connection.write(assoc_key, assoc, :expires_in => assoc.lifetime) + end + + def get_association(server_url, handle = nil) + if handle + @connection.read(association_key(server_url, handle)) + else + server_key = association_server_key(server_url) + assocs = @connection.read(server_key) + return if assocs.nil? + + last_key = assocs[assocs.keys.sort.last] + @connection.read(last_key) + end + end + + def remove_association(server_url, handle) + server_key = association_server_key(server_url) + assoc_key = association_key(server_url, handle) + assocs = @connection.read(server_key) + + return false unless assocs && assocs.has_value?(assoc_key) + + assocs = assocs.delete_if { |key, value| value == assoc_key } + + @connection.write(server_key, assocs) + @connection.delete(assoc_key) + + return true + end + + def use_nonce(server_url, timestamp, salt) + return false if @connection.read(nonce_key(server_url, salt)) + return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew + @connection.write(nonce_key(server_url, salt), timestamp, :expires_in => OpenID::Nonce.skew) + return true + end + + private + def association_key(server_url, handle = nil) + "openid_association_#{digest(server_url)}_#{digest(handle)}" + end + + def association_server_key(server_url) + "openid_association_server_#{digest(server_url)}" + end + + def nonce_key(server_url, salt) + "openid_nonce_#{digest(server_url)}_#{digest(salt)}" + end + + def digest(text) + Digest::SHA1.hexdigest(text) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/2f/2fe567e0745f50a0d8fa9b273c1a7d7bbb179c82.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/2f/2fe567e0745f50a0d8fa9b273c1a7d7bbb179c82.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,49 @@ +--- +member_roles_001: + id: 1 + role_id: 1 + member_id: 1 +member_roles_002: + id: 2 + role_id: 2 + member_id: 2 +member_roles_003: + id: 3 + role_id: 2 + member_id: 3 +member_roles_004: + id: 4 + role_id: 2 + member_id: 4 +member_roles_005: + id: 5 + role_id: 1 + member_id: 5 +member_roles_006: + id: 6 + role_id: 1 + member_id: 6 +member_roles_007: + id: 7 + role_id: 2 + member_id: 6 +member_roles_008: + id: 8 + role_id: 1 + member_id: 7 + inherited_from: 6 +member_roles_009: + id: 9 + role_id: 2 + member_id: 7 + inherited_from: 7 +member_roles_010: + id: 10 + role_id: 2 + member_id: 9 + inherited_from: +member_roles_011: + id: 11 + role_id: 2 + member_id: 10 + inherited_from: 10 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/3036fc94071bb177c6353a8d978f203a9d1289c5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/30/3036fc94071bb177c6353a8d978f203a9d1289c5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +welcome: + id: 1 + title: Welcome to the weblog + body: Such a lovely day + version: 24 + author_id: 1 + revisor_id: 1 \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/304b68e7e7a6cf907c51306f2e95b29f2a8946e9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/30/304b68e7e7a6cf907c51306f2e95b29f2a8946e9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class RepositoryTest < ActiveSupport::TestCase + fixtures :projects, + :trackers, + :projects_trackers, + :enabled_modules, + :repositories, + :issues, + :issue_statuses, + :issue_categories, + :changesets, + :changes, + :users, + :members, + :member_roles, + :roles, + :enumerations + + def setup + @repository = Project.find(1).repository + end + + def test_create + repository = Repository::Subversion.new(:project => Project.find(3)) + assert !repository.save + + repository.url = "svn://localhost" + assert repository.save + repository.reload + + project = Project.find(3) + assert_equal repository, project.repository + end + + def test_destroy + changesets = Changeset.count(:all, :conditions => "repository_id = 10") + changes = Change.count(:all, :conditions => "repository_id = 10", + :include => :changeset) + assert_difference 'Changeset.count', -changesets do + assert_difference 'Change.count', -changes do + Repository.find(10).destroy + end + end + end + + def test_should_not_create_with_disabled_scm + # disable Subversion + with_settings :enabled_scm => ['Darcs', 'Git'] do + repository = Repository::Subversion.new( + :project => Project.find(3), :url => "svn://localhost") + assert !repository.save + assert_equal I18n.translate('activerecord.errors.messages.invalid'), + repository.errors.on(:type) + end + end + + def test_scan_changesets_for_issue_ids + Setting.default_language = 'en' + Setting.notified_events = ['issue_added','issue_updated'] + + # choosing a status to apply to fix issues + Setting.commit_fix_status_id = IssueStatus.find( + :first, + :conditions => ["is_closed = ?", true]).id + Setting.commit_fix_done_ratio = "90" + Setting.commit_ref_keywords = 'refs , references, IssueID' + Setting.commit_fix_keywords = 'fixes , closes' + Setting.default_language = 'en' + ActionMailer::Base.deliveries.clear + + # make sure issue 1 is not already closed + fixed_issue = Issue.find(1) + assert !fixed_issue.status.is_closed? + old_status = fixed_issue.status + + Repository.scan_changesets_for_issue_ids + assert_equal [101, 102], Issue.find(3).changeset_ids + + # fixed issues + fixed_issue.reload + assert fixed_issue.status.is_closed? + assert_equal 90, fixed_issue.done_ratio + assert_equal [101], fixed_issue.changeset_ids + + # issue change + journal = fixed_issue.journals.find(:first, :order => 'created_on desc') + assert_equal User.find_by_login('dlopper'), journal.user + assert_equal 'Applied in changeset r2.', journal.notes + + # 2 email notifications + assert_equal 2, ActionMailer::Base.deliveries.size + mail = ActionMailer::Base.deliveries.first + assert_kind_of TMail::Mail, mail + assert mail.subject.starts_with?( + "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]") + assert mail.body.include?( + "Status changed from #{old_status} to #{fixed_issue.status}") + + # ignoring commits referencing an issue of another project + assert_equal [], Issue.find(4).changesets + end + + def test_for_changeset_comments_strip + repository = Repository::Mercurial.create( + :project => Project.find( 4 ), + :url => '/foo/bar/baz' ) + comment = <<-COMMENT + This is a loooooooooooooooooooooooooooong comment + + + COMMENT + changeset = Changeset.new( + :comments => comment, :commit_date => Time.now, + :revision => 0, :scmid => 'f39b7922fb3c', + :committer => 'foo ', + :committed_on => Time.now, :repository => repository ) + assert( changeset.save ) + assert_not_equal( comment, changeset.comments ) + assert_equal( 'This is a loooooooooooooooooooooooooooong comment', + changeset.comments ) + end + + def test_for_urls_strip_cvs + repository = Repository::Cvs.create( + :project => Project.find(4), + :url => ' :pserver:login:password@host:/path/to/the/repository', + :root_url => 'foo ', + :log_encoding => 'UTF-8') + assert repository.save + repository.reload + assert_equal ':pserver:login:password@host:/path/to/the/repository', + repository.url + assert_equal 'foo', repository.root_url + end + + def test_for_urls_strip_subversion + repository = Repository::Subversion.create( + :project => Project.find(4), + :url => ' file:///dummy ') + assert repository.save + repository.reload + assert_equal 'file:///dummy', repository.url + end + + def test_for_urls_strip_git + repository = Repository::Git.create( + :project => Project.find(4), + :url => ' c:\dummy ') + assert repository.save + repository.reload + assert_equal 'c:\dummy', repository.url + end + + def test_manual_user_mapping + assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do + c = Changeset.create!( + :repository => @repository, + :committer => 'foo', + :committed_on => Time.now, + :revision => 100, + :comments => 'Committed by foo.' + ) + assert_nil c.user + @repository.committer_ids = {'foo' => '2'} + assert_equal User.find(2), c.reload.user + # committer is now mapped + c = Changeset.create!( + :repository => @repository, + :committer => 'foo', + :committed_on => Time.now, + :revision => 101, + :comments => 'Another commit by foo.' + ) + assert_equal User.find(2), c.user + end + end + + def test_auto_user_mapping_by_username + c = Changeset.create!( + :repository => @repository, + :committer => 'jsmith', + :committed_on => Time.now, + :revision => 100, + :comments => 'Committed by john.' + ) + assert_equal User.find(2), c.user + end + + def test_auto_user_mapping_by_email + c = Changeset.create!( + :repository => @repository, + :committer => 'john ', + :committed_on => Time.now, + :revision => 100, + :comments => 'Committed by john.' + ) + assert_equal User.find(2), c.user + end + + def test_filesystem_avaialbe + klass = Repository::Filesystem + assert klass.scm_adapter_class + assert_equal true, klass.scm_available + end + + def test_merge_extra_info + repo = Repository::Subversion.new(:project => Project.find(3)) + assert !repo.save + repo.url = "svn://localhost" + assert repo.save + repo.reload + project = Project.find(3) + assert_equal repo, project.repository + assert_nil repo.extra_info + h1 = {"test_1" => {"test_11" => "test_value_11"}} + repo.merge_extra_info(h1) + assert_equal h1, repo.extra_info + h2 = {"test_2" => { + "test_21" => "test_value_21", + "test_22" => "test_value_22", + }} + repo.merge_extra_info(h2) + assert_equal (h = {"test_11" => "test_value_11"}), + repo.extra_info["test_1"] + assert_equal "test_value_21", + repo.extra_info["test_2"]["test_21"] + h3 = {"test_2" => { + "test_23" => "test_value_23", + "test_24" => "test_value_24", + }} + repo.merge_extra_info(h3) + assert_equal (h = {"test_11" => "test_value_11"}), + repo.extra_info["test_1"] + assert_nil repo.extra_info["test_2"]["test_21"] + assert_equal "test_value_23", + repo.extra_info["test_2"]["test_23"] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/30881f171a667b3a44449e71bb74b80be13859b2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/30/30881f171a667b3a44449e71bb74b80be13859b2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +module CodeRay +module Scanners + + # Scanner for JSON (JavaScript Object Notation). + class JSON < Scanner + + register_for :json + file_extension 'json' + + KINDS_NOT_LOC = [ + :float, :char, :content, :delimiter, + :error, :integer, :operator, :value, + ] # :nodoc: + + ESCAPE = / [bfnrt\\"\/] /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: + + protected + + # See http://json.org/ for a definition of the JSON lexic/grammar. + def scan_tokens encoder, options + + state = :initial + stack = [] + key_expected = false + + until eos? + + case state + + when :initial + if match = scan(/ \s+ /x) + encoder.text_token match, :space + elsif match = scan(/"/) + state = key_expected ? :key : :string + encoder.begin_group state + encoder.text_token match, :delimiter + elsif match = scan(/ [:,\[{\]}] /x) + encoder.text_token match, :operator + case match + when ':' then key_expected = false + when ',' then key_expected = true if stack.last == :object + when '{' then stack << :object; key_expected = true + when '[' then stack << :array + when '}', ']' then stack.pop # no error recovery, but works for valid JSON + end + elsif match = scan(/ true | false | null /x) + encoder.text_token match, :value + elsif match = scan(/ -? (?: 0 | [1-9]\d* ) /x) + if scan(/ \.\d+ (?:[eE][-+]?\d+)? | [eE][-+]? \d+ /x) + match << matched + encoder.text_token match, :float + else + encoder.text_token match, :integer + end + else + encoder.text_token getch, :error + end + + when :string, :key + if match = scan(/[^\\"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + encoder.text_token match, :error + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state: %p' % [state], encoder + + end + end + + if [:string, :key].include? state + encoder.end_group state + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/308a50990fe7138ee80b066400a54a3b1b066faf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/30/308a50990fe7138ee80b066400a54a3b1b066faf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= TestHelper.view_path_for __FILE__ %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/308f688f7ea9b63ad1f36c2cfc3b151507bfbaea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/30/308f688f7ea9b63ad1f36c2cfc3b151507bfbaea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +api.array :time_entries, api_meta(:total_count => @entry_count, :offset => @offset, :limit => @limit) do + @entries.each do |time_entry| + api.time_entry do + api.id time_entry.id + api.project(:id => time_entry.project_id, :name => time_entry.project.name) unless time_entry.project.nil? + api.issue(:id => time_entry.issue_id) unless time_entry.issue.nil? + api.user(:id => time_entry.user_id, :name => time_entry.user.name) unless time_entry.user.nil? + api.activity(:id => time_entry.activity_id, :name => time_entry.activity.name) unless time_entry.activity.nil? + api.hours time_entry.hours + api.comments time_entry.comments + api.spent_on time_entry.spent_on + api.created_on time_entry.created_on + api.updated_on time_entry.updated_on + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/30a4e4bcf8ad9e02c1978d0dcf32ae4d70a4af15.svn-base Binary file .svn/pristine/30/30a4e4bcf8ad9e02c1978d0dcf32ae4d70a4af15.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/30/30e01132e9ab5b3c9ae62f165db3ff3e34e482a8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/30/30e01132e9ab5b3c9ae62f165db3ff3e34e482a8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,86 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class DocumentsController < ApplicationController + default_search_scope :documents + model_object Document + before_filter :find_project, :only => [:index, :new] + before_filter :find_model_object, :except => [:index, :new] + before_filter :find_project_from_association, :except => [:index, :new] + before_filter :authorize + + helper :attachments + + def index + @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' + documents = @project.documents.find :all, :include => [:attachments, :category] + case @sort_by + when 'date' + @grouped = documents.group_by {|d| d.updated_on.to_date } + when 'title' + @grouped = documents.group_by {|d| d.title.first.upcase} + when 'author' + @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author} + else + @grouped = documents.group_by(&:category) + end + @document = @project.documents.build + render :layout => false if request.xhr? + end + + def show + @attachments = @document.attachments.find(:all, :order => "created_on DESC") + end + + def new + @document = @project.documents.build(params[:document]) + if request.post? and @document.save + attachments = Attachment.attach_files(@document, params[:attachments]) + render_attachment_warning_if_needed(@document) + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'index', :project_id => @project + end + end + + def edit + @categories = DocumentCategory.active #TODO: use it in the views + if request.post? and @document.update_attributes(params[:document]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'show', :id => @document + end + end + + def destroy + @document.destroy + redirect_to :controller => 'documents', :action => 'index', :project_id => @project + end + + def add_attachment + attachments = Attachment.attach_files(@document, params[:attachments]) + render_attachment_warning_if_needed(@document) + + Mailer.deliver_attachments_added(attachments[:files]) if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added') + redirect_to :action => 'show', :id => @document + end + +private + def find_project + @project = Project.find(params[:project_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/310894165a23b172c9ae0af61df340ce613e778e.svn-base Binary file .svn/pristine/31/310894165a23b172c9ae0af61df340ce613e778e.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/3111f66f2205d5a3793f8baff324b532853a4a60.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/31/3111f66f2205d5a3793f8baff324b532853a4a60.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1023 @@ +# French translations for Ruby on Rails +# by Christian Lescuyer (christian@flyingcoders.com) +# contributor: Sebastien Grosjean - ZenCocoon.com +# contributor: Thibaut Cuvelier - Developpez.com + +fr: + direction: ltr + date: + formats: + default: "%d/%m/%Y" + short: "%e %b" + long: "%e %B %Y" + long_ordinal: "%e %B %Y" + only_day: "%e" + + day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi] + abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam] + month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre] + abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.] + order: + - :day + - :month + - :year + + time: + formats: + default: "%d/%m/%Y %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%A %d %B %Y %H:%M:%S %Z" + long_ordinal: "%A %d %B %Y %H:%M:%S %Z" + only_second: "%S" + am: 'am' + pm: 'pm' + + datetime: + distance_in_words: + half_a_minute: "30 secondes" + less_than_x_seconds: + zero: "moins d'une seconde" + one: "moins d'une seconde" + other: "moins de %{count} secondes" + x_seconds: + one: "1 seconde" + other: "%{count} secondes" + less_than_x_minutes: + zero: "moins d'une minute" + one: "moins d'une minute" + other: "moins de %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "environ une heure" + other: "environ %{count} heures" + x_days: + one: "un jour" + other: "%{count} jours" + about_x_months: + one: "environ un mois" + other: "environ %{count} mois" + x_months: + one: "un mois" + other: "%{count} mois" + about_x_years: + one: "environ un an" + other: "environ %{count} ans" + over_x_years: + one: "plus d'un an" + other: "plus de %{count} ans" + almost_x_years: + one: "presqu'un an" + other: "presque %{count} ans" + prompts: + year: "Année" + month: "Mois" + day: "Jour" + hour: "Heure" + minute: "Minute" + second: "Seconde" + + number: + format: + precision: 3 + separator: ',' + delimiter: ' ' + currency: + format: + unit: '€' + precision: 2 + format: '%n %u' + human: + format: + precision: 2 + storage_units: + format: "%n %u" + units: + byte: + one: "octet" + other: "octet" + kb: "ko" + mb: "Mo" + gb: "Go" + tb: "To" + + support: + array: + sentence_connector: 'et' + skip_last_comma: true + word_connector: ", " + two_words_connector: " et " + last_word_connector: " et " + + activerecord: + errors: + template: + header: + one: "Impossible d'enregistrer %{model} : une erreur" + other: "Impossible d'enregistrer %{model} : %{count} erreurs." + body: "Veuillez vérifier les champs suivants :" + messages: + inclusion: "n'est pas inclus(e) dans la liste" + exclusion: "n'est pas disponible" + invalid: "n'est pas valide" + confirmation: "ne concorde pas avec la confirmation" + accepted: "doit être accepté(e)" + empty: "doit être renseigné(e)" + blank: "doit être renseigné(e)" + too_long: "est trop long (pas plus de %{count} caractères)" + too_short: "est trop court (au moins %{count} caractères)" + wrong_length: "ne fait pas la bonne longueur (doit comporter %{count} caractères)" + taken: "est déjà utilisé" + not_a_number: "n'est pas un nombre" + not_a_date: "n'est pas une date valide" + greater_than: "doit être supérieur à %{count}" + greater_than_or_equal_to: "doit être supérieur ou égal à %{count}" + equal_to: "doit être égal à %{count}" + less_than: "doit être inférieur à %{count}" + less_than_or_equal_to: "doit être inférieur ou égal à %{count}" + odd: "doit être impair" + even: "doit être pair" + greater_than_start_date: "doit être postérieure à la date de début" + not_same_project: "n'appartient pas au même projet" + circular_dependency: "Cette relation créerait une dépendance circulaire" + cant_link_an_issue_with_a_descendant: "Une demande ne peut pas être liée à l'une de ses sous-tâches" + + actionview_instancetag_blank_option: Choisir + + general_text_No: 'Non' + general_text_Yes: 'Oui' + general_text_no: 'non' + general_text_yes: 'oui' + general_lang_name: 'Français' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Le compte a été mis à jour avec succès. + notice_account_invalid_creditentials: Identifiant ou mot de passe invalide. + notice_account_password_updated: Mot de passe mis à jour avec succès. + notice_account_wrong_password: Mot de passe incorrect + notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a été envoyé. + notice_account_unknown_email: Aucun compte ne correspond à cette adresse. + notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe. + notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a été envoyé. + notice_account_activated: Votre compte a été activé. Vous pouvez à présent vous connecter. + notice_successful_create: Création effectuée avec succès. + notice_successful_update: Mise à jour effectuée avec succès. + notice_successful_delete: Suppression effectuée avec succès. + notice_successful_connection: Connexion réussie. + notice_file_not_found: "La page à laquelle vous souhaitez accéder n'existe pas ou a été supprimée." + notice_locking_conflict: Les données ont été mises à jour par un autre utilisateur. Mise à jour impossible. + notice_not_authorized: "Vous n'êtes pas autorisé à accéder à cette page." + notice_not_authorized_archived_project: Le projet auquel vous tentez d'accéder a été archivé. + notice_email_sent: "Un email a été envoyé à %{value}" + notice_email_error: "Erreur lors de l'envoi de l'email (%{value})" + notice_feeds_access_key_reseted: "Votre clé d'accès aux flux RSS a été réinitialisée." + notice_failed_to_save_issues: "%{count} demande(s) sur les %{total} sélectionnées n'ont pas pu être mise(s) à jour : %{ids}." + notice_no_issue_selected: "Aucune demande sélectionnée ! Cochez les demandes que vous voulez mettre à jour." + notice_account_pending: "Votre compte a été créé et attend l'approbation de l'administrateur." + notice_default_data_loaded: Paramétrage par défaut chargé avec succès. + notice_unable_delete_version: Impossible de supprimer cette version. + notice_issue_done_ratios_updated: L'avancement des demandes a été mis à jour. + notice_api_access_key_reseted: Votre clé d'accès API a été réinitialisée. + notice_gantt_chart_truncated: "Le diagramme a été tronqué car il excède le nombre maximal d'éléments pouvant être affichés (%{max})" + notice_issue_successful_create: "La demande %{id} a été créée." + + error_can_t_load_default_data: "Une erreur s'est produite lors du chargement du paramétrage : %{value}" + error_scm_not_found: "L'entrée et/ou la révision demandée n'existe pas dans le dépôt." + error_scm_command_failed: "Une erreur s'est produite lors de l'accès au dépôt : %{value}" + error_scm_annotate: "L'entrée n'existe pas ou ne peut pas être annotée." + error_issue_not_found_in_project: "La demande n'existe pas ou n'appartient pas à ce projet" + error_can_not_reopen_issue_on_closed_version: 'Une demande assignée à une version fermée ne peut pas être réouverte' + error_can_not_archive_project: "Ce projet ne peut pas être archivé" + error_workflow_copy_source: 'Veuillez sélectionner un tracker et/ou un rôle source' + error_workflow_copy_target: 'Veuillez sélectionner les trackers et rôles cibles' + error_issue_done_ratios_not_updated: L'avancement des demandes n'a pas pu être mis à jour. + error_attachment_too_big: Ce fichier ne peut pas être attaché car il excède la taille maximale autorisée (%{max_size}) + + warning_attachments_not_saved: "%{count} fichier(s) n'ont pas pu être sauvegardés." + + mail_subject_lost_password: "Votre mot de passe %{value}" + mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :' + mail_subject_register: "Activation de votre compte %{value}" + mail_body_register: 'Pour activer votre compte, cliquez sur le lien suivant :' + mail_body_account_information_external: "Vous pouvez utiliser votre compte %{value} pour vous connecter." + mail_body_account_information: Paramètres de connexion de votre compte + mail_subject_account_activation_request: "Demande d'activation d'un compte %{value}" + mail_body_account_activation_request: "Un nouvel utilisateur (%{value}) s'est inscrit. Son compte nécessite votre approbation :" + mail_subject_reminder: "%{count} demande(s) arrivent à échéance (%{days})" + mail_body_reminder: "%{count} demande(s) qui vous sont assignées arrivent à échéance dans les %{days} prochains jours :" + mail_subject_wiki_content_added: "Page wiki '%{id}' ajoutée" + mail_body_wiki_content_added: "La page wiki '%{id}' a été ajoutée par %{author}." + mail_subject_wiki_content_updated: "Page wiki '%{id}' mise à jour" + mail_body_wiki_content_updated: "La page wiki '%{id}' a été mise à jour par %{author}." + + gui_validation_error: 1 erreur + gui_validation_error_plural: "%{count} erreurs" + + field_name: Nom + field_description: Description + field_summary: Résumé + field_is_required: Obligatoire + field_firstname: Prénom + field_lastname: Nom + field_mail: "Email " + field_filename: Fichier + field_filesize: Taille + field_downloads: Téléchargements + field_author: Auteur + field_created_on: "Créé " + field_updated_on: "Mis-à-jour " + field_field_format: Format + field_is_for_all: Pour tous les projets + field_possible_values: Valeurs possibles + field_regexp: Expression régulière + field_min_length: Longueur minimum + field_max_length: Longueur maximum + field_value: Valeur + field_category: Catégorie + field_title: Titre + field_project: Projet + field_issue: Demande + field_status: Statut + field_notes: Notes + field_is_closed: Demande fermée + field_is_default: Valeur par défaut + field_tracker: Tracker + field_subject: Sujet + field_due_date: Echéance + field_assigned_to: Assigné à + field_priority: Priorité + field_fixed_version: Version cible + field_user: Utilisateur + field_role: Rôle + field_homepage: "Site web " + field_is_public: Public + field_parent: Sous-projet de + field_is_in_roadmap: Demandes affichées dans la roadmap + field_login: "Identifiant " + field_mail_notification: Notifications par mail + field_admin: Administrateur + field_last_login_on: "Dernière connexion " + field_language: Langue + field_effective_date: Date + field_password: Mot de passe + field_new_password: Nouveau mot de passe + field_password_confirmation: Confirmation + field_version: Version + field_type: Type + field_host: Hôte + field_port: Port + field_account: Compte + field_base_dn: Base DN + field_attr_login: Attribut Identifiant + field_attr_firstname: Attribut Prénom + field_attr_lastname: Attribut Nom + field_attr_mail: Attribut Email + field_onthefly: Création des utilisateurs à la volée + field_start_date: Début + field_done_ratio: "% réalisé" + field_auth_source: Mode d'authentification + field_hide_mail: Cacher mon adresse mail + field_comments: Commentaire + field_url: URL + field_start_page: Page de démarrage + field_subproject: Sous-projet + field_hours: Heures + field_activity: Activité + field_spent_on: Date + field_identifier: Identifiant + field_is_filter: Utilisé comme filtre + field_issue_to: Demande liée + field_delay: Retard + field_assignable: Demandes assignables à ce rôle + field_redirect_existing_links: Rediriger les liens existants + field_estimated_hours: Temps estimé + field_column_names: Colonnes + field_time_zone: Fuseau horaire + field_searchable: Utilisé pour les recherches + field_default_value: Valeur par défaut + field_comments_sorting: Afficher les commentaires + field_parent_title: Page parent + field_editable: Modifiable + field_watcher: Observateur + field_identity_url: URL OpenID + field_content: Contenu + field_group_by: Grouper par + field_sharing: Partage + field_active: Actif + field_parent_issue: Tâche parente + field_visible: Visible + field_warn_on_leaving_unsaved: "M'avertir lorsque je quitte une page contenant du texte non sauvegardé" + field_issues_visibility: Visibilité des demandes + field_is_private: Privée + field_commit_logs_encoding: Encodage des messages de commit + + setting_app_title: Titre de l'application + setting_app_subtitle: Sous-titre de l'application + setting_welcome_text: Texte d'accueil + setting_default_language: Langue par défaut + setting_login_required: Authentification obligatoire + setting_self_registration: Inscription des nouveaux utilisateurs + setting_attachment_max_size: Taille maximale des fichiers + setting_issues_export_limit: Limite d'exportation des demandes + setting_mail_from: Adresse d'émission + setting_bcc_recipients: Destinataires en copie cachée (cci) + setting_plain_text_mail: Mail en texte brut (non HTML) + setting_host_name: Nom d'hôte et chemin + setting_text_formatting: Formatage du texte + setting_wiki_compression: Compression de l'historique des pages wiki + setting_feeds_limit: Nombre maximal d'éléments dans les flux Atom + setting_default_projects_public: Définir les nouveaux projets comme publics par défaut + setting_autofetch_changesets: Récupération automatique des commits + setting_sys_api_enabled: Activer les WS pour la gestion des dépôts + setting_commit_ref_keywords: Mots-clés de référencement + setting_commit_fix_keywords: Mots-clés de résolution + setting_autologin: Durée maximale de connexion automatique + setting_date_format: Format de date + setting_time_format: Format d'heure + setting_cross_project_issue_relations: Autoriser les relations entre demandes de différents projets + setting_issue_list_default_columns: Colonnes affichées par défaut sur la liste des demandes + setting_emails_footer: Pied-de-page des emails + setting_protocol: Protocole + setting_per_page_options: Options d'objets affichés par page + setting_user_format: Format d'affichage des utilisateurs + setting_activity_days_default: Nombre de jours affichés sur l'activité des projets + setting_display_subprojects_issues: Afficher par défaut les demandes des sous-projets sur les projets principaux + setting_enabled_scm: SCM activés + setting_mail_handler_body_delimiters: "Tronquer les emails après l'une de ces lignes" + setting_mail_handler_api_enabled: "Activer le WS pour la réception d'emails" + setting_mail_handler_api_key: Clé de protection de l'API + setting_sequential_project_identifiers: Générer des identifiants de projet séquentiels + setting_gravatar_enabled: Afficher les Gravatar des utilisateurs + setting_diff_max_lines_displayed: Nombre maximum de lignes de diff affichées + setting_file_max_size_displayed: Taille maximum des fichiers texte affichés en ligne + setting_repository_log_display_limit: "Nombre maximum de révisions affichées sur l'historique d'un fichier" + setting_openid: "Autoriser l'authentification et l'enregistrement OpenID" + setting_password_min_length: Longueur minimum des mots de passe + setting_new_project_user_role_id: Rôle donné à un utilisateur non-administrateur qui crée un projet + setting_default_projects_modules: Modules activés par défaut pour les nouveaux projets + setting_issue_done_ratio: Calcul de l'avancement des demandes + setting_issue_done_ratio_issue_status: Utiliser le statut + setting_issue_done_ratio_issue_field: 'Utiliser le champ % effectué' + setting_rest_api_enabled: Activer l'API REST + setting_gravatar_default: Image Gravatar par défaut + setting_start_of_week: Jour de début des calendriers + setting_cache_formatted_text: Mettre en cache le texte formaté + setting_commit_logtime_enabled: Permettre la saisie de temps + setting_commit_logtime_activity_id: Activité pour le temps saisi + setting_gantt_items_limit: Nombre maximum d'éléments affichés sur le gantt + setting_issue_group_assignment: Permettre l'assignement des demandes aux groupes + setting_default_issue_start_date_to_creation_date: Donner à la date de début d'une nouvelle demande la valeur de la date du jour + + permission_add_project: Créer un projet + permission_add_subprojects: Créer des sous-projets + permission_edit_project: Modifier le projet + permission_select_project_modules: Choisir les modules + permission_manage_members: Gérer les membres + permission_manage_versions: Gérer les versions + permission_manage_categories: Gérer les catégories de demandes + permission_view_issues: Voir les demandes + permission_add_issues: Créer des demandes + permission_edit_issues: Modifier les demandes + permission_manage_issue_relations: Gérer les relations + permission_set_issues_private: Rendre les demandes publiques ou privées + permission_set_own_issues_private: Rendre ses propres demandes publiques ou privées + permission_add_issue_notes: Ajouter des notes + permission_edit_issue_notes: Modifier les notes + permission_edit_own_issue_notes: Modifier ses propres notes + permission_move_issues: Déplacer les demandes + permission_delete_issues: Supprimer les demandes + permission_manage_public_queries: Gérer les requêtes publiques + permission_save_queries: Sauvegarder les requêtes + permission_view_gantt: Voir le gantt + permission_view_calendar: Voir le calendrier + permission_view_issue_watchers: Voir la liste des observateurs + permission_add_issue_watchers: Ajouter des observateurs + permission_delete_issue_watchers: Supprimer des observateurs + permission_log_time: Saisir le temps passé + permission_view_time_entries: Voir le temps passé + permission_edit_time_entries: Modifier les temps passés + permission_edit_own_time_entries: Modifier son propre temps passé + permission_manage_news: Gérer les annonces + permission_comment_news: Commenter les annonces + permission_manage_documents: Gérer les documents + permission_view_documents: Voir les documents + permission_manage_files: Gérer les fichiers + permission_view_files: Voir les fichiers + permission_manage_wiki: Gérer le wiki + permission_rename_wiki_pages: Renommer les pages + permission_delete_wiki_pages: Supprimer les pages + permission_view_wiki_pages: Voir le wiki + permission_view_wiki_edits: "Voir l'historique des modifications" + permission_edit_wiki_pages: Modifier les pages + permission_delete_wiki_pages_attachments: Supprimer les fichiers joints + permission_protect_wiki_pages: Protéger les pages + permission_manage_repository: Gérer le dépôt de sources + permission_browse_repository: Parcourir les sources + permission_view_changesets: Voir les révisions + permission_commit_access: Droit de commit + permission_manage_boards: Gérer les forums + permission_view_messages: Voir les messages + permission_add_messages: Poster un message + permission_edit_messages: Modifier les messages + permission_edit_own_messages: Modifier ses propres messages + permission_delete_messages: Supprimer les messages + permission_delete_own_messages: Supprimer ses propres messages + permission_export_wiki_pages: Exporter les pages + permission_manage_project_activities: Gérer les activités + permission_manage_subtasks: Gérer les sous-tâches + + project_module_issue_tracking: Suivi des demandes + project_module_time_tracking: Suivi du temps passé + project_module_news: Publication d'annonces + project_module_documents: Publication de documents + project_module_files: Publication de fichiers + project_module_wiki: Wiki + project_module_repository: Dépôt de sources + project_module_boards: Forums de discussion + + label_user: Utilisateur + label_user_plural: Utilisateurs + label_user_new: Nouvel utilisateur + label_user_anonymous: Anonyme + label_project: Projet + label_project_new: Nouveau projet + label_project_plural: Projets + label_x_projects: + zero: aucun projet + one: un projet + other: "%{count} projets" + label_project_all: Tous les projets + label_project_latest: Derniers projets + label_issue: Demande + label_issue_new: Nouvelle demande + label_issue_plural: Demandes + label_issue_view_all: Voir toutes les demandes + label_issue_added: Demande ajoutée + label_issue_updated: Demande mise à jour + label_issue_note_added: Note ajoutée + label_issue_status_updated: Statut changé + label_issue_priority_updated: Priorité changée + label_issues_by: "Demandes par %{value}" + label_document: Document + label_document_new: Nouveau document + label_document_plural: Documents + label_document_added: Document ajouté + label_role: Rôle + label_role_plural: Rôles + label_role_new: Nouveau rôle + label_role_and_permissions: Rôles et permissions + label_role_anonymous: Anonyme + label_role_non_member: Non membre + label_member: Membre + label_member_new: Nouveau membre + label_member_plural: Membres + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: Nouveau tracker + label_workflow: Workflow + label_issue_status: Statut de demandes + label_issue_status_plural: Statuts de demandes + label_issue_status_new: Nouveau statut + label_issue_category: Catégorie de demandes + label_issue_category_plural: Catégories de demandes + label_issue_category_new: Nouvelle catégorie + label_custom_field: Champ personnalisé + label_custom_field_plural: Champs personnalisés + label_custom_field_new: Nouveau champ personnalisé + label_enumerations: Listes de valeurs + label_enumeration_new: Nouvelle valeur + label_information: Information + label_information_plural: Informations + label_please_login: Identification + label_register: S'enregistrer + label_login_with_open_id_option: S'authentifier avec OpenID + label_password_lost: Mot de passe perdu + label_home: Accueil + label_my_page: Ma page + label_my_account: Mon compte + label_my_projects: Mes projets + label_my_page_block: Blocs disponibles + label_administration: Administration + label_login: Connexion + label_logout: Déconnexion + label_help: Aide + label_reported_issues: "Demandes soumises " + label_assigned_to_me_issues: Demandes qui me sont assignées + label_last_login: "Dernière connexion " + label_registered_on: "Inscrit le " + label_activity: Activité + label_overall_activity: Activité globale + label_user_activity: "Activité de %{value}" + label_new: Nouveau + label_logged_as: Connecté en tant que + label_environment: Environnement + label_authentication: Authentification + label_auth_source: Mode d'authentification + label_auth_source_new: Nouveau mode d'authentification + label_auth_source_plural: Modes d'authentification + label_subproject_plural: Sous-projets + label_subproject_new: Nouveau sous-projet + label_and_its_subprojects: "%{value} et ses sous-projets" + label_min_max_length: Longueurs mini - maxi + label_list: Liste + label_date: Date + label_integer: Entier + label_float: Nombre décimal + label_boolean: Booléen + label_string: Texte + label_text: Texte long + label_attribute: Attribut + label_attribute_plural: Attributs + label_download: "%{count} téléchargement" + label_download_plural: "%{count} téléchargements" + label_no_data: Aucune donnée à afficher + label_change_status: Changer le statut + label_history: Historique + label_attachment: Fichier + label_attachment_new: Nouveau fichier + label_attachment_delete: Supprimer le fichier + label_attachment_plural: Fichiers + label_file_added: Fichier ajouté + label_report: Rapport + label_report_plural: Rapports + label_news: Annonce + label_news_new: Nouvelle annonce + label_news_plural: Annonces + label_news_latest: Dernières annonces + label_news_view_all: Voir toutes les annonces + label_news_added: Annonce ajoutée + label_news_comment_added: Commentaire ajouté à une annonce + label_settings: Configuration + label_overview: Aperçu + label_version: Version + label_version_new: Nouvelle version + label_version_plural: Versions + label_confirmation: Confirmation + label_export_to: 'Formats disponibles :' + label_read: Lire... + label_public_projects: Projets publics + label_open_issues: ouvert + label_open_issues_plural: ouverts + label_closed_issues: fermé + label_closed_issues_plural: fermés + label_x_open_issues_abbr_on_total: + zero: 0 ouvert sur %{total} + one: 1 ouvert sur %{total} + other: "%{count} ouverts sur %{total}" + label_x_open_issues_abbr: + zero: 0 ouvert + one: 1 ouvert + other: "%{count} ouverts" + label_x_closed_issues_abbr: + zero: 0 fermé + one: 1 fermé + other: "%{count} fermés" + label_total: Total + label_permissions: Permissions + label_current_status: Statut actuel + label_new_statuses_allowed: Nouveaux statuts autorisés + label_all: tous + label_none: aucun + label_nobody: personne + label_next: Suivant + label_previous: Précédent + label_used_by: Utilisé par + label_details: Détails + label_add_note: Ajouter une note + label_per_page: Par page + label_calendar: Calendrier + label_months_from: mois depuis + label_gantt: Gantt + label_internal: Interne + label_last_changes: "%{count} derniers changements" + label_change_view_all: Voir tous les changements + label_personalize_page: Personnaliser cette page + label_comment: Commentaire + label_comment_plural: Commentaires + label_x_comments: + zero: aucun commentaire + one: un commentaire + other: "%{count} commentaires" + label_comment_add: Ajouter un commentaire + label_comment_added: Commentaire ajouté + label_comment_delete: Supprimer les commentaires + label_query: Rapport personnalisé + label_query_plural: Rapports personnalisés + label_query_new: Nouveau rapport + label_my_queries: Mes rapports personnalisés + label_filter_add: "Ajouter le filtre " + label_filter_plural: Filtres + label_equals: égal + label_not_equals: différent + label_in_less_than: dans moins de + label_in_more_than: dans plus de + label_in: dans + label_today: aujourd'hui + label_all_time: toute la période + label_yesterday: hier + label_this_week: cette semaine + label_last_week: la semaine dernière + label_last_n_days: "les %{count} derniers jours" + label_this_month: ce mois-ci + label_last_month: le mois dernier + label_this_year: cette année + label_date_range: Période + label_less_than_ago: il y a moins de + label_more_than_ago: il y a plus de + label_ago: il y a + label_contains: contient + label_not_contains: ne contient pas + label_day_plural: jours + label_repository: Dépôt + label_repository_plural: Dépôts + label_browse: Parcourir + label_modification: "%{count} modification" + label_modification_plural: "%{count} modifications" + label_revision: "Révision " + label_revision_plural: Révisions + label_associated_revisions: Révisions associées + label_added: ajouté + label_modified: modifié + label_copied: copié + label_renamed: renommé + label_deleted: supprimé + label_latest_revision: Dernière révision + label_latest_revision_plural: Dernières révisions + label_view_revisions: Voir les révisions + label_max_size: Taille maximale + label_sort_highest: Remonter en premier + label_sort_higher: Remonter + label_sort_lower: Descendre + label_sort_lowest: Descendre en dernier + label_roadmap: Roadmap + label_roadmap_due_in: "Échéance dans %{value}" + label_roadmap_overdue: "En retard de %{value}" + label_roadmap_no_issues: Aucune demande pour cette version + label_search: "Recherche " + label_result_plural: Résultats + label_all_words: Tous les mots + label_wiki: Wiki + label_wiki_edit: Révision wiki + label_wiki_edit_plural: Révisions wiki + label_wiki_page: Page wiki + label_wiki_page_plural: Pages wiki + label_index_by_title: Index par titre + label_index_by_date: Index par date + label_current_version: Version actuelle + label_preview: Prévisualisation + label_feed_plural: Flux RSS + label_changes_details: Détails de tous les changements + label_issue_tracking: Suivi des demandes + label_spent_time: Temps passé + label_f_hour: "%{value} heure" + label_f_hour_plural: "%{value} heures" + label_time_tracking: Suivi du temps + label_change_plural: Changements + label_statistics: Statistiques + label_commits_per_month: Commits par mois + label_commits_per_author: Commits par auteur + label_view_diff: Voir les différences + label_diff_inline: en ligne + label_diff_side_by_side: côte à côte + label_options: Options + label_copy_workflow_from: Copier le workflow de + label_permissions_report: Synthèse des permissions + label_watched_issues: Demandes surveillées + label_related_issues: Demandes liées + label_applied_status: Statut appliqué + label_loading: Chargement... + label_relation_new: Nouvelle relation + label_relation_delete: Supprimer la relation + label_relates_to: lié à + label_duplicates: duplique + label_duplicated_by: dupliqué par + label_blocks: bloque + label_blocked_by: bloqué par + label_precedes: précède + label_follows: suit + label_end_to_start: fin à début + label_end_to_end: fin à fin + label_start_to_start: début à début + label_start_to_end: début à fin + label_stay_logged_in: Rester connecté + label_disabled: désactivé + label_show_completed_versions: Voir les versions passées + label_me: moi + label_board: Forum + label_board_new: Nouveau forum + label_board_plural: Forums + label_topic_plural: Discussions + label_message_plural: Messages + label_message_last: Dernier message + label_message_new: Nouveau message + label_message_posted: Message ajouté + label_reply_plural: Réponses + label_send_information: Envoyer les informations à l'utilisateur + label_year: Année + label_month: Mois + label_week: Semaine + label_date_from: Du + label_date_to: Au + label_language_based: Basé sur la langue de l'utilisateur + label_sort_by: "Trier par %{value}" + label_send_test_email: Envoyer un email de test + label_feeds_access_key_created_on: "Clé d'accès RSS créée il y a %{value}" + label_module_plural: Modules + label_added_time_by: "Ajouté par %{author} il y a %{age}" + label_updated_time_by: "Mis à jour par %{author} il y a %{age}" + label_updated_time: "Mis à jour il y a %{value}" + label_jump_to_a_project: Aller à un projet... + label_file_plural: Fichiers + label_changeset_plural: Révisions + label_default_columns: Colonnes par défaut + label_no_change_option: (Pas de changement) + label_bulk_edit_selected_issues: Modifier les demandes sélectionnées + label_theme: Thème + label_default: Défaut + label_search_titles_only: Uniquement dans les titres + label_user_mail_option_all: "Pour tous les événements de tous mes projets" + label_user_mail_option_selected: "Pour tous les événements des projets sélectionnés..." + label_user_mail_no_self_notified: "Je ne veux pas être notifié des changements que j'effectue" + label_registration_activation_by_email: activation du compte par email + label_registration_manual_activation: activation manuelle du compte + label_registration_automatic_activation: activation automatique du compte + label_display_per_page: "Par page : %{value}" + label_age: Âge + label_change_properties: Changer les propriétés + label_general: Général + label_more: Plus + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: Authentification LDAP + label_downloads_abbr: D/L + label_optional_description: Description facultative + label_add_another_file: Ajouter un autre fichier + label_preferences: Préférences + label_chronological_order: Dans l'ordre chronologique + label_reverse_chronological_order: Dans l'ordre chronologique inverse + label_planning: Planning + label_incoming_emails: Emails entrants + label_generate_key: Générer une clé + label_issue_watchers: Observateurs + label_example: Exemple + label_display: Affichage + label_sort: Tri + label_ascending: Croissant + label_descending: Décroissant + label_date_from_to: Du %{start} au %{end} + label_wiki_content_added: Page wiki ajoutée + label_wiki_content_updated: Page wiki mise à jour + label_group_plural: Groupes + label_group: Groupe + label_group_new: Nouveau groupe + label_time_entry_plural: Temps passé + label_version_sharing_none: Non partagé + label_version_sharing_descendants: Avec les sous-projets + label_version_sharing_hierarchy: Avec toute la hiérarchie + label_version_sharing_tree: Avec tout l'arbre + label_version_sharing_system: Avec tous les projets + label_copy_source: Source + label_copy_target: Cible + label_copy_same_as_target: Comme la cible + label_update_issue_done_ratios: Mettre à jour l'avancement des demandes + label_display_used_statuses_only: N'afficher que les statuts utilisés dans ce tracker + label_api_access_key: Clé d'accès API + label_api_access_key_created_on: Clé d'accès API créée il y a %{value} + label_feeds_access_key: Clé d'accès RSS + label_missing_api_access_key: Clé d'accès API manquante + label_missing_feeds_access_key: Clé d'accès RSS manquante + label_close_versions: Fermer les versions terminées + label_revision_id: Revision %{value} + label_profile: Profil + label_subtask_plural: Sous-tâches + label_project_copy_notifications: Envoyer les notifications durant la copie du projet + label_principal_search: "Rechercher un utilisateur ou un groupe :" + label_user_search: "Rechercher un utilisateur :" + label_additional_workflow_transitions_for_author: Autorisations supplémentaires lorsque l'utilisateur a créé la demande + label_additional_workflow_transitions_for_assignee: Autorisations supplémentaires lorsque la demande est assignée à l'utilisateur + label_issues_visibility_all: Toutes les demandes + label_issues_visibility_public: Toutes les demandes non privées + label_issues_visibility_own: Demandes créées par ou assignées à l'utilisateur + label_export_options: Options d'exportation %{export_format} + + button_login: Connexion + button_submit: Soumettre + button_save: Sauvegarder + button_check_all: Tout cocher + button_uncheck_all: Tout décocher + button_collapse_all: Plier tout + button_expand_all: Déplier tout + button_delete: Supprimer + button_create: Créer + button_create_and_continue: Créer et continuer + button_test: Tester + button_edit: Modifier + button_add: Ajouter + button_change: Changer + button_apply: Appliquer + button_clear: Effacer + button_lock: Verrouiller + button_unlock: Déverrouiller + button_download: Télécharger + button_list: Lister + button_view: Voir + button_move: Déplacer + button_move_and_follow: Déplacer et suivre + button_back: Retour + button_cancel: Annuler + button_activate: Activer + button_sort: Trier + button_log_time: Saisir temps + button_rollback: Revenir à cette version + button_watch: Surveiller + button_unwatch: Ne plus surveiller + button_reply: Répondre + button_archive: Archiver + button_unarchive: Désarchiver + button_reset: Réinitialiser + button_rename: Renommer + button_change_password: Changer de mot de passe + button_copy: Copier + button_copy_and_follow: Copier et suivre + button_annotate: Annoter + button_update: Mettre à jour + button_configure: Configurer + button_quote: Citer + button_duplicate: Dupliquer + button_show: Afficher + button_edit_section: Modifier cette section + button_export: Exporter + + status_active: actif + status_registered: enregistré + status_locked: verrouillé + + version_status_open: ouvert + version_status_locked: verrouillé + version_status_closed: fermé + + text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 pour aucune restriction + text_project_destroy_confirmation: Êtes-vous sûr de vouloir supprimer ce projet et toutes ses données ? + text_subprojects_destroy_warning: "Ses sous-projets : %{value} seront également supprimés." + text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow + text_are_you_sure: Êtes-vous sûr ? + text_tip_issue_begin_day: tâche commençant ce jour + text_tip_issue_end_day: tâche finissant ce jour + text_tip_issue_begin_end_day: tâche commençant et finissant ce jour + text_project_identifier_info: 'Seuls les lettres minuscules (a-z), chiffres et tirets sont autorisés.
Un fois sauvegardé, l''identifiant ne pourra plus être modifié.' + text_caracters_maximum: "%{count} caractères maximum." + text_caracters_minimum: "%{count} caractères minimum." + text_length_between: "Longueur comprise entre %{min} et %{max} caractères." + text_tracker_no_workflow: Aucun worflow n'est défini pour ce tracker + text_unallowed_characters: Caractères non autorisés + text_comma_separated: Plusieurs valeurs possibles (séparées par des virgules). + text_line_separated: Plusieurs valeurs possibles (une valeur par ligne). + text_issues_ref_in_commit_messages: Référencement et résolution des demandes dans les commentaires de commits + text_issue_added: "La demande %{id} a été soumise par %{author}." + text_issue_updated: "La demande %{id} a été mise à jour par %{author}." + text_wiki_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce wiki et tout son contenu ? + text_issue_category_destroy_question: "%{count} demandes sont affectées à cette catégorie. Que voulez-vous faire ?" + text_issue_category_destroy_assignments: N'affecter les demandes à aucune autre catégorie + text_issue_category_reassign_to: Réaffecter les demandes à cette catégorie + text_user_mail_option: "Pour les projets non sélectionnés, vous recevrez seulement des notifications pour ce que vous surveillez ou à quoi vous participez (exemple: demandes dont vous êtes l'auteur ou la personne assignée)." + text_no_configuration_data: "Les rôles, trackers, statuts et le workflow ne sont pas encore paramétrés.\nIl est vivement recommandé de charger le paramétrage par defaut. Vous pourrez le modifier une fois chargé." + text_load_default_configuration: Charger le paramétrage par défaut + text_status_changed_by_changeset: "Appliqué par commit %{value}." + text_time_logged_by_changeset: "Appliqué par commit %{value}" + text_issues_destroy_confirmation: 'Êtes-vous sûr de vouloir supprimer la ou les demandes(s) selectionnée(s) ?' + text_issues_destroy_descendants_confirmation: "Cela entrainera également la suppression de %{count} sous-tâche(s)." + text_select_project_modules: 'Sélectionner les modules à activer pour ce projet :' + text_default_administrator_account_changed: Compte administrateur par défaut changé + text_file_repository_writable: Répertoire de stockage des fichiers accessible en écriture + text_plugin_assets_writable: Répertoire public des plugins accessible en écriture + text_rmagick_available: Bibliothèque RMagick présente (optionnelle) + text_destroy_time_entries_question: "%{hours} heures ont été enregistrées sur les demandes à supprimer. Que voulez-vous faire ?" + text_destroy_time_entries: Supprimer les heures + text_assign_time_entries_to_project: Reporter les heures sur le projet + text_reassign_time_entries: 'Reporter les heures sur cette demande:' + text_user_wrote: "%{value} a écrit :" + text_enumeration_destroy_question: "Cette valeur est affectée à %{count} objets." + text_enumeration_category_reassign_to: 'Réaffecter les objets à cette valeur:' + text_email_delivery_not_configured: "L'envoi de mail n'est pas configuré, les notifications sont désactivées.\nConfigurez votre serveur SMTP dans config/configuration.yml et redémarrez l'application pour les activer." + text_repository_usernames_mapping: "Vous pouvez sélectionner ou modifier l'utilisateur Redmine associé à chaque nom d'utilisateur figurant dans l'historique du dépôt.\nLes utilisateurs avec le même identifiant ou la même adresse mail seront automatiquement associés." + text_diff_truncated: '... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.' + text_custom_field_possible_values_info: 'Une ligne par valeur' + text_wiki_page_destroy_question: "Cette page possède %{descendants} sous-page(s) et descendante(s). Que voulez-vous faire ?" + text_wiki_page_nullify_children: "Conserver les sous-pages en tant que pages racines" + text_wiki_page_destroy_children: "Supprimer les sous-pages et toutes leurs descedantes" + text_wiki_page_reassign_children: "Réaffecter les sous-pages à cette page" + text_own_membership_delete_confirmation: "Vous allez supprimer tout ou partie de vos permissions sur ce projet et ne serez peut-être plus autorisé à modifier ce projet.\nEtes-vous sûr de vouloir continuer ?" + text_warn_on_leaving_unsaved: "Cette page contient du texte non sauvegardé qui sera perdu si vous quittez la page." + + default_role_manager: "Manager " + default_role_developer: "Développeur " + default_role_reporter: "Rapporteur " + default_tracker_bug: Anomalie + default_tracker_feature: Evolution + default_tracker_support: Assistance + default_issue_status_new: Nouveau + default_issue_status_in_progress: En cours + default_issue_status_resolved: Résolu + default_issue_status_feedback: Commentaire + default_issue_status_closed: Fermé + default_issue_status_rejected: Rejeté + default_doc_category_user: Documentation utilisateur + default_doc_category_tech: Documentation technique + default_priority_low: Bas + default_priority_normal: Normal + default_priority_high: Haut + default_priority_urgent: Urgent + default_priority_immediate: Immédiat + default_activity_design: Conception + default_activity_development: Développement + + enumeration_issue_priorities: Priorités des demandes + enumeration_doc_categories: Catégories des documents + enumeration_activities: Activités (suivi du temps) + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + label_between: entre + label_view_all_revisions: Voir toutes les révisions + label_tag: Tag + label_branch: Branche + error_no_tracker_in_project: "Aucun tracker n'est associé à ce projet. Vérifier la configuration du projet." + error_no_default_issue_status: "Aucun statut de demande n'est défini par défaut. Vérifier votre configuration (Administration -> Statuts de demandes)." + text_journal_changed: "%{label} changé de %{old} à %{new}" + text_journal_changed_no_detail: "%{label} mis à jour" + text_journal_set_to: "%{label} mis à %{value}" + text_journal_deleted: "%{label} %{old} supprimé" + text_journal_added: "%{label} %{value} ajouté" + enumeration_system_activity: Activité système + label_board_sticky: Sticky + label_board_locked: Verrouillé + error_unable_delete_issue_status: Impossible de supprimer le statut de demande + error_can_not_delete_custom_field: Impossible de supprimer le champ personnalisé + error_unable_to_connect: Connexion impossible (%{value}) + error_can_not_remove_role: Ce rôle est utilisé et ne peut pas être supprimé. + error_can_not_delete_tracker: Ce tracker contient des demandes et ne peut pas être supprimé. + field_principal: Principal + notice_failed_to_save_members: "Erreur lors de la sauvegarde des membres: %{errors}." + text_zoom_out: Zoom arrière + text_zoom_in: Zoom avant + notice_unable_delete_time_entry: Impossible de supprimer le temps passé. + label_overall_spent_time: Temps passé global + field_time_entries: Temps passé + project_module_gantt: Gantt + project_module_calendar: Calendrier + button_edit_associated_wikipage: "Modifier la page wiki associée: %{page_title}" + text_are_you_sure_with_children: Supprimer la demande et toutes ses sous-demandes ? + field_text: Champ texte + label_user_mail_option_only_owner: Seulement pour ce que j'ai créé + setting_default_notification_option: Option de notification par défaut + label_user_mail_option_only_my_events: Seulement pour ce que je surveille + label_user_mail_option_only_assigned: Seulement pour ce qui m'est assigné + label_user_mail_option_none: Aucune notification + field_member_of_group: Groupe de l'assigné + field_assigned_to_role: Rôle de l'assigné + setting_emails_header: En-tête des emails + label_bulk_edit_selected_time_entries: Modifier les temps passés sélectionnées + text_time_entries_destroy_confirmation: "Etes-vous sûr de vouloir supprimer les temps passés sélectionnés ?" + field_scm_path_encoding: Encodage des chemins + text_scm_path_encoding_note: "Défaut : UTF-8" + field_path_to_repository: Chemin du dépôt + field_root_directory: Répertoire racine + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: "Dépôt local (exemples : /hgrepo, c:\\hgrepo)" + text_scm_command: Commande + text_scm_command_version: Version + label_git_report_last_commit: Afficher le dernier commit des fichiers et répertoires + text_scm_config: Vous pouvez configurer les commandes des SCM dans config/configuration.yml. Redémarrer l'application après modification. + text_scm_command_not_available: Ce SCM n'est pas disponible. Vérifier les paramètres dans la section administration. + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Ordre de tri + description_project_scope: Périmètre de recherche + description_filter: Filtre + description_user_mail_notification: Option de notification + description_date_from: Date de début + description_message_content: Contenu du message + description_available_columns: Colonnes disponibles + description_all_columns: Toutes les colonnes + description_date_range_interval: Choisir une période + description_issue_category_reassign: Choisir une catégorie + description_search: Champ de recherche + description_notes: Notes + description_date_range_list: Choisir une période prédéfinie + description_choose_project: Projets + description_date_to: Date de fin + description_query_sort_criteria_attribute: Critère de tri + description_wiki_subpages_reassign: Choisir une nouvelle page parent + description_selected_columns: Colonnes sélectionnées + label_parent_revision: Parent + label_child_revision: Enfant + error_scm_annotate_big_text_file: Cette entrée ne peut pas être annotée car elle excède la taille maximale. + setting_repositories_encodings: Encodages des fichiers et des dépôts diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/31149e0d29158240e0df21a807fe4c81bbdba840.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/31/31149e0d29158240e0df21a807fe4c81bbdba840.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToMessages < ActiveRecord::Migration + def self.up + add_index :messages, :last_reply_id + add_index :messages, :author_id + end + + def self.down + remove_index :messages, :last_reply_id + remove_index :messages, :author_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/31192143eb1c52ad53b2edf56c4ab09d186df056.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/31/31192143eb1c52ad53b2edf56c4ab09d186df056.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,54 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class IssueCategoryTest < ActiveSupport::TestCase + fixtures :issue_categories, :issues + + def setup + @category = IssueCategory.find(1) + end + + def test_create + assert IssueCategory.new(:project_id => 2, :name => 'New category').save + category = IssueCategory.first(:order => 'id DESC') + assert_equal 'New category', category.name + end + + def test_create_with_group_assignment + assert IssueCategory.new(:project_id => 2, :name => 'Group assignment', :assigned_to_id => 11).save + category = IssueCategory.first(:order => 'id DESC') + assert_kind_of Group, category.assigned_to + assert_equal Group.find(11), category.assigned_to + end + + def test_destroy + issue = @category.issues.first + @category.destroy + # Make sure the category was nullified on the issue + assert_nil issue.reload.category + end + + def test_destroy_with_reassign + issue = @category.issues.first + reassign_to = IssueCategory.find(2) + @category.destroy(reassign_to) + # Make sure the issue was reassigned + assert_equal reassign_to, issue.reload.category + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/3139e69df98621082dc93f59ee7b15298dc36628.svn-base Binary file .svn/pristine/31/3139e69df98621082dc93f59ee7b15298dc36628.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/318f04133e3e32c333e98ac7f8065761353f5042.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/31/318f04133e3e32c333e98ac7f8065761353f5042.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +class AddIssueStatusPosition < ActiveRecord::Migration + def self.up + add_column :issue_statuses, :position, :integer, :default => 1 + IssueStatus.find(:all).each_with_index {|status, i| status.update_attribute(:position, i+1)} + end + + def self.down + remove_column :issue_statuses, :position + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/31/31fa227633ea6c4259f0d7dd6d5668da6f1d4647.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/31/31fa227633ea6c4259f0d7dd6d5668da6f1d4647.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,237 @@ +/* The main calendar widget. DIV containing a table. */ + +img.calendar-trigger { + cursor: pointer; + vertical-align: middle; + margin-left: 4px; +} + +div.calendar { position: relative; z-index: 30;} + +div.calendar, div.calendar table { + border: 1px solid #556; + font-size: 11px; + color: #000; + cursor: default; + background: #fafbfc; + font-family: tahoma,verdana,sans-serif; +} + +/* Header part -- contains navigation buttons and day names. */ + +div.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ + text-align: center; /* They are the navigation buttons */ + padding: 2px; /* Make the buttons seem like they're pressing */ +} + +div.calendar .nav { + background: #467aa7; +} + +div.calendar thead .title { /* This holds the current "month, year" */ + font-weight: bold; /* Pressing it will take you to the current date */ + text-align: center; + background: #fff; + color: #000; + padding: 2px; +} + +div.calendar thead .headrow { /* Row containing navigation buttons */ + background: #467aa7; + color: #fff; +} + +div.calendar thead .daynames { /* Row containing the day names */ + background: #bdf; +} + +div.calendar thead .name { /* Cells containing the day names */ + border-bottom: 1px solid #556; + padding: 2px; + text-align: center; + color: #000; +} + +div.calendar thead .weekend { /* How a weekend day name shows in header */ + color: #a66; +} + +div.calendar thead .hilite { /* How do the buttons in header appear when hover */ + background-color: #80b0da; + color: #000; + padding: 1px; +} + +div.calendar thead .active { /* Active (pressed) buttons in header */ + background-color: #77c; + padding: 2px 0px 0px 2px; +} + +/* The body part -- contains all the days in month. */ + +div.calendar tbody .day { /* Cells containing month days dates */ + width: 2em; + color: #456; + text-align: right; + padding: 2px 4px 2px 2px; +} +div.calendar tbody .day.othermonth { + font-size: 80%; + color: #bbb; +} +div.calendar tbody .day.othermonth.oweekend { + color: #fbb; +} + +div.calendar table .wn { + padding: 2px 3px 2px 2px; + border-right: 1px solid #000; + background: #bdf; +} + +div.calendar tbody .rowhilite td { + background: #def; +} + +div.calendar tbody .rowhilite td.wn { + background: #80b0da; +} + +div.calendar tbody td.hilite { /* Hovered cells */ + background: #80b0da; + padding: 1px 3px 1px 1px; + border: 1px solid #bbb; +} + +div.calendar tbody td.active { /* Active (pressed) cells */ + background: #cde; + padding: 2px 2px 0px 2px; +} + +div.calendar tbody td.selected { /* Cell showing today date */ + font-weight: bold; + border: 1px solid #000; + padding: 1px 3px 1px 1px; + background: #fff; + color: #000; +} + +div.calendar tbody td.weekend { /* Cells showing weekend days */ + color: #a66; +} + +div.calendar tbody td.today { /* Cell showing selected date */ + font-weight: bold; + color: #f00; +} + +div.calendar tbody .disabled { color: #999; } + +div.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +div.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + +/* The footer part -- status bar and "Close" button */ + +div.calendar tfoot .footrow { /* The in footer (only one right now) */ + text-align: center; + background: #556; + color: #fff; +} + +div.calendar tfoot .ttip { /* Tooltip (status bar) cell */ + background: #fff; + color: #445; + border-top: 1px solid #556; + padding: 1px; +} + +div.calendar tfoot .hilite { /* Hover style for buttons in footer */ + background: #aaf; + border: 1px solid #04f; + color: #000; + padding: 1px; +} + +div.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ + background: #77c; + padding: 2px 0px 0px 2px; +} + +/* Combo boxes (menus that display months/years for direct selection) */ + +div.calendar .combo { + position: absolute; + display: none; + top: 0px; + left: 0px; + width: 4em; + cursor: default; + border: 1px solid #655; + background: #def; + color: #000; + font-size: 90%; + z-index: 100; +} + +div.calendar .combo .label, +div.calendar .combo .label-IEfix { + text-align: center; + padding: 1px; +} + +div.calendar .combo .label-IEfix { + width: 4em; +} + +div.calendar .combo .hilite { + background: #acf; +} + +div.calendar .combo .active { + border-top: 1px solid #46a; + border-bottom: 1px solid #46a; + background: #eef; + font-weight: bold; +} + +div.calendar td.time { + border-top: 1px solid #000; + padding: 1px 0px; + text-align: center; + background-color: #f4f0e8; +} + +div.calendar td.time .hour, +div.calendar td.time .minute, +div.calendar td.time .ampm { + padding: 0px 3px 0px 4px; + border: 1px solid #889; + font-weight: bold; + background-color: #fff; +} + +div.calendar td.time .ampm { + text-align: center; +} + +div.calendar td.time .colon { + padding: 0px 2px 0px 3px; + font-weight: bold; +} + +div.calendar td.time span.hilite { + border-color: #000; + background-color: #667; + color: #fff; +} + +div.calendar td.time span.active { + border-color: #f00; + background-color: #000; + color: #0f0; +} diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/32/32621c66778dffd99e5e7238a5aa46a6518b1b3c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/32/32621c66778dffd99e5e7238a5aa46a6518b1b3c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,304 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 IssuesHelper + include ApplicationHelper + + def issue_list(issues, &block) + ancestors = [] + issues.each do |issue| + while (ancestors.any? && !issue.is_descendant_of?(ancestors.last)) + ancestors.pop + end + yield issue, ancestors.size + ancestors << issue unless issue.leaf? + end + end + + # Renders a HTML/CSS tooltip + # + # To use, a trigger div is needed. This is a div with the class of "tooltip" + # that contains this method wrapped in a span with the class of "tip" + # + #
<%= link_to_issue(issue) %> + # <%= render_issue_tooltip(issue) %> + #
+ # + def render_issue_tooltip(issue) + @cached_label_status ||= l(:field_status) + @cached_label_start_date ||= l(:field_start_date) + @cached_label_due_date ||= l(:field_due_date) + @cached_label_assigned_to ||= l(:field_assigned_to) + @cached_label_priority ||= l(:field_priority) + @cached_label_project ||= l(:field_project) + + (link_to_issue(issue) + "

" + + "#{@cached_label_project}: #{link_to_project(issue.project)}
" + + "#{@cached_label_status}: #{h(issue.status.name)}
" + + "#{@cached_label_start_date}: #{format_date(issue.start_date)}
" + + "#{@cached_label_due_date}: #{format_date(issue.due_date)}
" + + "#{@cached_label_assigned_to}: #{h(issue.assigned_to)}
" + + "#{@cached_label_priority}: #{h(issue.priority.name)}").html_safe + end + + def issue_heading(issue) + h("#{issue.tracker} ##{issue.id}") + end + + def render_issue_subject_with_tree(issue) + s = '' + ancestors = issue.root? ? [] : issue.ancestors.visible.all + ancestors.each do |ancestor| + s << '
' + content_tag('p', link_to_issue(ancestor)) + end + s << '
' + subject = h(issue.subject) + if issue.is_private? + subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject + end + s << content_tag('h3', subject) + s << '
' * (ancestors.size + 1) + s.html_safe + end + + def render_descendants_tree(issue) + s = '
' + issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level| + s << content_tag('tr', + content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') + + content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') + + content_tag('td', h(child.status)) + + content_tag('td', link_to_user(child.assigned_to)) + + content_tag('td', progress_bar(child.done_ratio, :width => '80px')), + :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}") + end + s << '
' + s.html_safe + end + + def render_custom_fields_rows(issue) + return if issue.custom_field_values.empty? + ordered_values = [] + half = (issue.custom_field_values.size / 2.0).ceil + half.times do |i| + ordered_values << issue.custom_field_values[i] + ordered_values << issue.custom_field_values[i + half] + end + s = "\n" + n = 0 + ordered_values.compact.each do |value| + s << "\n\n" if n > 0 && (n % 2) == 0 + s << "\t#{ h(value.custom_field.name) }:#{ simple_format_without_paragraph(h(show_value(value))) }\n" + n += 1 + end + s << "\n" + s.html_safe + end + + def issues_destroy_confirmation_message(issues) + issues = [issues] unless issues.is_a?(Array) + message = l(:text_issues_destroy_confirmation) + descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2} + if descendant_count > 0 + issues.each do |issue| + next if issue.root? + issues.each do |other_issue| + descendant_count -= 1 if issue.is_descendant_of?(other_issue) + end + end + if descendant_count > 0 + message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count) + end + end + message + end + + def sidebar_queries + unless @sidebar_queries + # User can see public queries and his own queries + visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)]) + # Project specific queries and global queries + visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]) + @sidebar_queries = Query.find(:all, + :select => 'id, name, is_public', + :order => "name ASC", + :conditions => visible.conditions) + end + @sidebar_queries + end + + def query_links(title, queries) + # links to #index on issues/show + url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params + + content_tag('h3', h(title)) + + queries.collect {|query| + link_to(h(query.name), url_params.merge(:query_id => query)) + }.join('
') + end + + def render_sidebar_queries + out = '' + queries = sidebar_queries.select {|q| !q.is_public?} + out << query_links(l(:label_my_queries), queries) if queries.any? + queries = sidebar_queries.select {|q| q.is_public?} + out << query_links(l(:label_query_plural), queries) if queries.any? + out + end + + def show_detail(detail, no_html=false) + case detail.property + when 'attr' + field = detail.prop_key.to_s.gsub(/\_id$/, "") + label = l(("field_" + field).to_sym) + case + when ['due_date', 'start_date'].include?(detail.prop_key) + value = format_date(detail.value.to_date) if detail.value + old_value = format_date(detail.old_value.to_date) if detail.old_value + + when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key) + value = find_name_by_reflection(field, detail.value) + old_value = find_name_by_reflection(field, detail.old_value) + + when detail.prop_key == 'estimated_hours' + value = "%0.02f" % detail.value.to_f unless detail.value.blank? + old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank? + + when detail.prop_key == 'parent_id' + label = l(:field_parent_issue) + value = "##{detail.value}" unless detail.value.blank? + old_value = "##{detail.old_value}" unless detail.old_value.blank? + + when detail.prop_key == 'is_private' + value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? + old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? + end + when 'cf' + custom_field = CustomField.find_by_id(detail.prop_key) + if custom_field + label = custom_field.name + value = format_value(detail.value, custom_field.field_format) if detail.value + old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value + end + when 'attachment' + label = l(:label_attachment) + end + call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value }) + + label ||= detail.prop_key + value ||= detail.value + old_value ||= detail.old_value + + unless no_html + label = content_tag('strong', label) + old_value = content_tag("i", h(old_value)) if detail.old_value + old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank? + if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key) + # Link to the attachment if it has not been removed + value = link_to_attachment(a) + else + value = content_tag("i", h(value)) if value + end + end + + if detail.property == 'attr' && detail.prop_key == 'description' + s = l(:text_journal_changed_no_detail, :label => label) + unless no_html + diff_link = link_to 'diff', + {:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id}, + :title => l(:label_view_diff) + s << " (#{ diff_link })" + end + s + elsif !detail.value.blank? + case detail.property + when 'attr', 'cf' + if !detail.old_value.blank? + l(:text_journal_changed, :label => label, :old => old_value, :new => value) + else + l(:text_journal_set_to, :label => label, :value => value) + end + when 'attachment' + l(:text_journal_added, :label => label, :value => value) + end + else + l(:text_journal_deleted, :label => label, :old => old_value) + end + end + + # Find the name of an associated record stored in the field attribute + def find_name_by_reflection(field, id) + association = Issue.reflect_on_association(field.to_sym) + if association + record = association.class_name.constantize.find_by_id(id) + return record.name if record + end + end + + # Renders issue children recursively + def render_api_issue_children(issue, api) + return if issue.leaf? + api.array :children do + issue.children.each do |child| + api.issue(:id => child.id) do + api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil? + api.subject child.subject + render_api_issue_children(child, api) + end + end + end + end + + def issues_to_csv(issues, project, query, options={}) + decimal_separator = l(:general_csv_decimal_separator) + encoding = l(:general_csv_encoding) + columns = (options[:columns] == 'all' ? query.available_columns : query.columns) + + export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + # csv header fields + csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + + (options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : []) + + # csv lines + issues.each do |issue| + col_values = columns.collect do |column| + s = if column.is_a?(QueryCustomFieldColumn) + cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} + show_value(cv) + else + value = issue.send(column.name) + if value.is_a?(Date) + format_date(value) + elsif value.is_a?(Time) + format_time(value) + elsif value.is_a?(Float) + value.to_s.gsub('.', decimal_separator) + else + value + end + end + s.to_s + end + csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } + + (options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : []) + end + end + export + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/32/328e5d644f9c7f34ce3b37165d648bfc6611fce5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/32/328e5d644f9c7f34ce3b37165d648bfc6611fce5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +class AddCustomFieldsPosition < ActiveRecord::Migration + def self.up + add_column(:custom_fields, :position, :integer, :default => 1) + CustomField.find(:all).group_by(&:type).each do |t, fields| + fields.each_with_index do |field, i| + # do not call model callbacks + CustomField.update_all "position = #{i+1}", {:id => field.id} + end + end + end + + def self.down + remove_column :custom_fields, :position + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/32/32d6d2763efb421cb7068135f9bd0b5ba898d1a2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/32/32d6d2763efb421cb7068135f9bd0b5ba898d1a2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +Put your Redmine themes here. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/32/32f548872e7dda9a87d4e449afcdf5184ca9059d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/32/32f548872e7dda9a87d4e449afcdf5184ca9059d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,87 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array ("日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array ("日", "月", "火", "水", "木", "金", "土"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array ("1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"); + +// short month names +Calendar._SMN = new Array ("1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "このカレンダーについて"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"日付の選択方法:\n" + +"- \xab, \xbb ボタンで年を選択。\n" + +"- " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " ボタンで年を選択。\n" + +"- 上記ボタンの長押しでメニューから選択。"; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "前年 (長押しでメニュー表示)"; +Calendar._TT["PREV_MONTH"] = "前月 (長押しでメニュー表示)"; +Calendar._TT["GO_TODAY"] = "今日の日付を選択"; +Calendar._TT["NEXT_MONTH"] = "翌月 (長押しでメニュー表示)"; +Calendar._TT["NEXT_YEAR"] = "翌年 (長押しでメニュー表示)"; +Calendar._TT["SEL_DATE"] = "日付を選択してください"; +Calendar._TT["DRAG_TO_MOVE"] = "ドラッグで移動"; +Calendar._TT["PART_TODAY"] = " (今日)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s始まりで表示"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "閉じる"; +Calendar._TT["TODAY"] = "今日"; +Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%b%e日(%a)"; + +Calendar._TT["WK"] = "週"; +Calendar._TT["TIME"] = "Time:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/33275847ce5564fa4ff57de7cb764a0f4a778730.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/33275847ce5564fa4ff57de7cb764a0f4a778730.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +

<%=l(:label_report_plural)%>

+ +
+

<%=l(:field_tracker)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'tracker' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> +
+

<%=l(:field_priority)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'priority' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> +
+

<%=l(:field_assigned_to)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'assigned_to' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => "assigned_to_id", :rows => @assignees } %> +
+

<%=l(:field_author)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'author' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> +
+<%= call_hook(:view_reports_issue_report_split_content_left, :project => @project) %> +
+ +
+

<%=l(:field_version)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'version' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_version, :field_name => "fixed_version_id", :rows => @versions } %> +
+<% if @project.children.any? %> +

<%=l(:field_subproject)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'subproject' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => "project_id", :rows => @subprojects } %> +
+<% end %> +

<%=l(:field_category)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'category' %>

+<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> +
+<%= call_hook(:view_reports_issue_report_split_content_right, :project => @project) %> +
+ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/332beac4e5a854120b53b926beb38dfe9376b34a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/332beac4e5a854120b53b926beb38dfe9376b34a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Search + + mattr_accessor :available_search_types + + @@available_search_types = [] + + class << self + def map(&block) + yield self + end + + # Registers a search provider + def register(search_type, options={}) + search_type = search_type.to_s + @@available_search_types << search_type unless @@available_search_types.include?(search_type) + end + end + + module Controller + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + @@default_search_scopes = Hash.new {|hash, key| hash[key] = {:default => nil, :actions => {}}} + mattr_accessor :default_search_scopes + + # Set the default search scope for a controller or specific actions + # Examples: + # * search_scope :issues # => sets the search scope to :issues for the whole controller + # * search_scope :issues, :only => :index + # * search_scope :issues, :only => [:index, :show] + def default_search_scope(id, options = {}) + if actions = options[:only] + actions = [] << actions unless actions.is_a?(Array) + actions.each {|a| default_search_scopes[controller_name.to_sym][:actions][a.to_sym] = id.to_s} + else + default_search_scopes[controller_name.to_sym][:default] = id.to_s + end + end + end + + def default_search_scopes + self.class.default_search_scopes + end + + # Returns the default search scope according to the current action + def default_search_scope + @default_search_scope ||= default_search_scopes[controller_name.to_sym][:actions][action_name.to_sym] || + default_search_scopes[controller_name.to_sym][:default] + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/332d3d52b592a1156755d111d7a6b0f8eac58495.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/332d3d52b592a1156755d111d7a6b0f8eac58495.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,83 @@ +<%= error_messages_for 'member' %> +<% roles = Role.find_all_givable + members = @project.member_principals.find(:all, :include => [:roles, :principal]).sort %> + +
+<% if members.any? %> + + + + + + <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %> + + + <% members.each do |member| %> + <% next if member.new_record? %> + + + + + <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %> + +<% end; reset_cycle %> + +
<%= l(:label_user) %> / <%= l(:label_group) %><%= l(:label_role_plural) %>
<%= link_to_user member.principal %> + <%=h member.roles.sort.collect(&:to_s).join(', ') %> + <% if authorize_for('members', 'edit') %> + <% remote_form_for(:member, member, :url => {:controller => 'members', :action => 'edit', :id => member}, + :method => :post, + :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }) do |f| %> +

<% roles.each do |role| %> +
+ <% end %>

+ <%= hidden_field_tag 'member[role_ids][]', '' %> +

<%= submit_tag l(:button_change), :class => "small" %> + <%= link_to_function l(:button_cancel), "$('member-#{member.id}-roles').show(); $('member-#{member.id}-roles-form').hide(); return false;" %>

+ <% end %> + <% end %> +
+ <%= link_to_function l(:button_edit), "$('member-#{member.id}-roles').hide(); $('member-#{member.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %> + <%= link_to_remote(l(:button_delete), { :url => {:controller => 'members', :action => 'destroy', :id => member}, + :method => :post, + :confirm => (!User.current.admin? && member.include?(User.current) ? l(:text_own_membership_delete_confirmation) : nil) + }, :title => l(:button_delete), + :class => 'icon icon-del') if member.deletable? %> +
+<% else %> +

<%= l(:label_no_data) %>

+<% end %> +
+ +<% principals = Principal.active.find(:all, :limit => 100, :order => 'type, login, lastname ASC') - @project.principals %> + +
+<% if roles.any? && principals.any? %> + <% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post, + :loading => '$(\'member-add-submit\').disable();', + :complete => 'if($(\'member-add-submit\')) $(\'member-add-submit\').enable();') do |f| %> +
<%=l(:label_member_new)%> + +

<%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %>

+ <%= observe_field(:principal_search, + :frequency => 0.5, + :update => :principals, + :url => { :controller => 'members', :action => 'autocomplete_for_member', :id => @project }, + :with => 'q') + %> + +
+ <%= principals_check_box_tags 'member[user_ids][]', principals %> +
+ +

<%= l(:label_role_plural) %>: + <% roles.each do |role| %> + + <% end %>

+ +

<%= submit_tag l(:button_add), :id => 'member-add-submit' %>

+
+ <% end %> +<% end %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/334064fdd6c0e2bb410ee3b77bdb35e019b3487f.svn-base Binary file .svn/pristine/33/334064fdd6c0e2bb410ee3b77bdb35e019b3487f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/3349206fec5e88c2e11146378e031801f405150d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/3349206fec5e88c2e11146378e031801f405150d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev %> +<% +dirs = path.split('/') +if 'file' == kind + filename = dirs.pop +end +link_path = '' +dirs.each do |dir| + next if dir.blank? + link_path << '/' unless link_path.empty? + link_path << "#{dir}" + %> + / <%= link_to h(dir), :action => 'show', :id => @project, + :path => to_path_param(link_path), :rev => @rev %> +<% end %> +<% if filename %> + / <%= link_to h(filename), + :action => 'changes', :id => @project, + :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> +<% end %> +<% + # @rev is revsion or Git and Mercurial branch or tag. + # For Mercurial *tip*, @rev and @changeset are nil. + rev_text = @changeset.nil? ? @rev : format_revision(@changeset) +%> +<%= "@ #{h rev_text}" unless rev_text.blank? %> + +<% html_title(with_leading_slash(path)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/3357225f79b9b7908f02d51c4dcc557f0e92041e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/3357225f79b9b7908f02d51c4dcc557f0e92041e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,388 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class GitAdapter < AbstractAdapter + + # Git executable name + GIT_BIN = Redmine::Configuration['scm_git_command'] || "git" + + class << self + def client_command + @@bin ||= GIT_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + !client_version.empty? + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + super + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def info + begin + Info.new(:root_url => url, :lastrev => lastrev('',nil)) + rescue + nil + end + end + + def branches + return @branches if @branches + @branches = [] + cmd_args = %w|branch --no-color --verbose --no-abbrev| + scm_cmd(*cmd_args) do |io| + io.each_line do |line| + branch_rev = line.match('\s*\*?\s*(.*?)\s*([0-9a-f]{40}).*$') + bran = Branch.new(branch_rev[1]) + bran.revision = branch_rev[2] + bran.scmid = branch_rev[2] + @branches << bran + end + end + @branches.sort! + rescue ScmCommandAborted + nil + end + + def tags + return @tags if @tags + cmd_args = %w|tag| + scm_cmd(*cmd_args) do |io| + @tags = io.readlines.sort!.map{|t| t.strip} + end + rescue ScmCommandAborted + nil + end + + def default_branch + bras = self.branches + return nil if bras.nil? + bras.include?('master') ? 'master' : bras.first + end + + def entry(path=nil, identifier=nil) + parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} + search_path = parts[0..-2].join('/') + search_name = parts[-1] + if search_path.blank? && search_name.blank? + # Root entry + Entry.new(:path => '', :kind => 'dir') + else + # Search for the entry in the parent directory + es = entries(search_path, identifier, + options = {:report_last_commit => false}) + es ? es.detect {|e| e.name == search_name} : nil + end + end + + def entries(path=nil, identifier=nil, options={}) + path ||= '' + p = scm_iconv(@path_encoding, 'UTF-8', path) + entries = Entries.new + cmd_args = %w|ls-tree -l| + cmd_args << "HEAD:#{p}" if identifier.nil? + cmd_args << "#{identifier}:#{p}" if identifier + scm_cmd(*cmd_args) do |io| + io.each_line do |line| + e = line.chomp.to_s + if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/ + type = $1 + sha = $2 + size = $3 + name = $4 + if name.respond_to?(:force_encoding) + name.force_encoding(@path_encoding) + end + full_path = p.empty? ? name : "#{p}/#{name}" + n = scm_iconv('UTF-8', @path_encoding, name) + full_p = scm_iconv('UTF-8', @path_encoding, full_path) + entries << Entry.new({:name => n, + :path => full_p, + :kind => (type == "tree") ? 'dir' : 'file', + :size => (type == "tree") ? nil : size, + :lastrev => options[:report_last_commit] ? + lastrev(full_path, identifier) : Revision.new + }) unless entries.detect{|entry| entry.name == name} + end + end + end + entries.sort_by_name + rescue ScmCommandAborted + nil + end + + def lastrev(path, rev) + return nil if path.nil? + cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1| + cmd_args << rev if rev + cmd_args << "--" << path unless path.empty? + lines = [] + scm_cmd(*cmd_args) { |io| lines = io.readlines } + begin + id = lines[0].split[1] + author = lines[1].match('Author:\s+(.*)$')[1] + time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1]) + + Revision.new({ + :identifier => id, + :scmid => id, + :author => author, + :time => time, + :message => nil, + :paths => nil + }) + rescue NoMethodError => e + logger.error("The revision '#{path}' has a wrong format") + return nil + end + rescue ScmCommandAborted + nil + end + + def revisions(path, identifier_from, identifier_to, options={}) + revs = Revisions.new + cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents| + cmd_args << "--reverse" if options[:reverse] + cmd_args << "--all" if options[:all] + cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit] + from_to = "" + from_to << "#{identifier_from}.." if identifier_from + from_to << "#{identifier_to}" if identifier_to + cmd_args << from_to if !from_to.empty? + cmd_args << "--since=#{options[:since].strftime("%Y-%m-%d %H:%M:%S")}" if options[:since] + cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty? + + scm_cmd *cmd_args do |io| + files=[] + changeset = {} + parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files + + io.each_line do |line| + if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/ + key = "commit" + value = $1 + parents_str = $2 + if (parsing_descr == 1 || parsing_descr == 2) + parsing_descr = 0 + revision = Revision.new({ + :identifier => changeset[:commit], + :scmid => changeset[:commit], + :author => changeset[:author], + :time => Time.parse(changeset[:date]), + :message => changeset[:description], + :paths => files, + :parents => changeset[:parents] + }) + if block_given? + yield revision + else + revs << revision + end + changeset = {} + files = [] + end + changeset[:commit] = $1 + unless parents_str.nil? or parents_str == "" + changeset[:parents] = parents_str.strip.split(' ') + end + elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/ + key = $1 + value = $2 + if key == "Author" + changeset[:author] = value + elsif key == "CommitDate" + changeset[:date] = value + end + elsif (parsing_descr == 0) && line.chomp.to_s == "" + parsing_descr = 1 + changeset[:description] = "" + elsif (parsing_descr == 1 || parsing_descr == 2) \ + && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/ + parsing_descr = 2 + fileaction = $1 + filepath = $2 + p = scm_iconv('UTF-8', @path_encoding, filepath) + files << {:action => fileaction, :path => p} + elsif (parsing_descr == 1 || parsing_descr == 2) \ + && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/ + parsing_descr = 2 + fileaction = $1 + filepath = $3 + p = scm_iconv('UTF-8', @path_encoding, filepath) + files << {:action => fileaction, :path => p} + elsif (parsing_descr == 1) && line.chomp.to_s == "" + parsing_descr = 2 + elsif (parsing_descr == 1) + changeset[:description] << line[4..-1] + end + end + + if changeset[:commit] + revision = Revision.new({ + :identifier => changeset[:commit], + :scmid => changeset[:commit], + :author => changeset[:author], + :time => Time.parse(changeset[:date]), + :message => changeset[:description], + :paths => files, + :parents => changeset[:parents] + }) + if block_given? + yield revision + else + revs << revision + end + end + end + revs + rescue ScmCommandAborted => e + logger.error("git log #{from_to.to_s} error: #{e.message}") + revs + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + cmd_args = [] + if identifier_to + cmd_args << "diff" << "--no-color" << identifier_to << identifier_from + else + cmd_args << "show" << "--no-color" << identifier_from + end + cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty? + diff = [] + scm_cmd *cmd_args do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue ScmCommandAborted + nil + end + + def annotate(path, identifier=nil) + identifier = 'HEAD' if identifier.blank? + cmd_args = %w|blame| + cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path) + blame = Annotate.new + content = nil + scm_cmd(*cmd_args) { |io| io.binmode; content = io.read } + # git annotates binary files + return nil if content.is_binary_data? + identifier = '' + # git shows commit author on the first occurrence only + authors_by_commit = {} + content.split("\n").each do |line| + if line =~ /^([0-9a-f]{39,40})\s.*/ + identifier = $1 + elsif line =~ /^author (.+)/ + authors_by_commit[identifier] = $1.strip + elsif line =~ /^\t(.*)/ + blame.add_line($1, Revision.new( + :identifier => identifier, + :revision => identifier, + :scmid => identifier, + :author => authors_by_commit[identifier] + )) + identifier = '' + author = '' + end + end + blame + rescue ScmCommandAborted + nil + end + + def cat(path, identifier=nil) + if identifier.nil? + identifier = 'HEAD' + end + cmd_args = %w|show --no-color| + cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}" + cat = nil + scm_cmd(*cmd_args) do |io| + io.binmode + cat = io.read + end + cat + rescue ScmCommandAborted + nil + end + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + identifier[0,8] + end + end + + def scm_cmd(*args, &block) + repo_path = root_url || url + full_args = ['--git-dir', repo_path] + if self.class.client_version_above?([1, 7, 2]) + full_args << '-c' << 'core.quotepath=false' + full_args << '-c' << 'log.decorate=no' + end + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/33735f1e27040c23a0be5f08f9793049e1a2b35d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/33735f1e27040c23a0be5f08f9793049e1a2b35d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Подебљано'; +jsToolBar.strings['Italic'] = 'Курзив'; +jsToolBar.strings['Underline'] = 'Подвучено'; +jsToolBar.strings['Deleted'] = 'Обрисано'; +jsToolBar.strings['Code'] = 'Уграђени кôд'; +jsToolBar.strings['Heading 1'] = 'Наслов 1'; +jsToolBar.strings['Heading 2'] = 'Наслов 2'; +jsToolBar.strings['Heading 3'] = 'Наслов 3'; +jsToolBar.strings['Unordered list'] = 'Листа набрајања'; +jsToolBar.strings['Ordered list'] = 'Уређена листа'; +jsToolBar.strings['Quote'] = 'Под наводницима'; +jsToolBar.strings['Unquote'] = 'Уклони наводнике'; +jsToolBar.strings['Preformatted text'] = 'Претходно форматиран текст'; +jsToolBar.strings['Wiki link'] = 'Веза према Wiki страни'; +jsToolBar.strings['Image'] = 'Слика'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/339298a5f0f39e0023eec53de59bce2a01d6d690.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/339298a5f0f39e0023eec53de59bce2a01d6d690.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToComments < ActiveRecord::Migration + def self.up + add_index :comments, [:commented_id, :commented_type] + add_index :comments, :author_id + end + + def self.down + remove_index :comments, :column => [:commented_id, :commented_type] + remove_index :comments, :author_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/3396ee85e7860d58bce2840b1f00fae7a535409f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/3396ee85e7860d58bce2840b1f00fae7a535409f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +module TestHelper + def self.report_location(path) + [RAILS_ROOT + '/', 'vendor/plugins/'].each { |part| path.sub! part, ''} + path = path.split('/') + location, subject = path.first, path.last + if subject.sub! '.rb', '' + subject = subject.classify + else + subject.sub! '.html.erb', '' + end + "#{subject} (from #{location})" + end + + def self.view_path_for path + [RAILS_ROOT + '/', 'vendor/plugins/', '.html.erb'].each { |part| path.sub! part, ''} + parts = path.split('/') + parts[(parts.index('views')+1)..-1].join('/') + end +end + +class Test::Unit::TestCase + # Add more helper methods to be used by all tests here... + def get_action_on_controller(*args) + action = args.shift + with_controller *args + get action + end + + def with_controller(controller, namespace = nil) + classname = controller.to_s.classify + 'Controller' + classname = namespace.to_s.classify + '::' + classname unless namespace.nil? + @controller = classname.constantize.new + end + + def assert_response_body(expected) + assert_equal expected, @response.body + end +end + +# Because we're testing this behaviour, we actually want these features on! +Engines.disable_application_view_loading = false +Engines.disable_application_code_loading = false diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/339e744cec4e7135848bd091a8aa59a4585d0f11.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/339e744cec4e7135848bd091a8aa59a4585d0f11.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddVersionsWikiPageTitle < ActiveRecord::Migration + def self.up + add_column :versions, :wiki_page_title, :string + end + + def self.down + remove_column :versions, :wiki_page_title + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/33/33a69333d665b6d06e88fdb324d960ab74dff338.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/33/33a69333d665b6d06e88fdb324d960ab74dff338.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +module CodeRay + + # The result of a scan operation is a TokensProxy, but should act like Tokens. + # + # This proxy makes it possible to use the classic CodeRay.scan.encode API + # while still providing the benefits of direct streaming. + class TokensProxy + + attr_accessor :input, :lang, :options, :block + + # Create a new TokensProxy with the arguments of CodeRay.scan. + def initialize input, lang, options = {}, block = nil + @input = input + @lang = lang + @options = options + @block = block + end + + # Call CodeRay.encode if +encoder+ is a Symbol; + # otherwise, convert the receiver to tokens and call encoder.encode_tokens. + def encode encoder, options = {} + if encoder.respond_to? :to_sym + CodeRay.encode(input, lang, encoder, options) + else + encoder.encode_tokens tokens, options + end + end + + # Tries to call encode; + # delegates to tokens otherwise. + def method_missing method, *args, &blk + encode method.to_sym, *args + rescue PluginHost::PluginNotFound + tokens.send(method, *args, &blk) + end + + # The (cached) result of the tokenized input; a Tokens instance. + def tokens + @tokens ||= scanner.tokenize(input) + end + + # A (cached) scanner instance to use for the scan task. + def scanner + @scanner ||= CodeRay.scanner(lang, options, &block) + end + + # Overwrite Struct#each. + def each *args, &blk + tokens.each(*args, &blk) + self + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/341712110e6c8b5fef912215a71a7cdd1b0920e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/341712110e6c8b5fef912215a71a7cdd1b0920e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,187 @@ +This is the language coverage file for DejaVu fonts +($Id: langcover.txt 1586 2007-02-18 16:07:32Z ben_laenen $) + + Sans Serif Sans Mono +aa Afar 100% (62/62) 100% (62/62) 100% (62/62) +ab Abkhazia 100% (90/90) 93% (84/90) 84% (76/90) +af Afrikaans 100% (69/69) 100% (69/69) 100% (69/69) +am Amharic (0/264) (0/264) (0/264) +ar Arabic 100% (125/125) (0/125) (0/125) +ast Asturian 100% (72/72) 100% (72/72) 100% (72/72) +ava Avaric 100% (67/67) 100% (67/67) 100% (67/67) +ay Aymara 100% (60/60) 100% (60/60) 100% (60/60) +az Azerbaijani 100% (148/148) 97% (144/148) 97% (144/148) +az-ir Azerbaijani in Iran 100% (130/130) (0/130) (0/130) +ba Bashkir 100% (82/82) 100% (82/82) 97% (80/82) +bam Bambara 100% (60/60) 100% (60/60) 100% (60/60) +be Byelorussian 100% (68/68) 100% (68/68) 100% (68/68) +bg Bulgarian 100% (60/60) 100% (60/60) 100% (60/60) +bh Bihari (Devanagari script) (0/68) (0/68) (0/68) +bho Bhojpuri (Devanagari script) (0/68) (0/68) (0/68) +bi Bislama 100% (58/58) 100% (58/58) 100% (58/58) +bin Edo or Bini 100% (78/78) 100% (78/78) 100% (78/78) +bn Bengali (0/89) (0/89) (0/89) +bo Tibetan (0/95) (0/95) (0/95) +br Breton 100% (64/64) 100% (64/64) 100% (64/64) +bs Bosnian 100% (62/62) 100% (62/62) 100% (62/62) +bua Buriat (Buryat) 100% (70/70) 100% (70/70) 100% (70/70) +ca Catalan 100% (74/74) 100% (74/74) 100% (74/74) +ce Chechen 100% (67/67) 100% (67/67) 100% (67/67) +ch Chamorro 100% (58/58) 100% (58/58) 100% (58/58) +chm Mari (Lower Cheremis / Upper Cheremis) 100% (76/76) 100% (76/76) 97% (74/76) +chr Cherokee (0/85) (0/85) (0/85) +co Corsican 100% (84/84) 100% (84/84) 100% (84/84) +cs Czech 100% (82/82) 100% (82/82) 100% (82/82) +cu Old Church Slavonic 100% (103/103) 80% (83/103) 74% (77/103) +cv Chuvash 100% (74/74) 100% (74/74) 100% (74/74) +cy Welsh 100% (78/78) 100% (78/78) 100% (78/78) +da Danish 100% (70/70) 100% (70/70) 100% (70/70) +de German 100% (59/59) 100% (59/59) 100% (59/59) +dz Dzongkha (0/95) (0/95) (0/95) +el Greek 100% (69/69) 100% (69/69) 100% (69/69) +en English 100% (72/72) 100% (72/72) 100% (72/72) +eo Esperanto 100% (64/64) 100% (64/64) 100% (64/64) +es Spanish 100% (66/66) 100% (66/66) 100% (66/66) +et Estonian 100% (64/64) 100% (64/64) 100% (64/64) +eu Basque 100% (56/56) 100% (56/56) 100% (56/56) +fa Persian 100% (129/129) (0/129) (0/129) +fi Finnish 100% (62/62) 100% (62/62) 100% (62/62) +fj Fijian 100% (52/52) 100% (52/52) 100% (52/52) +fo Faroese 100% (68/68) 100% (68/68) 100% (68/68) +fr French 100% (84/84) 100% (84/84) 100% (84/84) +ful Fulah (Fula) 100% (62/62) 100% (62/62) 100% (62/62) +fur Friulian 100% (66/66) 100% (66/66) 100% (66/66) +fy Frisian 100% (75/75) 100% (75/75) 100% (75/75) +ga Irish 100% (80/80) 100% (80/80) 100% (80/80) +gd Scots Gaelic 100% (70/70) 100% (70/70) 100% (70/70) +gez Ethiopic (Geez) (0/218) (0/218) (0/218) +gl Galician 100% (66/66) 100% (66/66) 100% (66/66) +gn Guarani 100% (70/70) 100% (70/70) 100% (70/70) +gu Gujarati (0/78) (0/78) (0/78) +gv Manx Gaelic 100% (54/54) 100% (54/54) 100% (54/54) +ha Hausa 100% (60/60) 100% (60/60) 100% (60/60) +haw Hawaiian 100% (63/63) 100% (63/63) 100% (63/63) +he Hebrew 100% (27/27) (0/27) (0/27) +hi Hindi (Devanagari script) (0/68) (0/68) (0/68) +ho Hiri Motu 100% (52/52) 100% (52/52) 100% (52/52) +hr Croatian 100% (62/62) 100% (62/62) 100% (62/62) +hu Hungarian 100% (70/70) 100% (70/70) 100% (70/70) +hy Armenian 100% (77/77) (0/77) (0/77) +ia Interlingua 100% (52/52) 100% (52/52) 100% (52/52) +ibo Igbo 100% (58/58) 100% (58/58) 100% (58/58) +id Indonesian 100% (54/54) 100% (54/54) 100% (54/54) +ie Interlingue 100% (52/52) 100% (52/52) 100% (52/52) +ik Inupiaq (Inupiak, Eskimo) 100% (68/68) 100% (68/68) 100% (68/68) +io Ido 100% (52/52) 100% (52/52) 100% (52/52) +is Icelandic 100% (70/70) 100% (70/70) 100% (70/70) +it Italian 100% (72/72) 100% (72/72) 100% (72/72) +iu Inuktitut 100% (161/161) (0/161) (0/161) +ja Japanese (0/6538) (0/6538) (0/6538) +ka Georgian (0/34) (0/34) (0/34) +kaa Kara-Kalpak (Karakalpak) 100% (78/78) 100% (78/78) 100% (78/78) +ki Kikuyu 100% (56/56) 100% (56/56) 100% (56/56) +kk Kazakh 100% (77/77) 100% (77/77) 100% (77/77) +kl Greenlandic 100% (81/81) 100% (81/81) 100% (81/81) +km Khmer (0/70) (0/70) (0/70) +kn Kannada (0/80) (0/80) (0/80) +ko Korean (0/2443) (0/2443) (0/2443) +kok Kokani (Devanagari script) (0/68) (0/68) (0/68) +ks Kashmiri (Devanagari script) (0/68) (0/68) (0/68) +ku Kurdish 100% (64/64) 100% (64/64) 100% (64/64) +ku-ir Kurdish in Iran 100% (32/32) (0/32) (0/32) +kum Kumyk 100% (66/66) 100% (66/66) 100% (66/66) +kv Komi (Komi-Permyak/Komi-Siryan) 100% (70/70) 100% (70/70) 100% (70/70) +kw Cornish 100% (64/64) 100% (64/64) 100% (64/64) +ky Kirgiz 100% (70/70) 100% (70/70) 100% (70/70) +la Latin 100% (68/68) 100% (68/68) 100% (68/68) +lb Luxembourgish (Letzeburgesch) 100% (75/75) 100% (75/75) 100% (75/75) +lez Lezghian (Lezgian) 100% (67/67) 100% (67/67) 100% (67/67) +lo Lao 84% (55/65) (0/65) 43% (28/65) +lt Lithuanian 100% (70/70) 100% (70/70) 100% (70/70) +lv Latvian 100% (78/78) 100% (78/78) 100% (78/78) +mg Malagasy 100% (56/56) 100% (56/56) 100% (56/56) +mh Marshallese 100% (62/62) 100% (62/62) 100% (62/62) +mi Maori 100% (64/64) 100% (64/64) 100% (64/64) +mk Macedonian 100% (42/42) 100% (42/42) 100% (42/42) +ml Malayalam (0/78) (0/78) (0/78) +mn Mongolian (0/130) (0/130) (0/130) +mo Moldavian 100% (128/128) 100% (128/128) 100% (128/128) +mr Marathi (Devanagari script) (0/68) (0/68) (0/68) +mt Maltese 100% (72/72) 100% (72/72) 100% (72/72) +my Burmese (Myanmar) (0/48) (0/48) (0/48) +nb Norwegian Bokmal 100% (70/70) 100% (70/70) 100% (70/70) +nds Low Saxon 100% (59/59) 100% (59/59) 100% (59/59) +ne Nepali (Devanagari script) (0/68) (0/68) (0/68) +nl Dutch 100% (82/82) 100% (82/82) 100% (82/82) +nn Norwegian Nynorsk 100% (76/76) 100% (76/76) 100% (76/76) +no Norwegian (Bokmal) 100% (70/70) 100% (70/70) 100% (70/70) +ny Chichewa 100% (54/54) 100% (54/54) 100% (54/54) +oc Occitan 100% (70/70) 100% (70/70) 100% (70/70) +om Oromo or Galla 100% (52/52) 100% (52/52) 100% (52/52) +or Oriya (0/79) (0/79) (0/79) +os Ossetic 100% (66/66) 100% (66/66) 100% (66/66) +pa Punjabi (Gurumukhi script) (0/63) (0/63) (0/63) +pl Polish 100% (70/70) 100% (70/70) 100% (70/70) +ps-af Pashto in Afghanistan 83% (41/49) (0/49) (0/49) +ps-pk Pashto in Pakistan 81% (40/49) (0/49) (0/49) +pt Portuguese 100% (82/82) 100% (82/82) 100% (82/82) +rm Rhaeto-Romance (Romansch) 100% (66/66) 100% (66/66) 100% (66/66) +ro Romanian 100% (62/62) 100% (62/62) 100% (62/62) +ru Russian 100% (66/66) 100% (66/66) 100% (66/66) +sa Sanskrit (Devanagari script) (0/68) (0/68) (0/68) +sah Yakut 100% (76/76) 100% (76/76) 97% (74/76) +sco Scots 100% (56/56) 96% (54/56) 96% (54/56) +se North Sami 100% (66/66) 100% (66/66) 100% (66/66) +sel Selkup (Ostyak-Samoyed) 100% (66/66) 100% (66/66) 100% (66/66) +sh Serbo-Croatian 100% (76/76) 100% (76/76) 100% (76/76) +si Sinhala (Sinhalese) (0/77) (0/77) (0/77) +sk Slovak 100% (86/86) 100% (86/86) 100% (86/86) +sl Slovenian 100% (62/62) 100% (62/62) 100% (62/62) +sm Samoan 100% (53/53) 100% (53/53) 100% (53/53) +sma South Sami 100% (60/60) 100% (60/60) 100% (60/60) +smj Lule Sami 100% (60/60) 100% (60/60) 100% (60/60) +smn Inari Sami 100% (68/68) 100% (68/68) 100% (68/68) +sms Skolt Sami 100% (80/80) 100% (80/80) 97% (78/80) +so Somali 100% (52/52) 100% (52/52) 100% (52/52) +sq Albanian 100% (56/56) 100% (56/56) 100% (56/56) +sr Serbian 100% (76/76) 100% (76/76) 100% (76/76) +sv Swedish 100% (68/68) 100% (68/68) 100% (68/68) +sw Swahili 100% (52/52) 100% (52/52) 100% (52/52) +syr Syriac (0/45) (0/45) (0/45) +ta Tamil (0/48) (0/48) (0/48) +te Telugu (0/80) (0/80) (0/80) +tg Tajik 100% (78/78) 100% (78/78) 97% (76/78) +th Thai 1% (1/87) (0/87) (0/87) +ti-er Eritrean Tigrinya (0/256) (0/256) (0/256) +ti-et Ethiopian Tigrinya (0/282) (0/282) (0/282) +tig Tigre (0/221) (0/221) (0/221) +tk Turkmen 100% (74/74) 100% (74/74) 97% (72/74) +tl Tagalog (0/19) (0/19) (0/19) +tn Tswana 100% (56/56) 100% (56/56) 100% (56/56) +to Tonga 100% (53/53) 100% (53/53) 100% (53/53) +tr Turkish 100% (70/70) 100% (70/70) 100% (70/70) +ts Tsonga 100% (52/52) 100% (52/52) 100% (52/52) +tt Tatar 100% (76/76) 100% (76/76) 97% (74/76) +tw Twi 100% (73/73) 100% (73/73) 100% (73/73) +tyv Tuvinian 100% (70/70) 100% (70/70) 100% (70/70) +ug Uighur 100% (125/125) (0/125) (0/125) +uk Ukrainian 100% (72/72) 100% (72/72) 100% (72/72) +ur Urdu 94% (137/145) (0/145) (0/145) +uz Uzbek 100% (68/68) 100% (68/68) 100% (68/68) +ven Venda 100% (62/62) 100% (62/62) 100% (62/62) +vi Vietnamese 100% (194/194) 77% (150/194) 62% (122/194) +vo Volapuk 100% (54/54) 100% (54/54) 100% (54/54) +vot Votic 100% (62/62) 100% (62/62) 100% (62/62) +wa Walloon 100% (70/70) 100% (70/70) 100% (70/70) +wen Sorbian languages (lower and upper) 100% (76/76) 100% (76/76) 100% (76/76) +wo Wolof 100% (66/66) 100% (66/66) 100% (66/66) +xh Xhosa 100% (52/52) 100% (52/52) 100% (52/52) +yap Yapese 100% (58/58) 100% (58/58) 100% (58/58) +yi Yiddish 100% (27/27) (0/27) (0/27) +yo Yoruba 100% (119/119) 100% (119/119) 100% (119/119) +zh-cn Chinese (simplified) 0% (2/6765) 0% (2/6765) 0% (2/6765) +zh-hk Chinese Hong Kong Supplementary Character Set (0/2213) (0/2213) (0/2213) +zh-mo Chinese in Macau (0/13063) (0/13063) (0/13063) +zh-sg Chinese in Singapore 0% (2/6765) 0% (2/6765) 0% (2/6765) +zh-tw Chinese (traditional) (0/13063) (0/13063) (0/13063) +zu Zulu 100% (52/52) 100% (52/52) 100% (52/52) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/3426569be9b65b6dce3f0afa56586bb79fc07741.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/3426569be9b65b6dce3f0afa56586bb79fc07741.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,112 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Acts + module Customizable + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_customizable(options = {}) + return if self.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods) + cattr_accessor :customizable_options + self.customizable_options = options + has_many :custom_values, :as => :customized, + :include => :custom_field, + :order => "#{CustomField.table_name}.position", + :dependent => :delete_all + before_validation { |customized| customized.custom_field_values if customized.new_record? } + # Trigger validation only if custom values were changed + validates_associated :custom_values, :on => :update, :if => Proc.new { |customized| customized.custom_field_values_changed? } + send :include, Redmine::Acts::Customizable::InstanceMethods + # Save custom values when saving the customized object + after_save :save_custom_field_values + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + end + + def available_custom_fields + CustomField.find(:all, :conditions => "type = '#{self.class.name}CustomField'", + :order => 'position') + end + + # Sets the values of the object's custom fields + # values is an array like [{'id' => 1, 'value' => 'foo'}, {'id' => 2, 'value' => 'bar'}] + def custom_fields=(values) + values_to_hash = values.inject({}) do |hash, v| + v = v.stringify_keys + if v['id'] && v.has_key?('value') + hash[v['id']] = v['value'] + end + hash + end + self.custom_field_values = values_to_hash + end + + # Sets the values of the object's custom fields + # values is a hash like {'1' => 'foo', 2 => 'bar'} + def custom_field_values=(values) + @custom_field_values_changed = true + values = values.stringify_keys + custom_field_values.each do |custom_value| + custom_value.value = values[custom_value.custom_field_id.to_s] if values.has_key?(custom_value.custom_field_id.to_s) + end if values.is_a?(Hash) + end + + def custom_field_values + @custom_field_values ||= available_custom_fields.collect { |x| custom_values.detect { |v| v.custom_field == x } || custom_values.build(:customized => self, :custom_field => x, :value => nil) } + end + + def visible_custom_field_values + custom_field_values.select(&:visible?) + end + + def custom_field_values_changed? + @custom_field_values_changed == true + end + + def custom_value_for(c) + field_id = (c.is_a?(CustomField) ? c.id : c.to_i) + custom_values.detect {|v| v.custom_field_id == field_id } + end + + def save_custom_field_values + self.custom_values = custom_field_values + custom_field_values.each(&:save) + @custom_field_values_changed = false + @custom_field_values = nil + end + + def reset_custom_values! + @custom_field_values = nil + @custom_field_values_changed = true + values = custom_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h} + custom_values.each {|cv| cv.destroy unless custom_field_values.include?(cv)} + end + + module ClassMethods + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/342bfb95b19c2d2bc64485e9d4d12de5afbbc42e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/342bfb95b19c2d2bc64485e9d4d12de5afbbc42e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,57 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +From: "John Smith" +To: +Subject: New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say... +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris --- Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +--- This line starts with a delimiter and should not be stripped + +This paragraph is before delimiters. + +BREAK + +This paragraph is between delimiters. + +--- + +This paragraph is after the delimiter so it shouldn't appear. + +Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque +sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. +Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, +dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, +massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo +pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. + +Project: onlinestore +Status: Resolved +due date: 2010-12-31 +Start Date:2010-01-01 +Assigned to: John Smith + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/345622a2bbb9659bb7cca2675ef8c8ee055a16f0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/345622a2bbb9659bb7cca2675ef8c8ee055a16f0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMemberRolesInheritedFrom < ActiveRecord::Migration + def self.up + add_column :member_roles, :inherited_from, :integer + end + + def self.down + remove_column :member_roles, :inherited_from + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34b73ece1e831dc1971184e3860929bca8555291.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/34b73ece1e831dc1971184e3860929bca8555291.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '粗體'; +jsToolBar.strings['Italic'] = '斜體'; +jsToolBar.strings['Underline'] = '底線'; +jsToolBar.strings['Deleted'] = '刪除線'; +jsToolBar.strings['Code'] = '程式碼'; +jsToolBar.strings['Heading 1'] = '標題 1'; +jsToolBar.strings['Heading 2'] = '標題 2'; +jsToolBar.strings['Heading 3'] = '標題 3'; +jsToolBar.strings['Unordered list'] = '項目清單'; +jsToolBar.strings['Ordered list'] = '編號清單'; +jsToolBar.strings['Quote'] = '引文'; +jsToolBar.strings['Unquote'] = '取消引文'; +jsToolBar.strings['Preformatted text'] = '已格式文字'; +jsToolBar.strings['Wiki link'] = '連結至 Wiki 頁面'; +jsToolBar.strings['Image'] = '圖片'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34bbd22558c309af2608a5aaf343302b2d47bfb5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/34bbd22558c309af2608a5aaf343302b2d47bfb5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 WorkflowsHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34ce52464aaba9c361d4d597bfc1e5b07bef8911.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/34ce52464aaba9c361d4d597bfc1e5b07bef8911.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,449 @@ +# Copyright (c) 2006 4ssoM LLC +# 1.12 contributed by Ed Moss. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# This is direct port of korean.php +# +# Korean PDF support. +# +# Usage is as follows: +# +# require 'fpdf' +# require 'chinese' +# pdf = FPDF.new +# pdf.extend(PDF_Korean) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_Korean + +UHC_widths={' ' => 333, '!' => 416, '"' => 416, '#' => 833, '$' => 625, '%' => 916, '&' => 833, '\'' => 250, + '(' => 500, ')' => 500, '*' => 500, '+' => 833, ',' => 291, '-' => 833, '.' => 291, '/' => 375, '0' => 625, '1' => 625, + '2' => 625, '3' => 625, '4' => 625, '5' => 625, '6' => 625, '7' => 625, '8' => 625, '9' => 625, ':' => 333, ';' => 333, + '<' => 833, '=' => 833, '>' => 916, '?' => 500, '@' => 1000, 'A' => 791, 'B' => 708, 'C' => 708, 'D' => 750, 'E' => 708, + 'F' => 666, 'G' => 750, 'H' => 791, 'I' => 375, 'J' => 500, 'K' => 791, 'L' => 666, 'M' => 916, 'N' => 791, 'O' => 750, + 'P' => 666, 'Q' => 750, 'R' => 708, 'S' => 666, 'T' => 791, 'U' => 791, 'V' => 750, 'W' => 1000, 'X' => 708, 'Y' => 708, + 'Z' => 666, '[' => 500, '\\' => 375, ']' => 500, '^' => 500, '_' => 500, '`' => 333, 'a' => 541, 'b' => 583, 'c' => 541, + 'd' => 583, 'e' => 583, 'f' => 375, 'g' => 583, 'h' => 583, 'i' => 291, 'j' => 333, 'k' => 583, 'l' => 291, 'm' => 875, + 'n' => 583, 'o' => 583, 'p' => 583, 'q' => 583, 'r' => 458, 's' => 541, 't' => 375, 'u' => 583, 'v' => 583, 'w' => 833, + 'x' => 625, 'y' => 625, 'z' => 500, '{' => 583, '|' => 583, '}' => 583, '~' => 750} + + def AddCIDFont(family,style,name,cw,cMap,registry) + fontkey=family.downcase+style.upcase + unless @fonts[fontkey].nil? + Error("Font already added: family style") + end + i=@fonts.length+1 + name=name.gsub(' ','') + @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, + 'CMap'=>cMap,'registry'=>registry} + end + + def AddCIDFonts(family,name,cw,cMap,registry) + AddCIDFont(family,'',name,cw,cMap,registry) + AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) + AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) + AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) + end + + def AddUHCFont(family='UHC',name='HYSMyeongJoStd-Medium-Acro') + #Add UHC font with proportional Latin + cw=UHC_widths + cMap='KSCms-UHC-H' + registry={'ordering'=>'Korea1','supplement'=>1} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddUHChwFont(family='UHC-hw',name='HYSMyeongJoStd-Medium-Acro') + #Add UHC font with half-witdh Latin + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='KSCms-UHC-HW-H' + registry={'ordering'=>'Korea1','supplement'=>1} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def GetStringWidth(s) + if(@current_font['type']=='Type0') + return GetMBStringWidth(s) + else + return super(s) + end + end + + def GetMBStringWidth(s) + #Multi-byte version of GetStringWidth() + l=0 + cw=@current_font['cw'] + nb=s.length + i=0 + while(i0 and s[nb-1]=="\n") + nb-=1 + end + b=0 + if(border) + if(border==1) + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + b2='L' unless border.to_s.index('L').nil? + b2=b2+'R' unless border.to_s.index('R').nil? + b=(border.to_s.index('T')) ? (b2+'T') : b2 + end + end + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],b,2,align,fill) + else + Cell(w,h,s[j,sep-j],b,2,align,fill) + i=(s[sep].chr==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + nl+=1 + if(border and nl==2) + b=b2 + end + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(border and not border.to_s.index('B').nil?) + b+='B' + end + Cell(w,h,s[j,i-j],b,2,align,fill) + + # move cursor to specified position + if (ln == 1) + # go to the beginning of the next line + @x=@l_margin + elsif (ln == 0) + # go to the top-right of the cell + @y = prevy; + @x = prevx + w; + elsif (ln == 2) + # go to the bottom-left of the cell + @x = prevx; + end + end + + def Write(h,txt,link='',fill=0) + if(@current_font['type']=='Type0') + MBWrite(h,txt,link,fill) + else + super(h,txt,link,fill) + end + end + + def MBWrite(h,txt,link,fill=0) + #Multi-byte version of Write() + cw=@current_font['cw'] + w=@w-@r_margin-@x + wmax=(w-2*@c_margin)*1000/@font_size + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(@x>@l_margin) + #Move to next line + @x=@l_margin + @y+=h + w=@w-@r_margin-@x + wmax=(w-2*@c_margin)*1000/@font_size + i+=1 + nl+=1 + next + end + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],0,2,'',fill,link) + else + Cell(w,h,s[j,sep-j],0,2,'',fill,link) + i=(s[sep].chr==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + if(nl==1) + @x=@l_margin + w=@w-@r_margin-@x + wmax=(w-2*@c_margin)*1000/@font_size + end + nl+=1 + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(i!=j) + Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link) + end + end + +private + + def putfonts() + nf=@n + @diffs.each do |diff| + #Encodings + newobj() + out('<>') + out('endobj') + end + # mqr=get_magic_quotes_runtime() + # set_magic_quotes_runtime(0) + @font_files.each_pair do |file, info| + #Font file embedding + newobj() + @font_files[file]['n']=@n + if(defined('FPDF_FONTPATH')) + file=FPDF_FONTPATH+file + end + size=filesize(file) + if(!size) + Error('Font file not found') + end + out('<>') + f=fopen(file,'rb') + putstream(fread(f,size)) + fclose(f) + out('endobj') + end + # set_magic_quotes_runtime(mqr) + @fonts.each_pair do |k, font| + #Font objects + newobj() + @fonts[k]['n']=@n + out('<>') + out('endobj') + if(font['type']!='core') + #Widths + newobj() + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s+=cw[i.chr]+' ' + end + out(s+']') + out('endobj') + #Descriptor + newobj() + s='<>') + out('endobj') + end + end + end + end + + def putType0(font) + #Type0 + out('/Subtype /Type0') + out('/BaseFont /'+font['name']+'-'+font['CMap']) + out('/Encoding /'+font['CMap']) + out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') + out('>>') + out('endobj') + #CIDFont + newobj() + out('<>') + out('/FontDescriptor '+(@n+1).to_s+' 0 R') + if(font['CMap']=='KSCms-UHC-HW-H') + w='8094 8190 500' + else + w='1 [' + font['cw'].keys.sort.each {|key| + w+=font['cw'][key].to_s + " " + # ActionController::Base::logger.debug key.to_s + # ActionController::Base::logger.debug font['cw'][key].to_s + } + w +=']' + end + out('/W ['+w+']>>') + out('endobj') + #Font descriptor + newobj() + out('<>') + out('endobj') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34d6a29ace227b986c6d51e0271421fb54c5621a.svn-base Binary file .svn/pristine/34/34d6a29ace227b986c6d51e0271421fb54c5621a.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34d8d3802dc99a5fc894d045c9ab06f8defd3e34.svn-base Binary file .svn/pristine/34/34d8d3802dc99a5fc894d045c9ab06f8defd3e34.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34e888bcdeab7ab62509c340e12806f908468391.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/34e888bcdeab7ab62509c340e12806f908468391.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +author: James Adam +email: james.adam@gmail.com +homepage: http://www.rails-engines.org +summary: Enhances the plugin mechanism to perform more flexible sharing +description: The Rails Engines plugin allows the sharing of almost any type of code or asset that you could use in a Rails application, including controllers, models, stylesheets, and views. +license: MIT +version: 2.3.2 \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/34/34e8f3b289ef523b2e5c39a872d6efc48111b2f3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/34/34e8f3b289ef523b2e5c39a872d6efc48111b2f3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class Query < ActiveRecord::Base + generator_for :name, :start => 'Query 0' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/3512f0a7e8a0b7dd8c33b6309137ca6b0f893a68.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/3512f0a7e8a0b7dd8c33b6309137ca6b0f893a68.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= TestHelper.view_path_for __FILE__ %> (from a_view) \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/35159d7789b8fbcfc57c58eacb8fb9632b6c69c9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/35159d7789b8fbcfc57c58eacb8fb9632b6c69c9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,67 @@ +api.issue do + api.id @issue.id + api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil? + api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil? + api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil? + api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil? + api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil? + api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil? + api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil? + api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil? + api.parent(:id => @issue.parent_id) unless @issue.parent.nil? + + api.subject @issue.subject + api.description @issue.description + api.start_date @issue.start_date + api.due_date @issue.due_date + api.done_ratio @issue.done_ratio + api.estimated_hours @issue.estimated_hours + api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project) + + render_api_custom_values @issue.custom_field_values, api + + api.created_on @issue.created_on + api.updated_on @issue.updated_on + + render_api_issue_children(@issue, api) if include_in_api_response?('children') + + api.array :attachments do + @issue.attachments.each do |attachment| + render_api_attachment(attachment, api) + end + end if include_in_api_response?('attachments') + + api.array :relations do + @relations.each do |relation| + api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay) + end + end if include_in_api_response?('relations') && @relations.present? + + api.array :changesets do + @issue.changesets.each do |changeset| + api.changeset :revision => changeset.revision do + api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil? + api.comments changeset.comments + api.committed_on changeset.committed_on + end + end + end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project) + + api.array :journals do + @issue.journals.each do |journal| + api.journal :id => journal.id do + api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil? + api.notes journal.notes + api.created_on journal.created_on + api.array :details do + journal.details.each do |detail| + api.detail :property => detail.property, :name => detail.prop_key do + api.old_value detail.old_value + api.new_value detail.value + end + end + end + end + end + end if include_in_api_response?('journals') +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/351cacac800f1602b5c0dedb02c5f120d59d437c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/351cacac800f1602b5c0dedb02c5f120d59d437c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddQueriesColumnNames < ActiveRecord::Migration + def self.up + add_column :queries, :column_names, :text + end + + def self.down + remove_column :queries, :column_names + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/351ed79f1a1eb0a05256bd9bbc96463418f0bb9b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/351ed79f1a1eb0a05256bd9bbc96463418f0bb9b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +module Redmine + module Scm + class Base + class << self + + def all + @scms + end + + # Add a new SCM adapter and repository + def add(scm_name) + @scms ||= [] + @scms << scm_name + end + + # Remove a SCM adapter from Redmine's list of supported scms + def delete(scm_name) + @scms.delete(scm_name) + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/358efe99a3fb53178835eb3b5414a8ad980d694b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/358efe99a3fb53178835eb3b5414a8ad980d694b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddCommitAccessPermission < ActiveRecord::Migration + def self.up + Role.find(:all).select { |r| not r.builtin? }.each do |r| + r.add_permission!(:commit_access) + end + end + + def self.down + Role.find(:all).select { |r| not r.builtin? }.each do |r| + r.remove_permission!(:commit_access) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/35f4a8f6d445be82c25ddd771533cf2c583a1a3d.svn-base Binary file .svn/pristine/35/35f4a8f6d445be82c25ddd771533cf2c583a1a3d.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/35f7ce114c4047a04259024e5c563af98880d0e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/35f7ce114c4047a04259024e5c563af98880d0e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +# Add new mime types for use in respond_to blocks: + +Mime::SET << Mime::CSV unless Mime::SET.include?(Mime::CSV) +Mime::Type.register 'application/pdf', :pdf +Mime::Type.register 'image/png', :png diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/35/35fc8b0e44592da620fe5b31cc99784200b75c0a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/35/35fc8b0e44592da620fe5b31cc99784200b75c0a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings ['Strong'] = 'قوي'; +jsToolBar.strings ['Italic'] = 'مائل'; +jsToolBar.strings ['Underline'] = 'تسطير'; +jsToolBar.strings ['Deleted'] = 'محذوف'; +jsToolBar.strings ['Code'] = 'رمز ضمني'; +jsToolBar.strings ['Heading 1'] = 'عنوان 1'; +jsToolBar.strings ['Heading 2'] = 'عنوان 2'; +jsToolBar.strings ['Heading 3'] = 'عنوان 3'; +jsToolBar.strings ['Unordered list'] = 'قائمة غير مرتبة'; +jsToolBar.strings ['Ordered list'] = 'قائمة مرتبة'; +jsToolBar.strings ['Quote'] = 'اقتباس'; +jsToolBar.strings ['Unquote'] = 'إزالة الاقتباس'; +jsToolBar.strings ['Preformatted text'] = 'نص مسبق التنسيق'; +jsToolBar.strings ['Wiki link'] = 'رابط الى صفحة ويكي'; +jsToolBar.strings ['Image'] = 'صورة'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/36167ee499dcc4b045fdbe86a18299795ead7b8c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/36167ee499dcc4b045fdbe86a18299795ead7b8c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +

<%=l(:label_my_account)%>

+ +

<%=l(:field_login)%>: <%= link_to_user(@user, :format => :username) %>
+<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

+ + +

<%= l(:label_feeds_access_key) %>

+ +

+<% if @user.rss_token %> +<%= l(:label_feeds_access_key_created_on, distance_of_time_in_words(Time.now, @user.rss_token.created_on)) %> +<% else %> +<%= l(:label_missing_feeds_access_key) %> +<% end %> +(<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>) +

+ +<% if Setting.rest_api_enabled? %> +

<%= l(:label_api_access_key) %>

+
+ <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> +
<%= h(@user.api_key) %>
+
+<%= javascript_tag("$('api-access-key').hide();") %> +

+<% if @user.api_token %> +<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> +<% else %> +<%= l(:label_missing_api_access_key) %> +<% end %> +(<%= link_to l(:button_reset), {:action => 'reset_api_key'}, :method => :post %>) +

+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/362876bd65a226af3b36d0e31a3e589d5fcd9d1f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/362876bd65a226af3b36d0e31a3e589d5fcd9d1f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,75 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 SafeAttributes + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + # Declares safe attributes + # An optional Proc can be given for conditional inclusion + # + # Example: + # safe_attributes 'title', 'pages' + # safe_attributes 'isbn', :if => {|book, user| book.author == user} + def safe_attributes(*args) + @safe_attributes ||= [] + if args.empty? + @safe_attributes + else + options = args.last.is_a?(Hash) ? args.pop : {} + @safe_attributes << [args, options] + end + end + end + + # Returns an array that can be safely set by user or current user + # + # Example: + # book.safe_attributes # => ['title', 'pages'] + # book.safe_attributes(book.author) # => ['title', 'pages', 'isbn'] + def safe_attribute_names(user=User.current) + names = [] + self.class.safe_attributes.collect do |attrs, options| + if options[:if].nil? || options[:if].call(self, user) + names += attrs.collect(&:to_s) + end + end + names.uniq + end + + # Returns a hash with unsafe attributes removed + # from the given attrs hash + # + # Example: + # book.delete_unsafe_attributes({'title' => 'My book', 'foo' => 'bar'}) + # # => {'title' => 'My book'} + def delete_unsafe_attributes(attrs, user=User.current) + safe = safe_attribute_names(user) + attrs.dup.delete_if {|k,v| !safe.include?(k)} + end + + # Sets attributes from attrs that are safe + # attrs is a Hash with string keys + def safe_attributes=(attrs, user=User.current) + return unless attrs.is_a?(Hash) + self.attributes = delete_unsafe_attributes(attrs, user) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/3657119b33807d83538ff00e53e1e48fb5a449bb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/3657119b33807d83538ff00e53e1e48fb5a449bb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +default: + +production: + +development: + +test: diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/36589025ebdaf07deddb1166ea208abc6424e050.svn-base Binary file .svn/pristine/36/36589025ebdaf07deddb1166ea208abc6424e050.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/3663be5758316520e265df67bcab8169afbe2ac4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/3663be5758316520e265df67bcab8169afbe2ac4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +sqlite: + :adapter: sqlite + :dbfile: acts_as_versioned_plugin.sqlite.db +sqlite3: + :adapter: sqlite3 + :dbfile: acts_as_versioned_plugin.sqlite3.db +postgresql: + :adapter: postgresql + :username: postgres + :password: postgres + :database: acts_as_versioned_plugin_test + :min_messages: ERROR +mysql: + :adapter: mysql + :host: localhost + :username: rails + :password: + :database: acts_as_versioned_plugin_test \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/367e362e67878aa031a1c63db7f4d7ea9727c0a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/367e362e67878aa031a1c63db7f4d7ea9727c0a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddAuthSourcesTls < ActiveRecord::Migration + def self.up + add_column :auth_sources, :tls, :boolean, :default => false, :null => false + end + + def self.down + remove_column :auth_sources, :tls + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/36a71efadc331c3001a59098a85ebc847b7a529a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/36a71efadc331c3001a59098a85ebc847b7a529a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2021 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'issues_controller' + +class IssuesControllerTest < ActionController::TestCase + fixtures :projects, + :users, + :roles, + :members, + :member_roles, + :issues, + :issue_statuses, + :versions, + :trackers, + :projects_trackers, + :issue_categories, + :enabled_modules, + :enumerations, + :attachments, + :workflows, + :custom_fields, + :custom_values, + :custom_fields_projects, + :custom_fields_trackers, + :time_entries, + :journals, + :journal_details, + :queries + + include Redmine::I18n + + def setup + @controller = IssuesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_index + Setting.default_language = 'en' + + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_nil assigns(:project) + assert_tag :tag => 'a', :content => /Can't print recipes/ + assert_tag :tag => 'a', :content => /Subproject issue/ + # private projects hidden + assert_no_tag :tag => 'a', :content => /Issue of a private subproject/ + assert_no_tag :tag => 'a', :content => /Issue on project 2/ + # project column + assert_tag :tag => 'th', :content => /Project/ + end + + def test_index_should_not_list_issues_when_module_disabled + EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_nil assigns(:project) + assert_no_tag :tag => 'a', :content => /Can't print recipes/ + assert_tag :tag => 'a', :content => /Subproject issue/ + end + + def test_index_should_list_visible_issues_only + get :index, :per_page => 100 + assert_response :success + assert_not_nil assigns(:issues) + assert_nil assigns(:issues).detect {|issue| !issue.visible?} + end + + def test_index_with_project + Setting.display_subprojects_issues = 0 + get :index, :project_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_tag :tag => 'a', :content => /Can't print recipes/ + assert_no_tag :tag => 'a', :content => /Subproject issue/ + end + + def test_index_with_project_and_subprojects + Setting.display_subprojects_issues = 1 + get :index, :project_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_tag :tag => 'a', :content => /Can't print recipes/ + assert_tag :tag => 'a', :content => /Subproject issue/ + assert_no_tag :tag => 'a', :content => /Issue of a private subproject/ + end + + def test_index_with_project_and_subprojects_should_show_private_subprojects + @request.session[:user_id] = 2 + Setting.display_subprojects_issues = 1 + get :index, :project_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_tag :tag => 'a', :content => /Can't print recipes/ + assert_tag :tag => 'a', :content => /Subproject issue/ + assert_tag :tag => 'a', :content => /Issue of a private subproject/ + end + + def test_index_with_project_and_default_filter + get :index, :project_id => 1, :set_filter => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + + query = assigns(:query) + assert_not_nil query + # default filter + assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters) + end + + def test_index_with_project_and_filter + get :index, :project_id => 1, :set_filter => 1, + :f => ['tracker_id'], + :op => {'tracker_id' => '='}, + :v => {'tracker_id' => ['1']} + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + + query = assigns(:query) + assert_not_nil query + assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters) + end + + def test_index_with_short_filters + + to_test = { + 'status_id' => { + 'o' => { :op => 'o', :values => [''] }, + 'c' => { :op => 'c', :values => [''] }, + '7' => { :op => '=', :values => ['7'] }, + '7|3|4' => { :op => '=', :values => ['7', '3', '4'] }, + '=7' => { :op => '=', :values => ['7'] }, + '!3' => { :op => '!', :values => ['3'] }, + '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }}, + 'subject' => { + 'This is a subject' => { :op => '=', :values => ['This is a subject'] }, + 'o' => { :op => '=', :values => ['o'] }, + '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] }, + '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }}, + 'tracker_id' => { + '3' => { :op => '=', :values => ['3'] }, + '=3' => { :op => '=', :values => ['3'] }}, + 'start_date' => { + '2011-10-12' => { :op => '=', :values => ['2011-10-12'] }, + '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] }, + '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] }, + '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] }, + '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] }, + ' { :op => ' ['2'] }, + '>t+2' => { :op => '>t+', :values => ['2'] }, + 't+2' => { :op => 't+', :values => ['2'] }, + 't' => { :op => 't', :values => [''] }, + 'w' => { :op => 'w', :values => [''] }, + '>t-2' => { :op => '>t-', :values => ['2'] }, + ' { :op => ' ['2'] }, + 't-2' => { :op => 't-', :values => ['2'] }}, + 'created_on' => { + '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] }, + ' { :op => '=', :values => ['t+2' => { :op => '=', :values => ['>t+2'] }, + 't+2' => { :op => 't', :values => ['+2'] }}, + 'cf_1' => { + 'c' => { :op => '=', :values => ['c'] }, + '!c' => { :op => '!', :values => ['c'] }, + '!*' => { :op => '!*', :values => [''] }, + '*' => { :op => '*', :values => [''] }}, + 'estimated_hours' => { + '=13.4' => { :op => '=', :values => ['13.4'] }, + '>=45' => { :op => '>=', :values => ['45'] }, + '<=125' => { :op => '<=', :values => ['125'] }, + '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] }, + '!*' => { :op => '!*', :values => [''] }, + '*' => { :op => '*', :values => [''] }} + } + + default_filter = { 'status_id' => {:operator => 'o', :values => [''] }} + + to_test.each do |field, expression_and_expected| + expression_and_expected.each do |filter_expression, expected| + + get :index, :set_filter => 1, field => filter_expression + + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + + query = assigns(:query) + assert_not_nil query + assert query.has_filter?(field) + assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters) + end + end + + end + + def test_index_with_project_and_empty_filters + get :index, :project_id => 1, :set_filter => 1, :fields => [''] + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + + query = assigns(:query) + assert_not_nil query + # no filter + assert_equal({}, query.filters) + end + + def test_index_with_query + get :index, :project_id => 1, :query_id => 5 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_nil assigns(:issue_count_by_group) + end + + def test_index_with_query_grouped_by_tracker + get :index, :project_id => 1, :query_id => 6 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_not_nil assigns(:issue_count_by_group) + end + + def test_index_with_query_grouped_by_list_custom_field + get :index, :project_id => 1, :query_id => 9 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + assert_not_nil assigns(:issue_count_by_group) + end + + def test_index_with_query_id_and_project_id_should_set_session_query + get :index, :project_id => 1, :query_id => 4 + assert_response :success + assert_kind_of Hash, session[:query] + assert_equal 4, session[:query][:id] + assert_equal 1, session[:query][:project_id] + end + + def test_index_with_cross_project_query_in_session_should_show_project_issues + q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil) + @request.session[:query] = {:id => q.id, :project_id => 1} + + with_settings :display_subprojects_issues => '0' do + get :index, :project_id => 1 + end + assert_response :success + assert_not_nil assigns(:query) + assert_equal q.id, assigns(:query).id + assert_equal 1, assigns(:query).project_id + assert_equal [1], assigns(:issues).map(&:project_id).uniq + end + + def test_private_query_should_not_be_available_to_other_users + q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil) + @request.session[:user_id] = 3 + + get :index, :query_id => q.id + assert_response 403 + end + + def test_private_query_should_be_available_to_its_user + q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil) + @request.session[:user_id] = 2 + + get :index, :query_id => q.id + assert_response :success + end + + def test_public_query_should_be_available_to_other_users + q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil) + @request.session[:user_id] = 3 + + get :index, :query_id => q.id + assert_response :success + end + + def test_index_csv + get :index, :format => 'csv' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'text/csv', @response.content_type + assert @response.body.starts_with?("#,") + lines = @response.body.chomp.split("\n") + assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size + end + + def test_index_csv_with_project + get :index, :project_id => 1, :format => 'csv' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'text/csv', @response.content_type + end + + def test_index_csv_with_description + get :index, :format => 'csv', :description => '1' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'text/csv', @response.content_type + assert @response.body.starts_with?("#,") + lines = @response.body.chomp.split("\n") + assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size + end + + def test_index_csv_with_all_columns + get :index, :format => 'csv', :columns => 'all' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'text/csv', @response.content_type + assert @response.body.starts_with?("#,") + lines = @response.body.chomp.split("\n") + assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size + end + + def test_index_csv_big_5 + with_settings :default_language => "zh-TW" do + str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88" + str_big5 = "\xa4@\xa4\xeb" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + str_big5.force_encoding('Big5') + end + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str_utf8) + assert issue.save + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str_utf8], + :format => 'csv' + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + s1 = "\xaa\xac\xbaA" + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert lines[0].include?(s1) + assert lines[1].include?(str_big5) + end + end + + def test_index_csv_cannot_convert_should_be_replaced_big_5 + with_settings :default_language => "zh-TW" do + str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + end + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str_utf8) + assert issue.save + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str_utf8], + :c => ['status', 'subject'], + :format => 'csv', + :set_filter => 1 + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + s1 = "\xaa\xac\xbaA" # status + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert lines[0].include?(s1) + s2 = lines[1].split(",")[2] + if s1.respond_to?(:force_encoding) + s3 = "\xa5H?" # subject + s3.force_encoding('Big5') + assert_equal s3, s2 + elsif RUBY_PLATFORM == 'java' + assert_equal "??", s2 + else + assert_equal "\xa5H???", s2 + end + end + end + + def test_index_csv_tw + with_settings :default_language => "zh-TW" do + str1 = "test_index_csv_tw" + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str1, :estimated_hours => '1234.5') + assert issue.save + assert_equal 1234.5, issue.estimated_hours + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str1], + :c => ['estimated_hours', 'subject'], + :format => 'csv', + :set_filter => 1 + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + assert_equal "#{issue.id},1234.5,#{str1}", lines[1] + + str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)" + if str_tw.respond_to?(:force_encoding) + str_tw.force_encoding('UTF-8') + end + assert_equal str_tw, l(:general_lang_name) + assert_equal ',', l(:general_csv_separator) + assert_equal '.', l(:general_csv_decimal_separator) + end + end + + def test_index_csv_fr + with_settings :default_language => "fr" do + str1 = "test_index_csv_fr" + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str1, :estimated_hours => '1234.5') + assert issue.save + assert_equal 1234.5, issue.estimated_hours + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str1], + :c => ['estimated_hours', 'subject'], + :format => 'csv', + :set_filter => 1 + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + assert_equal "#{issue.id};1234,5;#{str1}", lines[1] + + str_fr = "Fran\xc3\xa7ais" + if str_fr.respond_to?(:force_encoding) + str_fr.force_encoding('UTF-8') + end + assert_equal str_fr, l(:general_lang_name) + assert_equal ';', l(:general_csv_separator) + assert_equal ',', l(:general_csv_decimal_separator) + end + end + + def test_index_pdf + ["en", "zh", "zh-TW", "ja", "ko"].each do |lang| + with_settings :default_language => lang do + + get :index + assert_response :success + assert_template 'index' + + if lang == "ja" + if RUBY_PLATFORM != 'java' + assert_equal "CP932", l(:general_pdf_encoding) + end + if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932" + next + end + end + + get :index, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'application/pdf', @response.content_type + + get :index, :project_id => 1, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'application/pdf', @response.content_type + + get :index, :project_id => 1, :query_id => 6, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'application/pdf', @response.content_type + end + end + end + + def test_index_pdf_with_query_grouped_by_list_custom_field + get :index, :project_id => 1, :query_id => 9, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_not_nil assigns(:issue_count_by_group) + assert_equal 'application/pdf', @response.content_type + end + + def test_index_sort + get :index, :sort => 'tracker,id:desc' + assert_response :success + + sort_params = @request.session['issues_index_sort'] + assert sort_params.is_a?(String) + assert_equal 'tracker,id:desc', sort_params + + issues = assigns(:issues) + assert_not_nil issues + assert !issues.empty? + assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id) + end + + def test_index_sort_by_field_not_included_in_columns + Setting.issue_list_default_columns = %w(subject author) + get :index, :sort => 'tracker' + end + + def test_index_sort_by_assigned_to + get :index, :sort => 'assigned_to' + assert_response :success + assignees = assigns(:issues).collect(&:assigned_to).compact + assert_equal assignees.sort, assignees + end + + def test_index_sort_by_assigned_to_desc + get :index, :sort => 'assigned_to:desc' + assert_response :success + assignees = assigns(:issues).collect(&:assigned_to).compact + assert_equal assignees.sort.reverse, assignees + end + + def test_index_group_by_assigned_to + get :index, :group_by => 'assigned_to', :sort => 'priority' + assert_response :success + end + + def test_index_sort_by_author + get :index, :sort => 'author' + assert_response :success + authors = assigns(:issues).collect(&:author) + assert_equal authors.sort, authors + end + + def test_index_sort_by_author_desc + get :index, :sort => 'author:desc' + assert_response :success + authors = assigns(:issues).collect(&:author) + assert_equal authors.sort.reverse, authors + end + + def test_index_group_by_author + get :index, :group_by => 'author', :sort => 'priority' + assert_response :success + end + + def test_index_with_columns + columns = ['tracker', 'subject', 'assigned_to'] + get :index, :set_filter => 1, :c => columns + assert_response :success + + # query should use specified columns + query = assigns(:query) + assert_kind_of Query, query + assert_equal columns, query.column_names.map(&:to_s) + + # columns should be stored in session + assert_kind_of Hash, session[:query] + assert_kind_of Array, session[:query][:column_names] + assert_equal columns, session[:query][:column_names].map(&:to_s) + + # ensure only these columns are kept in the selected columns list + assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' }, + :children => { :count => 3 } + assert_no_tag :tag => 'option', :attributes => { :value => 'project' }, + :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } } + end + + def test_index_without_project_should_implicitly_add_project_column_to_default_columns + Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to'] + get :index, :set_filter => 1 + + # query should use specified columns + query = assigns(:query) + assert_kind_of Query, query + assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name) + end + + def test_index_without_project_and_explicit_default_columns_should_not_add_project_column + Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to'] + columns = ['tracker', 'subject', 'assigned_to'] + get :index, :set_filter => 1, :c => columns + + # query should use specified columns + query = assigns(:query) + assert_kind_of Query, query + assert_equal columns.map(&:to_sym), query.columns.map(&:name) + end + + def test_index_with_custom_field_column + columns = %w(tracker subject cf_2) + get :index, :set_filter => 1, :c => columns + assert_response :success + + # query should use specified columns + query = assigns(:query) + assert_kind_of Query, query + assert_equal columns, query.column_names.map(&:to_s) + + assert_tag :td, + :attributes => {:class => 'cf_2 string'}, + :ancestor => {:tag => 'table', :attributes => {:class => /issues/}} + end + + def test_index_with_date_column + Issue.find(1).update_attribute :start_date, '1987-08-24' + + with_settings :date_format => '%d/%m/%Y' do + get :index, :set_filter => 1, :c => %w(start_date) + assert_tag 'td', :attributes => {:class => /start_date/}, :content => '24/08/1987' + end + end + + def test_index_with_done_ratio + Issue.find(1).update_attribute :done_ratio, 40 + + get :index, :set_filter => 1, :c => %w(done_ratio) + assert_tag 'td', :attributes => {:class => /done_ratio/}, + :child => {:tag => 'table', :attributes => {:class => 'progress'}, + :descendant => {:tag => 'td', :attributes => {:class => 'closed', :style => 'width: 40%;'}} + } + end + + def test_index_with_fixed_version + get :index, :set_filter => 1, :c => %w(fixed_version) + assert_tag 'td', :attributes => {:class => /fixed_version/}, + :child => {:tag => 'a', :content => '1.0', :attributes => {:href => '/versions/2'}} + end + + def test_index_send_html_if_query_is_invalid + get :index, :f => ['start_date'], :op => {:start_date => '='} + assert_equal 'text/html', @response.content_type + assert_template 'index' + end + + def test_index_send_nothing_if_query_is_invalid + get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv' + assert_equal 'text/csv', @response.content_type + assert @response.body.blank? + end + + def test_show_by_anonymous + get :show, :id => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:issue) + assert_equal Issue.find(1), assigns(:issue) + + # anonymous role is allowed to add a note + assert_tag :tag => 'form', + :descendant => { :tag => 'fieldset', + :child => { :tag => 'legend', + :content => /Notes/ } } + assert_tag :tag => 'title', + :content => "Bug #1: Can't print recipes - eCookbook - Redmine" + end + + def test_show_by_manager + @request.session[:user_id] = 2 + get :show, :id => 1 + assert_response :success + + assert_tag :tag => 'a', + :content => /Quote/ + + assert_tag :tag => 'form', + :descendant => { :tag => 'fieldset', + :child => { :tag => 'legend', + :content => /Change properties/ } }, + :descendant => { :tag => 'fieldset', + :child => { :tag => 'legend', + :content => /Log time/ } }, + :descendant => { :tag => 'fieldset', + :child => { :tag => 'legend', + :content => /Notes/ } } + end + + def test_update_form_should_not_display_inactive_enumerations + @request.session[:user_id] = 2 + get :show, :id => 1 + assert_response :success + + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_update_form_should_allow_attachment_upload + @request.session[:user_id] = 2 + get :show, :id => 1 + + assert_tag :tag => 'form', + :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'}, + :descendant => { + :tag => 'input', + :attributes => {:type => 'file', :name => 'attachments[1][file]'} + } + end + + def test_show_should_deny_anonymous_access_without_permission + Role.anonymous.remove_permission!(:view_issues) + get :show, :id => 1 + assert_response :redirect + end + + def test_show_should_deny_anonymous_access_to_private_issue + Issue.update_all(["is_private = ?", true], "id = 1") + get :show, :id => 1 + assert_response :redirect + end + + def test_show_should_deny_non_member_access_without_permission + Role.non_member.remove_permission!(:view_issues) + @request.session[:user_id] = 9 + get :show, :id => 1 + assert_response 403 + end + + def test_show_should_deny_non_member_access_to_private_issue + Issue.update_all(["is_private = ?", true], "id = 1") + @request.session[:user_id] = 9 + get :show, :id => 1 + assert_response 403 + end + + def test_show_should_deny_member_access_without_permission + Role.find(1).remove_permission!(:view_issues) + @request.session[:user_id] = 2 + get :show, :id => 1 + assert_response 403 + end + + def test_show_should_deny_member_access_to_private_issue_without_permission + Issue.update_all(["is_private = ?", true], "id = 1") + @request.session[:user_id] = 3 + get :show, :id => 1 + assert_response 403 + end + + def test_show_should_allow_author_access_to_private_issue + Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1") + @request.session[:user_id] = 3 + get :show, :id => 1 + assert_response :success + end + + def test_show_should_allow_assignee_access_to_private_issue + Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1") + @request.session[:user_id] = 3 + get :show, :id => 1 + assert_response :success + end + + def test_show_should_allow_member_access_to_private_issue_with_permission + Issue.update_all(["is_private = ?", true], "id = 1") + User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all' + @request.session[:user_id] = 3 + get :show, :id => 1 + assert_response :success + end + + def test_show_should_not_disclose_relations_to_invisible_issues + Setting.cross_project_issue_relations = '1' + IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates') + # Relation to a private project issue + IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates') + + get :show, :id => 1 + assert_response :success + + assert_tag :div, :attributes => { :id => 'relations' }, + :descendant => { :tag => 'a', :content => /#2$/ } + assert_no_tag :div, :attributes => { :id => 'relations' }, + :descendant => { :tag => 'a', :content => /#4$/ } + end + + def test_show_atom + get :show, :id => 2, :format => 'atom' + assert_response :success + assert_template 'journals/index' + # Inline image + assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10')) + end + + def test_show_export_to_pdf + get :show, :id => 3, :format => 'pdf' + assert_response :success + assert_equal 'application/pdf', @response.content_type + assert @response.body.starts_with?('%PDF') + assert_not_nil assigns(:issue) + end + + def test_get_new + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + assert_response :success + assert_template 'new' + + assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]', + :value => 'Default string' } + + # Be sure we don't display inactive IssuePriorities + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_get_new_without_default_start_date_is_creation_date + Setting.default_issue_start_date_to_creation_date = 0 + + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + assert_response :success + assert_template 'new' + + assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]', + :value => nil } + end + + def test_get_new_with_default_start_date_is_creation_date + Setting.default_issue_start_date_to_creation_date = 1 + + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + assert_response :success + assert_template 'new' + + assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]', + :value => Date.today.to_s } + end + + def test_get_new_form_should_allow_attachment_upload + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + + assert_tag :tag => 'form', + :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'}, + :descendant => { + :tag => 'input', + :attributes => {:type => 'file', :name => 'attachments[1][file]'} + } + end + + def test_get_new_without_tracker_id + @request.session[:user_id] = 2 + get :new, :project_id => 1 + assert_response :success + assert_template 'new' + + issue = assigns(:issue) + assert_not_nil issue + assert_equal Project.find(1).trackers.first, issue.tracker + end + + def test_get_new_with_no_default_status_should_display_an_error + @request.session[:user_id] = 2 + IssueStatus.delete_all + + get :new, :project_id => 1 + assert_response 500 + assert_error_tag :content => /No default issue/ + end + + def test_get_new_with_no_tracker_should_display_an_error + @request.session[:user_id] = 2 + Tracker.delete_all + + get :new, :project_id => 1 + assert_response 500 + assert_error_tag :content => /No tracker/ + end + + def test_update_new_form + @request.session[:user_id] = 2 + xhr :post, :new, :project_id => 1, + :issue => {:tracker_id => 2, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5} + assert_response :success + assert_template 'attributes' + + issue = assigns(:issue) + assert_kind_of Issue, issue + assert_equal 1, issue.project_id + assert_equal 2, issue.tracker_id + assert_equal 'This is the test_new issue', issue.subject + end + + def test_post_create + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, + :status_id => 2, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5, + :start_date => '2010-11-07', + :estimated_hours => '', + :custom_field_values => {'2' => 'Value for field 2'}} + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new issue') + assert_not_nil issue + assert_equal 2, issue.author_id + assert_equal 3, issue.tracker_id + assert_equal 2, issue.status_id + assert_equal Date.parse('2010-11-07'), issue.start_date + assert_nil issue.estimated_hours + v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2}) + assert_not_nil v + assert_equal 'Value for field 2', v.value + end + + def test_post_new_with_group_assignment + group = Group.find(11) + project = Project.find(1) + project.members << Member.new(:principal => group, :roles => [Role.first]) + + with_settings :issue_group_assignment => '1' do + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => project.id, + :issue => {:tracker_id => 3, + :status_id => 1, + :subject => 'This is the test_new_with_group_assignment issue', + :assigned_to_id => group.id} + end + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue') + assert_not_nil issue + assert_equal group, issue.assigned_to + end + + def test_post_create_without_start_date_and_default_start_date_is_not_creation_date + Setting.default_issue_start_date_to_creation_date = 0 + + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, + :status_id => 2, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5, + :estimated_hours => '', + :custom_field_values => {'2' => 'Value for field 2'}} + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new issue') + assert_not_nil issue + assert_nil issue.start_date + end + + def test_post_create_without_start_date_and_default_start_date_is_creation_date + Setting.default_issue_start_date_to_creation_date = 1 + + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, + :status_id => 2, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5, + :estimated_hours => '', + :custom_field_values => {'2' => 'Value for field 2'}} + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new issue') + assert_not_nil issue + assert_equal Date.today, issue.start_date + end + + def test_post_create_and_continue + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5}, + :continue => '' + end + + issue = Issue.first(:order => 'id DESC') + assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3} + assert_not_nil flash[:notice], "flash was not set" + assert flash[:notice].include?("##{issue.id}"), "issue link not found in flash: #{flash[:notice]}" + end + + def test_post_create_without_custom_fields_param + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5} + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + end + + def test_post_create_with_required_custom_field_and_without_custom_fields_param + field = IssueCustomField.find_by_name('Database') + field.update_attribute(:is_required, true) + + @request.session[:user_id] = 2 + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5} + assert_response :success + assert_template 'new' + issue = assigns(:issue) + assert_not_nil issue + assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) + end + + def test_post_create_with_watchers + @request.session[:user_id] = 2 + ActionMailer::Base.deliveries.clear + + assert_difference 'Watcher.count', 2 do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is a new issue with watchers', + :description => 'This is the description', + :priority_id => 5, + :watcher_user_ids => ['2', '3']} + end + issue = Issue.find_by_subject('This is a new issue with watchers') + assert_not_nil issue + assert_redirected_to :controller => 'issues', :action => 'show', :id => issue + + # Watchers added + assert_equal [2, 3], issue.watcher_user_ids.sort + assert issue.watched_by?(User.find(3)) + # Watchers notified + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail) + end + + def test_post_create_subissue + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is a child issue', + :parent_issue_id => 2} + end + issue = Issue.find_by_subject('This is a child issue') + assert_not_nil issue + assert_equal Issue.find(2), issue.parent + end + + def test_post_create_subissue_with_non_numeric_parent_id + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is a child issue', + :parent_issue_id => 'ABC'} + end + issue = Issue.find_by_subject('This is a child issue') + assert_not_nil issue + assert_nil issue.parent + end + + def test_post_create_private + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is a private issue', + :is_private => '1'} + end + issue = Issue.first(:order => 'id DESC') + assert issue.is_private? + end + + def test_post_create_private_with_set_own_issues_private_permission + role = Role.find(1) + role.remove_permission! :set_issues_private + role.add_permission! :set_own_issues_private + + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is a private issue', + :is_private => '1'} + end + issue = Issue.first(:order => 'id DESC') + assert issue.is_private? + end + + def test_post_create_should_send_a_notification + ActionMailer::Base.deliveries.clear + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5, + :estimated_hours => '', + :custom_field_values => {'2' => 'Value for field 2'}} + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_post_create_should_preserve_fields_values_on_validation_failure + @request.session[:user_id] = 2 + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + # empty subject + :subject => '', + :description => 'This is a description', + :priority_id => 6, + :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}} + assert_response :success + assert_template 'new' + + assert_tag :textarea, :attributes => { :name => 'issue[description]' }, + :content => 'This is a description' + assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, + :child => { :tag => 'option', :attributes => { :selected => 'selected', + :value => '6' }, + :content => 'High' } + # Custom fields + assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' }, + :child => { :tag => 'option', :attributes => { :selected => 'selected', + :value => 'Oracle' }, + :content => 'Oracle' } + assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]', + :value => 'Value for field 2'} + end + + def test_post_create_should_ignore_non_safe_attributes + @request.session[:user_id] = 2 + assert_nothing_raised do + post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" } + end + end + + def test_post_create_with_attachment + set_tmp_attachments_directory + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + assert_difference 'Attachment.count' do + post :create, :project_id => 1, + :issue => { :tracker_id => '1', :subject => 'With attachment' }, + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}} + end + end + + issue = Issue.first(:order => 'id DESC') + attachment = Attachment.first(:order => 'id DESC') + + assert_equal issue, attachment.container + assert_equal 2, attachment.author_id + assert_equal 'testfile.txt', attachment.filename + assert_equal 'text/plain', attachment.content_type + assert_equal 'test file', attachment.description + assert_equal 59, attachment.filesize + assert File.exists?(attachment.diskfile) + assert_equal 59, File.size(attachment.diskfile) + end + + context "without workflow privilege" do + setup do + Workflow.delete_all(["role_id = ?", Role.anonymous.id]) + Role.anonymous.add_permission! :add_issues, :add_issue_notes + end + + context "#new" do + should "propose default status only" do + get :new, :project_id => 1 + assert_response :success + assert_template 'new' + assert_tag :tag => 'select', + :attributes => {:name => 'issue[status_id]'}, + :children => {:count => 1}, + :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}} + end + + should "accept default status" do + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is an issue', + :status_id => 1} + end + issue = Issue.last(:order => 'id') + assert_equal IssueStatus.default, issue.status + end + + should "ignore unauthorized status" do + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is an issue', + :status_id => 3} + end + issue = Issue.last(:order => 'id') + assert_equal IssueStatus.default, issue.status + end + end + + context "#update" do + should "ignore status change" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3} + end + assert_equal 1, Issue.find(1).status_id + end + + should "ignore attributes changes" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2} + end + issue = Issue.find(1) + assert_equal "Can't print recipes", issue.subject + assert_nil issue.assigned_to + end + end + end + + context "with workflow privilege" do + setup do + Workflow.delete_all(["role_id = ?", Role.anonymous.id]) + Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3) + Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4) + Role.anonymous.add_permission! :add_issues, :add_issue_notes + end + + context "#update" do + should "accept authorized status" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3} + end + assert_equal 3, Issue.find(1).status_id + end + + should "ignore unauthorized status" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2} + end + assert_equal 1, Issue.find(1).status_id + end + + should "accept authorized attributes changes" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2} + end + issue = Issue.find(1) + assert_equal 2, issue.assigned_to_id + end + + should "ignore unauthorized attributes changes" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'} + end + issue = Issue.find(1) + assert_equal "Can't print recipes", issue.subject + end + end + + context "and :edit_issues permission" do + setup do + Role.anonymous.add_permission! :add_issues, :edit_issues + end + + should "accept authorized status" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3} + end + assert_equal 3, Issue.find(1).status_id + end + + should "ignore unauthorized status" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2} + end + assert_equal 1, Issue.find(1).status_id + end + + should "accept authorized attributes changes" do + assert_difference 'Journal.count' do + put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2} + end + issue = Issue.find(1) + assert_equal "changed", issue.subject + assert_equal 2, issue.assigned_to_id + end + end + end + + def test_copy_issue + @request.session[:user_id] = 2 + get :new, :project_id => 1, :copy_from => 1 + assert_template 'new' + assert_not_nil assigns(:issue) + orig = Issue.find(1) + assert_equal orig.subject, assigns(:issue).subject + end + + def test_get_edit + @request.session[:user_id] = 2 + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + assert_not_nil assigns(:issue) + assert_equal Issue.find(1), assigns(:issue) + + # Be sure we don't display inactive IssuePriorities + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_get_edit_should_display_the_time_entry_form_with_log_time_permission + @request.session[:user_id] = 2 + Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time] + + get :edit, :id => 1 + assert_tag 'input', :attributes => {:name => 'time_entry[hours]'} + end + + def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :log_time + + get :edit, :id => 1 + assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'} + end + + def test_get_edit_with_params + @request.session[:user_id] = 2 + get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }, + :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id } + assert_response :success + assert_template 'edit' + + issue = assigns(:issue) + assert_not_nil issue + + assert_equal 5, issue.status_id + assert_tag :select, :attributes => { :name => 'issue[status_id]' }, + :child => { :tag => 'option', + :content => 'Closed', + :attributes => { :selected => 'selected' } } + + assert_equal 7, issue.priority_id + assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, + :child => { :tag => 'option', + :content => 'Urgent', + :attributes => { :selected => 'selected' } } + + assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' } + assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' }, + :child => { :tag => 'option', + :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } } + assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' } + end + + def test_update_edit_form + @request.session[:user_id] = 2 + xhr :post, :new, :project_id => 1, + :id => 1, + :issue => {:tracker_id => 2, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5} + assert_response :success + assert_template 'attributes' + + issue = assigns(:issue) + assert_kind_of Issue, issue + assert_equal 1, issue.id + assert_equal 1, issue.project_id + assert_equal 2, issue.tracker_id + assert_equal 'This is the test_new issue', issue.subject + end + + def test_update_using_invalid_http_verbs + @request.session[:user_id] = 2 + subject = 'Updated by an invalid http verb' + + get :update, :id => 1, :issue => {:subject => subject} + assert_not_equal subject, Issue.find(1).subject + + post :update, :id => 1, :issue => {:subject => subject} + assert_not_equal subject, Issue.find(1).subject + + delete :update, :id => 1, :issue => {:subject => subject} + assert_not_equal subject, Issue.find(1).subject + end + + def test_put_update_without_custom_fields_param + @request.session[:user_id] = 2 + ActionMailer::Base.deliveries.clear + + issue = Issue.find(1) + assert_equal '125', issue.custom_value_for(2).value + old_subject = issue.subject + new_subject = 'Subject modified by IssuesControllerTest#test_post_edit' + + assert_difference('Journal.count') do + assert_difference('JournalDetail.count', 2) do + put :update, :id => 1, :issue => {:subject => new_subject, + :priority_id => '6', + :category_id => '1' # no change + } + end + end + assert_redirected_to :action => 'show', :id => '1' + issue.reload + assert_equal new_subject, issue.subject + # Make sure custom fields were not cleared + assert_equal '125', issue.custom_value_for(2).value + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]") + assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}") + end + + def test_put_update_with_custom_field_change + @request.session[:user_id] = 2 + issue = Issue.find(1) + assert_equal '125', issue.custom_value_for(2).value + + assert_difference('Journal.count') do + assert_difference('JournalDetail.count', 3) do + put :update, :id => 1, :issue => {:subject => 'Custom field change', + :priority_id => '6', + :category_id => '1', # no change + :custom_field_values => { '2' => 'New custom value' } + } + end + end + assert_redirected_to :action => 'show', :id => '1' + issue.reload + assert_equal 'New custom value', issue.custom_value_for(2).value + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert mail.body.include?("Searchable field changed from 125 to New custom value") + end + + def test_put_update_with_status_and_assignee_change + issue = Issue.find(1) + assert_equal 1, issue.status_id + @request.session[:user_id] = 2 + assert_difference('TimeEntry.count', 0) do + put :update, + :id => 1, + :issue => { :status_id => 2, :assigned_to_id => 3 }, + :notes => 'Assigned to dlopper', + :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first } + end + assert_redirected_to :action => 'show', :id => '1' + issue.reload + assert_equal 2, issue.status_id + j = Journal.find(:first, :order => 'id DESC') + assert_equal 'Assigned to dlopper', j.notes + assert_equal 2, j.details.size + + mail = ActionMailer::Base.deliveries.last + assert mail.body.include?("Status changed from New to Assigned") + # subject should contain the new status + assert mail.subject.include?("(#{ IssueStatus.find(2).name })") + end + + def test_put_update_with_note_only + notes = 'Note added by IssuesControllerTest#test_update_with_note_only' + # anonymous user + put :update, + :id => 1, + :notes => notes + assert_redirected_to :action => 'show', :id => '1' + j = Journal.find(:first, :order => 'id DESC') + assert_equal notes, j.notes + assert_equal 0, j.details.size + assert_equal User.anonymous, j.user + + mail = ActionMailer::Base.deliveries.last + assert mail.body.include?(notes) + end + + def test_put_update_with_note_and_spent_time + @request.session[:user_id] = 2 + spent_hours_before = Issue.find(1).spent_hours + assert_difference('TimeEntry.count') do + put :update, + :id => 1, + :notes => '2.5 hours added', + :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id } + end + assert_redirected_to :action => 'show', :id => '1' + + issue = Issue.find(1) + + j = Journal.find(:first, :order => 'id DESC') + assert_equal '2.5 hours added', j.notes + assert_equal 0, j.details.size + + t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time') + assert_not_nil t + assert_equal 2.5, t.hours + assert_equal spent_hours_before + 2.5, issue.spent_hours + end + + def test_put_update_with_attachment_only + set_tmp_attachments_directory + + # Delete all fixtured journals, a race condition can occur causing the wrong + # journal to get fetched in the next find. + Journal.delete_all + + # anonymous user + assert_difference 'Attachment.count' do + put :update, :id => 1, + :notes => '', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}} + end + + assert_redirected_to :action => 'show', :id => '1' + j = Issue.find(1).journals.find(:first, :order => 'id DESC') + assert j.notes.blank? + assert_equal 1, j.details.size + assert_equal 'testfile.txt', j.details.first.value + assert_equal User.anonymous, j.user + + attachment = Attachment.first(:order => 'id DESC') + assert_equal Issue.find(1), attachment.container + assert_equal User.anonymous, attachment.author + assert_equal 'testfile.txt', attachment.filename + assert_equal 'text/plain', attachment.content_type + assert_equal 'test file', attachment.description + assert_equal 59, attachment.filesize + assert File.exists?(attachment.diskfile) + assert_equal 59, File.size(attachment.diskfile) + + mail = ActionMailer::Base.deliveries.last + assert mail.body.include?('testfile.txt') + end + + def test_put_update_with_attachment_that_fails_to_save + set_tmp_attachments_directory + + # Delete all fixtured journals, a race condition can occur causing the wrong + # journal to get fetched in the next find. + Journal.delete_all + + # Mock out the unsaved attachment + Attachment.any_instance.stubs(:create).returns(Attachment.new) + + # anonymous user + put :update, + :id => 1, + :notes => '', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} + assert_redirected_to :action => 'show', :id => '1' + assert_equal '1 file(s) could not be saved.', flash[:warning] + + end if Object.const_defined?(:Mocha) + + def test_put_update_with_no_change + issue = Issue.find(1) + issue.journals.clear + ActionMailer::Base.deliveries.clear + + put :update, + :id => 1, + :notes => '' + assert_redirected_to :action => 'show', :id => '1' + + issue.reload + assert issue.journals.empty? + # No email should be sent + assert ActionMailer::Base.deliveries.empty? + end + + def test_put_update_should_send_a_notification + @request.session[:user_id] = 2 + ActionMailer::Base.deliveries.clear + issue = Issue.find(1) + old_subject = issue.subject + new_subject = 'Subject modified by IssuesControllerTest#test_post_edit' + + put :update, :id => 1, :issue => {:subject => new_subject, + :priority_id => '6', + :category_id => '1' # no change + } + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_put_update_with_invalid_spent_time_hours_only + @request.session[:user_id] = 2 + notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time' + + assert_no_difference('Journal.count') do + put :update, + :id => 1, + :notes => notes, + :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"} + end + assert_response :success + assert_template 'edit' + + assert_error_tag :descendant => {:content => /Activity can't be blank/} + assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes + assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" } + end + + def test_put_update_with_invalid_spent_time_comments_only + @request.session[:user_id] = 2 + notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time' + + assert_no_difference('Journal.count') do + put :update, + :id => 1, + :notes => notes, + :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""} + end + assert_response :success + assert_template 'edit' + + assert_error_tag :descendant => {:content => /Activity can't be blank/} + assert_error_tag :descendant => {:content => /Hours can't be blank/} + assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes + assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" } + end + + def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject + issue = Issue.find(2) + @request.session[:user_id] = 2 + + put :update, + :id => issue.id, + :issue => { + :fixed_version_id => 4 + } + + assert_response :redirect + issue.reload + assert_equal 4, issue.fixed_version_id + assert_not_equal issue.project_id, issue.fixed_version.project_id + end + + def test_put_update_should_redirect_back_using_the_back_url_parameter + issue = Issue.find(2) + @request.session[:user_id] = 2 + + put :update, + :id => issue.id, + :issue => { + :fixed_version_id => 4 + }, + :back_url => '/issues' + + assert_response :redirect + assert_redirected_to '/issues' + end + + def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host + issue = Issue.find(2) + @request.session[:user_id] = 2 + + put :update, + :id => issue.id, + :issue => { + :fixed_version_id => 4 + }, + :back_url => 'http://google.com' + + assert_response :redirect + assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id + end + + def test_get_bulk_edit + @request.session[:user_id] = 2 + get :bulk_edit, :ids => [1, 2] + assert_response :success + assert_template 'bulk_edit' + + assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'} + + # Project specific custom field, date type + field = CustomField.find(9) + assert !field.is_for_all? + assert_equal 'date', field.field_format + assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'} + + # System wide custom field + assert CustomField.find(1).is_for_all? + assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'} + + # Be sure we don't display inactive IssuePriorities + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_get_bulk_edit_on_different_projects + @request.session[:user_id] = 2 + get :bulk_edit, :ids => [1, 2, 6] + assert_response :success + assert_template 'bulk_edit' + + # Can not set issues from different projects as children of an issue + assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'} + + # Project specific custom field, date type + field = CustomField.find(9) + assert !field.is_for_all? + assert !field.project_ids.include?(Issue.find(6).project_id) + assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'} + end + + def test_get_bulk_edit_with_user_custom_field + field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true) + + @request.session[:user_id] = 2 + get :bulk_edit, :ids => [1, 2] + assert_response :success + assert_template 'bulk_edit' + + assert_tag :select, + :attributes => {:name => "issue[custom_field_values][#{field.id}]"}, + :children => { + :only => {:tag => 'option'}, + :count => Project.find(1).users.count + 1 + } + end + + def test_get_bulk_edit_with_version_custom_field + field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true) + + @request.session[:user_id] = 2 + get :bulk_edit, :ids => [1, 2] + assert_response :success + assert_template 'bulk_edit' + + assert_tag :select, + :attributes => {:name => "issue[custom_field_values][#{field.id}]"}, + :children => { + :only => {:tag => 'option'}, + :count => Project.find(1).shared_versions.count + 1 + } + end + + def test_bulk_update + @request.session[:user_id] = 2 + # update issues priority + post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing', + :issue => {:priority_id => 7, + :assigned_to_id => '', + :custom_field_values => {'2' => ''}} + + assert_response 302 + # check that the issues were updated + assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} + + issue = Issue.find(1) + journal = issue.journals.find(:first, :order => 'created_on DESC') + assert_equal '125', issue.custom_value_for(2).value + assert_equal 'Bulk editing', journal.notes + assert_equal 1, journal.details.size + end + + def test_bulk_update_with_group_assignee + group = Group.find(11) + project = Project.find(1) + project.members << Member.new(:principal => group, :roles => [Role.first]) + + @request.session[:user_id] = 2 + # update issues assignee + post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing', + :issue => {:priority_id => '', + :assigned_to_id => group.id, + :custom_field_values => {'2' => ''}} + + assert_response 302 + assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to} + end + + def test_bulk_update_on_different_projects + @request.session[:user_id] = 2 + # update issues priority + post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing', + :issue => {:priority_id => 7, + :assigned_to_id => '', + :custom_field_values => {'2' => ''}} + + assert_response 302 + # check that the issues were updated + assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id) + + issue = Issue.find(1) + journal = issue.journals.find(:first, :order => 'created_on DESC') + assert_equal '125', issue.custom_value_for(2).value + assert_equal 'Bulk editing', journal.notes + assert_equal 1, journal.details.size + end + + def test_bulk_update_on_different_projects_without_rights + @request.session[:user_id] = 3 + user = User.find(3) + action = { :controller => "issues", :action => "bulk_update" } + assert user.allowed_to?(action, Issue.find(1).project) + assert ! user.allowed_to?(action, Issue.find(6).project) + post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail', + :issue => {:priority_id => 7, + :assigned_to_id => '', + :custom_field_values => {'2' => ''}} + assert_response 403 + assert_not_equal "Bulk should fail", Journal.last.notes + end + + def test_bullk_update_should_send_a_notification + @request.session[:user_id] = 2 + ActionMailer::Base.deliveries.clear + post(:bulk_update, + { + :ids => [1, 2], + :notes => 'Bulk editing', + :issue => { + :priority_id => 7, + :assigned_to_id => '', + :custom_field_values => {'2' => ''} + } + }) + + assert_response 302 + assert_equal 2, ActionMailer::Base.deliveries.size + end + + def test_bulk_update_status + @request.session[:user_id] = 2 + # update issues priority + post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status', + :issue => {:priority_id => '', + :assigned_to_id => '', + :status_id => '5'} + + assert_response 302 + issue = Issue.find(1) + assert issue.closed? + end + + def test_bulk_update_parent_id + @request.session[:user_id] = 2 + post :bulk_update, :ids => [1, 3], + :notes => 'Bulk editing parent', + :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'} + + assert_response 302 + parent = Issue.find(2) + assert_equal parent.id, Issue.find(1).parent_id + assert_equal parent.id, Issue.find(3).parent_id + assert_equal [1, 3], parent.children.collect(&:id).sort + end + + def test_bulk_update_custom_field + @request.session[:user_id] = 2 + # update issues priority + post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field', + :issue => {:priority_id => '', + :assigned_to_id => '', + :custom_field_values => {'2' => '777'}} + + assert_response 302 + + issue = Issue.find(1) + journal = issue.journals.find(:first, :order => 'created_on DESC') + assert_equal '777', issue.custom_value_for(2).value + assert_equal 1, journal.details.size + assert_equal '125', journal.details.first.old_value + assert_equal '777', journal.details.first.value + end + + def test_bulk_update_unassign + assert_not_nil Issue.find(2).assigned_to + @request.session[:user_id] = 2 + # unassign issues + post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'} + assert_response 302 + # check that the issues were updated + assert_nil Issue.find(2).assigned_to + end + + def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject + @request.session[:user_id] = 2 + + post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4} + + assert_response :redirect + issues = Issue.find([1,2]) + issues.each do |issue| + assert_equal 4, issue.fixed_version_id + assert_not_equal issue.project_id, issue.fixed_version.project_id + end + end + + def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter + @request.session[:user_id] = 2 + post :bulk_update, :ids => [1,2], :back_url => '/issues' + + assert_response :redirect + assert_redirected_to '/issues' + end + + def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host + @request.session[:user_id] = 2 + post :bulk_update, :ids => [1,2], :back_url => 'http://google.com' + + assert_response :redirect + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier + end + + def test_destroy_issue_with_no_time_entries + assert_nil TimeEntry.find_by_issue_id(2) + @request.session[:user_id] = 2 + post :destroy, :id => 2 + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert_nil Issue.find_by_id(2) + end + + def test_destroy_issues_with_time_entries + @request.session[:user_id] = 2 + post :destroy, :ids => [1, 3] + assert_response :success + assert_template 'destroy' + assert_not_nil assigns(:hours) + assert Issue.find_by_id(1) && Issue.find_by_id(3) + end + + def test_destroy_issues_and_destroy_time_entries + @request.session[:user_id] = 2 + post :destroy, :ids => [1, 3], :todo => 'destroy' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) + assert_nil TimeEntry.find_by_id([1, 2]) + end + + def test_destroy_issues_and_assign_time_entries_to_project + @request.session[:user_id] = 2 + post :destroy, :ids => [1, 3], :todo => 'nullify' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) + assert_nil TimeEntry.find(1).issue_id + assert_nil TimeEntry.find(2).issue_id + end + + def test_destroy_issues_and_reassign_time_entries_to_another_issue + @request.session[:user_id] = 2 + post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2 + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) + assert_equal 2, TimeEntry.find(1).issue_id + assert_equal 2, TimeEntry.find(2).issue_id + end + + def test_destroy_issues_from_different_projects + @request.session[:user_id] = 2 + post :destroy, :ids => [1, 2, 6], :todo => 'destroy' + assert_redirected_to :controller => 'issues', :action => 'index' + assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6)) + end + + def test_destroy_parent_and_child_issues + parent = Issue.generate!(:project_id => 1, :tracker_id => 1) + child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id) + assert child.is_descendant_of?(parent.reload) + + @request.session[:user_id] = 2 + assert_difference 'Issue.count', -2 do + post :destroy, :ids => [parent.id, child.id], :todo => 'destroy' + end + assert_response 302 + end + + def test_default_search_scope + get :index + assert_tag :div, :attributes => {:id => 'quick-search'}, + :child => {:tag => 'form', + :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/36da07b1ee2e0ce6db594d8c9206610d637ebf42.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/36da07b1ee2e0ce6db594d8c9206610d637ebf42.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Repository::Subversion < Repository + generator_for :type, :method => 'Subversion' + generator_for :url, :start => 'file:///test/svn' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/36/36ee24f61bb993329a397c77fd4b05efc6e92acd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/36/36ee24f61bb993329a397c77fd4b05efc6e92acd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class Issue < ActiveRecord::Base + generator_for :subject, :start => 'Subject 0' + generator_for :author, :method => :next_author + generator_for :priority, :method => :fetch_priority + + def self.next_author + User.generate_with_protected! + end + + def self.fetch_priority + IssuePriority.first || IssuePriority.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/3708cf8f04cafb1d769bb5ceca8ecd5dd9ef264d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/3708cf8f04cafb1d769bb5ceca8ecd5dd9ef264d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +<% reply_links = authorize_for('issues', 'edit') -%> +<% for journal in journals %> +
+

+ <%= avatar(journal.user, :size => "24") %> + <%= content_tag('a', '', :name => "note-#{journal.indice}")%> + <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

+ + <% if journal.details.any? %> +
    + <% for detail in journal.details %> +
  • <%= show_detail(detail) %>
  • + <% end %> +
+ <% end %> + <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %> +
+ <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> +<% end %> + +<% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/372b4534eab179905a7b1dc6353a83e941f61d9d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/372b4534eab179905a7b1dc6353a83e941f61d9d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negrita'; +jsToolBar.strings['Italic'] = 'Itálica'; +jsToolBar.strings['Underline'] = 'Subrayado'; +jsToolBar.strings['Deleted'] = 'Tachado'; +jsToolBar.strings['Code'] = 'Código fuente'; +jsToolBar.strings['Heading 1'] = 'Encabezado 1'; +jsToolBar.strings['Heading 2'] = 'Encabezado 2'; +jsToolBar.strings['Heading 3'] = 'Encabezado 3'; +jsToolBar.strings['Unordered list'] = 'Lista sin ordenar'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citar'; +jsToolBar.strings['Unquote'] = 'Quitar cita'; +jsToolBar.strings['Preformatted text'] = 'Texto con formato'; +jsToolBar.strings['Wiki link'] = 'Enlace a página Wiki'; +jsToolBar.strings['Image'] = 'Imagen'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/37653076d5bd98c98ab1be608add0cf094cbf5c5.svn-base Binary file .svn/pristine/37/37653076d5bd98c98ab1be608add0cf094cbf5c5.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/376863faf28c809b79e9482bad41eafa82991de6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/376863faf28c809b79e9482bad41eafa82991de6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +washington: + id: 1 + landmark_id: 1 + version: 1 + name: Washington, D.C. + latitude: 38.895 + longitude: -77.036667 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/376d8c99e588cd6ce8e1e869de342e76d55623d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/376d8c99e588cd6ce8e1e869de342e76d55623d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class AppAndPluginModel < ActiveRecord::Base + def self.report_location; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/379e1dce88d814d8a7bcf79ecfe42aa08a6ba5f8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/379e1dce88d814d8a7bcf79ecfe42aa08a6ba5f8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +<%= error_messages_for 'enumeration' %> +
+ +<%= hidden_field 'enumeration', 'type' %> + +

+<%= text_field 'enumeration', 'name' %>

+ +

+<%= check_box 'enumeration', 'active' %>

+ +

+<%= check_box 'enumeration', 'is_default' %>

+ + +<% @enumeration.custom_field_values.each do |value| %> +

<%= custom_field_tag_with_label :enumeration, value %>

+<% end %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/37ab6adb38ec399dce62202cc442ace6462d7703.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/37ab6adb38ec399dce62202cc442ace6462d7703.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 AttachmentsHelper + # Displays view/delete links to the attachments of the given object + # Options: + # :author -- author names are not displayed if set to false + def link_to_attachments(container, options = {}) + options.assert_valid_keys(:author) + + if container.attachments.any? + options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) + render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options} + end + end + + def render_api_attachment(attachment, api) + api.attachment do + api.id attachment.id + api.filename attachment.filename + api.filesize attachment.filesize + api.content_type attachment.content_type + api.description attachment.description + api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) + api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author + api.created_on attachment.created_on + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/37b31d80a7477985b5820b70128b01d1053a8cec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/37b31d80a7477985b5820b70128b01d1053a8cec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,89 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class AuthSourceLdapTest < ActiveSupport::TestCase + fixtures :auth_sources + + def setup + end + + def test_create + a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName') + assert a.save + end + + def test_should_strip_ldap_attributes + a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', + :attr_firstname => 'givenName ') + assert a.save + assert_equal 'givenName', a.reload.attr_firstname + end + + def test_replace_port_zero_to_389 + a = AuthSourceLdap.new( + :name => 'My LDAP', :host => 'ldap.example.net', :port => 0, + :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', + :attr_firstname => 'givenName ') + assert a.save + assert_equal 389, a.port + end + + if ldap_configured? + context '#authenticate' do + setup do + @auth = AuthSourceLdap.find(1) + end + + context 'with a valid LDAP user' do + should 'return the user attributes' do + attributes = @auth.authenticate('example1','123456') + assert attributes.is_a?(Hash), "An hash was not returned" + assert_equal 'Example', attributes[:firstname] + assert_equal 'One', attributes[:lastname] + assert_equal 'example1@redmine.org', attributes[:mail] + assert_equal @auth.id, attributes[:auth_source_id] + attributes.keys.each do |attribute| + assert User.new.respond_to?("#{attribute}="), "Unexpected :#{attribute} attribute returned" + end + end + end + + context 'with an invalid LDAP user' do + should 'return nil' do + assert_equal nil, @auth.authenticate('nouser','123456') + end + end + + context 'without a login' do + should 'return nil' do + assert_equal nil, @auth.authenticate('','123456') + end + end + + context 'without a password' do + should 'return nil' do + assert_equal nil, @auth.authenticate('edavis','') + end + end + + end + else + puts '(Test LDAP server not configured)' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/37c265b21c0c5ae4d4c2ec8cfe9dabe532a90dd1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/37c265b21c0c5ae4d4c2ec8cfe9dabe532a90dd1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ +
+<%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %> +<%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> +
+ +

<%=h @document.title %>

+ +

<%=h @document.category.name %>
+<%= format_date @document.created_on %>

+
+<%= textilizable @document.description, :attachments => @document.attachments %> +
+ +

<%= l(:label_attachment_plural) %>

+<%= link_to_attachments @document %> + +<% if authorize_for('documents', 'add_attachment') %> +

<%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", + :id => 'attach_files_link' %>

+ <% form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> +
+

<%= render :partial => 'attachments/form' %>

+
+ <%= submit_tag l(:button_add) %> + <% end %> +<% end %> + +<% html_title @document.title -%> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/37cb74d76d2538aa7b67f4fd3bd97c711823022f.svn-base Binary file .svn/pristine/37/37cb74d76d2538aa7b67f4fd3bd97c711823022f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/37/37f5b9c7485d4f52f7798b9d54c2aab8e937964a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/37/37f5b9c7485d4f52f7798b9d54c2aab8e937964a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class TokenTest < ActiveSupport::TestCase + fixtures :tokens + + def test_create + token = Token.new + token.save + assert_equal 40, token.value.length + assert !token.expired? + end + + def test_create_should_remove_existing_tokens + user = User.find(1) + t1 = Token.create(:user => user, :action => 'autologin') + t2 = Token.create(:user => user, :action => 'autologin') + assert_not_equal t1.value, t2.value + assert !Token.exists?(t1.id) + assert Token.exists?(t2.id) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/3811122058c03a62723dc5f9b7f68e09577985b6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/3811122058c03a62723dc5f9b7f68e09577985b6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +$:.unshift(File.dirname(__FILE__) + '/../../../rails/activesupport/lib') +$:.unshift(File.dirname(__FILE__) + '/../../../rails/activerecord/lib') +$:.unshift(File.dirname(__FILE__) + '/../lib') +require 'test/unit' +begin + require 'active_support' + require 'active_record' + require 'active_record/fixtures' +rescue LoadError + require 'rubygems' + retry +end +require 'acts_as_versioned' + +config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) +ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") +ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']} +ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) + +load(File.dirname(__FILE__) + "/schema.rb") + +# set up custom sequence on widget_versions for DBs that support sequences +if ENV['DB'] == 'postgresql' + ActiveRecord::Base.connection.execute "DROP SEQUENCE widgets_seq;" rescue nil + ActiveRecord::Base.connection.remove_column :widget_versions, :id + ActiveRecord::Base.connection.execute "CREATE SEQUENCE widgets_seq START 101;" + ActiveRecord::Base.connection.execute "ALTER TABLE widget_versions ADD COLUMN id INTEGER PRIMARY KEY DEFAULT nextval('widgets_seq');" +end + +Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/" +$:.unshift(Test::Unit::TestCase.fixture_path) + +class Test::Unit::TestCase #:nodoc: + # Turn off transactional fixtures if you're working with MyISAM tables in MySQL + self.use_transactional_fixtures = true + + # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david) + self.use_instantiated_fixtures = false + + # Add more helper methods to be used by all tests here... +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/3813f5e1b5a3dcfe71214c111cf9817ac22039cc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/3813f5e1b5a3dcfe71214c111cf9817ac22039cc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class GroupCustomField < CustomField + def type_name + :label_group_plural + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/384178c4f05b1a0eb059a8f4d3cd70f8c0aec17d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/384178c4f05b1a0eb059a8f4d3cd70f8c0aec17d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,219 @@ +require 'test/unit' + +require 'rubygems' +require 'active_record' + +$:.unshift File.dirname(__FILE__) + '/../lib' +require File.dirname(__FILE__) + '/../init' + +class Test::Unit::TestCase + def assert_queries(num = 1) + $query_count = 0 + yield + ensure + assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed." + end + + def assert_no_queries(&block) + assert_queries(0, &block) + end +end + +ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:") + +# AR keeps printing annoying schema statements +$stdout = StringIO.new + +def setup_db + ActiveRecord::Base.logger + ActiveRecord::Schema.define(:version => 1) do + create_table :mixins do |t| + t.column :type, :string + t.column :parent_id, :integer + end + end +end + +def teardown_db + ActiveRecord::Base.connection.tables.each do |table| + ActiveRecord::Base.connection.drop_table(table) + end +end + +class Mixin < ActiveRecord::Base +end + +class TreeMixin < Mixin + acts_as_tree :foreign_key => "parent_id", :order => "id" +end + +class TreeMixinWithoutOrder < Mixin + acts_as_tree :foreign_key => "parent_id" +end + +class RecursivelyCascadedTreeMixin < Mixin + acts_as_tree :foreign_key => "parent_id" + has_one :first_child, :class_name => 'RecursivelyCascadedTreeMixin', :foreign_key => :parent_id +end + +class TreeTest < Test::Unit::TestCase + + def setup + setup_db + @root1 = TreeMixin.create! + @root_child1 = TreeMixin.create! :parent_id => @root1.id + @child1_child = TreeMixin.create! :parent_id => @root_child1.id + @root_child2 = TreeMixin.create! :parent_id => @root1.id + @root2 = TreeMixin.create! + @root3 = TreeMixin.create! + end + + def teardown + teardown_db + end + + def test_children + assert_equal @root1.children, [@root_child1, @root_child2] + assert_equal @root_child1.children, [@child1_child] + assert_equal @child1_child.children, [] + assert_equal @root_child2.children, [] + end + + def test_parent + assert_equal @root_child1.parent, @root1 + assert_equal @root_child1.parent, @root_child2.parent + assert_nil @root1.parent + end + + def test_delete + assert_equal 6, TreeMixin.count + @root1.destroy + assert_equal 2, TreeMixin.count + @root2.destroy + @root3.destroy + assert_equal 0, TreeMixin.count + end + + def test_insert + @extra = @root1.children.create + + assert @extra + + assert_equal @extra.parent, @root1 + + assert_equal 3, @root1.children.size + assert @root1.children.include?(@extra) + assert @root1.children.include?(@root_child1) + assert @root1.children.include?(@root_child2) + end + + def test_ancestors + assert_equal [], @root1.ancestors + assert_equal [@root1], @root_child1.ancestors + assert_equal [@root_child1, @root1], @child1_child.ancestors + assert_equal [@root1], @root_child2.ancestors + assert_equal [], @root2.ancestors + assert_equal [], @root3.ancestors + end + + def test_root + assert_equal @root1, TreeMixin.root + assert_equal @root1, @root1.root + assert_equal @root1, @root_child1.root + assert_equal @root1, @child1_child.root + assert_equal @root1, @root_child2.root + assert_equal @root2, @root2.root + assert_equal @root3, @root3.root + end + + def test_roots + assert_equal [@root1, @root2, @root3], TreeMixin.roots + end + + def test_siblings + assert_equal [@root2, @root3], @root1.siblings + assert_equal [@root_child2], @root_child1.siblings + assert_equal [], @child1_child.siblings + assert_equal [@root_child1], @root_child2.siblings + assert_equal [@root1, @root3], @root2.siblings + assert_equal [@root1, @root2], @root3.siblings + end + + def test_self_and_siblings + assert_equal [@root1, @root2, @root3], @root1.self_and_siblings + assert_equal [@root_child1, @root_child2], @root_child1.self_and_siblings + assert_equal [@child1_child], @child1_child.self_and_siblings + assert_equal [@root_child1, @root_child2], @root_child2.self_and_siblings + assert_equal [@root1, @root2, @root3], @root2.self_and_siblings + assert_equal [@root1, @root2, @root3], @root3.self_and_siblings + end +end + +class TreeTestWithEagerLoading < Test::Unit::TestCase + + def setup + teardown_db + setup_db + @root1 = TreeMixin.create! + @root_child1 = TreeMixin.create! :parent_id => @root1.id + @child1_child = TreeMixin.create! :parent_id => @root_child1.id + @root_child2 = TreeMixin.create! :parent_id => @root1.id + @root2 = TreeMixin.create! + @root3 = TreeMixin.create! + + @rc1 = RecursivelyCascadedTreeMixin.create! + @rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id + @rc3 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc2.id + @rc4 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc3.id + end + + def teardown + teardown_db + end + + def test_eager_association_loading + roots = TreeMixin.find(:all, :include => :children, :conditions => "mixins.parent_id IS NULL", :order => "mixins.id") + assert_equal [@root1, @root2, @root3], roots + assert_no_queries do + assert_equal 2, roots[0].children.size + assert_equal 0, roots[1].children.size + assert_equal 0, roots[2].children.size + end + end + + def test_eager_association_loading_with_recursive_cascading_three_levels_has_many + root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :children => { :children => :children } }, :order => 'mixins.id') + assert_equal @rc4, assert_no_queries { root_node.children.first.children.first.children.first } + end + + def test_eager_association_loading_with_recursive_cascading_three_levels_has_one + root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :first_child => { :first_child => :first_child } }, :order => 'mixins.id') + assert_equal @rc4, assert_no_queries { root_node.first_child.first_child.first_child } + end + + def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to + leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :parent => { :parent => :parent } }, :order => 'mixins.id DESC') + assert_equal @rc1, assert_no_queries { leaf_node.parent.parent.parent } + end +end + +class TreeTestWithoutOrder < Test::Unit::TestCase + + def setup + setup_db + @root1 = TreeMixinWithoutOrder.create! + @root2 = TreeMixinWithoutOrder.create! + end + + def teardown + teardown_db + end + + def test_root + assert [@root1, @root2].include?(TreeMixinWithoutOrder.root) + end + + def test_roots + assert_equal [], [@root1, @root2] - TreeMixinWithoutOrder.roots + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/384c8a0657187a62ce9686aa38d6cb462cd66e8f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/384c8a0657187a62ce9686aa38d6cb462cd66e8f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class ChangeJournalDetailsValuesToText < ActiveRecord::Migration + def self.up + change_column :journal_details, :old_value, :text + change_column :journal_details, :value, :text + end + + def self.down + change_column :journal_details, :old_value, :string + change_column :journal_details, :value, :string + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/387d439159b4d0ddd79c12022e45def5fc069c4f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/387d439159b4d0ddd79c12022e45def5fc069c4f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class EnabledModule < ActiveRecord::Base + belongs_to :project + + validates_presence_of :name + validates_uniqueness_of :name, :scope => :project_id + + after_create :module_enabled + + private + + # after_create callback used to do things when a module is enabled + def module_enabled + case name + when 'wiki' + # Create a wiki with a default start page + if project && project.wiki.nil? + Wiki.create(:project => project, :start_page => 'Wiki') + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/388380478a42a623e2dea4570d513e4016b08ee9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/388380478a42a623e2dea4570d513e4016b08ee9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +washington: + id: 1 + name: Washington, D.C. + latitude: 38.895 + longitude: -77.036667 + version: 1 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/389e9dcc20c4e06169902989d099cd6ec772aa7a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/389e9dcc20c4e06169902989d099cd6ec772aa7a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,274 @@ += EDGE + +* Samuel Williams (http://www.oriontransfer.co.nz/): + Thanks to Tekin for his patches. + Updated migrations system to tie in more closely with the current rails mechanism. + Rake task for updating database schema info + rake db:migrate:upgrade_plugin_migrations + Please see http://engines.lighthouseapp.com/projects/10178-engines-plugin/tickets/17 for more information. + +* Refactored the view loading to work with changes in Edge Rails + +* Fixed integration of plugin migrations with the new, default timestamped migrations in Edge Rails + +* Refactored tests into the plugin itself - the plugin can now generate its own test_app harness and run tests within it. + + += 2.0.0 - (ANOTHER) MASSIVE INTERNAL REFACTORING + +* Engines now conforms to the new plugin loading mechanism, delegating plugin load order and lots of other things to Rails itself. + + + += 1.2.2 + +* Added the ability to code mix different types of files, cleaning up the existing code-mixing implementation slightly (Ticket #271) + + += 1.2.1 + +* Added documentation to clarify some of the issues with Rails unloading classes that aren't required using "require_dependency" (Ticket #266) + +* Fixed a bug where test_help was being loaded when it wasn't needed, and was actually causing problems (Ticket #265) + + += 1.2.0 - MASSIVE INTERNAL REFACTORING + +* !!!Support for Rails < 1.2 has been dropped!!!; if you are using Rails =< 1.1.6, please use Engines 1.1.6, available from http://svn.rails-engines.org/engines/tags/rel_1.1.6 + +* Engines are dead! Long live plugins! There is now no meaningful notion of an engine - all plugins can take advantage of the more powerful features that the engines plugin provides by including app directories, etc. + +* Init_engine.rb is no longer used; please use the plugin-standard init.rb instead. + +* Engines.start is no longer required; please use the config.plugins array provided by Rails instead + +* To get the most benefit from Engines, set config.plugins to ["engines", "*"] to load the engines plugin first, and then all other plugins in their normal order after. + +* Access all loaded plugins via the new Rails.plugins array, and by name using Rails.plugins[:plugin_name]. + +* Access plugin metadata loaded automatically from about.yml: Rails.plugins[:name].about. Plugin#version is provided directly, for easy access. + +* Module.config is has been removed - use mattr_accessor instead, and initialize your default values via the init.rb mechanism. + +* Public asset helpers have been rewritten; instead of engine_stylesheet, now use stylesheet_link_tag :name, :plugin => "plugin_name" + +* Plugin migrations have been reworked to integrate into the main migration stream. Please run script/generate plugin_migration to create plugin migrations in your main application. + +* The fixture method for loading fixtures against any class has been removed; instead, engines will now provide a mechanism for loading fixtures from all plugins, by mirroring fixtures into a common location. + +* All references to engines have been removed; For example, any rake tasks which applied to engines now apply to all plugins. The default Rails rake tasks for plugins are overridden where necessary. + +* Layouts can now be shared via plugins - inspiration gratefully taken from PluginAWeek's plugin_routing :) + +* Actual routing from plugins is now possible, by including routes.rb in your plugin directory and using the from_plugin method in config/routes.rb (Ticket #182) + +* Controllers are no longer loaded twice if they're not present in the normal app/ directory (Ticket #177) + +* The preferred location for javascripts/stylesheets/etc is now 'assets' rather than 'public' + +* Ensure that plugins started before routing have their controllers appropriately added to config.controller_paths (Ticket #258) + +* Removed Engines.version - it's not longer relevant, now we're loading version information from about.yml files. + +* Added a huge amount of documentation to all new modules. + +* Added new warning message if installation of engines 1.2.x is attempted in a Rails 1.1.x application + +* Added details of the removal of the config method to UPGRADING + +* Removed the plugins:info rake task in favour of adding information to script/about via the Rails::Info module (Ticket #261) + +* Improved handling of testing and documentation tasks for plugins + + + += 1.1.4 + +* Fixed creation of multipart emails (Ticket #190) + +* Added a temporary fix to the code-mixing issue. In your engine's test/test_helper.rb, please add the following lines: + + # Ensure that the code mixing and view loading from the application is disabled + Engines.disable_app_views_loading = true + Engines.disable_app_code_mixing = true + + which will prevent code mixing for controllers and helpers, and loading views from the application. One thing to remember is to load any controllers/helpers using 'require_or_load' in your tests, to ensure that the engine behaviour is respected (Ticket #135) + +* Added tasks to easily test engines individually (Ticket #120) + +* Fixture extensions will now fail with an exception if the corresponding class cannot be loaded (Ticket #138) + +* Patch for new routing/controller loading in Rails 1.1.6. The routing code is now replaced with the contents of config.controller_paths, along with controller paths from any started engines (Ticket #196) + +* Rails' Configuration instance is now stored, and available from all engines and plugins. + + + += 1.1.3 + +* Fixed README to show 'models' rather than 'model' class (Ticket #167) +* Fixed dependency loading to work with Rails 1.1.4 (Ticket #180) + + + += 1.1.2 + +* Added better fix to version checking (Ticket #130, jdell@gbdev.com). + +* Fixed generated init_engine.rb so that VERSION module doesn't cause probems (Ticket #131, japgolly@gmail.com) + +* Fixed error with Rails 1.0 when trying to ignore the engine_schema_info table (Ticket #132, snowblink@gmail.com) + +* Re-added old style rake tasks (Ticket #133) + +* No longer adding all subdirectories of /app or /lib, as this can cause issues when files are grouped in modules (Ticket #149, kasatani@gmail.com) + +* Fixed engine precidence ordering for Rails 1.1 (Ticket #146) + +* Added new Engines.each method to assist in processing the engines in the desired order (Ticket #146) + +* Fixed annoying error message at appears when starting the console in development mode (Ticket #134) + +* Engines is now super-careful about loading the correct version of Rails from vendor (Ticket #154) + + + += 1.1.1 + +* Fixed migration rake task failing when given a specific version (Ticket #115) + +* Added new rake task "test:engines" which will test engines (and other plugins) but ensure that the test database is cloned from development beforehand (Ticket #125) + +* Fixed issue where 'engine_schema_info' table was included in schema dumps (Ticket #87) + +* Fixed multi-part emails (Ticket #121) + +* Added an 'install.rb' file to new engines created by the bundled generator, which installs the engines plugin automatically if it doesn't already exist (Ticket #122) + +* Added a default VERSION module to generated engines (Ticket #123) + +* Refactored copying of engine's public files to a method of an Engine instance. You can now call Engines.get(:engine_name).copy_public_files (Ticket #108) + +* Changed engine generator templates from .rb files to .erb files (Ticket #106) + +* Fixed the test_helper.erb file to use the correct testing extensions and not load any schema - the schema will be cloned automatically via rake test:engines + +* Fixed problem when running with Rails 1.1.1 where version wasn't determined correctly (Ticket #129) + +* Fixed bug preventing engines from loading when both Rails 1.1.0 and 1.1.1 gems are installed and in use. + +* Updated version (d'oh!) + + + += 1.1.0 + +* Improved regexp matching for Rails 1.0 engines with peculiar paths + +* Engine instance objects can be accessed via Engines[:name], an alias for Engines.get(:name) (Ticket #99) + +* init_engine.rb is now processed as the final step in the Engine.start process, so it can access files within the lib directory, which is now in the $LOAD_PATH at that point. (Ticket #99) + +* Clarified MIT license (Ticket #98) + +* Updated Rake tasks to integrate smoothly with Rails 1.1 namespaces + +* Changed the version to "1.1.0 (svn)" + +* Added more information about using the plugin with Edge Rails to the README + +* moved extensions into lib/engines/ directory to enable use of Engines module in extension code. + +* Added conditional require_or_load method which attempts to detect the current Rails version. To use the Edge Rails version of the loading mechanism, add the line: + +* Engines.config :edge, true + +* to your environment.rb file. + +* Merged changes from /branches/edge and /branches/rb_1.0 into /trunk + +* engine_schema_info now respects the prefix/suffixes set for ActiveRecord::Base (Ticket #67) + +* added ActiveRecord::Base.wrapped_table_name(name) method to assist in determining the correct table name + + + += 1.0.6 + +* Added ability to determine version information for engines: rake engine_info + +* Added a custom logger for the Engines module, to stop pollution of the Rails logs. + +* Added some more tests (in particular, see rails_engines/applications/engines_test). + +* Another attempt at solving Ticket #53 - controllers and helpers should now be loadable from modules, and if a full path (including RAILS_ROOT/ENGINES_ROOT) is given, it should be safely stripped from the require filename such that corresponding files can be located in any active engines. In other words, controller/helper overloading should now completely work, even if the controllers/helpers are in modules. + +* Added (finally) patch from Ticket #22 - ActionMailer helpers should now load + +* Removed support for Engines.start :engine, :engine_name => 'whatever'. It was pointless. + +* Fixed engine name referencing; engine_stylesheet/engine_javascript can now happily use shorthand engine names (i.e. :test == :test_engine) (Ticket #45) + +* Fixed minor documentation error ('Engine.start' ==> 'Engines.start') (Ticket #57) + +* Fixed double inclusion of RAILS_ROOT in engine_migrate rake task (Ticket #61) + +* Added ability to force config values even if given as a hash (Ticket #62) + + + += 1.0.5 + +* Fixed bug stopping fixtures from loading with PostgreSQL + + + += 1.0.4 + +* Another attempt at loading controllers within modules (Ticket #56) + + + += 1.0.3 + +* Fixed serious dependency bug stopping controllers being loaded (Ticket #56) + + + += 1.0.2 + +* Fixed bug with overloading controllers in modules from /app directory + +* Fixed exception thrown when public files couldn't be created; exception is now logged (Ticket #52) + +* Fixed problem with generated test_helper.rb file via File.expand_path (Ticket #50) + + + += 1.0.1 + +* Added engine generator for creation of new engines + +* Fixed 'Engine' typo in README + +* Fixed bug in fixtures extensions + +* Fixed /lib path management bug + +* Added method to determine public directory location from Engine object + +* Fixed bug in the error message in get_engine_dir() + +* Added proper component loading + +* Added preliminary tests for the config() methods module + + + += pre-v170 + +* Fixed copyright notices to point to DHH, rather than me. + +* Moved extension require statements into lib/engines.rb, so the will be loaded if another module/file calls require 'engines + +* Added a CHANGELOG file (this file) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/38a76f88bf0eaa9fbee317ff5425fe91fe1739e1.svn-base Binary file .svn/pristine/38/38a76f88bf0eaa9fbee317ff5425fe91fe1739e1.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/38ca6dda2ba6a1320c43393fa70400cd1996e3e9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/38ca6dda2ba6a1320c43393fa70400cd1996e3e9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,130 @@ +require 'test/unit' + +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +class ExamplesTest < Test::Unit::TestCase + + def test_examples + # output as HTML div (using inline CSS styles) + div = CodeRay.scan('puts "Hello, world!"', :ruby).div + assert_equal <<-DIV, div +
+
puts "Hello, world!"
+
+ DIV + + # ...with line numbers + div = CodeRay.scan(<<-CODE.chomp, :ruby).div(:line_numbers => :table) +5.times do + puts 'Hello, world!' +end + CODE + assert_equal <<-DIV, div + + + +
1
+2
+3
+
5.times do
+  puts 'Hello, world!'
+end
+ DIV + + # output as standalone HTML page (using CSS classes) + page = CodeRay.scan('puts "Hello, world!"', :ruby).page + assert page[<<-PAGE] + + + + + +
+
puts "Hello, world!"
+ + + PAGE + + # keep scanned tokens for later use + tokens = CodeRay.scan('{ "just": "an", "example": 42 }', :json) + assert_kind_of CodeRay::TokensProxy, tokens + + assert_equal ["{", :operator, " ", :space, :begin_group, :key, + "\"", :delimiter, "just", :content, "\"", :delimiter, + :end_group, :key, ":", :operator, " ", :space, + :begin_group, :string, "\"", :delimiter, "an", :content, + "\"", :delimiter, :end_group, :string, ",", :operator, + " ", :space, :begin_group, :key, "\"", :delimiter, + "example", :content, "\"", :delimiter, :end_group, :key, + ":", :operator, " ", :space, "42", :integer, + " ", :space, "}", :operator], tokens.tokens + + # produce a token statistic + assert_equal <<-STATISTIC, tokens.statistic + +Code Statistics + +Tokens 26 + Non-Whitespace 15 +Bytes Total 31 + +Token Types (7): + type count ratio size (average) +------------------------------------------------------------- + TOTAL 26 100.00 % 1.2 + delimiter 6 23.08 % 1.0 + operator 5 19.23 % 1.0 + space 5 19.23 % 1.0 + key 4 15.38 % 0.0 + :begin_group 3 11.54 % 0.0 + :end_group 3 11.54 % 0.0 + content 3 11.54 % 4.3 + string 2 7.69 % 0.0 + integer 1 3.85 % 2.0 + + STATISTIC + + # count the tokens + assert_equal 26, tokens.count + + # produce a HTML div, but with CSS classes + div = tokens.div(:css => :class) + assert_equal <<-DIV, div +
+
{ "just": "an", "example": 42 }
+
+ DIV + + # highlight a file (HTML div); guess the file type base on the extension + require 'coderay/helpers/file_type' + assert_equal :ruby, CodeRay::FileType[__FILE__] + + # get a new scanner for Python + python_scanner = CodeRay.scanner :python + assert_kind_of CodeRay::Scanners::Python, python_scanner + + # get a new encoder for terminal + terminal_encoder = CodeRay.encoder :term + assert_kind_of CodeRay::Encoders::Terminal, terminal_encoder + + # scanning into tokens + tokens = python_scanner.tokenize 'import this; # The Zen of Python' + assert_equal ["import", :keyword, " ", :space, "this", :include, + ";", :operator, " ", :space, "# The Zen of Python", :comment], tokens + + # format the tokens + term = terminal_encoder.encode_tokens(tokens) + assert_equal "\e[1;31mimport\e[0m \e[33mthis\e[0m; \e[37m# The Zen of Python\e[0m", term + + # re-using scanner and encoder + ruby_highlighter = CodeRay::Duo[:ruby, :div] + div = ruby_highlighter.encode('puts "Hello, world!"') + assert_equal <<-DIV, div +
+
puts "Hello, world!"
+
+ DIV + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/38d3fc6a695b34cdb3895e43b2a6149999c95fa1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/38d3fc6a695b34cdb3895e43b2a6149999c95fa1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +require 'openid/store/interface' + +module OpenIdAuthentication + class DbStore < OpenID::Store::Interface + def self.cleanup_nonces + now = Time.now.to_i + Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew]) + end + + def self.cleanup_associations + now = Time.now.to_i + Association.delete_all(['issued + lifetime > ?',now]) + end + + def store_association(server_url, assoc) + remove_association(server_url, assoc.handle) + Association.create(:server_url => server_url, + :handle => assoc.handle, + :secret => assoc.secret, + :issued => assoc.issued, + :lifetime => assoc.lifetime, + :assoc_type => assoc.assoc_type) + end + + def get_association(server_url, handle = nil) + assocs = if handle.blank? + Association.find_all_by_server_url(server_url) + else + Association.find_all_by_server_url_and_handle(server_url, handle) + end + + assocs.reverse.each do |assoc| + a = assoc.from_record + if a.expires_in == 0 + assoc.destroy + else + return a + end + end if assocs.any? + + return nil + end + + def remove_association(server_url, handle) + Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0 + end + + def use_nonce(server_url, timestamp, salt) + return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt) + return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew + Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt) + return true + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/38/38de9a35c49c6806866d6eea334cfca945dbc5f9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/38/38de9a35c49c6806866d6eea334cfca945dbc5f9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddMissingIndexesToWorkflows < ActiveRecord::Migration + def self.up + add_index :workflows, :old_status_id + add_index :workflows, :role_id + add_index :workflows, :new_status_id + end + + def self.down + remove_index :workflows, :old_status_id + remove_index :workflows, :role_id + remove_index :workflows, :new_status_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/39/3902557efe433942347c0cf86447979527ade652.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/39/3902557efe433942347c0cf86447979527ade652.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +Copyright (c) 2007 West Arete Computing, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/39/390e71b002ea8073c16b9d8e33ea8c3450b2266a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/39/390e71b002ea8073c16b9d8e33ea8c3450b2266a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,117 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::PluginTest < ActiveSupport::TestCase + + def setup + @klass = Redmine::Plugin + # In case some real plugins are installed + @klass.clear + end + + def teardown + @klass.clear + end + + def test_register + @klass.register :foo do + name 'Foo plugin' + url 'http://example.net/plugins/foo' + author 'John Smith' + author_url 'http://example.net/jsmith' + description 'This is a test plugin' + version '0.0.1' + settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings' + end + + assert_equal 1, @klass.all.size + + plugin = @klass.find('foo') + assert plugin.is_a?(Redmine::Plugin) + assert_equal :foo, plugin.id + assert_equal 'Foo plugin', plugin.name + assert_equal 'http://example.net/plugins/foo', plugin.url + assert_equal 'John Smith', plugin.author + assert_equal 'http://example.net/jsmith', plugin.author_url + assert_equal 'This is a test plugin', plugin.description + assert_equal '0.0.1', plugin.version + end + + def test_requires_redmine + test = self + version = Redmine::VERSION.to_a.slice(0,3).join('.') + + @klass.register :foo do + test.assert requires_redmine(:version_or_higher => '0.1.0') + test.assert requires_redmine(:version_or_higher => version) + test.assert requires_redmine(version) + test.assert_raise Redmine::PluginRequirementError do + requires_redmine(:version_or_higher => '99.0.0') + end + + test.assert requires_redmine(:version => version) + test.assert requires_redmine(:version => [version, '99.0.0']) + test.assert_raise Redmine::PluginRequirementError do + requires_redmine(:version => '99.0.0') + end + test.assert_raise Redmine::PluginRequirementError do + requires_redmine(:version => ['98.0.0', '99.0.0']) + end + end + end + + def test_requires_redmine_plugin + test = self + other_version = '0.5.0' + + @klass.register :other do + name 'Other' + version other_version + end + + @klass.register :foo do + test.assert requires_redmine_plugin(:other, :version_or_higher => '0.1.0') + test.assert requires_redmine_plugin(:other, :version_or_higher => other_version) + test.assert requires_redmine_plugin(:other, other_version) + test.assert_raise Redmine::PluginRequirementError do + requires_redmine_plugin(:other, :version_or_higher => '99.0.0') + end + + test.assert requires_redmine_plugin(:other, :version => other_version) + test.assert requires_redmine_plugin(:other, :version => [other_version, '99.0.0']) + test.assert_raise Redmine::PluginRequirementError do + requires_redmine_plugin(:other, :version => '99.0.0') + end + test.assert_raise Redmine::PluginRequirementError do + requires_redmine_plugin(:other, :version => ['98.0.0', '99.0.0']) + end + # Missing plugin + test.assert_raise Redmine::PluginNotFound do + requires_redmine_plugin(:missing, :version_or_higher => '0.1.0') + end + test.assert_raise Redmine::PluginNotFound do + requires_redmine_plugin(:missing, '0.1.0') + end + test.assert_raise Redmine::PluginNotFound do + requires_redmine_plugin(:missing, :version => '0.1.0') + end + + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/39/3989df463d71da05bed8c7a24a4bb085b8755d7f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/39/3989df463d71da05bed8c7a24a4bb085b8755d7f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +To: +Subject: Ticket by unknown user +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit + +This is a ticket submitted by an unknown user. + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/39/39e52a0654ea7d5e49b76b29ba4c1190481acad6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/39/39e52a0654ea7d5e49b76b29ba4c1190481acad6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,118 @@ +# RedMine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang +# +# FileSystem adapter +# File written by Paul Rivier, at Demotera. +# +# 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 'redmine/scm/adapters/abstract_adapter' +require 'find' + +module Redmine + module Scm + module Adapters + class FilesystemAdapter < AbstractAdapter + + class << self + def client_available + true + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @url = with_trailling_slash(url) + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def format_path_ends(path, leading=true, trailling=true) + path = leading ? with_leading_slash(path) : + without_leading_slash(path) + trailling ? with_trailling_slash(path) : + without_trailling_slash(path) + end + + def info + info = Info.new({:root_url => target(), + :lastrev => nil + }) + info + rescue CommandFailed + return nil + end + + def entries(path="", identifier=nil, options={}) + entries = Entries.new + trgt_utf8 = target(path) + trgt = scm_iconv(@path_encoding, 'UTF-8', trgt_utf8) + Dir.new(trgt).each do |e1| + e_utf8 = scm_iconv('UTF-8', @path_encoding, e1) + next if e_utf8.blank? + relative_path_utf8 = format_path_ends( + (format_path_ends(path,false,true) + e_utf8),false,false) + t1_utf8 = target(relative_path_utf8) + t1 = scm_iconv(@path_encoding, 'UTF-8', t1_utf8) + relative_path = scm_iconv(@path_encoding, 'UTF-8', relative_path_utf8) + e1 = scm_iconv(@path_encoding, 'UTF-8', e_utf8) + if File.exist?(t1) and # paranoid test + %w{file directory}.include?(File.ftype(t1)) and # avoid special types + not File.basename(e1).match(/^\.+$/) # avoid . and .. + p1 = File.readable?(t1) ? relative_path : "" + utf_8_path = scm_iconv('UTF-8', @path_encoding, p1) + entries << + Entry.new({ :name => scm_iconv('UTF-8', @path_encoding, File.basename(e1)), + # below : list unreadable files, but dont link them. + :path => utf_8_path, + :kind => (File.directory?(t1) ? 'dir' : 'file'), + :size => (File.directory?(t1) ? nil : [File.size(t1)].pack('l').unpack('L').first), + :lastrev => + Revision.new({:time => (File.mtime(t1)) }) + }) + end + end + entries.sort_by_name + rescue => err + logger.error "scm: filesystem: error: #{err.message}" + raise CommandFailed.new(err.message) + end + + def cat(path, identifier=nil) + p = scm_iconv(@path_encoding, 'UTF-8', target(path)) + File.new(p, "rb").read + rescue => err + logger.error "scm: filesystem: error: #{err.message}" + raise CommandFailed.new(err.message) + end + + private + + # AbstractAdapter::target is implicitly made to quote paths. + # Here we do not shell-out, so we do not want quotes. + def target(path=nil) + # Prevent the use of .. + if path and !path.match(/(^|\/)\.\.(\/|$)/) + return "#{self.url}#{without_leading_slash(path)}" + end + return self.url + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/39/39f3a5c7c7d4cc80712d09ddef25b516f9d5c1ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/39/39f3a5c7c7d4cc80712d09ddef25b516f9d5c1ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

<%= link_to(h(@news.title), @news_url) %>

+ +

<%= l(:text_user_wrote, :value => h(@comment.author)) %>

+ +<%= textilizable @comment, :comments, :only_path => false %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/39/39faeb0151b407d013fa291b6fe7a94c6860c63f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/39/39faeb0151b407d013fa291b6fe7a94c6860c63f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class AppAndPluginController < ApplicationController + def an_action + render_class_and_action 'from app' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3a/3a513868a533431476e8232f1b95f5f62246b3de.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3a/3a513868a533431476e8232f1b95f5f62246b3de.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class Journal < ActiveRecord::Base + generator_for :journalized, :method => :generate_issue + generator_for :user, :method => :generate_user + + def self.generate_issue + project = Project.generate! + Issue.generate_for_project!(project) + end + + def self.generate_user + User.generate_with_protected! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3a/3a9dc91a25cf2b005cd173f3205f2e045b03c2d1.svn-base Binary file .svn/pristine/3a/3a9dc91a25cf2b005cd173f3205f2e045b03c2d1.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3a/3abba0780c56be34f089a5b70681173c4f0cb4c0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3a/3abba0780c56be34f089a5b70681173c4f0cb4c0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +api.time_entry do + api.id @time_entry.id + api.project(:id => @time_entry.project_id, :name => @time_entry.project.name) unless @time_entry.project.nil? + api.issue(:id => @time_entry.issue_id) unless @time_entry.issue.nil? + api.user(:id => @time_entry.user_id, :name => @time_entry.user.name) unless @time_entry.user.nil? + api.activity(:id => @time_entry.activity_id, :name => @time_entry.activity.name) unless @time_entry.activity.nil? + api.hours @time_entry.hours + api.comments @time_entry.comments + api.spent_on @time_entry.spent_on + api.created_on @time_entry.created_on + api.updated_on @time_entry.updated_on +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3a/3abc1f89e503ed8ed7b8d39f1ca30cf842fd70e1.svn-base Binary file .svn/pristine/3a/3abc1f89e503ed8ed7b8d39f1ca30cf842fd70e1.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3b0a04b81b3503971b4e570669380aa1831579cc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3b0a04b81b3503971b4e570669380aa1831579cc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,162 @@ +require File.expand_path('../../test_helper', __FILE__) +require 'search_controller' + +# Re-raise errors caught by the controller. +class SearchController; def rescue_action(e) raise e end; end + +class SearchControllerTest < ActionController::TestCase + fixtures :projects, :enabled_modules, :roles, :users, :members, :member_roles, + :issues, :trackers, :issue_statuses, + :custom_fields, :custom_values, + :repositories, :changesets + + def setup + @controller = SearchController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_search_for_projects + get :index + assert_response :success + assert_template 'index' + + get :index, :q => "cook" + assert_response :success + assert_template 'index' + assert assigns(:results).include?(Project.find(1)) + end + + def test_search_all_projects + get :index, :q => 'recipe subproject commit', :all_words => '' + assert_response :success + assert_template 'index' + + assert assigns(:results).include?(Issue.find(2)) + assert assigns(:results).include?(Issue.find(5)) + assert assigns(:results).include?(Changeset.find(101)) + assert_tag :dt, :attributes => { :class => /issue/ }, + :child => { :tag => 'a', :content => /Add ingredients categories/ }, + :sibling => { :tag => 'dd', :content => /should be classified by categories/ } + + assert assigns(:results_by_type).is_a?(Hash) + assert_equal 5, assigns(:results_by_type)['changesets'] + assert_tag :a, :content => 'Changesets (5)' + end + + def test_search_issues + get :index, :q => 'issue', :issues => 1 + assert_response :success + assert_template 'index' + + assert_equal true, assigns(:all_words) + assert_equal false, assigns(:titles_only) + assert assigns(:results).include?(Issue.find(8)) + assert assigns(:results).include?(Issue.find(5)) + assert_tag :dt, :attributes => { :class => /issue closed/ }, + :child => { :tag => 'a', :content => /Closed/ } + end + + def test_search_project_and_subprojects + get :index, :id => 1, :q => 'recipe subproject', :scope => 'subprojects', :all_words => '' + assert_response :success + assert_template 'index' + assert assigns(:results).include?(Issue.find(1)) + assert assigns(:results).include?(Issue.find(5)) + end + + def test_search_without_searchable_custom_fields + CustomField.update_all "searchable = #{ActiveRecord::Base.connection.quoted_false}" + + get :index, :id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:project) + + get :index, :id => 1, :q => "can" + assert_response :success + assert_template 'index' + end + + def test_search_with_searchable_custom_fields + get :index, :id => 1, :q => "stringforcustomfield" + assert_response :success + results = assigns(:results) + assert_not_nil results + assert_equal 1, results.size + assert results.include?(Issue.find(7)) + end + + def test_search_all_words + # 'all words' is on by default + get :index, :id => 1, :q => 'recipe updating saving', :all_words => '1' + assert_equal true, assigns(:all_words) + results = assigns(:results) + assert_not_nil results + assert_equal 1, results.size + assert results.include?(Issue.find(3)) + end + + def test_search_one_of_the_words + get :index, :id => 1, :q => 'recipe updating saving', :all_words => '' + assert_equal false, assigns(:all_words) + results = assigns(:results) + assert_not_nil results + assert_equal 3, results.size + assert results.include?(Issue.find(3)) + end + + def test_search_titles_only_without_result + get :index, :id => 1, :q => 'recipe updating saving', :titles_only => '1' + results = assigns(:results) + assert_not_nil results + assert_equal 0, results.size + end + + def test_search_titles_only + get :index, :id => 1, :q => 'recipe', :titles_only => '1' + assert_equal true, assigns(:titles_only) + results = assigns(:results) + assert_not_nil results + assert_equal 2, results.size + end + + def test_search_content + Issue.update_all("description = 'This is a searchkeywordinthecontent'", "id=1") + + get :index, :id => 1, :q => 'searchkeywordinthecontent', :titles_only => '' + assert_equal false, assigns(:titles_only) + results = assigns(:results) + assert_not_nil results + assert_equal 1, results.size + end + + def test_search_with_invalid_project_id + get :index, :id => 195, :q => 'recipe' + assert_response 404 + assert_nil assigns(:results) + end + + def test_quick_jump_to_issue + # issue of a public project + get :index, :q => "3" + assert_redirected_to '/issues/3' + + # issue of a private project + get :index, :q => "4" + assert_response :success + assert_template 'index' + end + + def test_large_integer + get :index, :q => '4615713488' + assert_response :success + assert_template 'index' + end + + def test_tokens_with_quotes + get :index, :id => 1, :q => '"good bye" hello "bye bye"' + assert_equal ["good bye", "hello", "bye bye"], assigns(:tokens) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3b0de502ec8b6120c31b659193b4e6c0d564605f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3b0de502ec8b6120c31b659193b4e6c0d564605f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +<%= error_messages_for 'issue_status' %> + +
+

<%= f.text_field :name, :required => true %>

+<% if Issue.use_status_for_done_ratio? %> +

<%= f.select :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true, :label => :field_done_ratio %>

+<% end %> +

<%= f.check_box :is_closed %>

+

<%= f.check_box :is_default %>

+ +<%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3b1b10ce6290c2ed3a8ab7a0cbea04c53b0b08e9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3b1b10ce6290c2ed3a8ab7a0cbea04c53b0b08e9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,232 @@ +/* redMine - project management software + Copyright (C) 2006-2008 Jean-Philippe Lang */ + +var observingContextMenuClick; + +ContextMenu = Class.create(); +ContextMenu.prototype = { + initialize: function (url) { + this.url = url; + this.createMenu(); + + if (!observingContextMenuClick) { + Event.observe(document, 'click', this.Click.bindAsEventListener(this)); + Event.observe(document, 'contextmenu', this.RightClick.bindAsEventListener(this)); + observingContextMenuClick = true; + } + + this.unselectAll(); + this.lastSelected = null; + }, + + RightClick: function(e) { + this.hideMenu(); + // do not show the context menu on links + if (Event.element(e).tagName == 'A') { return; } + var tr = Event.findElement(e, 'tr'); + if (tr == document || tr == undefined || !tr.hasClassName('hascontextmenu')) { return; } + Event.stop(e); + if (!this.isSelected(tr)) { + this.unselectAll(); + this.addSelection(tr); + this.lastSelected = tr; + } + this.showMenu(e); + }, + + Click: function(e) { + this.hideMenu(); + if (Event.element(e).tagName == 'A' || Event.element(e).tagName == 'IMG') { return; } + if (Event.isLeftClick(e) || (navigator.appVersion.match(/\bMSIE\b/))) { + var tr = Event.findElement(e, 'tr'); + if (tr!=null && tr!=document && tr.hasClassName('hascontextmenu')) { + // a row was clicked, check if the click was on checkbox + var box = Event.findElement(e, 'input'); + if (box!=document && box!=undefined) { + // a checkbox may be clicked + if (box.checked) { + tr.addClassName('context-menu-selection'); + } else { + tr.removeClassName('context-menu-selection'); + } + } else { + if (e.ctrlKey || e.metaKey) { + this.toggleSelection(tr); + } else if (e.shiftKey) { + if (this.lastSelected != null) { + var toggling = false; + var rows = $$('.hascontextmenu'); + for (i=0; i window_width) { + render_x -= menu_width; + $('context-menu').addClassName('reverse-x'); + } else { + $('context-menu').removeClassName('reverse-x'); + } + if (max_height > window_height) { + render_y -= menu_height; + $('context-menu').addClassName('reverse-y'); + } else { + $('context-menu').removeClassName('reverse-y'); + } + if (render_x <= 0) render_x = 1; + if (render_y <= 0) render_y = 1; + $('context-menu').style['left'] = (render_x + 'px'); + $('context-menu').style['top'] = (render_y + 'px'); + + Effect.Appear('context-menu', {duration: 0.20}); + if (window.parseStylesheets) { window.parseStylesheets(); } // IE + }}) + }, + + hideMenu: function() { + Element.hide('context-menu'); + }, + + addSelection: function(tr) { + tr.addClassName('context-menu-selection'); + this.checkSelectionBox(tr, true); + this.clearDocumentSelection(); + }, + + toggleSelection: function(tr) { + if (this.isSelected(tr)) { + this.removeSelection(tr); + } else { + this.addSelection(tr); + } + }, + + removeSelection: function(tr) { + tr.removeClassName('context-menu-selection'); + this.checkSelectionBox(tr, false); + }, + + unselectAll: function() { + var rows = $$('.hascontextmenu'); + for (i=0; i 0) { inputs[0].checked = checked; } + }, + + isSelected: function(tr) { + return Element.hasClassName(tr, 'context-menu-selection'); + }, + + clearDocumentSelection: function() { + if (document.selection) { + document.selection.clear(); // IE + } else { + window.getSelection().removeAllRanges(); + } + } +} + +function toggleIssuesSelection(el) { + var boxes = el.getElementsBySelector('input[type=checkbox]'); + var all_checked = true; + for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } } + for (i = 0; i < boxes.length; i++) { + if (all_checked) { + boxes[i].checked = false; + boxes[i].up('tr').removeClassName('context-menu-selection'); + } else if (boxes[i].checked == false) { + boxes[i].checked = true; + boxes[i].up('tr').addClassName('context-menu-selection'); + } + } +} + +function window_size() { + var w; + var h; + if (window.innerWidth) { + w = window.innerWidth; + h = window.innerHeight; + } else if (document.documentElement) { + w = document.documentElement.clientWidth; + h = document.documentElement.clientHeight; + } else { + w = document.body.clientWidth; + h = document.body.clientHeight; + } + return {width: w, height: h}; +} diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3b35aa3e53757a7316cb173ab97cf120044ce7fe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3b35aa3e53757a7316cb173ab97cf120044ce7fe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= yield %> (with plugin layout) \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3b35bfc6a457be42f49a86352010582aa133bde7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3b35bfc6a457be42f49a86352010582aa133bde7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +welcome_1: + id: 1 + page_id: 1 + title: Welcome to the weblg + version: 23 + version_type: LockedPage + +welcome_2: + id: 2 + page_id: 1 + title: Welcome to the weblog + version: 24 + version_type: LockedPage + +thinking_1: + id: 3 + page_id: 2 + title: So I was thinking!!! + version: 23 + version_type: SpecialLockedPage + +thinking_2: + id: 4 + page_id: 2 + title: So I was thinking + version: 24 + version_type: SpecialLockedPage diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3bcad5336e16798c44c61e4b8a0a1326c50733be.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3bcad5336e16798c44c61e4b8a0a1326c50733be.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,250 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+2018 quoteleft +!A2 U+2019 quoteright +!A3 U+00A3 sterling +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+0385 dieresistonos +!B6 U+0386 Alphatonos +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3b/3bdc9be57907c77b3244c04ca134e43fe57a10c8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3b/3bdc9be57907c77b3244c04ca134e43fe57a10c8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %> + +
> +<% if @issue.safe_attribute_names.include?('is_private') %> +

+ +

+<% end %> +

<%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %>

+<%= observe_field :issue_tracker_id, :url => { :action => :new, :project_id => @project, :id => @issue }, + :update => :attributes, + :with => "Form.serialize('issue-form')" %> + +

<%= f.text_field :subject, :size => 80, :required => true %>

+

<%= f.text_area :description, + :cols => 60, + :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min), + :accesskey => accesskey(:edit), + :class => 'wiki-edit' %>

+
+ +
+ <%= render :partial => 'issues/attributes' %> +
+ +<% if @issue.new_record? %> +

<%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %>

+<% end %> + +<% if @issue.new_record? && User.current.allowed_to?(:add_issue_watchers, @project) -%> +

+<% @issue.project.users.sort.each do |user| -%> + +<% end -%> +

+<% end %> + +<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %> + +<%= wikitoolbar_for 'issue_description' %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3c16dbd6e7c58f730f5ff1711301f6b5ab6045e0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3c16dbd6e7c58f730f5ff1711301f6b5ab6045e0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# In the development environment your application's code is reloaded on +# every request. This slows down response time but is perfect for development +# since you don't have to restart the webserver when you make code changes. +config.cache_classes = false + +# Log error messages when you accidentally call methods on nil. +config.whiny_nils = true + +# Show full error reports and disable caching +config.action_controller.consider_all_requests_local = true +config.action_controller.perform_caching = false + +# Don't care if the mailer can't send +config.action_mailer.raise_delivery_errors = false diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3c376c5f92040d674ff0d9660198f1ddf43a3782.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3c376c5f92040d674ff0d9660198f1ddf43a3782.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,264 @@ +--- +issues_001: + created_on: <%= 3.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 1.day.ago.to_date.to_s(:db) %> + priority_id: 4 + subject: Can't print recipes + id: 1 + fixed_version_id: + category_id: 1 + description: Unable to print recipes + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + start_date: <%= 1.day.ago.to_date.to_s(:db) %> + due_date: <%= 10.day.from_now.to_date.to_s(:db) %> + root_id: 1 + lft: 1 + rgt: 2 +issues_002: + created_on: 2006-07-19 21:04:21 +02:00 + project_id: 1 + updated_on: 2006-07-19 21:09:50 +02:00 + priority_id: 5 + subject: Add ingredients categories + id: 2 + fixed_version_id: 2 + category_id: + description: Ingredients of the recipe should be classified by categories + tracker_id: 2 + assigned_to_id: 3 + author_id: 2 + status_id: 2 + start_date: <%= 2.day.ago.to_date.to_s(:db) %> + due_date: + root_id: 2 + lft: 1 + rgt: 2 + lock_version: 3 + done_ratio: 30 +issues_003: + created_on: 2006-07-19 21:07:27 +02:00 + project_id: 1 + updated_on: 2006-07-19 21:07:27 +02:00 + priority_id: 4 + subject: Error 281 when updating a recipe + id: 3 + fixed_version_id: + category_id: + description: Error 281 is encountered when saving a recipe + tracker_id: 1 + assigned_to_id: 3 + author_id: 2 + status_id: 1 + start_date: <%= 15.day.ago.to_date.to_s(:db) %> + due_date: <%= 5.day.ago.to_date.to_s(:db) %> + root_id: 3 + lft: 1 + rgt: 2 +issues_004: + created_on: <%= 5.days.ago.to_date.to_s(:db) %> + project_id: 2 + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + priority_id: 4 + subject: Issue on project 2 + id: 4 + fixed_version_id: + category_id: + description: Issue on project 2 + tracker_id: 1 + assigned_to_id: 2 + author_id: 2 + status_id: 1 + root_id: 4 + lft: 1 + rgt: 2 +issues_005: + created_on: <%= 5.days.ago.to_date.to_s(:db) %> + project_id: 3 + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + priority_id: 4 + subject: Subproject issue + id: 5 + fixed_version_id: + category_id: + description: This is an issue on a cookbook subproject + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + root_id: 5 + lft: 1 + rgt: 2 +issues_006: + created_on: <%= 1.minute.ago.to_date.to_s(:db) %> + project_id: 5 + updated_on: <%= 1.minute.ago.to_date.to_s(:db) %> + priority_id: 4 + subject: Issue of a private subproject + id: 6 + fixed_version_id: + category_id: + description: This is an issue of a private subproject of cookbook + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + start_date: <%= Date.today.to_s(:db) %> + due_date: <%= 1.days.from_now.to_date.to_s(:db) %> + root_id: 6 + lft: 1 + rgt: 2 +issues_007: + created_on: <%= 10.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 10.days.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Issue due today + id: 7 + fixed_version_id: + category_id: + description: This is an issue that is due today + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + start_date: <%= 10.days.ago.to_s(:db) %> + due_date: <%= Date.today.to_s(:db) %> + lock_version: 0 + root_id: 7 + lft: 1 + rgt: 2 +issues_008: + created_on: <%= 10.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 10.days.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Closed issue + id: 8 + fixed_version_id: + category_id: + description: This is a closed issue. + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 5 + start_date: + due_date: + lock_version: 0 + root_id: 8 + lft: 1 + rgt: 2 +issues_009: + created_on: <%= 1.minute.ago.to_date.to_s(:db) %> + project_id: 5 + updated_on: <%= 1.minute.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Blocked Issue + id: 9 + fixed_version_id: + category_id: + description: This is an issue that is blocked by issue #10 + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + start_date: <%= Date.today.to_s(:db) %> + due_date: <%= 1.days.from_now.to_date.to_s(:db) %> + root_id: 9 + lft: 1 + rgt: 2 +issues_010: + created_on: <%= 1.minute.ago.to_date.to_s(:db) %> + project_id: 5 + updated_on: <%= 1.minute.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Issue Doing the Blocking + id: 10 + fixed_version_id: + category_id: + description: This is an issue that blocks issue #9 + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + start_date: <%= Date.today.to_s(:db) %> + due_date: <%= 1.days.from_now.to_date.to_s(:db) %> + root_id: 10 + lft: 1 + rgt: 2 +issues_011: + created_on: <%= 3.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 1.day.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Closed issue on a closed version + id: 11 + fixed_version_id: 1 + category_id: 1 + description: + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 5 + start_date: <%= 1.day.ago.to_date.to_s(:db) %> + due_date: + root_id: 11 + lft: 1 + rgt: 2 +issues_012: + created_on: <%= 3.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 1.day.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Closed issue on a locked version + id: 12 + fixed_version_id: 2 + category_id: 1 + description: + tracker_id: 1 + assigned_to_id: + author_id: 3 + status_id: 5 + start_date: <%= 1.day.ago.to_date.to_s(:db) %> + due_date: + root_id: 12 + lft: 1 + rgt: 2 +issues_013: + created_on: <%= 5.days.ago.to_date.to_s(:db) %> + project_id: 3 + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + priority_id: 4 + subject: Subproject issue two + id: 13 + fixed_version_id: + category_id: + description: This is a second issue on a cookbook subproject + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + root_id: 13 + lft: 1 + rgt: 2 +issues_014: + id: 14 + created_on: <%= 15.days.ago.to_date.to_s(:db) %> + project_id: 3 + updated_on: <%= 15.days.ago.to_date.to_s(:db) %> + priority_id: 5 + subject: Private issue on public project + fixed_version_id: + category_id: + description: This is a private issue + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + is_private: true + root_id: 14 + lft: 1 + rgt: 2 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3c7ff621c4b3a329adfd7d06c0fa2ae1d92c4a27.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3c7ff621c4b3a329adfd7d06c0fa2ae1d92c4a27.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,142 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssueRelation < ActiveRecord::Base + belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id' + belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id' + + TYPE_RELATES = "relates" + TYPE_DUPLICATES = "duplicates" + TYPE_DUPLICATED = "duplicated" + TYPE_BLOCKS = "blocks" + TYPE_BLOCKED = "blocked" + TYPE_PRECEDES = "precedes" + TYPE_FOLLOWS = "follows" + + TYPES = { TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1, :sym => TYPE_RELATES }, + TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2, :sym => TYPE_DUPLICATED }, + TYPE_DUPLICATED => { :name => :label_duplicated_by, :sym_name => :label_duplicates, :order => 3, :sym => TYPE_DUPLICATES, :reverse => TYPE_DUPLICATES }, + TYPE_BLOCKS => { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 4, :sym => TYPE_BLOCKED }, + TYPE_BLOCKED => { :name => :label_blocked_by, :sym_name => :label_blocks, :order => 5, :sym => TYPE_BLOCKS, :reverse => TYPE_BLOCKS }, + TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, :order => 6, :sym => TYPE_FOLLOWS }, + TYPE_FOLLOWS => { :name => :label_follows, :sym_name => :label_precedes, :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES } + }.freeze + + validates_presence_of :issue_from, :issue_to, :relation_type + validates_inclusion_of :relation_type, :in => TYPES.keys + validates_numericality_of :delay, :allow_nil => true + validates_uniqueness_of :issue_to_id, :scope => :issue_from_id + + validate :validate_issue_relation + + attr_protected :issue_from_id, :issue_to_id + + before_save :handle_issue_order + + def visible?(user=User.current) + (issue_from.nil? || issue_from.visible?(user)) && (issue_to.nil? || issue_to.visible?(user)) + end + + def deletable?(user=User.current) + visible?(user) && + ((issue_from.nil? || user.allowed_to?(:manage_issue_relations, issue_from.project)) || + (issue_to.nil? || user.allowed_to?(:manage_issue_relations, issue_to.project))) + end + + def after_initialize + if new_record? + if relation_type.blank? + self.relation_type = IssueRelation::TYPE_RELATES + end + end + end + + def validate_issue_relation + if issue_from && issue_to + errors.add :issue_to_id, :invalid if issue_from_id == issue_to_id + errors.add :issue_to_id, :not_same_project unless issue_from.project_id == issue_to.project_id || Setting.cross_project_issue_relations? + #detect circular dependencies depending wether the relation should be reversed + if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] + errors.add :base, :circular_dependency if issue_from.all_dependent_issues.include? issue_to + else + errors.add :base, :circular_dependency if issue_to.all_dependent_issues.include? issue_from + end + errors.add :base, :cant_link_an_issue_with_a_descendant if issue_from.is_descendant_of?(issue_to) || issue_from.is_ancestor_of?(issue_to) + end + end + + def other_issue(issue) + (self.issue_from_id == issue.id) ? issue_to : issue_from + end + + # Returns the relation type for +issue+ + def relation_type_for(issue) + if TYPES[relation_type] + if self.issue_from_id == issue.id + relation_type + else + TYPES[relation_type][:sym] + end + end + end + + def label_for(issue) + TYPES[relation_type] ? TYPES[relation_type][(self.issue_from_id == issue.id) ? :name : :sym_name] : :unknow + end + + def handle_issue_order + reverse_if_needed + + if TYPE_PRECEDES == relation_type + self.delay ||= 0 + else + self.delay = nil + end + set_issue_to_dates + end + + def set_issue_to_dates + soonest_start = self.successor_soonest_start + if soonest_start && issue_to + issue_to.reschedule_after(soonest_start) + end + end + + def successor_soonest_start + if (TYPE_PRECEDES == self.relation_type) && delay && issue_from && (issue_from.start_date || issue_from.due_date) + (issue_from.due_date || issue_from.start_date) + 1 + delay + end + end + + def <=>(relation) + TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order] + end + + private + + # Reverses the relation if needed so that it gets stored in the proper way + # Should not be reversed before validation so that it can be displayed back + # as entered on new relation form + def reverse_if_needed + if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] + issue_tmp = issue_to + self.issue_to = issue_from + self.issue_from = issue_tmp + self.relation_type = TYPES[relation_type][:reverse] + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3cbf045871f4a74462d238faefdda2d93e946bc2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3cbf045871f4a74462d238faefdda2d93e946bc2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

<%=l(:label_project_new)%>

+ +<% labelled_tabular_form_for @project do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<%= submit_tag l(:button_create_and_continue), :name => 'continue' %> +<%= javascript_tag "Form.Element.focus('project_name');" %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3cc2762940ee93762d4d782147803b7d0198ed51.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3cc2762940ee93762d4d782147803b7d0198ed51.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +ActionController::Routing::Routes.draw do |map| + map.connect 'routes/:action', :controller => "test_routing" + map.plugin_route 'somespace/routes/:action', :controller => "namespace/test_routing" +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3cd8e88573cd0b42429f6ee4864dcc592f6b54a1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3cd8e88573cd0b42429f6ee4864dcc592f6b54a1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 #:nodoc: + module CoreExtensions #:nodoc: + module String #:nodoc: + # Custom string inflections + module Inflections + def with_leading_slash + starts_with?('/') ? self : "/#{ self }" + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3c/3cdf10eb8093cfc847c369901c8cec7bae62db8a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3c/3cdf10eb8093cfc847c369901c8cec7bae62db8a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,125 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class CustomValueTest < ActiveSupport::TestCase + fixtures :custom_fields, :custom_values, :users + + def test_string_field_validation_with_blank_value + f = CustomField.new(:field_format => 'string') + v = CustomValue.new(:custom_field => f) + + v.value = nil + assert v.valid? + v.value = '' + assert v.valid? + + f.is_required = true + v.value = nil + assert !v.valid? + v.value = '' + assert !v.valid? + end + + def test_string_field_validation_with_min_and_max_lengths + f = CustomField.new(:field_format => 'string', :min_length => 2, :max_length => 5) + v = CustomValue.new(:custom_field => f, :value => '') + assert v.valid? + v.value = 'a' + assert !v.valid? + v.value = 'a' * 2 + assert v.valid? + v.value = 'a' * 6 + assert !v.valid? + end + + def test_string_field_validation_with_regexp + f = CustomField.new(:field_format => 'string', :regexp => '^[A-Z0-9]*$') + v = CustomValue.new(:custom_field => f, :value => '') + assert v.valid? + v.value = 'abc' + assert !v.valid? + v.value = 'ABC' + assert v.valid? + end + + def test_date_field_validation + f = CustomField.new(:field_format => 'date') + v = CustomValue.new(:custom_field => f, :value => '') + assert v.valid? + v.value = 'abc' + assert !v.valid? + v.value = '1975-07-33' + assert !v.valid? + v.value = '1975-07-14' + assert v.valid? + end + + def test_list_field_validation + f = CustomField.new(:field_format => 'list', :possible_values => ['value1', 'value2']) + v = CustomValue.new(:custom_field => f, :value => '') + assert v.valid? + v.value = 'abc' + assert !v.valid? + v.value = 'value2' + assert v.valid? + end + + def test_int_field_validation + f = CustomField.new(:field_format => 'int') + v = CustomValue.new(:custom_field => f, :value => '') + assert v.valid? + v.value = 'abc' + assert !v.valid? + v.value = '123' + assert v.valid? + v.value = '+123' + assert v.valid? + v.value = '-123' + assert v.valid? + end + + def test_float_field_validation + v = CustomValue.new(:customized => User.find(:first), :custom_field => UserCustomField.find_by_name('Money')) + v.value = '11.2' + assert v.save + v.value = '' + assert v.save + v.value = '-6.250' + assert v.save + v.value = '6a' + assert !v.save + end + + def test_default_value + field = CustomField.find_by_default_value('Default string') + assert_not_nil field + + v = CustomValue.new(:custom_field => field) + assert_equal 'Default string', v.value + + v = CustomValue.new(:custom_field => field, :value => 'Not empty') + assert_equal 'Not empty', v.value + end + + def test_sti_polymorphic_association + # Rails uses top level sti class for polymorphic association. See #3978. + assert !User.find(4).custom_values.empty? + assert !CustomValue.find(2).customized.nil? + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3d0a99ce133ffd8be7f79466600a3a56ffab0213.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3d/3d0a99ce133ffd8be7f79466600a3a56ffab0213.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 MailHandlerHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3d3b405886b53d97a18acfbd6ee1f68a9fd0e1c4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3d/3d3b405886b53d97a18acfbd6ee1f68a9fd0e1c4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +

<%=l(:button_change_password)%>

+ +<%= error_messages_for 'user' %> + +<% form_tag({}, :class => "tabular") do %> +
+

+<%= password_field_tag 'password', nil, :size => 25 %>

+ +

+<%= password_field_tag 'new_password', nil, :size => 25 %>
+<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

+ +

+<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

+
+<%= submit_tag l(:button_apply) %> +<% end %> + +<% content_for :sidebar do %> +<%= render :partial => 'sidebar' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3d3f4dc404ea9324f3dc61ea78926c927911ae38.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3d/3d3f4dc404ea9324f3dc61ea78926c927911ae38.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,156 @@ +--- +queries_001: + id: 1 + project_id: 1 + is_public: true + name: Multiple custom fields query + filters: | + --- + cf_1: + :values: + - MySQL + :operator: "=" + status_id: + :values: + - "1" + :operator: o + cf_2: + :values: + - "125" + :operator: "=" + + user_id: 1 + column_names: +queries_002: + id: 2 + project_id: 1 + is_public: false + name: Private query for cookbook + filters: | + --- + tracker_id: + :values: + - "3" + :operator: "=" + status_id: + :values: + - "1" + :operator: o + + user_id: 3 + column_names: +queries_003: + id: 3 + project_id: + is_public: false + name: Private query for all projects + filters: | + --- + tracker_id: + :values: + - "3" + :operator: "=" + + user_id: 3 + column_names: +queries_004: + id: 4 + project_id: + is_public: true + name: Public query for all projects + filters: | + --- + tracker_id: + :values: + - "3" + :operator: "=" + + user_id: 2 + column_names: +queries_005: + id: 5 + project_id: + is_public: true + name: Open issues by priority and tracker + filters: | + --- + status_id: + :values: + - "1" + :operator: o + + user_id: 1 + column_names: + sort_criteria: | + --- + - - priority + - desc + - - tracker + - asc +queries_006: + id: 6 + project_id: + is_public: true + name: Open issues grouped by tracker + filters: | + --- + status_id: + :values: + - "1" + :operator: o + + user_id: 1 + column_names: + group_by: tracker + sort_criteria: | + --- + - - priority + - desc +queries_007: + id: 7 + project_id: 2 + is_public: true + name: Public query for project 2 + filters: | + --- + tracker_id: + :values: + - "3" + :operator: "=" + + user_id: 2 + column_names: +queries_008: + id: 8 + project_id: 2 + is_public: false + name: Private query for project 2 + filters: | + --- + tracker_id: + :values: + - "3" + :operator: "=" + + user_id: 2 + column_names: +queries_009: + id: 9 + project_id: + is_public: true + name: Open issues grouped by list custom field + filters: | + --- + status_id: + :values: + - "1" + :operator: o + + user_id: 1 + column_names: + group_by: cf_1 + sort_criteria: | + --- + - - priority + - desc + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3d503edadd13a313e0e3661d47e1156ded0be542.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3d/3d503edadd13a313e0e3661d47e1156ded0be542.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,65 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Watcher < ActiveRecord::Base + belongs_to :watchable, :polymorphic => true + belongs_to :user + + validates_presence_of :user + validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id] + + # Unwatch things that users are no longer allowed to view + def self.prune(options={}) + if options.has_key?(:user) + prune_single_user(options[:user], options) + else + pruned = 0 + User.find(:all, :conditions => "id IN (SELECT DISTINCT user_id FROM #{table_name})").each do |user| + pruned += prune_single_user(user, options) + end + pruned + end + end + + protected + + def validate + errors.add :user_id, :invalid unless user.nil? || user.active? + end + + private + + def self.prune_single_user(user, options={}) + return unless user.is_a?(User) + pruned = 0 + find(:all, :conditions => {:user_id => user.id}).each do |watcher| + next if watcher.watchable.nil? + + if options.has_key?(:project) + next unless watcher.watchable.respond_to?(:project) && watcher.watchable.project == options[:project] + end + + if watcher.watchable.respond_to?(:visible?) + unless watcher.watchable.visible?(user) + watcher.destroy + pruned += 1 + end + end + end + pruned + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3d8232d1207f44e7e488f7e43e0c4c6dd46b1462.svn-base Binary file .svn/pristine/3d/3d8232d1207f44e7e488f7e43e0c4c6dd46b1462.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3de9a7c0e8857c78fd6236475c621cbde49a6cbd.svn-base Binary file .svn/pristine/3d/3de9a7c0e8857c78fd6236475c621cbde49a6cbd.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3d/3dff9c6069908256974f3f7783cf2d5ebeafb576.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3d/3dff9c6069908256974f3f7783cf2d5ebeafb576.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class CreateIssueRelations < ActiveRecord::Migration + def self.up + create_table :issue_relations do |t| + t.column :issue_from_id, :integer, :null => false + t.column :issue_to_id, :integer, :null => false + t.column :relation_type, :string, :default => "", :null => false + t.column :delay, :integer + end + end + + def self.down + drop_table :issue_relations + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3e/3e2856705bc7c004aa221bf2a7acea9b1ba0b99e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3e/3e2856705bc7c004aa221bf2a7acea9b1ba0b99e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,554 @@ +module CollectiveIdea #:nodoc: + module Acts #:nodoc: + module NestedSet #:nodoc: + def self.included(base) + base.extend(SingletonMethods) + end + + # This acts provides Nested Set functionality. Nested Set is a smart way to implement + # an _ordered_ tree, with the added feature that you can select the children and all of their + # descendants with a single query. The drawback is that insertion or move need some complex + # sql queries. But everything is done here by this module! + # + # Nested sets are appropriate each time you want either an orderd tree (menus, + # commercial categories) or an efficient way of querying big trees (threaded posts). + # + # == API + # + # Methods names are aligned with acts_as_tree as much as possible, to make replacment from one + # by another easier, except for the creation: + # + # in acts_as_tree: + # item.children.create(:name => "child1") + # + # in acts_as_nested_set: + # # adds a new item at the "end" of the tree, i.e. with child.left = max(tree.right)+1 + # child = MyClass.new(:name => "child1") + # child.save + # # now move the item to its right place + # child.move_to_child_of my_item + # + # You can pass an id or an object to: + # * #move_to_child_of + # * #move_to_right_of + # * #move_to_left_of + # + module SingletonMethods + # Configuration options are: + # + # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id) + # * +:left_column+ - column name for left boundry data, default "lft" + # * +:right_column+ - column name for right boundry data, default "rgt" + # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id" + # (if it hasn't been already) and use that as the foreign key restriction. You + # can also pass an array to scope by multiple attributes. + # Example: acts_as_nested_set :scope => [:notable_id, :notable_type] + # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the + # child objects are destroyed alongside this object by calling their destroy + # method. If set to :delete_all (default), all the child objects are deleted + # without calling their destroy method. + # + # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and + # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added + # to acts_as_nested_set models + def acts_as_nested_set(options = {}) + options = { + :parent_column => 'parent_id', + :left_column => 'lft', + :right_column => 'rgt', + :order => 'id', + :dependent => :delete_all, # or :destroy + }.merge(options) + + if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ + options[:scope] = "#{options[:scope]}_id".intern + end + + write_inheritable_attribute :acts_as_nested_set_options, options + class_inheritable_reader :acts_as_nested_set_options + + include Comparable + include Columns + include InstanceMethods + extend Columns + extend ClassMethods + + # no bulk assignment + attr_protected left_column_name.intern, + right_column_name.intern, + parent_column_name.intern + + before_create :set_default_left_and_right + before_destroy :prune_from_tree + + # no assignment to structure fields + [left_column_name, right_column_name, parent_column_name].each do |column| + module_eval <<-"end_eval", __FILE__, __LINE__ + def #{column}=(x) + raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." + end + end_eval + end + + named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name + named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name + if self.respond_to?(:define_callbacks) + define_callbacks("before_move", "after_move") + end + + + end + + end + + module ClassMethods + + # Returns the first root + def root + roots.find(:first) + end + + def valid? + left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid? + end + + def left_and_rights_valid? + count( + :joins => "LEFT OUTER JOIN #{quoted_table_name} AS parent ON " + + "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}", + :conditions => + "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " + + "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " + + "#{quoted_table_name}.#{quoted_left_column_name} >= " + + "#{quoted_table_name}.#{quoted_right_column_name} OR " + + "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " + + "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " + + "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))" + ) == 0 + end + + def no_duplicates_for_columns? + scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| + connection.quote_column_name(c) + end.push(nil).join(", ") + [quoted_left_column_name, quoted_right_column_name].all? do |column| + # No duplicates + find(:first, + :select => "#{scope_string}#{column}, COUNT(#{column})", + :group => "#{scope_string}#{column} + HAVING COUNT(#{column}) > 1").nil? + end + end + + # Wrapper for each_root_valid? that can deal with scope. + def all_roots_valid? + if acts_as_nested_set_options[:scope] + roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots| + each_root_valid?(grouped_roots) + end + else + each_root_valid?(roots) + end + end + + def each_root_valid?(roots_to_validate) + left = right = 0 + roots_to_validate.all? do |root| + (root.left > left && root.right > right).tap do + left = root.left + right = root.right + end + end + end + + # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree. + def rebuild!(force=false) + # Don't rebuild a valid tree. + # valid? doesn't strictly validate the tree + return true if !force && valid? + + scope = lambda{|node|} + if acts_as_nested_set_options[:scope] + scope = lambda{|node| + scope_column_names.inject(""){|str, column_name| + str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} " + } + } + end + indices = {} + + set_left_and_rights = lambda do |node| + # set left + node[left_column_name] = indices[scope.call(node)] += 1 + # find + find(:all, :conditions => ["#{quoted_parent_column_name} = ? #{scope.call(node)}", node], :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}").each{|n| set_left_and_rights.call(n) } + # set right + node[right_column_name] = indices[scope.call(node)] += 1 + node.save! + end + + # Find root node(s) + root_nodes = find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}").each do |root_node| + # setup index for this scope + indices[scope.call(root_node)] ||= 0 + set_left_and_rights.call(root_node) + end + end + end + + # Mixed into both classes and instances to provide easy access to the column names + module Columns + def left_column_name + acts_as_nested_set_options[:left_column] + end + + def right_column_name + acts_as_nested_set_options[:right_column] + end + + def parent_column_name + acts_as_nested_set_options[:parent_column] + end + + def scope_column_names + Array(acts_as_nested_set_options[:scope]) + end + + def quoted_left_column_name + connection.quote_column_name(left_column_name) + end + + def quoted_right_column_name + connection.quote_column_name(right_column_name) + end + + def quoted_parent_column_name + connection.quote_column_name(parent_column_name) + end + + def quoted_scope_column_names + scope_column_names.collect {|column_name| connection.quote_column_name(column_name) } + end + end + + # Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder. + # + # category.self_and_descendants.count + # category.ancestors.find(:all, :conditions => "name like '%foo%'") + module InstanceMethods + # Value of the parent column + def parent_id + self[parent_column_name] + end + + # Value of the left column + def left + self[left_column_name] + end + + # Value of the right column + def right + self[right_column_name] + end + + # Returns true if this is a root node. + def root? + parent_id.nil? + end + + def leaf? + new_record? || (right - left == 1) + end + + # Returns true is this is a child node + def child? + !parent_id.nil? + end + + # order by left column + def <=>(x) + left <=> x.left + end + + # Redefine to act like active record + def ==(comparison_object) + comparison_object.equal?(self) || + (comparison_object.instance_of?(self.class) && + comparison_object.id == id && + !comparison_object.new_record?) + end + + # Returns root + def root + self_and_ancestors.find(:first) + end + + # Returns the immediate parent + def parent + nested_set_scope.find_by_id(parent_id) if parent_id + end + + # Returns the array of all parents and self + def self_and_ancestors + nested_set_scope.scoped :conditions => [ + "#{self.class.table_name}.#{quoted_left_column_name} <= ? AND #{self.class.table_name}.#{quoted_right_column_name} >= ?", left, right + ] + end + + # Returns an array of all parents + def ancestors + without_self self_and_ancestors + end + + # Returns the array of all children of the parent, including self + def self_and_siblings + nested_set_scope.scoped :conditions => {parent_column_name => parent_id} + end + + # Returns the array of all children of the parent, except self + def siblings + without_self self_and_siblings + end + + # Returns a set of all of its nested children which do not have children + def leaves + descendants.scoped :conditions => "#{self.class.table_name}.#{quoted_right_column_name} - #{self.class.table_name}.#{quoted_left_column_name} = 1" + end + + # Returns the level of this object in the tree + # root level is 0 + def level + parent_id.nil? ? 0 : ancestors.count + end + + # Returns a set of itself and all of its nested children + def self_and_descendants + nested_set_scope.scoped :conditions => [ + "#{self.class.table_name}.#{quoted_left_column_name} >= ? AND #{self.class.table_name}.#{quoted_right_column_name} <= ?", left, right + ] + end + + # Returns a set of all of its children and nested children + def descendants + without_self self_and_descendants + end + + # Returns a set of only this entry's immediate children + def children + nested_set_scope.scoped :conditions => {parent_column_name => self} + end + + def is_descendant_of?(other) + other.left < self.left && self.left < other.right && same_scope?(other) + end + + def is_or_is_descendant_of?(other) + other.left <= self.left && self.left < other.right && same_scope?(other) + end + + def is_ancestor_of?(other) + self.left < other.left && other.left < self.right && same_scope?(other) + end + + def is_or_is_ancestor_of?(other) + self.left <= other.left && other.left < self.right && same_scope?(other) + end + + # Check if other model is in the same scope + def same_scope?(other) + Array(acts_as_nested_set_options[:scope]).all? do |attr| + self.send(attr) == other.send(attr) + end + end + + # Find the first sibling to the left + def left_sibling + siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} < ?", left], + :order => "#{self.class.table_name}.#{quoted_left_column_name} DESC") + end + + # Find the first sibling to the right + def right_sibling + siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} > ?", left]) + end + + # Shorthand method for finding the left sibling and moving to the left of it. + def move_left + move_to_left_of left_sibling + end + + # Shorthand method for finding the right sibling and moving to the right of it. + def move_right + move_to_right_of right_sibling + end + + # Move the node to the left of another node (you can pass id only) + def move_to_left_of(node) + move_to node, :left + end + + # Move the node to the left of another node (you can pass id only) + def move_to_right_of(node) + move_to node, :right + end + + # Move the node to the child of another node (you can pass id only) + def move_to_child_of(node) + move_to node, :child + end + + # Move the node to root nodes + def move_to_root + move_to nil, :root + end + + def move_possible?(target) + self != target && # Can't target self + same_scope?(target) && # can't be in different scopes + # !(left..right).include?(target.left..target.right) # this needs tested more + # detect impossible move + !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right)) + end + + def to_text + self_and_descendants.map do |node| + "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})" + end.join("\n") + end + + protected + + def without_self(scope) + scope.scoped :conditions => ["#{self.class.table_name}.#{self.class.primary_key} != ?", self] + end + + # All nested set queries should use this nested_set_scope, which performs finds on + # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set + # declaration. + def nested_set_scope + options = {:order => "#{self.class.table_name}.#{quoted_left_column_name}"} + scopes = Array(acts_as_nested_set_options[:scope]) + options[:conditions] = scopes.inject({}) do |conditions,attr| + conditions.merge attr => self[attr] + end unless scopes.empty? + self.class.base_class.scoped options + end + + # on creation, set automatically lft and rgt to the end of the tree + def set_default_left_and_right + maxright = nested_set_scope.maximum(right_column_name) || 0 + # adds the new node to the right of all existing nodes + self[left_column_name] = maxright + 1 + self[right_column_name] = maxright + 2 + end + + # Prunes a branch off of the tree, shifting all of the elements on the right + # back to the left so the counts still work. + def prune_from_tree + return if right.nil? || left.nil? || !self.class.exists?(id) + + self.class.base_class.transaction do + reload_nested_set + if acts_as_nested_set_options[:dependent] == :destroy + children.each(&:destroy) + else + nested_set_scope.send(:delete_all, + ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", + left, right] + ) + end + reload_nested_set + diff = right - left + 1 + nested_set_scope.update_all( + ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff], + ["#{quoted_left_column_name} >= ?", right] + ) + nested_set_scope.update_all( + ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff], + ["#{quoted_right_column_name} >= ?", right] + ) + end + + # Reload is needed because children may have updated their parent (self) during deletion. + reload + end + + # reload left, right, and parent + def reload_nested_set + reload(:select => "#{quoted_left_column_name}, " + + "#{quoted_right_column_name}, #{quoted_parent_column_name}") + end + + def move_to(target, position) + raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record? + return if callback(:before_move) == false + transaction do + if target.is_a? self.class.base_class + target.reload_nested_set + elsif position != :root + # load object if node is not an object + target = nested_set_scope.find(target) + end + self.reload_nested_set + + unless position == :root || move_possible?(target) + raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." + end + + bound = case position + when :child; target[right_column_name] + when :left; target[left_column_name] + when :right; target[right_column_name] + 1 + when :root; 1 + else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)." + end + + if bound > self[right_column_name] + bound = bound - 1 + other_bound = self[right_column_name] + 1 + else + other_bound = self[left_column_name] - 1 + end + + # there would be no change + return if bound == self[right_column_name] || bound == self[left_column_name] + + # we have defined the boundaries of two non-overlapping intervals, + # so sorting puts both the intervals and their boundaries in order + a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort + + new_parent = case position + when :child; target.id + when :root; nil + else target[parent_column_name] + end + + self.class.base_class.update_all([ + "#{quoted_left_column_name} = CASE " + + "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " + + "THEN #{quoted_left_column_name} + :d - :b " + + "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " + + "THEN #{quoted_left_column_name} + :a - :c " + + "ELSE #{quoted_left_column_name} END, " + + "#{quoted_right_column_name} = CASE " + + "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " + + "THEN #{quoted_right_column_name} + :d - :b " + + "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " + + "THEN #{quoted_right_column_name} + :a - :c " + + "ELSE #{quoted_right_column_name} END, " + + "#{quoted_parent_column_name} = CASE " + + "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " + + "ELSE #{quoted_parent_column_name} END", + {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent} + ], nested_set_scope.proxy_options[:conditions]) + end + target.reload_nested_set if target + self.reload_nested_set + callback(:after_move) + end + + end + + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3e/3e497523d528dce449385801e7d571e2b8c31896.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3e/3e497523d528dce449385801e7d571e2b8c31896.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1006 @@ +bg: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Неделя, Понеделник, Вторник, Сряда, Четвъртък, Петък, Събота] + abbr_day_names: [Нед, Пон, Вто, Сря, Чет, Пет, Съб] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Януари, Февруари, Март, Април, Май, Юни, Юли, Август, Септември, Октомври, Ноември, Декември] + abbr_month_names: [~, Яну, Фев, Мар, Апр, Май, Юни, Юли, Авг, Сеп, Окт, Ное, Дек] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "по-малко от 1 секунда" + other: "по-малко от %{count} секунди" + x_seconds: + one: "1 секунда" + other: "%{count} секунди" + less_than_x_minutes: + one: "по-малко от 1 минута" + other: "по-малко от %{count} минути" + x_minutes: + one: "1 минута" + other: "%{count} минути" + about_x_hours: + one: "около 1 час" + other: "около %{count} часа" + x_days: + one: "1 ден" + other: "%{count} дена" + about_x_months: + one: "около 1 месец" + other: "около %{count} месеца" + x_months: + one: "1 месец" + other: "%{count} месеца" + about_x_years: + one: "около 1 година" + other: "около %{count} години" + over_x_years: + one: "над 1 година" + other: "над %{count} години" + almost_x_years: + one: "почти 1 година" + other: "почти %{count} години" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + precision: 1 + delimiter: "" + storage_units: + format: "%n %u" + units: + byte: + one: Byte + other: Bytes + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "и" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 грешка попречи този %{model} да бъде записан" + other: "%{count} грешки попречиха този %{model} да бъде записан" + messages: + inclusion: "не съществува в списъка" + exclusion: "е запазено" + invalid: "е невалидно" + confirmation: "липсва одобрение" + accepted: "трябва да се приеме" + empty: "не може да е празно" + blank: "не може да е празно" + too_long: "е прекалено дълго" + too_short: "е прекалено късо" + wrong_length: "е с грешна дължина" + taken: "вече съществува" + not_a_number: "не е число" + not_a_date: "е невалидна дата" + greater_than: "трябва да бъде по-голям[a/о] от %{count}" + greater_than_or_equal_to: "трябва да бъде по-голям[a/о] от или равен[a/o] на %{count}" + equal_to: "трябва да бъде равен[a/o] на %{count}" + less_than: "трябва да бъде по-малък[a/o] от %{count}" + less_than_or_equal_to: "трябва да бъде по-малък[a/o] от или равен[a/o] на %{count}" + odd: "трябва да бъде нечетен[a/o]" + even: "трябва да бъде четен[a/o]" + greater_than_start_date: "трябва да е след началната дата" + not_same_project: "не е от същия проект" + circular_dependency: "Тази релация ще доведе до безкрайна зависимост" + cant_link_an_issue_with_a_descendant: "Една задача не може да бъде свързвана към своя подзадача" + + actionview_instancetag_blank_option: Изберете + + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Bulgarian (Български)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Профилът е обновен успешно. + notice_account_invalid_creditentials: Невалиден потребител или парола. + notice_account_password_updated: Паролата е успешно променена. + notice_account_wrong_password: Грешна парола + notice_account_register_done: Профилът е създаден успешно. + notice_account_unknown_email: Непознат e-mail. + notice_can_t_change_password: Този профил е с външен метод за оторизация. Невъзможна смяна на паролата. + notice_account_lost_email_sent: Изпратен ви е e-mail с инструкции за избор на нова парола. + notice_account_activated: Профилът ви е активиран. Вече може да влезете в системата. + notice_successful_create: Успешно създаване. + notice_successful_update: Успешно обновяване. + notice_successful_delete: Успешно изтриване. + notice_successful_connection: Успешно свързване. + notice_file_not_found: Несъществуваща или преместена страница. + notice_locking_conflict: Друг потребител променя тези данни в момента. + notice_not_authorized: Нямате право на достъп до тази страница. + notice_not_authorized_archived_project: Проектът, който се опитвате да видите е архивиран. Ако смятате, че това не е правилно, обърнете се към администратора за разархивиране. + notice_email_sent: "Изпратен e-mail на %{value}" + notice_email_error: "Грешка при изпращане на e-mail (%{value})" + notice_feeds_access_key_reseted: Вашия ключ за RSS достъп беше променен. + notice_api_access_key_reseted: Вашият API ключ за достъп беше изчистен. + notice_failed_to_save_issues: "Неуспешен запис на %{count} задачи от %{total} избрани: %{ids}." + notice_failed_to_save_members: "Невъзможност за запис на член(ове): %{errors}." + notice_no_issue_selected: "Няма избрани задачи." + notice_account_pending: "Профилът Ви е създаден и очаква одобрение от администратор." + notice_default_data_loaded: Примерната информация е заредена успешно. + notice_unable_delete_version: Невъзможност за изтриване на версия + notice_unable_delete_time_entry: Невъзможност за изтриване на запис на time log. + notice_issue_done_ratios_updated: Обновен процент на завършените задачи. + notice_gantt_chart_truncated: Мрежовият график е съкратен, понеже броят на обектите, които могат да бъдат показани е твърде голям (%{max}) + notice_issue_successful_create: Задача %{id} е създадена. + + error_can_t_load_default_data: "Грешка при зареждане на примерната информация: %{value}" + error_scm_not_found: Несъществуващ обект в хранилището. + error_scm_command_failed: "Грешка при опит за комуникация с хранилище: %{value}" + error_scm_annotate: "Обектът не съществува или не може да бъде анотиран." + error_scm_annotate_big_text_file: "Файлът не може да бъде анотиран, понеже надхвърля максималния размер за текстови файлове." + error_issue_not_found_in_project: 'Задачата не е намерена или не принадлежи на този проект' + error_no_tracker_in_project: Няма асоциирани тракери с този проект. Проверете настройките на проекта. + error_no_default_issue_status: Няма установено подразбиращо се състояние за задачите. Моля проверете вашата конфигурация (Вижте "Администрация -> Състояния на задачи"). + error_can_not_delete_custom_field: Невъзможност за изтриване на потребителско поле + error_can_not_delete_tracker: Този тракер съдържа задачи и не може да бъде изтрит. + error_can_not_remove_role: Тази роля се използва и не може да бъде изтрита. + error_can_not_reopen_issue_on_closed_version: Задача, асоциирана със затворена версия не може да бъде отворена отново + error_can_not_archive_project: Този проект не може да бъде архивиран + error_issue_done_ratios_not_updated: Процентът на завършените задачи не е обновен. + error_workflow_copy_source: Моля изберете source тракер или роля + error_workflow_copy_target: Моля изберете тракер(и) и роля (роли). + error_unable_delete_issue_status: Невъзможност за изтриване на състояние на задача + error_unable_to_connect: Невъзможност за свързване с (%{value}) + error_attachment_too_big: Този файл не може да бъде качен, понеже надхвърля максималната възможна големина (%{max_size}) + warning_attachments_not_saved: "%{count} файла не бяха записани." + + mail_subject_lost_password: "Вашата парола (%{value})" + mail_body_lost_password: 'За да смените паролата си, използвайте следния линк:' + mail_subject_register: "Активация на профил (%{value})" + mail_body_register: 'За да активирате профила си използвайте следния линк:' + mail_body_account_information_external: "Можете да използвате вашия %{value} профил за вход." + mail_body_account_information: Информацията за профила ви + mail_subject_account_activation_request: "Заявка за активиране на профил в %{value}" + mail_body_account_activation_request: "Има новорегистриран потребител (%{value}), очакващ вашето одобрение:" + mail_subject_reminder: "%{count} задачи с краен срок с следващите %{days} дни" + mail_body_reminder: "%{count} задачи, назначени на вас са с краен срок в следващите %{days} дни:" + mail_subject_wiki_content_added: "Wiki страницата '%{id}' беше добавена" + mail_body_wiki_content_added: Wiki страницата '%{id}' беше добавена от %{author}. + mail_subject_wiki_content_updated: "Wiki страницата '%{id}' беше обновена" + mail_body_wiki_content_updated: Wiki страницата '%{id}' беше обновена от %{author}. + + gui_validation_error: 1 грешка + gui_validation_error_plural: "%{count} грешки" + + field_name: Име + field_description: Описание + field_summary: Анотация + field_is_required: Задължително + field_firstname: Име + field_lastname: Фамилия + field_mail: Email + field_filename: Файл + field_filesize: Големина + field_downloads: Изтеглени файлове + field_author: Автор + field_created_on: От дата + field_updated_on: Обновена + field_field_format: Тип + field_is_for_all: За всички проекти + field_possible_values: Възможни стойности + field_regexp: Регулярен израз + field_min_length: Мин. дължина + field_max_length: Макс. дължина + field_value: Стойност + field_category: Категория + field_title: Заглавие + field_project: Проект + field_issue: Задача + field_status: Състояние + field_notes: Бележка + field_is_closed: Затворена задача + field_is_default: Състояние по подразбиране + field_tracker: Тракер + field_subject: Относно + field_due_date: Крайна дата + field_assigned_to: Възложена на + field_priority: Приоритет + field_fixed_version: Планувана версия + field_user: Потребител + field_principal: Principal + field_role: Роля + field_homepage: Начална страница + field_is_public: Публичен + field_parent: Подпроект на + field_is_in_roadmap: Да се вижда ли в Пътна карта + field_login: Потребител + field_mail_notification: Известия по пощата + field_admin: Администратор + field_last_login_on: Последно свързване + field_language: Език + field_effective_date: Дата + field_password: Парола + field_new_password: Нова парола + field_password_confirmation: Потвърждение + field_version: Версия + field_type: Тип + field_host: Хост + field_port: Порт + field_account: Профил + field_base_dn: Base DN + field_attr_login: Атрибут Login + field_attr_firstname: Атрибут Първо име (Firstname) + field_attr_lastname: Атрибут Фамилия (Lastname) + field_attr_mail: Атрибут Email + field_onthefly: Динамично създаване на потребител + field_start_date: Начална дата + field_done_ratio: "% Прогрес" + field_auth_source: Начин на оторизация + field_hide_mail: Скрий e-mail адреса ми + field_comments: Коментар + field_url: Адрес + field_start_page: Начална страница + field_subproject: Подпроект + field_hours: Часове + field_activity: Дейност + field_spent_on: Дата + field_identifier: Идентификатор + field_is_filter: Използва се за филтър + field_issue_to: Свързана задача + field_delay: Отместване + field_assignable: Възможно е възлагане на задачи за тази роля + field_redirect_existing_links: Пренасочване на съществуващи линкове + field_estimated_hours: Изчислено време + field_column_names: Колони + field_time_entries: Log time + field_time_zone: Часова зона + field_searchable: С възможност за търсене + field_default_value: Стойност по подразбиране + field_comments_sorting: Сортиране на коментарите + field_parent_title: Родителска страница + field_editable: Editable + field_watcher: Наблюдател + field_identity_url: OpenID URL + field_content: Съдържание + field_group_by: Групиране на резултатите по + field_sharing: Sharing + field_parent_issue: Родителска задача + field_member_of_group: Член на група + field_assigned_to_role: Assignee's role + field_text: Текстово поле + field_visible: Видим + field_warn_on_leaving_unsaved: Предупреди ме, когато напускам страница с незаписано съдържание + field_issues_visibility: Видимост на задачите + field_is_private: Лична + field_commit_logs_encoding: Кодова таблица на съобщенията при поверяване + field_scm_path_encoding: Кодова таблица на пътищата (path) + field_path_to_repository: Път до хранилището + field_root_directory: Коренна директория (папка) + field_cvsroot: CVSROOT + field_cvs_module: Модул + + setting_app_title: Заглавие + setting_app_subtitle: Описание + setting_welcome_text: Допълнителен текст + setting_default_language: Език по подразбиране + setting_login_required: Изискване за вход в системата + setting_self_registration: Регистрация от потребители + setting_attachment_max_size: Максимална големина на прикачен файл + setting_issues_export_limit: Максимален брой задачи за експорт + setting_mail_from: E-mail адрес за емисии + setting_bcc_recipients: Получатели на скрито копие (bcc) + setting_plain_text_mail: само чист текст (без HTML) + setting_host_name: Хост + setting_text_formatting: Форматиране на текста + setting_wiki_compression: Компресиране на Wiki историята + setting_feeds_limit: Максимален брой записи в ATOM емисии + setting_default_projects_public: Новите проекти са публични по подразбиране + setting_autofetch_changesets: Автоматично извличане на ревизиите + setting_sys_api_enabled: Разрешаване на WS за управление + setting_commit_ref_keywords: Отбелязващи ключови думи + setting_commit_fix_keywords: Приключващи ключови думи + setting_autologin: Автоматичен вход + setting_date_format: Формат на датата + setting_time_format: Формат на часа + setting_cross_project_issue_relations: Релации на задачи между проекти + setting_issue_list_default_columns: Показвани колони по подразбиране + setting_repositories_encodings: Кодова таблица на прикачените файлове и хранилищата + setting_emails_header: Emails header + setting_emails_footer: Подтекст за e-mail + setting_protocol: Протокол + setting_per_page_options: Опции за страниране + setting_user_format: Потребителски формат + setting_activity_days_default: Брой дни показвани на таб Дейност + setting_display_subprojects_issues: Задачите от подпроектите по подразбиране се показват в главните проекти + setting_enabled_scm: Разрешена SCM + setting_mail_handler_body_delimiters: Отрязване на e-mail-ите след един от тези редове + setting_mail_handler_api_enabled: Разрешаване на WS за входящи e-mail-и + setting_mail_handler_api_key: API ключ + setting_sequential_project_identifiers: Генериране на последователни проектни идентификатори + setting_gravatar_enabled: Използване на портребителски икони от Gravatar + setting_gravatar_default: Подразбиращо се изображение от Gravatar + setting_diff_max_lines_displayed: Максимален брой показвани diff редове + setting_file_max_size_displayed: Максимален размер на текстовите файлове, показвани inline + setting_repository_log_display_limit: Максимален брой на показванете ревизии в лог файла + setting_openid: Рарешаване на OpenID вход и регистрация + setting_password_min_length: Минимална дължина на парола + setting_new_project_user_role_id: Роля, давана на потребител, създаващ проекти, който не е администратор + setting_default_projects_modules: Активирани модули по подразбиране за нов проект + setting_issue_done_ratio: Изчисление на процента на готови задачи с + setting_issue_done_ratio_issue_field: Използване на поле '% Прогрес' + setting_issue_done_ratio_issue_status: Използване на състоянието на задачите + setting_start_of_week: Първи ден на седмицата + setting_rest_api_enabled: Разрешаване на REST web сървис + setting_cache_formatted_text: Кеширане на форматираните текстове + setting_default_notification_option: Подразбиращ се начин за известяване + setting_commit_logtime_enabled: Разрешаване на отчитането на работното време + setting_commit_logtime_activity_id: Дейност при отчитане на работното време + setting_gantt_items_limit: Максимален брой обекти, които да се показват в мрежов график + setting_issue_group_assignment: Разрешено назначаването на задачи на групи + setting_default_issue_start_date_to_creation_date: Начална дата на новите задачи по подразбиране да бъде днешната дата + + permission_add_project: Създаване на проект + permission_add_subprojects: Създаване на подпроекти + permission_edit_project: Редактиране на проект + permission_select_project_modules: Избор на проектни модули + permission_manage_members: Управление на членовете (на екип) + permission_manage_project_activities: Управление на дейностите на проекта + permission_manage_versions: Управление на версиите + permission_manage_categories: Управление на категориите + permission_view_issues: Разглеждане на задачите + permission_add_issues: Добавяне на задачи + permission_edit_issues: Редактиране на задачи + permission_manage_issue_relations: Управление на връзките между задачите + permission_set_own_issues_private: Установяване на собствените задачи публични или лични + permission_set_issues_private: Установяване на задачите публични или лични + permission_add_issue_notes: Добавяне на бележки + permission_edit_issue_notes: Редактиране на бележки + permission_edit_own_issue_notes: Редактиране на собствени бележки + permission_move_issues: Преместване на задачи + permission_delete_issues: Изтриване на задачи + permission_manage_public_queries: Управление на публичните заявки + permission_save_queries: Запис на запитвания (queries) + permission_view_gantt: Разглеждане на мрежов график + permission_view_calendar: Разглеждане на календари + permission_view_issue_watchers: Разглеждане на списък с наблюдатели + permission_add_issue_watchers: Добавяне на наблюдатели + permission_delete_issue_watchers: Изтриване на наблюдатели + permission_log_time: Log spent time + permission_view_time_entries: Разглеждане на изразходваното време + permission_edit_time_entries: Редактиране на time logs + permission_edit_own_time_entries: Редактиране на собствените time logs + permission_manage_news: Управление на новини + permission_comment_news: Коментиране на новини + permission_manage_documents: Управление на документи + permission_view_documents: Разглеждане на документи + permission_manage_files: Управление на файлове + permission_view_files: Разглеждане на файлове + permission_manage_wiki: Управление на wiki + permission_rename_wiki_pages: Преименуване на wiki страници + permission_delete_wiki_pages: Изтриване на wiki страници + permission_view_wiki_pages: Разглеждане на wiki + permission_view_wiki_edits: Разглеждане на wiki история + permission_edit_wiki_pages: Редактиране на wiki страници + permission_delete_wiki_pages_attachments: Изтриване на прикачени файлове към wiki страници + permission_protect_wiki_pages: Заключване на wiki страници + permission_manage_repository: Управление на хранилища + permission_browse_repository: Разглеждане на хранилища + permission_view_changesets: Разглеждане на changesets + permission_commit_access: Поверяване + permission_manage_boards: Управление на boards + permission_view_messages: Разглеждане на съобщения + permission_add_messages: Публикуване на съобщения + permission_edit_messages: Редактиране на съобщения + permission_edit_own_messages: Редактиране на собствени съобщения + permission_delete_messages: Изтриване на съобщения + permission_delete_own_messages: Изтриване на собствени съобщения + permission_export_wiki_pages: Експорт на wiki страници + permission_manage_subtasks: Управление на подзадачите + + project_module_issue_tracking: Тракинг + project_module_time_tracking: Отделяне на време + project_module_news: Новини + project_module_documents: Документи + project_module_files: Файлове + project_module_wiki: Wiki + project_module_repository: Хранилище + project_module_boards: Форуми + project_module_calendar: Календар + project_module_gantt: Мрежов график + + label_user: Потребител + label_user_plural: Потребители + label_user_new: Нов потребител + label_user_anonymous: Анонимен + label_project: Проект + label_project_new: Нов проект + label_project_plural: Проекти + label_x_projects: + zero: 0 проекта + one: 1 проект + other: "%{count} проекта" + label_project_all: Всички проекти + label_project_latest: Последни проекти + label_issue: Задача + label_issue_new: Нова задача + label_issue_plural: Задачи + label_issue_view_all: Всички задачи + label_issues_by: "Задачи по %{value}" + label_issue_added: Добавена задача + label_issue_updated: Обновена задача + label_issue_note_added: Добавена бележка + label_issue_status_updated: Обновено състояние + label_issue_priority_updated: Обновен приоритет + label_document: Документ + label_document_new: Нов документ + label_document_plural: Документи + label_document_added: Добавен документ + label_role: Роля + label_role_plural: Роли + label_role_new: Нова роля + label_role_and_permissions: Роли и права + label_role_anonymous: Анонимен + label_role_non_member: Не член + label_member: Член + label_member_new: Нов член + label_member_plural: Членове + label_tracker: Тракер + label_tracker_plural: Тракери + label_tracker_new: Нов тракер + label_workflow: Работен процес + label_issue_status: Състояние на задача + label_issue_status_plural: Състояния на задачи + label_issue_status_new: Ново състояние + label_issue_category: Категория задача + label_issue_category_plural: Категории задачи + label_issue_category_new: Нова категория + label_custom_field: Потребителско поле + label_custom_field_plural: Потребителски полета + label_custom_field_new: Ново потребителско поле + label_enumerations: Списъци + label_enumeration_new: Нова стойност + label_information: Информация + label_information_plural: Информация + label_please_login: Вход + label_register: Регистрация + label_login_with_open_id_option: или вход чрез OpenID + label_password_lost: Забравена парола + label_home: Начало + label_my_page: Лична страница + label_my_account: Профил + label_my_projects: Проекти, в които участвам + label_my_page_block: Блокове в личната страница + label_administration: Администрация + label_login: Вход + label_logout: Изход + label_help: Помощ + label_reported_issues: Публикувани задачи + label_assigned_to_me_issues: Възложени на мен + label_last_login: Последно свързване + label_registered_on: Регистрация + label_activity: Дейност + label_overall_activity: Цялостна дейност + label_user_activity: "Активност на %{value}" + label_new: Нов + label_logged_as: Здравейте, + label_environment: Среда + label_authentication: Оторизация + label_auth_source: Начин на оторозация + label_auth_source_new: Нов начин на оторизация + label_auth_source_plural: Начини на оторизация + label_subproject_plural: Подпроекти + label_subproject_new: Нов подпроект + label_and_its_subprojects: "%{value} и неговите подпроекти" + label_min_max_length: Минимална - максимална дължина + label_list: Списък + label_date: Дата + label_integer: Целочислен + label_float: Дробно + label_boolean: Чекбокс + label_string: Текст + label_text: Дълъг текст + label_attribute: Атрибут + label_attribute_plural: Атрибути + label_download: "%{count} изтегляне" + label_download_plural: "%{count} изтегляния" + label_no_data: Няма изходни данни + label_change_status: Промяна на състоянието + label_history: История + label_attachment: Файл + label_attachment_new: Нов файл + label_attachment_delete: Изтриване + label_attachment_plural: Файлове + label_file_added: Добавен файл + label_report: Справка + label_report_plural: Справки + label_news: Новини + label_news_new: Добави + label_news_plural: Новини + label_news_latest: Последни новини + label_news_view_all: Виж всички + label_news_added: Добавена новина + label_news_comment_added: Добавен коментар към новина + label_settings: Настройки + label_overview: Общ изглед + label_version: Версия + label_version_new: Нова версия + label_version_plural: Версии + label_close_versions: Затваряне на завършените версии + label_confirmation: Одобрение + label_export_to: Експорт към + label_read: Read... + label_public_projects: Публични проекти + label_open_issues: отворена + label_open_issues_plural: отворени + label_closed_issues: затворена + label_closed_issues_plural: затворени + label_x_open_issues_abbr_on_total: + zero: 0 отворени / %{total} + one: 1 отворена / %{total} + other: "%{count} отворени / %{total}" + label_x_open_issues_abbr: + zero: 0 отворени + one: 1 отворена + other: "%{count} отворени" + label_x_closed_issues_abbr: + zero: 0 затворени + one: 1 затворена + other: "%{count} затворени" + label_total: Общо + label_permissions: Права + label_current_status: Текущо състояние + label_new_statuses_allowed: Позволени състояния + label_all: всички + label_none: никакви + label_nobody: никой + label_next: Следващ + label_previous: Предишен + label_used_by: Използва се от + label_details: Детайли + label_add_note: Добавяне на бележка + label_per_page: На страница + label_calendar: Календар + label_months_from: месеца от + label_gantt: Мрежов график + label_internal: Вътрешен + label_last_changes: "последни %{count} промени" + label_change_view_all: Виж всички промени + label_personalize_page: Персонализиране + label_comment: Коментар + label_comment_plural: Коментари + label_x_comments: + zero: 0 коментари + one: 1 коментар + other: "%{count} коментари" + label_comment_add: Добавяне на коментар + label_comment_added: Добавен коментар + label_comment_delete: Изтриване на коментари + label_query: Потребителска справка + label_query_plural: Потребителски справки + label_query_new: Нова заявка + label_my_queries: Моите заявки + label_filter_add: Добави филтър + label_filter_plural: Филтри + label_equals: е + label_not_equals: не е + label_in_less_than: след по-малко от + label_in_more_than: след повече от + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_between: между + label_in: в следващите + label_today: днес + label_all_time: всички + label_yesterday: вчера + label_this_week: тази седмица + label_last_week: последната седмица + label_last_n_days: "последните %{count} дни" + label_this_month: текущия месец + label_last_month: последния месец + label_this_year: текущата година + label_date_range: Период + label_less_than_ago: преди по-малко от + label_more_than_ago: преди повече от + label_ago: преди + label_contains: съдържа + label_not_contains: не съдържа + label_day_plural: дни + label_repository: Хранилище + label_repository_plural: Хранилища + label_browse: Разглеждане + label_modification: "%{count} промяна" + label_modification_plural: "%{count} промени" + label_branch: работен вариант + label_tag: Версия + label_revision: Ревизия + label_revision_plural: Ревизии + label_revision_id: Ревизия %{value} + label_associated_revisions: Асоциирани ревизии + label_added: добавено + label_modified: променено + label_copied: копирано + label_renamed: преименувано + label_deleted: изтрито + label_latest_revision: Последна ревизия + label_latest_revision_plural: Последни ревизии + label_view_revisions: Виж ревизиите + label_view_all_revisions: Разглеждане на всички ревизии + label_max_size: Максимална големина + label_sort_highest: Премести най-горе + label_sort_higher: Премести по-горе + label_sort_lower: Премести по-долу + label_sort_lowest: Премести най-долу + label_roadmap: Пътна карта + label_roadmap_due_in: "Излиза след %{value}" + label_roadmap_overdue: "%{value} закъснение" + label_roadmap_no_issues: Няма задачи за тази версия + label_search: Търсене + label_result_plural: Pезултати + label_all_words: Всички думи + label_wiki: Wiki + label_wiki_edit: Wiki редакция + label_wiki_edit_plural: Wiki редакции + label_wiki_page: Wiki страница + label_wiki_page_plural: Wiki страници + label_index_by_title: Индекс + label_index_by_date: Индекс по дата + label_current_version: Текуща версия + label_preview: Преглед + label_feed_plural: Емисии + label_changes_details: Подробни промени + label_issue_tracking: Тракинг + label_spent_time: Отделено време + label_overall_spent_time: Общо употребено време + label_f_hour: "%{value} час" + label_f_hour_plural: "%{value} часа" + label_time_tracking: Отделяне на време + label_change_plural: Промени + label_statistics: Статистики + label_commits_per_month: Ревизии по месеци + label_commits_per_author: Ревизии по автор + label_diff: diff + label_view_diff: Виж разликите + label_diff_inline: хоризонтално + label_diff_side_by_side: вертикално + label_options: Опции + label_copy_workflow_from: Копирай работния процес от + label_permissions_report: Справка за права + label_watched_issues: Наблюдавани задачи + label_related_issues: Свързани задачи + label_applied_status: Установено състояние + label_loading: Зареждане... + label_relation_new: Нова релация + label_relation_delete: Изтриване на релация + label_relates_to: свързана със + label_duplicates: дублира + label_duplicated_by: дублирана от + label_blocks: блокира + label_blocked_by: блокирана от + label_precedes: предшества + label_follows: изпълнява се след + label_end_to_start: край към начало + label_end_to_end: край към край + label_start_to_start: начало към начало + label_start_to_end: начало към край + label_stay_logged_in: Запомни ме + label_disabled: забранено + label_show_completed_versions: Показване на реализирани версии + label_me: аз + label_board: Форум + label_board_new: Нов форум + label_board_plural: Форуми + label_board_locked: Заключена + label_board_sticky: Sticky + label_topic_plural: Теми + label_message_plural: Съобщения + label_message_last: Последно съобщение + label_message_new: Нова тема + label_message_posted: Добавено съобщение + label_reply_plural: Отговори + label_send_information: Изпращане на информацията до потребителя + label_year: Година + label_month: Месец + label_week: Седмица + label_date_from: От + label_date_to: До + label_language_based: В зависимост от езика + label_sort_by: "Сортиране по %{value}" + label_send_test_email: Изпращане на тестов e-mail + label_feeds_access_key: RSS access ключ + label_missing_feeds_access_key: Липсващ RSS ключ за достъп + label_feeds_access_key_created_on: "%{value} от създаването на RSS ключа" + label_module_plural: Модули + label_added_time_by: "Публикувана от %{author} преди %{age}" + label_updated_time_by: "Обновена от %{author} преди %{age}" + label_updated_time: "Обновена преди %{value}" + label_jump_to_a_project: Проект... + label_file_plural: Файлове + label_changeset_plural: Ревизии + label_default_columns: По подразбиране + label_no_change_option: (Без промяна) + label_bulk_edit_selected_issues: Групово редактиране на задачи + label_bulk_edit_selected_time_entries: Групово редактиране на записи за използвано време + label_theme: Тема + label_default: По подразбиране + label_search_titles_only: Само в заглавията + label_user_mail_option_all: "За всяко събитие в проектите, в които участвам" + label_user_mail_option_selected: "За всички събития само в избраните проекти..." + label_user_mail_option_none: "Само за наблюдавани или в които участвам (автор или назначени на мен)" + label_user_mail_option_only_my_events: Само за неща, в които съм включен/а + label_user_mail_option_only_assigned: Само за неща, назначени на мен + label_user_mail_option_only_owner: Само за неща, на които аз съм собственик + label_user_mail_no_self_notified: "Не искам известия за извършени от мен промени" + label_registration_activation_by_email: активиране на профила по email + label_registration_manual_activation: ръчно активиране + label_registration_automatic_activation: автоматично активиране + label_display_per_page: "На страница по: %{value}" + label_age: Възраст + label_change_properties: Промяна на настройки + label_general: Основни + label_more: Още + label_scm: SCM (Система за контрол на версиите) + label_plugins: Плъгини + label_ldap_authentication: LDAP оторизация + label_downloads_abbr: D/L + label_optional_description: Незадължително описание + label_add_another_file: Добавяне на друг файл + label_preferences: Предпочитания + label_chronological_order: Хронологичен ред + label_reverse_chronological_order: Обратен хронологичен ред + label_planning: Планиране + label_incoming_emails: Входящи e-mail-и + label_generate_key: Генериране на ключ + label_issue_watchers: Наблюдатели + label_example: Пример + label_display: Display + label_sort: Сортиране + label_ascending: Нарастващ + label_descending: Намаляващ + label_date_from_to: От %{start} до %{end} + label_wiki_content_added: Wiki страница беше добавена + label_wiki_content_updated: Wiki страница беше обновена + label_group: Група + label_group_plural: Групи + label_group_new: Нова група + label_time_entry_plural: Използвано време + label_version_sharing_none: Не споделен + label_version_sharing_descendants: С подпроекти + label_version_sharing_hierarchy: С проектна йерархия + label_version_sharing_tree: С дърво на проектите + label_version_sharing_system: С всички проекти + label_update_issue_done_ratios: Обновяване на процента на завършените задачи + label_copy_source: Източник + label_copy_target: Цел + label_copy_same_as_target: Също като целта + label_display_used_statuses_only: Показване само на състоянията, използвани от този тракер + label_api_access_key: API ключ за достъп + label_missing_api_access_key: Липсващ API ключ + label_api_access_key_created_on: API ключ за достъп е създаден преди %{value} + label_profile: Профил + label_subtask_plural: Подзадачи + label_project_copy_notifications: Изпращане на Send e-mail известия по време на копирането на проекта + label_principal_search: "Търсене на потребител или група:" + label_user_search: "Търсене на потребител:" + label_additional_workflow_transitions_for_author: Позволени са допълнителни преходи, когато потребителят е авторът + label_additional_workflow_transitions_for_assignee: Позволени са допълнителни преходи, когато потребителят е назначеният към задачата + label_issues_visibility_all: Всички задачи + label_issues_visibility_public: Всички не-лични задачи + label_issues_visibility_own: Задачи, създадени от или назначени на потребителя + label_git_report_last_commit: Извеждане на последното поверяване за файлове и папки + label_parent_revision: Ревизия родител + label_child_revision: Ревизия наследник + label_export_options: "%{export_format} опции за експорт" + + button_login: Вход + button_submit: Прикачване + button_save: Запис + button_check_all: Избор на всички + button_uncheck_all: Изчистване на всички + button_collapse_all: Скриване всички + button_expand_all: Разгъване всички + button_delete: Изтриване + button_create: Създаване + button_create_and_continue: Създаване и продължаване + button_test: Тест + button_edit: Редакция + button_edit_associated_wikipage: "Редактиране на асоциираната Wiki страница: %{page_title}" + button_add: Добавяне + button_change: Промяна + button_apply: Приложи + button_clear: Изчисти + button_lock: Заключване + button_unlock: Отключване + button_download: Изтегляне + button_list: Списък + button_view: Преглед + button_move: Преместване + button_move_and_follow: Преместване и продължаване + button_back: Назад + button_cancel: Отказ + button_activate: Активация + button_sort: Сортиране + button_log_time: Отделяне на време + button_rollback: Върни се към тази ревизия + button_watch: Наблюдаване + button_unwatch: Край на наблюдението + button_reply: Отговор + button_archive: Архивиране + button_unarchive: Разархивиране + button_reset: Генериране наново + button_rename: Преименуване + button_change_password: Промяна на парола + button_copy: Копиране + button_copy_and_follow: Копиране и продължаване + button_annotate: Анотация + button_update: Обновяване + button_configure: Конфигуриране + button_quote: Цитат + button_duplicate: Дублиране + button_show: Показване + button_edit_section: Редактиране на тази секция + button_export: Експорт + + status_active: активен + status_registered: регистриран + status_locked: заключен + + version_status_open: отворена + version_status_locked: заключена + version_status_closed: затворена + + field_active: Активен + + text_select_mail_notifications: Изберете събития за изпращане на e-mail. + text_regexp_info: пр. ^[A-Z0-9]+$ + text_min_max_length_info: 0 - без ограничения + text_project_destroy_confirmation: Сигурни ли сте, че искате да изтриете проекта и данните в него? + text_subprojects_destroy_warning: "Неговите подпроекти: %{value} също ще бъдат изтрити." + text_workflow_edit: Изберете роля и тракер за да редактирате работния процес + text_are_you_sure: Сигурни ли сте? + text_are_you_sure_with_children: Изтриване на задачата и нейните подзадачи? + text_journal_changed: "%{label} променен от %{old} на %{new}" + text_journal_changed_no_detail: "%{label} променен" + text_journal_set_to: "%{label} установен на %{value}" + text_journal_deleted: "%{label} изтрит (%{old})" + text_journal_added: "Добавено %{label} %{value}" + text_tip_issue_begin_day: задача, започваща този ден + text_tip_issue_end_day: задача, завършваща този ден + text_tip_issue_begin_end_day: задача, започваща и завършваща този ден + text_project_identifier_info: 'Позволени са малки букви (a-z), цифри и тирета.
Невъзможна промяна след запис.' + text_caracters_maximum: "До %{count} символа." + text_caracters_minimum: "Минимум %{count} символа." + text_length_between: "От %{min} до %{max} символа." + text_tracker_no_workflow: Няма дефиниран работен процес за този тракер + text_unallowed_characters: Непозволени символи + text_comma_separated: Позволено е изброяване (с разделител запетая). + text_line_separated: Позволени са много стойности (по едно на ред). + text_issues_ref_in_commit_messages: Отбелязване и приключване на задачи от ревизии + text_issue_added: "Публикувана е нова задача с номер %{id} (от %{author})." + text_issue_updated: "Задача %{id} е обновена (от %{author})." + text_wiki_destroy_confirmation: Сигурни ли сте, че искате да изтриете това Wiki и цялото му съдържание? + text_issue_category_destroy_question: "Има задачи (%{count}) обвързани с тази категория. Какво ще изберете?" + text_issue_category_destroy_assignments: Премахване на връзките с категорията + text_issue_category_reassign_to: Преобвързване с категория + text_user_mail_option: "За неизбраните проекти, ще получавате известия само за наблюдавани дейности или в които участвате (т.е. автор или назначени на мен)." + text_no_configuration_data: "Все още не са конфигурирани Роли, тракери, състояния на задачи и работен процес.\nСтрого се препоръчва зареждането на примерната информация. Веднъж заредена ще имате възможност да я редактирате." + text_load_default_configuration: Зареждане на примерна информация + text_status_changed_by_changeset: "Приложено с ревизия %{value}." + text_time_logged_by_changeset: Приложено в ревизия %{value}. + text_issues_destroy_confirmation: 'Сигурни ли сте, че искате да изтриете избраните задачи?' + text_issues_destroy_descendants_confirmation: Тази операция ще премахне и %{count} подзадача(и). + text_time_entries_destroy_confirmation: Сигурен ли сте, че изтриете избраните записи за изразходвано време? + text_select_project_modules: 'Изберете активните модули за този проект:' + text_default_administrator_account_changed: Сменен фабричния администраторски профил + text_file_repository_writable: Възможност за писане в хранилището с файлове + text_plugin_assets_writable: Папката на приставките е разрешена за запис + text_rmagick_available: Наличен RMagick (по избор) + text_destroy_time_entries_question: "%{hours} часа са отделени на задачите, които искате да изтриете. Какво избирате?" + text_destroy_time_entries: Изтриване на отделеното време + text_assign_time_entries_to_project: Прехвърляне на отделеното време към проект + text_reassign_time_entries: 'Прехвърляне на отделеното време към задача:' + text_user_wrote: "%{value} написа:" + text_enumeration_destroy_question: "%{count} обекта са свързани с тази стойност." + text_enumeration_category_reassign_to: 'Пресвържете ги към тази стойност:' + text_email_delivery_not_configured: "Изпращането на e-mail-и не е конфигурирано и известията не са разрешени.\nКонфигурирайте вашия SMTP сървър в config/configuration.yml и рестартирайте Redmine, за да ги разрешите." + text_repository_usernames_mapping: "Изберете или променете потребителите в Redmine, съответстващи на потребителите в дневника на хранилището (repository).\nПотребителите с еднакви имена в Redmine и хранилищата се съвместяват автоматично." + text_diff_truncated: '... Този diff не е пълен, понеже е надхвърля максималния размер, който може да бъде показан.' + text_custom_field_possible_values_info: 'Една стойност на ред' + text_wiki_page_destroy_question: Тази страница има %{descendants} страници деца и descendant(s). Какво желаете да правите? + text_wiki_page_nullify_children: Запазване на тези страници като коренни страници + text_wiki_page_destroy_children: Изтриване на страниците деца и всички техни descendants + text_wiki_page_reassign_children: Преназначаване на страниците деца на тази родителска страница + text_own_membership_delete_confirmation: "Вие сте на път да премахнете някои или всички ваши разрешения и е възможно след това да не можете да редактирате този проект.\nСигурен ли сте, че искате да продължите?" + text_zoom_in: Увеличаване + text_zoom_out: Намаляване + text_warn_on_leaving_unsaved: Страницата съдържа незаписано съдържание, което може да бъде загубено, ако я напуснете. + text_scm_path_encoding_note: "По подразбиране: UTF-8" + text_git_repository_note: Празно и локално хранилище (например /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Локално хранилище (например /hgrepo, c:\hgrepo) + text_scm_command: SCM команда + text_scm_command_version: Версия + text_scm_config: Можете да конфигурирате SCM командите в config/configuration.yml. За да активирате промените, рестартирайте Redmine. + text_scm_command_not_available: SCM командата не е налична или достъпна. Проверете конфигурацията в административния панел. + + default_role_manager: Мениджър + default_role_developer: Разработчик + default_role_reporter: Публикуващ + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Поддръжка + default_issue_status_new: Нова + default_issue_status_in_progress: Изпълнение + default_issue_status_resolved: Приключена + default_issue_status_feedback: Обратна връзка + default_issue_status_closed: Затворена + default_issue_status_rejected: Отхвърлена + default_doc_category_user: Документация за потребителя + default_doc_category_tech: Техническа документация + default_priority_low: Нисък + default_priority_normal: Нормален + default_priority_high: Висок + default_priority_urgent: Спешен + default_priority_immediate: Веднага + default_activity_design: Дизайн + default_activity_development: Разработка + + enumeration_issue_priorities: Приоритети на задачи + enumeration_doc_categories: Категории документи + enumeration_activities: Дейности (time tracking) + enumeration_system_activity: Системна активност + description_filter: Филтър + description_search: Търсене + description_choose_project: Проекти + description_project_scope: Обхват на търсенето + description_notes: Бележки + description_message_content: Съдържание на съобщението + description_query_sort_criteria_attribute: Атрибут на сортиране + description_query_sort_criteria_direction: Посока на сортиране + description_user_mail_notification: Конфигурация известията по пощата + description_available_columns: Налични колони + description_selected_columns: Избрани колони + description_issue_category_reassign: Изберете категория + description_wiki_subpages_reassign: Изберете нова родителска страница + description_all_columns: Всички колони + description_date_range_list: Изберете диапазон от списъка + description_date_range_interval: Изберете диапазон чрез задаване на начална и крайна дати + description_date_from: Въведете начална дата + description_date_to: Въведете крайна дата diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3e/3e69b6e2154a117c66e42d50dd35e274a3a35611.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3e/3e69b6e2154a117c66e42d50dd35e274a3a35611.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +

<%=l(:label_confirmation)%>

+
+

<%=h @project_to_destroy %>
+<%=l(:text_project_destroy_confirmation)%> + +<% if @project_to_destroy.descendants.any? %> +
<%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.descendants.collect{|p| p.to_s}.join(', ')))) %> +<% end %> +

+

+ <% form_tag(project_path(@project_to_destroy), :method => :delete) do %> + + <%= submit_tag l(:button_delete) %> + <% end %> +

+
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3e/3ea6950d0c13cff7209ccaf8ef599127801a547f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3e/3ea6950d0c13cff7209ccaf8ef599127801a547f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+015A Sacute +!8D U+0164 Tcaron +!8E U+017D Zcaron +!8F U+0179 Zacute +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+015B sacute +!9D U+0165 tcaron +!9E U+017E zcaron +!9F U+017A zacute +!A0 U+00A0 space +!A1 U+02C7 caron +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+0104 Aogonek +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+015E Scedilla +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+0105 aogonek +!BA U+015F scedilla +!BB U+00BB guillemotright +!BC U+013D Lcaron +!BD U+02DD hungarumlaut +!BE U+013E lcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3e/3efd26febde35f053259781a6842c32aa0085eb7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3e/3efd26febde35f053259781a6842c32aa0085eb7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,144 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class SearchTest < ActiveSupport::TestCase + fixtures :users, + :members, + :member_roles, + :projects, + :roles, + :enabled_modules, + :issues, + :trackers, + :journals, + :journal_details, + :repositories, + :changesets + + def setup + @project = Project.find(1) + @issue_keyword = '%unable to print recipes%' + @issue = Issue.find(1) + @changeset_keyword = '%very first commit%' + @changeset = Changeset.find(100) + end + + def test_search_by_anonymous + User.current = nil + + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert r.include?(@changeset) + + # Removes the :view_changesets permission from Anonymous role + remove_permission Role.anonymous, :view_changesets + + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert !r.include?(@changeset) + + # Make the project private + @project.update_attribute :is_public, false + r = Issue.search(@issue_keyword).first + assert !r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert !r.include?(@changeset) + end + + def test_search_by_user + User.current = User.find_by_login('rhill') + assert User.current.memberships.empty? + + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert r.include?(@changeset) + + # Removes the :view_changesets permission from Non member role + remove_permission Role.non_member, :view_changesets + + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert !r.include?(@changeset) + + # Make the project private + @project.update_attribute :is_public, false + r = Issue.search(@issue_keyword).first + assert !r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert !r.include?(@changeset) + end + + def test_search_by_allowed_member + User.current = User.find_by_login('jsmith') + assert User.current.projects.include?(@project) + + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert r.include?(@changeset) + + # Make the project private + @project.update_attribute :is_public, false + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert r.include?(@changeset) + end + + def test_search_by_unallowed_member + # Removes the :view_changesets permission from user's and non member role + remove_permission Role.find(1), :view_changesets + remove_permission Role.non_member, :view_changesets + + User.current = User.find_by_login('jsmith') + assert User.current.projects.include?(@project) + + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert !r.include?(@changeset) + + # Make the project private + @project.update_attribute :is_public, false + r = Issue.search(@issue_keyword).first + assert r.include?(@issue) + r = Changeset.search(@changeset_keyword).first + assert !r.include?(@changeset) + end + + def test_search_issue_with_multiple_hits_in_journals + i = Issue.find(1) + assert_equal 2, i.journals.count(:all, :conditions => "notes LIKE '%notes%'") + + r = Issue.search('%notes%').first + assert_equal 1, r.size + assert_equal i, r.first + end + + private + + def remove_permission(role, permission) + role.permissions = role.permissions - [ permission ] + role.save + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3f0e8212628d5f669e97d1ba675898fce5586337.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3f0e8212628d5f669e97d1ba675898fce5586337.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class LdapAuthSourcesController < AuthSourcesController + + protected + + def auth_source_class + AuthSourceLdap + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3f1432f5ae9fdc8b43bfc5b1f1592ae627706799.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3f1432f5ae9fdc8b43bfc5b1f1592ae627706799.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,48 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class GanttsController < ApplicationController + menu_item :gantt + before_filter :find_optional_project + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :gantt + helper :issues + helper :projects + helper :queries + include QueriesHelper + helper :sort + include SortHelper + include Redmine::Export::PDF + + def show + @gantt = Redmine::Helpers::Gantt.new(params) + @gantt.project = @project + retrieve_query + @query.group_by = nil + @gantt.query = @query if @query.valid? + + basename = (@project ? "#{@project.identifier}-" : '') + 'gantt' + + respond_to do |format| + format.html { render :action => "show", :layout => !request.xhr? } + format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image') + format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => "#{basename}.pdf") } + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3f488b441d624dfa17dfe9e5c4d89573d9f2a475.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3f488b441d624dfa17dfe9e5c4d89573d9f2a475.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,60 @@ +Message-ID: <001101ca9762$293d68c0$0600a8c0@osiris> +From: "jsmith" +To: +Subject: Japanese Character pattern matching +Date: Sun, 17 Jan 2010 11:45:18 +0100 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_NextPart_000_000E_01CA976A.8AF5E9E0" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +This is a multi-part message in MIME format. + +------=_NextPart_000_000E_01CA976A.8AF5E9E0 +Content-Type: text/plain; + charset="iso-2022-jp" +Content-Transfer-Encoding: quoted-printable + +It should be noted that I am receiving emails using pop and the patch in = +Issue #2420 but I don't think the problem lies with this. + +When I try and send emails to the redmine server with Japanese = +characters in them it appears to work apart from the pattern matching. + +For example if I send an email with the following keywords. + +Tracker: =1B$B3+H/=1B(B + +------=_NextPart_000_000E_01CA976A.8AF5E9E0 +Content-Type: text/html; + charset="iso-2022-jp" +Content-Transfer-Encoding: quoted-printable + + + + + + + + +
+

It should be noted that I am receiving emails using pop and the patch = +in=20 +Issue #2420 but I don't think = +the=20 +problem lies with this.

+

When I try and send emails to the redmine server with Japanese = +characters in=20 +them it appears to work apart from the pattern matching.

+

For example if I send an email with the following keywords.

+

Tracker: = +=1B$B3+H/=1B(B

+ +------=_NextPart_000_000E_01CA976A.8AF5E9E0-- + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3f6eeecb089d9f691d285e568d733dd55d35c465.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3f6eeecb089d9f691d285e568d733dd55d35c465.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +require 'awesome_nested_set/compatability' +require 'awesome_nested_set' + +ActiveRecord::Base.class_eval do + include CollectiveIdea::Acts::NestedSet +end + +if defined?(ActionView) + require 'awesome_nested_set/helper' + ActionView::Base.class_eval do + include CollectiveIdea::Acts::NestedSet::Helper + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3fb6e89a6e5f14a7dfc6f31c98abfe75827ecbea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3fb6e89a6e5f14a7dfc6f31c98abfe75827ecbea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,66 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class PrincipalTest < ActiveSupport::TestCase + + context "#like" do + setup do + Principal.generate!(:login => 'login') + Principal.generate!(:login => 'login2') + + Principal.generate!(:firstname => 'firstname') + Principal.generate!(:firstname => 'firstname2') + + Principal.generate!(:lastname => 'lastname') + Principal.generate!(:lastname => 'lastname2') + + Principal.generate!(:mail => 'mail@example.com') + Principal.generate!(:mail => 'mail2@example.com') + end + + should "search login" do + results = Principal.like('login') + + assert_equal 2, results.count + assert results.all? {|u| u.login.match(/login/) } + end + + should "search firstname" do + results = Principal.like('firstname') + + assert_equal 2, results.count + assert results.all? {|u| u.firstname.match(/firstname/) } + end + + should "search lastname" do + results = Principal.like('lastname') + + assert_equal 2, results.count + assert results.all? {|u| u.lastname.match(/lastname/) } + end + + should "search mail" do + results = Principal.like('mail') + + assert_equal 2, results.count + assert results.all? {|u| u.mail.match(/mail/) } + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3fc095ae15466e551cacbea7f0776a64d74a2acd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3fc095ae15466e551cacbea7f0776a64d74a2acd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 UsersHelper + def users_status_options_for_select(selected) + user_count_by_status = User.count(:group => 'status').to_hash + options_for_select([[l(:label_all), ''], + ["#{l(:status_active)} (#{user_count_by_status[1].to_i})", 1], + ["#{l(:status_registered)} (#{user_count_by_status[2].to_i})", 2], + ["#{l(:status_locked)} (#{user_count_by_status[3].to_i})", 3]], selected) + end + + # Options for the new membership projects combo-box + def options_for_membership_project_select(user, projects) + options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options << project_tree_options_for_select(projects) do |p| + {:disabled => (user.projects.include?(p))} + end + options + end + + def user_mail_notification_options(user) + user.valid_notification_options.collect {|o| [l(o.last), o.first]} + end + + def change_status_link(user) + url = {:controller => 'users', :action => 'update', :id => user, :page => params[:page], :status => params[:status], :tab => nil} + + if user.locked? + link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' + elsif user.registered? + link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' + elsif user != User.current + link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock' + end + end + + def user_settings_tabs + tabs = [{:name => 'general', :partial => 'users/general', :label => :label_general}, + {:name => 'memberships', :partial => 'users/memberships', :label => :label_project_plural} + ] + if Group.all.any? + tabs.insert 1, {:name => 'groups', :partial => 'users/groups', :label => :label_group_plural} + end + tabs + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3fe4e91401e89e608109800b1ea5a303da548232.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3fe4e91401e89e608109800b1ea5a303da548232.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,196 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 TimelogHelper + include ApplicationHelper + + def render_timelog_breadcrumb + links = [] + links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) + links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project + if @issue + if @issue.visible? + links << link_to_issue(@issue, :subject => false) + else + links << "##{@issue.id}" + end + end + breadcrumb links + end + + # Returns a collection of activities for a select field. time_entry + # is optional and will be used to check if the selected TimeEntryActivity + # is active. + def activity_collection_for_select_options(time_entry=nil, project=nil) + project ||= @project + if project.nil? + activities = TimeEntryActivity.shared.active + else + activities = project.activities + end + + collection = [] + if time_entry && time_entry.activity && !time_entry.activity.active? + collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] + else + collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) + end + activities.each { |a| collection << [a.name, a.id] } + collection + end + + def select_hours(data, criteria, value) + if value.to_s.empty? + data.select {|row| row[criteria].blank? } + else + data.select {|row| row[criteria].to_s == value.to_s} + end + end + + def sum_hours(data) + sum = 0 + data.each do |row| + sum += row['hours'].to_f + end + sum + end + + def options_for_period_select(value) + options_for_select([[l(:label_all_time), 'all'], + [l(:label_today), 'today'], + [l(:label_yesterday), 'yesterday'], + [l(:label_this_week), 'current_week'], + [l(:label_last_week), 'last_week'], + [l(:label_last_n_days, 7), '7_days'], + [l(:label_this_month), 'current_month'], + [l(:label_last_month), 'last_month'], + [l(:label_last_n_days, 30), '30_days'], + [l(:label_this_year), 'current_year']], + value) + end + + def entries_to_csv(entries) + decimal_separator = l(:general_csv_decimal_separator) + custom_fields = TimeEntryCustomField.find(:all) + export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + # csv header fields + headers = [l(:field_spent_on), + l(:field_user), + l(:field_activity), + l(:field_project), + l(:field_issue), + l(:field_tracker), + l(:field_subject), + l(:field_hours), + l(:field_comments) + ] + # Export custom fields + headers += custom_fields.collect(&:name) + + csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } + # csv lines + entries.each do |entry| + fields = [format_date(entry.spent_on), + entry.user, + entry.activity, + entry.project, + (entry.issue ? entry.issue.id : nil), + (entry.issue ? entry.issue.tracker : nil), + (entry.issue ? entry.issue.subject : nil), + entry.hours.to_s.gsub('.', decimal_separator), + entry.comments + ] + fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } + + csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } + end + end + export + end + + def format_criteria_value(criteria, value) + if value.blank? + l(:label_none) + elsif k = @available_criterias[criteria][:klass] + obj = k.find_by_id(value.to_i) + if obj.is_a?(Issue) + obj.visible? ? "#{obj.tracker} ##{obj.id}: #{obj.subject}" : "##{obj.id}" + else + obj + end + else + format_value(value, @available_criterias[criteria][:format]) + end + end + + def report_to_csv(criterias, periods, hours) + decimal_separator = l(:general_csv_decimal_separator) + export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + # Column headers + headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } + headers += periods + headers << l(:label_total) + csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } + # Content + report_criteria_to_csv(csv, criterias, periods, hours) + # Total row + str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding)) + row = [ str_total ] + [''] * (criterias.size - 1) + total = 0 + periods.each do |period| + sum = sum_hours(select_hours(hours, @columns, period.to_s)) + total += sum + row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') + end + row << ("%.2f" % total).gsub('.',decimal_separator) + csv << row + end + export + end + + def report_criteria_to_csv(csv, criterias, periods, hours, level=0) + decimal_separator = l(:general_csv_decimal_separator) + hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| + hours_for_value = select_hours(hours, criterias[level], value) + next if hours_for_value.empty? + row = [''] * level + row << Redmine::CodesetUtil.from_utf8( + format_criteria_value(criterias[level], value).to_s, + l(:general_csv_encoding) ) + row += [''] * (criterias.length - level - 1) + total = 0 + periods.each do |period| + sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) + total += sum + row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') + end + row << ("%.2f" % total).gsub('.',decimal_separator) + csv << row + if criterias.length > level + 1 + report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/3f/3ff64c6f7b8c7d1560b577e6e864916cca4fbd1d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/3f/3ff64c6f7b8c7d1560b577e6e864916cca4fbd1d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/process/inspector' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/400375524648365ba1821512cc1d87f1c1fbb9c7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/400375524648365ba1821512cc1d87f1c1fbb9c7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= @added_to %><% @attachments.each do |attachment | %> +- <%= attachment.filename %><% end %> + +<%= @added_to_url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/4007bed662ec7349eb8fd5e92146039b21fc6ef7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/4007bed662ec7349eb8fd5e92146039b21fc6ef7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +desc 'Create YAML test fixtures from data in an existing database. +Defaults to development database. Set RAILS_ENV to override.' + +task :extract_fixtures => :environment do + sql = "SELECT * FROM %s" + skip_tables = ["schema_info"] + ActiveRecord::Base.establish_connection + (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| + i = "000" + File.open("#{Rails.root}/#{table_name}.yml", 'w' ) do |file| + data = ActiveRecord::Base.connection.select_all(sql % table_name) + file.write data.inject({}) { |hash, record| + # cast extracted values + ActiveRecord::Base.connection.columns(table_name).each { |col| + record[col.name] = col.type_cast(record[col.name]) if record[col.name] + } + hash["#{table_name}_#{i.succ!}"] = record + hash + }.to_yaml + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/4020a77b0d5d691da1ac32e725f8f600aff372b8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/4020a77b0d5d691da1ac32e725f8f600aff372b8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +

<%= class_name %>#<%= action %>

diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/402e1312cdbd9af078770d5f5cfd423f76b8df78.svn-base Binary file .svn/pristine/40/402e1312cdbd9af078770d5f5cfd423f76b8df78.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/4038e83eefe53cf4e2ba6b2f10fddf413b1d2edb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/4038e83eefe53cf4e2ba6b2f10fddf413b1d2edb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar GL (galician) language +// Author: Martín Vázquez Cabanas, +// Updated: 2009-01-23 +// Encoding: utf-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Luns", + "Martes", + "Mércores", + "Xoves", + "Venres", + "Sábado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Lun", + "Mar", + "Mér", + "Xov", + "Ven", + "Sáb", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Xaneiro", + "Febreiro", + "Marzo", + "Abril", + "Maio", + "Xuño", + "Xullo", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Decembro"); + +// short month names +Calendar._SMN = new Array +("Xan", + "Feb", + "Mar", + "Abr", + "Mai", + "Xun", + "Xull", + "Ago", + "Set", + "Out", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Acerca do calendario"; + +Calendar._TT["ABOUT"] = +"Selector DHTML de Data/Hora\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Para conseguila última versión visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuído baixo licenza GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para máis detalles." + +"\n\n" + +"Selección de data:\n" + +"- Use os botóns \xab, \xbb para seleccionalo ano\n" + +"- Use os botóns " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionalo mes\n" + +"- Manteña pulsado o rato en calquera destes botóns para unha selección rápida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selección de hora:\n" + +"- Pulse en calquera das partes da hora para incrementala\n" + +"- ou pulse maiúsculas mentres fai clic para decrementala\n" + +"- ou faga clic e arrastre o rato para unha selección máis rápida."; + +Calendar._TT["PREV_YEAR"] = "Ano anterior (manter para menú)"; +Calendar._TT["PREV_MONTH"] = "Mes anterior (manter para menú)"; +Calendar._TT["GO_TODAY"] = "Ir a hoxe"; +Calendar._TT["NEXT_MONTH"] = "Mes seguinte (manter para menú)"; +Calendar._TT["NEXT_YEAR"] = "Ano seguinte (manter para menú)"; +Calendar._TT["SEL_DATE"] = "Seleccionar data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar para mover"; +Calendar._TT["PART_TODAY"] = " (hoxe)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Facer %s primeiro día da semana"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Pechar"; +Calendar._TT["TODAY"] = "Hoxe"; +Calendar._TT["TIME_PART"] = "(Maiúscula-)Clic ou arrastre para cambiar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; + +Calendar._TT["WK"] = "sem"; +Calendar._TT["TIME"] = "Hora:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/406f7b24c26c10e7c0b7a7dfc884f38ff3b10cd2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/406f7b24c26c10e7c0b7a7dfc884f38ff3b10cd2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,383 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'SVG/Graph/Bar' +require 'SVG/Graph/BarHorizontal' +require 'digest/sha1' + +class ChangesetNotFound < Exception; end +class InvalidRevisionParam < Exception; end + +class RepositoriesController < ApplicationController + menu_item :repository + menu_item :settings, :only => :edit + default_search_scope :changesets + + before_filter :find_repository, :except => :edit + before_filter :find_project, :only => :edit + before_filter :authorize + accept_rss_auth :revisions + + rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed + + def edit + @repository = @project.repository + if !@repository && !params[:repository_scm].blank? + @repository = Repository.factory(params[:repository_scm]) + @repository.project = @project if @repository + end + if request.post? && @repository + p1 = params[:repository] + p = {} + p_extra = {} + p1.each do |k, v| + if k =~ /^extra_/ + p_extra[k] = v + else + p[k] = v + end + end + @repository.attributes = p + @repository.merge_extra_info(p_extra) + @repository.save + end + render(:update) do |page| + page.replace_html "tab-content-repository", + :partial => 'projects/settings/repository' + if @repository && !@project.repository + @project.reload # needed to reload association + page.replace_html "main-menu", render_main_menu(@project) + end + end + end + + def committers + @committers = @repository.committers + @users = @project.users + additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) + @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty? + @users.compact! + @users.sort! + if request.post? && params[:committers].is_a?(Hash) + # Build a hash with repository usernames as keys and corresponding user ids as values + @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h} + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'committers', :id => @project + end + end + + def destroy + @repository.destroy + redirect_to :controller => 'projects', + :action => 'settings', + :id => @project, + :tab => 'repository' + end + + def show + @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty? + + @entries = @repository.entries(@path, @rev) + @changeset = @repository.find_changeset_by_name(@rev) + if request.xhr? + @entries ? render(:partial => 'dir_list_content') : render(:nothing => true) + else + (show_error_not_found; return) unless @entries + @changesets = @repository.latest_changesets(@path, @rev) + @properties = @repository.properties(@path, @rev) + render :action => 'show' + end + end + + alias_method :browse, :show + + def changes + @entry = @repository.entry(@path, @rev) + (show_error_not_found; return) unless @entry + @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i) + @properties = @repository.properties(@path, @rev) + @changeset = @repository.find_changeset_by_name(@rev) + end + + def revisions + @changeset_count = @repository.changesets.count + @changeset_pages = Paginator.new self, @changeset_count, + per_page_option, + params['page'] + @changesets = @repository.changesets.find(:all, + :limit => @changeset_pages.items_per_page, + :offset => @changeset_pages.current.offset, + :include => [:user, :repository, :parents]) + + respond_to do |format| + format.html { render :layout => false if request.xhr? } + format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") } + end + end + + def entry + @entry = @repository.entry(@path, @rev) + (show_error_not_found; return) unless @entry + + # If the entry is a dir, show the browser + (show; return) if @entry.is_dir? + + @content = @repository.cat(@path, @rev) + (show_error_not_found; return) unless @content + if 'raw' == params[:format] || + (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) || + ! is_entry_text_data?(@content, @path) + # Force the download + send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) } + send_type = Redmine::MimeType.of(@path) + send_opt[:type] = send_type.to_s if send_type + send_data @content, send_opt + else + # Prevent empty lines when displaying a file with Windows style eol + # TODO: UTF-16 + # Is this needs? AttachmentsController reads file simply. + @content.gsub!("\r\n", "\n") + @changeset = @repository.find_changeset_by_name(@rev) + end + end + + def is_entry_text_data?(ent, path) + # UTF-16 contains "\x00". + # It is very strict that file contains less than 30% of ascii symbols + # in non Western Europe. + return true if Redmine::MimeType.is_type?('text', path) + # Ruby 1.8.6 has a bug of integer divisions. + # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F + return false if ent.is_binary_data? + true + end + private :is_entry_text_data? + + def annotate + @entry = @repository.entry(@path, @rev) + (show_error_not_found; return) unless @entry + + @annotate = @repository.scm.annotate(@path, @rev) + if @annotate.nil? || @annotate.empty? + (render_error l(:error_scm_annotate); return) + end + ann_buf_size = 0 + @annotate.lines.each do |buf| + ann_buf_size += buf.size + end + if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte + (render_error l(:error_scm_annotate_big_text_file); return) + end + @changeset = @repository.find_changeset_by_name(@rev) + end + + def revision + raise ChangesetNotFound if @rev.blank? + @changeset = @repository.find_changeset_by_name(@rev) + raise ChangesetNotFound unless @changeset + + respond_to do |format| + format.html + format.js {render :layout => false} + end + rescue ChangesetNotFound + show_error_not_found + end + + def diff + if params[:format] == 'diff' + @diff = @repository.diff(@path, @rev, @rev_to) + (show_error_not_found; return) unless @diff + filename = "changeset_r#{@rev}" + filename << "_r#{@rev_to}" if @rev_to + send_data @diff.join, :filename => "#{filename}.diff", + :type => 'text/x-patch', + :disposition => 'attachment' + else + @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' + @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) + + # Save diff type as user preference + if User.current.logged? && @diff_type != User.current.pref[:diff_type] + User.current.pref[:diff_type] = @diff_type + User.current.preference.save + end + @cache_key = "repositories/diff/#{@repository.id}/" + + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}") + unless read_fragment(@cache_key) + @diff = @repository.diff(@path, @rev, @rev_to) + show_error_not_found unless @diff + end + + @changeset = @repository.find_changeset_by_name(@rev) + @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil + @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to) + end + end + + def stats + end + + def graph + data = nil + case params[:graph] + when "commits_per_month" + data = graph_commits_per_month(@repository) + when "commits_per_author" + data = graph_commits_per_author(@repository) + end + if data + headers["Content-Type"] = "image/svg+xml" + send_data(data, :type => "image/svg+xml", :disposition => "inline") + else + render_404 + end + end + + private + + REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i + + def find_repository + @project = Project.find(params[:id]) + @repository = @project.repository + (render_404; return false) unless @repository + @path = params[:path].join('/') unless params[:path].nil? + @path ||= '' + @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip + @rev_to = params[:rev_to] + + unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE) + if @repository.branches.blank? + raise InvalidRevisionParam + end + end + rescue ActiveRecord::RecordNotFound + render_404 + rescue InvalidRevisionParam + show_error_not_found + end + + def show_error_not_found + render_error :message => l(:error_scm_not_found), :status => 404 + end + + # Handler for Redmine::Scm::Adapters::CommandFailed exception + def show_error_command_failed(exception) + render_error l(:error_scm_command_failed, exception.message) + end + + def graph_commits_per_month(repository) + @date_to = Date.today + @date_from = @date_to << 11 + @date_from = Date.civil(@date_from.year, @date_from.month, 1) + commits_by_day = repository.changesets.count( + :all, :group => :commit_date, + :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to]) + commits_by_month = [0] * 12 + commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last } + + changes_by_day = repository.changes.count( + :all, :group => :commit_date, + :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to]) + changes_by_month = [0] * 12 + changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last } + + fields = [] + 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)} + + graph = SVG::Graph::Bar.new( + :height => 300, + :width => 800, + :fields => fields.reverse, + :stack => :side, + :scale_integers => true, + :step_x_labels => 2, + :show_data_values => false, + :graph_title => l(:label_commits_per_month), + :show_graph_title => true + ) + + graph.add_data( + :data => commits_by_month[0..11].reverse, + :title => l(:label_revision_plural) + ) + + graph.add_data( + :data => changes_by_month[0..11].reverse, + :title => l(:label_change_plural) + ) + + graph.burn + end + + def graph_commits_per_author(repository) + commits_by_author = repository.changesets.count(:all, :group => :committer) + commits_by_author.to_a.sort! {|x, y| x.last <=> y.last} + + changes_by_author = repository.changes.count(:all, :group => :committer) + h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o} + + fields = commits_by_author.collect {|r| r.first} + commits_data = commits_by_author.collect {|r| r.last} + changes_data = commits_by_author.collect {|r| h[r.first] || 0} + + fields = fields + [""]*(10 - fields.length) if fields.length<10 + commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 + changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10 + + # Remove email adress in usernames + fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } + + graph = SVG::Graph::BarHorizontal.new( + :height => 400, + :width => 800, + :fields => fields, + :stack => :side, + :scale_integers => true, + :show_data_values => false, + :rotate_y_labels => false, + :graph_title => l(:label_commits_per_author), + :show_graph_title => true + ) + graph.add_data( + :data => commits_data, + :title => l(:label_revision_plural) + ) + graph.add_data( + :data => changes_data, + :title => l(:label_change_plural) + ) + graph.burn + end +end + +class Date + def months_ago(date = Date.today) + (date.year - self.year)*12 + (date.month - self.month) + end + + def weeks_ago(date = Date.today) + (date.year - self.year)*52 + (date.cweek - self.cweek) + end +end + +class String + def with_leading_slash + starts_with?('/') ? self : "/#{self}" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/40c4039ba9e47d815cba1a52d74f9e4a95251920.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/40c4039ba9e47d815cba1a52d74f9e4a95251920.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class RemoveProjectsProjectsCount < ActiveRecord::Migration + def self.up + remove_column :projects, :projects_count + end + + def self.down + add_column :projects, :projects_count, :integer, :default => 0 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/40d857531cd6b4668cb1e019211d87ead6d54850.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/40d857531cd6b4668cb1e019211d87ead6d54850.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +require 'test/unit' + +$VERBOSE = $CODERAY_DEBUG = true +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +mydir = File.dirname(__FILE__) +suite = Dir[File.join(mydir, '*.rb')]. + map { |tc| File.basename(tc).sub(/\.rb$/, '') } - %w'suite for_redcloth' + +puts "Running basic CodeRay #{CodeRay::VERSION} tests: #{suite.join(', ')}" + +for test_case in suite + load File.join(mydir, test_case + '.rb') +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/40/40fb7c915312a0bec722da5f4b2c6582d58a02b9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/40/40fb7c915312a0bec722da5f4b2c6582d58a02b9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,174 @@ +require 'active_support' +require File.join(File.dirname(__FILE__), 'engines/plugin') +require File.join(File.dirname(__FILE__), 'engines/plugin/list') +require File.join(File.dirname(__FILE__), 'engines/plugin/loader') +require File.join(File.dirname(__FILE__), 'engines/plugin/locator') +require File.join(File.dirname(__FILE__), 'engines/assets') +require File.join(File.dirname(__FILE__), 'engines/rails_extensions/rails') + +# == Parameters +# +# The Engines module has a number of public configuration parameters: +# +# [+public_directory+] The directory into which plugin assets should be +# mirrored. Defaults to RAILS_ROOT/public/plugin_assets. +# [+schema_info_table+] The table to use when storing plugin migration +# version information. Defaults to +plugin_schema_info+. +# +# Additionally, there are a few flags which control the behaviour of +# some of the features the engines plugin adds to Rails: +# +# [+disable_application_view_loading+] A boolean flag determining whether +# or not views should be loaded from +# the main app/views directory. +# Defaults to false; probably only +# useful when testing your plugin. +# [+disable_application_code_loading+] A boolean flag determining whether +# or not to load controllers/helpers +# from the main +app+ directory, +# if corresponding code exists within +# a plugin. Defaults to false; again, +# probably only useful when testing +# your plugin. +# [+disable_code_mixing+] A boolean flag indicating whether all plugin +# copies of a particular controller/helper should +# be loaded and allowed to override each other, +# or if the first matching file should be loaded +# instead. Defaults to false. +# +module Engines + # The set of all loaded plugins + mattr_accessor :plugins + self.plugins = Engines::Plugin::List.new + + # List of extensions to load, can be changed in init.rb before calling Engines.init + mattr_accessor :rails_extensions + self.rails_extensions = %w(asset_helpers form_tag_helpers migrations dependencies) + + # The name of the public directory to mirror public engine assets into. + # Defaults to RAILS_ROOT/public/plugin_assets. + mattr_accessor :public_directory + self.public_directory = File.join(RAILS_ROOT, 'public', 'plugin_assets') + + # The table in which to store plugin schema information. Defaults to + # "plugin_schema_info". + mattr_accessor :schema_info_table + self.schema_info_table = "plugin_schema_info" + + #-- + # These attributes control the behaviour of the engines extensions + #++ + + # Set this to true if views should *only* be loaded from plugins + mattr_accessor :disable_application_view_loading + self.disable_application_view_loading = false + + # Set this to true if controller/helper code shouldn't be loaded + # from the application + mattr_accessor :disable_application_code_loading + self.disable_application_code_loading = false + + # Set this to true if code should not be mixed (i.e. it will be loaded + # from the first valid path on $LOAD_PATH) + mattr_accessor :disable_code_mixing + self.disable_code_mixing = false + + # This is used to determine which files are candidates for the "code + # mixing" feature that the engines plugin provides, where classes from + # plugins can be loaded, and then code from the application loaded + # on top of that code to override certain methods. + mattr_accessor :code_mixing_file_types + self.code_mixing_file_types = %w(controller helper) + + class << self + def init(initializer) + load_extensions + Engines::Assets.initialize_base_public_directory + end + + def logger + RAILS_DEFAULT_LOGGER + end + + def load_extensions + rails_extensions.each { |name| require "engines/rails_extensions/#{name}" } + # load the testing extensions, if we are in the test environment. + require "engines/testing" if RAILS_ENV == "test" + end + + def select_existing_paths(paths) + paths.select { |path| File.directory?(path) } + end + + # The engines plugin will, by default, mix code from controllers and helpers, + # allowing application code to override specific methods in the corresponding + # controller or helper classes and modules. However, if other file types should + # also be mixed like this, they can be added by calling this method. For example, + # if you want to include "things" within your plugin and override them from + # your applications, you should use the following layout: + # + # app/ + # +-- things/ + # | +-- one_thing.rb + # | +-- another_thing.rb + # ... + # vendor/ + # +-- plugins/ + # +-- my_plugin/ + # +-- app/ + # +-- things/ + # +-- one_thing.rb + # +-- another_thing.rb + # + # The important point here is that your "things" are named _thing.rb, + # and that they are placed within plugin/app/things (the pluralized form of 'thing'). + # + # It's important to note that you'll also want to ensure that the "things" are + # on your load path by including them in Rails load path mechanism, e.g. in init.rb: + # + # ActiveSupport::Dependencies.load_paths << File.join(File.dirname(__FILE__), 'app', 'things')) + # + def mix_code_from(*types) + self.code_mixing_file_types += types.map { |x| x.to_s.singularize } + end + + # A general purpose method to mirror a directory (+source+) into a destination + # directory, including all files and subdirectories. Files will not be mirrored + # if they are identical already (checked via FileUtils#identical?). + def mirror_files_from(source, destination) + return unless File.directory?(source) + + # TODO: use Rake::FileList#pathmap? + source_files = Dir[source + "/**/*"] + source_dirs = source_files.select { |d| File.directory?(d) } + source_files -= source_dirs + + unless source_files.empty? + base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, '')) + FileUtils.mkdir_p(base_target_dir) + end + + source_dirs.each do |dir| + # strip down these paths so we have simple, relative paths we can + # add to the destination + target_dir = File.join(destination, dir.gsub(source, '')) + begin + FileUtils.mkdir_p(target_dir) + rescue Exception => e + raise "Could not create directory #{target_dir}: \n" + e + end + end + + source_files.each do |file| + begin + target = File.join(destination, file.gsub(source, '')) + unless File.exist?(target) && FileUtils.identical?(file, target) + FileUtils.cp(file, target) + end + rescue Exception => e + raise "Could not copy #{file} to #{target}: \n" + e + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/41/413080d862dfb1417751d3ce6800014b0d3f9e36.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/41/413080d862dfb1417751d3ce6800014b0d3f9e36.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class JournalObserverTest < ActiveSupport::TestCase + fixtures :issues, :issue_statuses, :journals, :journal_details + + def setup + ActionMailer::Base.deliveries.clear + @journal = Journal.find 1 + end + + # context: issue_updated notified_events + def test_create_should_send_email_notification_with_issue_updated + Setting.notified_events = ['issue_updated'] + issue = Issue.find(:first) + user = User.find(:first) + journal = issue.init_journal(user, issue) + + assert journal.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_create_should_not_send_email_notification_with_notify_set_to_false + Setting.notified_events = ['issue_updated'] + issue = Issue.find(:first) + user = User.find(:first) + journal = issue.init_journal(user, issue) + journal.notify = false + + assert journal.save + assert_equal 0, ActionMailer::Base.deliveries.size + end + + def test_create_should_not_send_email_notification_without_issue_updated + Setting.notified_events = [] + issue = Issue.find(:first) + user = User.find(:first) + journal = issue.init_journal(user, issue) + + assert journal.save + assert_equal 0, ActionMailer::Base.deliveries.size + end + + # context: issue_note_added notified_events + def test_create_should_send_email_notification_with_issue_note_added + Setting.notified_events = ['issue_note_added'] + issue = Issue.find(:first) + user = User.find(:first) + journal = issue.init_journal(user, issue) + journal.notes = 'This update has a note' + + assert journal.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_create_should_not_send_email_notification_without_issue_note_added + Setting.notified_events = [] + issue = Issue.find(:first) + user = User.find(:first) + journal = issue.init_journal(user, issue) + journal.notes = 'This update has a note' + + assert journal.save + assert_equal 0, ActionMailer::Base.deliveries.size + end + + # context: issue_status_updated notified_events + def test_create_should_send_email_notification_with_issue_status_updated + Setting.notified_events = ['issue_status_updated'] + issue = Issue.find(:first) + user = User.find(:first) + issue.init_journal(user, issue) + issue.status = IssueStatus.last + + assert issue.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_create_should_not_send_email_notification_without_issue_status_updated + Setting.notified_events = [] + issue = Issue.find(:first) + user = User.find(:first) + issue.init_journal(user, issue) + issue.status = IssueStatus.last + + assert issue.save + assert_equal 0, ActionMailer::Base.deliveries.size + end + + # context: issue_priority_updated notified_events + def test_create_should_send_email_notification_with_issue_priority_updated + Setting.notified_events = ['issue_priority_updated'] + issue = Issue.find(:first) + user = User.find(:first) + issue.init_journal(user, issue) + issue.priority = IssuePriority.last + + assert issue.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_create_should_not_send_email_notification_without_issue_priority_updated + Setting.notified_events = [] + issue = Issue.find(:first) + user = User.find(:first) + issue.init_journal(user, issue) + issue.priority = IssuePriority.last + + assert issue.save + assert_equal 0, ActionMailer::Base.deliveries.size + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/41/41dbe19704933be68922a961147886290a8f9c62.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/41/41dbe19704933be68922a961147886290a8f9c62.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1148 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class ProjectTest < ActiveSupport::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :groups_users, + :boards + + def setup + @ecookbook = Project.find(1) + @ecookbook_sub1 = Project.find(3) + User.current = nil + end + + should_validate_presence_of :name + should_validate_presence_of :identifier + + should_validate_uniqueness_of :identifier + + context "associations" do + should_have_many :members + should_have_many :users, :through => :members + should_have_many :member_principals + should_have_many :principals, :through => :member_principals + should_have_many :enabled_modules + should_have_many :issues + should_have_many :issue_changes, :through => :issues + should_have_many :versions + should_have_many :time_entries + should_have_many :queries + should_have_many :documents + should_have_many :news + should_have_many :issue_categories + should_have_many :boards + should_have_many :changesets, :through => :repository + + should_have_one :repository + should_have_one :wiki + + should_have_and_belong_to_many :trackers + should_have_and_belong_to_many :issue_custom_fields + end + + def test_truth + assert_kind_of Project, @ecookbook + assert_equal "eCookbook", @ecookbook.name + end + + def test_default_attributes + with_settings :default_projects_public => '1' do + assert_equal true, Project.new.is_public + assert_equal false, Project.new(:is_public => false).is_public + end + + with_settings :default_projects_public => '0' do + assert_equal false, Project.new.is_public + assert_equal true, Project.new(:is_public => true).is_public + end + + with_settings :sequential_project_identifiers => '1' do + assert !Project.new.identifier.blank? + assert Project.new(:identifier => '').identifier.blank? + end + + with_settings :sequential_project_identifiers => '0' do + assert Project.new.identifier.blank? + assert !Project.new(:identifier => 'test').blank? + end + + with_settings :default_projects_modules => ['issue_tracking', 'repository'] do + assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names + end + + assert_equal Tracker.all, Project.new.trackers + assert_equal Tracker.find(1, 3), Project.new(:tracker_ids => [1, 3]).trackers + end + + def test_update + assert_equal "eCookbook", @ecookbook.name + @ecookbook.name = "eCook" + assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ") + @ecookbook.reload + assert_equal "eCook", @ecookbook.name + end + + def test_validate_identifier + to_test = {"abc" => true, + "ab12" => true, + "ab-12" => true, + "12" => false, + "new" => false} + + to_test.each do |identifier, valid| + p = Project.new + p.identifier = identifier + p.valid? + assert_equal valid, p.errors['identifier'].nil? + end + end + + def test_members_should_be_active_users + Project.all.each do |project| + assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) } + end + end + + def test_users_should_be_active_users + Project.all.each do |project| + assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) } + end + end + + def test_archive + user = @ecookbook.members.first.user + @ecookbook.archive + @ecookbook.reload + + assert !@ecookbook.active? + assert @ecookbook.archived? + assert !user.projects.include?(@ecookbook) + # Subproject are also archived + assert !@ecookbook.children.empty? + assert @ecookbook.descendants.active.empty? + end + + def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects + # Assign an issue of a project to a version of a child project + Issue.find(4).update_attribute :fixed_version_id, 4 + + assert_no_difference "Project.count(:all, :conditions => 'status = #{Project::STATUS_ARCHIVED}')" do + assert_equal false, @ecookbook.archive + end + @ecookbook.reload + assert @ecookbook.active? + end + + def test_unarchive + user = @ecookbook.members.first.user + @ecookbook.archive + # A subproject of an archived project can not be unarchived + assert !@ecookbook_sub1.unarchive + + # Unarchive project + assert @ecookbook.unarchive + @ecookbook.reload + assert @ecookbook.active? + assert !@ecookbook.archived? + assert user.projects.include?(@ecookbook) + # Subproject can now be unarchived + @ecookbook_sub1.reload + assert @ecookbook_sub1.unarchive + end + + def test_destroy + # 2 active members + assert_equal 2, @ecookbook.members.size + # and 1 is locked + assert_equal 3, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size + # some boards + assert @ecookbook.boards.any? + + @ecookbook.destroy + # make sure that the project non longer exists + assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) } + # make sure related data was removed + assert_nil Member.first(:conditions => {:project_id => @ecookbook.id}) + assert_nil Board.first(:conditions => {:project_id => @ecookbook.id}) + assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id}) + end + + def test_destroying_root_projects_should_clear_data + Project.roots.each do |root| + root.destroy + end + + assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}" + assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}" + assert_equal 0, MemberRole.count + assert_equal 0, Issue.count + assert_equal 0, Journal.count + assert_equal 0, JournalDetail.count + assert_equal 0, Attachment.count + assert_equal 0, EnabledModule.count + assert_equal 0, IssueCategory.count + assert_equal 0, IssueRelation.count + assert_equal 0, Board.count + assert_equal 0, Message.count + assert_equal 0, News.count + assert_equal 0, Query.count(:conditions => "project_id IS NOT NULL") + assert_equal 0, Repository.count + assert_equal 0, Changeset.count + assert_equal 0, Change.count + assert_equal 0, Comment.count + assert_equal 0, TimeEntry.count + assert_equal 0, Version.count + assert_equal 0, Watcher.count + assert_equal 0, Wiki.count + assert_equal 0, WikiPage.count + assert_equal 0, WikiContent.count + assert_equal 0, WikiContent::Version.count + assert_equal 0, Project.connection.select_all("SELECT * FROM projects_trackers").size + assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").size + assert_equal 0, CustomValue.count(:conditions => {:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']}) + end + + def test_move_an_orphan_project_to_a_root_project + sub = Project.find(2) + sub.set_parent! @ecookbook + assert_equal @ecookbook.id, sub.parent.id + @ecookbook.reload + assert_equal 4, @ecookbook.children.size + end + + def test_move_an_orphan_project_to_a_subproject + sub = Project.find(2) + assert sub.set_parent!(@ecookbook_sub1) + end + + def test_move_a_root_project_to_a_project + sub = @ecookbook + assert sub.set_parent!(Project.find(2)) + end + + def test_should_not_move_a_project_to_its_children + sub = @ecookbook + assert !(sub.set_parent!(Project.find(3))) + end + + def test_set_parent_should_add_roots_in_alphabetical_order + ProjectCustomField.delete_all + Project.delete_all + Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(nil) + Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil) + Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil) + Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil) + + assert_equal 4, Project.count + assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft) + end + + def test_set_parent_should_add_children_in_alphabetical_order + ProjectCustomField.delete_all + parent = Project.create!(:name => 'Parent', :identifier => 'parent') + Project.create!(:name => 'Project C', :identifier => 'project-c').set_parent!(parent) + Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent) + Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent) + Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent) + + parent.reload + assert_equal 4, parent.children.size + assert_equal parent.children.sort_by(&:name), parent.children + end + + def test_rebuild_should_sort_children_alphabetically + ProjectCustomField.delete_all + parent = Project.create!(:name => 'Parent', :identifier => 'parent') + Project.create!(:name => 'Project C', :identifier => 'project-c').move_to_child_of(parent) + Project.create!(:name => 'Project B', :identifier => 'project-b').move_to_child_of(parent) + Project.create!(:name => 'Project D', :identifier => 'project-d').move_to_child_of(parent) + Project.create!(:name => 'Project A', :identifier => 'project-a').move_to_child_of(parent) + + Project.update_all("lft = NULL, rgt = NULL") + Project.rebuild! + + parent.reload + assert_equal 4, parent.children.size + assert_equal parent.children.sort_by(&:name), parent.children + end + + + def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy + # Parent issue with a hierarchy project's fixed version + parent_issue = Issue.find(1) + parent_issue.update_attribute(:fixed_version_id, 4) + parent_issue.reload + assert_equal 4, parent_issue.fixed_version_id + + # Should keep fixed versions for the issues + issue_with_local_fixed_version = Issue.find(5) + issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4) + issue_with_local_fixed_version.reload + assert_equal 4, issue_with_local_fixed_version.fixed_version_id + + # Local issue with hierarchy fixed_version + issue_with_hierarchy_fixed_version = Issue.find(13) + issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6) + issue_with_hierarchy_fixed_version.reload + assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id + + # Move project out of the issue's hierarchy + moved_project = Project.find(3) + moved_project.set_parent!(Project.find(2)) + parent_issue.reload + issue_with_local_fixed_version.reload + issue_with_hierarchy_fixed_version.reload + + assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project" + assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in" + assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue." + end + + def test_parent + p = Project.find(6).parent + assert p.is_a?(Project) + assert_equal 5, p.id + end + + def test_ancestors + a = Project.find(6).ancestors + assert a.first.is_a?(Project) + assert_equal [1, 5], a.collect(&:id) + end + + def test_root + r = Project.find(6).root + assert r.is_a?(Project) + assert_equal 1, r.id + end + + def test_children + c = Project.find(1).children + assert c.first.is_a?(Project) + assert_equal [5, 3, 4], c.collect(&:id) + end + + def test_descendants + d = Project.find(1).descendants + assert d.first.is_a?(Project) + assert_equal [5, 6, 3, 4], d.collect(&:id) + end + + def test_allowed_parents_should_be_empty_for_non_member_user + Role.non_member.add_permission!(:add_project) + user = User.find(9) + assert user.memberships.empty? + User.current = user + assert Project.new.allowed_parents.compact.empty? + end + + def test_allowed_parents_with_add_subprojects_permission + Role.find(1).remove_permission!(:add_project) + Role.find(1).add_permission!(:add_subprojects) + User.current = User.find(2) + # new project + assert !Project.new.allowed_parents.include?(nil) + assert Project.new.allowed_parents.include?(Project.find(1)) + # existing root project + assert Project.find(1).allowed_parents.include?(nil) + # existing child + assert Project.find(3).allowed_parents.include?(Project.find(1)) + assert !Project.find(3).allowed_parents.include?(nil) + end + + def test_allowed_parents_with_add_project_permission + Role.find(1).add_permission!(:add_project) + Role.find(1).remove_permission!(:add_subprojects) + User.current = User.find(2) + # new project + assert Project.new.allowed_parents.include?(nil) + assert !Project.new.allowed_parents.include?(Project.find(1)) + # existing root project + assert Project.find(1).allowed_parents.include?(nil) + # existing child + assert Project.find(3).allowed_parents.include?(Project.find(1)) + assert Project.find(3).allowed_parents.include?(nil) + end + + def test_allowed_parents_with_add_project_and_subprojects_permission + Role.find(1).add_permission!(:add_project) + Role.find(1).add_permission!(:add_subprojects) + User.current = User.find(2) + # new project + assert Project.new.allowed_parents.include?(nil) + assert Project.new.allowed_parents.include?(Project.find(1)) + # existing root project + assert Project.find(1).allowed_parents.include?(nil) + # existing child + assert Project.find(3).allowed_parents.include?(Project.find(1)) + assert Project.find(3).allowed_parents.include?(nil) + end + + def test_users_by_role + users_by_role = Project.find(1).users_by_role + assert_kind_of Hash, users_by_role + role = Role.find(1) + assert_kind_of Array, users_by_role[role] + assert users_by_role[role].include?(User.find(2)) + end + + def test_rolled_up_trackers + parent = Project.find(1) + parent.trackers = Tracker.find([1,2]) + child = parent.children.find(3) + + assert_equal [1, 2], parent.tracker_ids + assert_equal [2, 3], child.trackers.collect(&:id) + + assert_kind_of Tracker, parent.rolled_up_trackers.first + assert_equal Tracker.find(1), parent.rolled_up_trackers.first + + assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id) + assert_equal [2, 3], child.rolled_up_trackers.collect(&:id) + end + + def test_rolled_up_trackers_should_ignore_archived_subprojects + parent = Project.find(1) + parent.trackers = Tracker.find([1,2]) + child = parent.children.find(3) + child.trackers = Tracker.find([1,3]) + parent.children.each(&:archive) + + assert_equal [1,2], parent.rolled_up_trackers.collect(&:id) + end + + context "#rolled_up_versions" do + setup do + @project = Project.generate! + @parent_version_1 = Version.generate!(:project => @project) + @parent_version_2 = Version.generate!(:project => @project) + end + + should "include the versions for the current project" do + assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions + end + + should "include versions for a subproject" do + @subproject = Project.generate! + @subproject.set_parent!(@project) + @subproject_version = Version.generate!(:project => @subproject) + + assert_same_elements [ + @parent_version_1, + @parent_version_2, + @subproject_version + ], @project.rolled_up_versions + end + + should "include versions for a sub-subproject" do + @subproject = Project.generate! + @subproject.set_parent!(@project) + @sub_subproject = Project.generate! + @sub_subproject.set_parent!(@subproject) + @sub_subproject_version = Version.generate!(:project => @sub_subproject) + + @project.reload + + assert_same_elements [ + @parent_version_1, + @parent_version_2, + @sub_subproject_version + ], @project.rolled_up_versions + end + + should "only check active projects" do + @subproject = Project.generate! + @subproject.set_parent!(@project) + @subproject_version = Version.generate!(:project => @subproject) + assert @subproject.archive + + @project.reload + + assert !@subproject.active? + assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions + end + end + + def test_shared_versions_none_sharing + p = Project.find(5) + v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none') + assert p.shared_versions.include?(v) + assert !p.children.first.shared_versions.include?(v) + assert !p.root.shared_versions.include?(v) + assert !p.siblings.first.shared_versions.include?(v) + assert !p.root.siblings.first.shared_versions.include?(v) + end + + def test_shared_versions_descendants_sharing + p = Project.find(5) + v = Version.create!(:name => 'descendants_sharing', :project => p, :sharing => 'descendants') + assert p.shared_versions.include?(v) + assert p.children.first.shared_versions.include?(v) + assert !p.root.shared_versions.include?(v) + assert !p.siblings.first.shared_versions.include?(v) + assert !p.root.siblings.first.shared_versions.include?(v) + end + + def test_shared_versions_hierarchy_sharing + p = Project.find(5) + v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy') + assert p.shared_versions.include?(v) + assert p.children.first.shared_versions.include?(v) + assert p.root.shared_versions.include?(v) + assert !p.siblings.first.shared_versions.include?(v) + assert !p.root.siblings.first.shared_versions.include?(v) + end + + def test_shared_versions_tree_sharing + p = Project.find(5) + v = Version.create!(:name => 'tree_sharing', :project => p, :sharing => 'tree') + assert p.shared_versions.include?(v) + assert p.children.first.shared_versions.include?(v) + assert p.root.shared_versions.include?(v) + assert p.siblings.first.shared_versions.include?(v) + assert !p.root.siblings.first.shared_versions.include?(v) + end + + def test_shared_versions_system_sharing + p = Project.find(5) + v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system') + assert p.shared_versions.include?(v) + assert p.children.first.shared_versions.include?(v) + assert p.root.shared_versions.include?(v) + assert p.siblings.first.shared_versions.include?(v) + assert p.root.siblings.first.shared_versions.include?(v) + end + + def test_shared_versions + parent = Project.find(1) + child = parent.children.find(3) + private_child = parent.children.find(5) + + assert_equal [1,2,3], parent.version_ids.sort + assert_equal [4], child.version_ids + assert_equal [6], private_child.version_ids + assert_equal [7], Version.find_all_by_sharing('system').collect(&:id) + + assert_equal 6, parent.shared_versions.size + parent.shared_versions.each do |version| + assert_kind_of Version, version + end + + assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort + end + + def test_shared_versions_should_ignore_archived_subprojects + parent = Project.find(1) + child = parent.children.find(3) + child.archive + parent.reload + + assert_equal [1,2,3], parent.version_ids.sort + assert_equal [4], child.version_ids + assert !parent.shared_versions.collect(&:id).include?(4) + end + + def test_shared_versions_visible_to_user + user = User.find(3) + parent = Project.find(1) + child = parent.children.find(5) + + assert_equal [1,2,3], parent.version_ids.sort + assert_equal [6], child.version_ids + + versions = parent.shared_versions.visible(user) + + assert_equal 4, versions.size + versions.each do |version| + assert_kind_of Version, version + end + + assert !versions.collect(&:id).include?(6) + end + + def test_next_identifier + ProjectCustomField.delete_all + Project.create!(:name => 'last', :identifier => 'p2008040') + assert_equal 'p2008041', Project.next_identifier + end + + def test_next_identifier_first_project + Project.delete_all + assert_nil Project.next_identifier + end + + def test_enabled_module_names + with_settings :default_projects_modules => ['issue_tracking', 'repository'] do + project = Project.new + + project.enabled_module_names = %w(issue_tracking news) + assert_equal %w(issue_tracking news), project.enabled_module_names.sort + end + end + + context "enabled_modules" do + setup do + @project = Project.find(1) + end + + should "define module by names and preserve ids" do + # Remove one module + modules = @project.enabled_modules.slice(0..-2) + assert modules.any? + assert_difference 'EnabledModule.count', -1 do + @project.enabled_module_names = modules.collect(&:name) + end + @project.reload + # Ids should be preserved + assert_equal @project.enabled_module_ids.sort, modules.collect(&:id).sort + end + + should "enable a module" do + @project.enabled_module_names = [] + @project.reload + assert_equal [], @project.enabled_module_names + #with string + @project.enable_module!("issue_tracking") + assert_equal ["issue_tracking"], @project.enabled_module_names + #with symbol + @project.enable_module!(:gantt) + assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names + #don't add a module twice + @project.enable_module!("issue_tracking") + assert_equal ["issue_tracking", "gantt"], @project.enabled_module_names + end + + should "disable a module" do + #with string + assert @project.enabled_module_names.include?("issue_tracking") + @project.disable_module!("issue_tracking") + assert ! @project.reload.enabled_module_names.include?("issue_tracking") + #with symbol + assert @project.enabled_module_names.include?("gantt") + @project.disable_module!(:gantt) + assert ! @project.reload.enabled_module_names.include?("gantt") + #with EnabledModule object + first_module = @project.enabled_modules.first + @project.disable_module!(first_module) + assert ! @project.reload.enabled_module_names.include?(first_module.name) + end + end + + def test_enabled_module_names_should_not_recreate_enabled_modules + project = Project.find(1) + # Remove one module + modules = project.enabled_modules.slice(0..-2) + assert modules.any? + assert_difference 'EnabledModule.count', -1 do + project.enabled_module_names = modules.collect(&:name) + end + project.reload + # Ids should be preserved + assert_equal project.enabled_module_ids.sort, modules.collect(&:id).sort + end + + def test_copy_from_existing_project + source_project = Project.find(1) + copied_project = Project.copy_from(1) + + assert copied_project + # Cleared attributes + assert copied_project.id.blank? + assert copied_project.name.blank? + assert copied_project.identifier.blank? + + # Duplicated attributes + assert_equal source_project.description, copied_project.description + assert_equal source_project.enabled_modules, copied_project.enabled_modules + assert_equal source_project.trackers, copied_project.trackers + + # Default attributes + assert_equal 1, copied_project.status + end + + def test_activities_should_use_the_system_activities + project = Project.find(1) + assert_equal project.activities, TimeEntryActivity.find(:all, :conditions => {:active => true} ) + end + + + def test_activities_should_use_the_project_specific_activities + project = Project.find(1) + overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project}) + assert overridden_activity.save! + + assert project.activities.include?(overridden_activity), "Project specific Activity not found" + end + + def test_activities_should_not_include_the_inactive_project_specific_activities + project = Project.find(1) + overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.find(:first), :active => false}) + assert overridden_activity.save! + + assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found" + end + + def test_activities_should_not_include_project_specific_activities_from_other_projects + project = Project.find(1) + overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)}) + assert overridden_activity.save! + + assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project" + end + + def test_activities_should_handle_nils + overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(1), :parent => TimeEntryActivity.find(:first)}) + TimeEntryActivity.delete_all + + # No activities + project = Project.find(1) + assert project.activities.empty? + + # No system, one overridden + assert overridden_activity.save! + project.reload + assert_equal [overridden_activity], project.activities + end + + def test_activities_should_override_system_activities_with_project_activities + project = Project.find(1) + parent_activity = TimeEntryActivity.find(:first) + overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity}) + assert overridden_activity.save! + + assert project.activities.include?(overridden_activity), "Project specific Activity not found" + assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden" + end + + def test_activities_should_include_inactive_activities_if_specified + project = Project.find(1) + overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.find(:first), :active => false}) + assert overridden_activity.save! + + assert project.activities(true).include?(overridden_activity), "Inactive Project specific Activity not found" + end + + test 'activities should not include active System activities if the project has an override that is inactive' do + project = Project.find(1) + system_activity = TimeEntryActivity.find_by_name('Design') + assert system_activity.active? + overridden_activity = TimeEntryActivity.generate!(:project => project, :parent => system_activity, :active => false) + assert overridden_activity.save! + + assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found" + assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override" + end + + def test_close_completed_versions + Version.update_all("status = 'open'") + project = Project.find(1) + assert_not_nil project.versions.detect {|v| v.completed? && v.status == 'open'} + assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'} + project.close_completed_versions + project.reload + assert_nil project.versions.detect {|v| v.completed? && v.status != 'closed'} + assert_not_nil project.versions.detect {|v| !v.completed? && v.status == 'open'} + end + + context "Project#copy" do + setup do + ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests + Project.destroy_all :identifier => "copy-test" + @source_project = Project.find(2) + @project = Project.new(:name => 'Copy Test', :identifier => 'copy-test') + @project.trackers = @source_project.trackers + @project.enabled_module_names = @source_project.enabled_modules.collect(&:name) + end + + should "copy issues" do + @source_project.issues << Issue.generate!(:status => IssueStatus.find_by_name('Closed'), + :subject => "copy issue status", + :tracker_id => 1, + :assigned_to_id => 2, + :project_id => @source_project.id) + assert @project.valid? + assert @project.issues.empty? + assert @project.copy(@source_project) + + assert_equal @source_project.issues.size, @project.issues.size + @project.issues.each do |issue| + assert issue.valid? + assert ! issue.assigned_to.blank? + assert_equal @project, issue.project + end + + copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"}) + assert copied_issue + assert copied_issue.status + assert_equal "Closed", copied_issue.status.name + end + + should "change the new issues to use the copied version" do + User.current = User.find(1) + assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open') + @source_project.versions << assigned_version + assert_equal 3, @source_project.versions.size + Issue.generate_for_project!(@source_project, + :fixed_version_id => assigned_version.id, + :subject => "change the new issues to use the copied version", + :tracker_id => 1, + :project_id => @source_project.id) + + assert @project.copy(@source_project) + @project.reload + copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"}) + + assert copied_issue + assert copied_issue.fixed_version + assert_equal "Assigned Issues", copied_issue.fixed_version.name # Same name + assert_not_equal assigned_version.id, copied_issue.fixed_version.id # Different record + end + + should "copy issue relations" do + Setting.cross_project_issue_relations = '1' + + second_issue = Issue.generate!(:status_id => 5, + :subject => "copy issue relation", + :tracker_id => 1, + :assigned_to_id => 2, + :project_id => @source_project.id) + source_relation = IssueRelation.generate!(:issue_from => Issue.find(4), + :issue_to => second_issue, + :relation_type => "relates") + source_relation_cross_project = IssueRelation.generate!(:issue_from => Issue.find(1), + :issue_to => second_issue, + :relation_type => "duplicates") + + assert @project.copy(@source_project) + assert_equal @source_project.issues.count, @project.issues.count + copied_issue = @project.issues.find_by_subject("Issue on project 2") # Was #4 + copied_second_issue = @project.issues.find_by_subject("copy issue relation") + + # First issue with a relation on project + assert_equal 1, copied_issue.relations.size, "Relation not copied" + copied_relation = copied_issue.relations.first + assert_equal "relates", copied_relation.relation_type + assert_equal copied_second_issue.id, copied_relation.issue_to_id + assert_not_equal source_relation.id, copied_relation.id + + # Second issue with a cross project relation + assert_equal 2, copied_second_issue.relations.size, "Relation not copied" + copied_relation = copied_second_issue.relations.select {|r| r.relation_type == 'duplicates'}.first + assert_equal "duplicates", copied_relation.relation_type + assert_equal 1, copied_relation.issue_from_id, "Cross project relation not kept" + assert_not_equal source_relation_cross_project.id, copied_relation.id + end + + should "copy memberships" do + assert @project.valid? + assert @project.members.empty? + assert @project.copy(@source_project) + + assert_equal @source_project.memberships.size, @project.memberships.size + @project.memberships.each do |membership| + assert membership + assert_equal @project, membership.project + end + end + + should "copy memberships with groups and additional roles" do + group = Group.create!(:lastname => "Copy group") + user = User.find(7) + group.users << user + # group role + Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2]) + member = Member.find_by_user_id_and_project_id(user.id, @source_project.id) + # additional role + member.role_ids = [1] + + assert @project.copy(@source_project) + member = Member.find_by_user_id_and_project_id(user.id, @project.id) + assert_not_nil member + assert_equal [1, 2], member.role_ids.sort + end + + should "copy project specific queries" do + assert @project.valid? + assert @project.queries.empty? + assert @project.copy(@source_project) + + assert_equal @source_project.queries.size, @project.queries.size + @project.queries.each do |query| + assert query + assert_equal @project, query.project + end + assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort + end + + should "copy versions" do + @source_project.versions << Version.generate! + @source_project.versions << Version.generate! + + assert @project.versions.empty? + assert @project.copy(@source_project) + + assert_equal @source_project.versions.size, @project.versions.size + @project.versions.each do |version| + assert version + assert_equal @project, version.project + end + end + + should "copy wiki" do + assert_difference 'Wiki.count' do + assert @project.copy(@source_project) + end + + assert @project.wiki + assert_not_equal @source_project.wiki, @project.wiki + assert_equal "Start page", @project.wiki.start_page + end + + should "copy wiki pages and content with hierarchy" do + assert_difference 'WikiPage.count', @source_project.wiki.pages.size do + assert @project.copy(@source_project) + end + + assert @project.wiki + assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size + + @project.wiki.pages.each do |wiki_page| + assert wiki_page.content + assert !@source_project.wiki.pages.include?(wiki_page) + end + + parent = @project.wiki.find_page('Parent_page') + child1 = @project.wiki.find_page('Child_page_1') + child2 = @project.wiki.find_page('Child_page_2') + assert_equal parent, child1.parent + assert_equal parent, child2.parent + end + + should "copy issue categories" do + assert @project.copy(@source_project) + + assert_equal 2, @project.issue_categories.size + @project.issue_categories.each do |issue_category| + assert !@source_project.issue_categories.include?(issue_category) + end + end + + should "copy boards" do + assert @project.copy(@source_project) + + assert_equal 1, @project.boards.size + @project.boards.each do |board| + assert !@source_project.boards.include?(board) + end + end + + should "change the new issues to use the copied issue categories" do + issue = Issue.find(4) + issue.update_attribute(:category_id, 3) + + assert @project.copy(@source_project) + + @project.issues.each do |issue| + assert issue.category + assert_equal "Stock management", issue.category.name # Same name + assert_not_equal IssueCategory.find(3), issue.category # Different record + end + end + + should "limit copy with :only option" do + assert @project.members.empty? + assert @project.issue_categories.empty? + assert @source_project.issues.any? + + assert @project.copy(@source_project, :only => ['members', 'issue_categories']) + + assert @project.members.any? + assert @project.issue_categories.any? + assert @project.issues.empty? + end + + end + + context "#start_date" do + setup do + ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests + @project = Project.generate!(:identifier => 'test0') + @project.trackers << Tracker.generate! + end + + should "be nil if there are no issues on the project" do + assert_nil @project.start_date + end + + should "be tested when issues have no start date" + + should "be the earliest start date of it's issues" do + early = 7.days.ago.to_date + Issue.generate_for_project!(@project, :start_date => Date.today) + Issue.generate_for_project!(@project, :start_date => early) + + assert_equal early, @project.start_date + end + + end + + context "#due_date" do + setup do + ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests + @project = Project.generate!(:identifier => 'test0') + @project.trackers << Tracker.generate! + end + + should "be nil if there are no issues on the project" do + assert_nil @project.due_date + end + + should "be tested when issues have no due date" + + should "be the latest due date of it's issues" do + future = 7.days.from_now.to_date + Issue.generate_for_project!(@project, :due_date => future) + Issue.generate_for_project!(@project, :due_date => Date.today) + + assert_equal future, @project.due_date + end + + should "be the latest due date of it's versions" do + future = 7.days.from_now.to_date + @project.versions << Version.generate!(:effective_date => future) + @project.versions << Version.generate!(:effective_date => Date.today) + + + assert_equal future, @project.due_date + + end + + should "pick the latest date from it's issues and versions" do + future = 7.days.from_now.to_date + far_future = 14.days.from_now.to_date + Issue.generate_for_project!(@project, :due_date => far_future) + @project.versions << Version.generate!(:effective_date => future) + + assert_equal far_future, @project.due_date + end + + end + + context "Project#completed_percent" do + setup do + ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests + @project = Project.generate!(:identifier => 'test0') + @project.trackers << Tracker.generate! + end + + context "no versions" do + should "be 100" do + assert_equal 100, @project.completed_percent + end + end + + context "with versions" do + should "return 0 if the versions have no issues" do + Version.generate!(:project => @project) + Version.generate!(:project => @project) + + assert_equal 0, @project.completed_percent + end + + should "return 100 if the version has only closed issues" do + v1 = Version.generate!(:project => @project) + Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v1) + v2 = Version.generate!(:project => @project) + Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('Closed'), :fixed_version => v2) + + assert_equal 100, @project.completed_percent + end + + should "return the averaged completed percent of the versions (not weighted)" do + v1 = Version.generate!(:project => @project) + Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v1) + v2 = Version.generate!(:project => @project) + Issue.generate_for_project!(@project, :status => IssueStatus.find_by_name('New'), :estimated_hours => 10, :done_ratio => 50, :fixed_version => v2) + + assert_equal 50, @project.completed_percent + end + + end + end + + context "#notified_users" do + setup do + @project = Project.generate! + @role = Role.generate! + + @user_with_membership_notification = User.generate!(:mail_notification => 'selected') + Member.generate!(:project => @project, :roles => [@role], :principal => @user_with_membership_notification, :mail_notification => true) + + @all_events_user = User.generate!(:mail_notification => 'all') + Member.generate!(:project => @project, :roles => [@role], :principal => @all_events_user) + + @no_events_user = User.generate!(:mail_notification => 'none') + Member.generate!(:project => @project, :roles => [@role], :principal => @no_events_user) + + @only_my_events_user = User.generate!(:mail_notification => 'only_my_events') + Member.generate!(:project => @project, :roles => [@role], :principal => @only_my_events_user) + + @only_assigned_user = User.generate!(:mail_notification => 'only_assigned') + Member.generate!(:project => @project, :roles => [@role], :principal => @only_assigned_user) + + @only_owned_user = User.generate!(:mail_notification => 'only_owner') + Member.generate!(:project => @project, :roles => [@role], :principal => @only_owned_user) + end + + should "include members with a mail notification" do + assert @project.notified_users.include?(@user_with_membership_notification) + end + + should "include users with the 'all' notification option" do + assert @project.notified_users.include?(@all_events_user) + end + + should "not include users with the 'none' notification option" do + assert !@project.notified_users.include?(@no_events_user) + end + + should "not include users with the 'only_my_events' notification option" do + assert !@project.notified_users.include?(@only_my_events_user) + end + + should "not include users with the 'only_assigned' notification option" do + assert !@project.notified_users.include?(@only_assigned_user) + end + + should "not include users with the 'only_owner' notification option" do + assert !@project.notified_users.include?(@only_owned_user) + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/41/41f52ddbd628d1e0dc1111fbeab3adb26bd9f575.svn-base Binary file .svn/pristine/41/41f52ddbd628d1e0dc1111fbeab3adb26bd9f575.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/42065d6686eb12e9679c9132fc4c1d7b2537270b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/42/42065d6686eb12e9679c9132fc4c1d7b2537270b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do + xml.title @title + xml.link "rel" => "self", "href" => url_for(:format => 'atom', :key => User.current.rss_key, :only_path => false) + xml.link "rel" => "alternate", "href" => home_url(:only_path => false) + xml.id url_for(:controller => 'welcome', :only_path => false) + xml.updated((@journals.first ? @journals.first.event_datetime : Time.now).xmlschema) + xml.author { xml.name "#{Setting.app_title}" } + @journals.each do |change| + issue = change.issue + xml.entry do + xml.title "#{issue.project.name} - #{issue.tracker.name} ##{issue.id}: #{issue.subject}" + xml.link "rel" => "alternate", "href" => url_for(:controller => 'issues' , :action => 'show', :id => issue, :only_path => false) + xml.id url_for(:controller => 'issues' , :action => 'show', :id => issue, :journal_id => change, :only_path => false) + xml.updated change.created_on.xmlschema + xml.author do + xml.name change.user.name + xml.email(change.user.mail) if change.user.is_a?(User) && !change.user.mail.blank? && !change.user.pref.hide_mail + end + xml.content "type" => "html" do + xml.text! '
    ' + change.details.each do |detail| + xml.text! '
  • ' + show_detail(detail, false) + '
  • ' + end + xml.text! '
' + xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank? + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/424e41245ec7eb996b3059cfa13429062c4c2046.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/42/424e41245ec7eb996b3059cfa13429062c4c2046.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToWikiRedirects < ActiveRecord::Migration + def self.up + add_index :wiki_redirects, :wiki_id + end + + def self.down + remove_index :wiki_redirects, :wiki_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/427b264a64a6d9342fb25880cb15db8377d4ab62.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/42/427b264a64a6d9342fb25880cb15db8377d4ab62.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %> +
+<%= render :partial => "issue.html.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/427c435973b09320d012f4a307265921e2e2fd84.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/42/427c435973b09320d012f4a307265921e2e2fd84.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +#!/usr/bin/perl +# +# redMine 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. + +# modify to suit your repository base +my $repos_base = '/var/svn'; + +my $path = '/usr/bin/'; +my %kwown_commands = map { $_ => 1 } qw/svnserve/; + +umask 0002; + +exec ('/usr/bin/svnserve', '-r', $repos_base, '-t'); diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/428612395d9016270f63f32ed9dffa1b755e4922.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/42/428612395d9016270f63f32ed9dffa1b755e4922.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,960 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Issue < ActiveRecord::Base + include Redmine::SafeAttributes + + belongs_to :project + belongs_to :tracker + belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' + belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' + belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id' + belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' + + has_many :journals, :as => :journalized, :dependent => :destroy + has_many :time_entries, :dependent => :delete_all + has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC" + + has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all + has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all + + acts_as_nested_set :scope => 'root_id', :dependent => :destroy + acts_as_attachable :after_add => :attachment_added, :after_remove => :attachment_removed + acts_as_customizable + acts_as_watchable + acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], + :include => [:project, :journals], + # sort by id so that limited eager loading doesn't break with postgresql + :order_column => "#{table_name}.id" + acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, + :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}, + :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') } + + acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}, + :author_key => :author_id + + DONE_RATIO_OPTIONS = %w(issue_field issue_status) + + attr_reader :current_journal + + validates_presence_of :subject, :priority, :project, :tracker, :author, :status + + validates_length_of :subject, :maximum => 255 + validates_inclusion_of :done_ratio, :in => 0..100 + validates_numericality_of :estimated_hours, :allow_nil => true + validate :validate_issue + + named_scope :visible, lambda {|*args| { :include => :project, + :conditions => Issue.visible_condition(args.shift || User.current, *args) } } + + named_scope :open, :conditions => ["#{IssueStatus.table_name}.is_closed = ?", false], :include => :status + + named_scope :recently_updated, :order => "#{Issue.table_name}.updated_on DESC" + named_scope :with_limit, lambda { |limit| { :limit => limit} } + named_scope :on_active_project, :include => [:status, :project, :tracker], + :conditions => ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"] + + named_scope :without_version, lambda { + { + :conditions => { :fixed_version_id => nil} + } + } + + named_scope :with_query, lambda {|query| + { + :conditions => Query.merge_conditions(query.statement) + } + } + + before_create :default_assign + before_save :close_duplicates, :update_done_ratio_from_issue_status + after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal + after_destroy :update_parent_attributes + + # Returns a SQL conditions string used to find all issues visible by the specified user + def self.visible_condition(user, options={}) + Project.allowed_to_condition(user, :view_issues, options) do |role, user| + case role.issues_visibility + when 'all' + nil + when 'default' + user_ids = [user.id] + user.groups.map(&:id) + "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" + when 'own' + user_ids = [user.id] + user.groups.map(&:id) + "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" + else + '1=0' + end + end + end + + # Returns true if usr or current user is allowed to view the issue + def visible?(usr=nil) + (usr || User.current).allowed_to?(:view_issues, self.project) do |role, user| + case role.issues_visibility + when 'all' + true + when 'default' + !self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to) + when 'own' + self.author == user || user.is_or_belongs_to?(assigned_to) + else + false + end + end + end + + def after_initialize + if new_record? + # set default values for new records only + self.status ||= IssueStatus.default + self.priority ||= IssuePriority.default + end + end + + # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields + def available_custom_fields + (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : [] + end + + def copy_from(arg) + issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg) + self.attributes = issue.attributes.dup.except("id", "root_id", "parent_id", "lft", "rgt", "created_on", "updated_on") + self.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h} + self.status = issue.status + self + end + + # Moves/copies an issue to a new project and tracker + # Returns the moved/copied issue on success, false on failure + def move_to_project(*args) + ret = Issue.transaction do + move_to_project_without_transaction(*args) || raise(ActiveRecord::Rollback) + end || false + end + + def move_to_project_without_transaction(new_project, new_tracker = nil, options = {}) + options ||= {} + issue = options[:copy] ? self.class.new.copy_from(self) : self + + if new_project && issue.project_id != new_project.id + # delete issue relations + unless Setting.cross_project_issue_relations? + issue.relations_from.clear + issue.relations_to.clear + end + # issue is moved to another project + # reassign to the category with same name if any + new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name) + issue.category = new_category + # Keep the fixed_version if it's still valid in the new_project + unless new_project.shared_versions.include?(issue.fixed_version) + issue.fixed_version = nil + end + issue.project = new_project + if issue.parent && issue.parent.project_id != issue.project_id + issue.parent_issue_id = nil + end + end + if new_tracker + issue.tracker = new_tracker + issue.reset_custom_values! + end + if options[:copy] + issue.author = User.current + issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h} + issue.status = if options[:attributes] && options[:attributes][:status_id] + IssueStatus.find_by_id(options[:attributes][:status_id]) + else + self.status + end + end + # Allow bulk setting of attributes on the issue + if options[:attributes] + issue.attributes = options[:attributes] + end + if issue.save + if options[:copy] + if current_journal && current_journal.notes.present? + issue.init_journal(current_journal.user, current_journal.notes) + issue.current_journal.notify = false + issue.save + end + else + # Manually update project_id on related time entries + TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id}) + + issue.children.each do |child| + unless child.move_to_project_without_transaction(new_project) + # Move failed and transaction was rollback'd + return false + end + end + end + else + return false + end + issue + end + + def status_id=(sid) + self.status = nil + write_attribute(:status_id, sid) + end + + def priority_id=(pid) + self.priority = nil + write_attribute(:priority_id, pid) + end + + def tracker_id=(tid) + self.tracker = nil + result = write_attribute(:tracker_id, tid) + @custom_field_values = nil + result + end + + def description=(arg) + if arg.is_a?(String) + arg = arg.gsub(/(\r\n|\n|\r)/, "\r\n") + end + write_attribute(:description, arg) + end + + # Overrides attributes= so that tracker_id gets assigned first + def attributes_with_tracker_first=(new_attributes, *args) + return if new_attributes.nil? + new_tracker_id = new_attributes['tracker_id'] || new_attributes[:tracker_id] + if new_tracker_id + self.tracker_id = new_tracker_id + end + send :attributes_without_tracker_first=, new_attributes, *args + end + # Do not redefine alias chain on reload (see #4838) + alias_method_chain(:attributes=, :tracker_first) unless method_defined?(:attributes_without_tracker_first=) + + def estimated_hours=(h) + write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) + end + + safe_attributes 'tracker_id', + 'status_id', + 'parent_issue_id', + 'category_id', + 'assigned_to_id', + 'priority_id', + 'fixed_version_id', + 'subject', + 'description', + 'start_date', + 'due_date', + 'done_ratio', + 'estimated_hours', + 'custom_field_values', + 'custom_fields', + 'lock_version', + :if => lambda {|issue, user| issue.new_record? || user.allowed_to?(:edit_issues, issue.project) } + + safe_attributes 'status_id', + 'assigned_to_id', + 'fixed_version_id', + 'done_ratio', + :if => lambda {|issue, user| issue.new_statuses_allowed_to(user).any? } + + safe_attributes 'is_private', + :if => lambda {|issue, user| + user.allowed_to?(:set_issues_private, issue.project) || + (issue.author == user && user.allowed_to?(:set_own_issues_private, issue.project)) + } + + # Safely sets attributes + # Should be called from controllers instead of #attributes= + # attr_accessible is too rough because we still want things like + # Issue.new(:project => foo) to work + # TODO: move workflow/permission checks from controllers to here + def safe_attributes=(attrs, user=User.current) + return unless attrs.is_a?(Hash) + + # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed + attrs = delete_unsafe_attributes(attrs, user) + return if attrs.empty? + + # Tracker must be set before since new_statuses_allowed_to depends on it. + if t = attrs.delete('tracker_id') + self.tracker_id = t + end + + if attrs['status_id'] + unless new_statuses_allowed_to(user).collect(&:id).include?(attrs['status_id'].to_i) + attrs.delete('status_id') + end + end + + unless leaf? + attrs.reject! {|k,v| %w(priority_id done_ratio start_date due_date estimated_hours).include?(k)} + end + + if attrs.has_key?('parent_issue_id') + if !user.allowed_to?(:manage_subtasks, project) + attrs.delete('parent_issue_id') + elsif !attrs['parent_issue_id'].blank? + attrs.delete('parent_issue_id') unless Issue.visible(user).exists?(attrs['parent_issue_id'].to_i) + end + end + + self.attributes = attrs + end + + def done_ratio + if Issue.use_status_for_done_ratio? && status && status.default_done_ratio + status.default_done_ratio + else + read_attribute(:done_ratio) + end + end + + def self.use_status_for_done_ratio? + Setting.issue_done_ratio == 'issue_status' + end + + def self.use_field_for_done_ratio? + Setting.issue_done_ratio == 'issue_field' + end + + def validate_issue + if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? + errors.add :due_date, :not_a_date + end + + if self.due_date and self.start_date and self.due_date < self.start_date + errors.add :due_date, :greater_than_start_date + end + + if start_date && soonest_start && start_date < soonest_start + errors.add :start_date, :invalid + end + + if fixed_version + if !assignable_versions.include?(fixed_version) + errors.add :fixed_version_id, :inclusion + elsif reopened? && fixed_version.closed? + errors.add :base, I18n.t(:error_can_not_reopen_issue_on_closed_version) + end + end + + # Checks that the issue can not be added/moved to a disabled tracker + if project && (tracker_id_changed? || project_id_changed?) + unless project.trackers.include?(tracker) + errors.add :tracker_id, :inclusion + end + end + + # Checks parent issue assignment + if @parent_issue + if @parent_issue.project_id != project_id + errors.add :parent_issue_id, :not_same_project + elsif !new_record? + # moving an existing issue + if @parent_issue.root_id != root_id + # we can always move to another tree + elsif move_possible?(@parent_issue) + # move accepted inside tree + else + errors.add :parent_issue_id, :not_a_valid_parent + end + end + end + end + + # Set the done_ratio using the status if that setting is set. This will keep the done_ratios + # even if the user turns off the setting later + def update_done_ratio_from_issue_status + if Issue.use_status_for_done_ratio? && status && status.default_done_ratio + self.done_ratio = status.default_done_ratio + end + end + + def init_journal(user, notes = "") + @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) + @issue_before_change = self.clone + @issue_before_change.status = self.status + @custom_values_before_change = {} + self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } + # Make sure updated_on is updated when adding a note. + updated_on_will_change! + @current_journal + end + + # Return true if the issue is closed, otherwise false + def closed? + self.status.is_closed? + end + + # Return true if the issue is being reopened + def reopened? + if !new_record? && status_id_changed? + status_was = IssueStatus.find_by_id(status_id_was) + status_new = IssueStatus.find_by_id(status_id) + if status_was && status_new && status_was.is_closed? && !status_new.is_closed? + return true + end + end + false + end + + # Return true if the issue is being closed + def closing? + if !new_record? && status_id_changed? + status_was = IssueStatus.find_by_id(status_id_was) + status_new = IssueStatus.find_by_id(status_id) + if status_was && status_new && !status_was.is_closed? && status_new.is_closed? + return true + end + end + false + end + + # Returns true if the issue is overdue + def overdue? + !due_date.nil? && (due_date < Date.today) && !status.is_closed? + end + + # Is the amount of work done less than it should for the due date + def behind_schedule? + return false if start_date.nil? || due_date.nil? + done_date = start_date + ((due_date - start_date+1)* done_ratio/100).floor + return done_date <= Date.today + end + + # Does this issue have children? + def children? + !leaf? + end + + # Users the issue can be assigned to + def assignable_users + users = project.assignable_users + users << author if author + users << assigned_to if assigned_to + users.uniq.sort + end + + # Versions that the issue can be assigned to + def assignable_versions + @assignable_versions ||= (project.shared_versions.open + [Version.find_by_id(fixed_version_id_was)]).compact.uniq.sort + end + + # Returns true if this issue is blocked by another issue that is still open + def blocked? + !relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil? + end + + # Returns an array of status that user is able to apply + def new_statuses_allowed_to(user, include_default=false) + statuses = status.find_new_statuses_allowed_to( + user.roles_for_project(project), + tracker, + author == user, + assigned_to_id_changed? ? assigned_to_id_was == user.id : assigned_to_id == user.id + ) + statuses << status unless statuses.empty? + statuses << IssueStatus.default if include_default + statuses = statuses.uniq.sort + blocked? ? statuses.reject {|s| s.is_closed?} : statuses + end + + # Returns the mail adresses of users that should be notified + def recipients + notified = project.notified_users + # Author and assignee are always notified unless they have been + # locked or don't want to be notified + notified << author if author && author.active? && author.notify_about?(self) + if assigned_to + if assigned_to.is_a?(Group) + notified += assigned_to.users.select {|u| u.active? && u.notify_about?(self)} + else + notified << assigned_to if assigned_to.active? && assigned_to.notify_about?(self) + end + end + notified.uniq! + # Remove users that can not view the issue + notified.reject! {|user| !visible?(user)} + notified.collect(&:mail) + end + + # Returns the total number of hours spent on this issue and its descendants + # + # Example: + # spent_hours => 0.0 + # spent_hours => 50.2 + def spent_hours + @spent_hours ||= self_and_descendants.sum("#{TimeEntry.table_name}.hours", :include => :time_entries).to_f || 0.0 + end + + def relations + @relations ||= (relations_from + relations_to).sort + end + + # Preloads relations for a collection of issues + def self.load_relations(issues) + if issues.any? + relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}]) + issues.each do |issue| + issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id} + end + end + end + + # Finds an issue relation given its id. + def find_relation(relation_id) + IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id]) + end + + def all_dependent_issues(except=[]) + except << self + dependencies = [] + relations_from.each do |relation| + if relation.issue_to && !except.include?(relation.issue_to) + dependencies << relation.issue_to + dependencies += relation.issue_to.all_dependent_issues(except) + end + end + dependencies + end + + # Returns an array of issues that duplicate this one + def duplicates + relations_to.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.issue_from} + end + + # Returns the due date or the target due date if any + # Used on gantt chart + def due_before + due_date || (fixed_version ? fixed_version.effective_date : nil) + end + + # Returns the time scheduled for this issue. + # + # Example: + # Start Date: 2/26/09, End Date: 3/04/09 + # duration => 6 + def duration + (start_date && due_date) ? due_date - start_date : 0 + end + + def soonest_start + @soonest_start ||= ( + relations_to.collect{|relation| relation.successor_soonest_start} + + ancestors.collect(&:soonest_start) + ).compact.max + end + + def reschedule_after(date) + return if date.nil? + if leaf? + if start_date.nil? || start_date < date + self.start_date, self.due_date = date, date + duration + save + end + else + leaves.each do |leaf| + leaf.reschedule_after(date) + end + end + end + + def <=>(issue) + if issue.nil? + -1 + elsif root_id != issue.root_id + (root_id || 0) <=> (issue.root_id || 0) + else + (lft || 0) <=> (issue.lft || 0) + end + end + + def to_s + "#{tracker} ##{id}: #{subject}" + end + + # Returns a string of css classes that apply to the issue + def css_classes + s = "issue status-#{status.position} priority-#{priority.position}" + s << ' closed' if closed? + s << ' overdue' if overdue? + s << ' child' if child? + s << ' parent' unless leaf? + s << ' private' if is_private? + s << ' created-by-me' if User.current.logged? && author_id == User.current.id + s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id + s + end + + # Saves an issue, time_entry, attachments, and a journal from the parameters + # Returns false if save fails + def save_issue_with_child_records(params, existing_time_entry=nil) + Issue.transaction do + if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, project) + @time_entry = existing_time_entry || TimeEntry.new + @time_entry.project = project + @time_entry.issue = self + @time_entry.user = User.current + @time_entry.spent_on = User.current.today + @time_entry.attributes = params[:time_entry] + self.time_entries << @time_entry + end + + if valid? + attachments = Attachment.attach_files(self, params[:attachments]) + # TODO: Rename hook + Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + begin + if save + # TODO: Rename hook + Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + else + raise ActiveRecord::Rollback + end + rescue ActiveRecord::StaleObjectError + attachments[:files].each(&:destroy) + errors.add :base, l(:notice_locking_conflict) + raise ActiveRecord::Rollback + end + end + end + end + + # Unassigns issues from +version+ if it's no longer shared with issue's project + def self.update_versions_from_sharing_change(version) + # Update issues assigned to the version + update_versions(["#{Issue.table_name}.fixed_version_id = ?", version.id]) + end + + # Unassigns issues from versions that are no longer shared + # after +project+ was moved + def self.update_versions_from_hierarchy_change(project) + moved_project_ids = project.self_and_descendants.reload.collect(&:id) + # Update issues of the moved projects and issues assigned to a version of a moved project + Issue.update_versions(["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)", moved_project_ids, moved_project_ids]) + end + + def parent_issue_id=(arg) + parent_issue_id = arg.blank? ? nil : arg.to_i + if parent_issue_id && @parent_issue = Issue.find_by_id(parent_issue_id) + @parent_issue.id + else + @parent_issue = nil + nil + end + end + + def parent_issue_id + if instance_variable_defined? :@parent_issue + @parent_issue.nil? ? nil : @parent_issue.id + else + parent_id + end + end + + # Extracted from the ReportsController. + def self.by_tracker(project) + count_and_group_by(:project => project, + :field => 'tracker_id', + :joins => Tracker.table_name) + end + + def self.by_version(project) + count_and_group_by(:project => project, + :field => 'fixed_version_id', + :joins => Version.table_name) + end + + def self.by_priority(project) + count_and_group_by(:project => project, + :field => 'priority_id', + :joins => IssuePriority.table_name) + end + + def self.by_category(project) + count_and_group_by(:project => project, + :field => 'category_id', + :joins => IssueCategory.table_name) + end + + def self.by_assigned_to(project) + count_and_group_by(:project => project, + :field => 'assigned_to_id', + :joins => User.table_name) + end + + def self.by_author(project) + count_and_group_by(:project => project, + :field => 'author_id', + :joins => User.table_name) + end + + def self.by_subproject(project) + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + #{Issue.table_name}.project_id as project_id, + count(#{Issue.table_name}.id) as total + from + #{Issue.table_name}, #{Project.table_name}, #{IssueStatus.table_name} s + where + #{Issue.table_name}.status_id=s.id + and #{Issue.table_name}.project_id = #{Project.table_name}.id + and #{visible_condition(User.current, :project => project, :with_subprojects => true)} + and #{Issue.table_name}.project_id <> #{project.id} + group by s.id, s.is_closed, #{Issue.table_name}.project_id") if project.descendants.active.any? + end + # End ReportsController extraction + + # Returns an array of projects that current user can move issues to + def self.allowed_target_projects_on_move + projects = [] + if User.current.admin? + # admin is allowed to move issues to any active (visible) project + projects = Project.visible.all + elsif User.current.logged? + if Role.non_member.allowed_to?(:move_issues) + projects = Project.visible.all + else + User.current.memberships.each {|m| projects << m.project if m.roles.detect {|r| r.allowed_to?(:move_issues)}} + end + end + projects + end + + private + + def update_nested_set_attributes + if root_id.nil? + # issue was just created + self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id) + set_default_left_and_right + Issue.update_all("root_id = #{root_id}, lft = #{lft}, rgt = #{rgt}", ["id = ?", id]) + if @parent_issue + move_to_child_of(@parent_issue) + end + reload + elsif parent_issue_id != parent_id + former_parent_id = parent_id + # moving an existing issue + if @parent_issue && @parent_issue.root_id == root_id + # inside the same tree + move_to_child_of(@parent_issue) + else + # to another tree + unless root? + move_to_right_of(root) + reload + end + old_root_id = root_id + self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id ) + target_maxright = nested_set_scope.maximum(right_column_name) || 0 + offset = target_maxright + 1 - lft + Issue.update_all("root_id = #{root_id}, lft = lft + #{offset}, rgt = rgt + #{offset}", + ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]) + self[left_column_name] = lft + offset + self[right_column_name] = rgt + offset + if @parent_issue + move_to_child_of(@parent_issue) + end + end + reload + # delete invalid relations of all descendants + self_and_descendants.each do |issue| + issue.relations.each do |relation| + relation.destroy unless relation.valid? + end + end + # update former parent + recalculate_attributes_for(former_parent_id) if former_parent_id + end + remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue) + end + + def update_parent_attributes + recalculate_attributes_for(parent_id) if parent_id + end + + def recalculate_attributes_for(issue_id) + if issue_id && p = Issue.find_by_id(issue_id) + # priority = highest priority of children + if priority_position = p.children.maximum("#{IssuePriority.table_name}.position", :include => :priority) + p.priority = IssuePriority.find_by_position(priority_position) + end + + # start/due dates = lowest/highest dates of children + p.start_date = p.children.minimum(:start_date) + p.due_date = p.children.maximum(:due_date) + if p.start_date && p.due_date && p.due_date < p.start_date + p.start_date, p.due_date = p.due_date, p.start_date + end + + # done ratio = weighted average ratio of leaves + unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio + leaves_count = p.leaves.count + if leaves_count > 0 + average = p.leaves.average(:estimated_hours).to_f + if average == 0 + average = 1 + end + done = p.leaves.sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :include => :status).to_f + progress = done / (average * leaves_count) + p.done_ratio = progress.round + end + end + + # estimate = sum of leaves estimates + p.estimated_hours = p.leaves.sum(:estimated_hours).to_f + p.estimated_hours = nil if p.estimated_hours == 0.0 + + # ancestors will be recursively updated + p.save(false) + end + end + + # Update issues so their versions are not pointing to a + # fixed_version that is not shared with the issue's project + def self.update_versions(conditions=nil) + # Only need to update issues with a fixed_version from + # a different project and that is not systemwide shared + Issue.all(:conditions => merge_conditions("#{Issue.table_name}.fixed_version_id IS NOT NULL" + + " AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" + + " AND #{Version.table_name}.sharing <> 'system'", + conditions), + :include => [:project, :fixed_version] + ).each do |issue| + next if issue.project.nil? || issue.fixed_version.nil? + unless issue.project.shared_versions.include?(issue.fixed_version) + issue.init_journal(User.current) + issue.fixed_version = nil + issue.save + end + end + end + + # Callback on attachment deletion + def attachment_added(obj) + if @current_journal && !obj.new_record? + @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename) + end + end + + # Callback on attachment deletion + def attachment_removed(obj) + journal = init_journal(User.current) + journal.details << JournalDetail.new(:property => 'attachment', + :prop_key => obj.id, + :old_value => obj.filename) + journal.save + end + + # Default assignment based on category + def default_assign + if assigned_to.nil? && category && category.assigned_to + self.assigned_to = category.assigned_to + end + end + + # Updates start/due dates of following issues + def reschedule_following_issues + if start_date_changed? || due_date_changed? + relations_from.each do |relation| + relation.set_issue_to_dates + end + end + end + + # Closes duplicates if the issue is being closed + def close_duplicates + if closing? + duplicates.each do |duplicate| + # Reload is need in case the duplicate was updated by a previous duplicate + duplicate.reload + # Don't re-close it if it's already closed + next if duplicate.closed? + # Same user and notes + if @current_journal + duplicate.init_journal(@current_journal.user, @current_journal.notes) + end + duplicate.update_attribute :status, self.status + end + end + end + + # Saves the changes in a Journal + # Called after_save + def create_journal + if @current_journal + # attributes changes + (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on)).each {|c| + before = @issue_before_change.send(c) + after = send(c) + next if before == after || (before.blank? && after.blank?) + @current_journal.details << JournalDetail.new(:property => 'attr', + :prop_key => c, + :old_value => @issue_before_change.send(c), + :value => send(c)) + } + # custom fields changes + custom_values.each {|c| + next if (@custom_values_before_change[c.custom_field_id]==c.value || + (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?)) + @current_journal.details << JournalDetail.new(:property => 'cf', + :prop_key => c.custom_field_id, + :old_value => @custom_values_before_change[c.custom_field_id], + :value => c.value) + } + @current_journal.save + # reset current journal + init_journal @current_journal.user, @current_journal.notes + end + end + + # Query generator for selecting groups of issue counts for a project + # based on specific criteria + # + # Options + # * project - Project to search in. + # * field - String. Issue field to key off of in the grouping. + # * joins - String. The table name to join against. + def self.count_and_group_by(options) + project = options.delete(:project) + select_field = options.delete(:field) + joins = options.delete(:joins) + + where = "#{Issue.table_name}.#{select_field}=j.id" + + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + j.id as #{select_field}, + count(#{Issue.table_name}.id) as total + from + #{Issue.table_name}, #{Project.table_name}, #{IssueStatus.table_name} s, #{joins} j + where + #{Issue.table_name}.status_id=s.id + and #{where} + and #{Issue.table_name}.project_id=#{Project.table_name}.id + and #{visible_condition(User.current, :project => project)} + group by s.id, s.is_closed, j.id") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/428bfa93a4c970791698a943e257eddabf08b22f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/42/428bfa93a4c970791698a943e257eddabf08b22f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

<%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %>

+

<%= format_time(document.updated_on) %>

+ +
+ <%= textilizable(truncate_lines(document.description), :object => document) %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/42aed296ea3b78b41d0b511de71f7c91b132644f.svn-base Binary file .svn/pristine/42/42aed296ea3b78b41d0b511de71f7c91b132644f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/42/42be01ceec820afa8054f8cb8fb95aec43abad90.svn-base Binary file .svn/pristine/42/42be01ceec820afa8054f8cb8fb95aec43abad90.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/431e564a1e03f4cc7d0102d7d18816df7d2cc0e3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/431e564a1e03f4cc7d0102d7d18816df7d2cc0e3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,117 @@ +require File.expand_path('../../../test_helper', __FILE__) + +class ApiTest::DisabledRestApiTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def setup + Setting.rest_api_enabled = '0' + Setting.login_required = '1' + end + + def teardown + Setting.rest_api_enabled = '1' + Setting.login_required = '0' + end + + # Using the NewsController because it's a simple API. + context "get /news with the API disabled" do + + context "in :xml format" do + context "with a valid api token" do + setup do + @user = User.generate_with_protected! + @token = Token.generate!(:user => @user, :action => 'api') + get "/news.xml?key=#{@token.value}" + end + + should_respond_with :unauthorized + should_respond_with_content_type :xml + should "not login as the user" do + assert_equal User.anonymous, User.current + end + end + + context "with a valid HTTP authentication" do + setup do + @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password') + @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password') + get "/news.xml", nil, :authorization => @authorization + end + + should_respond_with :unauthorized + should_respond_with_content_type :xml + should "not login as the user" do + assert_equal User.anonymous, User.current + end + end + + context "with a valid HTTP authentication using the API token" do + setup do + @user = User.generate_with_protected! + @token = Token.generate!(:user => @user, :action => 'api') + @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X') + get "/news.xml", nil, :authorization => @authorization + end + + should_respond_with :unauthorized + should_respond_with_content_type :xml + should "not login as the user" do + assert_equal User.anonymous, User.current + end + end + end + + context "in :json format" do + context "with a valid api token" do + setup do + @user = User.generate_with_protected! + @token = Token.generate!(:user => @user, :action => 'api') + get "/news.json?key=#{@token.value}" + end + + should_respond_with :unauthorized + should_respond_with_content_type :json + should "not login as the user" do + assert_equal User.anonymous, User.current + end + end + + context "with a valid HTTP authentication" do + setup do + @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password') + @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password') + get "/news.json", nil, :authorization => @authorization + end + + should_respond_with :unauthorized + should_respond_with_content_type :json + should "not login as the user" do + assert_equal User.anonymous, User.current + end + end + + context "with a valid HTTP authentication using the API token" do + setup do + @user = User.generate_with_protected! + @token = Token.generate!(:user => @user, :action => 'api') + @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'DoesNotMatter') + get "/news.json", nil, :authorization => @authorization + end + + should_respond_with :unauthorized + should_respond_with_content_type :json + should "not login as the user" do + assert_equal User.anonymous, User.current + end + end + + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/43272555ea477da0c1b59cf98e2f63d68056c98b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/43272555ea477da0c1b59cf98e2f63d68056c98b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,113 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/darcs_adapter' + +class Repository::Darcs < Repository + validates_presence_of :url, :log_encoding + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::DarcsAdapter + end + + def self.scm_name + 'Darcs' + end + + def supports_directory_revisions? + true + end + + def entry(path=nil, identifier=nil) + patch = identifier.nil? ? nil : changesets.find_by_revision(identifier) + scm.entry(path, patch.nil? ? nil : patch.scmid) + end + + def entries(path=nil, identifier=nil) + patch = nil + if ! identifier.nil? + patch = changesets.find_by_revision(identifier) + return nil if patch.nil? + end + entries = scm.entries(path, patch.nil? ? nil : patch.scmid) + if entries + entries.each do |entry| + # Search the DB for the entry's last change + if entry.lastrev && !entry.lastrev.scmid.blank? + changeset = changesets.find_by_scmid(entry.lastrev.scmid) + end + if changeset + entry.lastrev.identifier = changeset.revision + entry.lastrev.name = changeset.revision + entry.lastrev.time = changeset.committed_on + entry.lastrev.author = changeset.committer + end + end + end + entries + end + + def cat(path, identifier=nil) + patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s) + scm.cat(path, patch.nil? ? nil : patch.scmid) + end + + def diff(path, rev, rev_to) + patch_from = changesets.find_by_revision(rev) + return nil if patch_from.nil? + patch_to = changesets.find_by_revision(rev_to) if rev_to + if path.blank? + path = patch_from.changes.collect{|change| change.path}.join(' ') + end + patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil + end + + def fetch_changesets + scm_info = scm.info + if scm_info + db_last_id = latest_changeset ? latest_changeset.scmid : nil + next_rev = latest_changeset ? latest_changeset.revision.to_i + 1 : 1 + # latest revision in the repository + scm_revision = scm_info.lastrev.scmid + unless changesets.find_by_scmid(scm_revision) + revisions = scm.revisions('', db_last_id, nil, :with_path => true) + transaction do + revisions.reverse_each do |revision| + changeset = Changeset.create(:repository => self, + :revision => next_rev, + :scmid => revision.scmid, + :committer => revision.author, + :committed_on => revision.time, + :comments => revision.message) + revision.paths.each do |change| + changeset.create_change(change) + end + next_rev += 1 + end if revisions + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/4337bbf3d5bbaacb08a93d431c377d12025521b9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/4337bbf3d5bbaacb08a93d431c377d12025521b9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +--- partials.txt Wed Jan 19 12:06:17 2011 ++++ partials.1.txt Wed Jan 19 12:06:10 2011 +@@ -1,31 +1,31 @@ +-Lorem ipsum dolor sit amet, consectetur adipiscing elit ++Lorem ipsum dolor sit amet, consectetur adipiscing xx + Praesent et sagittis dui. Vivamus ac diam diam +-Ut sed auctor justo ++xxx auctor justo + Suspendisse venenatis sollicitudin magna quis suscipit +-Sed blandit gravida odio ac ultrices ++Sed blandit gxxxxa odio ac ultrices + Morbi rhoncus est ut est aliquam tempus +-Morbi id nisi vel felis tincidunt tempus ++Morbi id nisi vel felis xx tempus + Mauris auctor sagittis ante eu luctus +-Fusce commodo felis sed ligula congue molestie ++Fusce commodo felis sed ligula congue + Lorem ipsum dolor sit amet, consectetur adipiscing elit +-Praesent et sagittis dui. Vivamus ac diam diam ++et sagittis dui. Vivamus ac diam diam + Ut sed auctor justo + Suspendisse venenatis sollicitudin magna quis suscipit + Sed blandit gravida odio ac ultrices + +-Lorem ipsum dolor sit amet, consectetur adipiscing elit +-Praesent et sagittis dui. Vivamus ac diam diam ++Lorem ipsum dolor sit amet, xxxx adipiscing elit + Ut sed auctor justo + Suspendisse venenatis sollicitudin magna quis suscipit + Sed blandit gravida odio ac ultrices +-Morbi rhoncus est ut est aliquam tempus ++Morbi rhoncus est ut est xxxx tempus ++New line + Morbi id nisi vel felis tincidunt tempus + Mauris auctor sagittis ante eu luctus + Fusce commodo felis sed ligula congue molestie + +-Lorem ipsum dolor sit amet, consectetur adipiscing elit +-Praesent et sagittis dui. Vivamus ac diam diam +-Ut sed auctor justo ++Lorem ipsum dolor sit amet, xxxxtetur adipiscing elit ++Praesent et xxxxx. Vivamus ac diam diam ++Ut sed auctor + Suspendisse venenatis sollicitudin magna quis suscipit + Sed blandit gravida odio ac ultrices + Morbi rhoncus est ut est aliquam tempus diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/437c58e98b2bf838355e6ccb0adcad2c75761185.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/437c58e98b2bf838355e6ccb0adcad2c75761185.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +

<%= l(:label_search) %>

+ +
+<% form_tag({}, :method => :get) do %> +<%= label_tag "search-input", l(:description_search), :class => "hidden-for-sighted" %> +

<%= text_field_tag 'q', @question, :size => 60, :id => 'search-input' %> +<%= javascript_tag "Field.focus('search-input')" %> +<%= project_select_tag %> +<%= hidden_field_tag 'all_words', '', :id => nil %> + +<%= hidden_field_tag 'titles_only', '', :id => nil %> + +

+

+<% @object_types.each do |t| %> + +<% end %> +

+ +

<%= submit_tag l(:button_submit), :name => 'submit' %>

+<% end %> +
+ +<% if @results %> +
+ <%= render_results_by_type(@results_by_type) unless @scope.size == 1 %> +
+ +

<%= l(:label_result_plural) %> (<%= @results_by_type.values.sum %>)

+
+ <% @results.each do |e| %> +
<%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(h(e.event_title), :length => 255), @tokens), e.event_url %>
+
<%= highlight_tokens(h(e.event_description), @tokens) %> + <%= format_time(e.event_datetime) %>
+ <% end %> +
+<% end %> + +

+<% if @pagination_previous_date %> +<%= link_to_content_update("\xc2\xab " + l(:label_previous), + params.merge(:previous => 1, + :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>  +<% end %> +<% if @pagination_next_date %> +<%= link_to_content_update(l(:label_next) + " \xc2\xbb", + params.merge(:previous => nil, + :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %> +<% end %> +

+ +<% html_title(l(:label_search)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/43815b2797ad5e2c1f98a876a3c98a313e459bdb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/43815b2797ad5e2c1f98a876a3c98a313e459bdb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +RUBYTREE - http://rubytree.rubyforge.org +======================================== + +Copyright (c) 2006, 2007 Anupam Sengupta + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +- Neither the name of the organization nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/4384f149ba601f6c60fa67ac6f918ddfc90dc0b6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/4384f149ba601f6c60fa67ac6f918ddfc90dc0b6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,281 @@ +# This code lets us redefine existing Rake tasks, which is extremely +# handy for modifying existing Rails rake tasks. +# Credit for the original snippet of code goes to Jeremy Kemper +# http://pastie.caboo.se/9620 +unless Rake::TaskManager.methods.include?('redefine_task') + module Rake + module TaskManager + def redefine_task(task_class, args, &block) + task_name, arg_names, deps = resolve_args([args]) + task_name = task_class.scope_name(@scope, task_name) + deps = [deps] unless deps.respond_to?(:to_ary) + deps = deps.collect {|d| d.to_s } + task = @tasks[task_name.to_s] = task_class.new(task_name, self) + task.application = self + task.add_description(@last_description) + @last_description = nil + task.enhance(deps, &block) + task + end + + end + class Task + class << self + def redefine_task(args, &block) + Rake.application.redefine_task(self, [args], &block) + end + end + end + end +end + +namespace :db do + namespace :migrate do + desc 'Migrate database and plugins to current status.' + task :all => [ 'db:migrate', 'db:migrate:plugins' ] + + desc 'Migrate plugins to current status.' + task :plugins => :environment do + Engines.plugins.each do |plugin| + next unless plugin.respond_to?(:migration_directory) + next unless File.exists? plugin.migration_directory + puts "Migrating plugin #{plugin.name} ..." + plugin.migrate + end + end + + desc 'For engines coming from Rails version < 2.0 or for those previously updated to work with Sven Fuch\'s fork of engines, you need to upgrade the schema info table' + task :upgrade_plugin_migrations => :environment do + svens_fork_table_name = 'plugin_schema_migrations' + + # Check if app was previously using Sven's fork + if ActiveRecord::Base.connection.table_exists?(svens_fork_table_name) + old_sm_table = svens_fork_table_name + else + old_sm_table = ActiveRecord::Migrator.proper_table_name(Engines.schema_info_table) + end + + unless ActiveRecord::Base.connection.table_exists?(old_sm_table) + abort "Cannot find old migration table - assuming nothing needs to be done" + end + + # There are two forms of the engines schema info - pre-fix_plugin_migrations and post + # We need to figure this out before we continue. + + results = ActiveRecord::Base.connection.select_rows( + "SELECT version, plugin_name FROM #{old_sm_table}" + ).uniq + + def insert_new_version(plugin_name, version) + version_string = "#{version}-#{plugin_name}" + new_sm_table = ActiveRecord::Migrator.schema_migrations_table_name + + # Check if the row already exists for some reason - maybe run this task more than once. + return if ActiveRecord::Base.connection.select_rows("SELECT * FROM #{new_sm_table} WHERE version = #{version_string.dump.gsub("\"", "'")}").size > 0 + + puts "Inserting new version #{version} for plugin #{plugin_name}.." + ActiveRecord::Base.connection.insert("INSERT INTO #{new_sm_table} (version) VALUES (#{version_string.dump.gsub("\"", "'")})") + end + + # We need to figure out if they already used "fix_plugin_migrations" + versions = {} + results.each do |r| + versions[r[1]] ||= [] + versions[r[1]] << r[0].to_i + end + + if versions.values.find{ |v| v.size > 1 } == nil + puts "Fixing migration info" + # We only have one listed migration per plugin - this is pre-fix_plugin_migrations, + # so we build all versions required. In this case, all migrations should + versions.each do |plugin_name, version| + version = version[0] # There is only one version + + # We have to make an assumption that numeric migrations won't get this long.. + # I'm not sure if there is a better assumption, it should work in all + # current cases.. (touch wood..) + if version.to_s.size < "YYYYMMDDHHMMSS".size + # Insert version records for each migration + (1..version).each do |v| + insert_new_version(plugin_name, v) + end + else + # If the plugin is new-format "YYYYMMDDHHMMSS", we just copy it across... + # The case in which this occurs is very rare.. + insert_new_version(plugin_name, version) + end + end + else + puts "Moving migration info" + # We have multiple migrations listed per plugin - thus we can assume they have + # already applied fix_plugin_migrations - we just copy it across verbatim + versions.each do |plugin_name, version| + version.each { |v| insert_new_version(plugin_name, v) } + end + end + + puts "Migration info successfully migrated - removing old schema info table" + ActiveRecord::Base.connection.drop_table(old_sm_table) + end + + desc 'Migrate a specified plugin.' + task(:plugin => :environment) do + name = ENV['NAME'] + if plugin = Engines.plugins[name] + version = ENV['VERSION'] + puts "Migrating #{plugin.name} to " + (version ? "version #{version}" : 'latest version') + " ..." + plugin.migrate(version ? version.to_i : nil) + else + puts "Plugin #{name} does not exist." + end + end + end +end + + +namespace :db do + namespace :fixtures do + namespace :plugins do + + desc "Load plugin fixtures into the current environment's database." + task :load => :environment do + require 'active_record/fixtures' + ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym) + Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', ENV['PLUGIN'] || '**', + 'test', 'fixtures', '*.yml')).each do |fixture_file| + Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) + end + end + + end + end +end + +# this is just a modification of the original task in railties/lib/tasks/documentation.rake, +# because the default task doesn't support subdirectories like /app or +# /component. These tasks now include every file under a plugin's load paths (see +# Plugin#load_paths). +namespace :doc do + + plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) } + + namespace :plugins do + + # Define doc tasks for each plugin + plugins.each do |plugin| + desc "Create plugin documentation for '#{plugin}'" + Rake::Task.redefine_task(plugin => :environment) do + plugin_base = RAILS_ROOT + "/vendor/plugins/#{plugin}" + options = [] + files = Rake::FileList.new + options << "-o doc/plugins/#{plugin}" + options << "--title '#{plugin.titlecase} Plugin Documentation'" + options << '--line-numbers' << '--inline-source' + options << '-T html' + + # Include every file in the plugin's load_paths (see Plugin#load_paths) + if Engines.plugins[plugin] + files.include("#{plugin_base}/{#{Engines.plugins[plugin].load_paths.join(",")}}/**/*.rb") + end + if File.exists?("#{plugin_base}/README") + files.include("#{plugin_base}/README") + options << "--main '#{plugin_base}/README'" + end + files.include("#{plugin_base}/CHANGELOG") if File.exists?("#{plugin_base}/CHANGELOG") + + if files.empty? + puts "No source files found in #{plugin_base}. No documentation will be generated." + else + options << files.to_s + sh %(rdoc #{options * ' '}) + end + end + end + end +end + + + +namespace :test do + task :warn_about_multiple_plugin_testing_with_engines do + puts %{-~============== A Moste Polite Warninge ===========================~- + +You may experience issues testing multiple plugins at once when using +the code-mixing features that the engines plugin provides. If you do +experience any problems, please test plugins individually, i.e. + + $ rake test:plugins PLUGIN=my_plugin + +or use the per-type plugin test tasks: + + $ rake test:plugins:units + $ rake test:plugins:functionals + $ rake test:plugins:integration + $ rake test:plugins:all + +Report any issues on http://dev.rails-engines.org. Thanks! + +-~===============( ... as you were ... )============================~-} + end + + namespace :engines do + + def engine_plugins + Dir["vendor/plugins/*"].select { |f| File.directory?(File.join(f, "app")) }.map { |f| File.basename(f) }.join(",") + end + + desc "Run tests from within engines plugins (plugins with an 'app' directory)" + task :all => [:units, :functionals, :integration] + + desc "Run unit tests from within engines plugins (plugins with an 'app' directory)" + Rake::TestTask.new(:units => "test:plugins:setup_plugin_fixtures") do |t| + t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/unit/**/*_test.rb" + t.verbose = true + end + + desc "Run functional tests from within engines plugins (plugins with an 'app' directory)" + Rake::TestTask.new(:functionals => "test:plugins:setup_plugin_fixtures") do |t| + t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/functional/**/*_test.rb" + t.verbose = true + end + + desc "Run integration tests from within engines plugins (plugins with an 'app' directory)" + Rake::TestTask.new(:integration => "test:plugins:setup_plugin_fixtures") do |t| + t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/integration/**/*_test.rb" + t.verbose = true + end + end + + namespace :plugins do + + desc "Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)" + task :all => [:warn_about_multiple_plugin_testing_with_engines, + :units, :functionals, :integration] + + desc "Run all plugin unit tests" + Rake::TestTask.new(:units => :setup_plugin_fixtures) do |t| + t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/unit/**/*_test.rb" + t.verbose = true + end + + desc "Run all plugin functional tests" + Rake::TestTask.new(:functionals => :setup_plugin_fixtures) do |t| + t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/functional/**/*_test.rb" + t.verbose = true + end + + desc "Integration test engines" + Rake::TestTask.new(:integration => :setup_plugin_fixtures) do |t| + t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/integration/**/*_test.rb" + t.verbose = true + end + + desc "Mirrors plugin fixtures into a single location to help plugin tests" + task :setup_plugin_fixtures => :environment do + Engines::Testing.setup_plugin_fixtures + end + + # Patch the default plugin testing task to have setup_plugin_fixtures as a prerequisite + Rake::Task["test:plugins"].prerequisites << "test:plugins:setup_plugin_fixtures" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/43a9cf968cef1d70b773de7f7dc8546e52df7a2e.svn-base Binary file .svn/pristine/43/43a9cf968cef1d70b773de7f7dc8546e52df7a2e.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/43d930c64afa3ca6fd55d83a6abe6fa0100097e4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/43d930c64afa3ca6fd55d83a6abe6fa0100097e4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToIssueCategories < ActiveRecord::Migration + def self.up + add_index :issue_categories, :assigned_to_id + end + + def self.down + remove_index :issue_categories, :assigned_to_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/43/43fb9902139b2b7a8fd0a8822cc6d9e2aa8f6362.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/43/43fb9902139b2b7a8fd0a8822cc6d9e2aa8f6362.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddCustomValueCustomizedIndex < ActiveRecord::Migration + def self.up + add_index :custom_values, [:customized_type, :customized_id], :name => :custom_values_customized + end + + def self.down + remove_index :custom_values, :name => :custom_values_customized + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/44/44029a2dcfcc837db56531526bf2db2927ce13c1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/44/44029a2dcfcc837db56531526bf2db2927ce13c1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Đậm'; +jsToolBar.strings['Italic'] = 'Nghiêng'; +jsToolBar.strings['Underline'] = 'Gạch chân'; +jsToolBar.strings['Deleted'] = 'Xóa'; +jsToolBar.strings['Code'] = 'Mã chung dòng'; +jsToolBar.strings['Heading 1'] = 'Tiêu đề 1'; +jsToolBar.strings['Heading 2'] = 'Tiêu đề 2'; +jsToolBar.strings['Heading 3'] = 'Tiêu đề 3'; +jsToolBar.strings['Unordered list'] = 'Danh sách không thứ tự'; +jsToolBar.strings['Ordered list'] = 'Danh sách có thứ tự'; +jsToolBar.strings['Quote'] = 'Trích dẫn'; +jsToolBar.strings['Unquote'] = 'Bỏ trích dẫn'; +jsToolBar.strings['Preformatted text'] = 'Mã nguồn'; +jsToolBar.strings['Wiki link'] = 'Liên kết đến trang wiki'; +jsToolBar.strings['Image'] = 'Ảnh'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/44/4439ef733d46df57772e77a997ac371196818a57.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/44/4439ef733d46df57772e77a997ac371196818a57.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +# Load the normal Rails helper +require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper') + +# Ensure that we are using the temporary fixture path +Engines::Testing.set_fixture_path diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/44/44669c27372c172ef04555f4bb81865f6ca83884.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/44/44669c27372c172ef04555f4bb81865f6ca83884.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +require File.expand_path('../../test_helper', __FILE__) + +class GanttsControllerTest < ActionController::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions + + context "#gantt" do + should "work" do + i2 = Issue.find(2) + i2.update_attribute(:due_date, 1.month.from_now) + + get :show, :project_id => 1 + assert_response :success + assert_template 'gantts/show' + assert_not_nil assigns(:gantt) + # Issue with start and due dates + i = Issue.find(1) + assert_not_nil i.due_date + assert_select "div a.issue", /##{i.id}/ + # Issue with on a targeted version should not be in the events but loaded in the html + i = Issue.find(2) + assert_select "div a.issue", /##{i.id}/ + end + + should "work without issue due dates" do + Issue.update_all("due_date = NULL") + + get :show, :project_id => 1 + assert_response :success + assert_template 'gantts/show' + assert_not_nil assigns(:gantt) + end + + should "work without issue and version due dates" do + Issue.update_all("due_date = NULL") + Version.update_all("effective_date = NULL") + + get :show, :project_id => 1 + assert_response :success + assert_template 'gantts/show' + assert_not_nil assigns(:gantt) + end + + should "work cross project" do + get :show + assert_response :success + assert_template 'gantts/show' + assert_not_nil assigns(:gantt) + assert_not_nil assigns(:gantt).query + assert_nil assigns(:gantt).project + end + + should "not disclose private projects" do + get :show + assert_response :success + assert_template 'gantts/show' + + assert_tag 'a', :content => /eCookbook/ + # Root private project + assert_no_tag 'a', {:content => /OnlineStore/} + # Private children of a public project + assert_no_tag 'a', :content => /Private child of eCookbook/ + end + + should "export to pdf" do + get :show, :project_id => 1, :format => 'pdf' + assert_response :success + assert_equal 'application/pdf', @response.content_type + assert @response.body.starts_with?('%PDF') + assert_not_nil assigns(:gantt) + end + + should "export to pdf cross project" do + get :show, :format => 'pdf' + assert_response :success + assert_equal 'application/pdf', @response.content_type + assert @response.body.starts_with?('%PDF') + assert_not_nil assigns(:gantt) + end + + should "export to png" do + get :show, :project_id => 1, :format => 'png' + assert_response :success + assert_equal 'image/png', @response.content_type + end if Object.const_defined?(:Magick) + + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/44/448dc5ae56acac81ffaeeeb288586a6544fe08b0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/44/448dc5ae56acac81ffaeeeb288586a6544fe08b0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,545 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'projects_controller' + +# Re-raise errors caught by the controller. +class ProjectsController; def rescue_action(e) raise e end; end + +class ProjectsControllerTest < ActionController::TestCase + fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, + :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, + :attachments, :custom_fields, :custom_values, :time_entries + + def setup + @controller = ProjectsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @request.session[:user_id] = nil + Setting.default_language = 'en' + end + + def test_index + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:projects) + + assert_tag :ul, :child => {:tag => 'li', + :descendant => {:tag => 'a', :content => 'eCookbook'}, + :child => { :tag => 'ul', + :descendant => { :tag => 'a', + :content => 'Child of private child' + } + } + } + + assert_no_tag :a, :content => /Private child of eCookbook/ + end + + def test_index_atom + get :index, :format => 'atom' + assert_response :success + assert_template 'common/feed.atom' + assert_select 'feed>title', :text => 'Redmine: Latest projects' + assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_condition(User.current)) + end + + context "#index" do + context "by non-admin user with view_time_entries permission" do + setup do + @request.session[:user_id] = 3 + end + should "show overall spent time link" do + get :index + assert_template 'index' + assert_tag :a, :attributes => {:href => '/time_entries'} + end + end + + context "by non-admin user without view_time_entries permission" do + setup do + Role.find(2).remove_permission! :view_time_entries + Role.non_member.remove_permission! :view_time_entries + Role.anonymous.remove_permission! :view_time_entries + @request.session[:user_id] = 3 + end + should "not show overall spent time link" do + get :index + assert_template 'index' + assert_no_tag :a, :attributes => {:href => '/time_entries'} + end + end + end + + context "#new" do + context "by admin user" do + setup do + @request.session[:user_id] = 1 + end + + should "accept get" do + get :new + assert_response :success + assert_template 'new' + end + + end + + context "by non-admin user with add_project permission" do + setup do + Role.non_member.add_permission! :add_project + @request.session[:user_id] = 9 + end + + should "accept get" do + get :new + assert_response :success + assert_template 'new' + assert_no_tag :select, :attributes => {:name => 'project[parent_id]'} + end + end + + context "by non-admin user with add_subprojects permission" do + setup do + Role.find(1).remove_permission! :add_project + Role.find(1).add_permission! :add_subprojects + @request.session[:user_id] = 2 + end + + should "accept get" do + get :new, :parent_id => 'ecookbook' + assert_response :success + assert_template 'new' + # parent project selected + assert_tag :select, :attributes => {:name => 'project[parent_id]'}, + :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}} + # no empty value + assert_no_tag :select, :attributes => {:name => 'project[parent_id]'}, + :child => {:tag => 'option', :attributes => {:value => ''}} + end + end + + end + + context "POST :create" do + context "by admin user" do + setup do + @request.session[:user_id] = 1 + end + + should "create a new project" do + post :create, + :project => { + :name => "blog", + :description => "weblog", + :homepage => 'http://weblog', + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' }, + :tracker_ids => ['1', '3'], + # an issue custom field that is not for all project + :issue_custom_field_ids => ['9'], + :enabled_module_names => ['issue_tracking', 'news', 'repository'] + } + assert_redirected_to '/projects/blog/settings' + + project = Project.find_by_name('blog') + assert_kind_of Project, project + assert project.active? + assert_equal 'weblog', project.description + assert_equal 'http://weblog', project.homepage + assert_equal true, project.is_public? + assert_nil project.parent + assert_equal 'Beta', project.custom_value_for(3).value + assert_equal [1, 3], project.trackers.map(&:id).sort + assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort + assert project.issue_custom_fields.include?(IssueCustomField.find(9)) + end + + should "create a new subproject" do + post :create, :project => { :name => "blog", + :description => "weblog", + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' }, + :parent_id => 1 + } + assert_redirected_to '/projects/blog/settings' + + project = Project.find_by_name('blog') + assert_kind_of Project, project + assert_equal Project.find(1), project.parent + end + + should "continue" do + assert_difference 'Project.count' do + post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue' + end + assert_redirected_to '/projects/new?' + end + end + + context "by non-admin user with add_project permission" do + setup do + Role.non_member.add_permission! :add_project + @request.session[:user_id] = 9 + end + + should "accept create a Project" do + post :create, :project => { :name => "blog", + :description => "weblog", + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' }, + :tracker_ids => ['1', '3'], + :enabled_module_names => ['issue_tracking', 'news', 'repository'] + } + + assert_redirected_to '/projects/blog/settings' + + project = Project.find_by_name('blog') + assert_kind_of Project, project + assert_equal 'weblog', project.description + assert_equal true, project.is_public? + assert_equal [1, 3], project.trackers.map(&:id).sort + assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort + + # User should be added as a project member + assert User.find(9).member_of?(project) + assert_equal 1, project.members.size + end + + should "fail with parent_id" do + assert_no_difference 'Project.count' do + post :create, :project => { :name => "blog", + :description => "weblog", + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' }, + :parent_id => 1 + } + end + assert_response :success + project = assigns(:project) + assert_kind_of Project, project + assert_not_nil project.errors[:parent_id] + end + end + + context "by non-admin user with add_subprojects permission" do + setup do + Role.find(1).remove_permission! :add_project + Role.find(1).add_permission! :add_subprojects + @request.session[:user_id] = 2 + end + + should "create a project with a parent_id" do + post :create, :project => { :name => "blog", + :description => "weblog", + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' }, + :parent_id => 1 + } + assert_redirected_to '/projects/blog/settings' + project = Project.find_by_name('blog') + end + + should "fail without parent_id" do + assert_no_difference 'Project.count' do + post :create, :project => { :name => "blog", + :description => "weblog", + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' } + } + end + assert_response :success + project = assigns(:project) + assert_kind_of Project, project + assert_not_nil project.errors[:parent_id] + end + + should "fail with unauthorized parent_id" do + assert !User.find(2).member_of?(Project.find(6)) + assert_no_difference 'Project.count' do + post :create, :project => { :name => "blog", + :description => "weblog", + :identifier => "blog", + :is_public => 1, + :custom_field_values => { '3' => 'Beta' }, + :parent_id => 6 + } + end + assert_response :success + project = assigns(:project) + assert_kind_of Project, project + assert_not_nil project.errors[:parent_id] + end + end + end + + def test_create_should_preserve_modules_on_validation_failure + with_settings :default_projects_modules => ['issue_tracking', 'repository'] do + @request.session[:user_id] = 1 + assert_no_difference 'Project.count' do + post :create, :project => { + :name => "blog", + :identifier => "", + :enabled_module_names => %w(issue_tracking news) + } + end + assert_response :success + project = assigns(:project) + assert_equal %w(issue_tracking news), project.enabled_module_names.sort + end + end + + def test_create_should_not_accept_get + @request.session[:user_id] = 1 + get :create + assert_response :method_not_allowed + end + + def test_show_by_id + get :show, :id => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:project) + end + + def test_show_by_identifier + get :show, :id => 'ecookbook' + assert_response :success + assert_template 'show' + assert_not_nil assigns(:project) + assert_equal Project.find_by_identifier('ecookbook'), assigns(:project) + + assert_tag 'li', :content => /Development status/ + end + + def test_show_should_not_display_hidden_custom_fields + ProjectCustomField.find_by_name('Development status').update_attribute :visible, false + get :show, :id => 'ecookbook' + assert_response :success + assert_template 'show' + assert_not_nil assigns(:project) + + assert_no_tag 'li', :content => /Development status/ + end + + def test_show_should_not_fail_when_custom_values_are_nil + project = Project.find_by_identifier('ecookbook') + project.custom_values.first.update_attribute(:value, nil) + get :show, :id => 'ecookbook' + assert_response :success + assert_template 'show' + assert_not_nil assigns(:project) + assert_equal Project.find_by_identifier('ecookbook'), assigns(:project) + end + + def show_archived_project_should_be_denied + project = Project.find_by_identifier('ecookbook') + project.archive! + + get :show, :id => 'ecookbook' + assert_response 403 + assert_nil assigns(:project) + assert_tag :tag => 'p', :content => /archived/ + end + + def test_private_subprojects_hidden + get :show, :id => 'ecookbook' + assert_response :success + assert_template 'show' + assert_no_tag :tag => 'a', :content => /Private child/ + end + + def test_private_subprojects_visible + @request.session[:user_id] = 2 # manager who is a member of the private subproject + get :show, :id => 'ecookbook' + assert_response :success + assert_template 'show' + assert_tag :tag => 'a', :content => /Private child/ + end + + def test_settings + @request.session[:user_id] = 2 # manager + get :settings, :id => 1 + assert_response :success + assert_template 'settings' + end + + def test_update + @request.session[:user_id] = 2 # manager + post :update, :id => 1, :project => {:name => 'Test changed name', + :issue_custom_field_ids => ['']} + assert_redirected_to '/projects/ecookbook/settings' + project = Project.find(1) + assert_equal 'Test changed name', project.name + end + + def test_modules + @request.session[:user_id] = 2 + Project.find(1).enabled_module_names = ['issue_tracking', 'news'] + + post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents'] + assert_redirected_to '/projects/ecookbook/settings/modules' + assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort + end + + def test_modules_should_not_allow_get + @request.session[:user_id] = 1 + get :modules, :id => 1 + assert_response :method_not_allowed + end + + def test_get_destroy + @request.session[:user_id] = 1 # admin + get :destroy, :id => 1 + assert_response :success + assert_template 'destroy' + assert_not_nil Project.find_by_id(1) + end + + def test_post_destroy + @request.session[:user_id] = 1 # admin + post :destroy, :id => 1, :confirm => 1 + assert_redirected_to '/admin/projects' + assert_nil Project.find_by_id(1) + end + + def test_archive + @request.session[:user_id] = 1 # admin + post :archive, :id => 1 + assert_redirected_to '/admin/projects' + assert !Project.find(1).active? + end + + def test_unarchive + @request.session[:user_id] = 1 # admin + Project.find(1).archive + post :unarchive, :id => 1 + assert_redirected_to '/admin/projects' + assert Project.find(1).active? + end + + def test_project_breadcrumbs_should_be_limited_to_3_ancestors + CustomField.delete_all + parent = nil + 6.times do |i| + p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}") + p.set_parent!(parent) + get :show, :id => p + assert_tag :h1, :parent => { :attributes => {:id => 'header'}}, + :children => { :count => [i, 3].min, + :only => { :tag => 'a' } } + + parent = p + end + end + + def test_get_copy + @request.session[:user_id] = 1 # admin + get :copy, :id => 1 + assert_response :success + assert_template 'copy' + assert assigns(:project) + assert_equal Project.find(1).description, assigns(:project).description + assert_nil assigns(:project).id + + assert_tag :tag => 'input', + :attributes => {:name => 'project[enabled_module_names][]', :value => 'issue_tracking'} + end + + def test_get_copy_without_project + @request.session[:user_id] = 1 # admin + get :copy + assert_response :redirect + assert_redirected_to :controller => 'admin', :action => 'projects' + end + + def test_post_copy_should_copy_requested_items + @request.session[:user_id] = 1 # admin + CustomField.delete_all + + assert_difference 'Project.count' do + post :copy, :id => 1, + :project => { + :name => 'Copy', + :identifier => 'unique-copy', + :tracker_ids => ['1', '2', '3', ''], + :enabled_module_names => %w(issue_tracking time_tracking) + }, + :only => %w(issues versions) + end + project = Project.find('unique-copy') + source = Project.find(1) + assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort + + assert_equal source.versions.count, project.versions.count, "All versions were not copied" + # issues assigned to a closed version won't be copied + assert_equal source.issues.select {|i| i.fixed_version.nil? || i.fixed_version.open?}.size, + project.issues.count, "All issues were not copied" + assert_equal 0, project.members.count + end + + def test_post_copy_should_redirect_to_settings_when_successful + @request.session[:user_id] = 1 # admin + post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'} + assert_response :redirect + assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy' + end + + def test_jump_should_redirect_to_active_tab + get :show, :id => 1, :jump => 'issues' + assert_redirected_to '/projects/ecookbook/issues' + end + + def test_jump_should_not_redirect_to_inactive_tab + get :show, :id => 3, :jump => 'documents' + assert_response :success + assert_template 'show' + end + + def test_jump_should_not_redirect_to_unknown_tab + get :show, :id => 3, :jump => 'foobar' + assert_response :success + assert_template 'show' + end + + # A hook that is manually registered later + class ProjectBasedTemplate < Redmine::Hook::ViewListener + def view_layouts_base_html_head(context) + # Adds a project stylesheet + stylesheet_link_tag(context[:project].identifier) if context[:project] + end + end + # Don't use this hook now + Redmine::Hook.clear_listeners + + def test_hook_response + Redmine::Hook.add_listener(ProjectBasedTemplate) + get :show, :id => 1 + assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'}, + :parent => {:tag => 'head'} + + Redmine::Hook.clear_listeners + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/44/449222a50e6cb8714622770c05bae7166ee2e543.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/44/449222a50e6cb8714622770c05bae7166ee2e543.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToJournals < ActiveRecord::Migration + def self.up + add_index :journals, :user_id + add_index :journals, :journalized_id + end + + def self.down + remove_index :journals, :user_id + remove_index :journals, :journalized_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/44/44d79a17ffe7c2b64a23af9018ae26f5e13961e3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/44/44d79a17ffe7c2b64a23af9018ae26f5e13961e3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +<% form_tag({:action => 'edit', :tab => 'issues'}) do %> + +
+

<%= setting_check_box :cross_project_issue_relations %>

+ +

<%= setting_check_box :issue_group_assignment %>

+ +

<%= setting_check_box :default_issue_start_date_to_creation_date %>

+ +

<%= setting_check_box :display_subprojects_issues %>

+ +

<%= setting_select :issue_done_ratio, Issue::DONE_RATIO_OPTIONS.collect {|i| [l("setting_issue_done_ratio_#{i}"), i]} %>

+ +

<%= setting_text_field :issues_export_limit, :size => 6 %>

+ +

<%= setting_text_field :gantt_items_limit, :size => 6 %>

+
+ +
<%= l(:setting_issue_list_default_columns) %> +<%= setting_multiselect(:issue_list_default_columns, + Query.new.available_columns.collect {|c| [c.caption, c.name.to_s]}, :label => false) %> +
+ +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/451613f5e947795f045fad0d3c035a4d108e9d4d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/451613f5e947795f045fad0d3c035a4d108e9d4d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1020 @@ +html {overflow-y:scroll;} +body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } + +h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;} +h1 {margin:0; padding:0; font-size: 24px;} +h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;} +h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;} +h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;} + +/***** Layout *****/ +#wrapper {background: white;} + +#top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;} +#top-menu ul {margin: 0; padding: 0;} +#top-menu li { + float:left; + list-style-type:none; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + white-space:nowrap; +} +#top-menu a {color: #fff; margin-right: 8px; font-weight: bold;} +#top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } + +#account {float:right;} + +#header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;} +#header a {color:#f8f8f8;} +#header h1 a.ancestor { font-size: 80%; } +#quick-search {float:right;} + +#main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;} +#main-menu ul {margin: 0; padding: 0;} +#main-menu li { + float:left; + list-style-type:none; + margin: 0px 2px 0px 0px; + padding: 0px 0px 0px 0px; + white-space:nowrap; +} +#main-menu li a { + display: block; + color: #fff; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 4px 10px 4px 10px; +} +#main-menu li a:hover {background:#759FCF; color:#fff;} +#main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;} + +#admin-menu ul {margin: 0; padding: 0;} +#admin-menu li {margin: 0; padding: 0 0 12px 0; list-style-type:none;} + +#admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;} +#admin-menu a.projects { background-image: url(../images/projects.png); } +#admin-menu a.users { background-image: url(../images/user.png); } +#admin-menu a.groups { background-image: url(../images/group.png); } +#admin-menu a.roles { background-image: url(../images/database_key.png); } +#admin-menu a.trackers { background-image: url(../images/ticket.png); } +#admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); } +#admin-menu a.workflows { background-image: url(../images/ticket_go.png); } +#admin-menu a.custom_fields { background-image: url(../images/textfield.png); } +#admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); } +#admin-menu a.settings { background-image: url(../images/changeset.png); } +#admin-menu a.plugins { background-image: url(../images/plugin.png); } +#admin-menu a.info { background-image: url(../images/help.png); } +#admin-menu a.server_authentication { background-image: url(../images/server_key.png); } + +#main {background-color:#EEEEEE;} + +#sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;} +* html #sidebar{ width: 22%; } +#sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } +#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } +* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } +#sidebar .contextual { margin-right: 1em; } + +#content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } +* html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} +html>body #content { min-height: 600px; } +* html body #content { height: 600px; } /* IE */ + +#main.nosidebar #sidebar{ display: none; } +#main.nosidebar #content{ width: auto; border-right: 0; } + +#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} + +#login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } +#login-form table td {padding: 6px;} +#login-form label {font-weight: bold;} +#login-form input#username, #login-form input#password { width: 300px; } + +#modalbg {position:absolute; top:0; left:0; width:100%; height:100%; background:#ccc; z-index:49; opacity:0.5;} +html>body #modalbg {position:fixed;} +div.modal { border-radius:5px; position:absolute; top:25%; background:#fff; border:2px solid #759FCF; z-index:50; padding:0px; padding:8px;} +div.modal h3.title {background:#759FCF; color:#fff; border:0; padding-left:8px; margin:-8px; margin-bottom: 1em; border-top-left-radius:2px;border-top-right-radius:2px;} +div.modal p.buttons {text-align:right; margin-bottom:0;} +html>body div.modal {position:fixed;} + +input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } + +.clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } + +/***** Links *****/ +a, a:link, a:visited{ color: #2A5685; text-decoration: none; } +a:hover, a:active{ color: #c61a1a; text-decoration: underline;} +a img{ border: 0; } + +a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; } + +/***** Tables *****/ +table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } +table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } +table.list td { vertical-align: top; } +table.list td.id { width: 2%; text-align: center;} +table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } +table.list td.checkbox input {padding:0px;} +table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; } +table.list td.buttons a { padding-right: 0.6em; } +table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; } + +tr.project td.name a { white-space:nowrap; } + +tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.project.idnt-1 td.name {padding-left: 0.5em;} +tr.project.idnt-2 td.name {padding-left: 2em;} +tr.project.idnt-3 td.name {padding-left: 3.5em;} +tr.project.idnt-4 td.name {padding-left: 5em;} +tr.project.idnt-5 td.name {padding-left: 6.5em;} +tr.project.idnt-6 td.name {padding-left: 8em;} +tr.project.idnt-7 td.name {padding-left: 9.5em;} +tr.project.idnt-8 td.name {padding-left: 11em;} +tr.project.idnt-9 td.name {padding-left: 12.5em;} + +tr.issue { text-align: center; white-space: nowrap; } +tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text { white-space: normal; } +tr.issue td.subject { text-align: left; } +tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} + +tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.issue.idnt-1 td.subject {padding-left: 0.5em;} +tr.issue.idnt-2 td.subject {padding-left: 2em;} +tr.issue.idnt-3 td.subject {padding-left: 3.5em;} +tr.issue.idnt-4 td.subject {padding-left: 5em;} +tr.issue.idnt-5 td.subject {padding-left: 6.5em;} +tr.issue.idnt-6 td.subject {padding-left: 8em;} +tr.issue.idnt-7 td.subject {padding-left: 9.5em;} +tr.issue.idnt-8 td.subject {padding-left: 11em;} +tr.issue.idnt-9 td.subject {padding-left: 12.5em;} + +tr.entry { border: 1px solid #f8f8f8; } +tr.entry td { white-space: nowrap; } +tr.entry td.filename { width: 30%; } +tr.entry td.filename_no_report { width: 70%; } +tr.entry td.size { text-align: right; font-size: 90%; } +tr.entry td.revision, tr.entry td.author { text-align: center; } +tr.entry td.age { text-align: right; } +tr.entry.file td.filename a { margin-left: 16px; } +tr.entry.file td.filename_no_report a { margin-left: 16px; } + +tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} +tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} + +tr.changeset { height: 20px } +tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } +tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } +tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.comments_nowrap { width: 45%; white-space:nowrap;} + +table.files tr.file td { text-align: center; } +table.files tr.file td.filename { text-align: left; padding-left: 24px; } +table.files tr.file td.digest { font-size: 80%; } + +table.members td.roles, table.memberships td.roles { width: 45%; } + +tr.message { height: 2.6em; } +tr.message td.subject { padding-left: 20px; } +tr.message td.created_on { white-space: nowrap; } +tr.message td.last_message { font-size: 80%; white-space: nowrap; } +tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; } +tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; } + +tr.version.closed, tr.version.closed a { color: #999; } +tr.version td.name { padding-left: 20px; } +tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; } +tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; } + +tr.user td { width:13%; } +tr.user td.email { width:18%; } +tr.user td { white-space: nowrap; } +tr.user.locked, tr.user.registered { color: #aaa; } +tr.user.locked a, tr.user.registered a { color: #aaa; } + +tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;} + +tr.time-entry { text-align: center; white-space: nowrap; } +tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; } +td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } +td.hours .hours-dec { font-size: 0.9em; } + +table.plugins td { vertical-align: middle; } +table.plugins td.configure { text-align: right; padding-right: 1em; } +table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } +table.plugins span.description { display: block; font-size: 0.9em; } +table.plugins span.url { display: block; font-size: 0.9em; } + +table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; } +table.list tbody tr.group span.count { color: #aaa; font-size: 80%; } +tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;} +tr.group:hover a.toggle-all { display:inline;} +a.toggle-all:hover {text-decoration:none;} + +table.list tbody tr:hover { background-color:#ffffdd; } +table.list tbody tr.group:hover { background-color:inherit; } +table td {padding:2px;} +table p {margin:0;} +.odd {background-color:#f6f7f8;} +.even {background-color: #fff;} + +a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; } +a.sort.asc { background-image: url(../images/sort_asc.png); } +a.sort.desc { background-image: url(../images/sort_desc.png); } + +table.attributes { width: 100% } +table.attributes th { vertical-align: top; text-align: left; } +table.attributes td { vertical-align: top; } + +table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; } + +td.center {text-align:center;} + +h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; } + +div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; } +div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; } +div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; } +div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; } + +#watchers ul {margin: 0; padding: 0;} +#watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;} +#watchers select {width: 95%; display: block;} +#watchers a.delete {opacity: 0.4;} +#watchers a.delete:hover {opacity: 1;} +#watchers img.gravatar {vertical-align: middle;margin: 0 4px 2px 0;} + +.highlight { background-color: #FCFD8D;} +.highlight.token-1 { background-color: #faa;} +.highlight.token-2 { background-color: #afa;} +.highlight.token-3 { background-color: #aaf;} + +.box{ +padding:6px; +margin-bottom: 10px; +background-color:#f6f6f6; +color:#505050; +line-height:1.5em; +border: 1px solid #e4e4e4; +} + +div.square { + border: 1px solid #999; + float: left; + margin: .3em .4em 0 .4em; + overflow: hidden; + width: .6em; height: .6em; +} +.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} +.contextual input, .contextual select {font-size:0.9em;} +.message .contextual { margin-top: 0; } + +.splitcontentleft{float:left; width:49%;} +.splitcontentright{float:right; width:49%;} +form {display: inline;} +input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} +fieldset {border: 1px solid #e4e4e4; margin:0;} +legend {color: #484848;} +hr { width: 100%; height: 1px; background: #ccc; border: 0;} +blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;} +blockquote blockquote { margin-left: 0;} +acronym { border-bottom: 1px dotted; cursor: help; } +textarea.wiki-edit { width: 99%; } +li p {margin-top: 0;} +div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} +p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} +p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } +p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } + +div.issue div.subject div div { padding-left: 16px; } +div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;} +div.issue div.subject>div>p { margin-top: 0.5em; } +div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} +div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px; -moz-border-radius: 2px;} + +#issue_tree table.issues, #relations table.issues { border: 0; } +#issue_tree td.checkbox, #relations td.checkbox {display:none;} +#relations td.buttons {padding:0;} + +fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; } +fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; } +fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); } + +fieldset#date-range p { margin: 2px 0 2px 0; } +fieldset#filters table { border-collapse: collapse; } +fieldset#filters table td { padding: 0; vertical-align: middle; } +fieldset#filters tr.filter { height: 2em; } +fieldset#filters td.field { width:200px; } +fieldset#filters td.operator { width:170px; } +fieldset#filters td.values { white-space:nowrap; } +fieldset#filters td.values img { vertical-align: bottom; } +fieldset#filters td.add-filter { text-align: right; vertical-align: top; } +.buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } + +div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} +div#issue-changesets div.changeset { padding: 4px;} +div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } +div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} + +div#activity dl, #search-results { margin-left: 2em; } +div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } +div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } +div#activity dt.me .time { border-bottom: 1px solid #999; } +div#activity dt .time { color: #777; font-size: 80%; } +div#activity dd .description, #search-results dd .description { font-style: italic; } +div#activity span.project:after, #search-results span.project:after { content: " -"; } +div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } + +#search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } + +div#search-results-counts {float:right;} +div#search-results-counts ul { margin-top: 0.5em; } +div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } + +dt.issue { background-image: url(../images/ticket.png); } +dt.issue-edit { background-image: url(../images/ticket_edit.png); } +dt.issue-closed { background-image: url(../images/ticket_checked.png); } +dt.issue-note { background-image: url(../images/ticket_note.png); } +dt.changeset { background-image: url(../images/changeset.png); } +dt.news { background-image: url(../images/news.png); } +dt.message { background-image: url(../images/message.png); } +dt.reply { background-image: url(../images/comments.png); } +dt.wiki-page { background-image: url(../images/wiki_edit.png); } +dt.attachment { background-image: url(../images/attachment.png); } +dt.document { background-image: url(../images/document.png); } +dt.project { background-image: url(../images/projects.png); } +dt.time-entry { background-image: url(../images/time.png); } + +#search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } + +div#roadmap .related-issues { margin-bottom: 1em; } +div#roadmap .related-issues td.checkbox { display: none; } +div#roadmap .wiki h1:first-child { display: none; } +div#roadmap .wiki h1 { font-size: 120%; } +div#roadmap .wiki h2 { font-size: 110%; } +body.controller-versions.action-show div#roadmap .related-issues {width:auto;} + +div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } +div#version-summary fieldset { margin-bottom: 1em; } +div#version-summary .total-hours { text-align: right; } + +table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; } +table#time-report tbody tr { font-style: italic; color: #777; } +table#time-report tbody tr.last-level { font-style: normal; color: #555; } +table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; } +table#time-report .hours-dec { font-size: 0.9em; } + +div.wiki-page .contextual a {opacity: 0.4} +div.wiki-page .contextual a:hover {opacity: 1} + +form .attributes select { width: 60%; } +input#issue_subject { width: 99%; } +select#issue_done_ratio { width: 95px; } + +ul.projects { margin: 0; padding-left: 1em; } +ul.projects.root { margin: 0; padding: 0; } +ul.projects ul.projects { border-left: 3px solid #e0e0e0; } +ul.projects li.root { list-style-type:none; margin-bottom: 1em; } +ul.projects li.child { list-style-type:none; margin-top: 1em;} +ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } +.my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } + +#tracker_project_ids ul { margin: 0; padding-left: 1em; } +#tracker_project_ids li { list-style-type:none; } + +ul.properties {padding:0; font-size: 0.9em; color: #777;} +ul.properties li {list-style-type:none;} +ul.properties li span {font-style:italic;} + +.total-hours { font-size: 110%; font-weight: bold; } +.total-hours span.hours-int { font-size: 120%; } + +.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} +#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; } + +#workflow_copy_form select { width: 200px; } + +textarea#custom_field_possible_values {width: 99%} + +.pagination {font-size: 90%} +p.pagination {margin-top:8px;} + +/***** Tabular forms ******/ +.tabular p{ +margin: 0; +padding: 3px 0 3px 0; +padding-left: 180px; /* width of left column containing the label elements */ +height: 1%; +clear:left; +} + +html>body .tabular p {overflow:hidden;} + +.tabular label{ +font-weight: bold; +float: left; +text-align: right; +/* width of left column */ +margin-left: -180px; +/* width of labels. Should be smaller than left column to create some right margin */ +width: 175px; +} + +.tabular label.floating{ +font-weight: normal; +margin-left: 0px; +text-align: left; +width: 270px; +} + +.tabular label.block{ +font-weight: normal; +margin-left: 0px !important; +text-align: left; +float: none; +display: block; +width: auto; +} + +.tabular label.inline{ +float:none; +margin-left: 5px !important; +width: auto; +} + +label.no-css { + font-weight: inherit; + float:none; + text-align:left; + margin-left:0px; + width:auto; +} +input#time_entry_comments { width: 90%;} + +#preview fieldset {margin-top: 1em; background: url(../images/draft.png)} + +.tabular.settings p{ padding-left: 300px; } +.tabular.settings label{ margin-left: -300px; width: 295px; } +.tabular.settings textarea { width: 99%; } + +.settings.enabled_scm table {width:100%} +.settings.enabled_scm td.scm_name{ font-weight: bold; } + +fieldset.settings label { display: block; } +fieldset#notified_events .parent { padding-left: 20px; } + +.required {color: #bb0000;} +.summary {font-style: italic;} + +#attachments_fields input[type=text] {margin-left: 8px; } +#attachments_fields span {display:block; white-space:nowrap;} +#attachments_fields img {vertical-align: middle;} + +div.attachments { margin-top: 12px; } +div.attachments p { margin:4px 0 2px 0; } +div.attachments img { vertical-align: middle; } +div.attachments span.author { font-size: 0.9em; color: #888; } + +p.other-formats { text-align: right; font-size:0.9em; color: #666; } +.other-formats span + span:before { content: "| "; } + +a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } + +/* Project members tab */ +div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% } +div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% } +div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; } +div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; } +div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; } +div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; } + +table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; } + +input#principal_search, input#user_search {width:100%} + +* html div#tab-content-members fieldset div { height: 450px; } + +/***** Flash & error messages ****/ +#errorExplanation, div.flash, .nodata, .warning { + padding: 4px 4px 4px 30px; + margin-bottom: 12px; + font-size: 1.1em; + border: 2px solid; +} + +div.flash {margin-top: 8px;} + +div.flash.error, #errorExplanation { + background: url(../images/exclamation.png) 8px 50% no-repeat; + background-color: #ffe3e3; + border-color: #dd0000; + color: #880000; +} + +div.flash.notice { + background: url(../images/true.png) 8px 5px no-repeat; + background-color: #dfffdf; + border-color: #9fcf9f; + color: #005f00; +} + +div.flash.warning { + background: url(../images/warning.png) 8px 5px no-repeat; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; + text-align: left; +} + +.nodata, .warning { + text-align: center; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; +} + +span.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} + +#errorExplanation ul { font-size: 0.9em;} +#errorExplanation h2, #errorExplanation p { display: none; } + +/***** Ajax indicator ******/ +#ajax-indicator { +position: absolute; /* fixed not supported by IE */ +background-color:#eee; +border: 1px solid #bbb; +top:35%; +left:40%; +width:20%; +font-weight:bold; +text-align:center; +padding:0.6em; +z-index:100; +opacity: 0.5; +} + +html>body #ajax-indicator { position: fixed; } + +#ajax-indicator span { +background-position: 0% 40%; +background-repeat: no-repeat; +background-image: url(../images/loading.gif); +padding-left: 26px; +vertical-align: bottom; +} + +/***** Calendar *****/ +table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;} +table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; } +table.cal thead th.week-number {width: auto;} +table.cal tbody tr {height: 100px;} +table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;} +table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;} +table.cal td p.day-num {font-size: 1.1em; text-align:right;} +table.cal td.odd p.day-num {color: #bbb;} +table.cal td.today {background:#ffffdd;} +table.cal td.today p.day-num {font-weight: bold;} +table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} +p.cal.legend span {display:block;} + +/***** Tooltips ******/ +.tooltip{position:relative;z-index:24;} +.tooltip:hover{z-index:25;color:#000;} +.tooltip span.tip{display: none; text-align:left;} + +div.tooltip:hover span.tip{ +display:block; +position:absolute; +top:12px; left:24px; width:270px; +border:1px solid #555; +background-color:#fff; +padding: 4px; +font-size: 0.8em; +color:#505050; +} + +/***** Progress bar *****/ +table.progress { + border: 1px solid #D7D7D7; + border-collapse: collapse; + border-spacing: 0pt; + empty-cells: show; + text-align: center; + float:left; + margin: 1px 6px 1px 0px; +} + +table.progress td { height: 0.9em; } +table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } +table.progress td.done { background: #DEF0DE none repeat scroll 0%; } +table.progress td.open { background: #FFF none repeat scroll 0%; } +p.pourcent {font-size: 80%;} +p.progress-info {clear: left; font-style: italic; font-size: 80%;} + +/***** Tabs *****/ +#content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} +#content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:1em; width: 2000px; border-bottom: 1px solid #bbbbbb;} +#content .tabs ul li { +float:left; +list-style-type:none; +white-space:nowrap; +margin-right:8px; +background:#fff; +position:relative; +margin-bottom:-1px; +} +#content .tabs ul li a{ +display:block; +font-size: 0.9em; +text-decoration:none; +line-height:1.3em; +padding:4px 6px 4px 6px; +border: 1px solid #ccc; +border-bottom: 1px solid #bbbbbb; +background-color: #eeeeee; +color:#777; +font-weight:bold; +} + +#content .tabs ul li a:hover { +background-color: #ffffdd; +text-decoration:none; +} + +#content .tabs ul li a.selected { +background-color: #fff; +border: 1px solid #bbbbbb; +border-bottom: 1px solid #fff; +} + +#content .tabs ul li a.selected:hover { +background-color: #fff; +} + +div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } + +button.tab-left, button.tab-right { + font-size: 0.9em; + cursor: pointer; + height:24px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + position:absolute; + padding:4px; + width: 20px; + bottom: -1px; +} + +button.tab-left { + right: 20px; + background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; +} + +button.tab-right { + right: 0; + background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; +} + +/***** Auto-complete *****/ +div.autocomplete { + position:absolute; + width:400px; + margin:0; + padding:0; +} +div.autocomplete ul { + list-style-type:none; + margin:0; + padding:0; +} +div.autocomplete ul li { + list-style-type:none; + display:block; + margin:-1px 0 0 0; + padding:2px; + cursor:pointer; + font-size: 90%; + border: 1px solid #ccc; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; + background-color:white; +} +div.autocomplete ul li.selected { background-color: #ffb;} +div.autocomplete ul li span.informal { + font-size: 80%; + color: #aaa; +} + +#parent_issue_candidates ul li {width: 500px;} +#related_issue_candidates ul li {width: 500px;} + +/***** Diff *****/ +.diff_out { background: #fcc; } +.diff_out span { background: #faa; } +.diff_in { background: #cfc; } +.diff_in span { background: #afa; } + +.text-diff { +padding: 1em; +background-color:#f6f6f6; +color:#505050; +border: 1px solid #e4e4e4; +} + +/***** Wiki *****/ +div.wiki table { + border: 1px solid #505050; + border-collapse: collapse; + margin-bottom: 1em; +} + +div.wiki table, div.wiki td, div.wiki th { + border: 1px solid #bbb; + padding: 4px; +} + +div.wiki .external { + background-position: 0% 60%; + background-repeat: no-repeat; + padding-left: 12px; + background-image: url(../images/external.png); +} + +div.wiki a.new { + color: #b73535; +} + +div.wiki ul, div.wiki ol {margin-bottom:1em;} + +div.wiki pre { + margin: 1em 1em 1em 1.6em; + padding: 2px 2px 2px 0; + background-color: #fafafa; + border: 1px solid #dadada; + width:auto; + overflow-x: auto; + overflow-y: hidden; +} + +div.wiki ul.toc { + background-color: #ffffdd; + border: 1px solid #e4e4e4; + padding: 4px; + line-height: 1.2em; + margin-bottom: 12px; + margin-right: 12px; + margin-left: 0; + display: table +} +* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */ + +div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; } +div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; } +div.wiki ul.toc ul { margin: 0; padding: 0; } +div.wiki ul.toc li { list-style-type:none; margin: 0;} +div.wiki ul.toc li li { margin-left: 1.5em; } +div.wiki ul.toc li li li { font-size: 0.8em; } + +div.wiki ul.toc a { + font-size: 0.9em; + font-weight: normal; + text-decoration: none; + color: #606060; +} +div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;} + +a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; } +a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } +h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } + +div.wiki img { vertical-align: middle; } + +/***** My page layout *****/ +.block-receiver { +border:1px dashed #c0c0c0; +margin-bottom: 20px; +padding: 15px 0 15px 0; +} + +.mypage-box { +margin:0 0 20px 0; +color:#505050; +line-height:1.5em; +} + +.handle { +cursor: move; +} + +a.close-icon { +display:block; +margin-top:3px; +overflow:hidden; +width:12px; +height:12px; +background-repeat: no-repeat; +cursor:pointer; +background-image:url('../images/close.png'); +} + +a.close-icon:hover { +background-image:url('../images/close_hl.png'); +} + +/***** Gantt chart *****/ +.gantt_hdr { + position:absolute; + top:0; + height:16px; + border-top: 1px solid #c0c0c0; + border-bottom: 1px solid #c0c0c0; + border-right: 1px solid #c0c0c0; + text-align: center; + overflow: hidden; +} + +.gantt_subjects { font-size: 0.8em; } +.gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } + +.task { + position: absolute; + height:8px; + font-size:0.8em; + color:#888; + padding:0; + margin:0; + line-height:16px; + white-space:nowrap; +} + +.task.label {width:100%;} +.task.label.project, .task.label.version { font-weight: bold; } + +.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } +.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } +.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } + +.task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} +.task_late.parent, .task_done.parent { height: 3px;} +.task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;} +.task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;} + +.version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.version-behind-schedule a, .issue-behind-schedule a {color: #f66914;} +.version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;} + +/***** Icons *****/ +.icon { +background-position: 0% 50%; +background-repeat: no-repeat; +padding-left: 20px; +padding-top: 2px; +padding-bottom: 3px; +} + +.icon-add { background-image: url(../images/add.png); } +.icon-edit { background-image: url(../images/edit.png); } +.icon-copy { background-image: url(../images/copy.png); } +.icon-duplicate { background-image: url(../images/duplicate.png); } +.icon-del { background-image: url(../images/delete.png); } +.icon-move { background-image: url(../images/move.png); } +.icon-save { background-image: url(../images/save.png); } +.icon-cancel { background-image: url(../images/cancel.png); } +.icon-multiple { background-image: url(../images/table_multiple.png); } +.icon-folder { background-image: url(../images/folder.png); } +.open .icon-folder { background-image: url(../images/folder_open.png); } +.icon-package { background-image: url(../images/package.png); } +.icon-user { background-image: url(../images/user.png); } +.icon-projects { background-image: url(../images/projects.png); } +.icon-help { background-image: url(../images/help.png); } +.icon-attachment { background-image: url(../images/attachment.png); } +.icon-history { background-image: url(../images/history.png); } +.icon-time { background-image: url(../images/time.png); } +.icon-time-add { background-image: url(../images/time_add.png); } +.icon-stats { background-image: url(../images/stats.png); } +.icon-warning { background-image: url(../images/warning.png); } +.icon-fav { background-image: url(../images/fav.png); } +.icon-fav-off { background-image: url(../images/fav_off.png); } +.icon-reload { background-image: url(../images/reload.png); } +.icon-lock { background-image: url(../images/locked.png); } +.icon-unlock { background-image: url(../images/unlock.png); } +.icon-checked { background-image: url(../images/true.png); } +.icon-details { background-image: url(../images/zoom_in.png); } +.icon-report { background-image: url(../images/report.png); } +.icon-comment { background-image: url(../images/comment.png); } +.icon-summary { background-image: url(../images/lightning.png); } +.icon-server-authentication { background-image: url(../images/server_key.png); } +.icon-issue { background-image: url(../images/ticket.png); } +.icon-zoom-in { background-image: url(../images/zoom_in.png); } +.icon-zoom-out { background-image: url(../images/zoom_out.png); } +.icon-passwd { background-image: url(../images/textfield_key.png); } + +.icon-file { background-image: url(../images/files/default.png); } +.icon-file.text-plain { background-image: url(../images/files/text.png); } +.icon-file.text-x-c { background-image: url(../images/files/c.png); } +.icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); } +.icon-file.text-x-php { background-image: url(../images/files/php.png); } +.icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); } +.icon-file.text-xml { background-image: url(../images/files/xml.png); } +.icon-file.image-gif { background-image: url(../images/files/image.png); } +.icon-file.image-jpeg { background-image: url(../images/files/image.png); } +.icon-file.image-png { background-image: url(../images/files/image.png); } +.icon-file.image-tiff { background-image: url(../images/files/image.png); } +.icon-file.application-pdf { background-image: url(../images/files/pdf.png); } +.icon-file.application-zip { background-image: url(../images/files/zip.png); } +.icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } + +img.gravatar { + padding: 2px; + border: solid 1px #d5d5d5; + background: #fff; +} + +div.issue img.gravatar { + float: right; + margin: 0 0 0 1em; + padding: 5px; +} + +div.issue table img.gravatar { + height: 14px; + width: 14px; + padding: 2px; + float: left; + margin: 0 0.5em 0 0; +} + +h2 img.gravatar { + padding: 3px; + margin: -2px 4px -4px 0; + vertical-align: top; +} + +h4 img.gravatar { + padding: 3px; + margin: -6px 0 -4px 0; + vertical-align: top; +} + +td.username img.gravatar { + margin: 0 0.5em 0 0; + vertical-align: top; +} + +#activity dt img.gravatar { + float: left; + margin: 0 1em 1em 0; +} + +/* Used on 12px Gravatar img tags without the icon background */ +.icon-gravatar { + float: left; + margin-right: 4px; +} + +#activity dt, +.journal { + clear: left; +} + +.journal-link { + float: right; +} + +h2 img { vertical-align:middle; } + +.hascontextmenu { cursor: context-menu; } + +/***** Media print specific styles *****/ +@media print { + #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } + #main { background: #fff; } + #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} + #wiki_add_attachment { display:none; } + .hide-when-print { display: none; } + .autoscroll {overflow-x: visible;} + table.list {margin-top:0.5em;} + table.list th, table.list td {border: 1px solid #aaa;} +} + +/* Accessibility specific styles */ +.hidden-for-sighted { + position:absolute; + left:-10000px; + top:auto; + width:1px; + height:1px; + overflow:hidden; +} diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/4541853cf8b57a89416ab78d9c5650a0f0ed5774.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/4541853cf8b57a89416ab78d9c5650a0f0ed5774.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class AppAndPluginController < ApplicationController + def an_action + render_class_and_action 'from beta_plugin' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/45449e749880a66ea8408df45e3c59692469e462.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/45449e749880a66ea8408df45e3c59692469e462.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fet'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Understreking'; +jsToolBar.strings['Deleted'] = 'Slettet'; +jsToolBar.strings['Code'] = 'Kode'; +jsToolBar.strings['Heading 1'] = 'Overskrift 1'; +jsToolBar.strings['Heading 2'] = 'Overskrift 2'; +jsToolBar.strings['Heading 3'] = 'Overskrift 3'; +jsToolBar.strings['Unordered list'] = 'Punktliste'; +jsToolBar.strings['Ordered list'] = 'Nummerert liste'; +jsToolBar.strings['Quote'] = 'Sitat'; +jsToolBar.strings['Unquote'] = 'Avslutt sitat'; +jsToolBar.strings['Preformatted text'] = 'Preformatert tekst'; +jsToolBar.strings['Wiki link'] = 'Lenke til Wiki-side'; +jsToolBar.strings['Image'] = 'Bilde'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/455894853af15224c178defd4436e0297eee3c97.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/455894853af15224c178defd4436e0297eee3c97.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,258 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 + # Class used to parse unified diffs + class UnifiedDiff < Array + attr_reader :diff_type + + def initialize(diff, options={}) + options.assert_valid_keys(:type, :max_lines) + diff = diff.split("\n") if diff.is_a?(String) + @diff_type = options[:type] || 'inline' + lines = 0 + @truncated = false + diff_table = DiffTable.new(@diff_type) + diff.each do |line| + line_encoding = nil + if line.respond_to?(:force_encoding) + line_encoding = line.encoding + # TODO: UTF-16 and Japanese CP932 which is imcompatible with ASCII + # In Japan, diffrence between file path encoding + # and file contents encoding is popular. + line.force_encoding('ASCII-8BIT') + end + unless diff_table.add_line line + line.force_encoding(line_encoding) if line_encoding + self << diff_table if diff_table.length > 0 + diff_table = DiffTable.new(diff_type) + end + lines += 1 + if options[:max_lines] && lines > options[:max_lines] + @truncated = true + break + end + end + self << diff_table unless diff_table.empty? + self + end + + def truncated?; @truncated; end + end + + # Class that represents a file diff + class DiffTable < Array + attr_reader :file_name + + # Initialize with a Diff file and the type of Diff View + # The type view must be inline or sbs (side_by_side) + def initialize(type="inline") + @parsing = false + @added = 0 + @removed = 0 + @type = type + end + + # Function for add a line of this Diff + # Returns false when the diff ends + def add_line(line) + unless @parsing + if line =~ /^(---|\+\+\+) (.*)$/ + @file_name = $2 + elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ + @line_num_l = $2.to_i + @line_num_r = $5.to_i + @parsing = true + end + else + if line =~ /^[^\+\-\s@\\]/ + @parsing = false + return false + elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ + @line_num_l = $2.to_i + @line_num_r = $5.to_i + else + parse_line(line, @type) + end + end + return true + end + + def each_line + prev_line_left, prev_line_right = nil, nil + each do |line| + spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left+1) && (line.nb_line_right != prev_line_right+1) + yield spacing, line + prev_line_left = line.nb_line_left.to_i if line.nb_line_left.to_i > 0 + prev_line_right = line.nb_line_right.to_i if line.nb_line_right.to_i > 0 + end + end + + def inspect + puts '### DIFF TABLE ###' + puts "file : #{file_name}" + self.each do |d| + d.inspect + end + end + + private + + # Escape the HTML for the diff + def escapeHTML(line) + CGI.escapeHTML(line) + end + + def diff_for_added_line + if @type == 'sbs' && @removed > 0 && @added < @removed + self[-(@removed - @added)] + else + diff = Diff.new + self << diff + diff + end + end + + def parse_line(line, type="inline") + if line[0, 1] == "+" + diff = diff_for_added_line + diff.line_right = escapeHTML line[1..-1] + diff.nb_line_right = @line_num_r + diff.type_diff_right = 'diff_in' + @line_num_r += 1 + @added += 1 + true + elsif line[0, 1] == "-" + diff = Diff.new + diff.line_left = escapeHTML line[1..-1] + diff.nb_line_left = @line_num_l + diff.type_diff_left = 'diff_out' + self << diff + @line_num_l += 1 + @removed += 1 + true + else + write_offsets + if line[0, 1] =~ /\s/ + diff = Diff.new + diff.line_right = escapeHTML line[1..-1] + diff.nb_line_right = @line_num_r + diff.line_left = escapeHTML line[1..-1] + diff.nb_line_left = @line_num_l + self << diff + @line_num_l += 1 + @line_num_r += 1 + true + elsif line[0, 1] = "\\" + true + else + false + end + end + end + + def write_offsets + if @added > 0 && @added == @removed + @added.times do |i| + line = self[-(1 + i)] + removed = (@type == 'sbs') ? line : self[-(1 + @added + i)] + offsets = offsets(removed.line_left, line.line_right) + removed.offsets = line.offsets = offsets + end + end + @added = 0 + @removed = 0 + end + + def offsets(line_left, line_right) + if line_left.present? && line_right.present? && line_left != line_right + max = [line_left.size, line_right.size].min + starting = 0 + while starting < max && line_left[starting] == line_right[starting] + starting += 1 + end + ending = -1 + while ending >= -(max - starting) && line_left[ending] == line_right[ending] + ending -= 1 + end + unless starting == 0 && ending == -1 + [starting, ending] + end + end + end + end + + # A line of diff + class Diff + attr_accessor :nb_line_left + attr_accessor :line_left + attr_accessor :nb_line_right + attr_accessor :line_right + attr_accessor :type_diff_right + attr_accessor :type_diff_left + attr_accessor :offsets + + def initialize() + self.nb_line_left = '' + self.nb_line_right = '' + self.line_left = '' + self.line_right = '' + self.type_diff_right = '' + self.type_diff_left = '' + end + + def type_diff + type_diff_right == 'diff_in' ? type_diff_right : type_diff_left + end + + def line + type_diff_right == 'diff_in' ? line_right : line_left + end + + def html_line_left + if offsets + line_left.dup.insert(offsets.first, '').insert(offsets.last, '') + else + line_left + end + end + + def html_line_right + if offsets + line_right.dup.insert(offsets.first, '').insert(offsets.last, '') + else + line_right + end + end + + def html_line + if offsets + line.dup.insert(offsets.first, '').insert(offsets.last, '') + else + line + end + end + + def inspect + puts '### Start Line Diff ###' + puts self.nb_line_left + puts self.line_left + puts self.nb_line_right + puts self.line_right + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/456ef3443ff7df8c5dc761c97f3f05ad3eb5ac25.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/456ef3443ff7df8c5dc761c97f3f05ad3eb5ac25.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,101 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) + +class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase + include ApplicationHelper + include ActionView::Helpers::TextHelper + include ActionView::Helpers::SanitizeHelper + extend ActionView::Helpers::SanitizeHelper::ClassMethods + + fixtures :projects, :roles, :enabled_modules, :users, + :repositories, :changesets, + :trackers, :issue_statuses, :issues, + :versions, :documents, + :wikis, :wiki_pages, :wiki_contents, + :boards, :messages, + :attachments + + def setup + super + @project = nil + end + + def teardown + end + + def test_macro_hello_world + text = "{{hello_world}}" + assert textilizable(text).match(/Hello world!/) + # escaping + text = "!{{hello_world}}" + assert_equal '

{{hello_world}}

', textilizable(text) + end + + def test_macro_include + @project = Project.find(1) + # include a page of the current project wiki + text = "{{include(Another page)}}" + assert textilizable(text).match(/This is a link to a ticket/) + + @project = nil + # include a page of a specific project wiki + text = "{{include(ecookbook:Another page)}}" + assert textilizable(text).match(/This is a link to a ticket/) + + text = "{{include(ecookbook:)}}" + assert textilizable(text).match(/CookBook documentation/) + + text = "{{include(unknowidentifier:somepage)}}" + assert textilizable(text).match(/Page not found/) + end + + def test_macro_child_pages + expected = "

\n

" + + @project = Project.find(1) + # child pages of the current wiki page + assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content) + # child pages of another page + assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content) + + @project = Project.find(2) + assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content) + end + + def test_macro_child_pages_with_option + expected = "

\n

" + + @project = Project.find(1) + # child pages of the current wiki page + assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content) + # child pages of another page + assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content) + + @project = Project.find(2) + assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/457635320d7cf0fe410b58dcbd4445d01bddd1f8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/457635320d7cf0fe410b58dcbd4445d01bddd1f8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,285 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) +require 'pp' +class ApiTest::UsersTest < ActionController::IntegrationTest + fixtures :users + + def setup + Setting.rest_api_enabled = '1' + end + + context "GET /users" do + should_allow_api_authentication(:get, "/users.xml") + should_allow_api_authentication(:get, "/users.json") + end + + context "GET /users/2" do + context ".xml" do + should "return requested user" do + get '/users/2.xml' + + assert_tag :tag => 'user', + :child => {:tag => 'id', :content => '2'} + end + end + + context ".json" do + should "return requested user" do + get '/users/2.json' + + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert_kind_of Hash, json['user'] + assert_equal 2, json['user']['id'] + end + end + end + + context "GET /users/current" do + context ".xml" do + should "require authentication" do + get '/users/current.xml' + + assert_response 401 + end + + should "return current user" do + get '/users/current.xml', {}, :authorization => credentials('jsmith') + + assert_tag :tag => 'user', + :child => {:tag => 'id', :content => '2'} + end + end + end + + context "POST /users" do + context "with valid parameters" do + setup do + @parameters = {:user => {:login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname', :mail => 'foo@example.net', :password => 'secret', :mail_notification => 'only_assigned'}} + end + + context ".xml" do + should_allow_api_authentication(:post, + '/users.xml', + {:user => {:login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname', :mail => 'foo@example.net', :password => 'secret'}}, + {:success_code => :created}) + + should "create a user with the attributes" do + assert_difference('User.count') do + post '/users.xml', @parameters, :authorization => credentials('admin') + end + + user = User.first(:order => 'id DESC') + assert_equal 'foo', user.login + assert_equal 'Firstname', user.firstname + assert_equal 'Lastname', user.lastname + assert_equal 'foo@example.net', user.mail + assert_equal 'only_assigned', user.mail_notification + assert !user.admin? + assert user.check_password?('secret') + + assert_response :created + assert_equal 'application/xml', @response.content_type + assert_tag 'user', :child => {:tag => 'id', :content => user.id.to_s} + end + end + + context ".json" do + should_allow_api_authentication(:post, + '/users.json', + {:user => {:login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname', :mail => 'foo@example.net'}}, + {:success_code => :created}) + + should "create a user with the attributes" do + assert_difference('User.count') do + post '/users.json', @parameters, :authorization => credentials('admin') + end + + user = User.first(:order => 'id DESC') + assert_equal 'foo', user.login + assert_equal 'Firstname', user.firstname + assert_equal 'Lastname', user.lastname + assert_equal 'foo@example.net', user.mail + assert !user.admin? + + assert_response :created + assert_equal 'application/json', @response.content_type + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert_kind_of Hash, json['user'] + assert_equal user.id, json['user']['id'] + end + end + end + + context "with invalid parameters" do + setup do + @parameters = {:user => {:login => 'foo', :lastname => 'Lastname', :mail => 'foo'}} + end + + context ".xml" do + should "return errors" do + assert_no_difference('User.count') do + post '/users.xml', @parameters, :authorization => credentials('admin') + end + + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + assert_tag 'errors', :child => {:tag => 'error', :content => "First name can't be blank"} + end + end + + context ".json" do + should "return errors" do + assert_no_difference('User.count') do + post '/users.json', @parameters, :authorization => credentials('admin') + end + + assert_response :unprocessable_entity + assert_equal 'application/json', @response.content_type + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert json.has_key?('errors') + assert_kind_of Array, json['errors'] + end + end + end + end + + context "PUT /users/2" do + context "with valid parameters" do + setup do + @parameters = {:user => {:login => 'jsmith', :firstname => 'John', :lastname => 'Renamed', :mail => 'jsmith@somenet.foo'}} + end + + context ".xml" do + should_allow_api_authentication(:put, + '/users/2.xml', + {:user => {:login => 'jsmith', :firstname => 'John', :lastname => 'Renamed', :mail => 'jsmith@somenet.foo'}}, + {:success_code => :ok}) + + should "update user with the attributes" do + assert_no_difference('User.count') do + put '/users/2.xml', @parameters, :authorization => credentials('admin') + end + + user = User.find(2) + assert_equal 'jsmith', user.login + assert_equal 'John', user.firstname + assert_equal 'Renamed', user.lastname + assert_equal 'jsmith@somenet.foo', user.mail + assert !user.admin? + + assert_response :ok + end + end + + context ".json" do + should_allow_api_authentication(:put, + '/users/2.json', + {:user => {:login => 'jsmith', :firstname => 'John', :lastname => 'Renamed', :mail => 'jsmith@somenet.foo'}}, + {:success_code => :ok}) + + should "update user with the attributes" do + assert_no_difference('User.count') do + put '/users/2.json', @parameters, :authorization => credentials('admin') + end + + user = User.find(2) + assert_equal 'jsmith', user.login + assert_equal 'John', user.firstname + assert_equal 'Renamed', user.lastname + assert_equal 'jsmith@somenet.foo', user.mail + assert !user.admin? + + assert_response :ok + end + end + end + + context "with invalid parameters" do + setup do + @parameters = {:user => {:login => 'jsmith', :firstname => '', :lastname => 'Lastname', :mail => 'foo'}} + end + + context ".xml" do + should "return errors" do + assert_no_difference('User.count') do + put '/users/2.xml', @parameters, :authorization => credentials('admin') + end + + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + assert_tag 'errors', :child => {:tag => 'error', :content => "First name can't be blank"} + end + end + + context ".json" do + should "return errors" do + assert_no_difference('User.count') do + put '/users/2.json', @parameters, :authorization => credentials('admin') + end + + assert_response :unprocessable_entity + assert_equal 'application/json', @response.content_type + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert json.has_key?('errors') + assert_kind_of Array, json['errors'] + end + end + end + end + + context "DELETE /users/2" do + context ".xml" do + should_allow_api_authentication(:delete, + '/users/2.xml', + {}, + {:success_code => :ok}) + + should "delete user" do + assert_difference('User.count', -1) do + delete '/users/2.xml', {}, :authorization => credentials('admin') + end + + assert_response :ok + end + end + + context ".json" do + should_allow_api_authentication(:delete, + '/users/2.xml', + {}, + {:success_code => :ok}) + + should "delete user" do + assert_difference('User.count', -1) do + delete '/users/2.json', {}, :authorization => credentials('admin') + end + + assert_response :ok + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/45/45ba0113063b6030bb97f2bd03aad9a662b0bfbf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/45/45ba0113063b6030bb97f2bd03aad9a662b0bfbf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,74 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class ThemesTest < ActionController::IntegrationTest + + def setup + @theme = Redmine::Themes.themes.last + Setting.ui_theme = @theme.id + end + + def teardown + Setting.ui_theme = '' + end + + def test_application_css + get '/' + + assert_response :success + assert_tag :tag => 'link', + :attributes => {:href => %r{^/themes/#{@theme.dir}/stylesheets/application.css}} + end + + def test_without_theme_js + get '/' + + assert_response :success + assert_no_tag :tag => 'script', + :attributes => {:src => %r{^/themes/#{@theme.dir}/javascripts/theme.js}} + end + + def test_with_theme_js + # Simulates a theme.js + @theme.javascripts << 'theme' + get '/' + + assert_response :success + assert_tag :tag => 'script', + :attributes => {:src => %r{^/themes/#{@theme.dir}/javascripts/theme.js}} + + ensure + @theme.javascripts.delete 'theme' + end + + def test_with_sub_uri + Redmine::Utils.relative_url_root = '/foo' + @theme.javascripts << 'theme' + get '/' + + assert_response :success + assert_tag :tag => 'link', + :attributes => {:href => %r{^/foo/themes/#{@theme.dir}/stylesheets/application.css}} + assert_tag :tag => 'script', + :attributes => {:src => %r{^/foo/themes/#{@theme.dir}/javascripts/theme.js}} + + ensure + Redmine::Utils.relative_url_root = '' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/46/460154f7f38123fe1c4a30970945d9f47767461e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/46/460154f7f38123fe1c4a30970945d9f47767461e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 WikiFormatting + module Textile + module Helper + def wikitoolbar_for(field_id) + heads_for_wiki_formatter + # Is there a simple way to link to a public resource? + url = "#{Redmine::Utils.relative_url_root}/help/wiki_syntax.html" + help_link = link_to(l(:setting_text_formatting), url, + :onclick => "window.open(\"#{ url }\", \"\", \"resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\"); return false;") + + javascript_tag("var wikiToolbar = new jsToolBar($('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript help_link}'); wikiToolbar.draw();") + end + + def initial_page_content(page) + "h1. #{@page.pretty_title}" + end + + def heads_for_wiki_formatter + unless @heads_for_wiki_formatter_included + content_for :header_tags do + javascript_include_tag('jstoolbar/jstoolbar') + + javascript_include_tag('jstoolbar/textile') + + javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language.to_s.downcase}") + + stylesheet_link_tag('jstoolbar') + end + @heads_for_wiki_formatter_included = true + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/46/4604849a86c8bbf40b2a1eb833e2c3ff6fe87f8f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/46/4604849a86c8bbf40b2a1eb833e2c3ff6fe87f8f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +
+<%= watcher_tag(@wiki, User.current) %> +
+ +

<%= l(:label_index_by_date) %>

+ +<% if @pages.empty? %> +

<%= l(:label_no_data) %>

+<% end %> + +<% @pages_by_date.keys.sort.reverse.each do |date| %> +

<%= format_date(date) %>

+
    +<% @pages_by_date[date].each do |page| %> +
  • <%= link_to h(page.pretty_title), :action => 'show', :id => page.title, :project_id => page.project %>
  • +<% end %> +
+<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% unless @pages.empty? %> +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> + <%= f.link_to('HTML', :url => {:action => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %> +<% end %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/46/4651d86297acde8efddeed79e9e6e8b2895332d3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/46/4651d86297acde8efddeed79e9e6e8b2895332d3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddChangesBranch < ActiveRecord::Migration + def self.up + add_column :changes, :branch, :string + end + + def self.down + remove_column :changes, :branch + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/46/46d08e5d685f85ea6b371254e247586c06beb87e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/46/46d08e5d685f85ea6b371254e247586c06beb87e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,107 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'sys_controller' +require 'mocha' + +# Re-raise errors caught by the controller. +class SysController; def rescue_action(e) raise e end; end + +class SysControllerTest < ActionController::TestCase + fixtures :projects, :repositories, :enabled_modules + + def setup + @controller = SysController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + Setting.sys_api_enabled = '1' + Setting.enabled_scm = %w(Subversion Git) + end + + def test_projects_with_repository_enabled + get :projects + assert_response :success + assert_equal 'application/xml', @response.content_type + with_options :tag => 'projects' do |test| + test.assert_tag :children => { :count => Project.active.has_module(:repository).count } + test.assert_tag 'project', :child => {:tag => 'identifier', :sibling => {:tag => 'is-public'}} + end + assert_no_tag 'extra-info' + assert_no_tag 'extra_info' + end + + def test_create_project_repository + assert_nil Project.find(4).repository + + post :create_project_repository, :id => 4, + :vendor => 'Subversion', + :repository => { :url => 'file:///create/project/repository/subproject2'} + assert_response :created + assert_equal 'application/xml', @response.content_type + + r = Project.find(4).repository + assert r.is_a?(Repository::Subversion) + assert_equal 'file:///create/project/repository/subproject2', r.url + + assert_tag 'repository-subversion', + :child => { + :tag => 'id', :content => r.id.to_s, + :sibling => {:tag => 'url', :content => r.url} + } + assert_no_tag 'extra-info' + assert_no_tag 'extra_info' + end + + def test_fetch_changesets + Repository::Subversion.any_instance.expects(:fetch_changesets).returns(true) + get :fetch_changesets + assert_response :success + end + + def test_fetch_changesets_one_project + Repository::Subversion.any_instance.expects(:fetch_changesets).returns(true) + get :fetch_changesets, :id => 'ecookbook' + assert_response :success + end + + def test_fetch_changesets_unknown_project + get :fetch_changesets, :id => 'unknown' + assert_response 404 + end + + def test_disabled_ws_should_respond_with_403_error + with_settings :sys_api_enabled => '0' do + get :projects + assert_response 403 + end + end + + def test_api_key + with_settings :sys_api_key => 'my_secret_key' do + get :projects, :key => 'my_secret_key' + assert_response :success + end + end + + def test_wrong_key_should_respond_with_403_error + with_settings :sys_api_enabled => 'my_secret_key' do + get :projects, :key => 'wrong_key' + assert_response 403 + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/47/4715b8761d3d616a6e3ff8f7139429ffdd309875.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/47/4715b8761d3d616a6e3ff8f7139429ffdd309875.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1008 @@ +sl: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Nedelja, Ponedeljek, Torek, Sreda, Četrtek, Petek, Sobota] + abbr_day_names: [Ned, Pon, To, Sr, Čet, Pet, Sob] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Januar, Februar, Marec, April, Maj, Junij, Julij, Avgust, September, Oktober, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Aug, Sep, Okt, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pol minute" + less_than_x_seconds: + one: "manj kot 1. sekundo" + other: "manj kot %{count} sekund" + x_seconds: + one: "1. sekunda" + other: "%{count} sekund" + less_than_x_minutes: + one: "manj kot minuto" + other: "manj kot %{count} minut" + x_minutes: + one: "1 minuta" + other: "%{count} minut" + about_x_hours: + one: "okrog 1. ure" + other: "okrog %{count} ur" + x_days: + one: "1 dan" + other: "%{count} dni" + about_x_months: + one: "okrog 1. mesec" + other: "okrog %{count} mesecev" + x_months: + one: "1 mesec" + other: "%{count} mesecev" + about_x_years: + one: "okrog 1. leto" + other: "okrog %{count} let" + over_x_years: + one: "več kot 1. leto" + other: "več kot %{count} let" + almost_x_years: + one: "skoraj 1. leto" + other: "skoraj %{count} let" + + number: + format: + separator: "," + delimiter: "." + precision: 3 + human: + format: + precision: 1 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "in" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1. napaka je preprečila temu %{model} da bi se shranil" + other: "%{count} napak je preprečilo temu %{model} da bi se shranil" + messages: + inclusion: "ni vključen na seznamu" + exclusion: "je rezerviran" + invalid: "je napačen" + confirmation: "ne ustreza potrdilu" + accepted: "mora biti sprejet" + empty: "ne sme biti prazen" + blank: "ne sme biti neizpolnjen" + too_long: "je predolg" + too_short: "je prekratek" + wrong_length: "je napačne dolžine" + taken: "je že zaseden" + not_a_number: "ni število" + not_a_date: "ni veljaven datum" + greater_than: "mora biti večji kot %{count}" + greater_than_or_equal_to: "mora biti večji ali enak kot %{count}" + equal_to: "mora biti enak kot %{count}" + less_than: "mora biti manjši kot %{count}" + less_than_or_equal_to: "mora biti manjši ali enak kot %{count}" + odd: "mora biti sodo" + even: "mora biti liho" + greater_than_start_date: "mora biti kasnejši kot začetni datum" + not_same_project: "ne pripada istemu projektu" + circular_dependency: "Ta odnos bi povzročil krožno odvisnost" + cant_link_an_issue_with_a_descendant: "Zahtevek ne more biti povezan s svojo podnalogo" + + actionview_instancetag_blank_option: Prosimo izberite + + general_text_No: 'Ne' + general_text_Yes: 'Da' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Slovenščina' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Račun je bil uspešno posodobljen. + notice_account_invalid_creditentials: Napačno uporabniško ime ali geslo + notice_account_password_updated: Geslo je bilo uspešno posodobljeno. + notice_account_wrong_password: Napačno geslo + notice_account_register_done: Račun je bil uspešno ustvarjen. Za aktivacijo potrdite povezavo, ki vam je bila poslana v e-nabiralnik. + notice_account_unknown_email: Neznan uporabnik. + notice_can_t_change_password: Ta račun za overovljanje uporablja zunanji. Gesla ni mogoče spremeniti. + notice_account_lost_email_sent: Poslano vam je bilo e-pismo z navodili za izbiro novega gesla. + notice_account_activated: Vaš račun je bil aktiviran. Sedaj se lahko prijavite. + notice_successful_create: Ustvarjanje uspelo. + notice_successful_update: Posodobitev uspela. + notice_successful_delete: Izbris uspel. + notice_successful_connection: Povezava uspela. + notice_file_not_found: Stran na katero se želite povezati ne obstaja ali pa je bila umaknjena. + notice_locking_conflict: Drug uporabnik je posodobil podatke. + notice_not_authorized: Nimate privilegijev za dostop do te strani. + notice_email_sent: "E-poštno sporočilo je bilo poslano %{value}" + notice_email_error: "Ob pošiljanju e-sporočila je prišlo do napake (%{value})" + notice_feeds_access_key_reseted: Vaš RSS dostopni ključ je bil ponastavljen. + notice_failed_to_save_issues: "Neuspelo shranjevanje %{count} zahtevka na %{total} izbranem: %{ids}." + notice_no_issue_selected: "Izbran ni noben zahtevek! Prosimo preverite zahtevke, ki jih želite urediti." + notice_account_pending: "Vaš račun je bil ustvarjen in čaka na potrditev s strani administratorja." + notice_default_data_loaded: Privzete nastavitve so bile uspešno naložene. + notice_unable_delete_version: Verzije ni bilo mogoče izbrisati. + + error_can_t_load_default_data: "Privzetih nastavitev ni bilo mogoče naložiti: %{value}" + error_scm_not_found: "Vnos ali revizija v shrambi ni bila najdena ." + error_scm_command_failed: "Med vzpostavljem povezave s shrambo je prišlo do napake: %{value}" + error_scm_annotate: "Vnos ne obstaja ali pa ga ni mogoče komentirati." + error_issue_not_found_in_project: 'Zahtevek ni bil najden ali pa ne pripada temu projektu' + + mail_subject_lost_password: "Vaše %{value} geslo" + mail_body_lost_password: 'Za spremembo glesla kliknite na naslednjo povezavo:' + mail_subject_register: "Aktivacija %{value} vašega računa" + mail_body_register: 'Za aktivacijo vašega računa kliknite na naslednjo povezavo:' + mail_body_account_information_external: "Za prijavo lahko uporabite vaš %{value} račun." + mail_body_account_information: Informacije o vašem računu + mail_subject_account_activation_request: "%{value} zahtevek za aktivacijo računa" + mail_body_account_activation_request: "Registriral se je nov uporabnik (%{value}). Račun čaka na vašo odobritev:" + mail_subject_reminder: "%{count} zahtevek(zahtevki) zapadejo v naslednjih %{days} dneh" + mail_body_reminder: "%{count} zahtevek(zahtevki), ki so vam dodeljeni bodo zapadli v naslednjih %{days} dneh:" + + gui_validation_error: 1 napaka + gui_validation_error_plural: "%{count} napak" + + field_name: Ime + field_description: Opis + field_summary: Povzetek + field_is_required: Zahtevano + field_firstname: Ime + field_lastname: Priimek + field_mail: E-naslov + field_filename: Datoteka + field_filesize: Velikost + field_downloads: Prenosi + field_author: Avtor + field_created_on: Ustvarjen + field_updated_on: Posodobljeno + field_field_format: Format + field_is_for_all: Za vse projekte + field_possible_values: Možne vrednosti + field_regexp: Regularni izraz + field_min_length: Minimalna dolžina + field_max_length: Maksimalna dolžina + field_value: Vrednost + field_category: Kategorija + field_title: Naslov + field_project: Projekt + field_issue: Zahtevek + field_status: Status + field_notes: Zabeležka + field_is_closed: Zahtevek zaprt + field_is_default: Privzeta vrednost + field_tracker: Vrsta zahtevka + field_subject: Tema + field_due_date: Do datuma + field_assigned_to: Dodeljen + field_priority: Prioriteta + field_fixed_version: Ciljna verzija + field_user: Uporabnik + field_role: Vloga + field_homepage: Domača stran + field_is_public: Javno + field_parent: Podprojekt projekta + field_is_in_roadmap: Zahtevki prikazani na zemljevidu + field_login: Prijava + field_mail_notification: E-poštna oznanila + field_admin: Administrator + field_last_login_on: Zadnjič povezan(a) + field_language: Jezik + field_effective_date: Datum + field_password: Geslo + field_new_password: Novo geslo + field_password_confirmation: Potrditev + field_version: Verzija + field_type: Tip + field_host: Gostitelj + field_port: Vrata + field_account: Račun + field_base_dn: Bazni DN + field_attr_login: Oznaka za prijavo + field_attr_firstname: Oznaka za ime + field_attr_lastname: Oznaka za priimek + field_attr_mail: Oznaka za e-naslov + field_onthefly: Sprotna izdelava uporabnikov + field_start_date: Začetek + field_done_ratio: "% Narejeno" + field_auth_source: Način overovljanja + field_hide_mail: Skrij moj e-naslov + field_comments: Komentar + field_url: URL + field_start_page: Začetna stran + field_subproject: Podprojekt + field_hours: Ur + field_activity: Aktivnost + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Uporabljen kot filter + field_issue_to: Povezan zahtevek + field_delay: Zamik + field_assignable: Zahtevki so lahko dodeljeni tej vlogi + field_redirect_existing_links: Preusmeri obstoječe povezave + field_estimated_hours: Ocenjen čas + field_column_names: Stolpci + field_time_zone: Časovni pas + field_searchable: Zmožen iskanja + field_default_value: Privzeta vrednost + field_comments_sorting: Prikaži komentarje + field_parent_title: Matična stran + + setting_app_title: Naslov aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Pozdravno besedilo + setting_default_language: Privzeti jezik + setting_login_required: Zahtevano overovljanje + setting_self_registration: Samostojna registracija + setting_attachment_max_size: Maksimalna velikost priponk + setting_issues_export_limit: Skrajna meja za izvoz zahtevkov + setting_mail_from: E-naslov za emisijo + setting_bcc_recipients: Prejemniki slepih kopij (bcc) + setting_plain_text_mail: navadno e-sporočilo (ne HTML) + setting_host_name: Ime gostitelja in pot + setting_text_formatting: Oblikovanje besedila + setting_wiki_compression: Stiskanje Wiki zgodovine + setting_feeds_limit: Meja obsega RSS virov + setting_default_projects_public: Novi projekti so privzeto javni + setting_autofetch_changesets: Samodejni izvleček zapisa sprememb + setting_sys_api_enabled: Omogoči WS za upravljanje shrambe + setting_commit_ref_keywords: Sklicne ključne besede + setting_commit_fix_keywords: Urejanje ključne besede + setting_autologin: Avtomatska prijava + setting_date_format: Oblika datuma + setting_time_format: Oblika časa + setting_cross_project_issue_relations: Dovoli povezave zahtevkov med različnimi projekti + setting_issue_list_default_columns: Privzeti stolpci prikazani na seznamu zahtevkov + setting_emails_footer: Noga e-sporočil + setting_protocol: Protokol + setting_per_page_options: Število elementov na stran + setting_user_format: Oblika prikaza uporabnikov + setting_activity_days_default: Prikaz dni na aktivnost projekta + setting_display_subprojects_issues: Privzeti prikaz zahtevkov podprojektov v glavnem projektu + setting_enabled_scm: Omogočen SCM + setting_mail_handler_api_enabled: Omogoči WS za prihajajočo e-pošto + setting_mail_handler_api_key: API ključ + setting_sequential_project_identifiers: Generiraj projektne identifikatorje sekvenčno + setting_gravatar_enabled: Uporabljaj Gravatar ikone + setting_diff_max_lines_displayed: Maksimalno število prikazanih vrstic različnosti + + permission_edit_project: Uredi projekt + permission_select_project_modules: Izberi module projekta + permission_manage_members: Uredi člane + permission_manage_versions: Uredi verzije + permission_manage_categories: Urejanje kategorij zahtevkov + permission_add_issues: Dodaj zahtevke + permission_edit_issues: Uredi zahtevke + permission_manage_issue_relations: Uredi odnose med zahtevki + permission_add_issue_notes: Dodaj zabeležke + permission_edit_issue_notes: Uredi zabeležke + permission_edit_own_issue_notes: Uredi lastne zabeležke + permission_move_issues: Premakni zahtevke + permission_delete_issues: Izbriši zahtevke + permission_manage_public_queries: Uredi javna povpraševanja + permission_save_queries: Shrani povpraševanje + permission_view_gantt: Poglej gantogram + permission_view_calendar: Poglej koledar + permission_view_issue_watchers: Oglej si listo spremeljevalcev + permission_add_issue_watchers: Dodaj spremljevalce + permission_log_time: Beleži porabljen čas + permission_view_time_entries: Poglej porabljen čas + permission_edit_time_entries: Uredi beležko časa + permission_edit_own_time_entries: Uredi beležko lastnega časa + permission_manage_news: Uredi novice + permission_comment_news: Komentiraj novice + permission_manage_documents: Uredi dokumente + permission_view_documents: Poglej dokumente + permission_manage_files: Uredi datoteke + permission_view_files: Poglej datoteke + permission_manage_wiki: Uredi wiki + permission_rename_wiki_pages: Preimenuj wiki strani + permission_delete_wiki_pages: Izbriši wiki strani + permission_view_wiki_pages: Poglej wiki + permission_view_wiki_edits: Poglej wiki zgodovino + permission_edit_wiki_pages: Uredi wiki strani + permission_delete_wiki_pages_attachments: Izbriši priponke + permission_protect_wiki_pages: Zaščiti wiki strani + permission_manage_repository: Uredi shrambo + permission_browse_repository: Prebrskaj shrambo + permission_view_changesets: Poglej zapis sprememb + permission_commit_access: Dostop za predajo + permission_manage_boards: Uredi table + permission_view_messages: Poglej sporočila + permission_add_messages: Objavi sporočila + permission_edit_messages: Uredi sporočila + permission_edit_own_messages: Uredi lastna sporočila + permission_delete_messages: Izbriši sporočila + permission_delete_own_messages: Izbriši lastna sporočila + + project_module_issue_tracking: Sledenje zahtevkom + project_module_time_tracking: Sledenje časa + project_module_news: Novice + project_module_documents: Dokumenti + project_module_files: Datoteke + project_module_wiki: Wiki + project_module_repository: Shramba + project_module_boards: Table + + label_user: Uporabnik + label_user_plural: Uporabniki + label_user_new: Nov uporabnik + label_project: Projekt + label_project_new: Nov projekt + label_project_plural: Projekti + label_x_projects: + zero: ni projektov + one: 1 projekt + other: "%{count} projektov" + label_project_all: Vsi projekti + label_project_latest: Zadnji projekti + label_issue: Zahtevek + label_issue_new: Nov zahtevek + label_issue_plural: Zahtevki + label_issue_view_all: Poglej vse zahtevke + label_issues_by: "Zahtevki od %{value}" + label_issue_added: Zahtevek dodan + label_issue_updated: Zahtevek posodobljen + label_document: Dokument + label_document_new: Nov dokument + label_document_plural: Dokumenti + label_document_added: Dokument dodan + label_role: Vloga + label_role_plural: Vloge + label_role_new: Nova vloga + label_role_and_permissions: Vloge in dovoljenja + label_member: Član + label_member_new: Nov član + label_member_plural: Člani + label_tracker: Vrsta zahtevka + label_tracker_plural: Vrste zahtevkov + label_tracker_new: Nova vrsta zahtevka + label_workflow: Potek dela + label_issue_status: Stanje zahtevka + label_issue_status_plural: Stanje zahtevkov + label_issue_status_new: Novo stanje + label_issue_category: Kategorija zahtevka + label_issue_category_plural: Kategorije zahtevkov + label_issue_category_new: Nova kategorija + label_custom_field: Polje po meri + label_custom_field_plural: Polja po meri + label_custom_field_new: Novo polje po meri + label_enumerations: Seznami + label_enumeration_new: Nova vrednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Prosimo prijavite se + label_register: Registracija + label_password_lost: Izgubljeno geslo + label_home: Domov + label_my_page: Moja stran + label_my_account: Moj račun + label_my_projects: Moji projekti + label_administration: Upravljanje + label_login: Prijavi se + label_logout: Odjavi se + label_help: Pomoč + label_reported_issues: Prijavljeni zahtevki + label_assigned_to_me_issues: Zahtevki dodeljeni meni + label_last_login: Zadnja povezava + label_registered_on: Registriran + label_activity: Aktivnost + label_overall_activity: Celotna aktivnost + label_user_activity: "Aktivnost %{value}" + label_new: Nov + label_logged_as: Prijavljen(a) kot + label_environment: Okolje + label_authentication: Overovitev + label_auth_source: Način overovitve + label_auth_source_new: Nov način overovitve + label_auth_source_plural: Načini overovitve + label_subproject_plural: Podprojekti + label_and_its_subprojects: "%{value} in njegovi podprojekti" + label_min_max_length: Min - Max dolžina + label_list: Seznam + label_date: Datum + label_integer: Celo število + label_float: Decimalno število + label_boolean: Boolean + label_string: Besedilo + label_text: Dolgo besedilo + label_attribute: Lastnost + label_attribute_plural: Lastnosti + label_download: "%{count} Prenos" + label_download_plural: "%{count} Prenosi" + label_no_data: Ni podatkov za prikaz + label_change_status: Spremeni stanje + label_history: Zgodovina + label_attachment: Datoteka + label_attachment_new: Nova datoteka + label_attachment_delete: Izbriši datoteko + label_attachment_plural: Datoteke + label_file_added: Datoteka dodana + label_report: Poročilo + label_report_plural: Poročila + label_news: Novica + label_news_new: Dodaj novico + label_news_plural: Novice + label_news_latest: Zadnje novice + label_news_view_all: Poglej vse novice + label_news_added: Dodane novice + label_settings: Nastavitve + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_confirmation: Potrditev + label_export_to: 'Na razpolago tudi v:' + label_read: Preberi... + label_public_projects: Javni projekti + label_open_issues: odprt zahtevek + label_open_issues_plural: odprti zahtevki + label_closed_issues: zaprt zahtevek + label_closed_issues_plural: zaprti zahtevki + label_x_open_issues_abbr_on_total: + zero: 0 odprtih / %{total} + one: 1 odprt / %{total} + other: "%{count} odprtih / %{total}" + label_x_open_issues_abbr: + zero: 0 odprtih + one: 1 odprt + other: "%{count} odprtih" + label_x_closed_issues_abbr: + zero: 0 zaprtih + one: 1 zaprt + other: "%{count} zaprtih" + label_total: Skupaj + label_permissions: Dovoljenja + label_current_status: Trenutno stanje + label_new_statuses_allowed: Novi zahtevki dovoljeni + label_all: vsi + label_none: noben + label_nobody: nihče + label_next: Naslednji + label_previous: Prejšnji + label_used_by: V uporabi od + label_details: Podrobnosti + label_add_note: Dodaj zabeležko + label_per_page: Na stran + label_calendar: Koledar + label_months_from: mesecev od + label_gantt: Gantogram + label_internal: Notranji + label_last_changes: "zadnjih %{count} sprememb" + label_change_view_all: Poglej vse spremembe + label_personalize_page: Individualiziraj to stran + label_comment: Komentar + label_comment_plural: Komentarji + label_x_comments: + zero: ni komentarjev + one: 1 komentar + other: "%{count} komentarjev" + label_comment_add: Dodaj komentar + label_comment_added: Komentar dodan + label_comment_delete: Izbriši komentarje + label_query: Iskanje po meri + label_query_plural: Iskanja po meri + label_query_new: Novo iskanje + label_filter_add: Dodaj filter + label_filter_plural: Filtri + label_equals: je enako + label_not_equals: ni enako + label_in_less_than: v manj kot + label_in_more_than: v več kot + label_in: v + label_today: danes + label_all_time: v vsem času + label_yesterday: včeraj + label_this_week: ta teden + label_last_week: pretekli teden + label_last_n_days: "zadnjih %{count} dni" + label_this_month: ta mesec + label_last_month: zadnji mesec + label_this_year: to leto + label_date_range: Razpon datumov + label_less_than_ago: manj kot dni nazaj + label_more_than_ago: več kot dni nazaj + label_ago: dni nazaj + label_contains: vsebuje + label_not_contains: ne vsebuje + label_day_plural: dni + label_repository: Shramba + label_repository_plural: Shrambe + label_browse: Prebrskaj + label_modification: "%{count} sprememba" + label_modification_plural: "%{count} spremembe" + label_revision: Revizija + label_revision_plural: Revizije + label_associated_revisions: Povezane revizije + label_added: dodano + label_modified: spremenjeno + label_copied: kopirano + label_renamed: preimenovano + label_deleted: izbrisano + label_latest_revision: Zadnja revizija + label_latest_revision_plural: Zadnje revizije + label_view_revisions: Poglej revizije + label_max_size: Največja velikost + label_sort_highest: Premakni na vrh + label_sort_higher: Premakni gor + label_sort_lower: Premakni dol + label_sort_lowest: Premakni na dno + label_roadmap: Načrt + label_roadmap_due_in: "Do %{value}" + label_roadmap_overdue: "%{value} zakasnel" + label_roadmap_no_issues: Ni zahtevkov za to verzijo + label_search: Išči + label_result_plural: Rezultati + label_all_words: Vse besede + label_wiki: Wiki + label_wiki_edit: Wiki urejanje + label_wiki_edit_plural: Wiki urejanja + label_wiki_page: Wiki stran + label_wiki_page_plural: Wiki strani + label_index_by_title: Razvrsti po naslovu + label_index_by_date: Razvrsti po datumu + label_current_version: Trenutna verzija + label_preview: Predogled + label_feed_plural: RSS viri + label_changes_details: Podrobnosti o vseh spremembah + label_issue_tracking: Sledenje zahtevkom + label_spent_time: Porabljen čas + label_f_hour: "%{value} ura" + label_f_hour_plural: "%{value} ur" + label_time_tracking: Sledenje času + label_change_plural: Spremembe + label_statistics: Statistika + label_commits_per_month: Predaj na mesec + label_commits_per_author: Predaj na avtorja + label_view_diff: Preglej razlike + label_diff_inline: znotraj + label_diff_side_by_side: vzporedno + label_options: Možnosti + label_copy_workflow_from: Kopiraj potek dela od + label_permissions_report: Poročilo o dovoljenjih + label_watched_issues: Spremljani zahtevki + label_related_issues: Povezani zahtevki + label_applied_status: Uveljavljeno stanje + label_loading: Nalaganje... + label_relation_new: Nova povezava + label_relation_delete: Izbriši povezavo + label_relates_to: povezan z + label_duplicates: duplikati + label_duplicated_by: dupliciral + label_blocks: blok + label_blocked_by: blokiral + label_precedes: ima prednost pred + label_follows: sledi + label_end_to_start: konec na začetek + label_end_to_end: konec na konec + label_start_to_start: začetek na začetek + label_start_to_end: začetek na konec + label_stay_logged_in: Ostani prijavljen(a) + label_disabled: onemogoči + label_show_completed_versions: Prikaži zaključene verzije + label_me: jaz + label_board: Forum + label_board_new: Nov forum + label_board_plural: Forumi + label_topic_plural: Teme + label_message_plural: Sporočila + label_message_last: Zadnje sporočilo + label_message_new: Novo sporočilo + label_message_posted: Sporočilo dodano + label_reply_plural: Odgovori + label_send_information: Pošlji informacijo o računu uporabniku + label_year: Leto + label_month: Mesec + label_week: Teden + label_date_from: Do + label_date_to: Do + label_language_based: Glede na uporabnikov jezik + label_sort_by: "Razporedi po %{value}" + label_send_test_email: Pošlji testno e-pismo + label_feeds_access_key_created_on: "RSS dostopni ključ narejen %{value} nazaj" + label_module_plural: Moduli + label_added_time_by: "Dodan %{author} %{age} nazaj" + label_updated_time_by: "Posodobljen od %{author} %{age} nazaj" + label_updated_time: "Posodobljen %{value} nazaj" + label_jump_to_a_project: Skoči na projekt... + label_file_plural: Datoteke + label_changeset_plural: Zapisi sprememb + label_default_columns: Privzeti stolpci + label_no_change_option: (Ni spremembe) + label_bulk_edit_selected_issues: Uredi izbrane zahtevke skupaj + label_theme: Tema + label_default: Privzeto + label_search_titles_only: Preišči samo naslove + label_user_mail_option_all: "Za vsak dogodek v vseh mojih projektih" + label_user_mail_option_selected: "Za vsak dogodek samo na izbranih projektih..." + label_user_mail_no_self_notified: "Ne želim biti opozorjen(a) na spremembe, ki jih naredim sam(a)" + label_registration_activation_by_email: aktivacija računa po e-pošti + label_registration_manual_activation: ročna aktivacija računa + label_registration_automatic_activation: samodejna aktivacija računa + label_display_per_page: "Na stran: %{value}" + label_age: Starost + label_change_properties: Sprememba lastnosti + label_general: Splošno + label_more: Več + label_scm: SCM + label_plugins: Vtičniki + label_ldap_authentication: LDAP overovljanje + label_downloads_abbr: D/L + label_optional_description: Neobvezen opis + label_add_another_file: Dodaj še eno datoteko + label_preferences: Preference + label_chronological_order: Kronološko + label_reverse_chronological_order: Obrnjeno kronološko + label_planning: Načrtovanje + label_incoming_emails: Prihajajoča e-pošta + label_generate_key: Ustvari ključ + label_issue_watchers: Spremljevalci + label_example: Vzorec + + button_login: Prijavi se + button_submit: Pošlji + button_save: Shrani + button_check_all: Označi vse + button_uncheck_all: Odznači vse + button_delete: Izbriši + button_create: Ustvari + button_test: Testiraj + button_edit: Uredi + button_add: Dodaj + button_change: Spremeni + button_apply: Uporabi + button_clear: Počisti + button_lock: Zakleni + button_unlock: Odkleni + button_download: Prenesi + button_list: Seznam + button_view: Pogled + button_move: Premakni + button_back: Nazaj + button_cancel: Prekliči + button_activate: Aktiviraj + button_sort: Razvrsti + button_log_time: Beleži čas + button_rollback: Povrni na to verzijo + button_watch: Spremljaj + button_unwatch: Ne spremljaj + button_reply: Odgovori + button_archive: Arhiviraj + button_unarchive: Odarhiviraj + button_reset: Ponastavi + button_rename: Preimenuj + button_change_password: Spremeni geslo + button_copy: Kopiraj + button_annotate: Zapiši pripombo + button_update: Posodobi + button_configure: Konfiguriraj + button_quote: Citiraj + + status_active: aktivni + status_registered: registriran + status_locked: zaklenjen + + text_select_mail_notifications: Izberi dejanja za katera naj bodo poslana oznanila preko e-pošto. + text_regexp_info: npr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 pomeni brez omejitev + text_project_destroy_confirmation: Ali ste prepričani da želite izbrisati izbrani projekt in vse z njim povezane podatke? + text_subprojects_destroy_warning: "Njegov(i) podprojekt(i): %{value} bodo prav tako izbrisani." + text_workflow_edit: Izberite vlogo in zahtevek za urejanje poteka dela + text_are_you_sure: Ali ste prepričani? + text_tip_issue_begin_day: naloga z začetkom na ta dan + text_tip_issue_end_day: naloga z zaključkom na ta dan + text_tip_issue_begin_end_day: naloga ki se začne in konča ta dan + text_project_identifier_info: 'Dovoljene so samo male črke (a-z), številke in vezaji.
Enkrat shranjen identifikator ne more biti spremenjen.' + text_caracters_maximum: "največ %{count} znakov." + text_caracters_minimum: "Mora biti vsaj dolg vsaj %{count} znakov." + text_length_between: "Dolžina med %{min} in %{max} znakov." + text_tracker_no_workflow: Potek dela za to vrsto zahtevka ni določen + text_unallowed_characters: Nedovoljeni znaki + text_comma_separated: Dovoljenih je več vrednosti (ločenih z vejico). + text_issues_ref_in_commit_messages: Zahtevki sklicev in popravkov v sporočilu predaje + text_issue_added: "Zahtevek %{id} je sporočil(a) %{author}." + text_issue_updated: "Zahtevek %{id} je posodobil(a) %{author}." + text_wiki_destroy_confirmation: Ali ste prepričani da želite izbrisati ta wiki in vso njegovo vsebino? + text_issue_category_destroy_question: "Nekateri zahtevki (%{count}) so dodeljeni tej kategoriji. Kaj želite storiti?" + text_issue_category_destroy_assignments: Odstrani naloge v kategoriji + text_issue_category_reassign_to: Ponovno dodeli zahtevke tej kategoriji + text_user_mail_option: "Na neizbrane projekte boste prejemali le obvestila o zadevah ki jih spremljate ali v katere ste vključeni (npr. zahtevki katerih avtor(ica) ste)" + text_no_configuration_data: "Vloge, vrste zahtevkov, statusi zahtevkov in potek dela še niso bili določeni. \nZelo priporočljivo je, da naložite privzeto konfiguracijo, ki jo lahko kasneje tudi prilagodite." + text_load_default_configuration: Naloži privzeto konfiguracijo + text_status_changed_by_changeset: "Dodano v zapis sprememb %{value}." + text_issues_destroy_confirmation: 'Ali ste prepričani, da želite izbrisati izbrani(e) zahtevek(ke)?' + text_select_project_modules: 'Izberite module, ki jih želite omogočiti za ta projekt:' + text_default_administrator_account_changed: Spremenjen privzeti administratorski račun + text_file_repository_writable: Omogočeno pisanje v shrambo datotek + text_rmagick_available: RMagick je na voljo(neobvezno) + text_destroy_time_entries_question: "%{hours} ur je bilo opravljenih na zahtevku, ki ga želite izbrisati. Kaj želite storiti?" + text_destroy_time_entries: Izbriši opravljene ure + text_assign_time_entries_to_project: Predaj opravljene ure projektu + text_reassign_time_entries: 'Prenesi opravljene ure na ta zahtevek:' + text_user_wrote: "%{value} je napisal(a):" + text_enumeration_destroy_question: "%{count} objektov je določenih tej vrednosti." + text_enumeration_category_reassign_to: 'Ponastavi jih na to vrednost:' + text_email_delivery_not_configured: "E-poštna dostava ni nastavljena in oznanila so onemogočena.\nNastavite vaš SMTP strežnik v config/configuration.yml in ponovno zaženite aplikacijo da ga omogočite.\n" + text_repository_usernames_mapping: "Izberite ali posodobite Redmine uporabnika dodeljenega vsakemu uporabniškemu imenu najdenemu v zapisniku shrambe.\n Uporabniki z enakim Redmine ali shrambinem uporabniškem imenu ali e-poštnem naslovu so samodejno dodeljeni." + text_diff_truncated: '... Ta sprememba je bila odsekana ker presega največjo velikost ki je lahko prikazana.' + + default_role_manager: Upravnik + default_role_developer: Razvijalec + default_role_reporter: Poročevalec + default_tracker_bug: Hrošč + default_tracker_feature: Funkcija + default_tracker_support: Podpora + default_issue_status_new: Nov + default_issue_status_in_progress: V teku + default_issue_status_resolved: Rešen + default_issue_status_feedback: Povratna informacija + default_issue_status_closed: Zaključen + default_issue_status_rejected: Zavrnjen + default_doc_category_user: Uporabniška dokumentacija + default_doc_category_tech: Tehnična dokumentacija + default_priority_low: Nizka + default_priority_normal: Običajna + default_priority_high: Visoka + default_priority_urgent: Urgentna + default_priority_immediate: Takojšnje ukrepanje + default_activity_design: Oblikovanje + default_activity_development: Razvoj + + enumeration_issue_priorities: Prioritete zahtevkov + enumeration_doc_categories: Kategorije dokumentov + enumeration_activities: Aktivnosti (sledenje časa) + warning_attachments_not_saved: "%{count} datotek(e) ni bilo mogoče shraniti." + field_editable: Uredljivo + text_plugin_assets_writable: Zapisljiva mapa za vtičnike + label_display: Prikaz + button_create_and_continue: Ustvari in nadaljuj + text_custom_field_possible_values_info: 'Ena vrstica za vsako vrednost' + setting_repository_log_display_limit: Največje število prikazanih revizij v log datoteki + setting_file_max_size_displayed: Največja velikost besedilnih datotek v vključenem prikazu + field_watcher: Opazovalec + setting_openid: Dovoli OpenID prijavo in registracijo + field_identity_url: OpenID URL + label_login_with_open_id_option: ali se prijavi z OpenID + field_content: Vsebina + label_descending: Padajoče + label_sort: Razvrsti + label_ascending: Naraščajoče + label_date_from_to: Od %{start} do %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Ta stran ima %{descendants} podstran(i) in naslednik(ov). Kaj želite storiti? + text_wiki_page_reassign_children: Znova dodeli podstrani tej glavni strani + text_wiki_page_nullify_children: Obdrži podstrani kot glavne strani + text_wiki_page_destroy_children: Izbriši podstrani in vse njihove naslednike + setting_password_min_length: Minimalna dolžina gesla + field_group_by: Združi rezultate po + mail_subject_wiki_content_updated: "'%{id}' wiki stran je bila posodobljena" + label_wiki_content_added: Wiki stran dodana + mail_subject_wiki_content_added: "'%{id}' wiki stran je bila dodana" + mail_body_wiki_content_added: "%{author} je dodal '%{id}' wiki stran" + label_wiki_content_updated: Wiki stran posodobljena + mail_body_wiki_content_updated: "%{author} je posodobil '%{id}' wiki stran." + permission_add_project: Ustvari projekt + setting_new_project_user_role_id: Vloga, dodeljena neadministratorskemu uporabniku, ki je ustvaril projekt + label_view_all_revisions: Poglej vse revizije + label_tag: Oznaka + label_branch: Veja + error_no_tracker_in_project: Noben sledilnik ni povezan s tem projektom. Prosimo preverite nastavitve projekta. + error_no_default_issue_status: Privzeti zahtevek ni definiran. Prosimo preverite svoje nastavitve (Pojdite na "Administracija -> Stanje zahtevkov"). + text_journal_changed: "%{label} se je spremenilo iz %{old} v %{new}" + text_journal_set_to: "%{label} nastavljeno na %{value}" + text_journal_deleted: "%{label} izbrisan (%{old})" + label_group_plural: Skupine + label_group: Skupina + label_group_new: Nova skupina + label_time_entry_plural: Porabljen čas + text_journal_added: "%{label} %{value} dodan" + field_active: Aktiven + enumeration_system_activity: Sistemska aktivnost + permission_delete_issue_watchers: Izbriši opazovalce + version_status_closed: zaprt + version_status_locked: zaklenjen + version_status_open: odprt + error_can_not_reopen_issue_on_closed_version: Zahtevek dodeljen zaprti verziji ne more biti ponovno odprt + label_user_anonymous: Anonimni + button_move_and_follow: Premakni in sledi + setting_default_projects_modules: Privzeti moduli za nove projekte + setting_gravatar_default: Privzeta Gravatar slika + field_sharing: Deljenje + label_version_sharing_hierarchy: S projektno hierarhijo + label_version_sharing_system: Z vsemi projekti + label_version_sharing_descendants: S podprojekti + label_version_sharing_tree: Z drevesom projekta + label_version_sharing_none: Ni deljeno + error_can_not_archive_project: Ta projekt ne more biti arhiviran + button_duplicate: Podvoji + button_copy_and_follow: Kopiraj in sledi + label_copy_source: Vir + setting_issue_done_ratio: Izračunaj razmerje opravljenega zahtevka z + setting_issue_done_ratio_issue_status: Uporabi stanje zahtevka + error_issue_done_ratios_not_updated: Razmerje opravljenega zahtevka ni bilo posodobljeno. + error_workflow_copy_target: Prosimo izberite ciljni(e) sledilnik(e) in vlogo(e) + setting_issue_done_ratio_issue_field: Uporabi polje zahtevka + label_copy_same_as_target: Enako kot cilj + label_copy_target: Cilj + notice_issue_done_ratios_updated: Razmerje opravljenega zahtevka posodobljeno. + error_workflow_copy_source: Prosimo izberite vir zahtevka ali vlogo + label_update_issue_done_ratios: Posodobi razmerje opravljenega zahtevka + setting_start_of_week: Začni koledarje z + permission_view_issues: Poglej zahtevke + label_display_used_statuses_only: Prikaži samo stanja ki uporabljajo ta sledilnik + label_revision_id: Revizija %{value} + label_api_access_key: API dostopni ključ + label_api_access_key_created_on: API dostopni ključ ustvarjen pred %{value} + label_feeds_access_key: RSS dostopni ključ + notice_api_access_key_reseted: Vaš API dostopni ključ je bil ponastavljen. + setting_rest_api_enabled: Omogoči REST spletni servis + label_missing_api_access_key: Manjkajoč API dostopni ključ + label_missing_feeds_access_key: Manjkajoč RSS dostopni ključ + button_show: Prikaži + text_line_separated: Dovoljenih več vrednosti (ena vrstica za vsako vrednost). + setting_mail_handler_body_delimiters: Odreži e-pošto po eni od teh vrstic + permission_add_subprojects: Ustvari podprojekte + label_subproject_new: Nov podprojekt + text_own_membership_delete_confirmation: |- + Odstranili boste nekatere ali vse od dovoljenj zaradi česar morda ne boste mogli več urejati tega projekta. + Ali ste prepričani, da želite nadaljevati? + label_close_versions: Zapri dokončane verzije + label_board_sticky: Lepljivo + label_board_locked: Zaklenjeno + permission_export_wiki_pages: Izvozi wiki strani + setting_cache_formatted_text: Predpomni oblikovano besedilo + permission_manage_project_activities: Uredi aktivnosti projekta + error_unable_delete_issue_status: Stanja zahtevka ni bilo možno spremeniti + label_profile: Profil + permission_manage_subtasks: Uredi podnaloge + field_parent_issue: Nadrejena naloga + label_subtask_plural: Podnaloge + label_project_copy_notifications: Med kopiranjem projekta pošlji e-poštno sporočilo + error_can_not_delete_custom_field: Polja po meri ni mogoče izbrisati + error_unable_to_connect: Povezava ni mogoča (%{value}) + error_can_not_remove_role: Ta vloga je v uporabi in je ni mogoče izbrisati. + error_can_not_delete_tracker: Ta sledilnik vsebuje zahtevke in se ga ne more izbrisati. + field_principal: Upravnik varnosti + label_my_page_block: Moj gradnik strani + notice_failed_to_save_members: "Shranjevanje uporabnika(ov) ni uspelo: %{errors}." + text_zoom_out: Približaj + text_zoom_in: Oddalji + notice_unable_delete_time_entry: Brisanje dnevnika porabljenaga časa ni mogoče. + label_overall_spent_time: Skupni porabljeni čas + field_time_entries: Beleži porabljeni čas + project_module_gantt: Gantogram + project_module_calendar: Koledear + button_edit_associated_wikipage: "Uredi povezano Wiki stran: %{page_title}" + text_are_you_sure_with_children: Izbriši zahtevek in vse podazahtevke? + field_text: Besedilno polje + label_user_mail_option_only_owner: Samo za stvari katerih lastnik sem + setting_default_notification_option: Privzeta možnost obveščanja + label_user_mail_option_only_my_events: Samo za stvari, ki jih opazujem ali sem v njih vpleten + label_user_mail_option_only_assigned: Samo za stvari, ki smo mi dodeljene + label_user_mail_option_none: Noben dogodek + field_member_of_group: Pooblaščenčeva skupina + field_assigned_to_role: Pooblaščenčeva vloga + notice_not_authorized_archived_project: Projekt, do katerega poskušate dostopati, je bil arhiviran. + label_principal_search: "Poišči uporabnika ali skupino:" + label_user_search: "Poišči uporabnikia:" + field_visible: Viden + setting_emails_header: Glava e-pošte + setting_commit_logtime_activity_id: Aktivnost zabeleženega časa + text_time_logged_by_changeset: Uporabljeno v spremembi %{value}. + setting_commit_logtime_enabled: Omogoči beleženje časa + notice_gantt_chart_truncated: Graf je bil odrezan, ker je prekoračil največje dovoljeno število elementov, ki se jih lahko prikaže (%{max}) + setting_gantt_items_limit: Največje število elementov prikazano na gantogramu + field_warn_on_leaving_unsaved: Opozori me, kadar zapuščam stran z neshranjenim besedilom + text_warn_on_leaving_unsaved: Trenutna stran vsebuje neshranjeno besedilo ki bo izgubljeno, če zapustite to stran. + label_my_queries: Moje poizvedbe po meri + text_journal_changed_no_detail: "%{label} posodobljen" + label_news_comment_added: Komentar dodan novici + button_expand_all: Razširi vse + button_collapse_all: Skrči vse + label_additional_workflow_transitions_for_assignee: Dovoljeni dodatni prehodi kadar je uporabnik pooblaščenec + label_additional_workflow_transitions_for_author: Dovoljeni dodatni prehodi kadar je uporabnik avtor + label_bulk_edit_selected_time_entries: Skupinsko urejanje izbranih časovnih zapisov + text_time_entries_destroy_confirmation: Ali ste prepričani, da želite izbristai izbran(e) časovn(i/e) zapis(e)? + label_role_anonymous: Anonimni + label_role_non_member: Nečlan + label_issue_note_added: Dodan zaznamek + label_issue_status_updated: Status posodobljen + label_issue_priority_updated: Prioriteta posodobljena + label_issues_visibility_own: Zahtevek ustvarjen s strani uporabnika ali dodeljen uporabniku + field_issues_visibility: Vidljivost zahtevkov + label_issues_visibility_all: Vsi zahtevki + permission_set_own_issues_private: Nastavi lastne zahtevke kot javne ali zasebne + field_is_private: Zaseben + permission_set_issues_private: Nastavi zahtevke kot javne ali zasebne + label_issues_visibility_public: Vsi nezasebni zahtevki + text_issues_destroy_descendants_confirmation: To bo izbrisalo tudi %{count} podnalog(o). + field_commit_logs_encoding: Kodiranje sporočil ob predaji + field_scm_path_encoding: Pot do kodiranja + text_scm_path_encoding_note: "Privzeto: UTF-8" + field_path_to_repository: Pot do shrambe + field_root_directory: Korenska mapa + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokalna shramba (npr. /hgrepo, c:\hgrepo) + text_scm_command: Ukaz + text_scm_command_version: Verzija + label_git_report_last_commit: Sporoči zadnje uveljavljanje datotek in map + text_scm_config: Svoje SCM ukaze lahko nastavite v datoteki config/configuration.yml. Po urejanju prosimo ponovno zaženite aplikacijo. + text_scm_command_not_available: SCM ukaz ni na voljo. Prosimo preverite nastavitve v upravljalskem podoknu. + + text_git_repository_note: Shramba je prazna in lokalna (npr. /gitrepo, c:\gitrepo) + + notice_issue_successful_create: Ustvarjen zahtevek %{id}. + label_between: med + setting_issue_group_assignment: Dovoli dodeljevanje zahtevka skupinam + label_diff: diff + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/47/47226d5a01dc8a69470963b9e6191a0eef3e2f87.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/47/47226d5a01dc8a69470963b9e6191a0eef3e2f87.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +

<%=l(:label_watched_issues)%> (<%= Issue.visible.watched_by(user.id).count %>)

+<% watched_issues = Issue.visible.on_active_project.watched_by(user.id).recently_updated.with_limit(10) %> + +<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %> +<% if watched_issues.length > 0 %> +

<%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :watcher_id => 'me', + :sort => 'updated_on:desc' %>

+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/47/47c9d985d61efc0ee6bcc740cf1e1b6d55c978e1.svn-base Binary file .svn/pristine/47/47c9d985d61efc0ee6bcc740cf1e1b6d55c978e1.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/47/47cd8b345d1020290ba00f3aec67bf352663d44c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/47/47cd8b345d1020290ba00f3aec67bf352663d44c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +module CodeRay +module Encoders + + # = XML Encoder + # + # Uses REXML. Very slow. + class XML < Encoder + + register_for :xml + + FILE_EXTENSION = 'xml' + + autoload :REXML, 'rexml/document' + + DEFAULT_OPTIONS = { + :tab_width => 8, + :pretty => -1, + :transitive => false, + } + + protected + def setup options + super + + @doc = REXML::Document.new + @doc << REXML::XMLDecl.new + @tab_width = options[:tab_width] + @root = @node = @doc.add_element('coderay-tokens') + end + + def finish options + @doc.write @out, options[:pretty], options[:transitive], true + + super + end + + public + def text_token text, kind + if kind == :space + token = @node + else + token = @node.add_element kind.to_s + end + text.scan(/(\x20+)|(\t+)|(\n)|[^\x20\t\n]+/) do |space, tab, nl| + case + when space + token << REXML::Text.new(space, true) + when tab + token << REXML::Text.new(tab, true) + when nl + token << REXML::Text.new(nl, true) + else + token << REXML::Text.new($&) + end + end + end + + def begin_group kind + @node = @node.add_element kind.to_s + end + + def end_group kind + if @node == @root + raise 'no token to close!' + end + @node = @node.parent + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/47/47ce3334dc16a4bb0dfcee650e73a424efc452c5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/47/47ce3334dc16a4bb0dfcee650e73a424efc452c5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddIssuesIsPrivate < ActiveRecord::Migration + def self.up + add_column :issues, :is_private, :boolean, :default => false, :null => false + end + + def self.down + remove_column :issues, :is_private + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/480105a11c0f3afc8905880402d1c48e924f0c70.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/48/480105a11c0f3afc8905880402d1c48e924f0c70.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +<% if @notes %> +
<%= l(:field_notes) %> + <%= textilizable @notes, :attachments => @attachements, :object => @issue %> +
+<% end %> + +<% if @description %> +
<%= l(:field_description) %> + <%= textilizable @description, :attachments => @attachements, :object => @issue %> +
+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/48150294b5e1667be0e02136382437b7ee17a5da.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/48/48150294b5e1667be0e02136382437b7ee17a5da.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,313 @@ += 0 && $cc < 0xFFFF && $glyph) { + $cidtogidmap{$cc*2} = chr($glyph >> 8); + $cidtogidmap{$cc*2 + 1} = chr($glyph & 0xFF); + } + } + if($gn=='.notdef' && !isset($fm['MissingWidth'])) + $fm['MissingWidth']=$w; + } + elseif($code=='FontName') + $fm['FontName']=$param; + elseif($code=='Weight') + $fm['Weight']=$param; + elseif($code=='ItalicAngle') + $fm['ItalicAngle']=(double)$param; + elseif($code=='Ascender') + $fm['Ascender']=(int)$param; + elseif($code=='Descender') + $fm['Descender']=(int)$param; + elseif($code=='UnderlineThickness') + $fm['UnderlineThickness']=(int)$param; + elseif($code=='UnderlinePosition') + $fm['UnderlinePosition']=(int)$param; + elseif($code=='IsFixedPitch') + $fm['IsFixedPitch']=($param=='true'); + elseif($code=='FontBBox') + $fm['FontBBox']=array($e[1],$e[2],$e[3],$e[4]); + elseif($code=='CapHeight') + $fm['CapHeight']=(int)$param; + elseif($code=='StdVW') + $fm['StdVW']=(int)$param; + } + if(!isset($fm['MissingWidth'])) + $fm['MissingWidth']=600; + + if(!isset($fm['FontName'])) + die('FontName not found'); + + $fm['Widths']=$widths; + + return $fm; +} + +function MakeFontDescriptor($fm) +{ + //Ascent + $asc=(isset($fm['Ascender']) ? $fm['Ascender'] : 1000); + $fd="{'Ascent'=>".$asc; + //Descent + $desc=(isset($fm['Descender']) ? $fm['Descender'] : -200); + $fd.=",'Descent'=>".$desc; + //CapHeight + if(isset($fm['CapHeight'])) + $ch=$fm['CapHeight']; + elseif(isset($fm['CapXHeight'])) + $ch=$fm['CapXHeight']; + else + $ch=$asc; + $fd.=",'CapHeight'=>".$ch; + //Flags + $flags=0; + if(isset($fm['IsFixedPitch']) and $fm['IsFixedPitch']) + $flags+=1<<0; + $flags+=1<<5; + if(isset($fm['ItalicAngle']) and $fm['ItalicAngle']!=0) + $flags+=1<<6; + $fd.=",'Flags'=>".$flags; + //FontBBox + if(isset($fm['FontBBox'])) + $fbb=$fm['FontBBox']; + else + $fbb=array(0,$des-100,1000,$asc+100); + $fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'"; + //ItalicAngle + $ia=(isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0); + $fd.=",'ItalicAngle'=>".$ia; + //StemV + if(isset($fm['StdVW'])) + $stemv=$fm['StdVW']; + elseif(isset($fm['Weight']) and eregi('(bold|black)',$fm['Weight'])) + $stemv=120; + else + $stemv=70; + $fd.=",'StemV'=>".$stemv; + //MissingWidth + if(isset($fm['MissingWidth'])) + $fd.=",'MissingWidth'=>".$fm['MissingWidth']; + $fd.='}'; + return $fd; +} + +function MakeWidthArray($fm) +{ + //Make character width array + $s="{"; + $cw=$fm['Widths']; + $els=array(); + $c=0; + foreach ($cw as $i => $w) + { + $els[] = ((($c++)%16==0)?"\n\t":'').$i.'=>'.$w; + } + $s .= implode(', ', $els); + $s.='}'; + return $s; +} + +function SaveToFile($file,$s,$mode='t') +{ + $f=fopen($file,'w'.$mode); + if(!$f) + die('Can\'t write to file '.$file); + fwrite($f,$s,strlen($s)); + fclose($f); +} + +function ReadShort($f) +{ + $a=unpack('n1n',fread($f,2)); + return $a['n']; +} + +function ReadLong($f) +{ + $a=unpack('N1N',fread($f,4)); + return $a['N']; +} + +function CheckTTF($file) +{ + //Check if font license allows embedding + $f=fopen($file,'rb'); + if(!$f) + die('Error: Can\'t open '.$file); + //Extract number of tables + fseek($f,4,SEEK_CUR); + $nb=ReadShort($f); + fseek($f,6,SEEK_CUR); + //Seek OS/2 table + $found=false; + for($i=0;$i<$nb;$i++) + { + if(fread($f,4)=='OS/2') + { + $found=true; + break; + } + fseek($f,12,SEEK_CUR); + } + if(!$found) + { + fclose($f); + return; + } + fseek($f,4,SEEK_CUR); + $offset=ReadLong($f); + fseek($f,$offset,SEEK_SET); + //Extract fsType flags + fseek($f,8,SEEK_CUR); + $fsType=ReadShort($f); + $rl=($fsType & 0x02)!=0; + $pp=($fsType & 0x04)!=0; + $e=($fsType & 0x08)!=0; + fclose($f); + if($rl and !$pp and !$e) + echo 'Warning: font license does not allow embedding'; +} + +/******************************************************************************* +* $fontfile: path to TTF file (or empty string if not to be embedded) * +* $ufmfile: path to UFM file * +*******************************************************************************/ +function MakeFont($fontfile,$ufmfile) +{ + //Generate a font definition file + set_magic_quotes_runtime(0); + if(!file_exists($ufmfile)) + die('Error: UFM file not found: '.$ufmfile); + $cidtogidmap = ''; + $fm=ReadUFM($ufmfile, $cidtogidmap); + $fd=MakeFontDescriptor($fm); + //Find font type + if($fontfile) + { + $ext=strtolower(substr($fontfile,-3)); + if($ext=='ttf') + $type='TrueTypeUnicode'; + else + die('Error: not a truetype font: '.$ext); + } + else + { + if($type!='TrueTypeUnicode') + die('Error: incorrect font type: '.$type); + } + //Start generation + $basename=strtolower(substr(basename($ufmfile),0,-4)); + $s='TCPDFFontDescriptor.define(\''.$basename."') do |font|\n"; + $s.=" font[:type]='".$type."'\n"; + $s.=" font[:name]='".$fm['FontName']."'\n"; + $s.=" font[:desc]=".$fd."\n"; + if(!isset($fm['UnderlinePosition'])) + $fm['UnderlinePosition']=-100; + if(!isset($fm['UnderlineThickness'])) + $fm['UnderlineThickness']=50; + $s.=" font[:up]=".$fm['UnderlinePosition']."\n"; + $s.=" font[:ut]=".$fm['UnderlineThickness']."\n"; + $s.=" font[:cw]=".MakeWidthArray($fm)."\n"; + $s.=" font[:enc]=''\n"; + $s.=" font[:diff]=''\n"; + if($fontfile) + { + //Embedded font + if(!file_exists($fontfile)) + die('Error: font file not found: '.$fontfile); + CheckTTF($fontfile); + $f=fopen($fontfile,'rb'); + if(!$f) + die('Error: Can\'t open '.$fontfile); + $file=fread($f,filesize($fontfile)); + fclose($f); + if(function_exists('gzcompress')) + { + $cmp=$basename.'.z'; + SaveToFile($cmp,gzcompress($file),'b'); + $s.=' font[:file]=\''.$cmp."'\n"; + echo 'Font file compressed ('.$cmp.')
'; + + $cmp=$basename.'.ctg.z'; + SaveToFile($cmp,gzcompress($cidtogidmap),'b'); + echo 'CIDToGIDMap created and compressed ('.$cmp.')
'; + $s.=' font[:ctg]=\''.$cmp."'\n"; + } + else + { + $s.='$file=\''.basename($fontfile)."'\n"; + echo 'Notice: font file could not be compressed (gzcompress not available)
'; + + $cmp=$basename.'.ctg'; + $f = fopen($cmp, 'wb'); + fwrite($f, $cidtogidmap); + fclose($f); + echo 'CIDToGIDMap created ('.$cmp.')
'; + $s.=' font[:ctg]=\''.$cmp."'\n"; + } + if($type=='Type1') + { + $s.=' font[:size1]='.$size1."\n"; + $s.=' font[:size2]='.$size2."\n"; + } + else + $s.=' font[:originalsize]='.filesize($fontfile)."\n"; + } + else + { + //Not embedded font + $s.=' font[:file]='."''\n"; + } + $s.="end\n"; + SaveToFile($basename.'.rb',$s); + echo 'Font definition file generated ('.$basename.'.rb'.')
'; +} + +$arg = $GLOBALS['argv']; +if (count($arg) >= 3) { + ob_start(); + array_shift($arg); + MakeFont($arg[0], $arg[1]); + $t = ob_get_clean(); + print preg_replace('!!i', "\n", $t); +} +else { + print "Usage: makefontuni_ruby.php \n"; +} +?> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/483aaf3d47fc1ab3086610e421bdd6e187cf57a8.svn-base Binary file .svn/pristine/48/483aaf3d47fc1ab3086610e421bdd6e187cf57a8.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/4852f1cf9dc40b28e85de8175f26734a857d7d04.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/48/4852f1cf9dc40b28e85de8175f26734a857d7d04.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class SharedEngineController < ApplicationController + def an_action + render_class_and_action 'from alpha_engine' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/487477c9cff9e9a9069caec577d2d37b4dc2bf28.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/48/487477c9cff9e9a9069caec577d2d37b4dc2bf28.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRoleTrackerOldStatusIndexToWorkflows < ActiveRecord::Migration + def self.up + add_index :workflows, [:role_id, :tracker_id, :old_status_id], :name => :wkfs_role_tracker_old_status + end + + def self.down + remove_index(:workflows, :name => :wkfs_role_tracker_old_status); rescue + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/48b2840db60b271c593d21c38917c44a5158b68b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/48/48b2840db60b271c593d21c38917c44a5158b68b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +# Rails <2.x doesn't define #except +class Hash #:nodoc: + # Returns a new hash without the given keys. + def except(*keys) + clone.except!(*keys) + end unless method_defined?(:except) + + # Replaces the hash without the given keys. + def except!(*keys) + keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) + keys.each { |key| delete(key) } + self + end unless method_defined?(:except!) +end + +# NamedScope is new to Rails 2.1 +unless defined? ActiveRecord::NamedScope + require 'awesome_nested_set/named_scope' + ActiveRecord::Base.class_eval do + include CollectiveIdea::NamedScope + end +end + +# Rails 1.2.x doesn't define #quoted_table_name +class ActiveRecord::Base #:nodoc: + def self.quoted_table_name + self.connection.quote_column_name(self.table_name) + end unless methods.include?('quoted_table_name') +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/48/48b4396c87b793f88c5ab4bc586ea45f81977244.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/48/48b4396c87b793f88c5ab4bc586ea45f81977244.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +<%= error_messages_for 'message' %> +<% replying ||= false %> + +
+ +


+<%= f.text_field :subject, :size => 120, :id => "message_subject" %> + +<% if !replying && User.current.allowed_to?(:edit_messages, @project) %> + + +<% end %> +

+ +<% if !replying && !@message.new_record? && User.current.allowed_to?(:edit_messages, @project) %> +


+ <%= f.select :board_id, @project.boards.collect {|b| [b.name, b.id]} %>

+<% end %> + +

+<%= label_tag "message_content", l(:description_message_content), :class => "hidden-for-sighted" %> +<%= f.text_area :content, :cols => 80, :rows => 15, :class => 'wiki-edit', :id => 'message_content' %>

+<%= wikitoolbar_for 'message_content' %> + + +

<%= l(:label_attachment_plural) %>
+<%= render :partial => 'attachments/form' %>

+
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/494407d02bba3407a10ba1c1ab453fed5d658a6e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/494407d02bba3407a10ba1c1ab453fed5d658a6e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddIndexesToIssueStatus < ActiveRecord::Migration + def self.up + add_index :issue_statuses, :position + add_index :issue_statuses, :is_closed + add_index :issue_statuses, :is_default + end + + def self.down + remove_index :issue_statuses, :position + remove_index :issue_statuses, :is_closed + remove_index :issue_statuses, :is_default + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/49a09daa149b6d9350cac1817bdfb249c5164fda.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/49a09daa149b6d9350cac1817bdfb249c5164fda.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

<%= link_to l(:label_tracker_plural), trackers_path %> » <%=h @tracker %>

+ +<% form_for @tracker, :builder => TabularFormBuilder do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/49aafa941ba2df3722536a8d3f8580c133f8b9fb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/49aafa941ba2df3722536a8d3f8580c133f8b9fb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +class CreateEnabledModules < ActiveRecord::Migration + def self.up + create_table :enabled_modules do |t| + t.column :project_id, :integer + t.column :name, :string, :null => false + end + add_index :enabled_modules, [:project_id], :name => :enabled_modules_project_id + + # Enable all modules for existing projects + Project.find(:all).each do |project| + project.enabled_module_names = Redmine::AccessControl.available_project_modules + end + end + + def self.down + drop_table :enabled_modules + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/49b1342eefb943ca4c9418539272ea4794cdb5e5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/49b1342eefb943ca4c9418539272ea4794cdb5e5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +// Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BF idea... +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Pogrubienie'; +jsToolBar.strings['Italic'] = 'Kursywa'; +jsToolBar.strings['Underline'] = 'Podkreślenie'; +jsToolBar.strings['Deleted'] = 'Usunięte'; +jsToolBar.strings['Code'] = 'Wstawka kodu'; +jsToolBar.strings['Heading 1'] = 'Nagłowek 1'; +jsToolBar.strings['Heading 2'] = 'Nagłówek 2'; +jsToolBar.strings['Heading 3'] = 'Nagłówek 3'; +jsToolBar.strings['Unordered list'] = 'Nieposortowana lista'; +jsToolBar.strings['Ordered list'] = 'Posortowana lista'; +jsToolBar.strings['Quote'] = 'Cytat'; +jsToolBar.strings['Unquote'] = 'Usuń cytat'; +jsToolBar.strings['Preformatted text'] = 'Sformatowany tekst'; +jsToolBar.strings['Wiki link'] = 'Odnośnik do strony Wiki'; +jsToolBar.strings['Image'] = 'Obraz'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/49c759950bed453cc0da75c2904a201b6bf1a7c4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/49c759950bed453cc0da75c2904a201b6bf1a7c4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,83 @@ +module CodeRay +module Encoders + + # A simple JSON Encoder. + # + # Example: + # CodeRay.scan('puts "Hello world!"', :ruby).json + # yields + # [ + # {"type"=>"text", "text"=>"puts", "kind"=>"ident"}, + # {"type"=>"text", "text"=>" ", "kind"=>"space"}, + # {"type"=>"block", "action"=>"open", "kind"=>"string"}, + # {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, + # {"type"=>"text", "text"=>"Hello world!", "kind"=>"content"}, + # {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, + # {"type"=>"block", "action"=>"close", "kind"=>"string"}, + # ] + class JSON < Encoder + + begin + require 'json' + rescue LoadError + begin + require 'rubygems' unless defined? Gem + gem 'json' + require 'json' + rescue LoadError + $stderr.puts "The JSON encoder needs the JSON library.\n" \ + "Please gem install json." + raise + end + end + + register_for :json + FILE_EXTENSION = 'json' + + protected + def setup options + super + + @first = true + @out << '[' + end + + def finish options + @out << ']' + end + + def append data + if @first + @first = false + else + @out << ',' + end + + @out << data.to_json + end + + public + def text_token text, kind + append :type => 'text', :text => text, :kind => kind + end + + def begin_group kind + append :type => 'block', :action => 'open', :kind => kind + end + + def end_group kind + append :type => 'block', :action => 'close', :kind => kind + end + + def begin_line kind + append :type => 'block', :action => 'begin_line', :kind => kind + end + + def end_line kind + append :type => 'block', :action => 'end_line', :kind => kind + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/49ce90be0c149fe7cbdb78cf85bb09564b042b23.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/49ce90be0c149fe7cbdb78cf85bb09564b042b23.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +From: "John Smith" +To: +Subject: New ticket on a given project +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris. Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque +sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. +Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, +dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, +massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo +pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. + +Projet: onlinestore +Tracker: Feature request +catgorie: Stock management +priorit: Urgent diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/49/49e241388e4f3f4216ec7154a82eaad6c0c8e9f4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/49/49e241388e4f3f4216ec7154a82eaad6c0c8e9f4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class JournalDetail < ActiveRecord::Base + belongs_to :journal + before_save :normalize_values + + private + + def normalize_values + self.value = normalize(value) + self.old_value = normalize(old_value) + end + + def normalize(v) + if v == true + "1" + elsif v == false + "0" + else + v + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4a0639ca12562188292e323bfd92d9487f71fda7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4a0639ca12562188292e323bfd92d9487f71fda7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,78 @@ +--- +wiki_pages_001: + created_on: 2007-03-07 00:08:07 +01:00 + title: CookBook_documentation + id: 1 + wiki_id: 1 + protected: true + parent_id: +wiki_pages_002: + created_on: 2007-03-08 00:18:07 +01:00 + title: Another_page + id: 2 + wiki_id: 1 + protected: false + parent_id: +wiki_pages_003: + created_on: 2007-03-08 00:18:07 +01:00 + title: Start_page + id: 3 + wiki_id: 2 + protected: false + parent_id: +wiki_pages_004: + created_on: 2007-03-08 00:18:07 +01:00 + title: Page_with_an_inline_image + id: 4 + wiki_id: 1 + protected: false + parent_id: 1 +wiki_pages_005: + created_on: 2007-03-08 00:18:07 +01:00 + title: Child_1 + id: 5 + wiki_id: 1 + protected: false + parent_id: 2 +wiki_pages_006: + created_on: 2007-03-08 00:18:07 +01:00 + title: Child_2 + id: 6 + wiki_id: 1 + protected: false + parent_id: 2 +wiki_pages_007: + created_on: 2007-03-08 00:18:07 +01:00 + title: Child_page_1 + id: 7 + wiki_id: 2 + protected: false + parent_id: 8 +wiki_pages_008: + created_on: 2007-03-08 00:18:07 +01:00 + title: Parent_page + id: 8 + wiki_id: 2 + protected: false + parent_id: +wiki_pages_009: + created_on: 2007-03-08 00:18:07 +01:00 + title: Child_page_2 + id: 9 + wiki_id: 2 + protected: false + parent_id: 8 +wiki_pages_010: + created_on: 2007-03-08 00:18:07 +01:00 + title: Этика_менеджмента + id: 10 + wiki_id: 1 + protected: false + parent_id: +wiki_pages_011: + created_on: 2007-03-08 00:18:07 +01:00 + title: Page_with_sections + id: 11 + wiki_id: 1 + protected: false + parent_id: diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4a0b59f652c0c5306fec4e23a9b966da98c95f60.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4a0b59f652c0c5306fec4e23a9b966da98c95f60.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +class CreateTimeEntries < ActiveRecord::Migration + def self.up + create_table :time_entries do |t| + t.column :project_id, :integer, :null => false + t.column :user_id, :integer, :null => false + t.column :issue_id, :integer + t.column :hours, :float, :null => false + t.column :comments, :string, :limit => 255 + t.column :activity_id, :integer, :null => false + t.column :spent_on, :date, :null => false + t.column :tyear, :integer, :null => false + t.column :tmonth, :integer, :null => false + t.column :tweek, :integer, :null => false + t.column :created_on, :datetime, :null => false + t.column :updated_on, :datetime, :null => false + end + add_index :time_entries, [:project_id], :name => :time_entries_project_id + add_index :time_entries, [:issue_id], :name => :time_entries_issue_id + end + + def self.down + drop_table :time_entries + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4a23cff6d2e8f3f4391d3ef5634965a5324bf60d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4a23cff6d2e8f3f4391d3ef5634965a5324bf60d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +module RFPDF + module TemplateHandlers + class Base < ::ActionView::TemplateHandlers::ERB + + def compile(template) + src = "_rfpdf_compile_setup;" + super + end + end + end +end + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4a4cc530e16fc15272849a68536d70a8eaa8b683.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4a4cc530e16fc15272849a68536d70a8eaa8b683.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class CommentTest < ActiveSupport::TestCase + fixtures :users, :news, :comments + + def setup + @jsmith = User.find(2) + @news = News.find(1) + end + + def test_create + comment = Comment.new(:commented => @news, :author => @jsmith, :comments => "my comment") + assert comment.save + @news.reload + assert_equal 2, @news.comments_count + end + + def test_create_should_send_notification + Setting.notified_events << 'news_comment_added' + Watcher.create!(:watchable => @news, :user => @jsmith) + + assert_difference 'ActionMailer::Base.deliveries.size' do + Comment.create!(:commented => @news, :author => @jsmith, :comments => "my comment") + end + end + + def test_validate + comment = Comment.new(:commented => @news) + assert !comment.save + assert_equal 2, comment.errors.length + end + + def test_destroy + comment = Comment.find(1) + assert comment.destroy + @news.reload + assert_equal 0, @news.comments_count + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4a7aa8e524e7ffcb9d61a2f01e83b69a07ba112b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4a7aa8e524e7ffcb9d61a2f01e83b69a07ba112b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +<% if version.completed? %> +

<%= format_date(version.effective_date) %>

+<% elsif version.effective_date %> +

<%= due_date_distance_in_words(version.effective_date) %> (<%= format_date(version.effective_date) %>)

+<% end %> + +

<%=h version.description %>

+
    + <% version.custom_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
  • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
  • + <% end %> + <% end %> +
+ +<% if version.fixed_issues.count > 0 %> + <%= progress_bar([version.closed_pourcent, version.completed_pourcent], :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %> +

+ <%= link_to_if(version.closed_issues_count > 0, l(:label_x_closed_issues_abbr, :count => version.closed_issues_count), :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %> + (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%) +   + <%= link_to_if(version.open_issues_count > 0, l(:label_x_open_issues_abbr, :count => version.open_issues_count), :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %> + (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%) +

+<% else %> +

<%= l(:label_roadmap_no_issues) %>

+<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4ab9278cce0785883057ff4ba259f3d5b17b6fd7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4ab9278cce0785883057ff4ba259f3d5b17b6fd7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,53 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'mail_handler_controller' + +# Re-raise errors caught by the controller. +class MailHandlerController; def rescue_action(e) raise e end; end + +class MailHandlerControllerTest < ActionController::TestCase + fixtures :users, :projects, :enabled_modules, :roles, :members, :member_roles, :issues, :issue_statuses, :trackers, :enumerations + + FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler' + + def setup + @controller = MailHandlerController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_should_create_issue + # Enable API and set a key + Setting.mail_handler_api_enabled = 1 + Setting.mail_handler_api_key = 'secret' + + post :index, :key => 'secret', :email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) + assert_response 201 + end + + def test_should_not_allow + # Disable API + Setting.mail_handler_api_enabled = 0 + Setting.mail_handler_api_key = 'secret' + + post :index, :key => 'secret', :email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) + assert_response 403 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4acf53c4cc6bbba75432401fef2bc6a21f92b246.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4a/4acf53c4cc6bbba75432401fef2bc6a21f92b246.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +ActsAsList +========== + +This acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a +position+ column defined as an integer on the mapped database table. + + +Example +======= + + class TodoList < ActiveRecord::Base + has_many :todo_items, :order => "position" + end + + class TodoItem < ActiveRecord::Base + belongs_to :todo_list + acts_as_list :scope => :todo_list + end + + todo_list.first.move_to_bottom + todo_list.last.move_higher + + +Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4a/4ae51c2679d1e5d524bca8962c5f290fef11df00.svn-base Binary file .svn/pristine/4a/4ae51c2679d1e5d524bca8962c5f290fef11df00.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4b/4b4de4b924745eb31dbf2319917091a84bc1704f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4b/4b4de4b924745eb31dbf2319917091a84bc1704f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,486 @@ +# Copyright (c) 2006 4ssoM LLC +# 1.12 contributed by Ed Moss. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# This is direct port of chinese.php +# +# Chinese PDF support. +# +# Usage is as follows: +# +# require 'fpdf' +# require 'chinese' +# pdf = FPDF.new +# pdf.extend(PDF_Chinese) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_Chinese + + Big5_widths={' '=>250,'!'=>250,'"'=>408,'#'=>668,'$'=>490,'%'=>875,'&'=>698,'\''=>250, + '('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500, + '2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,';'=>250, + '<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625, + 'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823, + 'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677, + 'Z'=>635,'['=>344,'\\'=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427, + 'd'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802, + 'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677, + 'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'}'=>480,'~'=>667} + + GB_widths={' '=>207,'!'=>270,'"'=>342,'#'=>467,'$'=>462,'%'=>797,'&'=>710,'\''=>239, + '('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462, + '2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,';'=>238, + '<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563, + 'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772, + 'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620, + 'Z'=>607,'['=>374,'\\'=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427, + 'd'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793, + 'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652, + 'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'}'=>370,'~'=>605} + + def AddCIDFont(family,style,name,cw,cMap,registry) +#ActionController::Base::logger.debug registry.to_a.join(":").to_s + fontkey=family.downcase+style.upcase + unless @fonts[fontkey].nil? + Error("Font already added: family style") + end + i=@fonts.length+1 + name=name.gsub(' ','') + @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, 'CMap'=>cMap,'registry'=>registry} + end + + def AddCIDFonts(family,name,cw,cMap,registry) + AddCIDFont(family,'',name,cw,cMap,registry) + AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) + AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) + AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) + end + + def AddBig5Font(family='Big5',name='MSungStd-Light-Acro') + #Add Big5 font with proportional Latin + cw=Big5_widths + cMap='ETenms-B5-H' + registry={'ordering'=>'CNS1','supplement'=>0} +#ActionController::Base::logger.debug registry.to_a.join(":").to_s + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddBig5hwFont(family='Big5-hw',name='MSungStd-Light-Acro') + #Add Big5 font with half-witdh Latin + cw = {} + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='ETen-B5-H' + registry={'ordering'=>'CNS1','supplement'=>0} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddGBFont(family='GB',name='STSongStd-Light-Acro') + #Add GB font with proportional Latin + cw=GB_widths + cMap='GBKp-EUC-H' + registry={'ordering'=>'GB1','supplement'=>2} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def AddGBhwFont(family='GB-hw',name='STSongStd-Light-Acro') + #Add GB font with half-width Latin + 32.upto(126) do |i| + cw[i.chr]=500 + end + cMap='GBK-EUC-H' + registry={'ordering'=>'GB1','supplement'=>2} + AddCIDFonts(family,name,cw,cMap,registry) + end + + def GetStringWidth(s) + if(@current_font['type']=='Type0') + return GetMBStringWidth(s) + else + return super(s) + end + end + + def GetMBStringWidth(s) + #Multi-byte version of GetStringWidth() + l=0 + cw=@current_font['cw'] + nb=s.length + i=0 + while(i0 and s[nb-1]=="\n") + nb-=1 + end + b=0 + if(border) + if(border==1) + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + b2='L' unless border.to_s.index('L').nil? + b2=b2+'R' unless border.to_s.index('R').nil? + b=(border.to_s.index('T')) ? (b2+'T') : b2 + end + end + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],b,2,align,fill) + else + Cell(w,h,s[j,sep-j],b,2,align,fill) + i=(s[sep].chr==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + nl+=1 + if(border and nl==2) + b=b2 + end + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(border and not border.to_s.index('B').nil?) + b+='B' + end + Cell(w,h,s[j,i-j],b,2,align,fill) + + # move cursor to specified position + if (ln == 1) + # go to the beginning of the next line + @x=@l_margin + elsif (ln == 0) + # go to the top-right of the cell + @y = prevy; + @x = prevx + w; + elsif (ln == 2) + # go to the bottom-left of the cell + @x = prevx; + end + end + + def Write(h,txt,link='',fill=0) + if(@current_font['type']=='Type0') + MBWrite(h,txt,link,fill) + else + super(h,txt,link,fill) + end + end + + def MBWrite(h,txt,link,fill=0) + #Multi-byte version of Write() + cw=@current_font['cw'] + w=@w-@r_margin-@x + wmax=(w-2*@c_margin)*1000/@font_size + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while(iwmax) + #Automatic line break + if(sep==-1 or i==j) + if(@x>@l_margin) + #Move to next line + @x=@l_margin + @y+=h + w=@w-@r_margin-@x + wmax=(w-2*@c_margin)*1000/@font_size + i+=1 + nl+=1 + next + end + if(i==j) + i+=ascii ? 1 : 2 + end + Cell(w,h,s[j,i-j],0,2,'',fill,link) + else + Cell(w,h,s[j,sep-j],0,2,'',fill,link) + i=(s[sep].chr==' ') ? sep+1 : sep + end + sep=-1 + j=i + l=0 + if(nl==1) + @x=@l_margin + w=@w-@r_margin-@x + wmax=(w-2*@c_margin)*1000/@font_size + end + nl+=1 + else + i+=ascii ? 1 : 2 + end + end + #Last chunk + if(i!=j) + Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link) + end + end + +private + + def putfonts() + nf=@n + @diffs.each do |diff| + #Encodings + newobj() + out('<>') + out('endobj') + end + # mqr=get_magic_quotes_runtime() + # set_magic_quotes_runtime(0) + @font_files.each_pair do |file, info| + #Font file embedding + newobj() + @font_files[file]['n']=@n + if(defined('FPDF_FONTPATH')) + file=FPDF_FONTPATH+file + end + size=filesize(file) + if(!size) + Error('Font file not found') + end + out('<>') + f=fopen(file,'rb') + putstream(fread(f,size)) + fclose(f) + out('endobj') + end +# + # set_magic_quotes_runtime(mqr) +# + @fonts.each_pair do |k, font| + #Font objects + newobj() + @fonts[k]['n']=@n + out('<>') + out('endobj') + if(font['type']!='core') + #Widths + newobj() + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s+=cw[i.chr]+' ' + end + out(s+']') + out('endobj') + #Descriptor + newobj() + s='<>') + out('endobj') + end + end + end + end + + def putType0(font) + #Type0 + out('/Subtype /Type0') + out('/BaseFont /'+font['name']+'-'+font['CMap']) + out('/Encoding /'+font['CMap']) + out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') + out('>>') + out('endobj') + #CIDFont + newobj() + out('<>') + out('/FontDescriptor '+(@n+1).to_s+' 0 R') + if(font['CMap']=='ETen-B5-H') + w='13648 13742 500' + elsif(font['CMap']=='GBK-EUC-H') + w='814 907 500 7716 [500]' + else + # ActionController::Base::logger.debug font['cw'].keys.sort.join(' ').to_s + # ActionController::Base::logger.debug font['cw'].values.join(' ').to_s + w='1 [' + font['cw'].keys.sort.each {|key| + w+=font['cw'][key].to_s + " " +# ActionController::Base::logger.debug key.to_s +# ActionController::Base::logger.debug font['cw'][key].to_s + } + w +=']' + end + out('/W ['+w+']>>') + out('endobj') + #Font descriptor + newobj() + out('<>') + out('endobj') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4b/4b587f932497db9752b0e60b835b63dc3bb6f32b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4b/4b587f932497db9752b0e60b835b63dc3bb6f32b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AC Euro +!A5 U+00A5 yen +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+017D Zcaron +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4b/4b9d105a6ddf9e2913feb748f35b6ced3a593557.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4b/4b9d105a6ddf9e2913feb748f35b6ced3a593557.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1045 @@ +# Spanish translations for Rails +# by Francisco Fernando García Nieto (ffgarcianieto@gmail.com) +# Redmine spanish translation: +# by J. Cayetano Delgado (Cayetano _dot_ Delgado _at_ ioko _dot_ com) + +es: + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "," + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "." + # Number of decimals, behind the separator (1 with a precision of 2 gives: 1.00) + precision: 3 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%n %u" + unit: "€" + # These three are to override number.format and are optional + separator: "," + delimiter: "." + precision: 2 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "medio minuto" + less_than_x_seconds: + one: "menos de 1 segundo" + other: "menos de %{count} segundos" + x_seconds: + one: "1 segundo" + other: "%{count} segundos" + less_than_x_minutes: + one: "menos de 1 minuto" + other: "menos de %{count} minutos" + x_minutes: + one: "1 minuto" + other: "%{count} minutos" + about_x_hours: + one: "alrededor de 1 hora" + other: "alrededor de %{count} horas" + x_days: + one: "1 día" + other: "%{count} días" + about_x_months: + one: "alrededor de 1 mes" + other: "alrededor de %{count} meses" + x_months: + one: "1 mes" + other: "%{count} meses" + about_x_years: + one: "alrededor de 1 año" + other: "alrededor de %{count} años" + over_x_years: + one: "más de 1 año" + other: "más de %{count} años" + almost_x_years: + one: "casi 1 año" + other: "casi %{count} años" + + activerecord: + errors: + template: + header: + one: "no se pudo guardar este %{model} porque se encontró 1 error" + other: "no se pudo guardar este %{model} porque se encontraron %{count} errores" + # The variable :count is also available + body: "Se encontraron problemas con los siguientes campos:" + + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "no está incluido en la lista" + exclusion: "está reservado" + invalid: "no es válido" + confirmation: "no coincide con la confirmación" + accepted: "debe ser aceptado" + empty: "no puede estar vacío" + blank: "no puede estar en blanco" + too_long: "es demasiado largo (%{count} caracteres máximo)" + too_short: "es demasiado corto (%{count} caracteres mínimo)" + wrong_length: "no tiene la longitud correcta (%{count} caracteres exactos)" + taken: "ya está en uso" + not_a_number: "no es un número" + greater_than: "debe ser mayor que %{count}" + greater_than_or_equal_to: "debe ser mayor que o igual a %{count}" + equal_to: "debe ser igual a %{count}" + less_than: "debe ser menor que %{count}" + less_than_or_equal_to: "debe ser menor que o igual a %{count}" + odd: "debe ser impar" + even: "debe ser par" + greater_than_start_date: "debe ser posterior a la fecha de comienzo" + not_same_project: "no pertenece al mismo proyecto" + circular_dependency: "Esta relación podría crear una dependencia circular" + cant_link_an_issue_with_a_descendant: "Esta petición no puede ser ligada a una de estas tareas" + + # Append your own errors here or at the model/attributes scope. + + models: + # Overrides default messages + + attributes: + # Overrides model and default messages. + + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%d de %b" + long: "%d de %B de %Y" + + day_names: [Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado] + abbr_day_names: [Dom, Lun, Mar, Mie, Jue, Vie, Sab] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Setiembre, Octubre, Noviembre, Diciembre] + abbr_month_names: [~, Ene, Feb, Mar, Abr, May, Jun, Jul, Ago, Set, Oct, Nov, Dic] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%A, %d de %B de %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d de %b %H:%M" + long: "%d de %B de %Y %H:%M" + am: "am" + pm: "pm" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "y" + + actionview_instancetag_blank_option: Por favor seleccione + + button_activate: Activar + button_add: Añadir + button_annotate: Anotar + button_apply: Aceptar + button_archive: Archivar + button_back: Atrás + button_cancel: Cancelar + button_change: Cambiar + button_change_password: Cambiar contraseña + button_check_all: Seleccionar todo + button_clear: Anular + button_configure: Configurar + button_copy: Copiar + button_create: Crear + button_delete: Borrar + button_download: Descargar + button_edit: Modificar + button_list: Listar + button_lock: Bloquear + button_log_time: Tiempo dedicado + button_login: Conexión + button_move: Mover + button_quote: Citar + button_rename: Renombrar + button_reply: Responder + button_reset: Reestablecer + button_rollback: Volver a esta versión + button_save: Guardar + button_sort: Ordenar + button_submit: Aceptar + button_test: Probar + button_unarchive: Desarchivar + button_uncheck_all: No seleccionar nada + button_unlock: Desbloquear + button_unwatch: No monitorizar + button_update: Actualizar + button_view: Ver + button_watch: Monitorizar + default_activity_design: Diseño + default_activity_development: Desarrollo + default_doc_category_tech: Documentación técnica + default_doc_category_user: Documentación de usuario + default_issue_status_in_progress: En curso + default_issue_status_closed: Cerrada + default_issue_status_feedback: Comentarios + default_issue_status_new: Nueva + default_issue_status_rejected: Rechazada + default_issue_status_resolved: Resuelta + default_priority_high: Alta + default_priority_immediate: Inmediata + default_priority_low: Baja + default_priority_normal: Normal + default_priority_urgent: Urgente + default_role_developer: Desarrollador + default_role_manager: Jefe de proyecto + default_role_reporter: Informador + default_tracker_bug: Errores + default_tracker_feature: Tareas + default_tracker_support: Soporte + enumeration_activities: Actividades (tiempo dedicado) + enumeration_doc_categories: Categorías del documento + enumeration_issue_priorities: Prioridad de las peticiones + error_can_t_load_default_data: "No se ha podido cargar la configuración por defecto: %{value}" + error_issue_not_found_in_project: 'La petición no se encuentra o no está asociada a este proyecto' + error_scm_annotate: "No existe la entrada o no ha podido ser anotada" + error_scm_annotate_big_text_file: "La entrada no puede anotarse, al superar el tamaño máximo para ficheros de texto." + error_scm_command_failed: "Se produjo un error al acceder al repositorio: %{value}" + error_scm_not_found: "La entrada y/o la revisión no existe en el repositorio." + field_account: Cuenta + field_activity: Actividad + field_admin: Administrador + field_assignable: Se pueden asignar peticiones a este perfil + field_assigned_to: Asignado a + field_attr_firstname: Cualidad del nombre + field_attr_lastname: Cualidad del apellido + field_attr_login: Cualidad del identificador + field_attr_mail: Cualidad del Email + field_auth_source: Modo de identificación + field_author: Autor + field_base_dn: DN base + field_category: Categoría + field_column_names: Columnas + field_comments: Comentario + field_comments_sorting: Mostrar comentarios + field_created_on: Creado + field_default_value: Estado por defecto + field_delay: Retraso + field_description: Descripción + field_done_ratio: "% Realizado" + field_downloads: Descargas + field_due_date: Fecha fin + field_effective_date: Fecha + field_estimated_hours: Tiempo estimado + field_field_format: Formato + field_filename: Fichero + field_filesize: Tamaño + field_firstname: Nombre + field_fixed_version: Versión prevista + field_hide_mail: Ocultar mi dirección de correo + field_homepage: Sitio web + field_host: Anfitrión + field_hours: Horas + field_identifier: Identificador + field_is_closed: Petición resuelta + field_is_default: Estado por defecto + field_is_filter: Usado como filtro + field_is_for_all: Para todos los proyectos + field_is_in_roadmap: Consultar las peticiones en la planificación + field_is_public: Público + field_is_required: Obligatorio + field_issue: Petición + field_issue_to: Petición relacionada + field_language: Idioma + field_last_login_on: Última conexión + field_lastname: Apellido + field_login: Identificador + field_mail: Correo electrónico + field_mail_notification: Notificaciones por correo + field_max_length: Longitud máxima + field_min_length: Longitud mínima + field_name: Nombre + field_new_password: Nueva contraseña + field_notes: Notas + field_onthefly: Creación del usuario "al vuelo" + field_parent: Proyecto padre + field_parent_title: Página padre + field_password: Contraseña + field_password_confirmation: Confirmación + field_port: Puerto + field_possible_values: Valores posibles + field_priority: Prioridad + field_project: Proyecto + field_redirect_existing_links: Redireccionar enlaces existentes + field_regexp: Expresión regular + field_role: Perfil + field_searchable: Incluir en las búsquedas + field_spent_on: Fecha + field_start_date: Fecha de inicio + field_start_page: Página principal + field_status: Estado + field_subject: Asunto + field_subproject: Proyecto secundario + field_summary: Resumen + field_time_zone: Zona horaria + field_title: Título + field_tracker: Tipo + field_type: Tipo + field_updated_on: Actualizado + field_url: URL + field_user: Usuario + field_value: Valor + field_version: Versión + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Español' + general_pdf_encoding: UTF-8 + general_text_No: 'No' + general_text_Yes: 'Sí' + general_text_no: 'no' + general_text_yes: 'sí' + gui_validation_error: 1 error + gui_validation_error_plural: "%{count} errores" + label_activity: Actividad + label_add_another_file: Añadir otro fichero + label_add_note: Añadir una nota + label_added: añadido + label_added_time_by: "Añadido por %{author} hace %{age}" + label_administration: Administración + label_age: Edad + label_ago: hace + label_all: todos + label_all_time: todo el tiempo + label_all_words: Todas las palabras + label_and_its_subprojects: "%{value} y proyectos secundarios" + label_applied_status: Aplicar estado + label_assigned_to_me_issues: Peticiones que me están asignadas + label_associated_revisions: Revisiones asociadas + label_attachment: Fichero + label_attachment_delete: Borrar el fichero + label_attachment_new: Nuevo fichero + label_attachment_plural: Ficheros + label_attribute: Cualidad + label_attribute_plural: Cualidades + label_auth_source: Modo de autenticación + label_auth_source_new: Nuevo modo de autenticación + label_auth_source_plural: Modos de autenticación + label_authentication: Autenticación + label_blocked_by: bloqueado por + label_blocks: bloquea a + label_board: Foro + label_board_new: Nuevo foro + label_board_plural: Foros + label_boolean: Booleano + label_browse: Hojear + label_bulk_edit_selected_issues: Editar las peticiones seleccionadas + label_calendar: Calendario + label_change_plural: Cambios + label_change_properties: Cambiar propiedades + label_change_status: Cambiar el estado + label_change_view_all: Ver todos los cambios + label_changes_details: Detalles de todos los cambios + label_changeset_plural: Cambios + label_chronological_order: En orden cronológico + label_closed_issues: cerrada + label_closed_issues_plural: cerradas + label_x_open_issues_abbr_on_total: + zero: 0 abiertas / %{total} + one: 1 abierta / %{total} + other: "%{count} abiertas / %{total}" + label_x_open_issues_abbr: + zero: 0 abiertas + one: 1 abierta + other: "%{count} abiertas" + label_x_closed_issues_abbr: + zero: 0 cerradas + one: 1 cerrada + other: "%{count} cerradas" + label_comment: Comentario + label_comment_add: Añadir un comentario + label_comment_added: Comentario añadido + label_comment_delete: Borrar comentarios + label_comment_plural: Comentarios + label_x_comments: + zero: sin comentarios + one: 1 comentario + other: "%{count} comentarios" + label_commits_per_author: Commits por autor + label_commits_per_month: Commits por mes + label_confirmation: Confirmación + label_contains: contiene + label_copied: copiado + label_copy_workflow_from: Copiar flujo de trabajo desde + label_current_status: Estado actual + label_current_version: Versión actual + label_custom_field: Campo personalizado + label_custom_field_new: Nuevo campo personalizado + label_custom_field_plural: Campos personalizados + label_date: Fecha + label_date_from: Desde + label_date_range: Rango de fechas + label_date_to: Hasta + label_day_plural: días + label_default: Por defecto + label_default_columns: Columnas por defecto + label_deleted: suprimido + label_details: Detalles + label_diff_inline: en línea + label_diff_side_by_side: cara a cara + label_disabled: deshabilitado + label_display_per_page: "Por página: %{value}" + label_document: Documento + label_document_added: Documento añadido + label_document_new: Nuevo documento + label_document_plural: Documentos + label_download: "%{count} Descarga" + label_download_plural: "%{count} Descargas" + label_downloads_abbr: D/L + label_duplicated_by: duplicada por + label_duplicates: duplicada de + label_end_to_end: fin a fin + label_end_to_start: fin a principio + label_enumeration_new: Nuevo valor + label_enumerations: Listas de valores + label_environment: Entorno + label_equals: igual + label_example: Ejemplo + label_export_to: 'Exportar a:' + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_feed_plural: Feeds + label_feeds_access_key_created_on: "Clave de acceso por RSS creada hace %{value}" + label_file_added: Fichero añadido + label_file_plural: Archivos + label_filter_add: Añadir el filtro + label_filter_plural: Filtros + label_float: Flotante + label_follows: posterior a + label_gantt: Gantt + label_general: General + label_generate_key: Generar clave + label_help: Ayuda + label_history: Histórico + label_home: Inicio + label_in: en + label_in_less_than: en menos que + label_in_more_than: en más que + label_incoming_emails: Correos entrantes + label_index_by_date: Índice por fecha + label_index_by_title: Índice por título + label_information: Información + label_information_plural: Información + label_integer: Número + label_internal: Interno + label_issue: Petición + label_issue_added: Petición añadida + label_issue_category: Categoría de las peticiones + label_issue_category_new: Nueva categoría + label_issue_category_plural: Categorías de las peticiones + label_issue_new: Nueva petición + label_issue_plural: Peticiones + label_issue_status: Estado de la petición + label_issue_status_new: Nuevo estado + label_issue_status_plural: Estados de las peticiones + label_issue_tracking: Peticiones + label_issue_updated: Petición actualizada + label_issue_view_all: Ver todas las peticiones + label_issue_watchers: Seguidores + label_issues_by: "Peticiones por %{value}" + label_jump_to_a_project: Ir al proyecto... + label_language_based: Basado en el idioma + label_last_changes: "últimos %{count} cambios" + label_last_login: Última conexión + label_last_month: último mes + label_last_n_days: "últimos %{count} días" + label_last_week: última semana + label_latest_revision: Última revisión + label_latest_revision_plural: Últimas revisiones + label_ldap_authentication: Autenticación LDAP + label_less_than_ago: hace menos de + label_list: Lista + label_loading: Cargando... + label_logged_as: Conectado como + label_login: Conexión + label_logout: Desconexión + label_max_size: Tamaño máximo + label_me: yo mismo + label_member: Miembro + label_member_new: Nuevo miembro + label_member_plural: Miembros + label_message_last: Último mensaje + label_message_new: Nuevo mensaje + label_message_plural: Mensajes + label_message_posted: Mensaje añadido + label_min_max_length: Longitud mín - máx + label_modification: "%{count} modificación" + label_modification_plural: "%{count} modificaciones" + label_modified: modificado + label_module_plural: Módulos + label_month: Mes + label_months_from: meses de + label_more: Más + label_more_than_ago: hace más de + label_my_account: Mi cuenta + label_my_page: Mi página + label_my_projects: Mis proyectos + label_new: Nuevo + label_new_statuses_allowed: Nuevos estados autorizados + label_news: Noticia + label_news_added: Noticia añadida + label_news_latest: Últimas noticias + label_news_new: Nueva noticia + label_news_plural: Noticias + label_news_view_all: Ver todas las noticias + label_next: Siguiente + label_no_change_option: (Sin cambios) + label_no_data: Ningún dato disponible + label_nobody: nadie + label_none: ninguno + label_not_contains: no contiene + label_not_equals: no igual + label_open_issues: abierta + label_open_issues_plural: abiertas + label_optional_description: Descripción opcional + label_options: Opciones + label_overall_activity: Actividad global + label_overview: Vistazo + label_password_lost: ¿Olvidaste la contraseña? + label_per_page: Por página + label_permissions: Permisos + label_permissions_report: Informe de permisos + label_personalize_page: Personalizar esta página + label_planning: Planificación + label_please_login: Conexión + label_plugins: Extensiones + label_precedes: anterior a + label_preferences: Preferencias + label_preview: Previsualizar + label_previous: Anterior + label_project: Proyecto + label_project_all: Todos los proyectos + label_project_latest: Últimos proyectos + label_project_new: Nuevo proyecto + label_project_plural: Proyectos + label_x_projects: + zero: sin proyectos + one: 1 proyecto + other: "%{count} proyectos" + label_public_projects: Proyectos públicos + label_query: Consulta personalizada + label_query_new: Nueva consulta + label_query_plural: Consultas personalizadas + label_read: Leer... + label_register: Registrar + label_registered_on: Inscrito el + label_registration_activation_by_email: activación de cuenta por correo + label_registration_automatic_activation: activación automática de cuenta + label_registration_manual_activation: activación manual de cuenta + label_related_issues: Peticiones relacionadas + label_relates_to: relacionada con + label_relation_delete: Eliminar relación + label_relation_new: Nueva relación + label_renamed: renombrado + label_reply_plural: Respuestas + label_report: Informe + label_report_plural: Informes + label_reported_issues: Peticiones registradas por mí + label_repository: Repositorio + label_repository_plural: Repositorios + label_result_plural: Resultados + label_reverse_chronological_order: En orden cronológico inverso + label_revision: Revisión + label_revision_plural: Revisiones + label_roadmap: Planificación + label_roadmap_due_in: "Finaliza en %{value}" + label_roadmap_no_issues: No hay peticiones para esta versión + label_roadmap_overdue: "%{value} tarde" + label_role: Perfil + label_role_and_permissions: Perfiles y permisos + label_role_new: Nuevo perfil + label_role_plural: Perfiles + label_scm: SCM + label_search: Búsqueda + label_search_titles_only: Buscar sólo en títulos + label_send_information: Enviar información de la cuenta al usuario + label_send_test_email: Enviar un correo de prueba + label_settings: Configuración + label_show_completed_versions: Muestra las versiones terminadas + label_sort_by: "Ordenar por %{value}" + label_sort_higher: Subir + label_sort_highest: Primero + label_sort_lower: Bajar + label_sort_lowest: Último + label_spent_time: Tiempo dedicado + label_start_to_end: principio a fin + label_start_to_start: principio a principio + label_statistics: Estadísticas + label_stay_logged_in: Recordar conexión + label_string: Texto + label_subproject_plural: Proyectos secundarios + label_text: Texto largo + label_theme: Tema + label_this_month: este mes + label_this_week: esta semana + label_this_year: este año + label_time_tracking: Control de tiempo + label_today: hoy + label_topic_plural: Temas + label_total: Total + label_tracker: Tipo + label_tracker_new: Nuevo tipo + label_tracker_plural: Tipos de peticiones + label_updated_time: "Actualizado hace %{value}" + label_updated_time_by: "Actualizado por %{author} hace %{age}" + label_used_by: Utilizado por + label_user: Usuario + label_user_activity: "Actividad de %{value}" + label_user_mail_no_self_notified: "No quiero ser avisado de cambios hechos por mí" + label_user_mail_option_all: "Para cualquier evento en todos mis proyectos" + label_user_mail_option_selected: "Para cualquier evento de los proyectos seleccionados..." + label_user_new: Nuevo usuario + label_user_plural: Usuarios + label_version: Versión + label_version_new: Nueva versión + label_version_plural: Versiones + label_view_diff: Ver diferencias + label_view_revisions: Ver las revisiones + label_watched_issues: Peticiones monitorizadas + label_week: Semana + label_wiki: Wiki + label_wiki_edit: Modificación Wiki + label_wiki_edit_plural: Modificaciones Wiki + label_wiki_page: Página Wiki + label_wiki_page_plural: Páginas Wiki + label_workflow: Flujo de trabajo + label_year: Año + label_yesterday: ayer + mail_body_account_activation_request: "Se ha inscrito un nuevo usuario (%{value}). La cuenta está pendiende de aprobación:" + mail_body_account_information: Información sobre su cuenta + mail_body_account_information_external: "Puede usar su cuenta %{value} para conectarse." + mail_body_lost_password: 'Para cambiar su contraseña, haga clic en el siguiente enlace:' + mail_body_register: 'Para activar su cuenta, haga clic en el siguiente enlace:' + mail_body_reminder: "%{count} peticion(es) asignadas a tí finalizan en los próximos %{days} días:" + mail_subject_account_activation_request: "Petición de activación de cuenta %{value}" + mail_subject_lost_password: "Tu contraseña del %{value}" + mail_subject_register: "Activación de la cuenta del %{value}" + mail_subject_reminder: "%{count} peticion(es) finalizan en los próximos %{days} días" + notice_account_activated: Su cuenta ha sido activada. Ya puede conectarse. + notice_account_invalid_creditentials: Usuario o contraseña inválido. + notice_account_lost_email_sent: Se le ha enviado un correo con instrucciones para elegir una nueva contraseña. + notice_account_password_updated: Contraseña modificada correctamente. + notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aprobación por parte del administrador." + notice_account_register_done: Cuenta creada correctamente. Para activarla, haga clic sobre el enlace que le ha sido enviado por correo. + notice_account_unknown_email: Usuario desconocido. + notice_account_updated: Cuenta actualizada correctamente. + notice_account_wrong_password: Contraseña incorrecta. + notice_can_t_change_password: Esta cuenta utiliza una fuente de autenticación externa. No es posible cambiar la contraseña. + notice_default_data_loaded: Configuración por defecto cargada correctamente. + notice_email_error: "Ha ocurrido un error mientras enviando el correo (%{value})" + notice_email_sent: "Se ha enviado un correo a %{value}" + notice_failed_to_save_issues: "Imposible grabar %{count} peticion(es) de %{total} seleccionada(s): %{ids}." + notice_feeds_access_key_reseted: Su clave de acceso para RSS ha sido reiniciada. + notice_file_not_found: La página a la que intenta acceder no existe. + notice_locking_conflict: Los datos han sido modificados por otro usuario. + notice_no_issue_selected: "Ninguna petición seleccionada. Por favor, compruebe la petición que quiere modificar" + notice_not_authorized: No tiene autorización para acceder a esta página. + notice_successful_connection: Conexión correcta. + notice_successful_create: Creación correcta. + notice_successful_delete: Borrado correcto. + notice_successful_update: Modificación correcta. + notice_unable_delete_version: No se puede borrar la versión + permission_add_issue_notes: Añadir notas + permission_add_issue_watchers: Añadir seguidores + permission_add_issues: Añadir peticiones + permission_add_messages: Enviar mensajes + permission_browse_repository: Hojear repositiorio + permission_comment_news: Comentar noticias + permission_commit_access: Acceso de escritura + permission_delete_issues: Borrar peticiones + permission_delete_messages: Borrar mensajes + permission_delete_own_messages: Borrar mensajes propios + permission_delete_wiki_pages: Borrar páginas wiki + permission_delete_wiki_pages_attachments: Borrar ficheros + permission_edit_issue_notes: Modificar notas + permission_edit_issues: Modificar peticiones + permission_edit_messages: Modificar mensajes + permission_edit_own_issue_notes: Modificar notas propias + permission_edit_own_messages: Editar mensajes propios + permission_edit_own_time_entries: Modificar tiempos dedicados propios + permission_edit_project: Modificar proyecto + permission_edit_time_entries: Modificar tiempos dedicados + permission_edit_wiki_pages: Modificar páginas wiki + permission_log_time: Anotar tiempo dedicado + permission_manage_boards: Administrar foros + permission_manage_categories: Administrar categorías de peticiones + permission_manage_documents: Administrar documentos + permission_manage_files: Administrar ficheros + permission_manage_issue_relations: Administrar relación con otras peticiones + permission_manage_members: Administrar miembros + permission_manage_news: Administrar noticias + permission_manage_public_queries: Administrar consultas públicas + permission_manage_repository: Administrar repositorio + permission_manage_versions: Administrar versiones + permission_manage_wiki: Administrar wiki + permission_move_issues: Mover peticiones + permission_protect_wiki_pages: Proteger páginas wiki + permission_rename_wiki_pages: Renombrar páginas wiki + permission_save_queries: Grabar consultas + permission_select_project_modules: Seleccionar módulos del proyecto + permission_view_calendar: Ver calendario + permission_view_changesets: Ver cambios + permission_view_documents: Ver documentos + permission_view_files: Ver ficheros + permission_view_gantt: Ver diagrama de Gantt + permission_view_issue_watchers: Ver lista de seguidores + permission_view_messages: Ver mensajes + permission_view_time_entries: Ver tiempo dedicado + permission_view_wiki_edits: Ver histórico del wiki + permission_view_wiki_pages: Ver wiki + project_module_boards: Foros + project_module_documents: Documentos + project_module_files: Ficheros + project_module_issue_tracking: Peticiones + project_module_news: Noticias + project_module_repository: Repositorio + project_module_time_tracking: Control de tiempo + project_module_wiki: Wiki + setting_activity_days_default: Días a mostrar en la actividad de proyecto + setting_app_subtitle: Subtítulo de la aplicación + setting_app_title: Título de la aplicación + setting_attachment_max_size: Tamaño máximo del fichero + setting_autofetch_changesets: Autorellenar los commits del repositorio + setting_autologin: Conexión automática + setting_bcc_recipients: Ocultar las copias de carbón (bcc) + setting_commit_fix_keywords: Palabras clave para la corrección + setting_commit_ref_keywords: Palabras clave para la referencia + setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos + setting_date_format: Formato de fecha + setting_default_language: Idioma por defecto + setting_default_projects_public: Los proyectos nuevos son públicos por defecto + setting_diff_max_lines_displayed: Número máximo de diferencias mostradas + setting_display_subprojects_issues: Mostrar por defecto peticiones de proy. secundarios en el principal + setting_emails_footer: Pie de mensajes + setting_enabled_scm: Activar SCM + setting_feeds_limit: Límite de contenido para sindicación + setting_gravatar_enabled: Usar iconos de usuario (Gravatar) + setting_host_name: Nombre y ruta del servidor + setting_issue_list_default_columns: Columnas por defecto para la lista de peticiones + setting_issues_export_limit: Límite de exportación de peticiones + setting_login_required: Se requiere identificación + setting_mail_from: Correo desde el que enviar mensajes + setting_mail_handler_api_enabled: Activar SW para mensajes entrantes + setting_mail_handler_api_key: Clave de la API + setting_per_page_options: Objetos por página + setting_plain_text_mail: sólo texto plano (no HTML) + setting_protocol: Protocolo + setting_self_registration: Registro permitido + setting_sequential_project_identifiers: Generar identificadores de proyecto + setting_sys_api_enabled: Habilitar SW para la gestión del repositorio + setting_text_formatting: Formato de texto + setting_time_format: Formato de hora + setting_user_format: Formato de nombre de usuario + setting_welcome_text: Texto de bienvenida + setting_wiki_compression: Compresión del historial del Wiki + status_active: activo + status_locked: bloqueado + status_registered: registrado + text_are_you_sure: ¿Está seguro? + text_assign_time_entries_to_project: Asignar las horas al proyecto + text_caracters_maximum: "%{count} caracteres como máximo." + text_caracters_minimum: "%{count} caracteres como mínimo." + text_comma_separated: Múltiples valores permitidos (separados por coma). + text_default_administrator_account_changed: Cuenta de administrador por defecto modificada + text_destroy_time_entries: Borrar las horas + text_destroy_time_entries_question: Existen %{hours} horas asignadas a la petición que quiere borrar. ¿Qué quiere hacer? + text_diff_truncated: '... Diferencia truncada por exceder el máximo tamaño visualizable.' + text_email_delivery_not_configured: "Las notificaciones están desactivadas porque el servidor de correo no está configurado.\nConfigure el servidor de SMTP en config/configuration.yml y reinicie la aplicación para activar los cambios." + text_enumeration_category_reassign_to: 'Reasignar al siguiente valor:' + text_enumeration_destroy_question: "%{count} objetos con este valor asignado." + text_file_repository_writable: Se puede escribir en el repositorio + text_issue_added: "Petición %{id} añadida por %{author}." + text_issue_category_destroy_assignments: Dejar las peticiones sin categoría + text_issue_category_destroy_question: "Algunas peticiones (%{count}) están asignadas a esta categoría. ¿Qué desea hacer?" + text_issue_category_reassign_to: Reasignar las peticiones a la categoría + text_issue_updated: "La petición %{id} ha sido actualizada por %{author}." + text_issues_destroy_confirmation: '¿Seguro que quiere borrar las peticiones seleccionadas?' + text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes + text_length_between: "Longitud entre %{min} y %{max} caracteres." + text_load_default_configuration: Cargar la configuración por defecto + text_min_max_length_info: 0 para ninguna restricción + text_no_configuration_data: "Todavía no se han configurado perfiles, ni tipos, estados y flujo de trabajo asociado a peticiones. Se recomiendo encarecidamente cargar la configuración por defecto. Una vez cargada, podrá modificarla." + text_project_destroy_confirmation: ¿Estás seguro de querer eliminar el proyecto? + text_project_identifier_info: 'Letras minúsculas (a-z), números y signos de puntuación permitidos.
Una vez guardado, el identificador no puede modificarse.' + text_reassign_time_entries: 'Reasignar las horas a esta petición:' + text_regexp_info: ej. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Establezca la correspondencia entre los usuarios de Redmine y los presentes en el log del repositorio.\nLos usuarios con el mismo nombre o correo en Redmine y en el repositorio serán asociados automáticamente." + text_rmagick_available: RMagick disponible (opcional) + text_select_mail_notifications: Seleccionar los eventos a notificar + text_select_project_modules: 'Seleccione los módulos a activar para este proyecto:' + text_status_changed_by_changeset: "Aplicado en los cambios %{value}" + text_subprojects_destroy_warning: "Los proyectos secundarios: %{value} también se eliminarán" + text_tip_issue_begin_day: tarea que comienza este día + text_tip_issue_begin_end_day: tarea que comienza y termina este día + text_tip_issue_end_day: tarea que termina este día + text_tracker_no_workflow: No hay ningún flujo de trabajo definido para este tipo de petición + text_unallowed_characters: Caracteres no permitidos + text_user_mail_option: "De los proyectos no seleccionados, sólo recibirá notificaciones sobre elementos monitorizados o elementos en los que esté involucrado (por ejemplo, peticiones de las que usted sea autor o asignadas a usted)." + text_user_wrote: "%{value} escribió:" + text_wiki_destroy_confirmation: ¿Seguro que quiere borrar el wiki y todo su contenido? + text_workflow_edit: Seleccionar un flujo de trabajo para actualizar + text_plugin_assets_writable: Se puede escribir en el directorio público de las extensiones + warning_attachments_not_saved: "No se han podido grabar %{count} ficheros." + button_create_and_continue: Crear y continuar + text_custom_field_possible_values_info: 'Un valor en cada línea' + label_display: Mostrar + field_editable: Modificable + setting_repository_log_display_limit: Número máximo de revisiones mostradas en el fichero de trazas + setting_file_max_size_displayed: Tamaño máximo de los ficheros de texto mostrados + field_watcher: Seguidor + setting_openid: Permitir identificación y registro por OpenID + field_identity_url: URL de OpenID + label_login_with_open_id_option: o identifíquese con OpenID + field_content: Contenido + label_descending: Descendente + label_sort: Ordenar + label_ascending: Ascendente + label_date_from_to: Desde %{start} hasta %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Esta página tiene %{descendants} página(s) hija(s) y descendiente(s). ¿Qué desea hacer? + text_wiki_page_reassign_children: Reasignar páginas hijas a esta página + text_wiki_page_nullify_children: Dejar páginas hijas como páginas raíz + text_wiki_page_destroy_children: Eliminar páginas hijas y todos sus descendientes + setting_password_min_length: Longitud mínima de la contraseña + field_group_by: Agrupar resultados por + mail_subject_wiki_content_updated: "La página wiki '%{id}' ha sido actualizada" + label_wiki_content_added: Página wiki añadida + mail_subject_wiki_content_added: "Se ha añadido la página wiki '%{id}'." + mail_body_wiki_content_added: "%{author} ha añadido la página wiki '%{id}'." + label_wiki_content_updated: Página wiki actualizada + mail_body_wiki_content_updated: La página wiki '%{id}' ha sido actualizada por %{author}. + permission_add_project: Crear proyecto + setting_new_project_user_role_id: Permiso asignado a un usuario no-administrador para crear proyectos + label_view_all_revisions: Ver todas las revisiones + label_tag: Etiqueta + label_branch: Rama + error_no_tracker_in_project: Este proyecto no tiene asociados tipos de peticiones. Por favor, revise la configuración. + error_no_default_issue_status: No se ha definido un estado de petición por defecto. Por favor, revise la configuración (en "Administración" -> "Estados de las peticiones"). + text_journal_changed: "%{label} cambiado %{old} por %{new}" + text_journal_set_to: "%{label} establecido a %{value}" + text_journal_deleted: "%{label} eliminado (%{old})" + label_group_plural: Grupos + label_group: Grupo + label_group_new: Nuevo grupo + label_time_entry_plural: Tiempo dedicado + text_journal_added: "Añadido %{label} %{value}" + field_active: Activo + enumeration_system_activity: Actividad del sistema + permission_delete_issue_watchers: Borrar seguidores + version_status_closed: cerrado + version_status_locked: bloqueado + version_status_open: abierto + error_can_not_reopen_issue_on_closed_version: No se puede reabrir una petición asignada a una versión cerrada + + label_user_anonymous: Anónimo + button_move_and_follow: Mover y seguir + setting_default_projects_modules: Módulos activados por defecto en proyectos nuevos + setting_gravatar_default: Imagen Gravatar por defecto + field_sharing: Compartir + button_copy_and_follow: Copiar y seguir + label_version_sharing_hierarchy: Con la jerarquía del proyecto + label_version_sharing_tree: Con el árbol del proyecto + label_version_sharing_descendants: Con proyectos hijo + label_version_sharing_system: Con todos los proyectos + label_version_sharing_none: No compartir + button_duplicate: Duplicar + error_can_not_archive_project: Este proyecto no puede ser archivado + label_copy_source: Fuente + setting_issue_done_ratio: Calcular el ratio de tareas realizadas con + setting_issue_done_ratio_issue_status: Usar el estado de tareas + error_issue_done_ratios_not_updated: Ratios de tareas realizadas no actualizado. + error_workflow_copy_target: Por favor, elija categoría(s) y perfil(es) destino + setting_issue_done_ratio_issue_field: Utilizar el campo de petición + label_copy_same_as_target: El mismo que el destino + label_copy_target: Destino + notice_issue_done_ratios_updated: Ratios de tareas realizadas actualizados. + error_workflow_copy_source: Por favor, elija una categoría o rol de origen + label_update_issue_done_ratios: Actualizar ratios de tareas realizadas + setting_start_of_week: Comenzar las semanas en + permission_view_issues: Ver peticiones + label_display_used_statuses_only: Sólo mostrar los estados usados por este tipo de petición + label_revision_id: Revisión %{value} + label_api_access_key: Clave de acceso de la API + label_api_access_key_created_on: Clave de acceso de la API creada hace %{value} + label_feeds_access_key: Clave de acceso RSS + notice_api_access_key_reseted: Clave de acceso a la API regenerada. + setting_rest_api_enabled: Activar servicio web REST + label_missing_api_access_key: Clave de acceso a la API ausente + label_missing_feeds_access_key: Clave de accesso RSS ausente + button_show: Mostrar + text_line_separated: Múltiples valores permitidos (un valor en cada línea). + setting_mail_handler_body_delimiters: Truncar correos tras una de estas líneas + permission_add_subprojects: Crear subproyectos + label_subproject_new: Nuevo subproyecto + text_own_membership_delete_confirmation: |- + Está a punto de eliminar algún o todos sus permisos y podría perder la posibilidad de modificar este proyecto tras hacerlo. + ¿Está seguro de querer continuar? + label_close_versions: Cerrar versiones completadas + label_board_sticky: Pegajoso + label_board_locked: Bloqueado + permission_export_wiki_pages: Exportar páginas wiki + setting_cache_formatted_text: Cachear texto formateado + permission_manage_project_activities: Gestionar actividades del proyecto + error_unable_delete_issue_status: Fue imposible eliminar el estado de la petición + label_profile: Perfil + permission_manage_subtasks: Gestionar subtareas + field_parent_issue: Tarea padre + label_subtask_plural: Subtareas + label_project_copy_notifications: Enviar notificaciones por correo electrónico durante la copia del proyecto + error_can_not_delete_custom_field: Fue imposible eliminar el campo personalizado + error_unable_to_connect: Fue imposible conectar con (%{value}) + error_can_not_remove_role: Este rol está en uso y no puede ser eliminado. + error_can_not_delete_tracker: Este tipo contiene peticiones y no puede ser eliminado. + field_principal: Principal + label_my_page_block: Bloque Mi página + notice_failed_to_save_members: "Fallo al guardar miembro(s): %{errors}." + text_zoom_out: Alejar + text_zoom_in: Acercar + notice_unable_delete_time_entry: Fue imposible eliminar la entrada de tiempo dedicado. + label_overall_spent_time: Tiempo total dedicado + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendario + button_edit_associated_wikipage: "Editar paginas Wiki asociadas: %{page_title}" + text_are_you_sure_with_children: ¿Borrar peticiones y todas sus peticiones hijas? + field_text: Campo de texto + label_user_mail_option_only_owner: Solo para objetos que soy propietario + setting_default_notification_option: Opcion de notificacion por defecto + label_user_mail_option_only_my_events: Solo para objetos que soy seguidor o estoy involucrado + label_user_mail_option_only_assigned: Solo para objetos que estoy asignado + label_user_mail_option_none: Sin eventos + field_member_of_group: Asignado al grupo + field_assigned_to_role: Asignado al perfil + notice_not_authorized_archived_project: El proyecto al que intenta acceder ha sido archivado. + label_principal_search: "Buscar por usuario o grupo:" + label_user_search: "Buscar por usuario:" + field_visible: Visible + setting_emails_header: Encabezado de Correos + + setting_commit_logtime_activity_id: Actividad de los tiempos registrados + text_time_logged_by_changeset: Aplicado en los cambios %{value}. + setting_commit_logtime_enabled: Habilitar registro de horas + notice_gantt_chart_truncated: Se recortó el diagrama porque excede el número máximo de elementos que pueden ser mostrados (%{max}) + setting_gantt_items_limit: Número máximo de elementos mostrados en el diagrama de Gantt + field_warn_on_leaving_unsaved: Avisarme cuando vaya a abandonar una página con texto no guardado + text_warn_on_leaving_unsaved: Esta página contiene texto no guardado y si la abandona sus cambios se perderán + label_my_queries: Mis consultas personalizadas + text_journal_changed_no_detail: "Se actualizó %{label}" + label_news_comment_added: Comentario añadido a noticia + button_expand_all: Expandir todo + button_collapse_all: Contraer todo + label_additional_workflow_transitions_for_assignee: Transiciones adicionales permitidas cuando la petición está asignada al usuario + label_additional_workflow_transitions_for_author: Transiciones adicionales permitidas cuando el usuario es autor de la petición + label_bulk_edit_selected_time_entries: Editar en bloque las horas seleccionadas + text_time_entries_destroy_confirmation: ¿Está seguro de querer eliminar (la hora seleccionada/las horas seleccionadas)? + label_role_anonymous: Anónimo + label_role_non_member: No miembro + label_issue_note_added: Nota añadida + label_issue_status_updated: Estado actualizado + label_issue_priority_updated: Prioridad actualizada + label_issues_visibility_own: Peticiones creadas por el usuario o asignadas a él + field_issues_visibility: Visibilidad de las peticiones + label_issues_visibility_all: Todas las peticiones + permission_set_own_issues_private: Poner las peticiones propias como públicas o privadas + field_is_private: Privada + permission_set_issues_private: Poner peticiones como públicas o privadas + label_issues_visibility_public: Todas las peticiones no privadas + text_issues_destroy_descendants_confirmation: Se procederá a borrar también %{count} subtarea(s). + field_commit_logs_encoding: Codificación de los mensajes de commit + field_scm_path_encoding: Codificación de las rutas + text_scm_path_encoding_note: "Por defecto: UTF-8" + field_path_to_repository: Ruta al repositorio + field_root_directory: Directorio raíz + field_cvs_module: Módulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: Repositorio local (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Orden + text_scm_command_version: Versión + label_git_report_last_commit: Informar del último commit para ficheros y directorios + text_scm_config: Puede configurar las órdenes de cada scm en configuration/configuration.yml. Por favor, reinicie la aplicación después de editarlo + text_scm_command_not_available: La orden para el Scm no está disponible. Por favor, compruebe la configuración en el panel de administración. + notice_issue_successful_create: Petición %{id} creada. + label_between: entre + setting_issue_group_assignment: Permitir asignar peticiones a grupos + label_diff: diferencias + text_git_repository_note: El repositorio es básico y local (p.e. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Dirección de ordenación + description_project_scope: Ámbito de búsqueda + description_filter: Filtro + description_user_mail_notification: Configuración de notificaciones por correo + description_date_from: Introduzca la fecha de inicio + description_message_content: Contenido del mensaje + description_available_columns: Columnas disponibles + description_date_range_interval: Elija el rango seleccionando la fecha de inicio y fin + description_issue_category_reassign: Elija la categoría de la petición + description_search: Campo de búsqueda + description_notes: Notas + description_date_range_list: Elija el rango en la lista + description_choose_project: Proyectos + description_date_to: Introduzca la fecha fin + description_query_sort_criteria_attribute: Atributo de ordenación + description_wiki_subpages_reassign: Elija la nueva página padre + description_selected_columns: Columnas seleccionadas + label_parent_revision: Padre + label_child_revision: Hijo + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: Todas las columnas + button_export: Exportar + label_export_options: "%{export_format} opciones de exportación" + error_attachment_too_big: Este fichero no se puede adjuntar porque excede el tamaño máximo de fichero (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4b/4bd5699fdfa1ef964b63852ff5e554bbdc600109.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4b/4bd5699fdfa1ef964b63852ff5e554bbdc600109.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +module Engines + class Plugin + class Loader < Rails::Plugin::Loader + protected + def register_plugin_as_loaded(plugin) + super plugin + Engines.plugins << plugin + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c26bfb624c6f937ebe8a274d8aa910d668f8e71.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4c26bfb624c6f937ebe8a274d8aa910d668f8e71.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeProjectsNameLimit < ActiveRecord::Migration + def self.up + change_column :projects, :name, :string, :limit => nil, :default => '', :null => false + end + + def self.down + change_column :projects, :name, :string, :limit => 30, :default => '', :null => false + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c2f7807c17edfaadfde41de28c64ed5f2677c01.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4c2f7807c17edfaadfde41de28c64ed5f2677c01.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Platform + class << self + def mswin? + (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || + (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c46450a69eddda0d211771bcf055604ac13c9ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4c46450a69eddda0d211771bcf055604ac13c9ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Namespace::SharedPluginController < ApplicationController + def an_action + render_class_and_action 'from alpha_plugin' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c59ba20a8f0cc2dfb2dedfa1e4641821d4c6a38.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4c59ba20a8f0cc2dfb2dedfa1e4641821d4c6a38.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,86 @@ +// ** I18N + +// Calendar NO language (Norwegian/Norsk bokmål) +// Author: Kai Olav Fredriksen + +// full day names +Calendar._DN = new Array +("Søndag", + "Mandag", + "Tirsdag", + "Onsdag", + "Torsdag", + "Fredag", + "Lørdag", + "Søndag"); + +Calendar._SDN_len = 3; // short day name length +Calendar._SMN_len = 3; // short month name length + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Mars", + "April", + "Mai", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "Desember"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Om kalenderen"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Forrige år (hold for meny)"; +Calendar._TT["PREV_MONTH"] = "Forrige måned (hold for meny)"; +Calendar._TT["GO_TODAY"] = "Gå til idag"; +Calendar._TT["NEXT_MONTH"] = "Neste måned (hold for meny)"; +Calendar._TT["NEXT_YEAR"] = "Neste år (hold for meny)"; +Calendar._TT["SEL_DATE"] = "Velg dato"; +Calendar._TT["DRAG_TO_MOVE"] = "Dra for å flytte"; +Calendar._TT["PART_TODAY"] = " (idag)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Vis %s først"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Lukk"; +Calendar._TT["TODAY"] = "Idag"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikk eller dra for å endre verdi"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "uke"; +Calendar._TT["TIME"] = "Tid:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c6502f5dcaa0e1bacfa501a1fb65e636a9e896d.svn-base Binary file .svn/pristine/4c/4c6502f5dcaa0e1bacfa501a1fb65e636a9e896d.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c80479416efc8fc2b56e2f6a51084fb339ddfb7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4c80479416efc8fc2b56e2f6a51084fb339ddfb7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ + + +Redmine 500 error + + +

Internal error

+

An error occurred on the page you were trying to access.
+ If you continue to experience problems please contact your Redmine administrator for assistance.

+

If you are the Redmine administrator, check your log files for details about the error.

+

Back

+ + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4c87209f1f933df211a435d5f5082b69a9cf19f5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4c87209f1f933df211a435d5f5082b69a9cf19f5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,297 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::ProjectsTest < ActionController::IntegrationTest + fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, + :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, + :attachments, :custom_fields, :custom_values, :time_entries, :issue_categories + + def setup + Setting.rest_api_enabled = '1' + set_tmp_attachments_directory + end + + context "GET /projects" do + context ".xml" do + should "return projects" do + get '/projects.xml' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag :tag => 'projects', + :child => {:tag => 'project', :child => {:tag => 'id', :content => '1'}} + end + end + + context ".json" do + should "return projects" do + get '/projects.json' + assert_response :success + assert_equal 'application/json', @response.content_type + + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert_kind_of Array, json['projects'] + assert_kind_of Hash, json['projects'].first + assert json['projects'].first.has_key?('id') + end + end + end + + context "GET /projects/:id" do + context ".xml" do + # TODO: A private project is needed because should_allow_api_authentication + # actually tests that authentication is *required*, not just allowed + should_allow_api_authentication(:get, "/projects/2.xml") + + should "return requested project" do + get '/projects/1.xml' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag :tag => 'project', + :child => {:tag => 'id', :content => '1'} + assert_tag :tag => 'custom_field', + :attributes => {:name => 'Development status'}, :content => 'Stable' + + assert_no_tag 'trackers' + assert_no_tag 'issue_categories' + end + + context "with hidden custom fields" do + setup do + ProjectCustomField.find_by_name('Development status').update_attribute :visible, false + end + + should "not display hidden custom fields" do + get '/projects/1.xml' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_no_tag 'custom_field', + :attributes => {:name => 'Development status'} + end + end + + should "return categories with include=issue_categories" do + get '/projects/1.xml?include=issue_categories' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag 'issue_categories', + :attributes => {:type => 'array'}, + :child => { + :tag => 'issue_category', + :attributes => { + :id => '2', + :name => 'Recipes' + } + } + end + + should "return trackers with include=trackers" do + get '/projects/1.xml?include=trackers' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag 'trackers', + :attributes => {:type => 'array'}, + :child => { + :tag => 'tracker', + :attributes => { + :id => '2', + :name => 'Feature request' + } + } + end + end + + context ".json" do + should_allow_api_authentication(:get, "/projects/2.json") + + should "return requested project" do + get '/projects/1.json' + + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert_kind_of Hash, json['project'] + assert_equal 1, json['project']['id'] + end + end + end + + context "POST /projects" do + context "with valid parameters" do + setup do + Setting.default_projects_modules = ['issue_tracking', 'repository'] + @parameters = {:project => {:name => 'API test', :identifier => 'api-test'}} + end + + context ".xml" do + should_allow_api_authentication(:post, + '/projects.xml', + {:project => {:name => 'API test', :identifier => 'api-test'}}, + {:success_code => :created}) + + + should "create a project with the attributes" do + assert_difference('Project.count') do + post '/projects.xml', @parameters, :authorization => credentials('admin') + end + + project = Project.first(:order => 'id DESC') + assert_equal 'API test', project.name + assert_equal 'api-test', project.identifier + assert_equal ['issue_tracking', 'repository'], project.enabled_module_names.sort + assert_equal Tracker.all.size, project.trackers.size + + assert_response :created + assert_equal 'application/xml', @response.content_type + assert_tag 'project', :child => {:tag => 'id', :content => project.id.to_s} + end + + should "accept enabled_module_names attribute" do + @parameters[:project].merge!({:enabled_module_names => ['issue_tracking', 'news', 'time_tracking']}) + + assert_difference('Project.count') do + post '/projects.xml', @parameters, :authorization => credentials('admin') + end + + project = Project.first(:order => 'id DESC') + assert_equal ['issue_tracking', 'news', 'time_tracking'], project.enabled_module_names.sort + end + + should "accept tracker_ids attribute" do + @parameters[:project].merge!({:tracker_ids => [1, 3]}) + + assert_difference('Project.count') do + post '/projects.xml', @parameters, :authorization => credentials('admin') + end + + project = Project.first(:order => 'id DESC') + assert_equal [1, 3], project.trackers.map(&:id).sort + end + end + end + + context "with invalid parameters" do + setup do + @parameters = {:project => {:name => 'API test'}} + end + + context ".xml" do + should "return errors" do + assert_no_difference('Project.count') do + post '/projects.xml', @parameters, :authorization => credentials('admin') + end + + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + assert_tag 'errors', :child => {:tag => 'error', :content => "Identifier can't be blank"} + end + end + end + end + + context "PUT /projects/:id" do + context "with valid parameters" do + setup do + @parameters = {:project => {:name => 'API update'}} + end + + context ".xml" do + should_allow_api_authentication(:put, + '/projects/2.xml', + {:project => {:name => 'API update'}}, + {:success_code => :ok}) + + should "update the project" do + assert_no_difference 'Project.count' do + put '/projects/2.xml', @parameters, :authorization => credentials('jsmith') + end + assert_response :ok + assert_equal 'application/xml', @response.content_type + project = Project.find(2) + assert_equal 'API update', project.name + end + + should "accept enabled_module_names attribute" do + @parameters[:project].merge!({:enabled_module_names => ['issue_tracking', 'news', 'time_tracking']}) + + assert_no_difference 'Project.count' do + put '/projects/2.xml', @parameters, :authorization => credentials('admin') + end + assert_response :ok + project = Project.find(2) + assert_equal ['issue_tracking', 'news', 'time_tracking'], project.enabled_module_names.sort + end + + should "accept tracker_ids attribute" do + @parameters[:project].merge!({:tracker_ids => [1, 3]}) + + assert_no_difference 'Project.count' do + put '/projects/2.xml', @parameters, :authorization => credentials('admin') + end + assert_response :ok + project = Project.find(2) + assert_equal [1, 3], project.trackers.map(&:id).sort + end + end + end + + context "with invalid parameters" do + setup do + @parameters = {:project => {:name => ''}} + end + + context ".xml" do + should "return errors" do + assert_no_difference('Project.count') do + put '/projects/2.xml', @parameters, :authorization => credentials('admin') + end + + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"} + end + end + end + end + + context "DELETE /projects/:id" do + context ".xml" do + should_allow_api_authentication(:delete, + '/projects/2.xml', + {}, + {:success_code => :ok}) + + should "delete the project" do + assert_difference('Project.count',-1) do + delete '/projects/2.xml', {}, :authorization => credentials('admin') + end + assert_response :ok + assert_nil Project.find_by_id(2) + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4ca8d2e681920bf2001c2ac648a34496845c929d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4ca8d2e681920bf2001c2ac648a34496845c929d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +# Sample plugin +fr: + label_plugin_example: Plugin exemple + label_meeting_plural: Meetings + text_say_hello: Plugin dit 'Bonjour' + text_say_goodbye: Plugin dit 'Au revoir' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4cde02772540ced7426b8c2828a1d2272fc2d8ad.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4cde02772540ced7426b8c2828a1d2272fc2d8ad.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar pt language +// Author: Adalberto Machado, +// Corrected by: Pedro Araújo +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Segunda", + "Terça", + "Quarta", + "Quinta", + "Sexta", + "Sábado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Seg", + "Ter", + "Qua", + "Qui", + "Sex", + "Sáb", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Janeiro", + "Fevereiro", + "Março", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Fev", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Out", + "Nov", + "Dez"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Sobre o calendário"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Última versão visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuído sobre a licença GNU LGPL. Veja http://gnu.org/licenses/lgpl.html para detalhes." + +"\n\n" + +"Selecção de data:\n" + +"- Use os botões \xab, \xbb para seleccionar o ano\n" + +"- Use os botões " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar o mês\n" + +"- Segure o botão do rato em qualquer um desses botões para selecção rápida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selecção de hora:\n" + +"- Clique em qualquer parte da hora para incrementar\n" + +"- ou Shift-click para decrementar\n" + +"- ou clique e segure para selecção rápida."; + +Calendar._TT["PREV_YEAR"] = "Ano ant. (segure para menu)"; +Calendar._TT["PREV_MONTH"] = "Mês ant. (segure para menu)"; +Calendar._TT["GO_TODAY"] = "Hoje"; +Calendar._TT["NEXT_MONTH"] = "Prox. mês (segure para menu)"; +Calendar._TT["NEXT_YEAR"] = "Prox. ano (segure para menu)"; +Calendar._TT["SEL_DATE"] = "Seleccione a data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arraste para mover"; +Calendar._TT["PART_TODAY"] = " (hoje)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Mostre %s primeiro"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Fechar"; +Calendar._TT["TODAY"] = "Hoje"; +Calendar._TT["TIME_PART"] = "(Shift-)Click ou arraste para mudar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; + +Calendar._TT["WK"] = "sm"; +Calendar._TT["TIME"] = "Hora:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4ce30d3521f9c879b76d2c58d967727fd036b9f7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4ce30d3521f9c879b76d2c58d967727fd036b9f7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,104 @@ +--- +changesets_001: + commit_date: 2007-04-11 + committed_on: 2007-04-11 15:14:44 +02:00 + revision: 1 + id: 100 + comments: My very first commit + repository_id: 10 + committer: dlopper + user_id: 3 +changesets_002: + commit_date: 2007-04-12 + committed_on: 2007-04-12 15:14:44 +02:00 + revision: 2 + id: 101 + comments: 'This commit fixes #1, #2 and references #1 & #3' + repository_id: 10 + committer: dlopper + user_id: 3 +changesets_003: + commit_date: 2007-04-12 + committed_on: 2007-04-12 15:14:44 +02:00 + revision: 3 + id: 102 + comments: |- + A commit with wrong issue ids + IssueID #666 #3 + repository_id: 10 + committer: dlopper + user_id: 3 +changesets_004: + commit_date: 2007-04-12 + committed_on: 2007-04-12 15:14:44 +02:00 + revision: 4 + id: 103 + comments: |- + A commit with an issue id of an other project + IssueID 4 2 + repository_id: 10 + committer: dlopper + user_id: 3 +changesets_005: + commit_date: "2007-09-10" + comments: Modified one file in the folder. + committed_on: 2007-09-10 19:01:08 + revision: "5" + id: 104 + scmid: + user_id: 3 + repository_id: 10 + committer: dlopper +changesets_006: + commit_date: "2007-09-10" + comments: Moved helloworld.rb from / to /folder. + committed_on: 2007-09-10 19:01:47 + revision: "6" + id: 105 + scmid: + user_id: 3 + repository_id: 10 + committer: dlopper +changesets_007: + commit_date: "2007-09-10" + comments: Removed one file. + committed_on: 2007-09-10 19:02:16 + revision: "7" + id: 106 + scmid: + user_id: 3 + repository_id: 10 + committer: dlopper +changesets_008: + commit_date: "2007-09-10" + comments: |- + This commits references an issue. + Refs #2 + committed_on: 2007-09-10 19:04:35 + revision: "8" + id: 107 + scmid: + user_id: 3 + repository_id: 10 + committer: dlopper +changesets_009: + commit_date: "2009-09-10" + comments: One file added. + committed_on: 2009-09-10 19:04:35 + revision: "9" + id: 108 + scmid: + user_id: 3 + repository_id: 10 + committer: dlopper +changesets_010: + commit_date: "2009-09-10" + comments: Same file modified. + committed_on: 2009-09-10 19:04:35 + revision: "10" + id: 109 + scmid: + user_id: 3 + repository_id: 10 + committer: dlopper + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4c/4ce572a386a0b87f49f89a4bc090bd7724a6e4b0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4c/4ce572a386a0b87f49f89a4bc090bd7724a6e4b0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class SharedPluginModel < ActiveRecord::Base + def self.report_location; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4d/4d0caccad592aa075ffb7a4bf6b9da87412b6d59.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4d/4d0caccad592aa075ffb7a4bf6b9da87412b6d59.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib') +plugin_test_dir = File.dirname(__FILE__) + +require 'rubygems' +require 'test/unit' +require 'multi_rails_init' +# gem 'activerecord', '>= 2.0' +require 'active_record' +require 'action_controller' +require 'action_view' +require 'active_record/fixtures' + +require plugin_test_dir + '/../init.rb' + +ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log") + +ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml")) +ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem") +ActiveRecord::Migration.verbose = false +load(File.join(plugin_test_dir, "db", "schema.rb")) + +Dir["#{plugin_test_dir}/fixtures/*.rb"].each {|file| require file } + + +class Test::Unit::TestCase #:nodoc: + self.fixture_path = File.dirname(__FILE__) + "/fixtures/" + self.use_transactional_fixtures = true + self.use_instantiated_fixtures = false + + fixtures :categories, :notes, :departments +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4d/4d303c92e6935bfe0bbc913277addc1ba08aef2e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4d/4d303c92e6935bfe0bbc913277addc1ba08aef2e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,272 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class ProjectsController < ApplicationController + menu_item :overview + menu_item :roadmap, :only => :roadmap + menu_item :settings, :only => :settings + + before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ] + before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy] + before_filter :authorize_global, :only => [:new, :create] + before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] + accept_rss_auth :index + accept_api_auth :index, :show, :create, :update, :destroy + + after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| + if controller.request.post? + controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt' + end + end + + helper :sort + include SortHelper + helper :custom_fields + include CustomFieldsHelper + helper :issues + helper :queries + include QueriesHelper + helper :repositories + include RepositoriesHelper + include ProjectsHelper + + # Lists visible projects + def index + respond_to do |format| + format.html { + @projects = Project.visible.find(:all, :order => 'lft') + } + format.api { + @offset, @limit = api_offset_and_limit + @project_count = Project.visible.count + @projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft') + } + format.atom { + projects = Project.visible.find(:all, :order => 'created_on DESC', + :limit => Setting.feeds_limit.to_i) + render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") + } + end + end + + def new + @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") + @trackers = Tracker.all + @project = Project.new(params[:project]) + end + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create + @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") + @trackers = Tracker.all + @project = Project.new + @project.safe_attributes = params[:project] + + if validate_parent_id && @project.save + @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') + # Add current user as a project member if he is not admin + unless User.current.admin? + r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first + m = Member.new(:user => User.current, :roles => [r]) + @project.members << m + end + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_create) + redirect_to(params[:continue] ? + {:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} : + {:controller => 'projects', :action => 'settings', :id => @project} + ) + } + format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) } + end + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@project) } + end + end + + end + + def copy + @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") + @trackers = Tracker.all + @root_projects = Project.find(:all, + :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}", + :order => 'name') + @source_project = Project.find(params[:id]) + if request.get? + @project = Project.copy_from(@source_project) + if @project + @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers? + else + redirect_to :controller => 'admin', :action => 'projects' + end + else + Mailer.with_deliveries(params[:notifications] == '1') do + @project = Project.new + @project.safe_attributes = params[:project] + if validate_parent_id && @project.copy(@source_project, :only => params[:only]) + @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'projects', :action => 'settings', :id => @project + elsif !@project.new_record? + # Project was created + # But some objects were not copied due to validation failures + # (eg. issues from disabled trackers) + # TODO: inform about that + redirect_to :controller => 'projects', :action => 'settings', :id => @project + end + end + end + rescue ActiveRecord::RecordNotFound + redirect_to :controller => 'admin', :action => 'projects' + end + + # Show @project + def show + if params[:jump] + # try to redirect to the requested menu item + redirect_to_project_menu_item(@project, params[:jump]) && return + end + + @users_by_role = @project.users_by_role + @subprojects = @project.children.visible.all + @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") + @trackers = @project.rolled_up_trackers + + cond = @project.project_condition(Setting.display_subprojects_issues?) + + @open_issues_by_tracker = Issue.visible.count(:group => :tracker, + :include => [:project, :status, :tracker], + :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false]) + @total_issues_by_tracker = Issue.visible.count(:group => :tracker, + :include => [:project, :status, :tracker], + :conditions => cond) + + if User.current.allowed_to?(:view_time_entries, @project) + @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f + end + + @key = User.current.rss_key + + respond_to do |format| + format.html + format.api + end + end + + def settings + @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") + @issue_category ||= IssueCategory.new + @member ||= @project.members.new + @trackers = Tracker.all + @repository ||= @project.repository + @wiki ||= @project.wiki + end + + def edit + end + + # TODO: convert to PUT only + verify :method => [:post, :put], :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + def update + @project.safe_attributes = params[:project] + if validate_parent_id && @project.save + @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'settings', :id => @project + } + format.api { head :ok } + end + else + respond_to do |format| + format.html { + settings + render :action => 'settings' + } + format.api { render_validation_errors(@project) } + end + end + end + + verify :method => :post, :only => :modules, :render => {:nothing => true, :status => :method_not_allowed } + def modules + @project.enabled_module_names = params[:enabled_module_names] + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'settings', :id => @project, :tab => 'modules' + end + + def archive + if request.post? + unless @project.archive + flash[:error] = l(:error_can_not_archive_project) + end + end + redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status])) + end + + def unarchive + @project.unarchive if request.post? && !@project.active? + redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status])) + end + + # Delete @project + def destroy + @project_to_destroy = @project + if request.get? + # display confirmation view + else + if api_request? || params[:confirm] + @project_to_destroy.destroy + respond_to do |format| + format.html { redirect_to :controller => 'admin', :action => 'projects' } + format.api { head :ok } + end + end + end + # hide project in layout + @project = nil + end + +private + def find_optional_project + return true unless params[:id] + @project = Project.find(params[:id]) + authorize + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Validates parent_id param according to user's permissions + # TODO: move it to Project model in a validation that depends on User.current + def validate_parent_id + return true if User.current.admin? + parent_id = params[:project] && params[:project][:parent_id] + if parent_id || @project.new_record? + parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i) + unless @project.allowed_parents.include?(parent) + @project.errors.add :parent_id, :invalid + return false + end + end + true + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4d/4d462e78d204c3aed1b100b04b6f63c31c637a6f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4d/4d462e78d204c3aed1b100b04b6f63c31c637a6f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar FA language +// Author: Behrang Noroozinia, behrangn at g mail +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("یک‌شنبه", + "دوشنبه", + "سه‌شنبه", + "چهارشنبه", + "پنج‌شنبه", + "آدینه", + "شنبه", + "یک‌شنبه"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("یک", + "دو", + "سه", + "چهار", + "پنج", + "آدینه", + "شنبه", + "یک"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("ژانویه", + "فوریه", + "مارس", + "آوریل", + "مه", + "ژوئن", + "ژوئیه", + "اوت", + "سپتامبر", + "اکتبر", + "نوامبر", + "دسامبر"); + +// short month names +Calendar._SMN = new Array +("ژان", + "فور", + "مار", + "آور", + "مه", + "ژوئن", + "ژوئیه", + "اوت", + "سپت", + "اکت", + "نوا", + "دسا"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "درباره گاهشمار"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "سال پیشین (برای فهرست نگه دارید)"; +Calendar._TT["PREV_MONTH"] = "ماه پیشین ( برای فهرست نگه دارید)"; +Calendar._TT["GO_TODAY"] = "برو به امروز"; +Calendar._TT["NEXT_MONTH"] = "ماه پسین (برای فهرست نگه دارید)"; +Calendar._TT["NEXT_YEAR"] = "سال پسین (برای فهرست نگه دارید)"; +Calendar._TT["SEL_DATE"] = "گزینش"; +Calendar._TT["DRAG_TO_MOVE"] = "برای جابجایی بکشید"; +Calendar._TT["PART_TODAY"] = " (امروز)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "آغاز هفته از %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "4,5"; + +Calendar._TT["CLOSE"] = "بسته"; +Calendar._TT["TODAY"] = "امروز"; +Calendar._TT["TIME_PART"] = "زدن (با Shift) یا کشیدن برای ویرایش"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "هفته"; +Calendar._TT["TIME"] = "زمان:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4d/4d81cc5316e201f2bbb721032960a2f74380fe9b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4d/4d81cc5316e201f2bbb721032960a2f74380fe9b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +FWIW - I am migrating my apps to Prawn and Prawnto + += RFPDF Template Plugin + +A template plugin allowing the inclusion of ERB-enabled RFPDF template files. + +== +== +== TCPDF Version (The New or UTF8 Version) +== +== + +If you are using HTML, it is recommended you install: + +gem install -r htmlentities + +TCPDF Documentation located at: + +http://phpdocs.moodle.org/com-tecnick-tcpdf/TCPDF.html + +Example of simple use in .rhtml: + +<% + @pdf = TCPDF.new() + @pdf.SetMargins(15, 27, 15); + @pdf.AddPage(); + text_options = {:font => "freeserif"} + @pdf.draw_text(15, 10, "text", {:font_size => 12, :font => "freeserif"}) +%><%=@pdf.Output()%> + +See the following files for sample of useage: + +test_unicode.rfpdf +utf8test.txt +logo_example.png + +FPDF users can migrate to TCPDF by changing the following from: + + pdf = FPDF.new + +to: + + pdf = TCPDF.new + +ENJOY! \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4d/4db1f392c52d1c52ef2d37c9a27b017bd4d891ac.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4d/4db1f392c52d1c52ef2d37c9a27b017bd4d891ac.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,278 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 #:nodoc: + + class PluginNotFound < StandardError; end + class PluginRequirementError < StandardError; end + + # Base class for Redmine plugins. + # Plugins are registered using the register class method that acts as the public constructor. + # + # Redmine::Plugin.register :example do + # name 'Example plugin' + # author 'John Smith' + # description 'This is an example plugin for Redmine' + # version '0.0.1' + # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' + # end + # + # === Plugin attributes + # + # +settings+ is an optional attribute that let the plugin be configurable. + # It must be a hash with the following keys: + # * :default: default value for the plugin settings + # * :partial: path of the configuration partial view, relative to the plugin app/views directory + # Example: + # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' + # In this example, the settings partial will be found here in the plugin directory: app/views/settings/_settings.rhtml. + # + # When rendered, the plugin settings value is available as the local variable +settings+ + class Plugin + @registered_plugins = {} + class << self + attr_reader :registered_plugins + private :new + + def def_field(*names) + class_eval do + names.each do |name| + define_method(name) do |*args| + args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args) + end + end + end + end + end + def_field :name, :description, :url, :author, :author_url, :version, :settings + attr_reader :id + + # Plugin constructor + def self.register(id, &block) + p = new(id) + p.instance_eval(&block) + # Set a default name if it was not provided during registration + p.name(id.to_s.humanize) if p.name.nil? + # Adds plugin locales if any + # YAML translation files should be found under /config/locales/ + ::I18n.load_path += Dir.glob(File.join(Rails.root, 'vendor', 'plugins', id.to_s, 'config', 'locales', '*.yml')) + registered_plugins[id] = p + end + + # Returns an array of all registered plugins + def self.all + registered_plugins.values.sort + end + + # Finds a plugin by its id + # Returns a PluginNotFound exception if the plugin doesn't exist + def self.find(id) + registered_plugins[id.to_sym] || raise(PluginNotFound) + end + + # Clears the registered plugins hash + # It doesn't unload installed plugins + def self.clear + @registered_plugins = {} + end + + # Checks if a plugin is installed + # + # @param [String] id name of the plugin + def self.installed?(id) + registered_plugins[id.to_sym].present? + end + + def initialize(id) + @id = id.to_sym + end + + def <=>(plugin) + self.id.to_s <=> plugin.id.to_s + end + + # Sets a requirement on Redmine version + # Raises a PluginRequirementError exception if the requirement is not met + # + # Examples + # # Requires Redmine 0.7.3 or higher + # requires_redmine :version_or_higher => '0.7.3' + # requires_redmine '0.7.3' + # + # # Requires a specific Redmine version + # requires_redmine :version => '0.7.3' # 0.7.3 only + # requires_redmine :version => ['0.7.3', '0.8.0'] # 0.7.3 or 0.8.0 + def requires_redmine(arg) + arg = { :version_or_higher => arg } unless arg.is_a?(Hash) + arg.assert_valid_keys(:version, :version_or_higher) + + current = Redmine::VERSION.to_a + arg.each do |k, v| + v = [] << v unless v.is_a?(Array) + versions = v.collect {|s| s.split('.').collect(&:to_i)} + case k + when :version_or_higher + raise ArgumentError.new("wrong number of versions (#{versions.size} for 1)") unless versions.size == 1 + unless (current <=> versions.first) >= 0 + raise PluginRequirementError.new("#{id} plugin requires Redmine #{v} or higher but current is #{current.join('.')}") + end + when :version + unless versions.include?(current.slice(0,3)) + raise PluginRequirementError.new("#{id} plugin requires one the following Redmine versions: #{v.join(', ')} but current is #{current.join('.')}") + end + end + end + true + end + + # Sets a requirement on a Redmine plugin version + # Raises a PluginRequirementError exception if the requirement is not met + # + # Examples + # # Requires a plugin named :foo version 0.7.3 or higher + # requires_redmine_plugin :foo, :version_or_higher => '0.7.3' + # requires_redmine_plugin :foo, '0.7.3' + # + # # Requires a specific version of a Redmine plugin + # requires_redmine_plugin :foo, :version => '0.7.3' # 0.7.3 only + # requires_redmine_plugin :foo, :version => ['0.7.3', '0.8.0'] # 0.7.3 or 0.8.0 + def requires_redmine_plugin(plugin_name, arg) + arg = { :version_or_higher => arg } unless arg.is_a?(Hash) + arg.assert_valid_keys(:version, :version_or_higher) + + plugin = Plugin.find(plugin_name) + current = plugin.version.split('.').collect(&:to_i) + + arg.each do |k, v| + v = [] << v unless v.is_a?(Array) + versions = v.collect {|s| s.split('.').collect(&:to_i)} + case k + when :version_or_higher + raise ArgumentError.new("wrong number of versions (#{versions.size} for 1)") unless versions.size == 1 + unless (current <=> versions.first) >= 0 + raise PluginRequirementError.new("#{id} plugin requires the #{plugin_name} plugin #{v} or higher but current is #{current.join('.')}") + end + when :version + unless versions.include?(current.slice(0,3)) + raise PluginRequirementError.new("#{id} plugin requires one the following versions of #{plugin_name}: #{v.join(', ')} but current is #{current.join('.')}") + end + end + end + true + end + + # Adds an item to the given +menu+. + # The +id+ parameter (equals to the project id) is automatically added to the url. + # menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample' + # + # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu + # + def menu(menu, item, url, options={}) + Redmine::MenuManager.map(menu).push(item, url, options) + end + alias :add_menu_item :menu + + # Removes +item+ from the given +menu+. + def delete_menu_item(menu, item) + Redmine::MenuManager.map(menu).delete(item) + end + + # Defines a permission called +name+ for the given +actions+. + # + # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array): + # permission :destroy_contacts, { :contacts => :destroy } + # permission :view_contacts, { :contacts => [:index, :show] } + # + # The +options+ argument can be used to make the permission public (implicitly given to any user) + # or to restrict users the permission can be given to. + # + # Examples + # # A permission that is implicitly given to any user + # # This permission won't appear on the Roles & Permissions setup screen + # permission :say_hello, { :example => :say_hello }, :public => true + # + # # A permission that can be given to any user + # permission :say_hello, { :example => :say_hello } + # + # # A permission that can be given to registered users only + # permission :say_hello, { :example => :say_hello }, :require => :loggedin + # + # # A permission that can be given to project members only + # permission :say_hello, { :example => :say_hello }, :require => :member + def permission(name, actions, options = {}) + if @project_module + Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}} + else + Redmine::AccessControl.map {|map| map.permission(name, actions, options)} + end + end + + # Defines a project module, that can be enabled/disabled for each project. + # Permissions defined inside +block+ will be bind to the module. + # + # project_module :things do + # permission :view_contacts, { :contacts => [:list, :show] }, :public => true + # permission :destroy_contacts, { :contacts => :destroy } + # end + def project_module(name, &block) + @project_module = name + self.instance_eval(&block) + @project_module = nil + end + + # Registers an activity provider. + # + # Options: + # * :class_name - one or more model(s) that provide these events (inferred from event_type by default) + # * :default - setting this option to false will make the events not displayed by default + # + # A model can provide several activity event types. + # + # Examples: + # register :news + # register :scrums, :class_name => 'Meeting' + # register :issues, :class_name => ['Issue', 'Journal'] + # + # Retrieving events: + # Associated model(s) must implement the find_events class method. + # ActiveRecord models can use acts_as_activity_provider as a way to implement this class method. + # + # The following call should return all the scrum events visible by current user that occured in the 5 last days: + # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today) + # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today, :project => foo) # events for project foo only + # + # Note that :view_scrums permission is required to view these events in the activity view. + def activity_provider(*args) + Redmine::Activity.register(*args) + end + + # Registers a wiki formatter. + # + # Parameters: + # * +name+ - human-readable name + # * +formatter+ - formatter class, which should have an instance method +to_html+ + # * +helper+ - helper module, which will be included by wiki pages + def wiki_format_provider(name, formatter, helper) + Redmine::WikiFormatting.register(name, formatter, helper) + end + + # Returns +true+ if the plugin can be configured. + def configurable? + settings && settings.is_a?(Hash) && !settings[:partial].blank? + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4e2b9ddd1957e8e9b8adf4bab52aeff57edc2985.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4e/4e2b9ddd1957e8e9b8adf4bab52aeff57edc2985.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Diumenge", + "Dilluns", + "Dimarts", + "Dimecres", + "Dijous", + "Divendres", + "Dissabte", + "Diumenge"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("dg", + "dl", + "dt", + "dc", + "dj", + "dv", + "ds", + "dg"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Gener", + "Febrer", + "Març", + "Abril", + "Maig", + "Juny", + "Juliol", + "Agost", + "Setembre", + "Octubre", + "Novembre", + "Desembre"); + +// short month names +Calendar._SMN = new Array +("Gen", + "Feb", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Oct", + "Nov", + "Des"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Quant al calendari"; + +Calendar._TT["ABOUT"] = +"Selector DHTML de data/hora\n" + +"(c) dynarch.com 2002-2005 / Autor: Mihai Bazon\n" + // don't translate this this ;-) +"Per aconseguir l'última versió visiteu: http://www.dynarch.com/projects/calendar/\n" + +"Distribuït sota la llicència GNU LGPL. Vegeu http://gnu.org/licenses/lgpl.html per obtenir més detalls." + +"\n\n" + +"Selecció de la data:\n" + +"- Utilitzeu els botons \xab, \xbb per seleccionar l'any\n" + +"- Utilitzeu els botons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " per seleccionar el mes\n" + +"- Mantingueu premut el botó del ratolí sobre qualsevol d'aquests botons per a una selecció més ràpida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selecció de l'hora:\n" + +"- Feu clic en qualsevol part de l'hora per incrementar-la\n" + +"- o premeu majúscules per disminuir-la\n" + +"- o feu clic i arrossegueu per a una selecció més ràpida."; + +Calendar._TT["PREV_YEAR"] = "Any anterior (mantenir per menú)"; +Calendar._TT["PREV_MONTH"] = "Mes anterior (mantenir per menú)"; +Calendar._TT["GO_TODAY"] = "Anar a avui"; +Calendar._TT["NEXT_MONTH"] = "Mes següent (mantenir per menú)"; +Calendar._TT["NEXT_YEAR"] = "Any següent (mantenir per menú)"; +Calendar._TT["SEL_DATE"] = "Sel·lecciona la data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrossega per moure"; +Calendar._TT["PART_TODAY"] = " (avui)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Primer mostra el %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Tanca"; +Calendar._TT["TODAY"] = "Avui"; +Calendar._TT["TIME_PART"] = "(Majúscules-)Feu clic o arrossegueu per canviar el valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; + +Calendar._TT["WK"] = "set"; +Calendar._TT["TIME"] = "Hora:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4e463aec85dd46647cbb6a677bff53b3a10966f4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4e/4e463aec85dd46647cbb6a677bff53b3a10966f4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::NotifiableTest < ActiveSupport::TestCase + def setup + end + + def test_all + assert_equal 12, Redmine::Notifiable.all.length + + %w(issue_added issue_updated issue_note_added issue_status_updated issue_priority_updated news_added news_comment_added document_added file_added message_posted wiki_content_added wiki_content_updated).each do |notifiable| + assert Redmine::Notifiable.all.collect(&:name).include?(notifiable), "missing #{notifiable}" + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4e64ceb850aaa04a7acc9aad3a69b5f58d199fa5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4e/4e64ceb850aaa04a7acc9aad3a69b5f58d199fa5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,182 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redcloth3' +require 'digest/md5' + +module Redmine + module WikiFormatting + module Textile + class Formatter < RedCloth3 + include ActionView::Helpers::TagHelper + + # auto_link rule after textile rules so that it doesn't break !image_url! tags + RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] + + def initialize(*args) + super + self.hard_breaks=true + self.no_span_caps=true + self.filter_styles=true + end + + def to_html(*rules) + @toc = [] + super(*RULES).to_s + end + + def get_section(index) + section = extract_sections(index)[1] + hash = Digest::MD5.hexdigest(section) + return section, hash + end + + def update_section(index, update, hash=nil) + t = extract_sections(index) + if hash.present? && hash != Digest::MD5.hexdigest(t[1]) + raise Redmine::WikiFormatting::StaleSectionError + end + t[1] = update unless t[1].blank? + t.reject(&:blank?).join "\n\n" + end + + def extract_sections(index) + @pre_list = [] + text = self.dup + rip_offtags text, false, false + before = '' + s = '' + after = '' + i = 0 + l = 1 + started = false + ended = false + text.scan(/(((?:.*?)(\A|\r?\n\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))? (.*?)$)|.*)/m).each do |all, content, lf, heading, level| + if heading.nil? + if ended + after << all + elsif started + s << all + else + before << all + end + break + end + i += 1 + if ended + after << all + elsif i == index + l = level.to_i + before << content + s << heading + started = true + elsif i > index + s << content + if level.to_i > l + s << heading + else + after << heading + ended = true + end + else + before << all + end + end + sections = [before.strip, s.strip, after.strip] + sections.each {|section| smooth_offtags_without_code_highlighting section} + sections + end + + private + + # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. + # http://code.whytheluckystiff.net/redcloth/changeset/128 + def hard_break( text ) + text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1
" ) if hard_breaks + end + + alias :smooth_offtags_without_code_highlighting :smooth_offtags + # Patch to add code highlighting support to RedCloth + def smooth_offtags( text ) + unless @pre_list.empty? + ## replace
 content
+            text.gsub!(//) do
+              content = @pre_list[$1.to_i]
+              if content.match(/\s?(.+)/m)
+                content = "" +
+                  Redmine::SyntaxHighlighting.highlight_by_language($2, $1)
+              end
+              content
+            end
+          end
+        end
+
+        AUTO_LINK_RE = %r{
+                        (                          # leading text
+                          <\w+.*?>|                # leading HTML tag, or
+                          [^=<>!:'"/]|             # leading punctuation, or
+                          ^                        # beginning of line
+                        )
+                        (
+                          (?:https?://)|           # protocol spec, or
+                          (?:s?ftps?://)|
+                          (?:www\.)                # www.*
+                        )
+                        (
+                          (\S+?)                   # url
+                          (\/)?                    # slash
+                        )
+                        ((?:>)?|[^\w\=\/;\(\)]*?)               # post
+                        (?=<|\s|$)
+                       }x unless const_defined?(:AUTO_LINK_RE)
+
+        # Turns all urls into clickable links (code from Rails).
+        def inline_auto_link(text)
+          text.gsub!(AUTO_LINK_RE) do
+            all, leading, proto, url, post = $&, $1, $2, $3, $6
+            if leading =~ /=]?/
+              # don't replace URL's that are already linked
+              # and URL's prefixed with ! !> !< != (textile images)
+              all
+            else
+              # Idea below : an URL with unbalanced parethesis and
+              # ending by ')' is put into external parenthesis
+              if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) )
+                url=url[0..-2] # discard closing parenth from url
+                post = ")"+post # add closing parenth to post
+              end
+              tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external')
+              %(#{leading}#{tag}#{post})
+            end
+          end
+        end
+
+        # Turns all email addresses into clickable links (code from Rails).
+        def inline_auto_mailto(text)
+          text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
+            mail = $1
+            if text.match(/]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/)
+              mail
+            else
+              content_tag('a', mail, :href => "mailto:#{mail}", :class => "email")
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4e65aa6af49f7dc6aa8157532f6bed6bfe2ae6d6.svn-base
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.svn/pristine/4e/4e65aa6af49f7dc6aa8157532f6bed6bfe2ae6d6.svn-base	Mon Feb 27 13:53:18 2012 +0000
@@ -0,0 +1,636 @@
+# Redmine - project management software
+# Copyright (C) 2006-2011  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 "digest/sha1"
+
+class User < Principal
+  include Redmine::SafeAttributes
+
+  # Account statuses
+  STATUS_ANONYMOUS  = 0
+  STATUS_ACTIVE     = 1
+  STATUS_REGISTERED = 2
+  STATUS_LOCKED     = 3
+
+  # Different ways of displaying/sorting users
+  USER_FORMATS = {
+    :firstname_lastname => {:string => '#{firstname} #{lastname}', :order => %w(firstname lastname id)},
+    :firstname => {:string => '#{firstname}', :order => %w(firstname id)},
+    :lastname_firstname => {:string => '#{lastname} #{firstname}', :order => %w(lastname firstname id)},
+    :lastname_coma_firstname => {:string => '#{lastname}, #{firstname}', :order => %w(lastname firstname id)},
+    :username => {:string => '#{login}', :order => %w(login id)},
+  }
+
+  MAIL_NOTIFICATION_OPTIONS = [
+    ['all', :label_user_mail_option_all],
+    ['selected', :label_user_mail_option_selected],
+    ['only_my_events', :label_user_mail_option_only_my_events],
+    ['only_assigned', :label_user_mail_option_only_assigned],
+    ['only_owner', :label_user_mail_option_only_owner],
+    ['none', :label_user_mail_option_none]
+  ]
+
+  has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
+                                   :after_remove => Proc.new {|user, group| group.user_removed(user)}
+  has_many :changesets, :dependent => :nullify
+  has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
+  has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
+  has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
+  belongs_to :auth_source
+
+  # Active non-anonymous users scope
+  named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
+
+  acts_as_customizable
+
+  attr_accessor :password, :password_confirmation
+  attr_accessor :last_before_login_on
+  # Prevents unauthorized assignments
+  attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
+	
+  validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
+  validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }, :case_sensitive => false
+  validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
+  # Login must contain lettres, numbers, underscores only
+  validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
+  validates_length_of :login, :maximum => 30
+  validates_length_of :firstname, :lastname, :maximum => 30
+  validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_blank => true
+  validates_length_of :mail, :maximum => 60, :allow_nil => true
+  validates_confirmation_of :password, :allow_nil => true
+  validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
+  validate :validate_password_length
+
+  before_create :set_mail_notification
+  before_save   :update_hashed_password
+  before_destroy :remove_references_before_destroy
+
+  named_scope :in_group, lambda {|group|
+    group_id = group.is_a?(Group) ? group.id : group.to_i
+    { :conditions => ["#{User.table_name}.id IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id] }
+  }
+  named_scope :not_in_group, lambda {|group|
+    group_id = group.is_a?(Group) ? group.id : group.to_i
+    { :conditions => ["#{User.table_name}.id NOT IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id] }
+  }
+
+  def set_mail_notification
+    self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
+    true
+  end
+
+  def update_hashed_password
+    # update hashed_password if password was set
+    if self.password && self.auth_source_id.blank?
+      salt_password(password)
+    end
+  end
+
+  def reload(*args)
+    @name = nil
+    @projects_by_role = nil
+    super
+  end
+
+  def mail=(arg)
+    write_attribute(:mail, arg.to_s.strip)
+  end
+
+  def identity_url=(url)
+    if url.blank?
+      write_attribute(:identity_url, '')
+    else
+      begin
+        write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
+      rescue OpenIdAuthentication::InvalidOpenId
+        # Invlaid url, don't save
+      end
+    end
+    self.read_attribute(:identity_url)
+  end
+
+  # Returns the user that matches provided login and password, or nil
+  def self.try_to_login(login, password)
+    # Make sure no one can sign in with an empty password
+    return nil if password.to_s.empty?
+    user = find_by_login(login)
+    if user
+      # user is already in local database
+      return nil if !user.active?
+      if user.auth_source
+        # user has an external authentication method
+        return nil unless user.auth_source.authenticate(login, password)
+      else
+        # authentication with local password
+        return nil unless user.check_password?(password)
+      end
+    else
+      # user is not yet registered, try to authenticate with available sources
+      attrs = AuthSource.authenticate(login, password)
+      if attrs
+        user = new(attrs)
+        user.login = login
+        user.language = Setting.default_language
+        if user.save
+          user.reload
+          logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
+        end
+      end
+    end
+    user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
+    user
+  rescue => text
+    raise text
+  end
+
+  # Returns the user who matches the given autologin +key+ or nil
+  def self.try_to_autologin(key)
+    tokens = Token.find_all_by_action_and_value('autologin', key)
+    # Make sure there's only 1 token that matches the key
+    if tokens.size == 1
+      token = tokens.first
+      if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
+        token.user.update_attribute(:last_login_on, Time.now)
+        token.user
+      end
+    end
+  end
+
+  def self.name_formatter(formatter = nil)
+    USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
+  end
+
+  # Returns an array of fields names than can be used to make an order statement for users
+  # according to how user names are displayed
+  # Examples:
+  #
+  #   User.fields_for_order_statement              => ['users.login', 'users.id']
+  #   User.fields_for_order_statement('authors')   => ['authors.login', 'authors.id']
+  def self.fields_for_order_statement(table=nil)
+    table ||= table_name
+    name_formatter[:order].map {|field| "#{table}.#{field}"}
+  end
+
+  # Return user's full name for display
+  def name(formatter = nil)
+    f = self.class.name_formatter(formatter)
+    if formatter
+      eval('"' + f[:string] + '"')
+    else
+      @name ||= eval('"' + f[:string] + '"')
+    end
+  end
+
+  def active?
+    self.status == STATUS_ACTIVE
+  end
+
+  def registered?
+    self.status == STATUS_REGISTERED
+  end
+
+  def locked?
+    self.status == STATUS_LOCKED
+  end
+
+  def activate
+    self.status = STATUS_ACTIVE
+  end
+
+  def register
+    self.status = STATUS_REGISTERED
+  end
+
+  def lock
+    self.status = STATUS_LOCKED
+  end
+
+  def activate!
+    update_attribute(:status, STATUS_ACTIVE)
+  end
+
+  def register!
+    update_attribute(:status, STATUS_REGISTERED)
+  end
+
+  def lock!
+    update_attribute(:status, STATUS_LOCKED)
+  end
+
+  # Returns true if +clear_password+ is the correct user's password, otherwise false
+  def check_password?(clear_password)
+    if auth_source_id.present?
+      auth_source.authenticate(self.login, clear_password)
+    else
+      User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password
+    end
+  end
+
+  # Generates a random salt and computes hashed_password for +clear_password+
+  # The hashed password is stored in the following form: SHA1(salt + SHA1(password))
+  def salt_password(clear_password)
+    self.salt = User.generate_salt
+    self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}")
+  end
+
+  # Does the backend storage allow this user to change their password?
+  def change_password_allowed?
+    return true if auth_source_id.blank?
+    return auth_source.allow_password_changes?
+  end
+
+  # Generate and set a random password.  Useful for automated user creation
+  # Based on Token#generate_token_value
+  #
+  def random_password
+    chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
+    password = ''
+    40.times { |i| password << chars[rand(chars.size-1)] }
+    self.password = password
+    self.password_confirmation = password
+    self
+  end
+
+  def pref
+    self.preference ||= UserPreference.new(:user => self)
+  end
+
+  def time_zone
+    @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
+  end
+
+  def wants_comments_in_reverse_order?
+    self.pref[:comments_sorting] == 'desc'
+  end
+
+  # Return user's RSS key (a 40 chars long string), used to access feeds
+  def rss_key
+    token = self.rss_token || Token.create(:user => self, :action => 'feeds')
+    token.value
+  end
+
+  # Return user's API key (a 40 chars long string), used to access the API
+  def api_key
+    token = self.api_token || self.create_api_token(:action => 'api')
+    token.value
+  end
+
+  # Return an array of project ids for which the user has explicitly turned mail notifications on
+  def notified_projects_ids
+    @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
+  end
+
+  def notified_project_ids=(ids)
+    Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
+    Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
+    @notified_projects_ids = nil
+    notified_projects_ids
+  end
+
+  def valid_notification_options
+    self.class.valid_notification_options(self)
+  end
+
+  # Only users that belong to more than 1 project can select projects for which they are notified
+  def self.valid_notification_options(user=nil)
+    # Note that @user.membership.size would fail since AR ignores
+    # :include association option when doing a count
+    if user.nil? || user.memberships.length < 1
+      MAIL_NOTIFICATION_OPTIONS.reject {|option| option.first == 'selected'}
+    else
+      MAIL_NOTIFICATION_OPTIONS
+    end
+  end
+
+  # Find a user account by matching the exact login and then a case-insensitive
+  # version.  Exact matches will be given priority.
+  def self.find_by_login(login)
+    # force string comparison to be case sensitive on MySQL
+    type_cast = (ActiveRecord::Base.connection.adapter_name == 'MySQL') ? 'BINARY' : ''
+
+    # First look for an exact match
+    user = first(:conditions => ["#{type_cast} login = ?", login])
+    # Fail over to case-insensitive if none was found
+    user ||= first(:conditions => ["#{type_cast} LOWER(login) = ?", login.to_s.downcase])
+  end
+
+  def self.find_by_rss_key(key)
+    token = Token.find_by_value(key)
+    token && token.user.active? ? token.user : nil
+  end
+
+  def self.find_by_api_key(key)
+    token = Token.find_by_action_and_value('api', key)
+    token && token.user.active? ? token.user : nil
+  end
+
+  # Makes find_by_mail case-insensitive
+  def self.find_by_mail(mail)
+    find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
+  end
+
+  def to_s
+    name
+  end
+
+  # Returns the current day according to user's time zone
+  def today
+    if time_zone.nil?
+      Date.today
+    else
+      Time.now.in_time_zone(time_zone).to_date
+    end
+  end
+
+  def logged?
+    true
+  end
+
+  def anonymous?
+    !logged?
+  end
+
+  # Return user's roles for project
+  def roles_for_project(project)
+    roles = []
+    # No role on archived projects
+    return roles unless project && project.active?
+    if logged?
+      # Find project membership
+      membership = memberships.detect {|m| m.project_id == project.id}
+      if membership
+        roles = membership.roles
+      else
+        @role_non_member ||= Role.non_member
+        roles << @role_non_member
+      end
+    else
+      @role_anonymous ||= Role.anonymous
+      roles << @role_anonymous
+    end
+    roles
+  end
+
+  # Return true if the user is a member of project
+  def member_of?(project)
+    !roles_for_project(project).detect {|role| role.member?}.nil?
+  end
+
+  # Returns a hash of user's projects grouped by roles
+  def projects_by_role
+    return @projects_by_role if @projects_by_role
+
+    @projects_by_role = Hash.new {|h,k| h[k]=[]}
+    memberships.each do |membership|
+      membership.roles.each do |role|
+        @projects_by_role[role] << membership.project if membership.project
+      end
+    end
+    @projects_by_role.each do |role, projects|
+      projects.uniq!
+    end
+
+    @projects_by_role
+  end
+
+  # Returns true if user is arg or belongs to arg
+  def is_or_belongs_to?(arg)
+    if arg.is_a?(User)
+      self == arg
+    elsif arg.is_a?(Group)
+      arg.users.include?(self)
+    else
+      false
+    end
+  end
+
+  # Return true if the user is allowed to do the specified action on a specific context
+  # Action can be:
+  # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
+  # * a permission Symbol (eg. :edit_project)
+  # Context can be:
+  # * a project : returns true if user is allowed to do the specified action on this project
+  # * an array of projects : returns true if user is allowed on every project
+  # * nil with options[:global] set : check if user has at least one role allowed for this action,
+  #   or falls back to Non Member / Anonymous permissions depending if the user is logged
+  def allowed_to?(action, context, options={}, &block)
+    if context && context.is_a?(Project)
+      # No action allowed on archived projects
+      return false unless context.active?
+      # No action allowed on disabled modules
+      return false unless context.allows_to?(action)
+      # Admin users are authorized for anything else
+      return true if admin?
+
+      roles = roles_for_project(context)
+      return false unless roles
+      roles.detect {|role|
+        (context.is_public? || role.member?) &&
+        role.allowed_to?(action) &&
+        (block_given? ? yield(role, self) : true)
+      }
+    elsif context && context.is_a?(Array)
+      # Authorize if user is authorized on every element of the array
+      context.map do |project|
+        allowed_to?(action, project, options, &block)
+      end.inject do |memo,allowed|
+        memo && allowed
+      end
+    elsif options[:global]
+      # Admin users are always authorized
+      return true if admin?
+
+      # authorize if user has at least one role that has this permission
+      roles = memberships.collect {|m| m.roles}.flatten.uniq
+      roles << (self.logged? ? Role.non_member : Role.anonymous)
+      roles.detect {|role|
+        role.allowed_to?(action) &&
+        (block_given? ? yield(role, self) : true)
+      }
+    else
+      false
+    end
+  end
+
+  # Is the user allowed to do the specified action on any project?
+  # See allowed_to? for the actions and valid options.
+  def allowed_to_globally?(action, options, &block)
+    allowed_to?(action, nil, options.reverse_merge(:global => true), &block)
+  end
+
+  safe_attributes 'login',
+    'firstname',
+    'lastname',
+    'mail',
+    'mail_notification',
+    'language',
+    'custom_field_values',
+    'custom_fields',
+    'identity_url'
+
+  safe_attributes 'status',
+    'auth_source_id',
+    :if => lambda {|user, current_user| current_user.admin?}
+
+  safe_attributes 'group_ids',
+    :if => lambda {|user, current_user| current_user.admin? && !user.new_record?}
+
+  # Utility method to help check if a user should be notified about an
+  # event.
+  #
+  # TODO: only supports Issue events currently
+  def notify_about?(object)
+    case mail_notification
+    when 'all'
+      true
+    when 'selected'
+      # user receives notifications for created/assigned issues on unselected projects
+      if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to))
+        true
+      else
+        false
+      end
+    when 'none'
+      false
+    when 'only_my_events'
+      if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to))
+        true
+      else
+        false
+      end
+    when 'only_assigned'
+      if object.is_a?(Issue) && is_or_belongs_to?(object.assigned_to)
+        true
+      else
+        false
+      end
+    when 'only_owner'
+      if object.is_a?(Issue) && object.author == self
+        true
+      else
+        false
+      end
+    else
+      false
+    end
+  end
+
+  def self.current=(user)
+    @current_user = user
+  end
+
+  def self.current
+    @current_user ||= User.anonymous
+  end
+
+  # Returns the anonymous user.  If the anonymous user does not exist, it is created.  There can be only
+  # one anonymous user per database.
+  def self.anonymous
+    anonymous_user = AnonymousUser.find(:first)
+    if anonymous_user.nil?
+      anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
+      raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
+    end
+    anonymous_user
+  end
+
+  # Salts all existing unsalted passwords
+  # It changes password storage scheme from SHA1(password) to SHA1(salt + SHA1(password))
+  # This method is used in the SaltPasswords migration and is to be kept as is
+  def self.salt_unsalted_passwords!
+    transaction do
+      User.find_each(:conditions => "salt IS NULL OR salt = ''") do |user|
+        next if user.hashed_password.blank?
+        salt = User.generate_salt
+        hashed_password = User.hash_password("#{salt}#{user.hashed_password}")
+        User.update_all("salt = '#{salt}', hashed_password = '#{hashed_password}'", ["id = ?", user.id] )
+      end
+    end
+  end
+
+  protected
+
+  def validate_password_length
+    # Password length validation based on setting
+    if !password.nil? && password.size < Setting.password_min_length.to_i
+      errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
+    end
+  end
+
+  private
+
+  # Removes references that are not handled by associations
+  # Things that are not deleted are reassociated with the anonymous user
+  def remove_references_before_destroy
+    return if self.id.nil?
+
+    substitute = User.anonymous
+    Attachment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+    Comment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+    Issue.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+    Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id]
+    Journal.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
+    JournalDetail.update_all ['old_value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]
+    JournalDetail.update_all ['value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]
+    Message.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+    News.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+    # Remove private queries and keep public ones
+    Query.delete_all ['user_id = ? AND is_public = ?', id, false]
+    Query.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
+    TimeEntry.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
+    Token.delete_all ['user_id = ?', id]
+    Watcher.delete_all ['user_id = ?', id]
+    WikiContent.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+    WikiContent::Version.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+  end
+
+  # Return password digest
+  def self.hash_password(clear_password)
+    Digest::SHA1.hexdigest(clear_password || "")
+  end
+
+  # Returns a 128bits random salt as a hex string (32 chars long)
+  def self.generate_salt
+    ActiveSupport::SecureRandom.hex(16)
+  end
+
+end
+
+class AnonymousUser < User
+
+  def validate_on_create
+    # There should be only one AnonymousUser in the database
+    errors.add :base, 'An anonymous user already exists.' if AnonymousUser.find(:first)
+  end
+
+  def available_custom_fields
+    []
+  end
+
+  # Overrides a few properties
+  def logged?; false end
+  def admin; false end
+  def name(*args); I18n.t(:label_user_anonymous) end
+  def mail; nil end
+  def time_zone; nil end
+  def rss_key; nil end
+
+  # Anonymous user can not be destroyed
+  def destroy
+    false
+  end
+end
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4ead8da3bccd9129e3a3aa36afffc50dc032eb7b.svn-base
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.svn/pristine/4e/4ead8da3bccd9129e3a3aa36afffc50dc032eb7b.svn-base	Mon Feb 27 13:53:18 2012 +0000
@@ -0,0 +1,6 @@
+

<%= l(:mail_body_wiki_content_updated, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), + :author => h(@wiki_content.author)) %>
+<%=h @wiki_content.comments %>

+ +

<%= l(:label_view_diff) %>:
+<%= link_to h(@wiki_diff_url), @wiki_diff_url %>

diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4eb9fbcc6b6593735e81af0dae9bbc0fbd5d1f99.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4e/4eb9fbcc6b6593735e81af0dae9bbc0fbd5d1f99.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddCustomFieldIsFilter < ActiveRecord::Migration + def self.up + add_column :custom_fields, :is_filter, :boolean, :null => false, :default => false + end + + def self.down + remove_column :custom_fields, :is_filter + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4e/4ef703128369b40fb6019b1a708a1cedffb1ad35.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4e/4ef703128369b40fb6019b1a708a1cedffb1ad35.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +thirty_seven_signals: + id: 1 + name: 37Signals + rating: 4 + +TextDrive: + id: 2 + name: TextDrive + rating: 4 + +PlanetArgon: + id: 3 + name: Planet Argon + rating: 4 + +Google: + id: 4 + name: Google + rating: 4 + +Ionist: + id: 5 + name: Ioni.st + rating: 4 \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4f4249c007fe05ae60a997c7b935c55203608b2e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4f4249c007fe05ae60a997c7b935c55203608b2e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +/* + * Raphael 1.5.2 - JavaScript Vector Library + * + * Copyright (c) 2010 Dmitry Baranovskiy (http://raphaeljs.com) + * Licensed under the MIT (http://raphaeljs.com/license.html) license. + */ +(function(){function cC(a,b,c,d,e,f){function o(a,b){var c,d,e,f,j,k;for(e=a,k=0;k<8;k++){f=m(e)-a;if(B(f)d)return d;while(cf?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cB(b){return function(c,d,e,f){var g={back:b};a.is(e,"function")?f=e:g.rot=e,c&&c.constructor==bN&&(c=c.attrs.path),c&&(g.along=c);return this.animate(g,d,f)}}function cp(){return this.x+q+this.y}function bm(a,b,c){function d(){var g=Array[e].slice.call(arguments,0),h=g[v]("►"),i=d.cache=d.cache||{},j=d.count=d.count||[];if(i[f](h))return c?c(i[h]):i[h];j[w]>=1e3&&delete i[j.shift()],j[L](h),i[h]=a[m](b,g);return c?c(i[h]):i[h]}return d}function bh(){var a=[],b=0;for(;b<32;b++)a[b]=(~~(y.random()*16))[H](16);a[12]=4,a[16]=(a[16]&3|8)[H](16);return"r-"+a[v]("")}function a(){if(a.is(arguments[0],G)){var b=arguments[0],d=bV[m](a,b.splice(0,3+a.is(b[0],E))),e=d.set();for(var g=0,h=b[w];g',bg=bf.firstChild,bg.style.behavior="url(#default#VML)";if(!bg||typeof bg.adj!="object")return a.type=null;bf=null}a.svg=!(a.vml=a.type=="VML"),j[e]=a[e],k=j[e],a._id=0,a._oid=0,a.fn={},a.is=function(a,b){b=x.call(b);if(b=="finite")return!O[f](+a);return b=="null"&&a===null||b==typeof a||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||J.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return((h<0)*180+y.atan(-i/-h)*180/D+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*D/180},a.deg=function(a){return a*180/D%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,G)){var e=b.length;while(e--)if(B(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c},a.setWindow=function(a){h=a,g=h.document};var bi=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),d=e.body}catch(f){d=createPopup().document.body}var h=d.createTextRange();bi=bm(function(a){try{d.style.color=r(a)[Y](c,p);var b=h.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b[H](16)).slice(-6)}catch(e){return"none"}})}else{var i=g.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",g.body[l](i),bi=bm(function(a){i.style.color=a;return g.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bi(b)},bj=function(){return"hsb("+[this.h,this.s,this.b]+")"},bk=function(){return"hsl("+[this.h,this.s,this.l]+")"},bl=function(){return this.hex};a.hsb2rgb=function(b,c,d,e){a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b&&(d=b.b,c=b.s,b=b.h,e=b.o);return a.hsl2rgb(b,c,d/2,e)},a.hsl2rgb=function(b,c,d,e){a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b&&(d=b.l,c=b.s,b=b.h);if(b>1||c>1||d>1)b/=360,c/=100,d/=100;var f={},g=["r","g","b"],h,i,j,k,l,m;if(!c)f={r:d,g:d,b:d};else{d<.5?h=d*(1+c):h=d+c-d*c,i=2*d-h;for(var n=0;n<3;n++)j=b+1/3*-(n-1),j<0&&j++,j>1&&j--,j*6<1?f[g[n]]=i+(h-i)*6*j:j*2<1?f[g[n]]=h:j*3<2?f[g[n]]=i+(h-i)*(2/3-j)*6:f[g[n]]=i}f.r*=255,f.g*=255,f.b*=255,f.hex="#"+(16777216|f.b|f.g<<8|f.r<<16).toString(16).slice(1),a.is(e,"finite")&&(f.opacity=e),f.toString=bl;return f},a.rgb2hsb=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;var f=z(b,c,d),g=A(b,c,d),h,i,j=f;if(g==f)return{h:0,s:0,b:f,toString:bj};var k=f-g;i=k/f,b==f?h=(c-d)/k:c==f?h=2+(d-b)/k:h=4+(b-c)/k,h/=6,h<0&&h++,h>1&&h--;return{h:h,s:i,b:j,toString:bj}},a.rgb2hsl=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;var f=z(b,c,d),g=A(b,c,d),h,i,j=(f+g)/2,k;if(g==f)k={h:0,s:0,l:j};else{var l=f-g;i=j<.5?l/(f+g):l/(2-f-g),b==f?h=(c-d)/l:c==f?h=2+(d-b)/l:h=4+(b-c)/l,h/=6,h<0&&h++,h>1&&h--,k={h:h,s:i,l:j}}k.toString=bk;return k},a._path2string=function(){return this.join(",")[Y](ba,"$1")},a.getRGB=bm(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none"};!_[f](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bi(b));var c,d,e,g,h,i,j,k=b.match(N);if(k){k[2]&&(g=T(k[2].substring(5),16),e=T(k[2].substring(3,5),16),d=T(k[2].substring(1,3),16)),k[3]&&(g=T((i=k[3].charAt(3))+i,16),e=T((i=k[3].charAt(2))+i,16),d=T((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s]($),d=S(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=S(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),g=S(j[2]),j[2].slice(-1)=="%"&&(g*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=S(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s]($),d=S(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=S(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),g=S(j[2]),j[2].slice(-1)=="%"&&(g*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=S(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,g,h)}if(k[6]){j=k[6][s]($),d=S(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=S(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),g=S(j[2]),j[2].slice(-1)=="%"&&(g*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=S(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,g,h)}k={r:d,g:e,b:g},k.hex="#"+(16777216|g|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1}},a),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=bm(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,G)&&a.is(b[0],G)&&(d=bo(b)),d[w]||r(b)[Y](bb,function(a,b,e){var f=[],g=x.call(b);e[Y](bc,function(a,b){b&&f[L](+b)}),g=="m"&&f[w]>2&&(d[L]([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");while(f[w]>=c[g]){d[L]([b][n](f.splice(0,c[g])));if(!c[g])break}}),d[H]=a._path2string;return d}),a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=C(j,3)*a+C(j,2)*3*i*c+j*3*i*i*e+C(i,3)*g,l=C(j,3)*b+C(j,2)*3*i*d+j*3*i*i*f+C(i,3)*h,m=a+2*i*(c-a)+i*i*(e-2*c+a),n=b+2*i*(d-b)+i*i*(f-2*d+b),o=c+2*i*(e-c)+i*i*(g-2*e+c),p=d+2*i*(f-d)+i*i*(h-2*f+d),q=(1-i)*a+i*c,r=(1-i)*b+i*d,s=(1-i)*e+i*g,t=(1-i)*f+i*h,u=90-y.atan((m-o)/(n-p))*180/D;(m>o||n1&&(x=y.sqrt(x),c=x*c,d=x*d);var z=c*c,A=d*d,C=(f==g?-1:1)*y.sqrt(B((z*A-z*u*u-A*t*t)/(z*u*u+A*t*t))),E=C*c*u/d+(a+h)/2,F=C*-d*t/c+(b+i)/2,G=y.asin(((b-F)/d).toFixed(9)),H=y.asin(((i-F)/d).toFixed(9));G=aH&&(G=G-D*2),!g&&H>G&&(H=H-D*2)}else G=j[0],H=j[1],E=j[2],F=j[3];var I=H-G;if(B(I)>k){var J=H,K=h,L=i;H=G+k*(g&&H>G?1:-1),h=E+c*y.cos(H),i=F+d*y.sin(H),m=bt(h,i,c,d,e,0,g,K,L,[H,J,E,F])}I=H-G;var M=y.cos(G),N=y.sin(G),O=y.cos(H),P=y.sin(H),Q=y.tan(I/4),R=4/3*c*Q,S=4/3*d*Q,T=[a,b],U=[a+R*N,b-S*M],V=[h+R*P,i-S*O],W=[h,i];U[0]=2*T[0]-U[0],U[1]=2*T[1]-U[1];if(j)return[U,V,W][n](m);m=[U,V,W][n](m)[v]()[s](",");var X=[];for(var Y=0,Z=m[w];Y"1e12"&&(l=.5),B(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bu(a,b,c,d,e,f,g,h,l),p[L](q.x),o[L](q.y)),n>0&&n<1&&(q=bu(a,b,c,d,e,f,g,h,n),p[L](q.x),o[L](q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+y.sqrt(j*j-4*i*k))/2/i,n=(-j-y.sqrt(j*j-4*i*k))/2/i,B(l)>"1e12"&&(l=.5),B(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bu(a,b,c,d,e,f,g,h,l),p[L](q.x),o[L](q.y)),n>0&&n<1&&(q=bu(a,b,c,d,e,f,g,h,n),p[L](q.x),o[L](q.y));return{min:{x:A[m](0,p),y:A[m](0,o)},max:{x:z[m](0,p),y:z[m](0,o)}}}),bw=bm(function(a,b){var c=bq(a),d=b&&bq(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bt[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bs(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bs(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](br(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](br(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](br(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](br(b.x,b.y,b.X,b.Y))}return a},h=function(a,b){if(a[b][w]>7){a[b].shift();var e=a[b];while(e[w])a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1),k=z(c[w],d&&d[w]||0)}},i=function(a,b,e,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),e.bx=0,e.by=0,e.x=a[g][1],e.y=a[g][2],k=z(c[w],d&&d[w]||0))};for(var j=0,k=z(c[w],d&&d[w]||0);j.5)*2-1;C(e-.5,2)+C(f-.5,2)>.25&&(f=y.sqrt(.25-C(e-.5,2))*g+.5)&&f!=.5&&(f=f.toFixed(5)-1e-5*g)}return p}),b=b[s](/\s*\-\s*/);if(d=="linear"){var i=b.shift();i=-S(i);if(isNaN(i))return null;var j=[0,0,y.cos(i*D/180),y.sin(i*D/180)],k=1/(z(B(j[2]),B(j[3]))||1);j[2]*=k,j[3]*=k,j[2]<0&&(j[0]=-j[2],j[2]=0),j[3]<0&&(j[1]=-j[3],j[3]=0)}var m=bx(b);if(!m)return null;var n=a.getAttribute(I);n=n.match(/^url\(#(.*)\)$/),n&&c.defs.removeChild(g.getElementById(n[1]));var o=bG(d+"Gradient");o.id=bh(),bG(o,d=="radial"?{fx:e,fy:f}:{x1:j[0],y1:j[1],x2:j[2],y2:j[3]}),c.defs[l](o);for(var q=0,t=m[w];q1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(o),h[R](n,G.hex),n=="stroke"&&G[f]("opacity")&&bG(h,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity});break;case"gradient":(({circle:1,ellipse:1})[f](c.type)||r(o).charAt()!="r")&&bI(h,o,c.paper);break;case"opacity":i.gradient&&!i[f]("stroke-opacity")&&bG(h,{"stroke-opacity":o>1?o/100:o});case"fill-opacity":if(i.gradient){var H=g.getElementById(h.getAttribute(I)[Y](/^url\(#|\)$/g,p));if(H){var J=H.getElementsByTagName("stop");J[J[w]-1][R]("stop-opacity",o)}break};default:n=="font-size"&&(o=T(o,10)+"px");var K=n[Y](/(\-.)/g,function(a){return V.call(a.substring(1))});h.style[K]=o,h[R](n,o)}}bM(c,d),m?c.rotate(m.join(q)):S(j)&&c.rotate(j,!0)},bL=1.2,bM=function(b,c){if(b.type=="text"&&!!(c[f]("text")||c[f]("font")||c[f]("font-size")||c[f]("x")||c[f]("y"))){var d=b.attrs,e=b.node,h=e.firstChild?T(g.defaultView.getComputedStyle(e.firstChild,p).getPropertyValue("font-size"),10):10;if(c[f]("text")){d.text=c.text;while(e.firstChild)e.removeChild(e.firstChild);var i=r(c.text)[s]("\n");for(var j=0,k=i[w];jb.height&&(b.height=f.y+f.height-b.y),f.x+f.width-b.x>b.width&&(b.width=f.x+f.width-b.x)}}a&&this.hide();return b},bN[e].attr=function(b,c){if(this.removed)return this;if(b==null){var d={};for(var e in this.attrs)this.attrs[f](e)&&(d[e]=this.attrs[e]);this._.rt.deg&&(d.rotation=this.rotate()),(this._.sx!=1||this._.sy!=1)&&(d.scale=this.scale()),d.gradient&&d.fill=="none"&&(d.fill=d.gradient)&&delete d.gradient;return d}if(c==null&&a.is(b,F)){if(b=="translation")return cA.call(this);if(b=="rotation")return this.rotate();if(b=="scale")return this.scale();if(b==I&&this.attrs.fill=="none"&&this.attrs.gradient)return this.attrs.gradient;return this.attrs[b]}if(c==null&&a.is(b,G)){var g={};for(var h=0,i=b.length;h")),m.W=h.w=m.paper.span.offsetWidth,m.H=h.h=m.paper.span.offsetHeight,m.X=h.x,m.Y=h.y+Q(m.H/2);switch(h["text-anchor"]){case"start":m.node.style["v-text-align"]="left",m.bbx=Q(m.W/2);break;case"end":m.node.style["v-text-align"]="right",m.bbx=-Q(m.W/2);break;default:m.node.style["v-text-align"]="center"}}},bI=function(a,b){a.attrs=a.attrs||{};var c=a.attrs,d,e="linear",f=".5 .5";a.attrs.gradient=b,b=r(b)[Y](bd,function(a,b,c){e="radial",b&&c&&(b=S(b),c=S(c),C(b-.5,2)+C(c-.5,2)>.25&&(c=y.sqrt(.25-C(b-.5,2))*((c>.5)*2-1)+.5),f=b+q+c);return p}),b=b[s](/\s*\-\s*/);if(e=="linear"){var g=b.shift();g=-S(g);if(isNaN(g))return null}var h=bx(b);if(!h)return null;a=a.shape||a.node,d=a.getElementsByTagName(I)[0]||cd(I),!d.parentNode&&a.appendChild(d);if(h[w]){d.on=!0,d.method="none",d.color=h[0].color,d.color2=h[h[w]-1].color;var i=[];for(var j=0,k=h[w];j')}}catch(ce){cd=function(a){return g.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}bV=function(){var b=by[m](0,arguments),c=b.container,d=b.height,e,f=b.width,h=b.x,i=b.y;if(!c)throw new Error("VML container not found.");var k=new j,n=k.canvas=g.createElement("div"),o=n.style;h=h||0,i=i||0,f=f||512,d=d||342,f==+f&&(f+="px"),d==+d&&(d+="px"),k.width=1e3,k.height=1e3,k.coordsize=b_*1e3+q+b_*1e3,k.coordorigin="0 0",k.span=g.createElement("span"),k.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",n[l](k.span),o.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(g.body[l](n),o.left=h+"px",o.top=i+"px",o.position="absolute"):c.firstChild?c.insertBefore(n,c.firstChild):c[l](n),bz.call(k,k,a.fn);return k},k.clear=function(){this.canvas.innerHTML=p,this.span=g.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas[l](this.span),this.bottom=this.top=null},k.remove=function(){this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]=bF(a);return!0}}var cf=navigator.userAgent.match(/Version\/(.*?)\s/);navigator.vendor=="Apple Computer, Inc."&&(cf&&cf[1]<4||navigator.platform.slice(0,2)=="iP")?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});h.setTimeout(function(){a.remove()})}:k.safari=function(){};var cg=function(){this.returnValue=!1},ch=function(){return this.originalEvent.preventDefault()},ci=function(){this.cancelBubble=!0},cj=function(){return this.originalEvent.stopPropagation()},ck=function(){if(g.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,g=function(e){if(o&&u[f](b))for(var g=0,h=e.targetTouches&&e.targetTouches.length;g1&&(a=Array[e].splice.call(arguments,0,arguments[w]));return new cD(a)},k.setSize=bU,k.top=k.bottom=null,k.raphael=a,bO.resetScale=function(){if(this.removed)return this;this._.sx=1,this._.sy=1,this.attrs.scale="1 1"},bO.scale=function(a,b,c,d){if(this.removed)return this;if(a==null&&b==null)return{x:this._.sx,y:this._.sy,toString:cp};b=b||a,!+b&&(b=a);var e,f,g,h,i=this.attrs;if(a!=0){var j=this.getBBox(),k=j.x+j.width/2,l=j.y+j.height/2,m=B(a/this._.sx),o=B(b/this._.sy);c=+c||c==0?c:k,d=+d||d==0?d:l;var r=this._.sx>0,s=this._.sy>0,t=~~(a/B(a)),u=~~(b/B(b)),x=m*t,y=o*u,z=this.node.style,A=c+B(k-c)*x*(k>c==r?1:-1),C=d+B(l-d)*y*(l>d==s?1:-1),D=a*t>b*u?o:m;switch(this.type){case"rect":case"image":var E=i.width*m,F=i.height*o;this.attr({height:F,r:i.r*D,width:E,x:A-E/2,y:C-F/2});break;case"circle":case"ellipse":this.attr({rx:i.rx*m,ry:i.ry*o,r:i.r*D,cx:A,cy:C});break;case"text":this.attr({x:A,y:C});break;case"path":var G=bp(i.path),H=!0,I=r?x:m,J=s?y:o;for(var K=0,L=G[w];Kr?p=n.data[r*l]:(p=a.findDotsAtSegment(b,c,d,e,f,g,h,i,r/l),n.data[r]=p),r&&(k+=C(C(o.x-p.x,2)+C(o.y-p.y,2),.5));if(j!=null&&k>=j)return p;o=p}if(j==null)return k},cs=function(b,c){return function(d,e,f){d=bw(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cr(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C",m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M",m.x,m.y+"C",m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]][v](),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cr(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[1],i[2],i[3],i[4],i[5],i[6],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},ct=cs(1),cu=cs(),cv=cs(0,1);bO.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return ct(this.attrs.path)}},bO.getPointAtLength=function(a){if(this.type=="path")return cu(this.attrs.path,a)},bO.getSubpath=function(a,b){if(this.type=="path"){if(B(this.getTotalLength()-b)<"1e-6")return cv(this.attrs.path,a).end;var c=cv(this.attrs.path,b,1);return a?cv(c,a).end:c}},a.easing_formulas={linear:function(a){return a},"<":function(a){return C(a,3)},">":function(a){return C(a-1,3)+1},"<>":function(a){a=a*2;if(a<1)return C(a,3)/2;a-=2;return(C(a,3)+2)/2},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==0||a==1)return a;var b=.3,c=b/4;return C(2,-10*a)*y.sin((a-c)*2*D/b)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};var cw=[],cx=function(){var b=+(new Date);for(var c=0;c +# by Alberto Ferreira +pt: + support: + array: + sentence_connector: "e" + skip_last_comma: true + + direction: ltr + date: + formats: + default: "%d/%m/%Y" + short: "%d de %B" + long: "%d de %B de %Y" + only_day: "%d" + day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] + abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] + month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] + abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %d de %B de %Y, %H:%Mh" + time: "%H:%M" + short: "%d/%m, %H:%M hs" + long: "%A, %d de %B de %Y, %H:%Mh" + am: '' + pm: '' + + datetime: + distance_in_words: + half_a_minute: "meio minuto" + less_than_x_seconds: + one: "menos de 1 segundo" + other: "menos de %{count} segundos" + x_seconds: + one: "1 segundo" + other: "%{count} segundos" + less_than_x_minutes: + one: "menos de um minuto" + other: "menos de %{count} minutos" + x_minutes: + one: "1 minuto" + other: "%{count} minutos" + about_x_hours: + one: "aproximadamente 1 hora" + other: "aproximadamente %{count} horas" + x_days: + one: "1 dia" + other: "%{count} dias" + about_x_months: + one: "aproximadamente 1 mês" + other: "aproximadamente %{count} meses" + x_months: + one: "1 mês" + other: "%{count} meses" + about_x_years: + one: "aproximadamente 1 ano" + other: "aproximadamente %{count} anos" + over_x_years: + one: "mais de 1 ano" + other: "mais de %{count} anos" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: '€' + precision: 2 + format: "%u %n" + separator: ',' + delimiter: '.' + percentage: + format: + delimiter: '' + precision: + format: + delimiter: '' + human: + format: + precision: 1 + delimiter: '' + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + activerecord: + errors: + template: + header: + one: "Não foi possível guardar %{model}: 1 erro" + other: "Não foi possível guardar %{model}: %{count} erros" + body: "Por favor, verifique os seguintes campos:" + messages: + inclusion: "não está incluído na lista" + exclusion: "não está disponível" + invalid: "não é válido" + confirmation: "não está de acordo com a confirmação" + accepted: "precisa de ser aceite" + empty: "não pode estar em branco" + blank: "não pode estar em branco" + too_long: "tem demasiados caracteres (máximo: %{count} caracteres)" + too_short: "tem poucos caracteres (mínimo: %{count} caracteres)" + wrong_length: "não é do tamanho correcto (necessita de ter %{count} caracteres)" + taken: "não está disponível" + not_a_number: "não é um número" + greater_than: "tem de ser maior do que %{count}" + greater_than_or_equal_to: "tem de ser maior ou igual a %{count}" + equal_to: "tem de ser igual a %{count}" + less_than: "tem de ser menor do que %{count}" + less_than_or_equal_to: "tem de ser menor ou igual a %{count}" + odd: "tem de ser ímpar" + even: "tem de ser par" + greater_than_start_date: "deve ser maior que a data inicial" + not_same_project: "não pertence ao mesmo projecto" + circular_dependency: "Esta relação iria criar uma dependência circular" + cant_link_an_issue_with_a_descendant: "Não é possível ligar uma tarefa a uma sub-tarefa que lhe é pertencente" + + ## Translated by: Pedro Araújo + actionview_instancetag_blank_option: Seleccione + + general_text_No: 'Não' + general_text_Yes: 'Sim' + general_text_no: 'não' + general_text_yes: 'sim' + general_lang_name: 'Português' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: A conta foi actualizada com sucesso. + notice_account_invalid_creditentials: Utilizador ou palavra-chave inválidos. + notice_account_password_updated: A palavra-chave foi alterada com sucesso. + notice_account_wrong_password: Palavra-chave errada. + notice_account_register_done: A conta foi criada com sucesso. + notice_account_unknown_email: Utilizador desconhecido. + notice_can_t_change_password: Esta conta utiliza uma fonte de autenticação externa. Não é possível alterar a palavra-chave. + notice_account_lost_email_sent: Foi-lhe enviado um e-mail com as instruções para escolher uma nova palavra-chave. + notice_account_activated: A sua conta foi activada. É agora possível autenticar-se. + notice_successful_create: Criado com sucesso. + notice_successful_update: Alterado com sucesso. + notice_successful_delete: Apagado com sucesso. + notice_successful_connection: Ligado com sucesso. + notice_file_not_found: A página que está a tentar aceder não existe ou foi removida. + notice_locking_conflict: Os dados foram actualizados por outro utilizador. + notice_not_authorized: Não está autorizado a visualizar esta página. + notice_email_sent: "Foi enviado um e-mail para %{value}" + notice_email_error: "Ocorreu um erro ao enviar o e-mail (%{value})" + notice_feeds_access_key_reseted: A sua chave de RSS foi inicializada. + notice_failed_to_save_issues: "Não foi possível guardar %{count} tarefa(s) das %{total} seleccionadas: %{ids}." + notice_no_issue_selected: "Nenhuma tarefa seleccionada! Por favor, seleccione as tarefas que quer editar." + notice_account_pending: "A sua conta foi criada e está agora à espera de aprovação do administrador." + notice_default_data_loaded: Configuração padrão carregada com sucesso. + notice_unable_delete_version: Não foi possível apagar a versão. + + error_can_t_load_default_data: "Não foi possível carregar a configuração padrão: %{value}" + error_scm_not_found: "A entrada ou revisão não foi encontrada no repositório." + error_scm_command_failed: "Ocorreu um erro ao tentar aceder ao repositório: %{value}" + error_scm_annotate: "A entrada não existe ou não pode ser anotada." + error_issue_not_found_in_project: 'A tarefa não foi encontrada ou não pertence a este projecto.' + + mail_subject_lost_password: "Palavra-chave de %{value}" + mail_body_lost_password: 'Para mudar a sua palavra-chave, clique na ligação abaixo:' + mail_subject_register: "Activação de conta de %{value}" + mail_body_register: 'Para activar a sua conta, clique na ligação abaixo:' + mail_body_account_information_external: "Pode utilizar a conta %{value} para autenticar-se." + mail_body_account_information: Informação da sua conta + mail_subject_account_activation_request: "Pedido de activação da conta %{value}" + mail_body_account_activation_request: "Um novo utilizador (%{value}) registou-se. A sua conta está à espera de aprovação:" + mail_subject_reminder: "%{count} tarefa(s) para entregar nos próximos %{days} dias" + mail_body_reminder: "%{count} tarefa(s) que estão atribuídas a si estão agendadas para estarem completas nos próximos %{days} dias:" + + gui_validation_error: 1 erro + gui_validation_error_plural: "%{count} erros" + + field_name: Nome + field_description: Descrição + field_summary: Sumário + field_is_required: Obrigatório + field_firstname: Nome + field_lastname: Apelido + field_mail: E-mail + field_filename: Ficheiro + field_filesize: Tamanho + field_downloads: Downloads + field_author: Autor + field_created_on: Criado + field_updated_on: Alterado + field_field_format: Formato + field_is_for_all: Para todos os projectos + field_possible_values: Valores possíveis + field_regexp: Expressão regular + field_min_length: Tamanho mínimo + field_max_length: Tamanho máximo + field_value: Valor + field_category: Categoria + field_title: Título + field_project: Projecto + field_issue: Tarefa + field_status: Estado + field_notes: Notas + field_is_closed: Tarefa fechada + field_is_default: Valor por omissão + field_tracker: Tipo + field_subject: Assunto + field_due_date: Data fim + field_assigned_to: Atribuído a + field_priority: Prioridade + field_fixed_version: Versão + field_user: Utilizador + field_role: Função + field_homepage: Página + field_is_public: Público + field_parent: Sub-projecto de + field_is_in_roadmap: Tarefas mostradas no mapa de planificação + field_login: Nome de utilizador + field_mail_notification: Notificações por e-mail + field_admin: Administrador + field_last_login_on: Última visita + field_language: Língua + field_effective_date: Data + field_password: Palavra-chave + field_new_password: Nova palavra-chave + field_password_confirmation: Confirmação + field_version: Versão + field_type: Tipo + field_host: Servidor + field_port: Porta + field_account: Conta + field_base_dn: Base DN + field_attr_login: Atributo utilizador + field_attr_firstname: Atributo nome próprio + field_attr_lastname: Atributo último nome + field_attr_mail: Atributo e-mail + field_onthefly: Criação imediata de utilizadores + field_start_date: Data início + field_done_ratio: "% Completo" + field_auth_source: Modo de autenticação + field_hide_mail: Esconder endereço de e-mail + field_comments: Comentário + field_url: URL + field_start_page: Página inicial + field_subproject: Subprojecto + field_hours: Horas + field_activity: Actividade + field_spent_on: Data + field_identifier: Identificador + field_is_filter: Usado como filtro + field_issue_to: Tarefa relacionada + field_delay: Atraso + field_assignable: As tarefas podem ser associadas a esta função + field_redirect_existing_links: Redireccionar ligações existentes + field_estimated_hours: Tempo estimado + field_column_names: Colunas + field_time_zone: Fuso horário + field_searchable: Procurável + field_default_value: Valor por omissão + field_comments_sorting: Mostrar comentários + field_parent_title: Página pai + + setting_app_title: Título da aplicação + setting_app_subtitle: Sub-título da aplicação + setting_welcome_text: Texto de boas vindas + setting_default_language: Língua por omissão + setting_login_required: Autenticação obrigatória + setting_self_registration: Auto-registo + setting_attachment_max_size: Tamanho máximo do anexo + setting_issues_export_limit: Limite de exportação das tarefas + setting_mail_from: E-mail enviado de + setting_bcc_recipients: Recipientes de BCC + setting_host_name: Hostname + setting_text_formatting: Formatação do texto + setting_wiki_compression: Compressão do histórico do Wiki + setting_feeds_limit: Limite de conteúdo do feed + setting_default_projects_public: Projectos novos são públicos por omissão + setting_autofetch_changesets: Buscar automaticamente commits + setting_sys_api_enabled: Activar Web Service para gestão do repositório + setting_commit_ref_keywords: Palavras-chave de referência + setting_commit_fix_keywords: Palavras-chave de fecho + setting_autologin: Login automático + setting_date_format: Formato da data + setting_time_format: Formato do tempo + setting_cross_project_issue_relations: Permitir relações entre tarefas de projectos diferentes + setting_issue_list_default_columns: Colunas na lista de tarefas por omissão + setting_emails_footer: Rodapé do e-mails + setting_protocol: Protocolo + setting_per_page_options: Opções de objectos por página + setting_user_format: Formato de apresentaão de utilizadores + setting_activity_days_default: Dias mostrados na actividade do projecto + setting_display_subprojects_issues: Mostrar as tarefas dos sub-projectos nos projectos principais + setting_enabled_scm: Activar SCM + setting_mail_handler_api_enabled: Activar Web Service para e-mails recebidos + setting_mail_handler_api_key: Chave da API + setting_sequential_project_identifiers: Gerar identificadores de projecto sequênciais + + project_module_issue_tracking: Tarefas + project_module_time_tracking: Registo de tempo + project_module_news: Notícias + project_module_documents: Documentos + project_module_files: Ficheiros + project_module_wiki: Wiki + project_module_repository: Repositório + project_module_boards: Forum + + label_user: Utilizador + label_user_plural: Utilizadores + label_user_new: Novo utilizador + label_project: Projecto + label_project_new: Novo projecto + label_project_plural: Projectos + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Todos os projectos + label_project_latest: Últimos projectos + label_issue: Tarefa + label_issue_new: Nova tarefa + label_issue_plural: Tarefas + label_issue_view_all: Ver todas as tarefas + label_issues_by: "Tarefas por %{value}" + label_issue_added: Tarefa adicionada + label_issue_updated: Tarefa actualizada + label_document: Documento + label_document_new: Novo documento + label_document_plural: Documentos + label_document_added: Documento adicionado + label_role: Função + label_role_plural: Funções + label_role_new: Nova função + label_role_and_permissions: Funções e permissões + label_member: Membro + label_member_new: Novo membro + label_member_plural: Membros + label_tracker: Tipo + label_tracker_plural: Tipos + label_tracker_new: Novo tipo + label_workflow: Fluxo de trabalho + label_issue_status: Estado da tarefa + label_issue_status_plural: Estados da tarefa + label_issue_status_new: Novo estado + label_issue_category: Categoria de tarefa + label_issue_category_plural: Categorias de tarefa + label_issue_category_new: Nova categoria + label_custom_field: Campo personalizado + label_custom_field_plural: Campos personalizados + label_custom_field_new: Novo campo personalizado + label_enumerations: Enumerações + label_enumeration_new: Novo valor + label_information: Informação + label_information_plural: Informações + label_please_login: Por favor autentique-se + label_register: Registar + label_password_lost: Perdi a palavra-chave + label_home: Página Inicial + label_my_page: Página Pessoal + label_my_account: Minha conta + label_my_projects: Meus projectos + label_administration: Administração + label_login: Entrar + label_logout: Sair + label_help: Ajuda + label_reported_issues: Tarefas criadas + label_assigned_to_me_issues: Tarefas atribuídas a mim + label_last_login: Último acesso + label_registered_on: Registado em + label_activity: Actividade + label_overall_activity: Actividade geral + label_new: Novo + label_logged_as: Ligado como + label_environment: Ambiente + label_authentication: Autenticação + label_auth_source: Modo de autenticação + label_auth_source_new: Novo modo de autenticação + label_auth_source_plural: Modos de autenticação + label_subproject_plural: Sub-projectos + label_and_its_subprojects: "%{value} e sub-projectos" + label_min_max_length: Tamanho mínimo-máximo + label_list: Lista + label_date: Data + label_integer: Inteiro + label_float: Decimal + label_boolean: Booleano + label_string: Texto + label_text: Texto longo + label_attribute: Atributo + label_attribute_plural: Atributos + label_download: "%{count} Download" + label_download_plural: "%{count} Downloads" + label_no_data: Sem dados para mostrar + label_change_status: Mudar estado + label_history: Histórico + label_attachment: Ficheiro + label_attachment_new: Novo ficheiro + label_attachment_delete: Apagar ficheiro + label_attachment_plural: Ficheiros + label_file_added: Ficheiro adicionado + label_report: Relatório + label_report_plural: Relatórios + label_news: Notícia + label_news_new: Nova notícia + label_news_plural: Notícias + label_news_latest: Últimas notícias + label_news_view_all: Ver todas as notícias + label_news_added: Notícia adicionada + label_settings: Configurações + label_overview: Visão geral + label_version: Versão + label_version_new: Nova versão + label_version_plural: Versões + label_confirmation: Confirmação + label_export_to: 'Também disponível em:' + label_read: Ler... + label_public_projects: Projectos públicos + label_open_issues: aberto + label_open_issues_plural: abertos + label_closed_issues: fechado + label_closed_issues_plural: fechados + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Total + label_permissions: Permissões + label_current_status: Estado actual + label_new_statuses_allowed: Novos estados permitidos + label_all: todos + label_none: nenhum + label_nobody: ninguém + label_next: Próximo + label_previous: Anterior + label_used_by: Usado por + label_details: Detalhes + label_add_note: Adicionar nota + label_per_page: Por página + label_calendar: Calendário + label_months_from: meses de + label_gantt: Gantt + label_internal: Interno + label_last_changes: "últimas %{count} alterações" + label_change_view_all: Ver todas as alterações + label_personalize_page: Personalizar esta página + label_comment: Comentário + label_comment_plural: Comentários + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Adicionar comentário + label_comment_added: Comentário adicionado + label_comment_delete: Apagar comentários + label_query: Consulta personalizada + label_query_plural: Consultas personalizadas + label_query_new: Nova consulta + label_filter_add: Adicionar filtro + label_filter_plural: Filtros + label_equals: é + label_not_equals: não é + label_in_less_than: em menos de + label_in_more_than: em mais de + label_in: em + label_today: hoje + label_all_time: sempre + label_yesterday: ontem + label_this_week: esta semana + label_last_week: semana passada + label_last_n_days: "últimos %{count} dias" + label_this_month: este mês + label_last_month: mês passado + label_this_year: este ano + label_date_range: Date range + label_less_than_ago: menos de dias atrás + label_more_than_ago: mais de dias atrás + label_ago: dias atrás + label_contains: contém + label_not_contains: não contém + label_day_plural: dias + label_repository: Repositório + label_repository_plural: Repositórios + label_browse: Navegar + label_modification: "%{count} alteração" + label_modification_plural: "%{count} alterações" + label_revision: Revisão + label_revision_plural: Revisões + label_associated_revisions: Revisões associadas + label_added: adicionado + label_modified: modificado + label_copied: copiado + label_renamed: renomeado + label_deleted: apagado + label_latest_revision: Última revisão + label_latest_revision_plural: Últimas revisões + label_view_revisions: Ver revisões + label_max_size: Tamanho máximo + label_sort_highest: Mover para o início + label_sort_higher: Mover para cima + label_sort_lower: Mover para baixo + label_sort_lowest: Mover para o fim + label_roadmap: Planificação + label_roadmap_due_in: "Termina em %{value}" + label_roadmap_overdue: "Atrasado %{value}" + label_roadmap_no_issues: Sem tarefas para esta versão + label_search: Procurar + label_result_plural: Resultados + label_all_words: Todas as palavras + label_wiki: Wiki + label_wiki_edit: Edição da Wiki + label_wiki_edit_plural: Edições da Wiki + label_wiki_page: Página da Wiki + label_wiki_page_plural: Páginas da Wiki + label_index_by_title: Índice por título + label_index_by_date: Índice por data + label_current_version: Versão actual + label_preview: Pré-visualizar + label_feed_plural: Feeds + label_changes_details: Detalhes de todas as mudanças + label_issue_tracking: Tarefas + label_spent_time: Tempo gasto + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_time_tracking: Registo de tempo + label_change_plural: Mudanças + label_statistics: Estatísticas + label_commits_per_month: Commits por mês + label_commits_per_author: Commits por autor + label_view_diff: Ver diferenças + label_diff_inline: inline + label_diff_side_by_side: lado a lado + label_options: Opções + label_copy_workflow_from: Copiar fluxo de trabalho de + label_permissions_report: Relatório de permissões + label_watched_issues: Tarefas observadas + label_related_issues: Tarefas relacionadas + label_applied_status: Estado aplicado + label_loading: A carregar... + label_relation_new: Nova relação + label_relation_delete: Apagar relação + label_relates_to: relacionado a + label_duplicates: duplica + label_duplicated_by: duplicado por + label_blocks: bloqueia + label_blocked_by: bloqueado por + label_precedes: precede + label_follows: segue + label_end_to_start: fim a início + label_end_to_end: fim a fim + label_start_to_start: início a início + label_start_to_end: início a fim + label_stay_logged_in: Guardar sessão + label_disabled: desactivado + label_show_completed_versions: Mostrar versões acabadas + label_me: eu + label_board: Forum + label_board_new: Novo forum + label_board_plural: Forums + label_topic_plural: Tópicos + label_message_plural: Mensagens + label_message_last: Última mensagem + label_message_new: Nova mensagem + label_message_posted: Mensagem adicionada + label_reply_plural: Respostas + label_send_information: Enviar dados da conta para o utilizador + label_year: Ano + label_month: mês + label_week: Semana + label_date_from: De + label_date_to: Para + label_language_based: Baseado na língua do utilizador + label_sort_by: "Ordenar por %{value}" + label_send_test_email: enviar um e-mail de teste + label_feeds_access_key_created_on: "Chave RSS criada há %{value} atrás" + label_module_plural: Módulos + label_added_time_by: "Adicionado por %{author} há %{age} atrás" + label_updated_time: "Alterado há %{value} atrás" + label_jump_to_a_project: Ir para o projecto... + label_file_plural: Ficheiros + label_changeset_plural: Changesets + label_default_columns: Colunas por omissão + label_no_change_option: (sem alteração) + label_bulk_edit_selected_issues: Editar tarefas seleccionadas em conjunto + label_theme: Tema + label_default: Padrão + label_search_titles_only: Procurar apenas em títulos + label_user_mail_option_all: "Para qualquer evento em todos os meus projectos" + label_user_mail_option_selected: "Para qualquer evento apenas nos projectos seleccionados..." + label_user_mail_no_self_notified: "Não quero ser notificado de alterações feitas por mim" + label_registration_activation_by_email: Activação da conta por e-mail + label_registration_manual_activation: Activação manual da conta + label_registration_automatic_activation: Activação automática da conta + label_display_per_page: "Por página: %{value}" + label_age: Idade + label_change_properties: Mudar propriedades + label_general: Geral + label_more: Mais + label_scm: SCM + label_plugins: Extensões + label_ldap_authentication: Autenticação LDAP + label_downloads_abbr: D/L + label_optional_description: Descrição opcional + label_add_another_file: Adicionar outro ficheiro + label_preferences: Preferências + label_chronological_order: Em ordem cronológica + label_reverse_chronological_order: Em ordem cronológica inversa + label_planning: Planeamento + label_incoming_emails: E-mails a chegar + label_generate_key: Gerar uma chave + label_issue_watchers: Observadores + + button_login: Entrar + button_submit: Submeter + button_save: Guardar + button_check_all: Marcar tudo + button_uncheck_all: Desmarcar tudo + button_delete: Apagar + button_create: Criar + button_test: Testar + button_edit: Editar + button_add: Adicionar + button_change: Alterar + button_apply: Aplicar + button_clear: Limpar + button_lock: Bloquear + button_unlock: Desbloquear + button_download: Download + button_list: Listar + button_view: Ver + button_move: Mover + button_back: Voltar + button_cancel: Cancelar + button_activate: Activar + button_sort: Ordenar + button_log_time: Tempo de trabalho + button_rollback: Voltar para esta versão + button_watch: Observar + button_unwatch: Deixar de observar + button_reply: Responder + button_archive: Arquivar + button_unarchive: Desarquivar + button_reset: Reinicializar + button_rename: Renomear + button_change_password: Mudar palavra-chave + button_copy: Copiar + button_annotate: Anotar + button_update: Actualizar + button_configure: Configurar + button_quote: Citar + + status_active: activo + status_registered: registado + status_locked: bloqueado + + text_select_mail_notifications: Seleccionar as acções que originam uma notificação por e-mail. + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 siginifica sem restrição + text_project_destroy_confirmation: Tem a certeza que deseja apagar o projecto e todos os dados relacionados? + text_subprojects_destroy_warning: "O(s) seu(s) sub-projecto(s): %{value} também será/serão apagado(s)." + text_workflow_edit: Seleccione uma função e um tipo de tarefa para editar o fluxo de trabalho + text_are_you_sure: Tem a certeza? + text_tip_issue_begin_day: tarefa a começar neste dia + text_tip_issue_end_day: tarefa a acabar neste dia + text_tip_issue_begin_end_day: tarefa a começar e acabar neste dia + text_project_identifier_info: 'Apenas são permitidos letras minúsculas (a-z), números e hífens.
Uma vez guardado, o identificador não poderá ser alterado.' + text_caracters_maximum: "máximo %{count} caracteres." + text_caracters_minimum: "Deve ter pelo menos %{count} caracteres." + text_length_between: "Deve ter entre %{min} e %{max} caracteres." + text_tracker_no_workflow: Sem fluxo de trabalho definido para este tipo de tarefa. + text_unallowed_characters: Caracteres não permitidos + text_comma_separated: Permitidos múltiplos valores (separados por vírgula). + text_issues_ref_in_commit_messages: Referenciando e fechando tarefas em mensagens de commit + text_issue_added: "Tarefa %{id} foi criada por %{author}." + text_issue_updated: "Tarefa %{id} foi actualizada por %{author}." + text_wiki_destroy_confirmation: Tem a certeza que deseja apagar este wiki e todo o seu conteúdo? + text_issue_category_destroy_question: "Algumas tarefas (%{count}) estão atribuídas a esta categoria. O que quer fazer?" + text_issue_category_destroy_assignments: Remover as atribuições à categoria + text_issue_category_reassign_to: Re-atribuir as tarefas para esta categoria + text_user_mail_option: "Para projectos não seleccionados, apenas receberá notificações acerca de coisas que está a observar ou está envolvido (ex. tarefas das quais foi o criador ou lhes foram atribuídas)." + text_no_configuration_data: "Perfis, tipos de tarefas, estados das tarefas e workflows ainda não foram configurados.\nÉ extremamente recomendado carregar as configurações padrão. Será capaz de as modificar depois de estarem carregadas." + text_load_default_configuration: Carregar as configurações padrão + text_status_changed_by_changeset: "Aplicado no changeset %{value}." + text_issues_destroy_confirmation: 'Tem a certeza que deseja apagar a(s) tarefa(s) seleccionada(s)?' + text_select_project_modules: 'Seleccione os módulos a activar para este projecto:' + text_default_administrator_account_changed: Conta default de administrador alterada. + text_file_repository_writable: Repositório de ficheiros com permissões de escrita + text_rmagick_available: RMagick disponível (opcional) + text_destroy_time_entries_question: "%{hours} horas de trabalho foram atribuídas a estas tarefas que vai apagar. O que deseja fazer?" + text_destroy_time_entries: Apagar as horas + text_assign_time_entries_to_project: Atribuir as horas ao projecto + text_reassign_time_entries: 'Re-atribuir as horas para esta tarefa:' + text_user_wrote: "%{value} escreveu:" + text_enumeration_destroy_question: "%{count} objectos estão atribuídos a este valor." + text_enumeration_category_reassign_to: 'Re-atribuí-los para este valor:' + text_email_delivery_not_configured: "Entrega por e-mail não está configurada, e as notificação estão desactivadas.\nConfigure o seu servidor de SMTP em config/configuration.yml e reinicie a aplicação para activar estas funcionalidades." + + default_role_manager: Gestor + default_role_developer: Programador + default_role_reporter: Repórter + default_tracker_bug: Bug + default_tracker_feature: Funcionalidade + default_tracker_support: Suporte + default_issue_status_new: Novo + default_issue_status_in_progress: Em curso + default_issue_status_resolved: Resolvido + default_issue_status_feedback: Feedback + default_issue_status_closed: Fechado + default_issue_status_rejected: Rejeitado + default_doc_category_user: Documentação de utilizador + default_doc_category_tech: Documentação técnica + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_high: Alta + default_priority_urgent: Urgente + default_priority_immediate: Imediata + default_activity_design: Planeamento + default_activity_development: Desenvolvimento + + enumeration_issue_priorities: Prioridade de tarefas + enumeration_doc_categories: Categorias de documentos + enumeration_activities: Actividades (Registo de tempo) + setting_plain_text_mail: Apenas texto simples (sem HTML) + permission_view_files: Ver ficheiros + permission_edit_issues: Editar tarefas + permission_edit_own_time_entries: Editar horas pessoais + permission_manage_public_queries: Gerir queries públicas + permission_add_issues: Adicionar tarefas + permission_log_time: Registar tempo gasto + permission_view_changesets: Ver changesets + permission_view_time_entries: Ver tempo gasto + permission_manage_versions: Gerir versões + permission_manage_wiki: Gerir wiki + permission_manage_categories: Gerir categorias de tarefas + permission_protect_wiki_pages: Proteger páginas de wiki + permission_comment_news: Comentar notícias + permission_delete_messages: Apagar mensagens + permission_select_project_modules: Seleccionar módulos do projecto + permission_manage_documents: Gerir documentos + permission_edit_wiki_pages: Editar páginas de wiki + permission_add_issue_watchers: Adicionar observadores + permission_view_gantt: ver diagrama de Gantt + permission_move_issues: Mover tarefas + permission_manage_issue_relations: Gerir relações de tarefas + permission_delete_wiki_pages: Apagar páginas de wiki + permission_manage_boards: Gerir forums + permission_delete_wiki_pages_attachments: Apagar anexos + permission_view_wiki_edits: Ver histórico da wiki + permission_add_messages: Submeter mensagens + permission_view_messages: Ver mensagens + permission_manage_files: Gerir ficheiros + permission_edit_issue_notes: Editar notas de tarefas + permission_manage_news: Gerir notícias + permission_view_calendar: Ver calendário + permission_manage_members: Gerir membros + permission_edit_messages: Editar mensagens + permission_delete_issues: Apagar tarefas + permission_view_issue_watchers: Ver lista de observadores + permission_manage_repository: Gerir repositório + permission_commit_access: Acesso a submissão + permission_browse_repository: Navegar em repositório + permission_view_documents: Ver documentos + permission_edit_project: Editar projecto + permission_add_issue_notes: Adicionar notas a tarefas + permission_save_queries: Guardar queries + permission_view_wiki_pages: Ver wiki + permission_rename_wiki_pages: Renomear páginas de wiki + permission_edit_time_entries: Editar entradas de tempo + permission_edit_own_issue_notes: Editar as prórpias notas + setting_gravatar_enabled: Utilizar ícones Gravatar + label_example: Exemplo + text_repository_usernames_mapping: "Seleccionar ou actualizar o utilizador de Redmine mapeado a cada nome de utilizador encontrado no repositório.\nUtilizadores com o mesmo nome de utilizador ou email no Redmine e no repositório são mapeados automaticamente." + permission_edit_own_messages: Editar as próprias mensagens + permission_delete_own_messages: Apagar as próprias mensagens + label_user_activity: "Actividade de %{value}" + label_updated_time_by: "Actualizado por %{author} há %{age}" + text_diff_truncated: '... Este diff foi truncado porque excede o tamanho máximo que pode ser mostrado.' + setting_diff_max_lines_displayed: Número máximo de linhas de diff mostradas + text_plugin_assets_writable: Escrita na pasta de activos dos módulos de extensão possível + warning_attachments_not_saved: "Não foi possível gravar %{count} ficheiro(s) ." + button_create_and_continue: Criar e continuar + text_custom_field_possible_values_info: 'Uma linha para cada valor' + label_display: Mostrar + field_editable: Editável + setting_repository_log_display_limit: Número máximo de revisões exibido no relatório de ficheiro + setting_file_max_size_displayed: Tamanho máximo dos ficheiros de texto exibidos inline + field_watcher: Observador + setting_openid: Permitir início de sessão e registo com OpenID + field_identity_url: URL do OpenID + label_login_with_open_id_option: ou início de sessão com OpenID + field_content: Conteúdo + label_descending: Descendente + label_sort: Ordenar + label_ascending: Ascendente + label_date_from_to: De %{start} a %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Esta página tem %{descendants} página(s) subordinada(s) e descendente(s). O que deseja fazer? + text_wiki_page_reassign_children: Reatribuir páginas subordinadas a esta página principal + text_wiki_page_nullify_children: Manter páginas subordinadas como páginas raíz + text_wiki_page_destroy_children: Apagar as páginas subordinadas e todos os seus descendentes + setting_password_min_length: Tamanho mínimo de palavra-chave + field_group_by: Agrupar resultados por + mail_subject_wiki_content_updated: "A página Wiki '%{id}' foi actualizada" + label_wiki_content_added: Página Wiki adicionada + mail_subject_wiki_content_added: "A página Wiki '%{id}' foi adicionada" + mail_body_wiki_content_added: A página Wiki '%{id}' foi adicionada por %{author}. + label_wiki_content_updated: Página Wiki actualizada + mail_body_wiki_content_updated: A página Wiki '%{id}' foi actualizada por %{author}. + permission_add_project: Criar projecto + setting_new_project_user_role_id: Função atribuída a um utilizador não-administrador que cria um projecto + label_view_all_revisions: Ver todas as revisões + label_tag: Etiqueta + label_branch: Ramo + error_no_tracker_in_project: Este projecto não tem associado nenhum tipo de tarefas. Verifique as definições do projecto. + error_no_default_issue_status: Não está definido um estado padrão para as tarefas. Verifique a sua configuração (dirija-se a "Administração -> Estados da tarefa"). + label_group_plural: Grupos + label_group: Grupo + label_group_new: Novo grupo + label_time_entry_plural: Tempo registado + text_journal_changed: "%{label} alterado de %{old} para %{new}" + text_journal_set_to: "%{label} configurado como %{value}" + text_journal_deleted: "%{label} apagou (%{old})" + text_journal_added: "%{label} %{value} adicionado" + field_active: Activo + enumeration_system_activity: Actividade de sistema + permission_delete_issue_watchers: Apagar observadores + version_status_closed: fechado + version_status_locked: protegido + version_status_open: aberto + error_can_not_reopen_issue_on_closed_version: Não é possível voltar a abrir uma tarefa atribuída a uma versão fechada + label_user_anonymous: Anónimo + button_move_and_follow: Mover e seguir + setting_default_projects_modules: Módulos activos por predefinição para novos projectos + setting_gravatar_default: Imagem Gravatar predefinida + field_sharing: Partilha + label_version_sharing_hierarchy: Com hierarquia do projecto + label_version_sharing_system: Com todos os projectos + label_version_sharing_descendants: Com os sub-projectos + label_version_sharing_tree: Com árvore do projecto + label_version_sharing_none: Não partilhado + error_can_not_archive_project: Não é possível arquivar este projecto + button_duplicate: Duplicar + button_copy_and_follow: Copiar e seguir + label_copy_source: Origem + setting_issue_done_ratio: Calcular a percentagem de progresso da tarefa + setting_issue_done_ratio_issue_status: Através do estado da tarefa + error_issue_done_ratios_not_updated: Percentagens de progresso da tarefa não foram actualizadas. + error_workflow_copy_target: Seleccione os tipos de tarefas e funções desejadas + setting_issue_done_ratio_issue_field: Através do campo da tarefa + label_copy_same_as_target: Mesmo que o alvo + label_copy_target: Alvo + notice_issue_done_ratios_updated: Percentagens de progresso da tarefa actualizadas. + error_workflow_copy_source: Seleccione um tipo de tarefa ou função de origem + label_update_issue_done_ratios: Actualizar percentagens de progresso da tarefa + setting_start_of_week: Iniciar calendários a + permission_view_issues: Ver tarefas + label_display_used_statuses_only: Só exibir estados empregues por este tipo de tarefa + label_revision_id: Revisão %{value} + label_api_access_key: Chave de acesso API + label_api_access_key_created_on: Chave de acesso API criada há %{value} + label_feeds_access_key: Chave de acesso RSS + notice_api_access_key_reseted: A sua chave de acesso API foi reinicializada. + setting_rest_api_enabled: Activar serviço Web REST + label_missing_api_access_key: Chave de acesso API em falta + label_missing_feeds_access_key: Chave de acesso RSS em falta + button_show: Mostrar + text_line_separated: Vários valores permitidos (uma linha para cada valor). + setting_mail_handler_body_delimiters: Truncar mensagens de correio electrónico após uma destas linhas + permission_add_subprojects: Criar sub-projectos + label_subproject_new: Novo sub-projecto + text_own_membership_delete_confirmation: |- + Está prestes a eliminar parcial ou totalmente as suas permissões. É possível que não possa editar o projecto após esta acção. + Tem a certeza de que deseja continuar? + label_close_versions: Fechar versões completas + label_board_sticky: Fixar mensagem + label_board_locked: Proteger + permission_export_wiki_pages: Exportar páginas Wiki + setting_cache_formatted_text: Colocar formatação do texto na memória cache + permission_manage_project_activities: Gerir actividades do projecto + error_unable_delete_issue_status: Não foi possível apagar o estado da tarefa + label_profile: Perfil + permission_manage_subtasks: Gerir sub-tarefas + field_parent_issue: Tarefa principal + label_subtask_plural: Sub-tarefa + label_project_copy_notifications: Enviar notificações por e-mail durante a cópia do projecto + error_can_not_delete_custom_field: Não foi possível apagar o campo personalizado + error_unable_to_connect: Não foi possível ligar (%{value}) + error_can_not_remove_role: Esta função está actualmente em uso e não pode ser apagada. + error_can_not_delete_tracker: Existem ainda tarefas nesta categoria. Não é possível apagar este tipo de tarefa. + field_principal: Principal + label_my_page_block: Bloco da minha página + notice_failed_to_save_members: "Erro ao guardar o(s) membro(s): %{errors}." + text_zoom_out: Ampliar + text_zoom_in: Reduzir + notice_unable_delete_time_entry: Não foi possível apagar a entrada de tempo registado. + label_overall_spent_time: Total de tempo registado + field_time_entries: Tempo registado + project_module_gantt: Gantt + project_module_calendar: Calendário + button_edit_associated_wikipage: "Editar página Wiki associada: %{page_title}" + text_are_you_sure_with_children: Apagar tarefa e todas as sub-tarefas? + field_text: Campo de texto + label_user_mail_option_only_owner: Apenas para tarefas das quais sou proprietário + setting_default_notification_option: Opção predefinida de notificação + label_user_mail_option_only_my_events: Apenas para tarefas que observo ou em que estou envolvido + label_user_mail_option_only_assigned: Apenas para tarefas que me foram atribuídas + label_user_mail_option_none: Sem eventos + field_member_of_group: Grupo do detentor de atribuição + field_assigned_to_role: Papel do detentor de atribuição + notice_not_authorized_archived_project: O projecto a que tentou aceder foi arquivado. + label_principal_search: "Procurar utilizador ou grupo:" + label_user_search: "Procurar utilizador:" + field_visible: Visível + setting_emails_header: Cabeçalho dos e-mails + setting_commit_logtime_activity_id: Actividade para tempo registado + text_time_logged_by_changeset: Aplicado no conjunto de alterações %{value}. + setting_commit_logtime_enabled: Activar registo de tempo + notice_gantt_chart_truncated: O gráfico foi truncado porque excede o número máximo de itens visível (%{máx.}) + setting_gantt_items_limit: Número máximo de itens exibidos no gráfico Gantt + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Encoding das mensagens de commit + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4f73a84bff4795dfb5faa655966e733cc5e1a005.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4f73a84bff4795dfb5faa655966e733cc5e1a005.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,135 @@ +Sentences that contain all letters commonly used in a language +-------------------------------------------------------------- + +Markus Kuhn -- 2001-09-02 + +This file is UTF-8 encoded. + + +Danish (da) +--------- + + Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen + Wolther spillede på xylofon. + (= Quiz contestants were eating strawbery with cream while Wolther + the circus clown played on xylophone.) + +German (de) +----------- + + Falsches Üben von Xylophonmusik quält jeden größeren Zwerg + (= Wrongful practicing of xylophone music tortures every larger dwarf) + + Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich + (= Twelve boxing fighters hunted Eva across the dike of Sylt) + + Heizölrückstoßabdämpfung + (= fuel oil recoil absorber) + (jqvwxy missing, but all non-ASCII letters in one word) + +English (en) +------------ + + The quick brown fox jumps over the lazy dog + +Spanish (es) +------------ + + El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y + frío, añoraba a su querido cachorro. + (Contains every letter and every accent, but not every combination + of vowel + acute.) + +French (fr) +----------- + + Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à + côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce + qui lui permet de penser à la cænogenèse de l'être dont il est question + dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui, + pense-t-il, diminue çà et là la qualité de son œuvre. + + l'île exiguë + Où l'obèse jury mûr + Fête l'haï volapük, + Âne ex aéquo au whist, + Ôtez ce vœu déçu. + + Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en + canoë au delà des îles, près du mälström où brûlent les novæ. + +Irish Gaelic (ga) +----------------- + + D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh + +Hungarian (hu) +-------------- + + Árvíztűrő tükörfúrógép + (= flood-proof mirror-drilling machine, only all non-ASCII letters) + +Icelandic (is) +-------------- + + Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa + + Sævör grét áðan því úlpan var ónýt + (some ASCII letters missing) + +Greek (el) +------------- + + Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο + (= No more shall I see acacias or myrtles in the golden clearing) + + Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία + (= I uncover the soul-destroying abhorrence) + +Japanese (jp) +------------- + + Hiragana: (Iroha) + + いろはにほへとちりぬるを + わかよたれそつねならむ + うゐのおくやまけふこえて + あさきゆめみしゑひもせす + + Katakana: + + イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン + +Hebrew (iw) +----------- + + ? דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה + +Polish (pl) +----------- + + Pchnąć w tę łódź jeża lub ośm skrzyń fig + (= To push a hedgehog or eight bins of figs in this boat) + +Russian (ru) +------------ + + В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! + (= Would a citrus live in the bushes of south? Yes, but only a fake one!) + +Thai (th) +--------- + + [--------------------------|------------------------] + ๏ เป็นมนุษย์สุดประเสริฐเลิศคุณค่า กว่าบรรดาฝูงสัตว์เดรัจฉาน + จงฝ่าฟันพัฒนาวิชาการ อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร + ไม่ถือโทษโกรธแช่งซัดฮึดฮัดด่า หัดอภัยเหมือนกีฬาอัชฌาสัย + ปฏิบัติประพฤติกฎกำหนดใจ พูดจาให้จ๊ะๆ จ๋าๆ น่าฟังเอย ฯ + + [The copyright for the Thai example is owned by The Computer + Association of Thailand under the Royal Patronage of His Majesty the + King.] + +Please let me know if you find others! Special thanks to the people +from all over the world who contributed these sentences. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4f763e1fb601c197c6eeeedad018858337ca9744.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4f763e1fb601c197c6eeeedad018858337ca9744.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddTypeToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :type, :string + end + + def self.down + remove_column :enumerations, :type + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4f7c43bee38a0086927663fbc7e435338678ebfe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4f7c43bee38a0086927663fbc7e435338678ebfe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +

<%=l(:label_version)%>

+ +<% labelled_tabular_form_for @version do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4f91e1e0bb038b11d88f8da5ac2ec5d27ca2031c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4f91e1e0bb038b11d88f8da5ac2ec5d27ca2031c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class UserCustomField < CustomField + def type_name + :label_user_plural + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4f9b6989936a59570ee254faff0b99a606637086.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4f9b6989936a59570ee254faff0b99a606637086.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +class InsertBuiltinRoles < ActiveRecord::Migration + def self.up + nonmember = Role.new(:name => 'Non member', :position => 0) + nonmember.builtin = Role::BUILTIN_NON_MEMBER + nonmember.save + + anonymous = Role.new(:name => 'Anonymous', :position => 0) + anonymous.builtin = Role::BUILTIN_ANONYMOUS + anonymous.save + end + + def self.down + Role.destroy_all 'builtin <> 0' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4fa7fccc7426be98fbf63234a686b801fe484128.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4fa7fccc7426be98fbf63234a686b801fe484128.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +
+<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, + :class => 'icon icon-history') %> +
+ +<%= wiki_page_breadcrumb(@page) %> + +

<%= h(@page.pretty_title) %>

+ +

+<%= l(:label_version) %> <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %> +(<%= @diff.content_from.author ? + @diff.content_from.author.name : l(:label_user_anonymous) + %>, <%= format_time(@diff.content_from.updated_on) %>) +→ +<%= l(:label_version) %> <%= link_to @diff.content_to.version, :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => @diff.content_to.version + %>/<%= @page.content.version %> +(<%= @diff.content_to.author ? + link_to_user(@diff.content_to.author.name) : l(:label_user_anonymous) + %>, <%= format_time(@diff.content_to.updated_on) %>) +

+ +
+<%= simple_format_without_paragraph @diff.to_html %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/4f/4fb5582b9423d32809fbaa513dda130c44491b13.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/4f/4fb5582b9423d32809fbaa513dda130c44491b13.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +desc 'Generates a configuration file for cookie store sessions.' + +file 'config/initializers/session_store.rb' do + path = File.join(Rails.root, 'config', 'initializers', 'session_store.rb') + secret = ActiveSupport::SecureRandom.hex(40) + File.open(path, 'w') do |f| + f.write <<"EOF" +# This file was generated by 'rake config/initializers/session_store.rb', +# and should not be made visible to public. +# If you have a load-balancing Redmine cluster, you will need to use the +# same version of this file on each machine. And be sure to restart your +# server when you modify this file. + +# Your secret key for verifying cookie session data integrity. If you +# change this key, all old sessions will become invalid! Make sure the +# secret is at least 30 characters and all random, no regular words or +# you'll be exposed to dictionary attacks. +ActionController::Base.session = { + :key => '_redmine_session', + # + # Uncomment and edit the :session_path below if are hosting your Redmine + # at a suburi and don't want the top level path to access the cookies + # + # See: http://www.redmine.org/issues/3968 + # + # :session_path => '/url_path_to/your/redmine/', + :secret => '#{secret}' +} +EOF + end +end + +desc 'Generates a configuration file for cookie store sessions.' +task :generate_session_store => ['config/initializers/session_store.rb'] diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/50/509ee267bffe97965ae0a631af5009f5ad9e1775.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/50/509ee267bffe97965ae0a631af5009f5ad9e1775.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +
+<% form_tag({:action => 'revision', :id => @project}) do %> +<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %> +<%= submit_tag 'OK' %> +<% end %> +
+ +

<%= l(:label_revision_plural) %>

+ +<%= render :partial => 'revisions', + :locals => {:project => @project, + :path => '', + :revisions => @changesets, + :entry => nil } %> + +

<%= pagination_links_full @changeset_pages,@changeset_count %>

+ +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<%= auto_discovery_link_tag( + :atom, + params.merge( + {:format => 'atom', :page => nil, :key => User.current.rss_key})) %> +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title(l(:label_revision_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/50/50da835a6f15cfea65885171e3501d71716f5bea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/50/50da835a6f15cfea65885171e3501d71716f5bea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class EnabledModuleTest < ActiveSupport::TestCase + fixtures :projects, :wikis + + def test_enabling_wiki_should_create_a_wiki + CustomField.delete_all + project = Project.create!(:name => 'Project with wiki', :identifier => 'wikiproject') + assert_nil project.wiki + project.enabled_module_names = ['wiki'] + project.reload + assert_not_nil project.wiki + assert_equal 'Wiki', project.wiki.start_page + end + + def test_reenabling_wiki_should_not_create_another_wiki + project = Project.find(1) + assert_not_nil project.wiki + project.enabled_module_names = [] + project.reload + assert_no_difference 'Wiki.count' do + project.enabled_module_names = ['wiki'] + end + assert_not_nil project.wiki + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/51027398ce6a8d3706af5e108b6e6b3b8526c6c3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/51027398ce6a8d3706af5e108b6e6b3b8526c6c3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +# http://trac.openidenabled.com/trac/ticket/156 +module OpenID + @@timeout_threshold = 20 + + def self.timeout_threshold + @@timeout_threshold + end + + def self.timeout_threshold=(value) + @@timeout_threshold = value + end + + class StandardFetcher + def make_http(uri) + http = @proxy.new(uri.host, uri.port) + http.read_timeout = http.open_timeout = OpenID.timeout_threshold + http + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/511803794fbb1e6293350513f189e7f8e39bd703.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/511803794fbb1e6293350513f189e7f8e39bd703.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= Setting.emails_header %> +<%= yield %> +-- +<%= Setting.emails_footer %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/511d1a9b54cc17e8e6be5b0543b0c534e10de28e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/511d1a9b54cc17e8e6be5b0543b0c534e10de28e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +require File.join(File.dirname(__FILE__), *%w[.. .. test_helper]) + +class OverrideTest < ActiveSupport::TestCase + def test_overrides_from_the_application_should_work + assert true, "overriding plugin tests from the application should work" + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/515368fdaac86843c5831ecf3a694c18ace525e0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/515368fdaac86843c5831ecf3a694c18ace525e0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddEnumerationsIsDefault < ActiveRecord::Migration + def self.up + add_column :enumerations, :is_default, :boolean, :default => false, :null => false + end + + def self.down + remove_column :enumerations, :is_default + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/51931955320a8df763ed8cb90bc828e4398d3b92.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/51931955320a8df763ed8cb90bc828e4398d3b92.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +COPYING +ChangeLog +History.txt +Manifest.txt +README +Rakefile +TODO +lib/tree.rb +lib/tree/binarytree.rb +setup.rb +test/test_binarytree.rb +test/test_tree.rb diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/5194b9835666462a25b29cefc4dc53bf3bde050c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/5194b9835666462a25b29cefc4dc53bf3bde050c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1008 @@ +mk: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d/%m/%Y" + short: "%d %b" + long: "%d %B, %Y" + + day_names: [недела, понеделник, вторник, среда, четврток, петок, сабота] + abbr_day_names: [нед, пон, вто, сре, чет, пет, саб] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, јануари, февруари, март, април, мај, јуни, јули, август, септември, октомври, ноември, декември] + abbr_month_names: [~, јан, фев, мар, апр, мај, јун, јул, авг, сеп, окт, ное, дек] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d/%m/%Y %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "предпладне" + pm: "попладне" + + datetime: + distance_in_words: + half_a_minute: "пола минута" + less_than_x_seconds: + one: "помалку од 1 секунда" + other: "помалку од %{count} секунди" + x_seconds: + one: "1 секунда" + other: "%{count} секунди" + less_than_x_minutes: + one: "помалку од 1 минута" + other: "помалку од %{count} минути" + x_minutes: + one: "1 минута" + other: "%{count} минути" + about_x_hours: + one: "околу 1 час" + other: "околу %{count} часа" + x_days: + one: "1 ден" + other: "%{count} дена" + about_x_months: + one: "околу 1 месец" + other: "околу %{count} месеци" + x_months: + one: "1 месец" + other: "%{count} месеци" + about_x_years: + one: "околу 1 година" + other: "околу %{count} години" + over_x_years: + one: "преку 1 година" + other: "преку %{count} години" + almost_x_years: + one: "скоро 1 година" + other: "скоро %{count} години" + + number: + # Default format for numbers + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "и" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "не е вклучено во листата" + exclusion: "е резервирано" + invalid: "е невалидно" + confirmation: "не се совпаѓа со потврдата" + accepted: "мора да е прифатено" + empty: "неможе да е празно" + blank: "неможе да е празно" + too_long: "е предолго (макс. %{count} знаци)" + too_short: "е прекратко (мин. %{count} знаци)" + wrong_length: "е погрешна должина (треба да е %{count} знаци)" + taken: "е веќе зафатено" + not_a_number: "не е број" + not_a_date: "не е валидна дата" + greater_than: "мора да е поголемо од %{count}" + greater_than_or_equal_to: "мора да е поголемо или еднакво на %{count}" + equal_to: "мора да е еднакво на %{count}" + less_than: "мора да е помало од %{count}" + less_than_or_equal_to: "мора да е помало или еднакво на %{count}" + odd: "мора да е непарно" + even: "мора да е парно" + greater_than_start_date: "мора да е поголема од почетната дата" + not_same_project: "не припаѓа на истиот проект" + circular_dependency: "Оваа врска ќе креира кружна зависност" + cant_link_an_issue_with_a_descendant: "Задача неможе да се поврзе со една од нејзините подзадачи" + + actionview_instancetag_blank_option: Изберете + + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Macedonian (Македонски)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Профилот е успешно ажуриран. + notice_account_invalid_creditentials: Неточен корисник или лозинка + notice_account_password_updated: Лозинката е успешно ажурирана. + notice_account_wrong_password: Погрешна лозинка + notice_account_register_done: Профилот е успешно креиран. За активација, клкнете на врската што ви е пратена по е-пошта. + notice_account_unknown_email: Непознат корисник. + notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. + notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. + notice_account_activated: Your account has been activated. You can now log in. + notice_successful_create: Успешно креирање. + notice_successful_update: Успешно ажурирање. + notice_successful_delete: Успешно бришење. + notice_successful_connection: Успешна конекција. + notice_file_not_found: The page you were trying to access doesn't exist or has been removed. + notice_locking_conflict: Data has been updated by another user. + notice_not_authorized: You are not authorized to access this page. + notice_email_sent: "Е-порака е пратена на %{value}" + notice_email_error: "Се случи грешка при праќање на е-пораката (%{value})" + notice_feeds_access_key_reseted: Вашиот RSS клуч за пристап е reset. + notice_api_access_key_reseted: Вашиот API клуч за пристап е reset. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." + notice_account_pending: "Your account was created and is now pending administrator approval." + notice_default_data_loaded: Default configuration successfully loaded. + notice_unable_delete_version: Unable to delete version. + notice_unable_delete_time_entry: Unable to delete time log entry. + notice_issue_done_ratios_updated: Issue done ratios updated. + + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + error_scm_annotate: "The entry does not exist or can not be annotated." + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_delete_custom_field: Unable to delete custom field + error_can_not_delete_tracker: "This tracker contains issues and can't be deleted." + error_can_not_remove_role: "This role is in use and can not be deleted." + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version can not be reopened' + error_can_not_archive_project: This project can not be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + error_unable_delete_issue_status: 'Unable to delete issue status' + error_unable_to_connect: "Unable to connect (%{value})" + warning_attachments_not_saved: "%{count} file(s) could not be saved." + + mail_subject_lost_password: "Вашата %{value} лозинка" + mail_body_lost_password: 'To change your password, click on the following link:' + mail_subject_register: "Your %{value} account activation" + mail_body_register: 'To activate your account, click on the following link:' + mail_body_account_information_external: "You can use your %{value} account to log in." + mail_body_account_information: Your account information + mail_subject_account_activation_request: "%{value} account activation request" + mail_body_account_activation_request: "Нов корисник (%{value}) е регистриран. The account is pending your approval:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + gui_validation_error: 1 грешка + gui_validation_error_plural: "%{count} грешки" + + field_name: Име + field_description: Опис + field_summary: Краток опис + field_is_required: Задолжително + field_firstname: Име + field_lastname: Презиме + field_mail: Е-пошта + field_filename: Датотека + field_filesize: Големина + field_downloads: Превземања + field_author: Автор + field_created_on: Креиран + field_updated_on: Ажурирано + field_field_format: Формат + field_is_for_all: За сите проекти + field_possible_values: Можни вредности + field_regexp: Regular expression + field_min_length: Минимална должина + field_max_length: Максимална должина + field_value: Вредност + field_category: Категорија + field_title: Наслов + field_project: Проект + field_issue: Задача + field_status: Статус + field_notes: Белешки + field_is_closed: Задачата е затворена + field_is_default: Default value + field_tracker: Tracker + field_subject: Наслов + field_due_date: Краен рок + field_assigned_to: Доделена на + field_priority: Приоритет + field_fixed_version: Target version + field_user: Корисник + field_principal: Principal + field_role: Улога + field_homepage: Веб страна + field_is_public: Јавен + field_parent: Подпроект на + field_is_in_roadmap: Issues displayed in roadmap + field_login: Корисник + field_mail_notification: Известувања по e-пошта + field_admin: Администратор + field_last_login_on: Последна најава + field_language: Јазик + field_effective_date: Дата + field_password: Лозинка + field_new_password: Нова лозинка + field_password_confirmation: Потврда + field_version: Верзија + field_type: Тип + field_host: Хост + field_port: Порт + field_account: Account + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: Моментално (On-the-fly) креирање на корисници + field_start_date: Почеток + field_done_ratio: "% Завршено" + field_auth_source: Режим на автентикација + field_hide_mail: Криј ја мојата адреса на е-пошта + field_comments: Коментар + field_url: URL + field_start_page: Почетна страна + field_subproject: Подпроект + field_hours: Часови + field_activity: Активност + field_spent_on: Дата + field_identifier: Идентификатор + field_is_filter: Користи како филтер + field_issue_to: Поврзана задача + field_delay: Доцнење + field_assignable: На оваа улога може да се доделуваат задачи + field_redirect_existing_links: Пренасочи ги постоечките врски + field_estimated_hours: Проценето време + field_column_names: Колони + field_time_entries: Бележи време + field_time_zone: Временска зона + field_searchable: Може да се пребарува + field_default_value: Default value + field_comments_sorting: Прикажувај коментари + field_parent_title: Parent page + field_editable: Може да се уредува + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Содржина + field_group_by: Групирај ги резултатите според + field_sharing: Споделување + field_parent_issue: Parent task + + setting_app_title: Наслов на апликацијата + setting_app_subtitle: Поднаслов на апликацијата + setting_welcome_text: Текст за добредојде + setting_default_language: Default јазик + setting_login_required: Задолжителна автентикација + setting_self_registration: Само-регистрација + setting_attachment_max_size: Макс. големина на прилог + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Текстуални е-пораки (без HTML) + setting_host_name: Име на хост и патека + setting_text_formatting: Форматирање на текст + setting_wiki_compression: Компресија на историјата на вики + setting_feeds_limit: Feed content limit + setting_default_projects_public: Новите проекти се иницијално јавни + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Referencing keywords + setting_commit_fix_keywords: Fixing keywords + setting_autologin: Автоматска најава + setting_date_format: Формат на дата + setting_time_format: Формат на време + setting_cross_project_issue_relations: Дозволи релации на задачи меѓу проекти + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_emails_footer: Emails footer + setting_protocol: Протокол + setting_per_page_options: Objects per page options + setting_user_format: Приказ на корисниците + setting_activity_days_default: Денови прикажана во активноста на проектот + setting_display_subprojects_issues: Прикажи ги задачите на подпроектите во главните проекти + setting_enabled_scm: Овозможи SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API клуч + setting_sequential_project_identifiers: Генерирај последователни идентификатори на проекти + setting_gravatar_enabled: Користи Gravatar кориснички икони + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Max number of diff lines displayed + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Дозволи OpenID најава и регистрација + setting_password_min_length: Мин. должина на лозинка + setting_new_project_user_role_id: Улога доделена на неадминистраторски корисник кој креира проект + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + + permission_add_project: Креирај проекти + permission_add_subprojects: Креирај подпроекти + permission_edit_project: Уреди проект + permission_select_project_modules: Изберете модули за проект + permission_manage_members: Manage members + permission_manage_project_activities: Manage project activities + permission_manage_versions: Manage versions + permission_manage_categories: Manage issue categories + permission_view_issues: Прегледај задачи + permission_add_issues: Додавај задачи + permission_edit_issues: Уредувај задачи + permission_manage_issue_relations: Manage issue relations + permission_add_issue_notes: Додавај белешки + permission_edit_issue_notes: Уредувај белешки + permission_edit_own_issue_notes: Уредувај сопствени белешки + permission_move_issues: Преместувај задачи + permission_delete_issues: Бриши задачи + permission_manage_public_queries: Manage public queries + permission_save_queries: Save queries + permission_view_gantt: View gantt chart + permission_view_calendar: View calendar + permission_view_issue_watchers: View watchers list + permission_add_issue_watchers: Add watchers + permission_delete_issue_watchers: Delete watchers + permission_log_time: Бележи потрошено време + permission_view_time_entries: Прегледај потрошено време + permission_edit_time_entries: Уредувај белешки за потрошено време + permission_edit_own_time_entries: Уредувај сопствени белешки за потрошено време + permission_manage_news: Manage news + permission_comment_news: Коментирај на вести + permission_manage_documents: Manage documents + permission_view_documents: Прегледувај документи + permission_manage_files: Manage files + permission_view_files: Прегледувај датотеки + permission_manage_wiki: Manage wiki + permission_rename_wiki_pages: Преименувај вики страници + permission_delete_wiki_pages: Бриши вики страници + permission_view_wiki_pages: Прегледувај вики + permission_view_wiki_edits: Прегледувај вики историја + permission_edit_wiki_pages: Уредувај вики страници + permission_delete_wiki_pages_attachments: Бриши прилози + permission_protect_wiki_pages: Заштитувај вики страници + permission_manage_repository: Manage repository + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Commit access + permission_manage_boards: Manage boards + permission_view_messages: View messages + permission_add_messages: Post messages + permission_edit_messages: Уредувај пораки + permission_edit_own_messages: Уредувај сопствени пораки + permission_delete_messages: Бриши пораки + permission_delete_own_messages: Бриши сопствени пораки + permission_export_wiki_pages: Export wiki pages + permission_manage_subtasks: Manage subtasks + + project_module_issue_tracking: Следење на задачи + project_module_time_tracking: Следење на време + project_module_news: Вести + project_module_documents: Документи + project_module_files: Датотеки + project_module_wiki: Вики + project_module_repository: Repository + project_module_boards: Форуми + project_module_calendar: Календар + project_module_gantt: Gantt + + label_user: Корисник + label_user_plural: Корисници + label_user_new: Нов корисник + label_user_anonymous: Анонимен + label_project: Проект + label_project_new: Нов проект + label_project_plural: Проекти + label_x_projects: + zero: нема проекти + one: 1 проект + other: "%{count} проекти" + label_project_all: Сите проекти + label_project_latest: Последните проекти + label_issue: Задача + label_issue_new: Нова задача + label_issue_plural: Задачи + label_issue_view_all: Прегледај ги сите задачи + label_issues_by: "Задачи по %{value}" + label_issue_added: Задачата е додадена + label_issue_updated: Задачата е ажурирана + label_document: Документ + label_document_new: Нов документ + label_document_plural: Документи + label_document_added: Документот е додаден + label_role: Улога + label_role_plural: Улоги + label_role_new: Нова улога + label_role_and_permissions: Улоги и овластувања + label_member: Член + label_member_new: Нов член + label_member_plural: Членови + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: New tracker + label_workflow: Workflow + label_issue_status: Статус на задача + label_issue_status_plural: Статуси на задачи + label_issue_status_new: Нов статус + label_issue_category: Категорија на задача + label_issue_category_plural: Категории на задачи + label_issue_category_new: Нова категорија + label_custom_field: Прилагодено поле + label_custom_field_plural: Прилагодени полиња + label_custom_field_new: Ново прилагодено поле + label_enumerations: Enumerations + label_enumeration_new: Нова вредност + label_information: Информација + label_information_plural: Информации + label_please_login: Најави се + label_register: Регистрирај се + label_login_with_open_id_option: или најави се со OpenID + label_password_lost: Изгубена лозинка + label_home: Почетна + label_my_page: Мојата страна + label_my_account: Мојот профил + label_my_projects: Мои проекти + label_my_page_block: Блок елемент + label_administration: Администрација + label_login: Најави се + label_logout: Одјави се + label_help: Помош + label_reported_issues: Пријавени задачи + label_assigned_to_me_issues: Задачи доделени на мене + label_last_login: Последна најава + label_registered_on: Регистриран на + label_activity: Активност + label_overall_activity: Севкупна активност + label_user_activity: "Активност на %{value}" + label_new: Нова + label_logged_as: Најавени сте како + label_environment: Опкружување + label_authentication: Автентикација + label_auth_source: Режим на автентикација + label_auth_source_new: Нов режим на автентикација + label_auth_source_plural: Режими на автентикација + label_subproject_plural: Подпроекти + label_subproject_new: Нов подпроект + label_and_its_subprojects: "%{value} и неговите подпроекти" + label_min_max_length: Мин. - Макс. должина + label_list: Листа + label_date: Дата + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Текст + label_text: Долг текст + label_attribute: Атрибут + label_attribute_plural: Атрибути + label_download: "%{count} превземање" + label_download_plural: "%{count} превземања" + label_no_data: Нема податоци за прикажување + label_change_status: Промени статус + label_history: Историја + label_attachment: Датотека + label_attachment_new: Нова датотека + label_attachment_delete: Избриши датотека + label_attachment_plural: Датотеки + label_file_added: Датотеката е додадена + label_report: Извештај + label_report_plural: Извештаи + label_news: Новост + label_news_new: Додади новост + label_news_plural: Новости + label_news_latest: Последни новости + label_news_view_all: Прегледај ги сите новости + label_news_added: Новостта е додадена + label_settings: Settings + label_overview: Преглед + label_version: Верзија + label_version_new: Нова верзија + label_version_plural: Верзии + label_close_versions: Затвори ги завршените врзии + label_confirmation: Потврда + label_export_to: 'Достапно и во:' + label_read: Прочитај... + label_public_projects: Јавни проекти + label_open_issues: отворена + label_open_issues_plural: отворени + label_closed_issues: затворена + label_closed_issues_plural: затворени + label_x_open_issues_abbr_on_total: + zero: 0 отворени / %{total} + one: 1 отворена / %{total} + other: "%{count} отворени / %{total}" + label_x_open_issues_abbr: + zero: 0 отворени + one: 1 отворена + other: "%{count} отворени" + label_x_closed_issues_abbr: + zero: 0 затворени + one: 1 затворена + other: "%{count} затворени" + label_total: Вкупно + label_permissions: Овластувања + label_current_status: Моментален статус + label_new_statuses_allowed: Дозволени нови статуси + label_all: сите + label_none: ниеден + label_nobody: никој + label_next: Следно + label_previous: Претходно + label_used_by: Користено од + label_details: Детали + label_add_note: Додади белешка + label_per_page: По страна + label_calendar: Календар + label_months_from: месеци од + label_gantt: Gantt + label_internal: Internal + label_last_changes: "последни %{count} промени" + label_change_view_all: Прегледај ги сите промени + label_personalize_page: Прилагоди ја странава + label_comment: Коментар + label_comment_plural: Коментари + label_x_comments: + zero: нема коментари + one: 1 коментар + other: "%{count} коментари" + label_comment_add: Додади коментар + label_comment_added: Коментарот е додаден + label_comment_delete: Избриши коментари + label_query: Custom query + label_query_plural: Custom queries + label_query_new: New query + label_filter_add: Додади филтер + label_filter_plural: Филтри + label_equals: е + label_not_equals: не е + label_in_less_than: за помалку од + label_in_more_than: за повеќе од + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: во + label_today: денес + label_all_time: цело време + label_yesterday: вчера + label_this_week: оваа недела + label_last_week: минатата недела + label_last_n_days: "последните %{count} дена" + label_this_month: овој месец + label_last_month: минатиот месец + label_this_year: оваа година + label_date_range: Date range + label_less_than_ago: пред помалку од денови + label_more_than_ago: пред повеќе од денови + label_ago: пред денови + label_contains: содржи + label_not_contains: не содржи + label_day_plural: денови + label_repository: Складиште + label_repository_plural: Складишта + label_browse: Прелистувај + label_modification: "%{count} промени" + label_modification_plural: "%{count} промени" + label_branch: Гранка + label_tag: Tag + label_revision: Ревизија + label_revision_plural: Ревизии + label_revision_id: "Ревизија %{value}" + label_associated_revisions: Associated revisions + label_added: added + label_modified: modified + label_copied: copied + label_renamed: renamed + label_deleted: deleted + label_latest_revision: Последна ревизија + label_latest_revision_plural: Последни ревизии + label_view_revisions: Прегледај ги ревизиите + label_view_all_revisions: Прегледај ги сите ревизии + label_max_size: Макс. големина + label_sort_highest: Премести најгоре + label_sort_higher: Премести нагоре + label_sort_lower: Премести надоле + label_sort_lowest: Премести најдоле + label_roadmap: Roadmap + label_roadmap_due_in: "Due in %{value}" + label_roadmap_overdue: "Касни %{value}" + label_roadmap_no_issues: Нема задачи за оваа верзија + label_search: Барај + label_result_plural: Резултати + label_all_words: Сите зборови + label_wiki: Вики + label_wiki_edit: Вики уредување + label_wiki_edit_plural: Вики уредувања + label_wiki_page: Вики страница + label_wiki_page_plural: Вики страници + label_index_by_title: Индекс по наслов + label_index_by_date: Индекс по дата + label_current_version: Current version + label_preview: Preview + label_feed_plural: Feeds + label_changes_details: Детали за сите промени + label_issue_tracking: Следење на задачи + label_spent_time: Потрошено време + label_overall_spent_time: Вкупно потрошено време + label_f_hour: "%{value} час" + label_f_hour_plural: "%{value} часа" + label_time_tracking: Следење на време + label_change_plural: Промени + label_statistics: Статистики + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_view_diff: View differences + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Опции + label_copy_workflow_from: Copy workflow from + label_permissions_report: Permissions report + label_watched_issues: Watched issues + label_related_issues: Поврзани задачи + label_applied_status: Applied status + label_loading: Loading... + label_relation_new: Нова релација + label_relation_delete: Избриши релација + label_relates_to: related to + label_duplicates: дупликати + label_duplicated_by: duplicated by + label_blocks: blocks + label_blocked_by: блокирано од + label_precedes: претходи + label_follows: следи + label_end_to_start: крај до почеток + label_end_to_end: крај до крај + label_start_to_start: почеток до почеток + label_start_to_end: почеток до крај + label_stay_logged_in: Останете најавени + label_disabled: disabled + label_show_completed_versions: Show completed versions + label_me: јас + label_board: Форум + label_board_new: Нов форум + label_board_plural: Форуми + label_board_locked: Заклучен + label_board_sticky: Sticky + label_topic_plural: Теми + label_message_plural: Пораки + label_message_last: Последна порака + label_message_new: Нова порака + label_message_posted: Поракате е додадена + label_reply_plural: Одговори + label_send_information: Испрати ги информациите за профилот на корисникот + label_year: Година + label_month: Месец + label_week: Недела + label_date_from: Од + label_date_to: До + label_language_based: Според јазикот на корисникот + label_sort_by: "Подреди според %{value}" + label_send_test_email: Испрати тест е-порака + label_feeds_access_key: RSS клуч за пристап + label_missing_feeds_access_key: Недостика RSS клуч за пристап + label_feeds_access_key_created_on: "RSS клучот за пристап креиран пред %{value}" + label_module_plural: Модули + label_added_time_by: "Додадено од %{author} пред %{age}" + label_updated_time_by: "Ажурирано од %{author} пред %{age}" + label_updated_time: "Ажурирано пред %{value}" + label_jump_to_a_project: Префрли се на проект... + label_file_plural: Датотеки + label_changeset_plural: Changesets + label_default_columns: Основни колони + label_no_change_option: (Без промена) + label_bulk_edit_selected_issues: Групно уредување на задачи + label_theme: Тема + label_default: Default + label_search_titles_only: Пребарувај само наслови + label_user_mail_option_all: "За било кој настан во сите мои проекти" + label_user_mail_option_selected: "За било кој настан само во избраните проекти..." + label_user_mail_no_self_notified: "Не ме известувај за промените што јас ги правам" + label_registration_activation_by_email: активација на профил преку е-пошта + label_registration_manual_activation: мануелна активација на профил + label_registration_automatic_activation: автоматска активација на профил + label_display_per_page: "По страна: %{value}" + label_age: Age + label_change_properties: Change properties + label_general: Општо + label_more: Повеќе + label_scm: SCM + label_plugins: Додатоци + label_ldap_authentication: LDAP автентикација + label_downloads_abbr: Превземања + label_optional_description: Опис (незадолжително) + label_add_another_file: Додади уште една датотека + label_preferences: Preferences + label_chronological_order: Во хронолошки ред + label_reverse_chronological_order: In reverse chronological order + label_planning: Планирање + label_incoming_emails: Дојдовни е-пораки + label_generate_key: Генерирај клуч + label_issue_watchers: Watchers + label_example: Пример + label_display: Прикажи + label_sort: Подреди + label_ascending: Растечки + label_descending: Опаѓачки + label_date_from_to: Од %{start} до %{end} + label_wiki_content_added: Вики страница додадена + label_wiki_content_updated: Вики страница ажурирана + label_group: Група + label_group_plural: Групи + label_group_new: Нова група + label_time_entry_plural: Потрошено време + label_version_sharing_none: Не споделено + label_version_sharing_descendants: Со сите подпроекти + label_version_sharing_hierarchy: Со хиерархијата на проектот + label_version_sharing_tree: Со дрвото на проектот + label_version_sharing_system: Со сите проекти + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Извор + label_copy_target: Дестинација + label_copy_same_as_target: Исто како дестинацијата + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API клуч за пристап + label_missing_api_access_key: Недостига API клуч за пристап + label_api_access_key_created_on: "API клучот за пристап е креиран пред %{value}" + label_profile: Профил + label_subtask_plural: Подзадачи + label_project_copy_notifications: Праќај известувања по е-пошта при копирање на проект + + button_login: Најави се + button_submit: Испрати + button_save: Зачувај + button_check_all: Штиклирај ги сите + button_uncheck_all: Одштиклирај ги сите + button_delete: Избриши + button_create: Креирај + button_create_and_continue: Креирај и продолжи + button_test: Тест + button_edit: Уреди + button_add: Додади + button_change: Промени + button_apply: Примени + button_clear: Избриши + button_lock: Заклучи + button_unlock: Отклучи + button_download: Превземи + button_list: List + button_view: Прегледај + button_move: Премести + button_move_and_follow: Премести и следи + button_back: Back + button_cancel: Откажи + button_activate: Активирај + button_sort: Подреди + button_log_time: Бележи време + button_rollback: Rollback to this version + button_watch: Следи + button_unwatch: Не следи + button_reply: Одговори + button_archive: Архивирај + button_unarchive: Одархивирај + button_reset: Reset + button_rename: Преименувај + button_change_password: Промени лозинка + button_copy: Копирај + button_copy_and_follow: Копирај и следи + button_annotate: Annotate + button_update: Ажурирај + button_configure: Конфигурирај + button_quote: Цитирај + button_duplicate: Копирај + button_show: Show + + status_active: активни + status_registered: регистрирани + status_locked: заклучени + + version_status_open: отворени + version_status_locked: заклучени + version_status_closed: затворени + + field_active: Active + + text_select_mail_notifications: Изберете за кои настани да се праќаат известувања по е-пошта да се праќаат. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 значи без ограничување + text_project_destroy_confirmation: Дали сте сигурни дека сакате да го избришете проектот и сите поврзани податоци? + text_subprojects_destroy_warning: "Неговите подпроекти: %{value} исто така ќе бидат избришани." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Дали сте сигурни? + text_journal_changed: "%{label} променето од %{old} во %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} избришан (%{old})" + text_journal_added: "%{label} %{value} додаден" + text_tip_issue_begin_day: задачи што почнуваат овој ден + text_tip_issue_end_day: задачи што завршуваат овој ден + text_tip_issue_begin_end_day: задачи што почнуваат и завршуваат овој ден + text_project_identifier_info: 'Само мали букви (a-z), бројки и dashes се дозволени
По зачувувањето, идентификаторот неможе да се смени.' + text_caracters_maximum: "%{count} знаци максимум." + text_caracters_minimum: "Мора да е најмалку %{count} знаци долго." + text_length_between: "Должина помеѓу %{min} и %{max} знаци." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Недозволени знаци + text_comma_separated: Дозволени се повеќе вредности (разделени со запирка). + text_line_separated: Дозволени се повеќе вредности (една линија за секоја вредност). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Задачата %{id} е пријавена од %{author}." + text_issue_updated: "Задачата %{id} е ажурирана од %{author}." + text_wiki_destroy_confirmation: Дали сте сигурни дека сакате да го избришете ова вики и целата негова содржина? + text_issue_category_destroy_question: "Некои задачи (%{count}) се доделени на оваа категорија. Што сакате да правите?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Додели ги задачите на оваа категорија + text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Дали сте сигурни дека сакате да ги избришете избраните задачи?' + text_select_project_modules: 'Изберете модули за овој проект:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Во папката за прилози може да се запишува + text_plugin_assets_writable: Во папката за додатоци може да се запишува + text_rmagick_available: RMagick available (незадолжително) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do ?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Додели ги пријавените часови на проектот + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} напиша:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Доставата по е-пошта не е конфигурирана, и известувањата се оневозможени.\nКонфигурирајте го Вашиот SMTP сервер во config/configuration.yml и рестартирајте ја апликацијата." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + + default_role_manager: Менаџер + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Поддршка + default_issue_status_new: Нова + default_issue_status_in_progress: Во прогрес + default_issue_status_resolved: Разрешена + default_issue_status_feedback: Feedback + default_issue_status_closed: Затворена + default_issue_status_rejected: Одбиена + default_doc_category_user: Корисничка документација + default_doc_category_tech: Техничка документација + default_priority_low: Низок + default_priority_normal: Нормален + default_priority_high: Висок + default_priority_urgent: Итно + default_priority_immediate: Веднаш + default_activity_design: Дизајн + default_activity_development: Развој + + enumeration_issue_priorities: Приоритети на задача + enumeration_doc_categories: Категории на документ + enumeration_activities: Активности (следење на време) + enumeration_system_activity: Системска активност + + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/519546b54485a90980ee98464e417cc62979df94.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/519546b54485a90980ee98464e417cc62979df94.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +module CodeRay + module Scanners + + # Scanner for plain text. + # + # Yields just one token of the kind :plain. + # + # Alias: +plaintext+, +plain+ + class Text < Scanner + + register_for :text + title 'Plain text' + + KINDS_NOT_LOC = [:plain] # :nodoc: + + protected + + def scan_tokens encoder, options + encoder.text_token string, :plain + encoder + end + + end + + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/51b0f06b906ad6629342cb0764451031456c212f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/51b0f06b906ad6629342cb0764451031456c212f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +<%= l(:notice_account_activated) %> +<%= l(:label_login) %>: <%= @login_url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/51b919386182e47c3ef0ca6e2a6f8f116db68244.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/51b919386182e47c3ef0ca6e2a6f8f116db68244.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class Thing + def self.from_plugin; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/51be1ed9a6fd0f544bf7334bc87d5f8e3ed5bf74.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/51be1ed9a6fd0f544bf7334bc87d5f8e3ed5bf74.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class CalendarsController < ApplicationController + menu_item :calendar + before_filter :find_optional_project + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :issues + helper :projects + helper :queries + include QueriesHelper + helper :sort + include SortHelper + + def show + if params[:year] and params[:year].to_i > 1900 + @year = params[:year].to_i + if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 + @month = params[:month].to_i + end + end + @year ||= Date.today.year + @month ||= Date.today.month + + @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) + retrieve_query + @query.group_by = nil + if @query.valid? + events = [] + events += @query.issues(:include => [:tracker, :assigned_to, :priority], + :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] + ) + events += @query.versions(:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) + + @calendar.events = events + end + + render :action => 'show', :layout => false if request.xhr? + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/51/51f64479905fa6ebe754a8ef36329d97b292d2ad.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/51/51f64479905fa6ebe754a8ef36329d97b292d2ad.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,793 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class QueryColumn + attr_accessor :name, :sortable, :groupable, :default_order + include Redmine::I18n + + def initialize(name, options={}) + self.name = name + self.sortable = options[:sortable] + self.groupable = options[:groupable] || false + if groupable == true + self.groupable = name.to_s + end + self.default_order = options[:default_order] + @caption_key = options[:caption] || "field_#{name}" + end + + def caption + l(@caption_key) + end + + # Returns true if the column is sortable, otherwise false + def sortable? + !@sortable.nil? + end + + def sortable + @sortable.is_a?(Proc) ? @sortable.call : @sortable + end + + def value(issue) + issue.send name + end + + def css_classes + name + end +end + +class QueryCustomFieldColumn < QueryColumn + + def initialize(custom_field) + self.name = "cf_#{custom_field.id}".to_sym + self.sortable = custom_field.order_statement || false + if %w(list date bool int).include?(custom_field.field_format) + self.groupable = custom_field.order_statement + end + self.groupable ||= false + @cf = custom_field + end + + def caption + @cf.name + end + + def custom_field + @cf + end + + def value(issue) + cv = issue.custom_values.detect {|v| v.custom_field_id == @cf.id} + cv && @cf.cast_value(cv.value) + end + + def css_classes + @css_classes ||= "#{name} #{@cf.field_format}" + end +end + +class Query < ActiveRecord::Base + class StatementInvalid < ::ActiveRecord::StatementInvalid + end + + belongs_to :project + belongs_to :user + serialize :filters + serialize :column_names + serialize :sort_criteria, Array + + attr_protected :project_id, :user_id + + validates_presence_of :name, :on => :save + validates_length_of :name, :maximum => 255 + validate :validate_query_filters + + @@operators = { "=" => :label_equals, + "!" => :label_not_equals, + "o" => :label_open_issues, + "c" => :label_closed_issues, + "!*" => :label_none, + "*" => :label_all, + ">=" => :label_greater_or_equal, + "<=" => :label_less_or_equal, + "><" => :label_between, + " :label_in_less_than, + ">t+" => :label_in_more_than, + "t+" => :label_in, + "t" => :label_today, + "w" => :label_this_week, + ">t-" => :label_less_than_ago, + " :label_more_than_ago, + "t-" => :label_ago, + "~" => :label_contains, + "!~" => :label_not_contains } + + cattr_reader :operators + + @@operators_by_filter_type = { :list => [ "=", "!" ], + :list_status => [ "o", "=", "!", "c", "*" ], + :list_optional => [ "=", "!", "!*", "*" ], + :list_subprojects => [ "*", "!*", "=" ], + :date => [ "=", ">=", "<=", "><", "t+", "t+", "t", "w", ">t-", " [ "=", ">=", "<=", "><", ">t-", " [ "=", "~", "!", "!~" ], + :text => [ "~", "!~" ], + :integer => [ "=", ">=", "<=", "><", "!*", "*" ], + :float => [ "=", ">=", "<=", "><", "!*", "*" ] } + + cattr_reader :operators_by_filter_type + + @@available_columns = [ + QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), + QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true), + QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue), + QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true), + QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true), + QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), + QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true), + QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), + QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), + QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true), + QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc', :groupable => true), + QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"), + QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"), + QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"), + QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), + QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), + ] + cattr_reader :available_columns + + named_scope :visible, lambda {|*args| + user = args.shift || User.current + base = Project.allowed_to_condition(user, :view_issues, *args) + user_id = user.logged? ? user.id : 0 + { + :conditions => ["(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id], + :include => :project + } + } + + def initialize(attributes = nil) + super attributes + self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } + end + + def after_initialize + # Store the fact that project is nil (used in #editable_by?) + @is_for_all = project.nil? + end + + def validate_query_filters + filters.each_key do |field| + if values_for(field) + case type_for(field) + when :integer + errors.add(label_for(field), :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) } + when :float + errors.add(label_for(field), :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+(\.\d*)?$/) } + when :date, :date_past + case operator_for(field) + when "=", ">=", "<=", "><" + errors.add(label_for(field), :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) } + when ">t-", " 'position') : project.rolled_up_trackers + + @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } }, + "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } }, + "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } }, + "subject" => { :type => :text, :order => 8 }, + "created_on" => { :type => :date_past, :order => 9 }, + "updated_on" => { :type => :date_past, :order => 10 }, + "start_date" => { :type => :date, :order => 11 }, + "due_date" => { :type => :date, :order => 12 }, + "estimated_hours" => { :type => :float, :order => 13 }, + "done_ratio" => { :type => :integer, :order => 14 }} + + principals = [] + if project + principals += project.principals.sort + else + all_projects = Project.visible.all + if all_projects.any? + # members of visible projects + principals += Principal.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", all_projects.collect(&:id)]).sort + + # project filter + project_values = [] + Project.project_tree(all_projects) do |p, level| + prefix = (level > 0 ? ('--' * level + ' ') : '') + project_values << ["#{prefix}#{p.name}", p.id.to_s] + end + @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} unless project_values.empty? + end + end + users = principals.select {|p| p.is_a?(User)} + + assigned_to_values = [] + assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] } + @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => assigned_to_values } unless assigned_to_values.empty? + + author_values = [] + author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + author_values += users.collect{|s| [s.name, s.id.to_s] } + @available_filters["author_id"] = { :type => :list, :order => 5, :values => author_values } unless author_values.empty? + + group_values = Group.all.collect {|g| [g.name, g.id.to_s] } + @available_filters["member_of_group"] = { :type => :list_optional, :order => 6, :values => group_values } unless group_values.empty? + + role_values = Role.givable.collect {|r| [r.name, r.id.to_s] } + @available_filters["assigned_to_role"] = { :type => :list_optional, :order => 7, :values => role_values } unless role_values.empty? + + if User.current.logged? + @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] } + end + + if project + # project specific filters + categories = project.issue_categories.all + unless categories.empty? + @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => categories.collect{|s| [s.name, s.id.to_s] } } + end + versions = project.shared_versions.all + unless versions.empty? + @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } + end + unless project.leaf? + subprojects = project.descendants.visible.all + unless subprojects.empty? + @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => subprojects.collect{|s| [s.name, s.id.to_s] } } + end + end + add_custom_fields_filters(project.all_issue_custom_fields) + else + # global filters for cross project issue list + system_shared_versions = Version.visible.find_all_by_sharing('system') + unless system_shared_versions.empty? + @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } + end + add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) + end + @available_filters + end + + def add_filter(field, operator, values) + # values must be an array + return unless values.nil? || values.is_a?(Array) + # check if field is defined as an available filter + if available_filters.has_key? field + filter_options = available_filters[field] + # check if operator is allowed for that filter + #if @@operators_by_filter_type[filter_options[:type]].include? operator + # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]}) + # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator + #end + filters[field] = {:operator => operator, :values => (values || [''])} + end + end + + def add_short_filter(field, expression) + return unless expression && available_filters.has_key?(field) + field_type = available_filters[field][:type] + @@operators_by_filter_type[field_type].sort.reverse.detect do |operator| + next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ + add_filter field, operator, $1.present? ? $1.split('|') : [''] + end || add_filter(field, '=', expression.split('|')) + end + + # Add multiple filters using +add_filter+ + def add_filters(fields, operators, values) + if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash)) + fields.each do |field| + add_filter(field, operators[field], values && values[field]) + end + end + end + + def has_filter?(field) + filters and filters[field] + end + + def type_for(field) + available_filters[field][:type] if available_filters.has_key?(field) + end + + def operator_for(field) + has_filter?(field) ? filters[field][:operator] : nil + end + + def values_for(field) + has_filter?(field) ? filters[field][:values] : nil + end + + def value_for(field, index=0) + (values_for(field) || [])[index] + end + + def label_for(field) + label = available_filters[field][:name] if available_filters.has_key?(field) + label ||= field.gsub(/\_id$/, "") + end + + def available_columns + return @available_columns if @available_columns + @available_columns = ::Query.available_columns + @available_columns += (project ? + project.all_issue_custom_fields : + IssueCustomField.find(:all) + ).collect {|cf| QueryCustomFieldColumn.new(cf) } + end + + def self.available_columns=(v) + self.available_columns = (v) + end + + def self.add_available_column(column) + self.available_columns << (column) if column.is_a?(QueryColumn) + end + + # Returns an array of columns that can be used to group the results + def groupable_columns + available_columns.select {|c| c.groupable} + end + + # Returns a Hash of columns and the key for sorting + def sortable_columns + {'id' => "#{Issue.table_name}.id"}.merge(available_columns.inject({}) {|h, column| + h[column.name.to_s] = column.sortable + h + }) + end + + def columns + # preserve the column_names order + (has_default_columns? ? default_columns_names : column_names).collect do |name| + available_columns.find { |col| col.name == name } + end.compact + end + + def default_columns_names + @default_columns_names ||= begin + default_columns = Setting.issue_list_default_columns.map(&:to_sym) + + project.present? ? default_columns : [:project] | default_columns + end + end + + def column_names=(names) + if names + names = names.select {|n| n.is_a?(Symbol) || !n.blank? } + names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym } + # Set column_names to nil if default columns + if names == default_columns_names + names = nil + end + end + write_attribute(:column_names, names) + end + + def has_column?(column) + column_names && column_names.include?(column.name) + end + + def has_default_columns? + column_names.nil? || column_names.empty? + end + + def sort_criteria=(arg) + c = [] + if arg.is_a?(Hash) + arg = arg.keys.sort.collect {|k| arg[k]} + end + c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']} + write_attribute(:sort_criteria, c) + end + + def sort_criteria + read_attribute(:sort_criteria) || [] + end + + def sort_criteria_key(arg) + sort_criteria && sort_criteria[arg] && sort_criteria[arg].first + end + + def sort_criteria_order(arg) + sort_criteria && sort_criteria[arg] && sort_criteria[arg].last + end + + # Returns the SQL sort order that should be prepended for grouping + def group_by_sort_order + if grouped? && (column = group_by_column) + column.sortable.is_a?(Array) ? + column.sortable.collect {|s| "#{s} #{column.default_order}"}.join(',') : + "#{column.sortable} #{column.default_order}" + end + end + + # Returns true if the query is a grouped query + def grouped? + !group_by_column.nil? + end + + def group_by_column + groupable_columns.detect {|c| c.groupable && c.name.to_s == group_by} + end + + def group_by_statement + group_by_column.try(:groupable) + end + + def project_statement + project_clauses = [] + if project && !project.descendants.active.empty? + ids = [project.id] + if has_filter?("subproject_id") + case operator_for("subproject_id") + when '=' + # include the selected subprojects + ids += values_for("subproject_id").each(&:to_i) + when '!*' + # main project only + else + # all subprojects + ids += project.descendants.collect(&:id) + end + elsif Setting.display_subprojects_issues? + ids += project.descendants.collect(&:id) + end + project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') + elsif project + project_clauses << "#{Project.table_name}.id = %d" % project.id + end + project_clauses.any? ? project_clauses.join(' AND ') : nil + end + + def statement + # filters clauses + filters_clauses = [] + filters.each_key do |field| + next if field == "subproject_id" + v = values_for(field).clone + next unless v and !v.empty? + operator = operator_for(field) + + # "me" value subsitution + if %w(assigned_to_id author_id watcher_id).include?(field) + if v.delete("me") + if User.current.logged? + v.push(User.current.id.to_s) + v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id' + else + v.push("0") + end + end + end + + if field =~ /^cf_(\d+)$/ + # custom field + filters_clauses << sql_for_custom_field(field, operator, v, $1) + elsif respond_to?("sql_for_#{field}_field") + # specific statement + filters_clauses << send("sql_for_#{field}_field", field, operator, v) + else + # regular field + filters_clauses << '(' + sql_for_field(field, operator, v, Issue.table_name, field) + ')' + end + end if filters and valid? + + filters_clauses << project_statement + filters_clauses.reject!(&:blank?) + + filters_clauses.any? ? filters_clauses.join(' AND ') : nil + end + + # Returns the issue count + def issue_count + Issue.visible.count(:include => [:status, :project], :conditions => statement) + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the issue count by group or nil if query is not grouped + def issue_count_by_group + r = nil + if grouped? + begin + # Rails will raise an (unexpected) RecordNotFound if there's only a nil group value + r = Issue.visible.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement) + rescue ActiveRecord::RecordNotFound + r = {nil => issue_count} + end + c = group_by_column + if c.is_a?(QueryCustomFieldColumn) + r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h} + end + end + r + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the issues + # Valid options are :order, :offset, :limit, :include, :conditions + def issues(options={}) + order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') + order_option = nil if order_option.blank? + + joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil + + Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, + :conditions => statement, + :order => order_option, + :joins => joins, + :limit => options[:limit], + :offset => options[:offset] + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the journals + # Valid options are :order, :offset, :limit + def journals(options={}) + Journal.visible.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}], + :conditions => statement, + :order => options[:order], + :limit => options[:limit], + :offset => options[:offset] + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the versions + # Valid options are :conditions + def versions(options={}) + Version.visible.scoped(:conditions => options[:conditions]).find :all, :include => :project, :conditions => project_statement + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + def sql_for_watcher_id_field(field, operator, value) + db_table = Watcher.table_name + "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " + + sql_for_field(field, '=', value, db_table, 'user_id') + ')' + end + + def sql_for_member_of_group_field(field, operator, value) + if operator == '*' # Any group + groups = Group.all + operator = '=' # Override the operator since we want to find by assigned_to + elsif operator == "!*" + groups = Group.all + operator = '!' # Override the operator since we want to find by assigned_to + else + groups = Group.find_all_by_id(value) + end + groups ||= [] + + members_of_groups = groups.inject([]) {|user_ids, group| + if group && group.user_ids.present? + user_ids << group.user_ids + end + user_ids.flatten.uniq.compact + }.sort.collect(&:to_s) + + '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')' + end + + def sql_for_assigned_to_role_field(field, operator, value) + case operator + when "*", "!*" # Member / Not member + sw = operator == "!*" ? 'NOT' : '' + nl = operator == "!*" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' + "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}" + + " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))" + when "=", "!" + role_cond = value.any? ? + "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" : + "1=0" + + sw = operator == "!" ? 'NOT' : '' + nl = operator == "!" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' + "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}, #{MemberRole.table_name}" + + " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id AND #{Member.table_name}.id = #{MemberRole.table_name}.member_id AND #{role_cond}))" + end + end + + private + + def sql_for_custom_field(field, operator, value, custom_field_id) + db_table = CustomValue.table_name + db_field = 'value' + "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " + + sql_for_field(field, operator, value, db_table, db_field, true) + ')' + end + + # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+ + def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false) + sql = '' + case operator + when "=" + if value.any? + case type_for(field) + when :date, :date_past + sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil)) + when :integer + sql = "#{db_table}.#{db_field} = #{value.first.to_i}" + when :float + sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}" + else + sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" + end + else + # IN an empty set + sql = "1=0" + end + when "!" + if value.any? + sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))" + else + # NOT IN an empty set + sql = "1=1" + end + when "!*" + sql = "#{db_table}.#{db_field} IS NULL" + sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter + when "*" + sql = "#{db_table}.#{db_field} IS NOT NULL" + sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter + when ">=" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil) + else + if is_custom_filter + sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_f}" + else + sql = "#{db_table}.#{db_field} >= #{value.first.to_f}" + end + end + when "<=" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil)) + else + if is_custom_filter + sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_f}" + else + sql = "#{db_table}.#{db_field} <= #{value.first.to_f}" + end + end + when "><" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil)) + else + if is_custom_filter + sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f}" + else + sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}" + end + end + when "o" + sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id" + when "c" + sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id" + when ">t-" + sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0) + when "t+" + sql = relative_date_clause(db_table, db_field, value.first.to_i, nil) + when "= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) + sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) + when "~" + sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" + when "!~" + sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" + else + raise "Unknown query operator #{operator}" + end + + return sql + end + + def add_custom_fields_filters(custom_fields) + @available_filters ||= {} + + custom_fields.select(&:is_filter?).each do |field| + case field.field_format + when "text" + options = { :type => :text, :order => 20 } + when "list" + options = { :type => :list_optional, :values => field.possible_values, :order => 20} + when "date" + options = { :type => :date, :order => 20 } + when "bool" + options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 } + when "int" + options = { :type => :integer, :order => 20 } + when "float" + options = { :type => :float, :order => 20 } + when "user", "version" + next unless project + options = { :type => :list_optional, :values => field.possible_values_options(project), :order => 20} + else + options = { :type => :string, :order => 20 } + end + @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name }) + end + end + + # Returns a SQL clause for a date or datetime field. + def date_clause(table, field, from, to) + s = [] + if from + from_yesterday = from - 1 + from_yesterday_utc = Time.gm(from_yesterday.year, from_yesterday.month, from_yesterday.day) + s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_utc.end_of_day)]) + end + if to + to_utc = Time.gm(to.year, to.month, to.day) + s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_utc.end_of_day)]) + end + s.join(' AND ') + end + + # Returns a SQL clause for a date or datetime field using relative dates. + def relative_date_clause(table, field, days_from, days_to) + date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/52004253c47464e971de8985c2ff7d4abac9aadd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/52004253c47464e971de8985c2ff7d4abac9aadd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,60 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'net/imap' + +module Redmine + module IMAP + class << self + def check(imap_options={}, options={}) + host = imap_options[:host] || '127.0.0.1' + port = imap_options[:port] || '143' + ssl = !imap_options[:ssl].nil? + folder = imap_options[:folder] || 'INBOX' + + imap = Net::IMAP.new(host, port, ssl) + imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil? + imap.select(folder) + imap.search(['NOT', 'SEEN']).each do |message_id| + msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822'] + logger.debug "Receiving message #{message_id}" if logger && logger.debug? + if MailHandler.receive(msg, options) + logger.debug "Message #{message_id} successfully received" if logger && logger.debug? + if imap_options[:move_on_success] + imap.copy(message_id, imap_options[:move_on_success]) + end + imap.store(message_id, "+FLAGS", [:Seen, :Deleted]) + else + logger.debug "Message #{message_id} can not be processed" if logger && logger.debug? + imap.store(message_id, "+FLAGS", [:Seen]) + if imap_options[:move_on_failure] + imap.copy(message_id, imap_options[:move_on_failure]) + imap.store(message_id, "+FLAGS", [:Deleted]) + end + end + end + imap.expunge + end + + private + + def logger + RAILS_DEFAULT_LOGGER + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/5207c75436c85ec591b380afe15450272eeedb94.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/5207c75436c85ec591b380afe15450272eeedb94.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,81 @@ +module CodeRay + + # = Duo + # + # A Duo is a convenient way to use CodeRay. You just create a Duo, + # giving it a lang (language of the input code) and a format (desired + # output format), and call Duo#highlight with the code. + # + # Duo makes it easy to re-use both scanner and encoder for a repetitive + # task. It also provides a very easy interface syntax: + # + # require 'coderay' + # CodeRay::Duo[:python, :div].highlight 'import this' + # + # Until you want to do uncommon things with CodeRay, I recommend to use + # this method, since it takes care of everything. + class Duo + + attr_accessor :lang, :format, :options + + # Create a new Duo, holding a lang and a format to highlight code. + # + # simple: + # CodeRay::Duo[:ruby, :html].highlight 'bla 42' + # + # with options: + # CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??' + # + # alternative syntax without options: + # CodeRay::Duo[:ruby => :statistic].encode 'class << self; end' + # + # alternative syntax with options: + # CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc' + # + # The options are forwarded to scanner and encoder + # (see CodeRay.get_scanner_options). + def initialize lang = nil, format = nil, options = {} + if format.nil? && lang.is_a?(Hash) && lang.size == 1 + @lang = lang.keys.first + @format = lang[@lang] + else + @lang = lang + @format = format + end + @options = options + end + + class << self + # To allow calls like Duo[:ruby, :html].highlight. + alias [] new + end + + # The scanner of the duo. Only created once. + def scanner + @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options) + end + + # The encoder of the duo. Only created once. + def encoder + @encoder ||= CodeRay.encoder @format, @options + end + + # Tokenize and highlight the code using +scanner+ and +encoder+. + def encode code, options = {} + options = @options.merge options + encoder.encode(code, @lang, options) + end + alias highlight encode + + # Allows to use Duo like a proc object: + # + # CodeRay::Duo[:python => :yaml].call(code) + # + # or, in Ruby 1.9 and later: + # + # CodeRay::Duo[:python => :yaml].(code) + alias call encode + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/520b379788e40ebe77f4044b9785418c4b20c19c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/520b379788e40ebe77f4044b9785418c4b20c19c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Translater: Mads N. Vestergaard +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Søndag", + "Mandag", + "Tirsdag", + "Onsdag", + "Torsdag", + "Fredag", + "Lørdag", + "Søndag"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Søn", + "Man", + "Tir", + "Ons", + "Tor", + "Fre", + "Lør", + "Søn"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Marts", + "April", + "Maj", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Maj", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Om denne kalender"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For seneste version, besøg: http://www.dynarch.com/projects/calendar/\n" + +"Distribueret under GNU LGPL. Se http://gnu.org/licenses/lgpl.html for detaljer." + +"\n\n" + +"Dato valg:\n" + +"- Benyt \xab, \xbb tasterne til at vælge år\n" + +"- Benyt " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " tasterne til at vælge måned\n" + +"- Hold musetasten inde på punkterne for at vælge hurtigere."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Tids valg:\n" + +"- Klik på en af tidsrammerne for at forhøje det\n" + +"- eller Shift-klik for at mindske det\n" + +"- eller klik og træk for hurtigere valg."; + +Calendar._TT["PREV_YEAR"] = "Forrige år (hold for menu)"; +Calendar._TT["PREV_MONTH"] = "Forrige måned (hold for menu)"; +Calendar._TT["GO_TODAY"] = "Gå til dags dato"; +Calendar._TT["NEXT_MONTH"] = "Næste måned (hold for menu)"; +Calendar._TT["NEXT_YEAR"] = "Næste år (hold for menu)"; +Calendar._TT["SEL_DATE"] = "Vælg dato"; +Calendar._TT["DRAG_TO_MOVE"] = "Træk for at flytte"; +Calendar._TT["PART_TODAY"] = " (dags dato)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Vis %s først"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "6,7"; + +Calendar._TT["CLOSE"] = "Luk"; +Calendar._TT["TODAY"] = "I dag"; +Calendar._TT["TIME_PART"] = "(Shift-)Klik eller træk for at ændre værdi"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "uge"; +Calendar._TT["TIME"] = "Tid:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/5239875e2f66506ef4227a2d0ff1c43dcfbd22ad.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/5239875e2f66506ef4227a2d0ff1c43dcfbd22ad.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,121 @@ +
    + <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %> + +<% if !@issue.nil? -%> +
  • <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
  • +<% else %> +
  • <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
  • +<% end %> + + <% if @allowed_statuses.present? %> +
  • + <%= l(:field_status) %> +
      + <% @statuses.each do |s| -%> +
    • <%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post, + :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %>
    • + <% end -%> +
    +
  • + <% end %> + + <% unless @trackers.nil? %> +
  • + <%= l(:field_tracker) %> +
      + <% @trackers.each do |t| -%> +
    • <%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post, + :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %>
    • + <% end -%> +
    +
  • + <% end %> + +
  • + <%= l(:field_priority) %> +
      + <% @priorities.each do |p| -%> +
    • <%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post, + :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
    • + <% end -%> +
    +
  • + + <% #TODO: allow editing versions when multiple projects %> + <% unless @project.nil? || @project.shared_versions.open.empty? -%> +
  • + <%= l(:field_fixed_version) %> +
      + <% @project.shared_versions.open.sort.each do |v| -%> +
    • <%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post, + :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %>
    • +
    +
  • + <% end %> + <% if @assignables.present? -%> +
  • + <%= l(:field_assigned_to) %> +
      + <% @assignables.each do |u| -%> +
    • <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post, + :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %>
    • +
    +
  • + <% end %> + <% unless @project.nil? || @project.issue_categories.empty? -%> +
  • + <%= l(:field_category) %> +
      + <% @project.issue_categories.each do |u| -%> +
    • <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post, + :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %>
    • +
    +
  • + <% end -%> + + <% if Issue.use_field_for_done_ratio? %> +
  • + <%= l(:field_done_ratio) %> +
      + <% (0..10).map{|x|x*10}.each do |p| -%> +
    • <%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post, + :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
    • + <% end -%> +
    +
  • + <% end %> + +<% if !@issue.nil? %> + <% if @can[:log_time] -%> +
  • <%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, + :class => 'icon-time-add' %>
  • + <% end %> + <% if User.current.logged? %> +
  • <%= watcher_link(@issue, User.current) %>
  • + <% end %> +<% end %> + +<% if @issue.present? %> +
  • <%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, + :class => 'icon-duplicate', :disabled => !@can[:copy] %>
  • +<% end %> +
  • <%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}), + :class => 'icon-copy', :disabled => !@can[:move] %>
  • +
  • <%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)), + :class => 'icon-move', :disabled => !@can[:move] %>
  • +
  • <%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id), :back_url => @back}, + :method => :post, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %>
  • + + <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %> +
diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/523c9c2d9c7b015aa1113d76af95f9049ad0813d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/523c9c2d9c7b015aa1113d76af95f9049ad0813d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +# Only call Engines.init once, in the after_initialize block so that Rails +# plugin reloading works when turned on +config.after_initialize do + Engines.init(initializer) if defined? :Engines +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/524c64f89f9b5171077500c8f6e0240696dfd698.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/524c64f89f9b5171077500c8f6e0240696dfd698.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/generate' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/526a207c3d794968f2a7c5b89f01aadb8abb89d2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/526a207c3d794968f2a7c5b89f01aadb8abb89d2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4332 @@ +#============================================================+ +# File name : tcpdf.rb +# Begin : 2002-08-03 +# Last Update : 2007-03-20 +# Author : Nicola Asuni +# Version : 1.53.0.TC031 +# License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html) +# +# Description : This is a Ruby class for generating PDF files +# on-the-fly without requiring external +# extensions. +# +# IMPORTANT: +# This class is an extension and improvement of the Public Domain +# FPDF class by Olivier Plathey (http://www.fpdf.org). +# +# Main changes by Nicola Asuni: +# Ruby porting; +# UTF-8 Unicode support; +# code refactoring; +# source code clean up; +# code style and formatting; +# source code documentation using phpDocumentor (www.phpdoc.org); +# All ISO page formats were included; +# image scale factor; +# includes methods to parse and printsome XHTML code, supporting the following elements: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small; +# includes a method to print various barcode formats using an improved version of "Generic Barcode Render Class" by Karim Mribti (http://www.mribti.com/barcode/) (require GD library: http://www.boutell.com/gd/); +# defines standard Header() and Footer() methods. +# +# Ported to Ruby by Ed Moss 2007-08-06 +# +#============================================================+ + +# +# TCPDF Class. +# @package com.tecnick.tcpdf +# + +@@version = "1.53.0.TC031" +@@fpdf_charwidths = {} + +PDF_PRODUCER = 'TCPDF via RFPDF 1.53.0.TC031 (http://tcpdf.sourceforge.net)' + +module TCPDFFontDescriptor + @@descriptors = { 'freesans' => {} } + @@font_name = 'freesans' + + def self.font(font_name) + @@descriptors[font_name.gsub(".rb", "")] + end + + def self.define(font_name = 'freesans') + @@descriptors[font_name] ||= {} + yield @@descriptors[font_name] + end +end + +# This is a Ruby class for generating PDF files on-the-fly without requiring external extensions.
+# This class is an extension and improvement of the FPDF class by Olivier Plathey (http://www.fpdf.org).
+# This version contains some changes: [porting to Ruby, support for UTF-8 Unicode, code style and formatting, php documentation (www.phpdoc.org), ISO page formats, minor improvements, image scale factor]
+# TCPDF project (http://tcpdf.sourceforge.net) is based on the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org).
+# To add your own TTF fonts please read /fonts/README.TXT +# @name TCPDF +# @package com.tecnick.tcpdf +# @@version 1.53.0.TC031 +# @author Nicola Asuni +# @link http://tcpdf.sourceforge.net +# @license http://www.gnu.org/copyleft/lesser.html LGPL +# +class TCPDF + include RFPDF + include Core::RFPDF + include RFPDF::Math + + def logger + Rails.logger + end + + cattr_accessor :k_cell_height_ratio + @@k_cell_height_ratio = 1.25 + + cattr_accessor :k_blank_image + @@k_blank_image = "" + + cattr_accessor :k_small_ratio + @@k_small_ratio = 2/3.0 + + cattr_accessor :k_path_cache + @@k_path_cache = Rails.root.join('tmp') + + cattr_accessor :k_path_url_cache + @@k_path_url_cache = Rails.root.join('tmp') + + cattr_accessor :decoder + + attr_accessor :barcode + + attr_accessor :buffer + + attr_accessor :diffs + + attr_accessor :color_flag + + attr_accessor :default_table_columns + + attr_accessor :max_table_columns + + attr_accessor :default_font + + attr_accessor :draw_color + + attr_accessor :encoding + + attr_accessor :fill_color + + attr_accessor :fonts + + attr_accessor :font_family + + attr_accessor :font_files + + cattr_accessor :font_path + + attr_accessor :font_style + + attr_accessor :font_size_pt + + attr_accessor :header_width + + attr_accessor :header_logo + + attr_accessor :header_logo_width + + attr_accessor :header_title + + attr_accessor :header_string + + attr_accessor :images + + attr_accessor :img_scale + + attr_accessor :in_footer + + attr_accessor :is_unicode + + attr_accessor :lasth + + attr_accessor :links + + attr_accessor :list_ordered + + attr_accessor :list_count + + attr_accessor :li_spacer + + attr_accessor :n + + attr_accessor :offsets + + attr_accessor :orientation_changes + + attr_accessor :page + + attr_accessor :page_links + + attr_accessor :pages + + attr_accessor :pdf_version + + attr_accessor :prevfill_color + + attr_accessor :prevtext_color + + attr_accessor :print_header + + attr_accessor :print_footer + + attr_accessor :state + + attr_accessor :tableborder + + attr_accessor :tdbegin + + attr_accessor :tdwidth + + attr_accessor :tdheight + + attr_accessor :tdalign + + attr_accessor :tdfill + + attr_accessor :tempfontsize + + attr_accessor :text_color + + attr_accessor :underline + + attr_accessor :ws + + # + # This is the class constructor. + # It allows to set up the page format, the orientation and + # the measure unit used in all the methods (except for the font sizes). + # @since 1.0 + # @param string :orientation page orientation. Possible values are (case insensitive):
  • P or Portrait (default)
  • L or Landscape
+ # @param string :unit User measure unit. Possible values are:
  • pt: point
  • mm: millimeter (default)
  • cm: centimeter
  • in: inch

A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit. + # @param mixed :format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).
  • 4A0
  • 2A0
  • A0
  • A1
  • A2
  • A3
  • A4 (default)
  • A5
  • A6
  • A7
  • A8
  • A9
  • A10
  • B0
  • B1
  • B2
  • B3
  • B4
  • B5
  • B6
  • B7
  • B8
  • B9
  • B10
  • C0
  • C1
  • C2
  • C3
  • C4
  • C5
  • C6
  • C7
  • C8
  • C9
  • C10
  • RA0
  • RA1
  • RA2
  • RA3
  • RA4
  • SRA0
  • SRA1
  • SRA2
  • SRA3
  • SRA4
  • LETTER
  • LEGAL
  • EXECUTIVE
  • FOLIO
+ # @param boolean :unicode TRUE means that the input text is unicode (default = true) + # @param String :encoding charset encoding; default is UTF-8 + # + def initialize(orientation = 'P', unit = 'mm', format = 'A4', unicode = true, encoding = "UTF-8") + + # Set internal character encoding to ASCII# + #FIXME 2007-05-25 (EJM) Level=0 - + # if (respond_to?("mb_internal_encoding") and mb_internal_encoding()) + # @internal_encoding = mb_internal_encoding(); + # mb_internal_encoding("ASCII"); + # } + + #Some checks + dochecks(); + + begin + @@decoder = HTMLEntities.new + rescue + @@decoder = nil + end + + #Initialization of properties + @barcode ||= false + @buffer ||= '' + @diffs ||= [] + @color_flag ||= false + @default_table_columns ||= 4 + @table_columns ||= 0 + @max_table_columns ||= [] + @tr_id ||= 0 + @max_td_page ||= [] + @max_td_y ||= [] + @t_columns ||= 0 + @default_font ||= "FreeSans" if unicode + @default_font ||= "Helvetica" + @draw_color ||= '0 G' + @encoding ||= "UTF-8" + @fill_color ||= '0 g' + @fonts ||= {} + @font_family ||= '' + @font_files ||= {} + @font_style ||= '' + @font_size ||= 12 + @font_size_pt ||= 12 + @header_width ||= 0 + @header_logo ||= "" + @header_logo_width ||= 30 + @header_title ||= "" + @header_string ||= "" + @images ||= {} + @img_scale ||= 1 + @in_footer ||= false + @is_unicode = unicode + @lasth ||= 0 + @links ||= [] + @list_ordered ||= [] + @list_count ||= [] + @li_spacer ||= "" + @li_count ||= 0 + @spacer ||= "" + @quote_count ||= 0 + @prevquote_count ||= 0 + @quote_top ||= [] + @quote_page ||= [] + @n ||= 2 + @offsets ||= [] + @orientation_changes ||= [] + @page ||= 0 + @page_links ||= {} + @pages ||= [] + @pdf_version ||= "1.3" + @prevfill_color ||= [255,255,255] + @prevtext_color ||= [0,0,0] + @print_header ||= false + @print_footer ||= false + @state ||= 0 + @tableborder ||= 0 + @tdbegin ||= false + @tdwidth ||= 0 + @tdheight ||= 0 + @tdalign ||= "L" + @tdfill ||= 0 + @tempfontsize ||= 10 + @text_color ||= '0 g' + @underline ||= false + @deleted ||= false + @ws ||= 0 + + #Standard Unicode fonts + @core_fonts = { + 'courier'=>'Courier', + 'courierB'=>'Courier-Bold', + 'courierI'=>'Courier-Oblique', + 'courierBI'=>'Courier-BoldOblique', + 'helvetica'=>'Helvetica', + 'helveticaB'=>'Helvetica-Bold', + 'helveticaI'=>'Helvetica-Oblique', + 'helveticaBI'=>'Helvetica-BoldOblique', + 'times'=>'Times-Roman', + 'timesB'=>'Times-Bold', + 'timesI'=>'Times-Italic', + 'timesBI'=>'Times-BoldItalic', + 'symbol'=>'Symbol', + 'zapfdingbats'=>'ZapfDingbats'} + + #Scale factor + case unit.downcase + when 'pt' ; @k=1 + when 'mm' ; @k=72/25.4 + when 'cm' ; @k=72/2.54 + when 'in' ; @k=72 + else Error("Incorrect unit: #{unit}") + end + + #Page format + if format.is_a?(String) + # Page formats (45 standard ISO paper formats and 4 american common formats). + # Paper cordinates are calculated in this way: (inches# 72) where (1 inch = 2.54 cm) + case (format.upcase) + when '4A0' ; format = [4767.87,6740.79] + when '2A0' ; format = [3370.39,4767.87] + when 'A0' ; format = [2383.94,3370.39] + when 'A1' ; format = [1683.78,2383.94] + when 'A2' ; format = [1190.55,1683.78] + when 'A3' ; format = [841.89,1190.55] + when 'A4' ; format = [595.28,841.89] # ; default + when 'A5' ; format = [419.53,595.28] + when 'A6' ; format = [297.64,419.53] + when 'A7' ; format = [209.76,297.64] + when 'A8' ; format = [147.40,209.76] + when 'A9' ; format = [104.88,147.40] + when 'A10' ; format = [73.70,104.88] + when 'B0' ; format = [2834.65,4008.19] + when 'B1' ; format = [2004.09,2834.65] + when 'B2' ; format = [1417.32,2004.09] + when 'B3' ; format = [1000.63,1417.32] + when 'B4' ; format = [708.66,1000.63] + when 'B5' ; format = [498.90,708.66] + when 'B6' ; format = [354.33,498.90] + when 'B7' ; format = [249.45,354.33] + when 'B8' ; format = [175.75,249.45] + when 'B9' ; format = [124.72,175.75] + when 'B10' ; format = [87.87,124.72] + when 'C0' ; format = [2599.37,3676.54] + when 'C1' ; format = [1836.85,2599.37] + when 'C2' ; format = [1298.27,1836.85] + when 'C3' ; format = [918.43,1298.27] + when 'C4' ; format = [649.13,918.43] + when 'C5' ; format = [459.21,649.13] + when 'C6' ; format = [323.15,459.21] + when 'C7' ; format = [229.61,323.15] + when 'C8' ; format = [161.57,229.61] + when 'C9' ; format = [113.39,161.57] + when 'C10' ; format = [79.37,113.39] + when 'RA0' ; format = [2437.80,3458.27] + when 'RA1' ; format = [1729.13,2437.80] + when 'RA2' ; format = [1218.90,1729.13] + when 'RA3' ; format = [864.57,1218.90] + when 'RA4' ; format = [609.45,864.57] + when 'SRA0' ; format = [2551.18,3628.35] + when 'SRA1' ; format = [1814.17,2551.18] + when 'SRA2' ; format = [1275.59,1814.17] + when 'SRA3' ; format = [907.09,1275.59] + when 'SRA4' ; format = [637.80,907.09] + when 'LETTER' ; format = [612.00,792.00] + when 'LEGAL' ; format = [612.00,1008.00] + when 'EXECUTIVE' ; format = [521.86,756.00] + when 'FOLIO' ; format = [612.00,936.00] + #else then Error("Unknown page format: #{format}" + end + @fw_pt = format[0] + @fh_pt = format[1] + else + @fw_pt = format[0]*@k + @fh_pt = format[1]*@k + end + + @fw = @fw_pt/@k + @fh = @fh_pt/@k + + #Page orientation + orientation = orientation.downcase + if orientation == 'p' or orientation == 'portrait' + @def_orientation = 'P' + @w_pt = @fw_pt + @h_pt = @fh_pt + elsif orientation == 'l' or orientation == 'landscape' + @def_orientation = 'L' + @w_pt = @fh_pt + @h_pt = @fw_pt + else + Error("Incorrect orientation: #{orientation}") + end + + @cur_orientation = @def_orientation + @w = @w_pt/@k + @h = @h_pt/@k + #Page margins (1 cm) + margin = 28.35/@k + SetMargins(margin, margin) + #Interior cell margin (1 mm) + @c_margin = margin / 10 + #Line width (0.2 mm) + @line_width = 0.567 / @k + #Automatic page break + SetAutoPageBreak(true, 2 * margin) + #Full width display mode + SetDisplayMode('fullwidth') + #Compression + SetCompression(true) + #Set default PDF version number + @pdf_version = "1.3" + + @encoding = encoding + @b = 0 + @i = 0 + @u = 0 + @href = '' + @fontlist = ["arial", "times", "courier", "helvetica", "symbol"] + @issetfont = false + @issetcolor = false + + SetFillColor(200, 200, 200, true) + SetTextColor(0, 0, 0, true) + end + + # + # Set the image scale. + # @param float :scale image scale. + # @author Nicola Asuni + # @since 1.5.2 + # + def SetImageScale(scale) + @img_scale = scale; + end + alias_method :set_image_scale, :SetImageScale + + # + # Returns the image scale. + # @return float image scale. + # @author Nicola Asuni + # @since 1.5.2 + # + def GetImageScale() + return @img_scale; + end + alias_method :get_image_scale, :GetImageScale + + # + # Returns the page width in units. + # @return int page width. + # @author Nicola Asuni + # @since 1.5.2 + # + def GetPageWidth() + return @w; + end + alias_method :get_page_width, :GetPageWidth + + # + # Returns the page height in units. + # @return int page height. + # @author Nicola Asuni + # @since 1.5.2 + # + def GetPageHeight() + return @h; + end + alias_method :get_page_height, :GetPageHeight + + # + # Returns the page break margin. + # @return int page break margin. + # @author Nicola Asuni + # @since 1.5.2 + # + def GetBreakMargin() + return @b_margin; + end + alias_method :get_break_margin, :GetBreakMargin + + # + # Returns the scale factor (number of points in user unit). + # @return int scale factor. + # @author Nicola Asuni + # @since 1.5.2 + # + def GetScaleFactor() + return @k; + end + alias_method :get_scale_factor, :GetScaleFactor + + # + # Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change them. + # @param float :left Left margin. + # @param float :top Top margin. + # @param float :right Right margin. Default value is the left one. + # @since 1.0 + # @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak() + # + def SetMargins(left, top, right=-1) + #Set left, top and right margins + @l_margin = left + @t_margin = top + if (right == -1) + right = left + end + @r_margin = right + end + alias_method :set_margins, :SetMargins + + # + # Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin. + # @param float :margin The margin. + # @since 1.4 + # @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() + # + def SetLeftMargin(margin) + #Set left margin + @l_margin = margin + if ((@page>0) and (@x < margin)) + @x = margin + end + end + alias_method :set_left_margin, :SetLeftMargin + + # + # Defines the top margin. The method can be called before creating the first page. + # @param float :margin The margin. + # @since 1.5 + # @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins() + # + def SetTopMargin(margin) + #Set top margin + @t_margin = margin + end + alias_method :set_top_margin, :SetTopMargin + + # + # Defines the right margin. The method can be called before creating the first page. + # @param float :margin The margin. + # @since 1.5 + # @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins() + # + def SetRightMargin(margin) + #Set right margin + @r_margin = margin + end + alias_method :set_right_margin, :SetRightMargin + + # + # Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm. + # @param boolean :auto Boolean indicating if mode should be on or off. + # @param float :margin Distance from the bottom of the page. + # @since 1.0 + # @see Cell(), MultiCell(), AcceptPageBreak() + # + def SetAutoPageBreak(auto, margin=0) + #Set auto page break mode and triggering margin + @auto_page_break = auto + @b_margin = margin + @page_break_trigger = @h - margin + end + alias_method :set_auto_page_break, :SetAutoPageBreak + + # + # Defines the way the document is to be displayed by the viewer. The zoom level can be set: pages can be displayed entirely on screen, occupy the full width of the window, use real size, be scaled by a specific zooming factor or use viewer default (configured in the Preferences menu of Acrobat). The page layout can be specified too: single at once, continuous display, two columns or viewer default. By default, documents use the full width mode with continuous display. + # @param mixed :zoom The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use.
  • fullpage: displays the entire page on screen
  • fullwidth: uses maximum width of window
  • real: uses real size (equivalent to 100% zoom)
  • default: uses viewer default mode
+ # @param string :layout The page layout. Possible values are:
  • single: displays one page at once
  • continuous: displays pages continuously (default)
  • two: displays two pages on two columns
  • default: uses viewer default mode
+ # @since 1.2 + # + def SetDisplayMode(zoom, layout = 'continuous') + #Set display mode in viewer + if (zoom == 'fullpage' or zoom == 'fullwidth' or zoom == 'real' or zoom == 'default' or !zoom.is_a?(String)) + @zoom_mode = zoom + else + Error("Incorrect zoom display mode: #{zoom}") + end + if (layout == 'single' or layout == 'continuous' or layout == 'two' or layout == 'default') + @layout_mode = layout + else + Error("Incorrect layout display mode: #{layout}") + end + end + alias_method :set_display_mode, :SetDisplayMode + + # + # Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default. + # Note: the Zlib extension is required for this feature. If not present, compression will be turned off. + # @param boolean :compress Boolean indicating if compression must be enabled. + # @since 1.4 + # + def SetCompression(compress) + #Set page compression + if (respond_to?('gzcompress')) + @compress = compress + else + @compress = false + end + end + alias_method :set_compression, :SetCompression + + # + # Defines the title of the document. + # @param string :title The title. + # @since 1.2 + # @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject() + # + def SetTitle(title) + #Title of document + @title = title + end + alias_method :set_title, :SetTitle + + # + # Defines the subject of the document. + # @param string :subject The subject. + # @since 1.2 + # @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle() + # + def SetSubject(subject) + #Subject of document + @subject = subject + end + alias_method :set_subject, :SetSubject + + # + # Defines the author of the document. + # @param string :author The name of the author. + # @since 1.2 + # @see SetCreator(), SetKeywords(), SetSubject(), SetTitle() + # + def SetAuthor(author) + #Author of document + @author = author + end + alias_method :set_author, :SetAuthor + + # + # Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'. + # @param string :keywords The list of keywords. + # @since 1.2 + # @see SetAuthor(), SetCreator(), SetSubject(), SetTitle() + # + def SetKeywords(keywords) + #Keywords of document + @keywords = keywords + end + alias_method :set_keywords, :SetKeywords + + # + # Defines the creator of the document. This is typically the name of the application that generates the PDF. + # @param string :creator The name of the creator. + # @since 1.2 + # @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle() + # + def SetCreator(creator) + #Creator of document + @creator = creator + end + alias_method :set_creator, :SetCreator + + # + # Defines an alias for the total number of pages. It will be substituted as the document is closed.
+ # Example:
+ #
+	# class PDF extends TCPDF {
+	# 	def Footer()
+	# 		#Go to 1.5 cm from bottom
+	# 		SetY(-15);
+	# 		#Select Arial italic 8
+	# 		SetFont('Arial','I',8);
+	# 		#Print current and total page numbers
+	# 		Cell(0,10,'Page '.PageNo().'/{nb}',0,0,'C');
+	# 	end
+	# }
+	# :pdf=new PDF();
+	# :pdf->alias_nb_pages();
+	# 
+ # @param string :alias The alias. Default valuenb}. + # @since 1.4 + # @see PageNo(), Footer() + # + def AliasNbPages(alias_nb ='{nb}') + #Define an alias for total number of pages + @alias_nb_pages = escapetext(alias_nb) + end + alias_method :alias_nb_pages, :AliasNbPages + + # + # This method is automatically called in case of fatal error; it simply outputs the message and halts the execution. An inherited class may override it to customize the error handling but should always halt the script, or the resulting document would probably be invalid. + # 2004-06-11 :: Nicola Asuni : changed bold tag with strong + # @param string :msg The error message + # @since 1.0 + # + def Error(msg) + #Fatal error + raise ("TCPDF error: #{msg}") + end + alias_method :error, :Error + + # + # This method begins the generation of the PDF document. It is not necessary to call it explicitly because AddPage() does it automatically. + # Note: no page is created by this method + # @since 1.0 + # @see AddPage(), Close() + # + def Open() + #Begin document + @state = 1 + end + # alias_method :open, :Open + + # + # Terminates the PDF document. It is not necessary to call this method explicitly because Output() does it automatically. If the document contains no page, AddPage() is called to prevent from getting an invalid document. + # @since 1.0 + # @see Open(), Output() + # + def Close() + #Terminate document + if (@state==3) + return; + end + if (@page==0) + AddPage(); + end + #Page footer + @in_footer=true; + Footer(); + @in_footer=false; + #Close page + endpage(); + #Close document + enddoc(); + end + # alias_method :close, :Close + + # + # Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer. Then the page is added, the current position set to the top-left corner according to the left and top margins, and Header() is called to display the header. + # The font which was set before calling is automatically restored. There is no need to call SetFont() again if you want to continue with the same font. The same is true for colors and line width. + # The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards. + # @param string :orientation Page orientation. Possible values are (case insensitive):
  • P or Portrait
  • L or Landscape
The default value is the one passed to the constructor. + # @since 1.0 + # @see TCPDF(), Header(), Footer(), SetMargins() + # + def AddPage(orientation='') + #Start a new page + if (@state==0) + Open(); + end + family=@font_family; + style=@font_style + (@underline ? 'U' : '') + (@deleted ? 'D' : ''); + size=@font_size_pt; + lw=@line_width; + dc=@draw_color; + fc=@fill_color; + tc=@text_color; + cf=@color_flag; + if (@page>0) + #Page footer + @in_footer=true; + Footer(); + @in_footer=false; + #Close page + endpage(); + end + #Start new page + beginpage(orientation); + #Set line cap style to square + out('2 J'); + #Set line width + @line_width = lw; + out(sprintf('%.2f w', lw*@k)); + #Set font + if (family) + SetFont(family, style, size); + end + #Set colors + @draw_color = dc; + if (dc!='0 G') + out(dc); + end + @fill_color = fc; + if (fc!='0 g') + out(fc); + end + @text_color = tc; + @color_flag = cf; + #Page header + Header(); + #Restore line width + if (@line_width != lw) + @line_width = lw; + out(sprintf('%.2f w', lw*@k)); + end + #Restore font + if (family) + SetFont(family, style, size); + end + #Restore colors + if (@draw_color != dc) + @draw_color = dc; + out(dc); + end + if (@fill_color != fc) + @fill_color = fc; + out(fc); + end + @text_color = tc; + @color_flag = cf; + end + alias_method :add_page, :AddPage + + # + # Rotate object. + # @param float :angle angle in degrees for counter-clockwise rotation + # @param int :x abscissa of the rotation center. Default is current x position + # @param int :y ordinate of the rotation center. Default is current y position + # + def Rotate(angle, x="", y="") + + if (x == '') + x = @x; + end + + if (y == '') + y = @y; + end + + if (@rtl) + x = @w - x; + angle = -@angle; + end + + y = (@h - y) * @k; + x *= @k; + + # calculate elements of transformation matrix + tm = [] + tm[0] = ::Math::cos(deg2rad(angle)); + tm[1] = ::Math::sin(deg2rad(angle)); + tm[2] = -tm[1]; + tm[3] = tm[0]; + tm[4] = x + tm[1] * y - tm[0] * x; + tm[5] = y - tm[0] * y - tm[1] * x; + + # generate the transformation matrix + Transform(tm); + end + alias_method :rotate, :Rotate + + # + # Starts a 2D tranformation saving current graphic state. + # This function must be called before scaling, mirroring, translation, rotation and skewing. + # Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior. + # + def StartTransform + out('q'); + end + alias_method :start_transform, :StartTransform + + # + # Stops a 2D tranformation restoring previous graphic state. + # This function must be called after scaling, mirroring, translation, rotation and skewing. + # Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior. + # + def StopTransform + out('Q'); + end + alias_method :stop_transform, :StopTransform + + # + # Apply graphic transformations. + # @since 2.1.000 (2008-01-07) + # @see StartTransform(), StopTransform() + # + def Transform(tm) + x = out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])); + end + alias_method :transform, :Transform + + # + # Set header data. + # @param string :ln header image logo + # @param string :lw header image logo width in mm + # @param string :ht string to print as title on document header + # @param string :hs string to print on document header + # + def SetHeaderData(ln="", lw=0, ht="", hs="") + @header_logo = ln || "" + @header_logo_width = lw || 0 + @header_title = ht || "" + @header_string = hs || "" + end + alias_method :set_header_data, :SetHeaderData + + # + # Set header margin. + # (minimum distance between header and top page margin) + # @param int :hm distance in millimeters + # + def SetHeaderMargin(hm=10) + @header_margin = hm; + end + alias_method :set_header_margin, :SetHeaderMargin + + # + # Set footer margin. + # (minimum distance between footer and bottom page margin) + # @param int :fm distance in millimeters + # + def SetFooterMargin(fm=10) + @footer_margin = fm; + end + alias_method :set_footer_margin, :SetFooterMargin + + # + # Set a flag to print page header. + # @param boolean :val set to true to print the page header (default), false otherwise. + # + def SetPrintHeader(val=true) + @print_header = val; + end + alias_method :set_print_header, :SetPrintHeader + + # + # Set a flag to print page footer. + # @param boolean :value set to true to print the page footer (default), false otherwise. + # + def SetPrintFooter(val=true) + @print_footer = val; + end + alias_method :set_print_footer, :SetPrintFooter + + # + # This method is used to render the page header. + # It is automatically called by AddPage() and could be overwritten in your own inherited class. + # + def Header() + if (@print_header) + if (@original_l_margin.nil?) + @original_l_margin = @l_margin; + end + if (@original_r_margin.nil?) + @original_r_margin = @r_margin; + end + + #set current position + SetXY(@original_l_margin, @header_margin); + + if ((@header_logo) and (@header_logo != @@k_blank_image)) + Image(@header_logo, @original_l_margin, @header_margin, @header_logo_width); + else + @img_rb_y = GetY(); + end + + cell_height = ((@@k_cell_height_ratio * @header_font[2]) / @k).round(2) + + header_x = @original_l_margin + (@header_logo_width * 1.05); #set left margin for text data cell + + # header title + SetFont(@header_font[0], 'B', @header_font[2] + 1); + SetX(header_x); + Cell(@header_width, cell_height, @header_title, 0, 1, 'L'); + + # header string + SetFont(@header_font[0], @header_font[1], @header_font[2]); + SetX(header_x); + MultiCell(@header_width, cell_height, @header_string, 0, 'L', 0); + + # print an ending header line + if (@header_width) + #set style for cell border + SetLineWidth(0.3); + SetDrawColor(0, 0, 0); + SetY(1 + (@img_rb_y > GetY() ? @img_rb_y : GetY())); + SetX(@original_l_margin); + Cell(0, 0, '', 'T', 0, 'C'); + end + + #restore position + SetXY(@original_l_margin, @t_margin); + end + end + alias_method :header, :Header + + # + # This method is used to render the page footer. + # It is automatically called by AddPage() and could be overwritten in your own inherited class. + # + def Footer() + if (@print_footer) + + if (@original_l_margin.nil?) + @original_l_margin = @l_margin; + end + if (@original_r_margin.nil?) + @original_r_margin = @r_margin; + end + + #set font + SetFont(@footer_font[0], @footer_font[1] , @footer_font[2]); + #set style for cell border + line_width = 0.3; + SetLineWidth(line_width); + SetDrawColor(0, 0, 0); + + footer_height = ((@@k_cell_height_ratio * @footer_font[2]) / @k).round; #footer height, was , 2) + #get footer y position + footer_y = @h - @footer_margin - footer_height; + #set current position + SetXY(@original_l_margin, footer_y); + + #print document barcode + if (@barcode) + Ln(); + barcode_width = ((@w - @original_l_margin - @original_r_margin)).round; #max width + writeBarcode(@original_l_margin, footer_y + line_width, barcode_width, footer_height - line_width, "C128B", false, false, 2, @barcode); + end + + SetXY(@original_l_margin, footer_y); + + #Print page number + Cell(0, footer_height, @l['w_page'] + " " + PageNo().to_s + ' / {nb}', 'T', 0, 'R'); + end + end + alias_method :footer, :Footer + + # + # Returns the current page number. + # @return int page number + # @since 1.0 + # @see alias_nb_pages() + # + def PageNo() + #Get current page number + return @page; + end + alias_method :page_no, :PageNo + + # + # Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. + # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255 + # @param int :g Green component (between 0 and 255) + # @param int :b Blue component (between 0 and 255) + # @since 1.3 + # @see SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell() + # + def SetDrawColor(r, g=-1, b=-1) + #Set color for all stroking operations + if ((r==0 and g==0 and b==0) or g==-1) + @draw_color=sprintf('%.3f G', r/255.0); + else + @draw_color=sprintf('%.3f %.3f %.3f RG', r/255.0, g/255.0, b/255.0); + end + if (@page>0) + out(@draw_color); + end + end + alias_method :set_draw_color, :SetDrawColor + + # + # Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. + # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255 + # @param int :g Green component (between 0 and 255) + # @param int :b Blue component (between 0 and 255) + # @param boolean :storeprev if true stores the RGB array on :prevfill_color variable. + # @since 1.3 + # @see SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell() + # + def SetFillColor(r, g=-1, b=-1, storeprev=false) + #Set color for all filling operations + if ((r==0 and g==0 and b==0) or g==-1) + @fill_color=sprintf('%.3f g', r/255.0); + else + @fill_color=sprintf('%.3f %.3f %.3f rg', r/255.0, g/255.0, b/255.0); + end + @color_flag=(@fill_color!=@text_color); + if (@page>0) + out(@fill_color); + end + if (storeprev) + # store color as previous value + @prevfill_color = [r, g, b] + end + end + alias_method :set_fill_color, :SetFillColor + + # This hasn't been ported from tcpdf, it's a variation on SetTextColor for setting cmyk colors + def SetCmykFillColor(c, m, y, k, storeprev=false) + #Set color for all filling operations + @fill_color=sprintf('%.3f %.3f %.3f %.3f k', c, m, y, k); + @color_flag=(@fill_color!=@text_color); + if (storeprev) + # store color as previous value + @prevtext_color = [c, m, y, k] + end + if (@page>0) + out(@fill_color); + end + end + alias_method :set_cmyk_fill_color, :SetCmykFillColor + + # + # Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page. + # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255 + # @param int :g Green component (between 0 and 255) + # @param int :b Blue component (between 0 and 255) + # @param boolean :storeprev if true stores the RGB array on :prevtext_color variable. + # @since 1.3 + # @see SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell() + # + def SetTextColor(r, g=-1, b=-1, storeprev=false) + #Set color for text + if ((r==0 and :g==0 and :b==0) or :g==-1) + @text_color=sprintf('%.3f g', r/255.0); + else + @text_color=sprintf('%.3f %.3f %.3f rg', r/255.0, g/255.0, b/255.0); + end + @color_flag=(@fill_color!=@text_color); + if (storeprev) + # store color as previous value + @prevtext_color = [r, g, b] + end + end + alias_method :set_text_color, :SetTextColor + + # This hasn't been ported from tcpdf, it's a variation on SetTextColor for setting cmyk colors + def SetCmykTextColor(c, m, y, k, storeprev=false) + #Set color for text + @text_color=sprintf('%.3f %.3f %.3f %.3f k', c, m, y, k); + @color_flag=(@fill_color!=@text_color); + if (storeprev) + # store color as previous value + @prevtext_color = [c, m, y, k] + end + end + alias_method :set_cmyk_text_color, :SetCmykTextColor + + # + # Returns the length of a string in user unit. A font must be selected.
+ # Support UTF-8 Unicode [Nicola Asuni, 2005-01-02] + # @param string :s The string whose length is to be computed + # @return int + # @since 1.2 + # + def GetStringWidth(s) + #Get width of a string in the current font + s = s.to_s; + cw = @current_font['cw'] + w = 0; + if (@is_unicode) + unicode = UTF8StringToArray(s); + unicode.each do |char| + if (!cw[char].nil?) + w += cw[char]; + # This should not happen. UTF8StringToArray should guarentee the array is ascii values. + # elsif (c!cw[char[0]].nil?) + # w += cw[char[0]]; + # elsif (!cw[char.chr].nil?) + # w += cw[char.chr]; + elsif (!@current_font['desc']['MissingWidth'].nil?) + w += @current_font['desc']['MissingWidth']; # set default size + else + w += 500; + end + end + else + s.each_byte do |c| + if cw[c.chr] + w += cw[c.chr]; + elsif cw[?c.chr] + w += cw[?c.chr] + end + end + end + return (w * @font_size / 1000.0); + end + alias_method :get_string_width, :GetStringWidth + + # + # Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page. + # @param float :width The width. + # @since 1.0 + # @see Line(), Rect(), Cell(), MultiCell() + # + def SetLineWidth(width) + #Set line width + @line_width = width; + if (@page>0) + out(sprintf('%.2f w', width*@k)); + end + end + alias_method :set_line_width, :SetLineWidth + + # + # Draws a line between two points. + # @param float :x1 Abscissa of first point + # @param float :y1 Ordinate of first point + # @param float :x2 Abscissa of second point + # @param float :y2 Ordinate of second point + # @since 1.0 + # @see SetLineWidth(), SetDrawColor() + # + def Line(x1, y1, x2, y2) + #Draw a line + out(sprintf('%.2f %.2f m %.2f %.2f l S', x1 * @k, (@h - y1) * @k, x2 * @k, (@h - y2) * @k)); + end + alias_method :line, :Line + + def Circle(mid_x, mid_y, radius, style='') + mid_y = (@h-mid_y)*@k + out(sprintf("q\n")) # postscript content in pdf + # init line type etc. with /GSD gs G g (grey) RG rg (RGB) w=line witdh etc. + out(sprintf("1 j\n")) # line join + # translate ("move") circle to mid_y, mid_y + out(sprintf("1 0 0 1 %f %f cm", mid_x, mid_y)) + kappa = 0.5522847498307933984022516322796 + # Quadrant 1 + x_s = 0.0 # 12 o'clock + y_s = 0.0 + radius + x_e = 0.0 + radius # 3 o'clock + y_e = 0.0 + out(sprintf("%f %f m\n", x_s, y_s)) # move to 12 o'clock + # cubic bezier control point 1, start height and kappa * radius to the right + bx_e1 = x_s + (radius * kappa) + by_e1 = y_s + # cubic bezier control point 2, end and kappa * radius above + bx_e2 = x_e + by_e2 = y_e + (radius * kappa) + # draw cubic bezier from current point to x_e/y_e with bx_e1/by_e1 and bx_e2/by_e2 as bezier control points + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + # Quadrant 2 + x_s = x_e + y_s = y_e # 3 o'clock + x_e = 0.0 + y_e = 0.0 - radius # 6 o'clock + bx_e1 = x_s # cubic bezier point 1 + by_e1 = y_s - (radius * kappa) + bx_e2 = x_e + (radius * kappa) # cubic bezier point 2 + by_e2 = y_e + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + # Quadrant 3 + x_s = x_e + y_s = y_e # 6 o'clock + x_e = 0.0 - radius + y_e = 0.0 # 9 o'clock + bx_e1 = x_s - (radius * kappa) # cubic bezier point 1 + by_e1 = y_s + bx_e2 = x_e # cubic bezier point 2 + by_e2 = y_e - (radius * kappa) + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + # Quadrant 4 + x_s = x_e + y_s = y_e # 9 o'clock + x_e = 0.0 + y_e = 0.0 + radius # 12 o'clock + bx_e1 = x_s # cubic bezier point 1 + by_e1 = y_s + (radius * kappa) + bx_e2 = x_e - (radius * kappa) # cubic bezier point 2 + by_e2 = y_e + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + if style=='F' + op='f' + elsif style=='FD' or style=='DF' + op='b' + else + op='s' + end + out(sprintf("#{op}\n")) # stroke circle, do not fill and close path + # for filling etc. b, b*, f, f* + out(sprintf("Q\n")) # finish postscript in PDF + end + alias_method :circle, :Circle + + # + # Outputs a rectangle. It can be drawn (border only), filled (with no border) or both. + # @param float :x Abscissa of upper-left corner + # @param float :y Ordinate of upper-left corner + # @param float :w Width + # @param float :h Height + # @param string :style Style of rendering. Possible values are:
  • D or empty string: draw (default)
  • F: fill
  • DF or FD: draw and fill
+ # @since 1.0 + # @see SetLineWidth(), SetDrawColor(), SetFillColor() + # + def Rect(x, y, w, h, style='') + #Draw a rectangle + if (style=='F') + op='f'; + elsif (style=='FD' or style=='DF') + op='B'; + else + op='S'; + end + out(sprintf('%.2f %.2f %.2f %.2f re %s', x * @k, (@h - y) * @k, w * @k, -h * @k, op)); + end + alias_method :rect, :Rect + + # + # Imports a TrueType or Type1 font and makes it available. It is necessary to generate a font definition file first with the makefont.rb utility. The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by FPDF_FONTPATH if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated. + # Support UTF-8 Unicode [Nicola Asuni, 2005-01-02]. + # Example:
+ #
+	# :pdf->AddFont('Comic','I');
+	# # is equivalent to:
+	# :pdf->AddFont('Comic','I','comici.rb');
+	# 
+ # @param string :family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font. + # @param string :style Font style. Possible values are (case insensitive):
  • empty string: regular (default)
  • B: bold
  • I: italic
  • BI or IB: bold italic
+ # @param string :file The font definition file. By default, the name is built from the family and style, in lower case with no space. + # @since 1.5 + # @see SetFont() + # + def AddFont(family, style='', file='') + if (family.empty?) + return; + end + + #Add a TrueType or Type1 font + family = family.downcase + if ((!@is_unicode) and (family == 'arial')) + family = 'helvetica'; + end + + style=style.upcase + style=style.gsub('U',''); + style=style.gsub('D',''); + if (style == 'IB') + style = 'BI'; + end + + fontkey = family + style; + # check if the font has been already added + if !@fonts[fontkey].nil? + return; + end + + if (file=='') + file = family.gsub(' ', '') + style.downcase + '.rb'; + end + font_file_name = getfontpath(file) + if (font_file_name.nil?) + # try to load the basic file without styles + file = family.gsub(' ', '') + '.rb'; + font_file_name = getfontpath(file) + end + if font_file_name.nil? + Error("Could not find font #{file}.") + end + require(getfontpath(file)) + font_desc = TCPDFFontDescriptor.font(file) + + if (font_desc[:name].nil? and @@fpdf_charwidths.nil?) + Error('Could not include font definition file'); + end + + i = @fonts.length+1; + if (@is_unicode) + @fonts[fontkey] = {'i' => i, 'type' => font_desc[:type], 'name' => font_desc[:name], 'desc' => font_desc[:desc], 'up' => font_desc[:up], 'ut' => font_desc[:ut], 'cw' => font_desc[:cw], 'enc' => font_desc[:enc], 'file' => font_desc[:file], 'ctg' => font_desc[:ctg], 'cMap' => font_desc[:cMap], 'registry' => font_desc[:registry]} + @@fpdf_charwidths[fontkey] = font_desc[:cw]; + else + @fonts[fontkey]={'i' => i, 'type'=>'core', 'name'=>@core_fonts[fontkey], 'up'=>-100, 'ut'=>50, 'cw' => font_desc[:cw]} + @@fpdf_charwidths[fontkey] = font_desc[:cw]; + end + + if (!font_desc[:diff].nil? and (!font_desc[:diff].empty?)) + #Search existing encodings + d=0; + nb=@diffs.length; + 1.upto(nb) do |i| + if (@diffs[i]== font_desc[:diff]) + d = i; + break; + end + end + if (d==0) + d = nb+1; + @diffs[d] = font_desc[:diff]; + end + @fonts[fontkey]['diff'] = d; + end + if (font_desc[:file] and font_desc[:file].length > 0) + if (font_desc[:type] == "TrueType") or (font_desc[:type] == "TrueTypeUnicode") + @font_files[font_desc[:file]] = {'length1' => font_desc[:originalsize]} + else + @font_files[font_desc[:file]] = {'length1' => font_desc[:size1], 'length2' => font_desc[:size2]} + end + end + end + alias_method :add_font, :AddFont + + # + # Sets the font used to print character strings. It is mandatory to call this method at least once before printing text or the resulting document would not be valid. + # The font can be either a standard one or a font added via the AddFont() method. Standard fonts use Windows encoding cp1252 (Western Europe). + # The method can be called before the first page is created and the font is retained from page to page. + # If you just wish to change the current font size, it is simpler to call SetFontSize(). + # Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:
  • They are in the current directory (the one where the running script lies)
  • They are in one of the directories defined by the include_path parameter
  • They are in the directory defined by the FPDF_FONTPATH constant

+ # Example for the last case (note the trailing slash):
+ #
+	# define('FPDF_FONTPATH','/home/www/font/');
+	# require('tcpdf.rb');
+	#
+	# #Times regular 12
+	# :pdf->SetFont('Times');
+	# #Arial bold 14
+	# :pdf->SetFont('Arial','B',14);
+	# #Removes bold
+	# :pdf->SetFont('');
+	# #Times bold, italic and underlined 14
+	# :pdf->SetFont('Times','BIUD');
+	# 

+ # If the file corresponding to the requested font is not found, the error "Could not include font metric file" is generated. + # @param string :family Family font. It can be either a name defined by AddFont() or one of the standard families (case insensitive):
  • Courier (fixed-width)
  • Helvetica or Arial (synonymous; sans serif)
  • Times (serif)
  • Symbol (symbolic)
  • ZapfDingbats (symbolic)
It is also possible to pass an empty string. In that case, the current family is retained. + # @param string :style Font style. Possible values are (case insensitive):
  • empty string: regular
  • B: bold
  • I: italic
  • U: underline
or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats + # @param float :size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12 + # @since 1.0 + # @see AddFont(), SetFontSize(), Cell(), MultiCell(), Write() + # + def SetFont(family, style='', size=0) + # save previous values + @prevfont_family = @font_family; + @prevfont_style = @font_style; + + family=family.downcase; + if (family=='') + family=@font_family; + end + if ((!@is_unicode) and (family == 'arial')) + family = 'helvetica'; + elsif ((family=="symbol") or (family=="zapfdingbats")) + style=''; + end + + style=style.upcase; + + if (style.include?('U')) + @underline=true; + style= style.gsub('U',''); + else + @underline=false; + end + if (style.include?('D')) + @deleted=true; + style= style.gsub('D',''); + else + @deleted=false; + end + if (style=='IB') + style='BI'; + end + if (size==0) + size=@font_size_pt; + end + + # try to add font (if not already added) + AddFont(family, style); + + #Test if font is already selected + if ((@font_family == family) and (@font_style == style) and (@font_size_pt == size)) + return; + end + + fontkey = family + style; + style = '' if (@fonts[fontkey].nil? and !@fonts[family].nil?) + + #Test if used for the first time + if (@fonts[fontkey].nil?) + #Check if one of the standard fonts + if (!@core_fonts[fontkey].nil?) + if @@fpdf_charwidths[fontkey].nil? + #Load metric file + file = family; + if ((family!='symbol') and (family!='zapfdingbats')) + file += style.downcase; + end + if (getfontpath(file + '.rb').nil?) + # try to load the basic file without styles + file = family; + fontkey = family; + end + require(getfontpath(file + '.rb')); + font_desc = TCPDFFontDescriptor.font(file) + if ((@is_unicode and ctg.nil?) or ((!@is_unicode) and (@@fpdf_charwidths[fontkey].nil?)) ) + Error("Could not include font metric file [" + fontkey + "]: " + getfontpath(file + ".rb")); + end + end + i = @fonts.length + 1; + + if (@is_unicode) + @fonts[fontkey] = {'i' => i, 'type' => font_desc[:type], 'name' => font_desc[:name], 'desc' => font_desc[:desc], 'up' => font_desc[:up], 'ut' => font_desc[:ut], 'cw' => font_desc[:cw], 'enc' => font_desc[:enc], 'file' => font_desc[:file], 'ctg' => font_desc[:ctg]} + @@fpdf_charwidths[fontkey] = font_desc[:cw]; + else + @fonts[fontkey] = {'i' => i, 'type'=>'core', 'name'=>@core_fonts[fontkey], 'up'=>-100, 'ut'=>50, 'cw' => font_desc[:cw]} + @@fpdf_charwidths[fontkey] = font_desc[:cw]; + end + else + Error('Undefined font: ' + family + ' ' + style); + end + end + #Select it + @font_family = family; + @font_style = style; + @font_size_pt = size; + @font_size = size / @k; + @current_font = @fonts[fontkey]; # was & may need deep copy? + if (@page>0) + out(sprintf('BT /F%d %.2f Tf ET', @current_font['i'], @font_size_pt)); + end + end + alias_method :set_font, :SetFont + + # + # Defines the size of the current font. + # @param float :size The size (in points) + # @since 1.0 + # @see SetFont() + # + def SetFontSize(size) + #Set font size in points + if (@font_size_pt== size) + return; + end + @font_size_pt = size; + @font_size = size.to_f / @k; + if (@page > 0) + out(sprintf('BT /F%d %.2f Tf ET', @current_font['i'], @font_size_pt)); + end + end + alias_method :set_font_size, :SetFontSize + + # + # Creates a new internal link and returns its identifier. An internal link is a clickable area which directs to another place within the document.
+ # The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is defined with SetLink(). + # @since 1.5 + # @see Cell(), Write(), Image(), Link(), SetLink() + # + def AddLink() + #Create a new internal link + n=@links.length+1; + @links[n]=[0,0]; + return n; + end + alias_method :add_link, :AddLink + + # + # Defines the page and position a link points to + # @param int :link The link identifier returned by AddLink() + # @param float :y Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page) + # @param int :page Number of target page; -1 indicates the current page. This is the default value + # @since 1.5 + # @see AddLink() + # + def SetLink(link, y=0, page=-1) + #Set destination of internal link + if (y==-1) + y=@y; + end + if (page==-1) + page=@page; + end + @links[link] = [page, y] + end + alias_method :set_link, :SetLink + + # + # Puts a link on a rectangular area of the page. Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image. + # @param float :x Abscissa of the upper-left corner of the rectangle + # @param float :y Ordinate of the upper-left corner of the rectangle + # @param float :w Width of the rectangle + # @param float :h Height of the rectangle + # @param mixed :link URL or identifier returned by AddLink() + # @since 1.5 + # @see AddLink(), Cell(), Write(), Image() + # + def Link(x, y, w, h, link) + #Put a link on the page + @page_links ||= Array.new + @page_links[@page] ||= Array.new + @page_links[@page].push([x * @k, @h_pt - y * @k, w * @k, h*@k, link]); + end + alias_method :link, :Link + + # + # Prints a character string. The origin is on the left of the first charcter, on the baseline. This method allows to place a string precisely on the page, but it is usually easier to use Cell(), MultiCell() or Write() which are the standard methods to print text. + # @param float :x Abscissa of the origin + # @param float :y Ordinate of the origin + # @param string :txt String to print + # @since 1.0 + # @see SetFont(), SetTextColor(), Cell(), MultiCell(), Write() + # + def Text(x, y, txt) + #Output a string + s=sprintf('BT %.2f %.2f Td (%s) Tj ET', x * @k, (@h-y) * @k, escapetext(txt)); + if (@underline and (txt!='')) + s += ' ' + dolinetxt(x, y, txt); + end + if (@color_flag) + s='q ' + @text_color + ' ' + s + ' Q'; + end + out(s); + end + alias_method :text, :Text + + # + # Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value. The default implementation returns a value according to the mode selected by SetAutoPageBreak().
+ # This method is called automatically and should not be called directly by the application.
+ # Example:
+ # The method is overriden in an inherited class in order to obtain a 3 column layout:
+ #
+	# class PDF extends TCPDF {
+	# 	var :col=0;
+	#
+	# 	def SetCol(col)
+	# 		#Move position to a column
+	# 		@col = col;
+	# 		:x=10+:col*65;
+	# 		SetLeftMargin(x);
+	# 		SetX(x);
+	# 	end
+	#
+	# 	def AcceptPageBreak()
+	# 		if (@col<2)
+	# 			#Go to next column
+	# 			SetCol(@col+1);
+	# 			SetY(10);
+	# 			return false;
+	# 		end
+	# 		else
+	# 			#Go back to first column and issue page break
+	# 			SetCol(0);
+	# 			return true;
+	# 		end
+	# 	end
+	# }
+	#
+	# :pdf=new PDF();
+	# :pdf->Open();
+	# :pdf->AddPage();
+	# :pdf->SetFont('Arial','',12);
+	# for(i=1;:i<=300;:i++)
+	#     :pdf->Cell(0,5,"Line :i",0,1);
+	# }
+	# :pdf->Output();
+	# 
+ # @return boolean + # @since 1.4 + # @see SetAutoPageBreak() + # + def AcceptPageBreak() + #Accept automatic page break or not + return @auto_page_break; + end + alias_method :accept_page_break, :AcceptPageBreak + + def BreakThePage?(h) + if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak()) + true + else + false + end + end + alias_method :break_the_page?, :BreakThePage? + # + # Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.
+ # If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. + # @param float :w Cell width. If 0, the cell extends up to the right margin. + # @param float :h Cell height. Default value: 0. + # @param string :txt String to print. Default value: empty string. + # @param mixed :border Indicates if borders must be drawn around the cell. The value can be either a number:
  • 0: no border (default)
  • 1: frame
or a string containing some or all of the following characters (in any order):
  • L: left
  • T: top
  • R: right
  • B: bottom
+ # @param int :ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right
  • 1: to the beginning of the next line
  • 2: below
+ # Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + # @param string :align Allows to center or align the text. Possible values are:
  • L or empty string: left align (default value)
  • C: center
  • R: right align
+ # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + # @param mixed :link URL or identifier returned by AddLink(). + # @since 1.0 + # @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak() + # + def Cell(w, h=0, txt='', border=0, ln=0, align='', fill=0, link=nil) + #Output a cell + k=@k; + if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak()) + #Automatic page break + if @pages[@page+1].nil? + x = @x; + ws = @ws; + if (ws > 0) + @ws = 0; + out('0 Tw'); + end + AddPage(@cur_orientation); + @x = x; + if (ws > 0) + @ws = ws; + out(sprintf('%.3f Tw', ws * k)); + end + else + @page += 1; + @y=@t_margin; + end + end + + if (w == 0) + w = @w - @r_margin - @x; + end + s = ''; + if ((fill.to_i == 1) or (border.to_i == 1)) + if (fill.to_i == 1) + op = (border.to_i == 1) ? 'B' : 'f'; + else + op = 'S'; + end + s = sprintf('%.2f %.2f %.2f %.2f re %s ', @x * k, (@h - @y) * k, w * k, -h * k, op); + end + if (border.is_a?(String)) + x=@x; + y=@y; + if (border.include?('L')) + s<0) + # Go to next line + @y += h; + if (ln == 1) + @x = @l_margin; + end + else + @x += w; + end + end + alias_method :cell, :Cell + + # + # This method allows printing text with line breaks. They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.
+ # Text can be aligned, centered or justified. The cell block can be framed and the background painted. + # @param float :w Width of cells. If 0, they extend up to the right margin of the page. + # @param float :h Height of cells. + # @param string :txt String to print + # @param mixed :border Indicates if borders must be drawn around the cell block. The value can be either a number:
  • 0: no border (default)
  • 1: frame
or a string containing some or all of the following characters (in any order):
  • L: left
  • T: top
  • R: right
  • B: bottom
+ # @param string :align Allows to center or align the text. Possible values are:
  • L or empty string: left align
  • C: center
  • R: right align
  • J: justification (default value)
+ # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + # @param int :ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right
  • 1: to the beginning of the next line [DEFAULT]
  • 2: below
+ # @since 1.3 + # @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak() + # + def MultiCell(w, h, txt, border=0, align='J', fill=0, ln=1) + + # save current position + prevx = @x; + prevy = @y; + prevpage = @page; + + #Output text with automatic or explicit line breaks + + if (w == 0) + w = @w - @r_margin - @x; + end + + wmax = (w - 2 * @c_margin); + + s = txt.gsub("\r", ''); # remove carriage returns + nb = s.length; + + b=0; + if (border) + if (border==1) + border='LTRB'; + b='LRT'; + b2='LR'; + elsif border.is_a?(String) + b2=''; + if (border.include?('L')) + b2<<'L'; + end + if (border.include?('R')) + b2<<'R'; + end + b=(border.include?('T')) ? b2 + 'T' : b2; + end + end + sep=-1; + to_index=0; + from_j=0; + l=0; + ns=0; + nl=1; + + while to_index < nb + #Get next character + c = s[to_index]; + if c == "\n"[0] + #Explicit line break + if @ws > 0 + @ws = 0 + out('0 Tw') + end + #Ed Moss - change begin + end_i = to_index == 0 ? 0 : to_index - 1 + # Changed from s[from_j..to_index] to fix bug reported by Hans Allis. + from_j = to_index == 0 ? 1 : from_j + Cell(w, h, s[from_j..end_i], b, 2, align, fill) + #change end + to_index += 1 + sep=-1 + from_j=to_index + l=0 + ns=0 + nl += 1 + b = b2 if border and nl==2 + next + end + if (c == " "[0]) + sep = to_index; + ls = l; + ns += 1; + end + + l = GetStringWidth(s[from_j, to_index - from_j + 1]); + + if (l > wmax) + #Automatic line break + if (sep == -1) + if (to_index == from_j) + to_index += 1; + end + if (@ws > 0) + @ws = 0; + out('0 Tw'); + end + Cell(w, h, s[from_j..to_index-1], b, 2, align, fill) # my FPDF version + else + if (align=='J' || align=='justify' || align=='justified') + @ws = (ns>1) ? (wmax-ls)/(ns-1) : 0; + out(sprintf('%.3f Tw', @ws * @k)); + end + Cell(w, h, s[from_j..sep], b, 2, align, fill); + to_index = sep + 1; + end + sep=-1; + from_j = to_index; + l=0; + ns=0; + nl += 1; + if (border and (nl==2)) + b = b2; + end + else + to_index += 1; + end + end + #Last chunk + if (@ws>0) + @ws=0; + out('0 Tw'); + end + if (border.is_a?(String) and border.include?('B')) + b<<'B'; + end + Cell(w, h, s[from_j, to_index-from_j], b, 2, align, fill); + + # move cursor to specified position + # since 2007-03-03 + if (ln == 1) + # go to the beginning of the next line + @x = @l_margin; + elsif (ln == 0) + # go to the top-right of the cell + @page = prevpage; + @y = prevy; + @x = prevx + w; + elsif (ln == 2) + # go to the bottom-left of the cell + @x = prevx; + end + end + alias_method :multi_cell, :MultiCell + + # + # This method prints text from the current position. When the right margin is reached (or the \n character is met) a line break occurs and text continues from the left margin. Upon method exit, the current position is left just at the end of the text. It is possible to put a link on the text.
+ # Example:
+ #
+	# #Begin with regular font
+	# :pdf->SetFont('Arial','',14);
+	# :pdf->Write(5,'Visit ');
+	# #Then put a blue underlined link
+	# :pdf->SetTextColor(0,0,255);
+	# :pdf->SetFont('','U');
+	# :pdf->Write(5,'www.tecnick.com','http://www.tecnick.com');
+	# 
+ # @param float :h Line height + # @param string :txt String to print + # @param mixed :link URL or identifier returned by AddLink() + # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0. + # @since 1.5 + # @see SetFont(), SetTextColor(), AddLink(), MultiCell(), SetAutoPageBreak() + # + def Write(h, txt, link=nil, fill=0) + + #Output text in flowing mode + w = @w - @r_margin - @x; + wmax = (w - 2 * @c_margin); + + s = txt.gsub("\r", ''); + nb = s.length; + + # handle single space character + if ((nb==1) and (s == " ")) + @x += GetStringWidth(s); + return; + end + + sep=-1; + i=0; + j=0; + l=0; + nl=1; + while(i wmax) + #Automatic line break (word wrapping) + if (sep == -1) + if (@x > @l_margin) + #Move to next line + @x = @l_margin; + @y += h; + w=@w - @r_margin - @x; + wmax=(w - 2 * @c_margin); + i += 1 + nl += 1 + next + end + if (i == j) + i += 1 + end + Cell(w, h, s[j, (i-1)], 0, 2, '', fill, link); + else + Cell(w, h, s[j, (sep-j)], 0, 2, '', fill, link); + i = sep+1; + end + sep = -1; + j = i; + l = 0; + if (nl==1) + @x = @l_margin; + w = @w - @r_margin - @x; + wmax = (w - 2 * @c_margin); + end + nl += 1; + else + i += 1; + end + end + #Last chunk + if (i != j) + Cell(GetStringWidth(s[j..i]), h, s[j..i], 0, 0, '', fill, link); + end + end + alias_method :write, :Write + + # + # Puts an image in the page. The upper-left corner must be given. The dimensions can be specified in different ways:
  • explicit width and height (expressed in user unit)
  • one explicit dimension, the other being calculated automatically in order to keep the original proportions
  • no explicit dimension, in which case the image is put at 72 dpi
+ # Supported formats are JPEG and PNG. + # For JPEG, all flavors are allowed:
  • gray scales
  • true colors (24 bits)
  • CMYK (32 bits)
+ # For PNG, are allowed:
  • gray scales on at most 8 bits (256 levels)
  • indexed colors
  • true colors (24 bits)
+ # but are not supported:
  • Interlacing
  • Alpha channel
+ # If a transparent color is defined, it will be taken into account (but will be only interpreted by Acrobat 4 and above).
+ # The format can be specified explicitly or inferred from the file extension.
+ # It is possible to put a link on the image.
+ # Remark: if an image is used several times, only one copy will be embedded in the file.
+ # @param string :file Name of the file containing the image. + # @param float :x Abscissa of the upper-left corner. + # @param float :y Ordinate of the upper-left corner. + # @param float :w Width of the image in the page. If not specified or equal to zero, it is automatically calculated. + # @param float :h Height of the image in the page. If not specified or equal to zero, it is automatically calculated. + # @param string :type Image format. Possible values are (case insensitive): JPG, JPEG, PNG. If not specified, the type is inferred from the file extension. + # @param mixed :link URL or identifier returned by AddLink(). + # @since 1.1 + # @see AddLink() + # + def Image(file, x, y, w=0, h=0, type='', link=nil) + #Put an image on the page + if (@images[file].nil?) + #First use of image, get info + if (type == '') + pos = File::basename(file).rindex('.'); + if (pos.nil? or pos == 0) + Error('Image file has no extension and no type was specified: ' + file); + end + pos = file.rindex('.'); + type = file[pos+1..-1]; + end + type.downcase! + if (type == 'jpg' or type == 'jpeg') + info=parsejpg(file); + elsif (type == 'png' or type == 'gif') + img = Magick::ImageList.new(file) + img.format = "PNG" # convert to PNG from gif + img.opacity = 0 # PNG alpha channel delete + File.open( @@k_path_cache + File::basename(file), 'w'){|f| + f.binmode + f.print img.to_blob + f.close + } + info=parsepng( @@k_path_cache + File::basename(file)); + File.delete( @@k_path_cache + File::basename(file)) + else + #Allow for additional formats + mtd='parse' + type; + if (!self.respond_to?(mtd)) + Error('Unsupported image type: ' + type); + end + info=send(mtd, file); + end + info['i']=@images.length+1; + @images[file] = info; + else + info=@images[file]; + end + #Automatic width and height calculation if needed + if ((w == 0) and (h == 0)) + rescale_x = (@w - @r_margin - x) / (info['w'] / (@img_scale * @k)) + rescale_x = 1 if rescale_x >= 1 + if (y + info['h'] * rescale_x / (@img_scale * @k) > @page_break_trigger and !@in_footer and AcceptPageBreak()) + #Automatic page break + if @pages[@page+1].nil? + ws = @ws; + if (ws > 0) + @ws = 0; + out('0 Tw'); + end + AddPage(@cur_orientation); + if (ws > 0) + @ws = ws; + out(sprintf('%.3f Tw', ws * @k)); + end + else + @page += 1; + end + y=@t_margin; + end + rescale_y = (@page_break_trigger - y) / (info['h'] / (@img_scale * @k)) + rescale_y = 1 if rescale_y >= 1 + rescale = rescale_y >= rescale_x ? rescale_x : rescale_y + + #Put image at 72 dpi + # 2004-06-14 :: Nicola Asuni, scale factor where added + w = info['w'] * rescale / (@img_scale * @k); + h = info['h'] * rescale / (@img_scale * @k); + elsif (w == 0) + w = h * info['w'] / info['h']; + elsif (h == 0) + h = w * info['h'] / info['w']; + end + out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', w*@k, h*@k, x*@k, (@h-(y+h))*@k, info['i'])); + if (link) + Link(x, y, w, h, link); + end + + #2002-07-31 - Nicola Asuni + # set right-bottom corner coordinates + @img_rb_x = x + w; + @img_rb_y = y + h; + end + alias_method :image, :Image + + # + # Performs a line break. The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter. + # @param float :h The height of the break. By default, the value equals the height of the last printed cell. + # @since 1.0 + # @see Cell() + # + def Ln(h='') + #Line feed; default value is last cell height + @x=@l_margin; + if (h.is_a?(String)) + @y += @lasth; + else + @y += h; + end + + k=@k; + if (@y > @page_break_trigger and !@in_footer and AcceptPageBreak()) + #Automatic page break + if @pages[@page+1].nil? + x = @x; + ws = @ws; + if (ws > 0) + @ws = 0; + out('0 Tw'); + end + AddPage(@cur_orientation); + @x = x; + if (ws > 0) + @ws = ws; + out(sprintf('%.3f Tw', ws * k)); + end + else + @page += 1; + @y=@t_margin; + end + end + + end + alias_method :ln, :Ln + + # + # Returns the abscissa of the current position. + # @return float + # @since 1.2 + # @see SetX(), GetY(), SetY() + # + def GetX() + #Get x position + return @x; + end + alias_method :get_x, :GetX + + # + # Defines the abscissa of the current position. If the passed value is negative, it is relative to the right of the page. + # @param float :x The value of the abscissa. + # @since 1.2 + # @see GetX(), GetY(), SetY(), SetXY() + # + def SetX(x) + #Set x position + if (x>=0) + @x = x; + else + @x=@w+x; + end + end + alias_method :set_x, :SetX + + # + # Returns the ordinate of the current position. + # @return float + # @since 1.0 + # @see SetY(), GetX(), SetX() + # + def GetY() + #Get y position + return @y; + end + alias_method :get_y, :GetY + + # + # Moves the current abscissa back to the left margin and sets the ordinate. If the passed value is negative, it is relative to the bottom of the page. + # @param float :y The value of the ordinate. + # @since 1.0 + # @see GetX(), GetY(), SetY(), SetXY() + # + def SetY(y) + #Set y position and reset x + @x=@l_margin; + if (y>=0) + @y = y; + else + @y=@h+y; + end + end + alias_method :set_y, :SetY + + # + # Defines the abscissa and ordinate of the current position. If the passed values are negative, they are relative respectively to the right and bottom of the page. + # @param float :x The value of the abscissa + # @param float :y The value of the ordinate + # @since 1.2 + # @see SetX(), SetY() + # + def SetXY(x, y) + #Set x and y positions + SetY(y); + SetX(x); + end + alias_method :set_xy, :SetXY + + # + # Send the document to a given destination: string, local file or browser. In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.
+ # The method first calls Close() if necessary to terminate the document. + # @param string :name The name of the file. If not given, the document will be sent to the browser (destination I) with the name doc.pdf. + # @param string :dest Destination where to send the document. It can take one of the following values:
  • I: send the file inline to the browser. The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
  • D: send to the browser and force a file download with the name given by name.
  • F: save to a local file with the name given by name.
  • S: return the document as a string. name is ignored.
If the parameter is not specified but a name is given, destination is F. If no parameter is specified at all, destination is I.
+ # @since 1.0 + # @see Close() + # + def Output(name='', dest='') + #Output PDF to some destination + #Finish document if necessary + if (@state < 3) + Close(); + end + #Normalize parameters + # Boolean no longer supported + # if (dest.is_a?(Boolean)) + # dest = dest ? 'D' : 'F'; + # end + dest = dest.upcase + if (dest=='') + if (name=='') + name='doc.pdf'; + dest='I'; + else + dest='F'; + end + end + case (dest) + when 'I' + # This is PHP specific code + ##Send to standard output + # if (ob_get_contents()) + # Error('Some data has already been output, can\'t send PDF file'); + # end + # if (php_sapi_name()!='cli') + # #We send to a browser + # header('Content-Type: application/pdf'); + # if (headers_sent()) + # Error('Some data has already been output to browser, can\'t send PDF file'); + # end + # header('Content-Length: ' + @buffer.length); + # header('Content-disposition: inline; filename="' + name + '"'); + # end + return @buffer; + + when 'D' + # PHP specific + #Download file + # if (ob_get_contents()) + # Error('Some data has already been output, can\'t send PDF file'); + # end + # if (!_SERVER['HTTP_USER_AGENT'].nil? && SERVER['HTTP_USER_AGENT'].include?('MSIE')) + # header('Content-Type: application/force-download'); + # else + # header('Content-Type: application/octet-stream'); + # end + # if (headers_sent()) + # Error('Some data has already been output to browser, can\'t send PDF file'); + # end + # header('Content-Length: '+ @buffer.length); + # header('Content-disposition: attachment; filename="' + name + '"'); + return @buffer; + + when 'F' + open(name,'wb') do |f| + f.write(@buffer) + end + # PHP code + # #Save to local file + # f=open(name,'wb'); + # if (!f) + # Error('Unable to create output file: ' + name); + # end + # fwrite(f,@buffer,@buffer.length); + # f.close + + when 'S' + #Return as a string + return @buffer; + else + Error('Incorrect output destination: ' + dest); + + end + return ''; + end + alias_method :output, :Output + + # Protected methods + + # + # Check for locale-related bug + # @access protected + # + def dochecks() + #Check for locale-related bug + if (1.1==1) + Error('Don\'t alter the locale before including class file'); + end + #Check for decimal separator + if (sprintf('%.1f',1.0)!='1.0') + setlocale(LC_NUMERIC,'C'); + end + end + + # + # Return fonts path + # @access protected + # + def getfontpath(file) + # Is it in the @@font_path? + if @@font_path + fpath = File.join @@font_path, file + if File.exists?(fpath) + return fpath + end + end + # Is it in this plugin's font folder? + fpath = File.join File.dirname(__FILE__), 'fonts', file + if File.exists?(fpath) + return fpath + end + # Could not find it. + nil + end + + # + # Start document + # @access protected + # + def begindoc() + #Start document + @state=1; + out('%PDF-1.3'); + end + + # + # putpages + # @access protected + # + def putpages() + nb = @page; + if (@alias_nb_pages) + nbstr = UTF8ToUTF16BE(nb.to_s, false); + #Replace number of pages + 1.upto(nb) do |n| + @pages[n].gsub!(@alias_nb_pages, nbstr) + end + end + if @def_orientation=='P' + w_pt=@fw_pt + h_pt=@fh_pt + else + w_pt=@fh_pt + h_pt=@fw_pt + end + filter=(@compress) ? '/Filter /FlateDecode ' : '' + 1.upto(nb) do |n| + #Page + newobj + out('<>>>'; + else + l=@links[pl[4]]; + h=!@orientation_changes[l[0]].nil? ? w_pt : h_pt; + annots<>',1+2*l[0], h-l[1]*@k); + end + end + out(annots + ']'); + end + out('/Contents ' + (@n+1).to_s + ' 0 R>>'); + out('endobj'); + #Page content + p=(@compress) ? gzcompress(@pages[n]) : @pages[n]; + newobj(); + out('<<' + filter + '/Length '+ p.length.to_s + '>>'); + putstream(p); + out('endobj'); + end + #Pages root + @offsets[1]=@buffer.length; + out('1 0 obj'); + out('<>'); + out('endobj'); + end + + # + # Adds fonts + # putfonts + # @access protected + # + def putfonts() + nf=@n; + @diffs.each do |diff| + #Encodings + newobj(); + out('<>'); + out('endobj'); + end + @font_files.each do |file, info| + #Font file embedding + newobj(); + @font_files[file]['n']=@n; + font=''; + open(getfontpath(file),'rb') do |f| + font = f.read(); + end + compressed=(file[-2,2]=='.z'); + if (!compressed && !info['length2'].nil?) + header=((font[0][0])==128); + if (header) + #Strip first binary header + font=font[6]; + end + if header && (font[info['length1']][0] == 128) + #Strip second binary header + font=font[0..info['length1']] + font[info['length1']+6]; + end + end + out('<>'); + open(getfontpath(file),'rb') do |f| + putstream(font) + end + out('endobj'); + end + @fonts.each do |k, font| + #Font objects + @fonts[k]['n']=@n+1; + type = font['type']; + name = font['name']; + if (type=='core') + #Standard font + newobj(); + out('<>'); + out('endobj'); + elsif type == 'Type0' + putType0(font) + elsif (type=='Type1' || type=='TrueType') + #Additional Type1 or TrueType font + newobj(); + out('<>'); + out('endobj'); + #Widths + newobj(); + cw=font['cw']; # & + s='['; + 32.upto(255) do |i| + s << cw[i.chr] + ' '; + end + out(s + ']'); + out('endobj'); + #Descriptor + newobj(); + s='<>'); + out('endobj'); + else + #Allow for additional types + mtd='put' + type.downcase; + if (!self.respond_to?(mtd)) + Error('Unsupported font type: ' + type) + else + self.send(mtd,font) + end + end + end + end + + def putType0(font) + #Type0 + newobj(); + out('<>') + out('endobj') + #CIDFont + newobj() + out('<>') + out('/FontDescriptor '+(@n+1).to_s+' 0 R') + w='/W [1 [' + font['cw'].keys.sort.each {|key| + w+=font['cw'][key].to_s + " " +# ActionController::Base::logger.debug key.to_s +# ActionController::Base::logger.debug font['cw'][key].to_s + } + out(w+'] 231 325 500 631 [500] 326 389 500]') + out('>>') + out('endobj') + #Font descriptor + newobj() + out('<>') + out('endobj') + end + + # + # putimages + # @access protected + # + def putimages() + filter=(@compress) ? '/Filter /FlateDecode ' : ''; + @images.each do |file, info| # was while(list(file, info)=each(@images)) + newobj(); + @images[file]['n']=@n; + out('<>'); + putstream(info['data']); + @images[file]['data']=nil + out('endobj'); + #Palette + if (info['cs']=='Indexed') + newobj(); + pal=(@compress) ? gzcompress(info['pal']) : info['pal']; + out('<<' + filter + '/Length ' + pal.length.to_s + '>>'); + putstream(pal); + out('endobj'); + end + end + end + + # + # putxobjectdict + # @access protected + # + def putxobjectdict() + @images.each_value do |image| + out('/I' + image['i'].to_s + ' ' + image['n'].to_s + ' 0 R'); + end + end + + # + # putresourcedict + # @access protected + # + def putresourcedict() + out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); + out('/Font <<'); + @fonts.each_value do |font| + out('/F' + font['i'].to_s + ' ' + font['n'].to_s + ' 0 R'); + end + out('>>'); + out('/XObject <<'); + putxobjectdict(); + out('>>'); + end + + # + # putresources + # @access protected + # + def putresources() + putfonts(); + putimages(); + #Resource dictionary + @offsets[2]=@buffer.length; + out('2 0 obj'); + out('<<'); + putresourcedict(); + out('>>'); + out('endobj'); + end + + # + # putinfo + # @access protected + # + def putinfo() + out('/Producer ' + textstring(PDF_PRODUCER)); + if (!@title.nil?) + out('/Title ' + textstring(@title)); + end + if (!@subject.nil?) + out('/Subject ' + textstring(@subject)); + end + if (!@author.nil?) + out('/Author ' + textstring(@author)); + end + if (!@keywords.nil?) + out('/Keywords ' + textstring(@keywords)); + end + if (!@creator.nil?) + out('/Creator ' + textstring(@creator)); + end + out('/CreationDate ' + textstring('D:' + Time.now.strftime('%Y%m%d%H%M%S'))); + end + + # + # putcatalog + # @access protected + # + def putcatalog() + out('/Type /Catalog'); + out('/Pages 1 0 R'); + if (@zoom_mode=='fullpage') + out('/OpenAction [3 0 R /Fit]'); + elsif (@zoom_mode=='fullwidth') + out('/OpenAction [3 0 R /FitH null]'); + elsif (@zoom_mode=='real') + out('/OpenAction [3 0 R /XYZ null null 1]'); + elsif (!@zoom_mode.is_a?(String)) + out('/OpenAction [3 0 R /XYZ null null ' + (@zoom_mode/100) + ']'); + end + if (@layout_mode=='single') + out('/PageLayout /SinglePage'); + elsif (@layout_mode=='continuous') + out('/PageLayout /OneColumn'); + elsif (@layout_mode=='two') + out('/PageLayout /TwoColumnLeft'); + end + end + + # + # puttrailer + # @access protected + # + def puttrailer() + out('/Size ' + (@n+1).to_s); + out('/Root ' + @n.to_s + ' 0 R'); + out('/Info ' + (@n-1).to_s + ' 0 R'); + end + + # + # putheader + # @access protected + # + def putheader() + out('%PDF-' + @pdf_version); + end + + # + # enddoc + # @access protected + # + def enddoc() + putheader(); + putpages(); + putresources(); + #Info + newobj(); + out('<<'); + putinfo(); + out('>>'); + out('endobj'); + #Catalog + newobj(); + out('<<'); + putcatalog(); + out('>>'); + out('endobj'); + #Cross-ref + o=@buffer.length; + out('xref'); + out('0 ' + (@n+1).to_s); + out('0000000000 65535 f '); + 1.upto(@n) do |i| + out(sprintf('%010d 00000 n ',@offsets[i])); + end + #Trailer + out('trailer'); + out('<<'); + puttrailer(); + out('>>'); + out('startxref'); + out(o); + out('%%EOF'); + @state=3; + end + + # + # beginpage + # @access protected + # + def beginpage(orientation) + @page += 1; + @pages[@page]=''; + @state=2; + @x=@l_margin; + @y=@t_margin; + @font_family=''; + #Page orientation + if (orientation.empty?) + orientation=@def_orientation; + else + orientation.upcase! + if (orientation!=@def_orientation) + @orientation_changes[@page]=true; + end + end + if (orientation!=@cur_orientation) + #Change orientation + if (orientation=='P') + @w_pt=@fw_pt; + @h_pt=@fh_pt; + @w=@fw; + @h=@fh; + else + @w_pt=@fh_pt; + @h_pt=@fw_pt; + @w=@fh; + @h=@fw; + end + @page_break_trigger=@h-@b_margin; + @cur_orientation = orientation; + end + end + + # + # End of page contents + # @access protected + # + def endpage() + @state=1; + end + + # + # Begin a new object + # @access protected + # + def newobj() + @n += 1; + @offsets[@n]=@buffer.length; + out(@n.to_s + ' 0 obj'); + end + + # + # Underline and Deleted text + # @access protected + # + def dolinetxt(x, y, txt) + up = @current_font['up']; + ut = @current_font['ut']; + w = GetStringWidth(txt) + @ws * txt.count(' '); + sprintf('%.2f %.2f %.2f %.2f re f', x * @k, (@h - (y - up / 1000.0 * @font_size)) * @k, w * @k, -ut / 1000.0 * @font_size_pt); + end + + # + # Extract info from a JPEG file + # @access protected + # + def parsejpg(file) + a=getimagesize(file); + if (a.empty?) + Error('Missing or incorrect image file: ' + file); + end + if (!a[2].nil? and a[2]!='JPEG') + Error('Not a JPEG file: ' + file); + end + if (a['channels'].nil? or a['channels']==3) + colspace='DeviceRGB'; + elsif (a['channels']==4) + colspace='DeviceCMYK'; + else + colspace='DeviceGray'; + end + bpc=!a['bits'].nil? ? a['bits'] : 8; + #Read whole file + data=''; + + open( @@k_path_cache + File::basename(file),'rb') do |f| + data< a[0],'h' => a[1],'cs' => colspace,'bpc' => bpc,'f'=>'DCTDecode','data' => data} + end + + # + # Extract info from a PNG file + # @access protected + # + def parsepng(file) + f=open(file,'rb'); + #Check signature + if (f.read(8)!=137.chr + 'PNG' + 13.chr + 10.chr + 26.chr + 10.chr) + Error('Not a PNG file: ' + file); + end + #Read header chunk + f.read(4); + if (f.read(4)!='IHDR') + Error('Incorrect PNG file: ' + file); + end + w=freadint(f); + h=freadint(f); + bpc=f.read(1).unpack('C')[0]; + if (bpc>8) + Error('16-bit depth not supported: ' + file); + end + ct=f.read(1).unpack('C')[0]; + if (ct==0) + colspace='DeviceGray'; + elsif (ct==2) + colspace='DeviceRGB'; + elsif (ct==3) + colspace='Indexed'; + else + Error('Alpha channel not supported: ' + file); + end + if (f.read(1).unpack('C')[0] != 0) + Error('Unknown compression method: ' + file); + end + if (f.read(1).unpack('C')[0] != 0) + Error('Unknown filter method: ' + file); + end + if (f.read(1).unpack('C')[0] != 0) + Error('Interlacing not supported: ' + file); + end + f.read(4); + parms='/DecodeParms <>'; + #Scan chunks looking for palette, transparency and image data + pal=''; + trns=''; + data=''; + begin + n=freadint(f); + type=f.read(4); + if (type=='PLTE') + #Read palette + pal=f.read( n); + f.read(4); + elsif (type=='tRNS') + #Read transparency info + t=f.read( n); + if (ct==0) + trns = t[1].unpack('C')[0] + elsif (ct==2) + trns = t[[1].unpack('C')[0], t[3].unpack('C')[0], t[5].unpack('C')[0]] + else + pos=t.include?(0.chr); + if (pos!=false) + trns = [pos] + end + end + f.read(4); + elsif (type=='IDAT') + #Read image data block + data< w, 'h' => h, 'cs' => colspace, 'bpc' => bpc, 'f'=>'FlateDecode', 'parms' => parms, 'pal' => pal, 'trns' => trns, 'data' => data} + end + + # + # Read a 4-byte integer from file + # @access protected + # + def freadint(f) + # Read a 4-byte integer from file + a = f.read(4).unpack('N') + return a[0] + end + + # + # Format a text string + # @access protected + # + def textstring(s) + if (@is_unicode) + #Convert string to UTF-16BE + s = UTF8ToUTF16BE(s, true); + end + return '(' + escape(s) + ')'; + end + + # + # Format a text string + # @access protected + # + def escapetext(s) + if (@is_unicode) + #Convert string to UTF-16BE + s = UTF8ToUTF16BE(s, false); + end + return escape(s); + end + + # + # Add \ before \, ( and ) + # @access protected + # + def escape(s) + # Add \ before \, ( and ) + s.gsub('\\','\\\\\\').gsub('(','\\(').gsub(')','\\)').gsub(13.chr, '\r') + end + + # + # + # @access protected + # + def putstream(s) + out('stream'); + out(s); + out('endstream'); + end + + # + # Add a line to the document + # @access protected + # + def out(s) + if (@state==2) + @pages[@page] << s.to_s + "\n"; + else + @buffer << s.to_s + "\n"; + end + end + + # + # Adds unicode fonts.
+ # Based on PDF Reference 1.3 (section 5) + # @access protected + # @author Nicola Asuni + # @since 1.52.0.TC005 (2005-01-05) + # + def puttruetypeunicode(font) + # Type0 Font + # A composite font composed of other fonts, organized hierarchically + newobj(); + out('<>'); + out('endobj'); + + # CIDFontType2 + # A CIDFont whose glyph descriptions are based on TrueType font technology + newobj(); + out('<>'); + out('endobj'); + + # ToUnicode + # is a stream object that contains the definition of the CMap + # (PDF Reference 1.3 chap. 5.9) + newobj(); + out('<>'); + out('stream'); + out('/CIDInit /ProcSet findresource begin'); + out('12 dict begin'); + out('begincmap'); + out('/CIDSystemInfo'); + out('<> def'); + out('/CMapName /Adobe-Identity-UCS def'); + out('/CMapType 2 def'); + out('1 begincodespacerange'); + out('<0000> '); + out('endcodespacerange'); + out('1 beginbfrange'); + out('<0000> <0000>'); + out('endbfrange'); + out('endcmap'); + out('CMapName currentdict /CMap defineresource pop'); + out('end'); + out('end'); + out('endstream'); + out('endobj'); + + # CIDSystemInfo dictionary + # A dictionary containing entries that define the character collection of the CIDFont. + newobj(); + out('<>'); + out('endobj'); + + # Font descriptor + # A font descriptor describing the CIDFont default metrics other than its glyph widths + newobj(); + out('<>'); + out('endobj'); + + # Embed CIDToGIDMap + # A specification of the mapping from CIDs to glyph indices + newobj(); + ctgfile = getfontpath(font['ctg']) + if (!ctgfile) + Error('Font file not found: ' + ctgfile); + end + size = File.size(ctgfile); + out('<>'); + open(ctgfile, "rb") do |f| + putstream(f.read()) + end + out('endobj'); + end + + # + # Converts UTF-8 strings to codepoints array.
+ # Invalid byte sequences will be replaced with 0xFFFD (replacement character)
+ # Based on: http://www.faqs.org/rfcs/rfc3629.html + #
+	# 	  Char. number range  |        UTF-8 octet sequence
+	#       (hexadecimal)    |              (binary)
+	#    --------------------+-----------------------------------------------
+	#    0000 0000-0000 007F | 0xxxxxxx
+	#    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+	#    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+	#    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+	#    ---------------------------------------------------------------------
+	#
+	#   ABFN notation:
+	#   ---------------------------------------------------------------------
+	#   UTF8-octets =#( UTF8-char )
+	#   UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
+	#   UTF8-1      = %x00-7F
+	#   UTF8-2      = %xC2-DF UTF8-tail
+	#
+	#   UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
+	#                 %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
+	#   UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
+	#                 %xF4 %x80-8F 2( UTF8-tail )
+	#   UTF8-tail   = %x80-BF
+	#   ---------------------------------------------------------------------
+	# 
+ # @param string :str string to process. + # @return array containing codepoints (UTF-8 characters values) + # @access protected + # @author Nicola Asuni + # @since 1.53.0.TC005 (2005-01-05) + # + def UTF8StringToArray(str) + if (!@is_unicode) + return str; # string is not in unicode + end + + unicode = [] # array containing unicode values + bytes = [] # array containing single character byte sequences + numbytes = 1; # number of octetc needed to represent the UTF-8 character + + str = str.to_s; # force :str to be a string + + str.each_byte do |char| + if (bytes.length == 0) # get starting octect + if (char <= 0x7F) + unicode << char # use the character "as is" because is ASCII + numbytes = 1 + elsif ((char >> 0x05) == 0x06) # 2 bytes character (0x06 = 110 BIN) + bytes << ((char - 0xC0) << 0x06) + numbytes = 2 + elsif ((char >> 0x04) == 0x0E) # 3 bytes character (0x0E = 1110 BIN) + bytes << ((char - 0xE0) << 0x0C) + numbytes = 3 + elsif ((char >> 0x03) == 0x1E) # 4 bytes character (0x1E = 11110 BIN) + bytes << ((char - 0xF0) << 0x12) + numbytes = 4 + else + # use replacement character for other invalid sequences + unicode << 0xFFFD + bytes = [] + numbytes = 1 + end + elsif ((char >> 0x06) == 0x02) # bytes 2, 3 and 4 must start with 0x02 = 10 BIN + bytes << (char - 0x80) + if (bytes.length == numbytes) + # compose UTF-8 bytes to a single unicode value + char = bytes[0] + 1.upto(numbytes-1) do |j| + char += (bytes[j] << ((numbytes - j - 1) * 0x06)) + end + if (((char >= 0xD800) and (char <= 0xDFFF)) or (char >= 0x10FFFF)) + # The definition of UTF-8 prohibits encoding character numbers between + # U+D800 and U+DFFF, which are reserved for use with the UTF-16 + # encoding form (as surrogate pairs) and do not directly represent + # characters + unicode << 0xFFFD; # use replacement character + else + unicode << char; # add char to array + end + # reset data for next char + bytes = [] + numbytes = 1; + end + else + # use replacement character for other invalid sequences + unicode << 0xFFFD; + bytes = [] + numbytes = 1; + end + end + return unicode; + end + + # + # Converts UTF-8 strings to UTF16-BE.
+ # Based on: http://www.faqs.org/rfcs/rfc2781.html + #
+	#   Encoding UTF-16:
+	# 
+		#   Encoding of a single character from an ISO 10646 character value to
+	#    UTF-16 proceeds as follows. Let U be the character number, no greater
+	#    than 0x10FFFF.
+	# 
+	#    1) If U < 0x10000, encode U as a 16-bit unsigned integer and
+	#       terminate.
+	# 
+	#    2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
+	#       U' must be less than or equal to 0xFFFFF. That is, U' can be
+	#       represented in 20 bits.
+	# 
+	#    3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
+	#       0xDC00, respectively. These integers each have 10 bits free to
+	#       encode the character value, for a total of 20 bits.
+	# 
+	#    4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
+	#       bits of W1 and the 10 low-order bits of U' to the 10 low-order
+	#       bits of W2. Terminate.
+	# 
+	#    Graphically, steps 2 through 4 look like:
+	#    U' = yyyyyyyyyyxxxxxxxxxx
+	#    W1 = 110110yyyyyyyyyy
+	#    W2 = 110111xxxxxxxxxx
+	# 
+ # @param string :str string to process. + # @param boolean :setbom if true set the Byte Order Mark (BOM = 0xFEFF) + # @return string + # @access protected + # @author Nicola Asuni + # @since 1.53.0.TC005 (2005-01-05) + # @uses UTF8StringToArray + # + def UTF8ToUTF16BE(str, setbom=true) + if (!@is_unicode) + return str; # string is not in unicode + end + outstr = ""; # string to be returned + unicode = UTF8StringToArray(str); # array containing UTF-8 unicode values + numitems = unicode.length; + + if (setbom) + outstr << "\xFE\xFF"; # Byte Order Mark (BOM) + end + unicode.each do |char| + if (char == 0xFFFD) + outstr << "\xFF\xFD"; # replacement character + elsif (char < 0x10000) + outstr << (char >> 0x08).chr; + outstr << (char & 0xFF).chr; + else + char -= 0x10000; + w1 = 0xD800 | (char >> 0x10); + w2 = 0xDC00 | (char & 0x3FF); + outstr << (w1 >> 0x08).chr; + outstr << (w1 & 0xFF).chr; + outstr << (w2 >> 0x08).chr; + outstr << (w2 & 0xFF).chr; + end + end + return outstr; + end + + # ==================================================== + + # + # Set header font. + # @param array :font font + # @since 1.1 + # + def SetHeaderFont(font) + @header_font = font; + end + alias_method :set_header_font, :SetHeaderFont + + # + # Set footer font. + # @param array :font font + # @since 1.1 + # + def SetFooterFont(font) + @footer_font = font; + end + alias_method :set_footer_font, :SetFooterFont + + # + # Set language array. + # @param array :language + # @since 1.1 + # + def SetLanguageArray(language) + @l = language; + end + alias_method :set_language_array, :SetLanguageArray + # + # Set document barcode. + # @param string :bc barcode + # + def SetBarcode(bc="") + @barcode = bc; + end + + # + # Print Barcode. + # @param int :x x position in user units + # @param int :y y position in user units + # @param int :w width in user units + # @param int :h height position in user units + # @param string :type type of barcode (I25, C128A, C128B, C128C, C39) + # @param string :style barcode style + # @param string :font font for text + # @param int :xres x resolution + # @param string :code code to print + # + def writeBarcode(x, y, w, h, type, style, font, xres, code) + require(File.dirname(__FILE__) + "/barcode/barcode.rb"); + require(File.dirname(__FILE__) + "/barcode/i25object.rb"); + require(File.dirname(__FILE__) + "/barcode/c39object.rb"); + require(File.dirname(__FILE__) + "/barcode/c128aobject.rb"); + require(File.dirname(__FILE__) + "/barcode/c128bobject.rb"); + require(File.dirname(__FILE__) + "/barcode/c128cobject.rb"); + + if (code.empty?) + return; + end + + if (style.empty?) + style = BCS_ALIGN_LEFT; + style |= BCS_IMAGE_PNG; + style |= BCS_TRANSPARENT; + #:style |= BCS_BORDER; + #:style |= BCS_DRAW_TEXT; + #:style |= BCS_STRETCH_TEXT; + #:style |= BCS_REVERSE_COLOR; + end + if (font.empty?) then font = BCD_DEFAULT_FONT; end + if (xres.empty?) then xres = BCD_DEFAULT_XRES; end + + scale_factor = 1.5 * xres * @k; + bc_w = (w * scale_factor).round #width in points + bc_h = (h * scale_factor).round #height in points + + case (type.upcase) + when "I25" + obj = I25Object.new(bc_w, bc_h, style, code); + when "C128A" + obj = C128AObject.new(bc_w, bc_h, style, code); + when "C128B" + obj = C128BObject.new(bc_w, bc_h, style, code); + when "C128C" + obj = C128CObject.new(bc_w, bc_h, style, code); + when "C39" + obj = C39Object.new(bc_w, bc_h, style, code); + end + + obj.SetFont(font); + obj.DrawObject(xres); + + #use a temporary file.... + tmpName = tempnam(@@k_path_cache,'img'); + imagepng(obj.getImage(), tmpName); + Image(tmpName, x, y, w, h, 'png'); + obj.DestroyObject(); + obj = nil + unlink(tmpName); + end + + # + # Returns the PDF data. + # + def GetPDFData() + if (@state < 3) + Close(); + end + return @buffer; + end + + # --- HTML PARSER FUNCTIONS --- + + # + # Allows to preserve some HTML formatting.
+ # Supports: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, ins, del, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small + # @param string :html text to display + # @param boolean :ln if true add a new line after text (default = true) + # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0. + # + def writeHTML(html, ln=true, fill=0, h=0) + + @lasth = h if h > 0 + if (@lasth == 0) + #set row height + @lasth = @font_size * @@k_cell_height_ratio; + end + + @href = nil + @style = ""; + @t_cells = [[]]; + @table_id = 0; + + # pre calculate + html.split(/(<[^>]+>)/).each do |element| + if "<" == element[0,1] + #Tag + if (element[1, 1] == '/') + closedHTMLTagCalc(element[2..-2].downcase); + else + #Extract attributes + # get tag name + tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0} + tag = tag[0].downcase; + + # get attributes + attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/) + attrs = {} + attr_array.each do |name, value| + attrs[name.downcase] = value; + end + openHTMLTagCalc(tag, attrs); + end + end + end + @table_id = 0; + + html.split(/(<[A-Za-z!?\/][^>]*?>)/).each do |element| + if "<" == element[0,1] + #Tag + if (element[1, 1] == '/') + closedHTMLTagHandler(element[2..-2].downcase); + else + #Extract attributes + # get tag name + tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0} + tag = tag[0].downcase; + + # get attributes + attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/) + attrs = {} + attr_array.each do |name, value| + attrs[name.downcase] = value; + end + openHTMLTagHandler(tag, attrs, fill); + end + + else + #Text + if (@href) + element.gsub!(/[\t\r\n\f]/, ""); + addHtmlLink(@href, element, fill); + elsif (@tdbegin) + element.gsub!(/[\t\r\n\f]/, ""); + element.gsub!(/ /, " "); + base_page = @page; + base_x = @x; + base_y = @y; + + MultiCell(@tdwidth, @tdheight, unhtmlentities(element.strip), @tableborder, @tdalign, @tdfill, 1); + tr_end = @t_cells[@table_id][@tr_id][@td_id]['j1'] + 1; + if @max_td_page[tr_end].nil? or (@max_td_page[tr_end] < @page) + @max_td_page[tr_end] = @page + @max_td_y[tr_end] = @y + elsif (@max_td_page[tr_end] == @page) + @max_td_y[tr_end] = @y if @max_td_y[tr_end].nil? or (@max_td_y[tr_end] < @y) + end + + @page = base_page; + @x = base_x + @tdwidth; + @y = base_y; + elsif (@pre_state == true and element.length > 0) + Write(@lasth, unhtmlentities(element), '', fill); + elsif (element.strip.length > 0) + element.gsub!(/[\t\r\n\f]/, ""); + element.gsub!(/ /, " "); + Write(@lasth, unhtmlentities(element), '', fill); + end + end + end + + if (ln) + Ln(@lasth); + end + end + alias_method :write_html, :writeHTML + + # + # Prints a cell (rectangular area) with optional borders, background color and html text string. The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.
+ # If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting. + # @param float :w Cell width. If 0, the cell extends up to the right margin. + # @param float :h Cell minimum height. The cell extends automatically if needed. + # @param float :x upper-left corner X coordinate + # @param float :y upper-left corner Y coordinate + # @param string :html html text to print. Default value: empty string. + # @param mixed :border Indicates if borders must be drawn around the cell. The value can be either a number:
  • 0: no border (default)
  • 1: frame
or a string containing some or all of the following characters (in any order):
  • L: left
  • T: top
  • R: right
  • B: bottom
+ # @param int :ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right
  • 1: to the beginning of the next line
  • 2: below
+# Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + # @see Cell() + # + def writeHTMLCell(w, h, x, y, html='', border=0, ln=1, fill=0) + + if (@lasth == 0) + #set row height + @lasth = @font_size * @@k_cell_height_ratio; + end + + if (x == 0) + x = GetX(); + end + if (y == 0) + y = GetY(); + end + + # get current page number + pagenum = @page; + + SetX(x); + SetY(y); + + if (w == 0) + w = @fw - x - @r_margin; + end + + b=0; + if (border) + if (border==1) + border='LTRB'; + b='LRT'; + b2='LR'; + elsif border.is_a?(String) + b2=''; + if (border.include?('L')) + b2<<'L'; + end + if (border.include?('R')) + b2<<'R'; + end + b=(border.include?('T')) ? b2 + 'T' : b2; + end + end + + # store original margin values + l_margin = @l_margin; + r_margin = @r_margin; + + # set new margin values + SetLeftMargin(x); + SetRightMargin(@fw - x - w); + + # calculate remaining vertical space on page + restspace = GetPageHeight() - GetY() - GetBreakMargin(); + + writeHTML(html, true, fill); # write html text + + currentY = GetY(); + + @auto_page_break = false; + # check if a new page has been created + if (@page > pagenum) + # design a cell around the text on first page + currentpage = @page; + @page = pagenum; + SetY(GetPageHeight() - restspace - GetBreakMargin()); + Cell(w, restspace - 1, "", b, 0, 'L', 0); + b = b2; + @page += 1; + while @page < currentpage + SetY(@t_margin); # put cursor at the beginning of text + Cell(w, @page_break_trigger - @t_margin, "", b, 0, 'L', 0); + @page += 1; + end + if (border.is_a?(String) and border.include?('B')) + b<<'B'; + end + # design a cell around the text on last page + SetY(@t_margin); # put cursor at the beginning of text + Cell(w, currentY - @t_margin, "", b, 0, 'L', 0); + else + SetY(y); # put cursor at the beginning of text + # design a cell around the text + Cell(w, [h, (currentY - y)].max, "", border, 0, 'L', 0); + end + @auto_page_break = true; + + # restore original margin values + SetLeftMargin(l_margin); + SetRightMargin(r_margin); + + @lasth = h + + # move cursor to specified position + if (ln == 0) + # go to the top-right of the cell + @x = x + w; + @y = y; + elsif (ln == 1) + # go to the beginning of the next line + @x = @l_margin; + @y = currentY; + elsif (ln == 2) + # go to the bottom-left of the cell (below) + @x = x; + @y = currentY; + end + end + alias_method :write_html_cell, :writeHTMLCell + + # + # Check html table tag position. + # + # @param array :table potision array + # @param int :current tr tag id number + # @param int :current td tag id number + # @access private + # @return int : next td_id position. + # value 0 mean that can use position. + # + def checkTableBlockingCellPosition(table, tr_id, td_id ) + 0.upto(tr_id) do |j| + 0.upto(@t_cells[table][j].size - 1) do |i| + if @t_cells[table][j][i]['i0'] <= td_id and td_id <= @t_cells[table][j][i]['i1'] + if @t_cells[table][j][i]['j0'] <= tr_id and tr_id <= @t_cells[table][j][i]['j1'] + return @t_cells[table][j][i]['i1'] - td_id + 1; + end + end + end + end + return 0; + end + + # + # Calculate opening tags. + # + # html table cell array : @t_cells + # + # i0: table cell start position + # i1: table cell end position + # j0: table row start position + # j1: table row end position + # + # +------+ + # |i0,j0 | + # | i1,j1| + # +------+ + # + # example html: + # + # + # + # + # + #
+ # + # i: 0 1 2 + # j+----+----+----+ + # :|0,0 |1,0 |2,0 | + # 0| 0,0| 1,0| 2,0| + # +----+----+----+ + # |0,1 |2,1 | + # 1| 1,1| 2,1| + # +----+----+----+ + # |0,2 |1,2 |2,2 | + # 2| | 1,2| 2,2| + # + +----+----+ + # | |1,3 |2,3 | + # 3| 0,3| 1,3| 2,3| + # +----+----+----+ + # + # html table cell array : + # [[[i0=>0,j0=>0,i1=>0,j1=>0],[i0=>1,j0=>0,i1=>1,j1=>0],[i0=>2,j0=>0,i1=>2,j1=>0]], + # [[i0=>0,j0=>1,i1=>1,j1=>1],[i0=>2,j0=>1,i1=>2,j1=>1]], + # [[i0=>0,j0=>2,i1=>0,j1=>3],[i0=>1,j0=>2,i1=>1,j1=>2],[i0=>2,j0=>2,i1=>2,j1=>2]] + # [[i0=>1,j0=>3,i1=>1,j1=>3],[i0=>2,j0=>3,i1=>2,j1=>3]]] + # + # @param string :tag tag name (in upcase) + # @param string :attr tag attribute (in upcase) + # @access private + # + def openHTMLTagCalc(tag, attrs) + #Opening tag + case (tag) + when 'table' + @max_table_columns[@table_id] = 0; + @t_columns = 0; + @tr_id = -1; + when 'tr' + if @max_table_columns[@table_id] < @t_columns + @max_table_columns[@table_id] = @t_columns; + end + @t_columns = 0; + @tr_id += 1; + @td_id = -1; + @t_cells[@table_id].push [] + when 'td', 'th' + @td_id += 1; + if attrs['colspan'].nil? or attrs['colspan'] == '' + colspan = 1; + else + colspan = attrs['colspan'].to_i; + end + if attrs['rowspan'].nil? or attrs['rowspan'] == '' + rowspan = 1; + else + rowspan = attrs['rowspan'].to_i; + end + + i = 0; + while true + next_i_distance = checkTableBlockingCellPosition(@table_id, @tr_id, @td_id + i); + if next_i_distance == 0 + @t_cells[@table_id][@tr_id].push "i0"=>@td_id + i, "j0"=>@tr_id, "i1"=>(@td_id + i + colspan - 1), "j1"=>@tr_id + rowspan - 1 + break; + end + i += next_i_distance; + end + + @t_columns += colspan; + end + end + + # + # Calculate closing tags. + # @param string :tag tag name (in upcase) + # @access private + # + def closedHTMLTagCalc(tag) + #Closing tag + case (tag) + when 'table' + if @max_table_columns[@table_id] < @t_columns + @max_table_columns[@table_id] = @t_columns; + end + @table_id += 1; + @t_cells.push [] + end + end + + # + # Convert to accessible file path + # @param string :attrname image file name + # + def getImageFilename( attrname ) + nil + end + + # + # Process opening tags. + # @param string :tag tag name (in upcase) + # @param string :attr tag attribute (in upcase) + # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + # @access private + # + def openHTMLTagHandler(tag, attrs, fill=0) + #Opening tag + case (tag) + when 'pre' + @pre_state = true; + @l_margin += 5; + @r_margin += 5; + @x += 5; + + when 'table' + if @default_table_columns < @max_table_columns[@table_id] + @table_columns = @max_table_columns[@table_id]; + else + @table_columns = @default_table_columns; + end + @l_margin += 5; + @r_margin += 5; + @x += 5; + + if attrs['border'].nil? or attrs['border'] == '' + @tableborder = 0; + else + @tableborder = attrs['border']; + end + @tr_id = -1; + @max_td_page[0] = @page; + @max_td_y[0] = @y; + + when 'tr', 'td', 'th' + if tag == 'th' + SetStyle('b', true); + @tdalign = "C"; + end + if ((!attrs['width'].nil?) and (attrs['width'] != '')) + @tdwidth = (attrs['width'].to_i/4); + else + @tdwidth = ((@w - @l_margin - @r_margin) / @table_columns); + end + + if tag == 'tr' + @tr_id += 1; + @td_id = -1; + else + @td_id += 1; + @x = @l_margin + @tdwidth * @t_cells[@table_id][@tr_id][@td_id]['i0']; + end + + if attrs['colspan'].nil? or attrs['border'] == '' + @colspan = 1; + else + @colspan = attrs['colspan'].to_i; + end + @tdwidth *= @colspan; + if ((!attrs['height'].nil?) and (attrs['height'] != '')) + @tdheight=(attrs['height'].to_i / @k); + else + @tdheight = @lasth; + end + if ((!attrs['align'].nil?) and (attrs['align'] != '')) + case (attrs['align']) + when 'center' + @tdalign = "C"; + when 'right' + @tdalign = "R"; + when 'left' + @tdalign = "L"; + end + end + if ((!attrs['bgcolor'].nil?) and (attrs['bgcolor'] != '')) + coul = convertColorHexToDec(attrs['bgcolor']); + SetFillColor(coul['R'], coul['G'], coul['B']); + @tdfill=1; + end + @tdbegin=true; + + when 'hr' + margin = 1; + if ((!attrs['width'].nil?) and (attrs['width'] != '')) + hrWidth = attrs['width']; + else + hrWidth = @w - @l_margin - @r_margin - margin; + end + SetLineWidth(0.2); + Line(@x + margin, @y, @x + hrWidth, @y); + Ln(); + + when 'strong' + SetStyle('b', true); + + when 'em' + SetStyle('i', true); + + when 'ins' + SetStyle('u', true); + + when 'del' + SetStyle('d', true); + + when 'b', 'i', 'u' + SetStyle(tag, true); + + when 'a' + @href = attrs['href']; + + when 'img' + if (!attrs['src'].nil?) + # Only generates image include a pdf if RMagick is avalaible + unless Object.const_defined?(:Magick) + Write(@lasth, attrs['src'], '', fill); + return + end + file = getImageFilename(attrs['src']) + if (file.nil?) + Write(@lasth, attrs['src'], '', fill); + return + end + + if (attrs['width'].nil?) + attrs['width'] = 0; + end + if (attrs['height'].nil?) + attrs['height'] = 0; + end + + begin + Image(file, GetX(),GetY(), pixelsToMillimeters(attrs['width']), pixelsToMillimeters(attrs['height'])); + #SetX(@img_rb_x); + SetY(@img_rb_y); + rescue => err + logger.error "pdf: Image: error: #{err.message}" + Write(@lasth, attrs['src'], '', fill); + if File.file?( @@k_path_cache + File::basename(file)) + File.delete( @@k_path_cache + File::basename(file)) + end + end + end + + when 'ul', 'ol' + if @li_count == 0 + Ln() if @prevquote_count == @quote_count; # insert Ln for keeping quote lines + @prevquote_count = @quote_count; + end + if @li_state == true + Ln(); + @li_state = false; + end + if tag == 'ul' + @list_ordered[@li_count] = false; + else + @list_ordered[@li_count] = true; + end + @list_count[@li_count] = 0; + @li_count += 1 + + when 'li' + Ln() if @li_state == true + if (@list_ordered[@li_count - 1]) + @list_count[@li_count - 1] += 1; + @li_spacer = " " * @li_count + (@list_count[@li_count - 1]).to_s + ". "; + else + #unordered list simbol + @li_spacer = " " * @li_count + "- "; + end + Write(@lasth, @spacer + @li_spacer, '', fill); + @li_state = true; + + when 'blockquote' + if (@quote_count == 0) + SetStyle('i', true); + @l_margin += 5; + else + @l_margin += 5 / 2; + end + @x = @l_margin; + @quote_top[@quote_count] = @y; + @quote_page[@quote_count] = @page; + @quote_count += 1 + when 'br' + Ln(); + + if (@li_spacer.length > 0) + @x += GetStringWidth(@li_spacer); + end + + when 'p' + Ln(); + 0.upto(@quote_count - 1) do |i| + if @quote_page[i] == @page; + if @quote_top[i] == @y - @lasth; # fix start line + @quote_top[i] = @y; + end + else + if @quote_page[i] == @page - 1; + @quote_page[i] = @page; # fix start line + @quote_top[i] = @t_margin; + end + end + end + + when 'sup' + currentfont_size = @font_size; + @tempfontsize = @font_size_pt; + SetFontSize(@font_size_pt * @@k_small_ratio); + SetXY(GetX(), GetY() - ((currentfont_size - @font_size)*(@@k_small_ratio))); + + when 'sub' + currentfont_size = @font_size; + @tempfontsize = @font_size_pt; + SetFontSize(@font_size_pt * @@k_small_ratio); + SetXY(GetX(), GetY() + ((currentfont_size - @font_size)*(@@k_small_ratio))); + + when 'small' + currentfont_size = @font_size; + @tempfontsize = @font_size_pt; + SetFontSize(@font_size_pt * @@k_small_ratio); + SetXY(GetX(), GetY() + ((currentfont_size - @font_size)/3)); + + when 'font' + if (!attrs['color'].nil? and attrs['color']!='') + coul = convertColorHexToDec(attrs['color']); + SetTextColor(coul['R'], coul['G'], coul['B']); + @issetcolor=true; + end + if (!attrs['face'].nil? and @fontlist.include?(attrs['face'].downcase)) + SetFont(attrs['face'].downcase); + @issetfont=true; + end + if (!attrs['size'].nil?) + headsize = attrs['size'].to_i; + else + headsize = 0; + end + currentfont_size = @font_size; + @tempfontsize = @font_size_pt; + SetFontSize(@font_size_pt + headsize); + @lasth = @font_size * @@k_cell_height_ratio; + + when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' + Ln(); + headsize = (4 - tag[1,1].to_f) * 2 + @tempfontsize = @font_size_pt; + SetFontSize(@font_size_pt + headsize); + SetStyle('b', true); + @lasth = @font_size * @@k_cell_height_ratio; + + end + end + + # + # Process closing tags. + # @param string :tag tag name (in upcase) + # @access private + # + def closedHTMLTagHandler(tag) + #Closing tag + case (tag) + when 'pre' + @pre_state = false; + @l_margin -= 5; + @r_margin -= 5; + @x = @l_margin; + Ln(); + + when 'td','th' + @tdbegin = false; + @tdwidth = 0; + @tdheight = 0; + @tdalign = "L"; + SetStyle('b', false); + @tdfill = 0; + SetFillColor(@prevfill_color[0], @prevfill_color[1], @prevfill_color[2]); + + when 'tr' + @y = @max_td_y[@tr_id + 1]; + @x = @l_margin; + @page = @max_td_page[@tr_id + 1]; + + when 'table' + # Write Table Line + width = (@w - @l_margin - @r_margin) / @table_columns; + 0.upto(@t_cells[@table_id].size - 1) do |j| + 0.upto(@t_cells[@table_id][j].size - 1) do |i| + @page = @max_td_page[j] + i0=@t_cells[@table_id][j][i]['i0']; + j0=@t_cells[@table_id][j][i]['j0']; + i1=@t_cells[@table_id][j][i]['i1']; + j1=@t_cells[@table_id][j][i]['j1']; + + Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j0]) # top + if ( @page == @max_td_page[j1 + 1]) + Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @max_td_y[j1+1]) # left + Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j1+1]) # right + else + Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @page_break_trigger) # left + Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @page_break_trigger) # right + @page += 1; + while @page < @max_td_page[j1 + 1] + Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @page_break_trigger) # left + Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @page_break_trigger) # right + @page += 1; + end + Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @max_td_y[j1+1]) # left + Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @max_td_y[j1+1]) # right + end + Line(@l_margin + width * i0, @max_td_y[j1+1], @l_margin + width * (i1+1), @max_td_y[j1+1]) # bottom + end + end + + @l_margin -= 5; + @r_margin -= 5; + @tableborder=0; + Ln(); + @table_id += 1; + + when 'strong' + SetStyle('b', false); + + when 'em' + SetStyle('i', false); + + when 'ins' + SetStyle('u', false); + + when 'del' + SetStyle('d', false); + + when 'b', 'i', 'u' + SetStyle(tag, false); + + when 'a' + @href = nil; + + when 'p' + Ln(); + + when 'sup' + currentfont_size = @font_size; + SetFontSize(@tempfontsize); + @tempfontsize = @font_size_pt; + SetXY(GetX(), GetY() - ((currentfont_size - @font_size)*(@@k_small_ratio))); + + when 'sub' + currentfont_size = @font_size; + SetFontSize(@tempfontsize); + @tempfontsize = @font_size_pt; + SetXY(GetX(), GetY() + ((currentfont_size - @font_size)*(@@k_small_ratio))); + + when 'small' + currentfont_size = @font_size; + SetFontSize(@tempfontsize); + @tempfontsize = @font_size_pt; + SetXY(GetX(), GetY() - ((@font_size - currentfont_size)/3)); + + when 'font' + if (@issetcolor == true) + SetTextColor(@prevtext_color[0], @prevtext_color[1], @prevtext_color[2]); + end + if (@issetfont) + @font_family = @prevfont_family; + @font_style = @prevfont_style; + SetFont(@font_family); + @issetfont = false; + end + currentfont_size = @font_size; + SetFontSize(@tempfontsize); + @tempfontsize = @font_size_pt; + #@text_color = @prevtext_color; + @lasth = @font_size * @@k_cell_height_ratio; + + when 'blockquote' + @quote_count -= 1 + if (@quote_page[@quote_count] == @page) + Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @y) # quoto line + else + cur_page = @page; + cur_y = @y; + @page = @quote_page[@quote_count]; + if (@quote_top[@quote_count] < @page_break_trigger) + Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @page_break_trigger) # quoto line + end + @page += 1; + while @page < cur_page + Line(@l_margin - 1, @t_margin, @l_margin - 1, @page_break_trigger) # quoto line + @page += 1; + end + @y = cur_y; + Line(@l_margin - 1, @t_margin, @l_margin - 1, @y) # quoto line + end + if (@quote_count <= 0) + SetStyle('i', false); + @l_margin -= 5; + else + @l_margin -= 5 / 2; + end + @x = @l_margin; + Ln() if @quote_count == 0 + + when 'ul', 'ol' + @li_count -= 1 + if @li_state == true + Ln(); + @li_state = false; + end + + when 'li' + @li_spacer = ""; + if @li_state == true + Ln(); + @li_state = false; + end + + when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' + SetFontSize(@tempfontsize); + @tempfontsize = @font_size_pt; + SetStyle('b', false); + Ln(); + @lasth = @font_size * @@k_cell_height_ratio; + + if tag == 'h1' or tag == 'h2' or tag == 'h3' or tag == 'h4' + margin = 1; + hrWidth = @w - @l_margin - @r_margin - margin; + if tag == 'h1' or tag == 'h2' + SetLineWidth(0.2); + else + SetLineWidth(0.1); + end + Line(@x + margin, @y, @x + hrWidth, @y); + end + end + end + + # + # Sets font style. + # @param string :tag tag name (in lowercase) + # @param boolean :enable + # @access private + # + def SetStyle(tag, enable) + #Modify style and select corresponding font + ['b', 'i', 'u', 'd'].each do |s| + if tag.downcase == s + if enable + @style << s if ! @style.include?(s) + else + @style = @style.gsub(s,'') + end + end + end + SetFont('', @style); + end + + # + # Output anchor link. + # @param string :url link URL + # @param string :name link name + # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + # @access public + # + def addHtmlLink(url, name, fill=0) + #Put a hyperlink + SetTextColor(0, 0, 255); + SetStyle('u', true); + Write(@lasth, name, url, fill); + SetStyle('u', false); + SetTextColor(0); + end + + # + # Returns an associative array (keys: R,G,B) from + # a hex html code (e.g. #3FE5AA). + # @param string :color hexadecimal html color [#rrggbb] + # @return array + # @access private + # + def convertColorHexToDec(color = "#000000") + tbl_color = {} + tbl_color['R'] = color[1,2].hex.to_i; + tbl_color['G'] = color[3,2].hex.to_i; + tbl_color['B'] = color[5,2].hex.to_i; + return tbl_color; + end + + # + # Converts pixels to millimeters in 72 dpi. + # @param int :px pixels + # @return float millimeters + # @access private + # + def pixelsToMillimeters(px) + return px.to_f * 25.4 / 72; + end + + # + # Reverse function for htmlentities. + # Convert entities in UTF-8. + # + # @param :text_to_convert Text to convert. + # @return string converted + # + def unhtmlentities(string) + if @@decoder.nil? + CGI.unescapeHTML(string) + else + @@decoder.decode(string) + end + end + +end # END OF CLASS + +#TODO 2007-05-25 (EJM) Level=0 - +#Handle special IE contype request +# if (!_SERVER['HTTP_USER_AGENT'].nil? and (_SERVER['HTTP_USER_AGENT']=='contype')) +# header('Content-Type: application/pdf'); +# exit; +# } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/52835e85663e2540d36b9bff7e6cf6a1403991c9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/52835e85663e2540d36b9bff7e6cf6a1403991c9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,115 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::CodesetUtilTest < ActiveSupport::TestCase + + def test_to_utf8_by_setting_from_latin1 + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + s1 = "Texte encod\xc3\xa9" + s2 = "Texte encod\xe9" + s3 = s2.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ASCII-8BIT") + s3.force_encoding("UTF-8") + end + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3) + end + end + + def test_to_utf8_by_setting_from_euc_jp + with_settings :repositories_encodings => 'UTF-8,EUC-JP' do + s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3" + s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3" + s3 = s2.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ASCII-8BIT") + s3.force_encoding("UTF-8") + end + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3) + end + end + + def test_to_utf8_by_setting_should_be_converted_all_latin1 + with_settings :repositories_encodings => 'ISO-8859-1' do + s1 = "\xc3\x82\xc2\x80" + s2 = "\xC2\x80" + s3 = s2.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ASCII-8BIT") + s3.force_encoding("UTF-8") + end + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3) + end + end + + def test_to_utf8_by_setting_blank_string + assert_equal "", Redmine::CodesetUtil.to_utf8_by_setting("") + assert_equal nil, Redmine::CodesetUtil.to_utf8_by_setting(nil) + end + + def test_to_utf8_by_setting_returns_ascii_as_utf8 + s1 = "ASCII" + s2 = s1.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ISO-8859-1") + end + str1 = Redmine::CodesetUtil.to_utf8_by_setting(s1) + str2 = Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, str1 + assert_equal s1, str2 + if s1.respond_to?(:force_encoding) + assert_equal "UTF-8", str1.encoding.to_s + assert_equal "UTF-8", str2.encoding.to_s + end + end + + def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped + with_settings :repositories_encodings => '' do + # s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") + s1 = "Texte encod\xe9 en ISO-8859-1." + s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding) + str = Redmine::CodesetUtil.to_utf8_by_setting(s1) + if str.respond_to?(:force_encoding) + assert str.valid_encoding? + assert_equal "UTF-8", str.encoding.to_s + end + assert_equal "Texte encod? en ISO-8859-1.", str + end + end + + def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped_ja_jis + with_settings :repositories_encodings => 'ISO-2022-JP' do + s1 = "test\xb5\xfetest\xb5\xfe" + s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding) + str = Redmine::CodesetUtil.to_utf8_by_setting(s1) + if str.respond_to?(:force_encoding) + assert str.valid_encoding? + assert_equal "UTF-8", str.encoding.to_s + end + assert_equal "test??test??", str + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/52861ceb2f3a417977bfbcbe6c0ba816774849bd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/52861ceb2f3a417977bfbcbe6c0ba816774849bd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,101 @@ +--- +enabled_modules_001: + name: issue_tracking + project_id: 1 + id: 1 +enabled_modules_002: + name: time_tracking + project_id: 1 + id: 2 +enabled_modules_003: + name: news + project_id: 1 + id: 3 +enabled_modules_004: + name: documents + project_id: 1 + id: 4 +enabled_modules_005: + name: files + project_id: 1 + id: 5 +enabled_modules_006: + name: wiki + project_id: 1 + id: 6 +enabled_modules_007: + name: repository + project_id: 1 + id: 7 +enabled_modules_008: + name: boards + project_id: 1 + id: 8 +enabled_modules_009: + name: repository + project_id: 3 + id: 9 +enabled_modules_010: + name: wiki + project_id: 3 + id: 10 +enabled_modules_011: + name: issue_tracking + project_id: 2 + id: 11 +enabled_modules_012: + name: time_tracking + project_id: 3 + id: 12 +enabled_modules_013: + name: issue_tracking + project_id: 3 + id: 13 +enabled_modules_014: + name: issue_tracking + project_id: 5 + id: 14 +enabled_modules_015: + name: wiki + project_id: 2 + id: 15 +enabled_modules_016: + name: boards + project_id: 2 + id: 16 +enabled_modules_017: + name: calendar + project_id: 1 + id: 17 +enabled_modules_018: + name: gantt + project_id: 1 + id: 18 +enabled_modules_019: + name: calendar + project_id: 2 + id: 19 +enabled_modules_020: + name: gantt + project_id: 2 + id: 20 +enabled_modules_021: + name: calendar + project_id: 3 + id: 21 +enabled_modules_022: + name: gantt + project_id: 3 + id: 22 +enabled_modules_023: + name: calendar + project_id: 5 + id: 23 +enabled_modules_024: + name: gantt + project_id: 5 + id: 24 +enabled_modules_025: + name: news + project_id: 2 + id: 25 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/528f95522c0c290aaee9f3ccf7b28d7c138ec9e4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/528f95522c0c290aaee9f3ccf7b28d7c138ec9e4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '粗体'; +jsToolBar.strings['Italic'] = '斜体'; +jsToolBar.strings['Underline'] = '下划线'; +jsToolBar.strings['Deleted'] = '删除线'; +jsToolBar.strings['Code'] = '程序代码'; +jsToolBar.strings['Heading 1'] = '标题 1'; +jsToolBar.strings['Heading 2'] = '标题 2'; +jsToolBar.strings['Heading 3'] = '标题 3'; +jsToolBar.strings['Unordered list'] = '无序列表'; +jsToolBar.strings['Ordered list'] = '排序列表'; +jsToolBar.strings['Quote'] = '引用'; +jsToolBar.strings['Unquote'] = '删除引用'; +jsToolBar.strings['Preformatted text'] = '格式化文本'; +jsToolBar.strings['Wiki link'] = '连接到 Wiki 页面'; +jsToolBar.strings['Image'] = '图片'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/52f0bf1c239cf648c203a8def6f59245b007d594.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/52f0bf1c239cf648c203a8def6f59245b007d594.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/console' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/52/52fb1ca187bdbea92b2ca21fb1a15fadb8ae488e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/52/52fb1ca187bdbea92b2ca21fb1a15fadb8ae488e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +# Tests in this file ensure that: +# +# * plugin controller actions are found +# * actions defined in application controllers take precedence over those in plugins +# * actions in controllers in subsequently loaded plugins take precendence over those in previously loaded plugins +# * this works for actions in namespaced controllers accordingly + +require File.dirname(__FILE__) + '/../test_helper' + +class ControllerLoadingTest < ActionController::TestCase + def setup + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + # plugin controller actions should be found + + def test_WITH_an_action_defined_only_in_a_plugin_IT_should_use_this_action + get_action_on_controller :an_action, :alpha_plugin + assert_response_body 'rendered in AlphaPluginController#an_action' + end + + def test_WITH_an_action_defined_only_in_a_namespaced_plugin_controller_IT_should_use_this_action + get_action_on_controller :an_action, :alpha_plugin, :namespace + assert_response_body 'rendered in Namespace::AlphaPluginController#an_action' + end + + # app takes precedence over plugins + + def test_WITH_an_action_defined_in_both_app_and_plugin_IT_should_use_the_one_in_app + get_action_on_controller :an_action, :app_and_plugin + assert_response_body 'rendered in AppAndPluginController#an_action (from app)' + end + + def test_WITH_an_action_defined_in_namespaced_controllers_in_both_app_and_plugin_IT_should_use_the_one_in_app + get_action_on_controller :an_action, :app_and_plugin, :namespace + assert_response_body 'rendered in Namespace::AppAndPluginController#an_action (from app)' + end + + # subsequently loaded plugins take precendence over previously loaded plugins + + def test_WITH_an_action_defined_in_two_plugin_controllers_IT_should_use_the_latter_of_both + get_action_on_controller :an_action, :shared_plugin + assert_response_body 'rendered in SharedPluginController#an_action (from beta_plugin)' + end + + def test_WITH_an_action_defined_in_two_namespaced_plugin_controllers_IT_should_use_the_latter_of_both + get_action_on_controller :an_action, :shared_plugin, :namespace + assert_response_body 'rendered in Namespace::SharedPluginController#an_action (from beta_plugin)' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/5379630b9d6429044c3fd0c2e60e7bdba5976f78.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/5379630b9d6429044c3fd0c2e60e7bdba5976f78.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,94 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'welcome_controller' + +# Re-raise errors caught by the controller. +class WelcomeController; def rescue_action(e) raise e end; end + +class WelcomeControllerTest < ActionController::TestCase + fixtures :projects, :news + + def setup + @controller = WelcomeController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_index + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:news) + assert_not_nil assigns(:projects) + assert !assigns(:projects).include?(Project.find(:first, :conditions => {:is_public => false})) + end + + def test_browser_language + Setting.default_language = 'en' + @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' + get :index + assert_equal :fr, @controller.current_language + end + + def test_browser_language_alternate + Setting.default_language = 'en' + @request.env['HTTP_ACCEPT_LANGUAGE'] = 'zh-TW' + get :index + assert_equal :"zh-TW", @controller.current_language + end + + def test_browser_language_alternate_not_valid + Setting.default_language = 'en' + @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr-CA' + get :index + assert_equal :fr, @controller.current_language + end + + def test_robots + get :robots + assert_response :success + assert_equal 'text/plain', @response.content_type + assert @response.body.match(%r{^Disallow: /projects/ecookbook/issues\r?$}) + end + + def test_warn_on_leaving_unsaved_turn_on + user = User.find(2) + user.pref.warn_on_leaving_unsaved = '1' + user.pref.save! + @request.session[:user_id] = 2 + + get :index + assert_tag 'script', + :attributes => {:type => "text/javascript"}, + :content => %r{new WarnLeavingUnsaved} + end + + def test_warn_on_leaving_unsaved_turn_off + user = User.find(2) + user.pref.warn_on_leaving_unsaved = '0' + user.pref.save! + @request.session[:user_id] = 2 + + get :index + assert_no_tag 'script', + :attributes => {:type => "text/javascript"}, + :content => %r{new WarnLeavingUnsaved} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/537c76b0b6db46cea1550518e810dd1d4d5b897a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/537c76b0b6db46cea1550518e810dd1d4d5b897a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class Document < ActiveRecord::Base + generator_for :title, :start => 'Document001' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/539f4d98713d0fa4ed6fd83111963b94c1350c7c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/539f4d98713d0fa4ed6fd83111963b94c1350c7c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,122 @@ + + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/53ae85a75b984c31fad63866e54e9b00f6355b8c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/53ae85a75b984c31fad63866e54e9b00f6355b8c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1008 @@ +# Greek translations for Ruby on Rails +# by Vaggelis Typaldos (vtypal@gmail.com), Spyros Raptis (spirosrap@gmail.com) + +el: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Κυριακή, Δευτέρα, Τρίτη, Τετάρτη, Πέμπτη, Παρασκευή, Σάββατο] + abbr_day_names: [Κυρ, Δευ, Τρι, Τετ, Πεμ, Παρ, Σαβ] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Ιανουάριος, Φεβρουάριος, Μάρτιος, Απρίλιος, Μάϊος, Ιούνιος, Ιούλιος, Αύγουστος, Σεπτέμβριος, Οκτώβριος, Νοέμβριος, Δεκέμβριος] + abbr_month_names: [~, Ιαν, Φεβ, Μαρ, Απρ, Μαϊ, Ιον, Ιολ, Αυγ, Σεπ, Οκτ, Νοε, Δεκ] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "πμ" + pm: "μμ" + + datetime: + distance_in_words: + half_a_minute: "μισό λεπτό" + less_than_x_seconds: + one: "λιγότερο από 1 δευτερόλεπτο" + other: "λιγότερο από %{count} δευτερόλεπτα" + x_seconds: + one: "1 δευτερόλεπτο" + other: "%{count} δευτερόλεπτα" + less_than_x_minutes: + one: "λιγότερο από ένα λεπτό" + other: "λιγότερο από %{count} λεπτά" + x_minutes: + one: "1 λεπτό" + other: "%{count} λεπτά" + about_x_hours: + one: "περίπου 1 ώρα" + other: "περίπου %{count} ώρες" + x_days: + one: "1 ημέρα" + other: "%{count} ημέρες" + about_x_months: + one: "περίπου 1 μήνα" + other: "περίπου %{count} μήνες" + x_months: + one: "1 μήνα" + other: "%{count} μήνες" + about_x_years: + one: "περίπου 1 χρόνο" + other: "περίπου %{count} χρόνια" + over_x_years: + one: "πάνω από 1 χρόνο" + other: "πάνω από %{count} χρόνια" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + precision: 1 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "δεν περιέχεται στη λίστα" + exclusion: "έχει κατοχυρωθεί" + invalid: "είναι άκυρο" + confirmation: "δεν αντιστοιχεί με την επιβεβαίωση" + accepted: "πρέπει να γίνει αποδοχή" + empty: "δε μπορεί να είναι άδειο" + blank: "δε μπορεί να είναι κενό" + too_long: "έχει πολλούς (μέγ.επιτρ. %{count} χαρακτήρες)" + too_short: "έχει λίγους (ελάχ.επιτρ. %{count} χαρακτήρες)" + wrong_length: "δεν είναι σωστός ο αριθμός χαρακτήρων (πρέπει να έχει %{count} χαρακτήρες)" + taken: "έχει ήδη κατοχυρωθεί" + not_a_number: "δεν είναι αριθμός" + not_a_date: "δεν είναι σωστή ημερομηνία" + greater_than: "πρέπει να είναι μεγαλύτερο από %{count}" + greater_than_or_equal_to: "πρέπει να είναι μεγαλύτερο από ή ίσο με %{count}" + equal_to: "πρέπει να είναι ίσον με %{count}" + less_than: "πρέπει να είναι μικρότερη από %{count}" + less_than_or_equal_to: "πρέπει να είναι μικρότερο από ή ίσο με %{count}" + odd: "πρέπει να είναι μονός" + even: "πρέπει να είναι ζυγός" + greater_than_start_date: "πρέπει να είναι αργότερα από την ημερομηνία έναρξης" + not_same_project: "δεν ανήκει στο ίδιο έργο" + circular_dependency: "Αυτή η σχέση θα δημιουργήσει κυκλικές εξαρτήσεις" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Παρακαλώ επιλέξτε + + general_text_No: 'Όχι' + general_text_Yes: 'Ναι' + general_text_no: 'όχι' + general_text_yes: 'ναι' + general_lang_name: 'Ελληνικά' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Ο λογαριασμός ενημερώθηκε επιτυχώς. + notice_account_invalid_creditentials: Άκυρο όνομα χρήστη ή κωδικού πρόσβασης + notice_account_password_updated: Ο κωδικός πρόσβασης ενημερώθηκε επιτυχώς. + notice_account_wrong_password: Λάθος κωδικός πρόσβασης + notice_account_register_done: Ο λογαριασμός δημιουργήθηκε επιτυχώς. Για να ενεργοποιήσετε το λογαριασμό σας, πατήστε το σύνδεσμο που σας έχει αποσταλεί με email. + notice_account_unknown_email: Άγνωστος χρήστης. + notice_can_t_change_password: Αυτός ο λογαριασμός χρησιμοποιεί εξωτερική πηγή πιστοποίησης. Δεν είναι δυνατόν να αλλάξετε τον κωδικό πρόσβασης. + notice_account_lost_email_sent: Σας έχει αποσταλεί email με οδηγίες για την επιλογή νέου κωδικού πρόσβασης. + notice_account_activated: Ο λογαριασμός σας έχει ενεργοποιηθεί. Τώρα μπορείτε να συνδεθείτε. + notice_successful_create: Επιτυχής δημιουργία. + notice_successful_update: Επιτυχής ενημέρωση. + notice_successful_delete: Επιτυχής διαγραφή. + notice_successful_connection: Επιτυχής σύνδεση. + notice_file_not_found: Η σελίδα που ζητήσατε δεν υπάρχει ή έχει αφαιρεθεί. + notice_locking_conflict: Τα δεδομένα έχουν ενημερωθεί από άλλο χρήστη. + notice_not_authorized: Δεν έχετε δικαίωμα πρόσβασης σε αυτή τη σελίδα. + notice_email_sent: "Ένα μήνυμα ηλεκτρονικού ταχυδρομείου εστάλη στο %{value}" + notice_email_error: "Σφάλμα κατά την αποστολή του μηνύματος στο (%{value})" + notice_feeds_access_key_reseted: Έγινε επαναφορά στο κλειδί πρόσβασης RSS. + notice_failed_to_save_issues: "Αποτυχία αποθήκευσης %{count} θεμα(των) από τα %{total} επιλεγμένα: %{ids}." + notice_no_issue_selected: "Κανένα θέμα δεν είναι επιλεγμένο! Παρακαλούμε, ελέγξτε τα θέματα που θέλετε να επεξεργαστείτε." + notice_account_pending: "Ο λογαριασμός σας έχει δημιουργηθεί και είναι σε στάδιο έγκρισης από τον διαχειριστή." + notice_default_data_loaded: Οι προεπιλεγμένες ρυθμίσεις φορτώθηκαν επιτυχώς. + notice_unable_delete_version: Αδύνατον να διαγραφεί η έκδοση. + + error_can_t_load_default_data: "Οι προεπιλεγμένες ρυθμίσεις δεν μπόρεσαν να φορτωθούν:: %{value}" + error_scm_not_found: "Η εγγραφή ή η αναθεώρηση δεν βρέθηκε στο αποθετήριο." + error_scm_command_failed: "Παρουσιάστηκε σφάλμα κατά την προσπάθεια πρόσβασης στο αποθετήριο: %{value}" + error_scm_annotate: "Η καταχώριση δεν υπάρχει ή δεν μπορεί να σχολιαστεί." + error_issue_not_found_in_project: 'Το θέμα δεν βρέθηκε ή δεν ανήκει σε αυτό το έργο' + error_no_tracker_in_project: 'Δεν υπάρχει ανιχνευτής για αυτό το έργο. Παρακαλώ ελέγξτε τις ρυθμίσεις του έργου.' + error_no_default_issue_status: 'Δεν έχει οριστεί η προεπιλογή κατάστασης θεμάτων. Παρακαλώ ελέγξτε τις ρυθμίσεις σας (Μεταβείτε στην "Διαχείριση -> Κατάσταση θεμάτων").' + + warning_attachments_not_saved: "%{count} αρχείο(α) δε μπορούν να αποθηκευτούν." + + mail_subject_lost_password: "Ο κωδικός σας %{value}" + mail_body_lost_password: 'Για να αλλάξετε τον κωδικό πρόσβασης, πατήστε τον ακόλουθο σύνδεσμο:' + mail_subject_register: "Ενεργοποίηση του λογαριασμού χρήστη %{value} " + mail_body_register: 'Για να ενεργοποιήσετε το λογαριασμό σας, επιλέξτε τον ακόλουθο σύνδεσμο:' + mail_body_account_information_external: "Μπορείτε να χρησιμοποιήσετε τον λογαριασμό %{value} για να συνδεθείτε." + mail_body_account_information: Πληροφορίες του λογαριασμού σας + mail_subject_account_activation_request: "αίτημα ενεργοποίησης λογαριασμού %{value}" + mail_body_account_activation_request: "'Ένας νέος χρήστης (%{value}) έχει εγγραφεί. Ο λογαριασμός είναι σε στάδιο αναμονής της έγκρισης σας:" + mail_subject_reminder: "%{count} θέμα(τα) με προθεσμία στις επόμενες %{days} ημέρες" + mail_body_reminder: "%{count}θέμα(τα) που έχουν ανατεθεί σε σας, με προθεσμία στις επόμενες %{days} ημέρες:" + mail_subject_wiki_content_added: "'προστέθηκε η σελίδα wiki %{id}' " + mail_body_wiki_content_added: "Η σελίδα wiki '%{id}' προστέθηκε από τον %{author}." + mail_subject_wiki_content_updated: "'ενημερώθηκε η σελίδα wiki %{id}' " + mail_body_wiki_content_updated: "Η σελίδα wiki '%{id}' ενημερώθηκε από τον %{author}." + + gui_validation_error: 1 σφάλμα + gui_validation_error_plural: "%{count} σφάλματα" + + field_name: Όνομα + field_description: Περιγραφή + field_summary: Συνοπτικά + field_is_required: Απαιτείται + field_firstname: Όνομα + field_lastname: Επώνυμο + field_mail: Email + field_filename: Αρχείο + field_filesize: Μέγεθος + field_downloads: Μεταφορτώσεις + field_author: Συγγραφέας + field_created_on: Δημιουργήθηκε + field_updated_on: Ενημερώθηκε + field_field_format: Μορφοποίηση + field_is_for_all: Για όλα τα έργα + field_possible_values: Πιθανές τιμές + field_regexp: Κανονική παράσταση + field_min_length: Ελάχιστο μήκος + field_max_length: Μέγιστο μήκος + field_value: Τιμή + field_category: Κατηγορία + field_title: Τίτλος + field_project: Έργο + field_issue: Θέμα + field_status: Κατάσταση + field_notes: Σημειώσεις + field_is_closed: Κλειστά θέματα + field_is_default: Προεπιλεγμένη τιμή + field_tracker: Ανιχνευτής + field_subject: Θέμα + field_due_date: Προθεσμία + field_assigned_to: Ανάθεση σε + field_priority: Προτεραιότητα + field_fixed_version: Στόχος έκδοσης + field_user: Χρήστης + field_role: Ρόλος + field_homepage: Αρχική σελίδα + field_is_public: Δημόσιο + field_parent: Επιμέρους έργο του + field_is_in_roadmap: Προβολή θεμάτων στο χάρτη πορείας + field_login: Όνομα χρήστη + field_mail_notification: Ειδοποιήσεις email + field_admin: Διαχειριστής + field_last_login_on: Τελευταία σύνδεση + field_language: Γλώσσα + field_effective_date: Ημερομηνία + field_password: Κωδικός πρόσβασης + field_new_password: Νέος κωδικός πρόσβασης + field_password_confirmation: Επιβεβαίωση + field_version: Έκδοση + field_type: Τύπος + field_host: Κόμβος + field_port: Θύρα + field_account: Λογαριασμός + field_base_dn: Βάση DN + field_attr_login: Ιδιότητα εισόδου + field_attr_firstname: Ιδιότητα ονόματος + field_attr_lastname: Ιδιότητα επωνύμου + field_attr_mail: Ιδιότητα email + field_onthefly: Άμεση δημιουργία χρήστη + field_start_date: Εκκίνηση + field_done_ratio: "% επιτεύχθη" + field_auth_source: Τρόπος πιστοποίησης + field_hide_mail: Απόκρυψη διεύθυνσης email + field_comments: Σχόλιο + field_url: URL + field_start_page: Πρώτη σελίδα + field_subproject: Επιμέρους έργο + field_hours: Ώρες + field_activity: Δραστηριότητα + field_spent_on: Ημερομηνία + field_identifier: Στοιχείο αναγνώρισης + field_is_filter: Χρήση ως φίλτρο + field_issue_to: Σχετικά θέματα + field_delay: Καθυστέρηση + field_assignable: Θέματα που μπορούν να ανατεθούν σε αυτό το ρόλο + field_redirect_existing_links: Ανακατεύθυνση των τρεχόντων συνδέσμων + field_estimated_hours: Εκτιμώμενος χρόνος + field_column_names: Στήλες + field_time_zone: Ωριαία ζώνη + field_searchable: Ερευνήσιμο + field_default_value: Προκαθορισμένη τιμή + field_comments_sorting: Προβολή σχολίων + field_parent_title: Γονική σελίδα + field_editable: Επεξεργάσιμο + field_watcher: Παρατηρητής + field_identity_url: OpenID URL + field_content: Περιεχόμενο + field_group_by: Ομαδικά αποτελέσματα από + + setting_app_title: Τίτλος εφαρμογής + setting_app_subtitle: Υπότιτλος εφαρμογής + setting_welcome_text: Κείμενο υποδοχής + setting_default_language: Προεπιλεγμένη γλώσσα + setting_login_required: Απαιτείται πιστοποίηση + setting_self_registration: Αυτο-εγγραφή + setting_attachment_max_size: Μέγ. μέγεθος συνημμένου + setting_issues_export_limit: Θέματα περιορισμού εξαγωγής + setting_mail_from: Μετάδοση διεύθυνσης email + setting_bcc_recipients: Αποδέκτες κρυφής κοινοποίησης (bcc) + setting_plain_text_mail: Email απλού κειμένου (όχι HTML) + setting_host_name: Όνομα κόμβου και διαδρομή + setting_text_formatting: Μορφοποίηση κειμένου + setting_wiki_compression: Συμπίεση ιστορικού wiki + setting_feeds_limit: Feed περιορισμού περιεχομένου + setting_default_projects_public: Τα νέα έργα έχουν προεπιλεγεί ως δημόσια + setting_autofetch_changesets: Αυτόματη λήψη commits + setting_sys_api_enabled: Ενεργοποίηση WS για διαχείριση αποθετηρίου + setting_commit_ref_keywords: Αναφορά σε λέξεις-κλειδιά + setting_commit_fix_keywords: Καθορισμός σε λέξεις-κλειδιά + setting_autologin: Αυτόματη σύνδεση + setting_date_format: Μορφή ημερομηνίας + setting_time_format: Μορφή ώρας + setting_cross_project_issue_relations: Επιτρέψτε συσχετισμό θεμάτων σε διασταύρωση-έργων + setting_issue_list_default_columns: Προκαθορισμένες εμφανιζόμενες στήλες στη λίστα θεμάτων + setting_emails_footer: Υποσέλιδο στα email + setting_protocol: Πρωτόκολο + setting_per_page_options: Αντικείμενα ανά σελίδα επιλογών + setting_user_format: Μορφή εμφάνισης χρηστών + setting_activity_days_default: Ημέρες που εμφανίζεται στη δραστηριότητα έργου + setting_display_subprojects_issues: Εμφάνιση από προεπιλογή θεμάτων επιμέρους έργων στα κύρια έργα + setting_enabled_scm: Ενεργοποίηση SCM + setting_mail_handler_api_enabled: Ενεργοποίηση WS για εισερχόμενα email + setting_mail_handler_api_key: κλειδί API + setting_sequential_project_identifiers: Δημιουργία διαδοχικών αναγνωριστικών έργου + setting_gravatar_enabled: Χρήση Gravatar εικονιδίων χρηστών + setting_diff_max_lines_displayed: Μεγ.αριθμός εμφάνισης γραμμών diff + setting_file_max_size_displayed: Μεγ.μέγεθος των αρχείων απλού κειμένου που εμφανίζονται σε σειρά + setting_repository_log_display_limit: Μέγιστος αριθμός αναθεωρήσεων που εμφανίζονται στο ιστορικό αρχείου + setting_openid: Επιτρέψτε συνδέσεις OpenID και εγγραφή + setting_password_min_length: Ελάχιστο μήκος κωδικού πρόσβασης + setting_new_project_user_role_id: Απόδοση ρόλου σε χρήστη μη-διαχειριστή όταν δημιουργεί ένα έργο + + permission_add_project: Δημιουργία έργου + permission_edit_project: Επεξεργασία έργου + permission_select_project_modules: Επιλογή μονάδων έργου + permission_manage_members: Διαχείριση μελών + permission_manage_versions: Διαχείριση εκδόσεων + permission_manage_categories: Διαχείριση κατηγοριών θεμάτων + permission_add_issues: Προσθήκη θεμάτων + permission_edit_issues: Επεξεργασία θεμάτων + permission_manage_issue_relations: Διαχείριση συσχετισμών θεμάτων + permission_add_issue_notes: Προσθήκη σημειώσεων + permission_edit_issue_notes: Επεξεργασία σημειώσεων + permission_edit_own_issue_notes: Επεξεργασία δικών μου σημειώσεων + permission_move_issues: Μεταφορά θεμάτων + permission_delete_issues: Διαγραφή θεμάτων + permission_manage_public_queries: Διαχείριση δημόσιων αναζητήσεων + permission_save_queries: Αποθήκευση αναζητήσεων + permission_view_gantt: Προβολή διαγράμματος gantt + permission_view_calendar: Προβολή ημερολογίου + permission_view_issue_watchers: Προβολή λίστας παρατηρητών + permission_add_issue_watchers: Προσθήκη παρατηρητών + permission_log_time: Ιστορικό χρόνου που δαπανήθηκε + permission_view_time_entries: Προβολή χρόνου που δαπανήθηκε + permission_edit_time_entries: Επεξεργασία ιστορικού χρόνου + permission_edit_own_time_entries: Επεξεργασία δικού μου ιστορικού χρόνου + permission_manage_news: Διαχείριση νέων + permission_comment_news: Σχολιασμός νέων + permission_manage_documents: Διαχείριση εγγράφων + permission_view_documents: Προβολή εγγράφων + permission_manage_files: Διαχείριση αρχείων + permission_view_files: Προβολή αρχείων + permission_manage_wiki: Διαχείριση wiki + permission_rename_wiki_pages: Μετονομασία σελίδων wiki + permission_delete_wiki_pages: Διαγραφή σελίδων wiki + permission_view_wiki_pages: Προβολή wiki + permission_view_wiki_edits: Προβολή ιστορικού wiki + permission_edit_wiki_pages: Επεξεργασία σελίδων wiki + permission_delete_wiki_pages_attachments: Διαγραφή συνημμένων + permission_protect_wiki_pages: Προστασία σελίδων wiki + permission_manage_repository: Διαχείριση αποθετηρίου + permission_browse_repository: Διαχείριση εγγράφων + permission_view_changesets: Προβολή changesets + permission_commit_access: Πρόσβαση commit + permission_manage_boards: Διαχείριση πινάκων συζητήσεων + permission_view_messages: Προβολή μηνυμάτων + permission_add_messages: Αποστολή μηνυμάτων + permission_edit_messages: Επεξεργασία μηνυμάτων + permission_edit_own_messages: Επεξεργασία δικών μου μηνυμάτων + permission_delete_messages: Διαγραφή μηνυμάτων + permission_delete_own_messages: Διαγραφή δικών μου μηνυμάτων + + project_module_issue_tracking: Ανίχνευση θεμάτων + project_module_time_tracking: Ανίχνευση χρόνου + project_module_news: Νέα + project_module_documents: Έγγραφα + project_module_files: Αρχεία + project_module_wiki: Wiki + project_module_repository: Αποθετήριο + project_module_boards: Πίνακες συζητήσεων + + label_user: Χρήστης + label_user_plural: Χρήστες + label_user_new: Νέος Χρήστης + label_project: Έργο + label_project_new: Νέο έργο + label_project_plural: Έργα + label_x_projects: + zero: κανένα έργο + one: 1 έργο + other: "%{count} έργα" + label_project_all: Όλα τα έργα + label_project_latest: Τελευταία έργα + label_issue: Θέμα + label_issue_new: Νέο θέμα + label_issue_plural: Θέματα + label_issue_view_all: Προβολή όλων των θεμάτων + label_issues_by: "Θέματα του %{value}" + label_issue_added: Το θέμα προστέθηκε + label_issue_updated: Το θέμα ενημερώθηκε + label_document: Έγγραφο + label_document_new: Νέο έγγραφο + label_document_plural: Έγγραφα + label_document_added: Έγγραφο προστέθηκε + label_role: Ρόλος + label_role_plural: Ρόλοι + label_role_new: Νέος ρόλος + label_role_and_permissions: Ρόλοι και άδειες + label_member: Μέλος + label_member_new: Νέο μέλος + label_member_plural: Μέλη + label_tracker: Ανιχνευτής + label_tracker_plural: Ανιχνευτές + label_tracker_new: Νέος Ανιχνευτής + label_workflow: Ροή εργασίας + label_issue_status: Κατάσταση θέματος + label_issue_status_plural: Κατάσταση θέματος + label_issue_status_new: Νέα κατάσταση + label_issue_category: Κατηγορία θέματος + label_issue_category_plural: Κατηγορίες θεμάτων + label_issue_category_new: Νέα κατηγορία + label_custom_field: Προσαρμοσμένο πεδίο + label_custom_field_plural: Προσαρμοσμένα πεδία + label_custom_field_new: Νέο προσαρμοσμένο πεδίο + label_enumerations: Απαριθμήσεις + label_enumeration_new: Νέα τιμή + label_information: Πληροφορία + label_information_plural: Πληροφορίες + label_please_login: Παρακαλώ συνδεθείτε + label_register: Εγγραφή + label_login_with_open_id_option: ή συνδεθείτε με OpenID + label_password_lost: Ανάκτηση κωδικού πρόσβασης + label_home: Αρχική σελίδα + label_my_page: Η σελίδα μου + label_my_account: Ο λογαριασμός μου + label_my_projects: Τα έργα μου + label_administration: Διαχείριση + label_login: Σύνδεση + label_logout: Αποσύνδεση + label_help: Βοήθεια + label_reported_issues: Εισηγμένα θέματα + label_assigned_to_me_issues: Θέματα που έχουν ανατεθεί σε μένα + label_last_login: Τελευταία σύνδεση + label_registered_on: Εγγράφηκε την + label_activity: Δραστηριότητα + label_overall_activity: Συνολική δραστηριότητα + label_user_activity: "δραστηριότητα του %{value}" + label_new: Νέο + label_logged_as: Σύνδεδεμένος ως + label_environment: Περιβάλλον + label_authentication: Πιστοποίηση + label_auth_source: Τρόπος πιστοποίησης + label_auth_source_new: Νέος τρόπος πιστοποίησης + label_auth_source_plural: Τρόποι πιστοποίησης + label_subproject_plural: Επιμέρους έργα + label_and_its_subprojects: "%{value} και τα επιμέρους έργα του" + label_min_max_length: Ελάχ. - Μέγ. μήκος + label_list: Λίστα + label_date: Ημερομηνία + label_integer: Ακέραιος + label_float: Αριθμός κινητής υποδιαστολής + label_boolean: Λογικός + label_string: Κείμενο + label_text: Μακροσκελές κείμενο + label_attribute: Ιδιότητα + label_attribute_plural: Ιδιότητες + label_download: "%{count} Μεταφόρτωση" + label_download_plural: "%{count} Μεταφορτώσεις" + label_no_data: Δεν υπάρχουν δεδομένα + label_change_status: Αλλαγή κατάστασης + label_history: Ιστορικό + label_attachment: Αρχείο + label_attachment_new: Νέο αρχείο + label_attachment_delete: Διαγραφή αρχείου + label_attachment_plural: Αρχεία + label_file_added: Το αρχείο προστέθηκε + label_report: Αναφορά + label_report_plural: Αναφορές + label_news: Νέα + label_news_new: Προσθήκη νέων + label_news_plural: Νέα + label_news_latest: Τελευταία νέα + label_news_view_all: Προβολή όλων των νέων + label_news_added: Τα νέα προστέθηκαν + label_settings: Ρυθμίσεις + label_overview: Επισκόπηση + label_version: Έκδοση + label_version_new: Νέα έκδοση + label_version_plural: Εκδόσεις + label_confirmation: Επιβεβαίωση + label_export_to: 'Επίσης διαθέσιμο σε:' + label_read: Διάβασε... + label_public_projects: Δημόσια έργα + label_open_issues: Ανοικτό + label_open_issues_plural: Ανοικτά + label_closed_issues: Κλειστό + label_closed_issues_plural: Κλειστά + label_x_open_issues_abbr_on_total: + zero: 0 ανοικτά / %{total} + one: 1 ανοικτό / %{total} + other: "%{count} ανοικτά / %{total}" + label_x_open_issues_abbr: + zero: 0 ανοικτά + one: 1 ανοικτό + other: "%{count} ανοικτά" + label_x_closed_issues_abbr: + zero: 0 κλειστά + one: 1 κλειστό + other: "%{count} κλειστά" + label_total: Σύνολο + label_permissions: Άδειες + label_current_status: Τρέχουσα κατάσταση + label_new_statuses_allowed: Νέες καταστάσεις επιτρέπονται + label_all: όλα + label_none: κανένα + label_nobody: κανείς + label_next: Επόμενο + label_previous: Προηγούμενο + label_used_by: Χρησιμοποιήθηκε από + label_details: Λεπτομέρειες + label_add_note: Προσθήκη σημείωσης + label_per_page: Ανά σελίδα + label_calendar: Ημερολόγιο + label_months_from: μηνών από + label_gantt: Gantt + label_internal: Εσωτερικό + label_last_changes: "Τελευταίες %{count} αλλαγές" + label_change_view_all: Προβολή όλων των αλλαγών + label_personalize_page: Προσαρμογή σελίδας + label_comment: Σχόλιο + label_comment_plural: Σχόλια + label_x_comments: + zero: δεν υπάρχουν σχόλια + one: 1 σχόλιο + other: "%{count} σχόλια" + label_comment_add: Προσθήκη σχολίου + label_comment_added: Τα σχόλια προστέθηκαν + label_comment_delete: Διαγραφή σχολίων + label_query: Προσαρμοσμένη αναζήτηση + label_query_plural: Προσαρμοσμένες αναζητήσεις + label_query_new: Νέα αναζήτηση + label_filter_add: Προσθήκη φίλτρου + label_filter_plural: Φίλτρα + label_equals: είναι + label_not_equals: δεν είναι + label_in_less_than: μικρότερο από + label_in_more_than: περισσότερο από + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: σε + label_today: σήμερα + label_all_time: συνέχεια + label_yesterday: χθες + label_this_week: αυτή την εβδομάδα + label_last_week: την προηγούμενη εβδομάδα + label_last_n_days: "τελευταίες %{count} μέρες" + label_this_month: αυτό το μήνα + label_last_month: τον προηγούμενο μήνα + label_this_year: αυτό το χρόνο + label_date_range: Χρονικό διάστημα + label_less_than_ago: σε λιγότερο από ημέρες πριν + label_more_than_ago: σε περισσότερο από ημέρες πριν + label_ago: ημέρες πριν + label_contains: περιέχει + label_not_contains: δεν περιέχει + label_day_plural: μέρες + label_repository: Αποθετήριο + label_repository_plural: Αποθετήρια + label_browse: Πλοήγηση + label_modification: "%{count} τροποποίηση" + label_modification_plural: "%{count} τροποποιήσεις" + label_branch: Branch + label_tag: Tag + label_revision: Αναθεώρηση + label_revision_plural: Αναθεωρήσεις + label_associated_revisions: Συνεταιρικές αναθεωρήσεις + label_added: προστέθηκε + label_modified: τροποποιήθηκε + label_copied: αντιγράφηκε + label_renamed: μετονομάστηκε + label_deleted: διαγράφηκε + label_latest_revision: Τελευταία αναθεώριση + label_latest_revision_plural: Τελευταίες αναθεωρήσεις + label_view_revisions: Προβολή αναθεωρήσεων + label_view_all_revisions: Προβολή όλων των αναθεωρήσεων + label_max_size: Μέγιστο μέγεθος + label_sort_highest: Μετακίνηση στην κορυφή + label_sort_higher: Μετακίνηση προς τα πάνω + label_sort_lower: Μετακίνηση προς τα κάτω + label_sort_lowest: Μετακίνηση στο κατώτατο μέρος + label_roadmap: Χάρτης πορείας + label_roadmap_due_in: "Προθεσμία σε %{value}" + label_roadmap_overdue: "%{value} καθυστερημένο" + label_roadmap_no_issues: Δεν υπάρχουν θέματα για αυτή την έκδοση + label_search: Αναζήτηση + label_result_plural: Αποτελέσματα + label_all_words: Όλες οι λέξεις + label_wiki: Wiki + label_wiki_edit: Επεξεργασία wiki + label_wiki_edit_plural: Επεξεργασία wiki + label_wiki_page: Σελίδα Wiki + label_wiki_page_plural: Σελίδες Wiki + label_index_by_title: Δείκτης ανά τίτλο + label_index_by_date: Δείκτης ανά ημερομηνία + label_current_version: Τρέχουσα έκδοση + label_preview: Προεπισκόπηση + label_feed_plural: Feeds + label_changes_details: Λεπτομέρειες όλων των αλλαγών + label_issue_tracking: Ανίχνευση θεμάτων + label_spent_time: Δαπανημένος χρόνος + label_f_hour: "%{value} ώρα" + label_f_hour_plural: "%{value} ώρες" + label_time_tracking: Ανίχνευση χρόνου + label_change_plural: Αλλαγές + label_statistics: Στατιστικά + label_commits_per_month: Commits ανά μήνα + label_commits_per_author: Commits ανά συγγραφέα + label_view_diff: Προβολή διαφορών + label_diff_inline: σε σειρά + label_diff_side_by_side: αντικρυστά + label_options: Επιλογές + label_copy_workflow_from: Αντιγραφή ροής εργασίας από + label_permissions_report: Συνοπτικός πίνακας αδειών + label_watched_issues: Θέματα υπό παρακολούθηση + label_related_issues: Σχετικά θέματα + label_applied_status: Εφαρμογή κατάστασης + label_loading: Φορτώνεται... + label_relation_new: Νέα συσχέτιση + label_relation_delete: Διαγραφή συσχέτισης + label_relates_to: σχετικό με + label_duplicates: αντίγραφα + label_duplicated_by: αντιγράφηκε από + label_blocks: φραγές + label_blocked_by: φραγή από τον + label_precedes: προηγείται + label_follows: ακολουθεί + label_end_to_start: από το τέλος στην αρχή + label_end_to_end: από το τέλος στο τέλος + label_start_to_start: από την αρχή στην αρχή + label_start_to_end: από την αρχή στο τέλος + label_stay_logged_in: Παραμονή σύνδεσης + label_disabled: απενεργοποιημένη + label_show_completed_versions: Προβολή ολοκληρωμένων εκδόσεων + label_me: εγώ + label_board: Φόρουμ + label_board_new: Νέο φόρουμ + label_board_plural: Φόρουμ + label_topic_plural: Θέματα + label_message_plural: Μηνύματα + label_message_last: Τελευταίο μήνυμα + label_message_new: Νέο μήνυμα + label_message_posted: Το μήνυμα προστέθηκε + label_reply_plural: Απαντήσεις + label_send_information: Αποστολή πληροφοριών λογαριασμού στο χρήστη + label_year: Έτος + label_month: Μήνας + label_week: Εβδομάδα + label_date_from: Από + label_date_to: Έως + label_language_based: Με βάση τη γλώσσα του χρήστη + label_sort_by: "Ταξινόμηση ανά %{value}" + label_send_test_email: Αποστολή δοκιμαστικού email + label_feeds_access_key_created_on: "το κλειδί πρόσβασης RSS δημιουργήθηκε πριν από %{value}" + label_module_plural: Μονάδες + label_added_time_by: "Προστέθηκε από τον %{author} πριν από %{age}" + label_updated_time_by: "Ενημερώθηκε από τον %{author} πριν από %{age}" + label_updated_time: "Ενημερώθηκε πριν από %{value}" + label_jump_to_a_project: Μεταβείτε σε ένα έργο... + label_file_plural: Αρχεία + label_changeset_plural: Changesets + label_default_columns: Προεπιλεγμένες στήλες + label_no_change_option: (Δεν υπάρχουν αλλαγές) + label_bulk_edit_selected_issues: Μαζική επεξεργασία επιλεγμένων θεμάτων + label_theme: Θέμα + label_default: Προεπιλογή + label_search_titles_only: Αναζήτηση τίτλων μόνο + label_user_mail_option_all: "Για όλες τις εξελίξεις σε όλα τα έργα μου" + label_user_mail_option_selected: "Για όλες τις εξελίξεις μόνο στα επιλεγμένα έργα..." + label_user_mail_no_self_notified: "Δεν θέλω να ειδοποιούμαι για τις δικές μου αλλαγές" + label_registration_activation_by_email: ενεργοποίηση λογαριασμού με email + label_registration_manual_activation: χειροκίνητη ενεργοποίηση λογαριασμού + label_registration_automatic_activation: αυτόματη ενεργοποίηση λογαριασμού + label_display_per_page: "Ανά σελίδα: %{value}" + label_age: Ηλικία + label_change_properties: Αλλαγή ιδιοτήτων + label_general: Γενικά + label_more: Περισσότερα + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: Πιστοποίηση LDAP + label_downloads_abbr: Μ/Φ + label_optional_description: Προαιρετική περιγραφή + label_add_another_file: Προσθήκη άλλου αρχείου + label_preferences: Προτιμήσεις + label_chronological_order: Κατά χρονολογική σειρά + label_reverse_chronological_order: Κατά αντίστροφη χρονολογική σειρά + label_planning: Σχεδιασμός + label_incoming_emails: Εισερχόμενα email + label_generate_key: Δημιουργία κλειδιού + label_issue_watchers: Παρατηρητές + label_example: Παράδειγμα + label_display: Προβολή + label_sort: Ταξινόμηση + label_ascending: Αύξουσα + label_descending: Φθίνουσα + label_date_from_to: Από %{start} έως %{end} + label_wiki_content_added: Η σελίδα Wiki προστέθηκε + label_wiki_content_updated: Η σελίδα Wiki ενημερώθηκε + + button_login: Σύνδεση + button_submit: Αποστολή + button_save: Αποθήκευση + button_check_all: Επιλογή όλων + button_uncheck_all: Αποεπιλογή όλων + button_delete: Διαγραφή + button_create: Δημιουργία + button_create_and_continue: Δημιουργία και συνέχεια + button_test: Τεστ + button_edit: Επεξεργασία + button_add: Προσθήκη + button_change: Αλλαγή + button_apply: Εφαρμογή + button_clear: Καθαρισμός + button_lock: Κλείδωμα + button_unlock: Ξεκλείδωμα + button_download: Μεταφόρτωση + button_list: Λίστα + button_view: Προβολή + button_move: Μετακίνηση + button_back: Πίσω + button_cancel: Ακύρωση + button_activate: Ενεργοποίηση + button_sort: Ταξινόμηση + button_log_time: Ιστορικό χρόνου + button_rollback: Επαναφορά σε αυτή την έκδοση + button_watch: Παρακολούθηση + button_unwatch: Αναίρεση παρακολούθησης + button_reply: Απάντηση + button_archive: Αρχειοθέτηση + button_unarchive: Αναίρεση αρχειοθέτησης + button_reset: Επαναφορά + button_rename: Μετονομασία + button_change_password: Αλλαγή κωδικού πρόσβασης + button_copy: Αντιγραφή + button_annotate: Σχολιασμός + button_update: Ενημέρωση + button_configure: Ρύθμιση + button_quote: Παράθεση + + status_active: ενεργό(ς)/ή + status_registered: εγεγγραμμένο(ς)/η + status_locked: κλειδωμένο(ς)/η + + text_select_mail_notifications: Επιλογή ενεργειών για τις οποίες θα πρέπει να αποσταλεί ειδοποίηση με email. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 σημαίνει ότι δεν υπάρχουν περιορισμοί + text_project_destroy_confirmation: Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το έργο και τα σχετικά δεδομένα του; + text_subprojects_destroy_warning: "Επίσης το(α) επιμέρους έργο(α): %{value} θα διαγραφούν." + text_workflow_edit: Επιλέξτε ένα ρόλο και έναν ανιχνευτή για να επεξεργαστείτε τη ροή εργασίας + text_are_you_sure: Είστε σίγουρος ; + text_tip_issue_begin_day: καθήκοντα που ξεκινάνε σήμερα + text_tip_issue_end_day: καθήκοντα που τελειώνουν σήμερα + text_tip_issue_begin_end_day: καθήκοντα που ξεκινάνε και τελειώνουν σήμερα + text_project_identifier_info: 'Επιτρέπονται μόνο μικρά πεζά γράμματα (a-z), αριθμοί και παύλες.
Μετά την αποθήκευση, το αναγνωριστικό δεν μπορεί να αλλάξει.' + text_caracters_maximum: "μέγιστος αριθμός %{count} χαρακτήρες." + text_caracters_minimum: "Πρέπει να περιέχει τουλάχιστον %{count} χαρακτήρες." + text_length_between: "Μήκος μεταξύ %{min} και %{max} χαρακτήρες." + text_tracker_no_workflow: Δεν έχει οριστεί ροή εργασίας για αυτό τον ανιχνευτή + text_unallowed_characters: Μη επιτρεπόμενοι χαρακτήρες + text_comma_separated: Επιτρέπονται πολλαπλές τιμές (χωρισμένες με κόμμα). + text_issues_ref_in_commit_messages: Αναφορά και καθορισμός θεμάτων σε μηνύματα commit + text_issue_added: "Το θέμα %{id} παρουσιάστηκε από τον %{author}." + text_issue_updated: "Το θέμα %{id} ενημερώθηκε από τον %{author}." + text_wiki_destroy_confirmation: Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το wiki και όλο το περιεχόμενο του ; + text_issue_category_destroy_question: "Κάποια θέματα (%{count}) έχουν εκχωρηθεί σε αυτή την κατηγορία. Τι θέλετε να κάνετε ;" + text_issue_category_destroy_assignments: Αφαίρεση εκχωρήσεων κατηγορίας + text_issue_category_reassign_to: Επανεκχώρηση θεμάτων σε αυτή την κατηγορία + text_user_mail_option: "Για μη επιλεγμένα έργα, θα λάβετε ειδοποιήσεις μόνο για πράγματα που παρακολουθείτε ή στα οποία συμμετέχω ενεργά (π.χ. θέματα των οποίων είστε συγγραφέας ή σας έχουν ανατεθεί)." + text_no_configuration_data: "Οι ρόλοι, οι ανιχνευτές, η κατάσταση των θεμάτων και η ροή εργασίας δεν έχουν ρυθμιστεί ακόμα.\nΣυνιστάται ιδιαίτερα να φορτώσετε τις προεπιλεγμένες ρυθμίσεις. Θα είστε σε θέση να τις τροποποιήσετε μετά τη φόρτωση τους." + text_load_default_configuration: Φόρτωση προεπιλεγμένων ρυθμίσεων + text_status_changed_by_changeset: "Εφαρμόστηκε στο changeset %{value}." + text_issues_destroy_confirmation: 'Είστε σίγουρος ότι θέλετε να διαγράψετε το επιλεγμένο θέμα(τα);' + text_select_project_modules: 'Επιλέξτε ποιες μονάδες θα ενεργοποιήσετε για αυτό το έργο:' + text_default_administrator_account_changed: Ο προκαθορισμένος λογαριασμός του διαχειριστή άλλαξε + text_file_repository_writable: Εγγράψιμος κατάλογος συνημμένων + text_plugin_assets_writable: Εγγράψιμος κατάλογος plugin assets + text_rmagick_available: Διαθέσιμο RMagick (προαιρετικό) + text_destroy_time_entries_question: "%{hours} δαπανήθηκαν σχετικά με τα θέματα που πρόκειται να διαγράψετε. Τι θέλετε να κάνετε ;" + text_destroy_time_entries: Διαγραφή αναφερόμενων ωρών + text_assign_time_entries_to_project: Ανάθεση αναφερόμενων ωρών στο έργο + text_reassign_time_entries: 'Ανάθεση εκ νέου των αναφερόμενων ωρών στο θέμα:' + text_user_wrote: "%{value} έγραψε:" + text_enumeration_destroy_question: "%{count} αντικείμενα έχουν τεθεί σε αυτή την τιμή." + text_enumeration_category_reassign_to: 'Επανεκχώρηση τους στην παρούσα αξία:' + text_email_delivery_not_configured: "Δεν έχουν γίνει ρυθμίσεις παράδοσης email, και οι ειδοποιήσεις είναι απενεργοποιημένες.\nΔηλώστε τον εξυπηρετητή SMTP στο config/configuration.yml και κάντε επανακκίνηση την εφαρμογή για να τις ρυθμίσεις." + text_repository_usernames_mapping: "Επιλέξτε ή ενημερώστε τον χρήστη Redmine που αντιστοιχεί σε κάθε όνομα χρήστη στο ιστορικό του αποθετηρίου.\nΧρήστες με το ίδιο όνομα χρήστη ή email στο Redmine και στο αποθετηρίο αντιστοιχίζονται αυτόματα." + text_diff_truncated: '... Αυτό το diff εχεί κοπεί επειδή υπερβαίνει το μέγιστο μέγεθος που μπορεί να προβληθεί.' + text_custom_field_possible_values_info: 'Μία γραμμή για κάθε τιμή' + text_wiki_page_destroy_question: "Αυτή η σελίδα έχει %{descendants} σελίδες τέκνων και απογόνων. Τι θέλετε να κάνετε ;" + text_wiki_page_nullify_children: "Διατηρήστε τις σελίδες τέκνων ως σελίδες root" + text_wiki_page_destroy_children: "Διαγράψτε όλες τις σελίδες τέκνων και των απογόνων τους" + text_wiki_page_reassign_children: "Επανεκχώριση των σελίδων τέκνων στη γονική σελίδα" + + default_role_manager: Manager + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Σφάλματα + default_tracker_feature: Λειτουργίες + default_tracker_support: Υποστήριξη + default_issue_status_new: Νέα + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Επιλυμένο + default_issue_status_feedback: Σχόλια + default_issue_status_closed: Κλειστό + default_issue_status_rejected: Απορριπτέο + default_doc_category_user: Τεκμηρίωση χρήστη + default_doc_category_tech: Τεχνική τεκμηρίωση + default_priority_low: Χαμηλή + default_priority_normal: Κανονική + default_priority_high: Υψηλή + default_priority_urgent: Επείγον + default_priority_immediate: Άμεση + default_activity_design: Σχεδιασμός + default_activity_development: Ανάπτυξη + + enumeration_issue_priorities: Προτεραιότητα θέματος + enumeration_doc_categories: Κατηγορία εγγράφων + enumeration_activities: Δραστηριότητες (κατακερματισμός χρόνου) + text_journal_changed: "%{label} άλλαξε από %{old} σε %{new}" + text_journal_set_to: "%{label} ορίζεται σε %{value}" + text_journal_deleted: "%{label} διαγράφηκε (%{old})" + label_group_plural: Ομάδες + label_group: Ομάδα + label_group_new: Νέα ομάδα + label_time_entry_plural: Χρόνος που δαπανήθηκε + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Κωδικοποίηση μηνυμάτων commit + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/53c4d6a7a29d3fa5b578b0d5db17f4ae870ab6e5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/53c4d6a7a29d3fa5b578b0d5db17f4ae870ab6e5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRolesBuiltin < ActiveRecord::Migration + def self.up + add_column :roles, :builtin, :integer, :default => 0, :null => false + end + + def self.down + remove_column :roles, :builtin + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/53e7bfd13c1bbfd84e32b60344b616bb91f37951.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/53e7bfd13c1bbfd84e32b60344b616bb91f37951.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,401 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class MailHandler < ActionMailer::Base + include ActionView::Helpers::SanitizeHelper + include Redmine::I18n + + class UnauthorizedAction < StandardError; end + class MissingInformation < StandardError; end + + attr_reader :email, :user + + def self.receive(email, options={}) + @@handler_options = options.dup + + @@handler_options[:issue] ||= {} + + @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String) + @@handler_options[:allow_override] ||= [] + # Project needs to be overridable if not specified + @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project) + # Status overridable by default + @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status) + + @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1' ? true : false) + super email + end + + # Processes incoming emails + # Returns the created object (eg. an issue, a message) or false + def receive(email) + @email = email + sender_email = email.from.to_a.first.to_s.strip + # Ignore emails received from the application emission address to avoid hell cycles + if sender_email.downcase == Setting.mail_from.to_s.strip.downcase + logger.info "MailHandler: ignoring email from Redmine emission address [#{sender_email}]" if logger && logger.info + return false + end + @user = User.find_by_mail(sender_email) if sender_email.present? + if @user && !@user.active? + logger.info "MailHandler: ignoring email from non-active user [#{@user.login}]" if logger && logger.info + return false + end + if @user.nil? + # Email was submitted by an unknown user + case @@handler_options[:unknown_user] + when 'accept' + @user = User.anonymous + when 'create' + @user = create_user_from_email(email) + if @user + logger.info "MailHandler: [#{@user.login}] account created" if logger && logger.info + Mailer.deliver_account_information(@user, @user.password) + else + logger.error "MailHandler: could not create account for [#{sender_email}]" if logger && logger.error + return false + end + else + # Default behaviour, emails from unknown users are ignored + logger.info "MailHandler: ignoring email from unknown user [#{sender_email}]" if logger && logger.info + return false + end + end + User.current = @user + dispatch + end + + private + + MESSAGE_ID_RE = %r{^ e + # TODO: send a email to the user + logger.error e.message if logger + false + rescue MissingInformation => e + logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger + false + rescue UnauthorizedAction => e + logger.error "MailHandler: unauthorized attempt from #{user}" if logger + false + end + + def dispatch_to_default + receive_issue + end + + # Creates a new issue + def receive_issue + project = target_project + # check permission + unless @@handler_options[:no_permission_check] + raise UnauthorizedAction unless user.allowed_to?(:add_issues, project) + end + + issue = Issue.new(:author => user, :project => project) + issue.safe_attributes = issue_attributes_from_keywords(issue) + issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} + issue.subject = email.subject.to_s.chomp[0,255] + if issue.subject.blank? + issue.subject = '(no subject)' + end + issue.description = cleaned_up_text_body + + # add To and Cc as watchers before saving so the watchers can reply to Redmine + add_watchers(issue) + issue.save! + add_attachments(issue) + logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info + issue + end + + # Adds a note to an existing issue + def receive_issue_reply(issue_id) + issue = Issue.find_by_id(issue_id) + return unless issue + # check permission + unless @@handler_options[:no_permission_check] + raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project) + end + + # ignore CLI-supplied defaults for new issues + @@handler_options[:issue].clear + + journal = issue.init_journal(user) + issue.safe_attributes = issue_attributes_from_keywords(issue) + issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} + journal.notes = cleaned_up_text_body + add_attachments(issue) + issue.save! + logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info + journal + end + + # Reply will be added to the issue + def receive_journal_reply(journal_id) + journal = Journal.find_by_id(journal_id) + if journal && journal.journalized_type == 'Issue' + receive_issue_reply(journal.journalized_id) + end + end + + # Receives a reply to a forum message + def receive_message_reply(message_id) + message = Message.find_by_id(message_id) + if message + message = message.root + + unless @@handler_options[:no_permission_check] + raise UnauthorizedAction unless user.allowed_to?(:add_messages, message.project) + end + + if !message.locked? + reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\d+\]}, '').strip, + :content => cleaned_up_text_body) + reply.author = user + reply.board = message.board + message.children << reply + add_attachments(reply) + reply + else + logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic" if logger && logger.info + end + end + end + + def add_attachments(obj) + if email.attachments && email.attachments.any? + email.attachments.each do |attachment| + obj.attachments << Attachment.create(:container => obj, + :file => attachment, + :author => user, + :content_type => attachment.content_type) + end + end + end + + # Adds To and Cc as watchers of the given object if the sender has the + # appropriate permission + def add_watchers(obj) + if user.allowed_to?("add_#{obj.class.name.underscore}_watchers".to_sym, obj.project) + addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase} + unless addresses.empty? + watchers = User.active.find(:all, :conditions => ['LOWER(mail) IN (?)', addresses]) + watchers.each {|w| obj.add_watcher(w)} + end + end + end + + def get_keyword(attr, options={}) + @keywords ||= {} + if @keywords.has_key?(attr) + @keywords[attr] + else + @keywords[attr] = begin + if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && (v = extract_keyword!(plain_text_body, attr, options[:format])) + v + elsif !@@handler_options[:issue][attr].blank? + @@handler_options[:issue][attr] + end + end + end + end + + # Destructively extracts the value for +attr+ in +text+ + # Returns nil if no matching keyword found + def extract_keyword!(text, attr, format=nil) + keys = [attr.to_s.humanize] + if attr.is_a?(Symbol) + keys << l("field_#{attr}", :default => '', :locale => user.language) if user && user.language.present? + keys << l("field_#{attr}", :default => '', :locale => Setting.default_language) if Setting.default_language.present? + end + keys.reject! {|k| k.blank?} + keys.collect! {|k| Regexp.escape(k)} + format ||= '.+' + text.gsub!(/^(#{keys.join('|')})[ \t]*:[ \t]*(#{format})\s*$/i, '') + $2 && $2.strip + end + + def target_project + # TODO: other ways to specify project: + # * parse the email To field + # * specific project (eg. Setting.mail_handler_target_project) + target = Project.find_by_identifier(get_keyword(:project)) + raise MissingInformation.new('Unable to determine target project') if target.nil? + target + end + + # Returns a Hash of issue attributes extracted from keywords in the email body + def issue_attributes_from_keywords(issue) + assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_assignee_from_keyword(k, issue) + + attrs = { + 'tracker_id' => (k = get_keyword(:tracker)) && issue.project.trackers.named(k).first.try(:id), + 'status_id' => (k = get_keyword(:status)) && IssueStatus.named(k).first.try(:id), + 'priority_id' => (k = get_keyword(:priority)) && IssuePriority.named(k).first.try(:id), + 'category_id' => (k = get_keyword(:category)) && issue.project.issue_categories.named(k).first.try(:id), + 'assigned_to_id' => assigned_to.try(:id), + 'fixed_version_id' => (k = get_keyword(:fixed_version, :override => true)) && issue.project.shared_versions.named(k).first.try(:id), + 'start_date' => get_keyword(:start_date, :override => true, :format => '\d{4}-\d{2}-\d{2}'), + 'due_date' => get_keyword(:due_date, :override => true, :format => '\d{4}-\d{2}-\d{2}'), + 'estimated_hours' => get_keyword(:estimated_hours, :override => true), + 'done_ratio' => get_keyword(:done_ratio, :override => true, :format => '(\d|10)?0') + }.delete_if {|k, v| v.blank? } + + if issue.new_record? && attrs['tracker_id'].nil? + attrs['tracker_id'] = issue.project.trackers.find(:first).try(:id) + end + + attrs + end + + # Returns a Hash of issue custom field values extracted from keywords in the email body + def custom_field_values_from_keywords(customized) + customized.custom_field_values.inject({}) do |h, v| + if value = get_keyword(v.custom_field.name, :override => true) + h[v.custom_field.id.to_s] = value + end + h + end + end + + # Returns the text/plain part of the email + # If not found (eg. HTML-only email), returns the body with tags removed + def plain_text_body + return @plain_text_body unless @plain_text_body.nil? + parts = @email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten + if parts.empty? + parts << @email + end + plain_text_part = parts.detect {|p| p.content_type == 'text/plain'} + if plain_text_part.nil? + # no text/plain part found, assuming html-only email + # strip html tags and remove doctype directive + @plain_text_body = strip_tags(@email.body.to_s) + @plain_text_body.gsub! %r{^ ]*(#{ delimiters.join('|') })\s*[\r\n].*", Regexp::MULTILINE) + body = body.gsub(regex, '') + end + body.strip + end + + def find_assignee_from_keyword(keyword, issue) + keyword = keyword.to_s.downcase + assignable = issue.assignable_users + assignee = nil + assignee ||= assignable.detect {|a| a.mail.to_s.downcase == keyword || a.login.to_s.downcase == keyword} + if assignee.nil? && keyword.match(/ /) + firstname, lastname = *(keyword.split) # "First Last Throwaway" + assignee ||= assignable.detect {|a| a.is_a?(User) && a.firstname.to_s.downcase == firstname && a.lastname.to_s.downcase == lastname} + end + if assignee.nil? + assignee ||= assignable.detect {|a| a.is_a?(Group) && a.name.downcase == keyword} + end + assignee + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/53/53eb3f2e1882327db7415ab09e0ccb8d4b2a4d5f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/53/53eb3f2e1882327db7415ab09e0ccb8d4b2a4d5f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1850 @@ +== Redmine changelog + +Redmine - project management software +Copyright (C) 2006-2012 Jean-Philippe Lang +http://www.redmine.org/ + +== 2012-02-06 v1.3.1 + +* Defect #9775: app/views/repository/_revision_graph.html.erb sets window.onload directly.. +* Defect #9792: Ruby 1.9: [v1.3.0] Error: incompatible character encodings for it translation on Calendar page +* Defect #9793: Bad spacing between numbered list and heading (recently broken). +* Defect #9795: Unrelated error message when creating a group with an invalid name +* Defect #9832: Revision graph height should depend on height of rows in revisions table +* Defect #9937: Repository settings are not saved when all SCM are disabled +* Defect #9961: Ukrainian "default_tracker_bug" is wrong +* Defect #10013: Rest API - Create Version -> Internal server error 500 +* Defect #10115: Javascript error - Can't attach more than 1 file on IE 6 and 7 +* Defect #10130: Broken italic text style in edited comment preview +* Defect #10152: Attachment diff type is not saved in user preference +* Feature #9943: Arabic translation +* Patch #9874: pt-BR translation updates +* Patch #9922: Spanish translation updated +* Patch #10137: Korean language file ko.yml updated to Redmine 1.3.0 + +== 2011-12-10 v1.3.0 + +* Defect #2109: Context menu is being submitted twice per right click +* Defect #7717: MailHandler user creation for unknown_user impossible due to diverging length-limits of login and email fields +* Defect #7917: Creating users via email fails if user real name containes special chars +* Defect #7966: MailHandler does not include JournalDetail for attached files +* Defect #8368: Bad decimal separator in time entry CSV +* Defect #8371: MySQL error when filtering a custom field using the REST api +* Defect #8549: Export CSV has character encoding error +* Defect #8573: Do not show inactive Enumerations where not needed +* Defect #8611: rake/rdoctask is deprecated +* Defect #8751: Email notification: bug, when number of recipients more then 8 +* Defect #8894: Private issues - make it more obvious in the UI? +* Defect #8994: Hardcoded French string "anonyme" +* Defect #9043: Hardcoded string "diff" in Wiki#show and Repositories_Helper +* Defect #9051: wrong "text_issue_added" in russian translation. +* Defect #9108: Custom query not saving status filter +* Defect #9252: Regression: application title escaped 2 times +* Defect #9264: Bad Portuguese translation +* Defect #9470: News list is missing Avatars +* Defect #9471: Inline markup broken in Wiki link labels +* Defect #9489: Label all input field and control tags +* Defect #9534: Precedence: bulk email header is non standard and discouraged +* Defect #9540: Issue filter by assigned_to_role is not project specific +* Defect #9619: Time zone ignored when logging time while editing ticket +* Defect #9638: Inconsistent image filename extensions +* Defect #9669: Issue list doesn't sort assignees/authors regarding user display format +* Defect #9672: Message-quoting in forums module broken +* Defect #9719: Filtering by numeric custom field types broken after update to master +* Defect #9724: Can't remote add new categories +* Defect #9738: Setting of cross-project custom query is not remembered inside project +* Defect #9748: Error about configuration.yml validness should mention file path +* Feature #69: Textilized description in PDF +* Feature #401: Add pdf export for WIKI page +* Feature #1567: Make author column sortable and groupable +* Feature #2222: Single section edit. +* Feature #2269: Default issue start date should become configurable. +* Feature #2371: character encoding for attachment file +* Feature #2964: Ability to assign issues to groups +* Feature #3033: Bug Reporting: Using "Create and continue" should show bug id of saved bug +* Feature #3261: support attachment images in PDF export +* Feature #4264: Update CodeRay to 1.0 final +* Feature #4324: Redmine renames my files, it shouldn't. +* Feature #4729: Add Date-Based Filters for Issues List +* Feature #4742: CSV export: option to export selected or all columns +* Feature #4976: Allow rdm-mailhandler to read the API key from a file +* Feature #5501: Git: Mercurial: Adding visual merge/branch history to repository view +* Feature #5634: Export issue to PDF does not include Subtasks and Related Issues +* Feature #5670: Cancel option for file upload +* Feature #5737: Custom Queries available through the REST Api +* Feature #6180: Searchable custom fields do not provide adequate operators +* Feature #6954: Filter from date to date +* Feature #7180: List of statuses in REST API +* Feature #7181: List of trackers in REST API +* Feature #7366: REST API for Issue Relations +* Feature #7403: REST API for Versions +* Feature #7671: REST API for reading attachments +* Feature #7832: Ability to assign issue categories to groups +* Feature #8420: Consider removing #7013 workaround +* Feature #9196: Improve logging in MailHandler when user creation fails +* Feature #9496: Adds an option in mailhandler to disable server certificate verification +* Feature #9553: CRUD operations for "Issue categories" in REST API +* Feature #9593: HTML title should be reordered +* Feature #9600: Wiki links for news and forums +* Feature #9607: Filter for issues without start date (or any another field based on date type) +* Feature #9609: Upgrade to Rails 2.3.14 +* Feature #9612: "side by side" and "inline" patch view for attachments +* Feature #9667: Check attachment size before upload +* Feature #9690: Link in notification pointing to the actual update +* Feature #9720: Add note number for single issue's PDF +* Patch #8617: Indent subject of subtask ticket in exported issues PDF +* Patch #8778: Traditional Chinese 'issue' translation change +* Patch #9053: Fix up Russian translation +* Patch #9129: Improve wording of Git repository note at project setting +* Patch #9148: Better handling of field_due_date italian translation +* Patch #9273: Fix typos in russian localization +* Patch #9484: Limit SCM annotate to text files under the maximum file size for viewing +* Patch #9659: Indexing rows in auth_sources/index view +* Patch #9692: Fix Textilized description in PDF for CodeRay + +== 2011-12-10 v1.2.3 + +* Defect #8707: Reposman: wrong constant name +* Defect #8809: Table in timelog report overflows +* Defect #9055: Version files in Files module cannot be downloaded if issue tracking is disabled +* Defect #9137: db:encrypt fails to handle repositories with blank password +* Defect #9394: Custom date field only validating on regex and not a valid date +* Defect #9405: Any user with :log_time permission can edit time entries via context menu +* Defect #9448: The attached images are not shown in documents +* Defect #9520: Copied private query not visible after project copy +* Defect #9552: Error when reading ciphered text from the database without cipher key configured +* Defect #9566: Redmine.pm considers all projects private when login_required is enabled +* Defect #9567: Redmine.pm potential security issue with cache credential enabled and subversion +* Defect #9577: Deleting a subtasks doesn't update parent's rgt & lft values +* Defect #9597: Broken version links in wiki annotate history +* Defect #9682: Wiki HTML Export only useful when Access history is accessible +* Defect #9737: Custom values deleted before issue submit +* Defect #9741: calendar-hr.js (Croatian) is not UTF-8 +* Patch #9558: Simplified Chinese translation for 1.2.2 updated +* Patch #9695: Bulgarian translation (r7942) + +== 2011-11-11 v1.2.2 + +* Defect #3276: Incorrect handling of anchors in Wiki to HTML export +* Defect #7215: Wiki formatting mangles links to internal headers +* Defect #7613: Generated test instances may share the same attribute value object +* Defect #8411: Can't remove "Project" column on custom query +* Defect #8615: Custom 'version' fields don't show shared versions +* Defect #8633: Pagination counts non visible issues +* Defect #8651: Email attachments are not added to issues any more in v1.2 +* Defect #8825: JRuby + Windows: SCMs do not work on Redmine 1.2 +* Defect #8836: Additional workflow transitions not available when set to both author and assignee +* Defect #8865: Custom field regular expression is not validated +* Defect #8880: Error deleting issue with grandchild +* Defect #8884: Assignee is cleared when updating issue with locked assignee +* Defect #8892: Unused fonts in rfpdf plugin folder +* Defect #9161: pt-BR field_warn_on_leaving_unsaved has a small gramatical error +* Defect #9308: Search fails when a role haven't "view wiki" permission +* Defect #9465: Mercurial: can't browse named branch below Mercurial 1.5 + +== 2011-07-11 v1.2.1 + +* Defect #5089: i18N error on truncated revision diff view +* Defect #7501: Search options get lost after clicking on a specific result type +* Defect #8229: "project.xml" response does not include the parent ID +* Defect #8449: Wiki annotated page does not display author of version 1 +* Defect #8467: Missing german translation - Warn me when leaving a page with unsaved text +* Defect #8468: No warning when leaving page with unsaved text that has not lost focus +* Defect #8472: Private checkbox ignored on issue creation with "Set own issues public or private" permission +* Defect #8510: JRuby: Can't open administrator panel if scm command is not available +* Defect #8512: Syntax highlighter on Welcome page +* Defect #8554: Translation missing error on custom field validation +* Defect #8565: JRuby: Japanese PDF export error +* Defect #8566: Exported PDF UTF-8 Vietnamese not correct +* Defect #8569: JRuby: PDF export error with TypeError +* Defect #8576: Missing german translation - different things +* Defect #8616: Circular relations +* Defect #8646: Russian translation "label_follows" and "label_follows" are wrong +* Defect #8712: False 'Description updated' journal details messages +* Defect #8729: Not-public queries are not private +* Defect #8737: Broken line of long issue description on issue PDF. +* Defect #8738: Missing revision number/id of associated revisions on issue PDF +* Defect #8739: Workflow copy does not copy advanced workflow settings +* Defect #8759: Setting issue attributes from mail should be case-insensitive +* Defect #8777: Mercurial: Not able to Resetting Redmine project respository + +== 2011-05-30 v1.2.0 + +* Defect #61: Broken character encoding in pdf export +* Defect #1965: Redmine is not Tab Safe +* Defect #2274: Filesystem Repository path encoding of non UTF-8 characters +* Defect #2664: Mercurial: Repository path encoding of non UTF-8 characters +* Defect #3421: Mercurial reads files from working dir instead of changesets +* Defect #3462: CVS: Repository path encoding of non UTF-8 characters +* Defect #3715: Login page should not show projects link and search box if authentication is required +* Defect #3724: Mercurial repositories display revision ID instead of changeset ID +* Defect #3761: Most recent CVS revisions are missing in "revisions" view +* Defect #4270: CVS Repository view in Project doesn't show Author, Revision, Comment +* Defect #5138: Don't use Ajax for pagination +* Defect #5152: Cannot use certain characters for user and role names. +* Defect #5251: Git: Repository path encoding of non UTF-8 characters +* Defect #5373: Translation missing when adding invalid watchers +* Defect #5817: Shared versions not shown in subproject's gantt chart +* Defect #6013: git tab,browsing, very slow -- even after first time +* Defect #6148: Quoting, newlines, and nightmares... +* Defect #6256: Redmine considers non ASCII and UTF-16 text files as binary in SCM +* Defect #6476: Subproject's issues are not shown in the subproject's gantt +* Defect #6496: Remove i18n 0.3.x/0.4.x hack for Rails 2.3.5 +* Defect #6562: Context-menu deletion of issues deletes all subtasks too without explicit prompt +* Defect #6604: Issues targeted at parent project versions' are not shown on gantt chart +* Defect #6706: Resolving issues with the commit message produces the wrong comment with CVS +* Defect #6901: Copy/Move an issue does not give any history of who actually did the action. +* Defect #6905: Specific heading-content breaks CSS +* Defect #7000: Project filter not applied on versions in Gantt chart +* Defect #7097: Starting day of week cannot be set to Saturday +* Defect #7114: New gantt doesn't display some projects +* Defect #7146: Git adapter lost commits before 7 days from database latest changeset +* Defect #7218: Date range error on issue query +* Defect #7257: "Issues by" version links bad criterias +* Defect #7279: CSS class ".icon-home" is not used. +* Defect #7320: circular dependency >2 issues +* Defect #7352: Filters not working in Gantt charts +* Defect #7367: Receiving pop3 email should not output debug messages +* Defect #7373: Error with PDF output and ruby 1.9.2 +* Defect #7379: Remove extraneous hidden_field on wiki history +* Defect #7516: Redmine does not work with RubyGems 1.5.0 +* Defect #7518: Mercurial diff can be wrong if the previous changeset isn't the parent +* Defect #7581: Not including a spent time value on the main issue update screen causes silent data loss +* Defect #7582: hiding form pages from search engines +* Defect #7597: Subversion and Mercurial log have the possibility to miss encoding +* Defect #7604: ActionView::TemplateError (undefined method `name' for nil:NilClass) +* Defect #7605: Using custom queries always redirects to "Issues" tab +* Defect #7615: CVS diffs do not handle new files properly +* Defect #7618: SCM diffs do not handle one line new files properly +* Defect #7639: Some date fields do not have requested format. +* Defect #7657: Wrong commit range in git log command on Windows +* Defect #7818: Wiki pages don't use the local timezone to display the "Updated ? hours ago" mouseover +* Defect #7821: Git "previous" and "next" revisions are incorrect +* Defect #7827: CVS: Age column on repository view is off by timezone delta +* Defect #7843: Add a relation between issues = explicit login window ! (basic authentication popup is prompted on AJAX request) +* Defect #8011: {{toc}} does not display headlines with inline code markup +* Defect #8029: List of users for adding to a group may be empty if 100 first users have been added +* Defect #8064: Text custom fields do not wrap on the issue list +* Defect #8071: Watching a subtask from the context menu updates main issue watch link +* Defect #8072: Two untranslatable default role names +* Defect #8075: Some "notifiable" names are not i18n-enabled +* Defect #8081: GIT: Commits missing when user has the "decorate" git option enabled +* Defect #8088: Colorful indentation of subprojects must be on right in RTL locales +* Defect #8239: notes field is not propagated during issue copy +* Defect #8356: GET /time_entries.xml ignores limit/offset parameters +* Defect #8432: Private issues information shows up on Activity page for unauthorized users +* Feature #746: Versioned issue descriptions +* Feature #1067: Differentiate public/private saved queries in the sidebar +* Feature #1236: Make destination folder for attachment uploads configurable +* Feature #1735: Per project repository log encoding setting +* Feature #1763: Autologin-cookie should be configurable +* Feature #1981: display mercurial tags +* Feature #2074: Sending email notifications when comments are added in the news section +* Feature #2096: Custom fields referencing system tables (users and versions) +* Feature #2732: Allow additional workflow transitions for author and assignee +* Feature #2910: Warning on leaving edited issue/wiki page without saving +* Feature #3396: Git: use --encoding=UTF-8 in "git log" +* Feature #4273: SCM command availability automatic check in administration panel +* Feature #4477: Use mime types in downloading from repository +* Feature #5518: Graceful fallback for "missing translation" needed +* Feature #5520: Text format buttons and preview link missing when editing comment +* Feature #5831: Parent Task to Issue Bulk Edit +* Feature #6887: Upgrade to Rails 2.3.11 +* Feature #7139: Highlight changes inside diff lines +* Feature #7236: Collapse All for Groups +* Feature #7246: Handle "named branch" for mercurial +* Feature #7296: Ability for admin to delete users +* Feature #7318: Add user agent to Redmine Mailhandler +* Feature #7408: Add an application configuration file +* Feature #7409: Cross project Redmine links +* Feature #7410: Add salt to user passwords +* Feature #7411: Option to cipher LDAP ans SCM passwords stored in the database +* Feature #7412: Add an issue visibility level to each role +* Feature #7414: Private issues +* Feature #7517: Configurable path of executable for scm adapters +* Feature #7640: Add "mystery man" gravatar to options +* Feature #7858: RubyGems 1.6 support +* Feature #7893: Group filter on the users list +* Feature #7899: Box for editing comments should open with the formatting toolbar +* Feature #7921: issues by pulldown should have 'status' option +* Feature #7996: Bulk edit and context menu for time entries +* Feature #8006: Right click context menu for Related Issues +* Feature #8209: I18n YAML files not parsable with psych yaml library +* Feature #8345: Link to user profile from account page +* Feature #8365: Git: per project setting to report last commit or not in repository tree +* Patch #5148: metaKey not handled in issues selection +* Patch #5629: Wrap text fields properly in PDF +* Patch #7418: Redmine Persian Translation +* Patch #8295: Wrap title fields properly in PDF +* Patch #8310: fixes automatic line break problem with TCPDF +* Patch #8312: Switch to TCPDF from FPDF for PDF export + +== 2011-04-29 v1.1.3 + +* Defect #5773: Email reminders are sent to locked users +* Defect #6590: Wrong file list link in email notification on new file upload +* Defect #7589: Wiki page with backslash in title can not be found +* Defect #7785: Mailhandler keywords are not removed when updating issues +* Defect #7794: Internal server error on formatting an issue as a PDF in Japanese +* Defect #7838: Gantt- Issues does not show up in green when start and end date are the same +* Defect #7846: Headers (h1, etc.) containing backslash followed by a digit are not displayed correctly +* Defect #7875: CSV export separators in polish locale (pl.yml) +* Defect #7890: Internal server error when referencing an issue without project in commit message +* Defect #7904: Subprojects not properly deleted when deleting a parent project +* Defect #7939: Simultaneous Wiki Updates Cause Internal Error +* Defect #7951: Atom links broken on wiki index +* Defect #7954: IE 9 can not select issues, does not display context menu +* Defect #7985: Trying to do a bulk edit results in "Internal Error" +* Defect #8003: Error raised by reposman.rb under Windows server 2003 +* Defect #8012: Wrong selection of modules when adding new project after validation error +* Defect #8038: Associated Revisions OL/LI items are not styled properly in issue view +* Defect #8067: CSV exporting in Italian locale +* Defect #8235: bulk edit issues and copy issues error in es, gl and ca locales +* Defect #8244: selected modules are not activated when copying a project +* Patch #7278: Update Simplified Chinese translation to 1.1 +* Patch #7390: Fixes in Czech localization +* Patch #7963: Reminder email: Link for show all issues does not sort + +== 2011-03-07 v1.1.2 + +* Defect #3132: Bulk editing menu non-functional in Opera browser +* Defect #6090: Most binary files become corrupted when downloading from CVS repository browser when Redmine is running on a Windows server +* Defect #7280: Issues subjects wrap in Gantt +* Defect #7288: Non ASCII filename downloaded from repo is broken on Internet Explorer. +* Defect #7317: Gantt tab gives internal error due to nil avatar icon +* Defect #7497: Aptana Studio .project file added to version 1.1.1-stable +* Defect #7611: Workflow summary shows X icon for workflow with exactly 1 status transition +* Defect #7625: Syntax highlighting unavailable from board new topic or topic edit preview +* Defect #7630: Spent time in commits not recognized +* Defect #7656: MySQL SQL Syntax Error when filtering issues by Assignee's Group +* Defect #7718: Minutes logged in commit message are converted to hours +* Defect #7763: Email notification are sent to watchers even if 'No events' setting is chosen +* Feature #7608: Add "retro" gravatars +* Patch #7598: Extensible MailHandler +* Patch #7795: Internal server error at journals#index with custom fields + +== 2011-01-30 v1.1.1 + +* Defect #4899: Redmine fails to list files for darcs repository +* Defect #7245: Wiki fails to find pages with cyrillic characters using postgresql +* Defect #7256: redmine/public/.htaccess must be moved for non-fastcgi installs/upgrades +* Defect #7258: Automatic spent time logging does not work properly with SQLite3 +* Defect #7259: Released 1.1.0 uses "devel" label inside admin information +* Defect #7265: "Loading..." icon does not disappear after add project member +* Defect #7266: Test test_due_date_distance_in_words fail due to undefined locale +* Defect #7274: CSV value separator in dutch locale +* Defect #7277: Enabling gravatas causes usernames to overlap first name field in user list +* Defect #7294: "Notifiy for only project I select" is not available anymore in 1.1.0 +* Defect #7307: HTTP 500 error on query for empty revision +* Defect #7313: Label not translated in french in Settings/Email Notification tab +* Defect #7329: with long strings may hang server +* Defect #7337: My page french translation +* Defect #7348: French Translation of "Connection" +* Defect #7385: Error when viewing an issue which was related to a deleted subtask +* Defect #7386: NoMethodError on pdf export +* Defect #7415: Darcs adapter recognizes new files as modified files above Darcs 2.4 +* Defect #7421: no email sent with 'Notifiy for any event on the selected projects only' +* Feature #5344: Update to latest CodeRay 0.9.x + +== 2011-01-09 v1.1.0 + +* Defect #2038: Italics in wiki headers show-up wrong in the toc +* Defect #3449: Redmine Takes Too Long On Large Mercurial Repository +* Defect #3567: Sorting for changesets might go wrong on Mercurial repos +* Defect #3707: {{toc}} doesn't work with {{include}} +* Defect #5096: Redmine hangs up while browsing Git repository +* Defect #6000: Safe Attributes prevents plugin extension of Issue model... +* Defect #6064: Modules not assigned to projects created via API +* Defect #6110: MailHandler should allow updating Issue Priority and Custom fields +* Defect #6136: JSON API holds less information than XML API +* Defect #6345: xml used by rest API is invalid +* Defect #6348: Gantt chart PDF rendering errors +* Defect #6403: Updating an issue with custom fields fails +* Defect #6467: "Member of role", "Member of group" filter not work correctly +* Defect #6473: New gantt broken after clearing issue filters +* Defect #6541: Email notifications send to everybody +* Defect #6549: Notification settings not migrated properly +* Defect #6591: Acronyms must have a minimum of three characters +* Defect #6674: Delete time log broken after changes to REST +* Defect #6681: Mercurial, Bazaar and Darcs auto close issue text should be commit id instead of revision number +* Defect #6724: Wiki uploads does not work anymore (SVN 4266) +* Defect #6746: Wiki links are broken on Activity page +* Defect #6747: Wiki diff does not work since r4265 +* Defect #6763: New gantt charts: subject displayed twice on issues +* Defect #6826: Clicking "Add" twice creates duplicate member record +* Defect #6844: Unchecking status filter on the issue list has no effect +* Defect #6895: Wrong Polish translation of "blocks" +* Defect #6943: Migration from boolean to varchar fails on PostgreSQL 8.1 +* Defect #7064: Mercurial adapter does not recognize non alphabetic nor numeric in UTF-8 copied files +* Defect #7128: New gantt chart does not render subtasks under parent task +* Defect #7135: paging mechanism returns the same last page forever +* Defect #7188: Activity page not refreshed when changing language +* Defect #7195: Apply CLI-supplied defaults for incoming mail only to new issues not replies +* Defect #7197: Tracker reset to default when replying to an issue email +* Defect #7213: Copy project does not copy all roles and permissions +* Defect #7225: Project settings: Trackers & Custom fields only relevant if module Issue tracking is active +* Feature #630: Allow non-unique names for projects +* Feature #1738: Add a "Visible" flag to project/user custom fields +* Feature #2803: Support for Javascript in Themes +* Feature #2852: Clean Incoming Email of quoted text "----- Reply above this line ------" +* Feature #2995: Improve error message when trying to access an archived project +* Feature #3170: Autocomplete issue relations on subject +* Feature #3503: Administrator Be Able To Modify Email settings Of Users +* Feature #4155: Automatic spent time logging from commit messages +* Feature #5136: Parent select on Wiki rename page +* Feature #5338: Descendants (subtasks) should be available via REST API +* Feature #5494: Wiki TOC should display heading from level 4 +* Feature #5594: Improve MailHandler's keyword handling +* Feature #5622: Allow version to be set via incoming email +* Feature #5712: Reload themes +* Feature #5869: Issue filters by Group and Role +* Feature #6092: Truncate Git revision labels in Activity page/feed and allow configurable length +* Feature #6112: Accept localized keywords when receiving emails +* Feature #6140: REST issues response with issue count limit and offset +* Feature #6260: REST API for Users +* Feature #6276: Gantt Chart rewrite +* Feature #6446: Remove length limits on project identifier and name +* Feature #6628: Improvements in truncate email +* Feature #6779: Project JSON API +* Feature #6823: REST API for time tracker. +* Feature #7072: REST API for news +* Feature #7111: Expose more detail on journal entries +* Feature #7141: REST API: get information about current user +* Patch #4807: Allow to set the done_ratio field with the incoming mail system +* Patch #5441: Initialize TimeEntry attributes with params[:time_entry] +* Patch #6762: Use GET instead of POST to retrieve context_menu +* Patch #7160: French translation ofr "not_a_date" is missing +* Patch #7212: Missing remove_index in AddUniqueIndexOnMembers down migration + + +== 2010-12-23 v1.0.5 + +* #6656: Mercurial adapter loses seconds of commit times +* #6996: Migration trac(sqlite3) -> redmine(postgresql) doesnt escape ' char +* #7013: v-1.0.4 trunk - see {{count}} in page display rather than value +* #7016: redundant 'field_start_date' in ja.yml +* #7018: 'undefined method `reschedule_after' for nil:NilClass' on new issues +* #7024: E-mail notifications about Wiki changes. +* #7033: 'class' attribute of
 tag shouldn't be truncate
+* #7035: CSV value separator in russian
+* #7122: Issue-description Quote-button missing
+* #7144: custom queries making use of deleted custom fields cause a 500 error
+* #7162: Multiply defined label in french translation
+
+== 2010-11-28 v1.0.4
+
+* #5324: Git not working if color.ui is enabled
+* #6447: Issues API doesn't allow full key auth for all actions
+* #6457: Edit User group problem
+* #6575: start date being filled with current date even when blank value is submitted
+* #6740: Max attachment size, incorrect usage of 'KB'
+* #6760: Select box sorted by ID instead of name in Issue Category
+* #6766: Changing target version name can cause an internal error
+* #6784: Redmine not working with i18n gem 0.4.2
+* #6839: Hardcoded absolute links in my/page_layout
+* #6841: Projects API doesn't allow full key auth for all actions
+* #6860: svn: Write error: Broken pipe when browsing repository
+* #6874: API should return XML description when creating a project
+* #6932: submitting wrong parent task input creates a 500 error
+* #6966: Records of Forums are remained, deleting project
+* #6990: Layout problem in workflow overview
+* #5117: mercurial_adapter should ensure the right LANG environment variable
+* #6782: Traditional Chinese language file (to r4352)
+* #6783: Swedish Translation for r4352
+* #6804: Bugfix: spelling fixes
+* #6814: Japanese Translation for r4362
+* #6948: Bulgarian translation
+* #6973: Update es.yml
+
+== 2010-10-31 v1.0.3
+
+* #4065: Redmine.pm doesn't work with LDAPS and a non-standard port
+* #4416: Link from version details page to edit the wiki.
+* #5484: Add new issue as subtask to an existing ticket
+* #5948: Update help/wiki_syntax_detailed.html with more link options
+* #6494: Typo in pt_BR translation for 1.0.2
+* #6508: Japanese translation update
+* #6509: Localization pt-PT (new strings)
+* #6511: Rake task to test email
+* #6525: Traditional Chinese language file (to r4225)
+* #6536: Patch for swedish translation
+* #6548: Rake tasks to add/remove i18n strings
+* #6569: Updated Hebrew translation
+* #6570: Japanese Translation for r4231
+* #6596: pt-BR translation updates
+* #6629: Change field-name of issues start date
+* #6669: Bulgarian translation
+* #6731: Macedonian translation fix
+* #6732: Japanese Translation for r4287
+* #6735: Add user-agent to reposman
+* #6736: Traditional Chinese language file (to r4288)
+* #6739: Swedish Translation for r4288
+* #6765: Traditional Chinese language file (to r4302)
+* Fixed #5324: Git not working if color.ui is enabled
+* Fixed #5652: Bad URL parsing in the wiki when it ends with right-angle-bracket(greater-than mark).
+* Fixed #5803: Precedes/Follows Relationships Broke
+* Fixed #6435: Links to wikipages bound to versions do not respect version-sharing in Settings -> Versions
+* Fixed #6438: Autologin cannot be disabled again once it's enabled
+* Fixed #6513: "Move" and "Copy" are not displayed when deployed in subdirectory
+* Fixed #6521: Tooltip/label for user "search-refinment" field on group/project member list
+* Fixed #6563: i18n-issues on calendar view
+* Fixed #6598: Wrong caption for button_create_and_continue in German language file
+* Fixed #6607: Unclear caption for german button_update
+* Fixed #6612: SortHelper missing from CalendarsController
+* Fixed #6740: Max attachment size, incorrect usage of 'KB'
+* Fixed #6750: ActionView::TemplateError (undefined method `empty?' for nil:NilClass) on line #12 of app/views/context_menus/issues.html.erb:
+
+== 2010-09-26 v1.0.2
+
+* #2285: issue-refinement: pressing enter should result to an "apply"
+* #3411: Allow mass status update trough context menu
+* #5929: https-enabled gravatars when called over https
+* #6189: Japanese Translation for r4011
+* #6197: Traditional Chinese language file (to r4036)
+* #6198: Updated german translation
+* #6208: Macedonian translation
+* #6210: Swedish Translation for r4039
+* #6248: nl translation update for r4050
+* #6263: Catalan translation update
+* #6275: After submitting a related issue, the Issue field should be re-focused
+* #6289: Checkboxes in issues list shouldn't be displayed when printing
+* #6290: Make journals theming easier
+* #6291: User#allowed_to? is not tested
+* #6306: Traditional Chinese language file (to r4061)
+* #6307: Korean translation update for 4066(4061)
+* #6316: pt_BR update
+* #6339: SERBIAN Updated
+* #6358: Updated Polish translation
+* #6363: Japanese Translation for r4080
+* #6365: Traditional Chinese language file (to r4081)
+* #6382: Issue PDF export variable usage
+* #6428: Interim solution for i18n >= 0.4
+* #6441: Japanese Translation for r4162
+* #6451: Traditional Chinese language file (to r4167)
+* #6465: Japanese Translation for r4171
+* #6466: Traditional Chinese language file (to r4171)
+* #6490: pt-BR translation for 1.0.2
+* Fixed #3935: stylesheet_link_tag with plugin doesn't take into account relative_url_root
+* Fixed #4998: Global issue list's context menu has enabled options for parent menus but there are no valid selections
+* Fixed #5170: Done ratio can not revert to 0% if status is used for done ratio
+* Fixed #5608: broken with i18n 0.4.0
+* Fixed #6054: Error 500 on filenames with whitespace in git reposities
+* Fixed #6135: Default logger configuration grows without bound.
+* Fixed #6191: Deletion of a main task deletes all subtasks
+* Fixed #6195: Missing move issues between projects
+* Fixed #6242: can't switch between inline and side-by-side diff
+* Fixed #6249: Create and continue returns 404
+* Fixed #6267: changing the authentication mode from ldap to internal with setting the password
+* Fixed #6270: diff coderay malformed in the "news" page
+* Fixed #6278: missing "cant_link_an_issue_with_a_descendant"from locale files
+* Fixed #6333: Create and continue results in a 404 Error
+* Fixed #6346: Age column on repository view is skewed for git, probably CVS too
+* Fixed #6351: Context menu on roadmap broken
+* Fixed #6388: New Subproject leads to a 404
+* Fixed #6392: Updated/Created links to activity broken
+* Fixed #6413: Error in SQL
+* Fixed #6443: Redirect to project settings after Copying a Project
+* Fixed #6448: Saving a wiki page with no content has a translation missing
+* Fixed #6452: Unhandled exception on creating File
+* Fixed #6471: Typo in label_report in Czech translation
+* Fixed #6479: Changing tracker type will lose watchers
+* Fixed #6499: Files with leading or trailing whitespace are not shown in git.
+
+== 2010-08-22 v1.0.1
+
+* #819: Add a body ID and class to all pages
+* #871: Commit new CSS styles!
+* #3301: Add favicon to base layout
+* #4656: On Issue#show page, clicking on “Add related issue� should focus on the input
+* #4896: Project identifier should be a limited field
+* #5084: Filter all isssues by projects
+* #5477: Replace Test::Unit::TestCase with ActiveSupport::TestCase
+* #5591: 'calendar' action is used with 'issue' controller in issue/sidebar
+* #5735: Traditional Chinese language file (to r3810)
+* #5740: Swedish Translation for r3810
+* #5785: pt-BR translation update
+* #5898: Projects should be displayed as links in users/memberships
+* #5910: Chinese translation to redmine-1.0.0
+* #5912: Translation update for french locale
+* #5962: Hungarian translation update to r3892
+* #5971: Remove falsly applied chrome on revision links
+* #5972: Updated Hebrew translation for 1.0.0
+* #5982: Updated german translation
+* #6008: Move admin_menu to Redmine::MenuManager
+* #6012: RTL layout
+* #6021: Spanish translation 1.0.0-RC
+* #6025: nl translation updated for r3905
+* #6030: Japanese Translation for r3907
+* #6074: sr-CY.yml contains DOS-type newlines (\r\n)
+* #6087: SERBIAN translation updated
+* #6093: Updated italian translation
+* #6142: Swedish Translation for r3940
+* #6153: Move view_calendar and view_gantt to own modules
+* #6169: Add issue status to issue tooltip
+* Fixed #3834: Add a warning when not choosing a member role
+* Fixed #3922: Bad english arround "Assigned to" text in journal entries
+* Fixed #5158: Simplified Chinese language file zh.yml updated to r3608
+* Fixed #5162: translation missing: zh-TW, field_time_entrie
+* Fixed #5297: openid not validated correctly
+* Fixed #5628: Wrong commit range in git log command
+* Fixed #5760: Assigned_to and author filters in "Projects>View all issues" should be based on user's project visibility
+* Fixed #5771: Problem when importing git repository
+* Fixed #5775: ldap authentication in admin menu should have an icon
+* Fixed #5811: deleting statuses doesnt delete workflow entries
+* Fixed #5834: Emails with trailing spaces incorrectly detected as invalid
+* Fixed #5846: ChangeChangesPathLengthLimit does not remove default for MySQL
+* Fixed #5861: Vertical scrollbar always visible in Wiki "code" blocks in Chrome.
+* Fixed #5883: correct label_project_latest Chinese translation
+* Fixed #5892: Changing status from contextual menu opens the ticket instead
+* Fixed #5904: Global gantt PDF and PNG should display project names
+* Fixed #5925: parent task's priority edit should be disabled through shortcut menu in issues list page
+* Fixed #5935: Add Another file to ticket doesn't work in IE Internet Explorer
+* Fixed #5937: Harmonize french locale "zero" translation with other locales
+* Fixed #5945: Forum message permalinks don't take pagination into account
+* Fixed #5978: Debug code still remains
+* Fixed #6009: When using "English (British)", the repository browser (svn) shows files over 1000 bytes as floating point (2.334355)
+* Fixed #6045: Repository file Diff view sometimes shows more than selected file
+* Fixed #6079: German Translation error in TimeEntryActivity
+* Fixed #6100: User's profile should display all visible projects
+* Fixed #6132: Allow Key based authentication in the Boards atom feed
+* Fixed #6163: Bad CSS class for calendar project menu_item
+* Fixed #6172: Browsing to a missing user's page shows the admin sidebar
+
+== 2010-07-18 v1.0.0 (Release candidate)
+
+* #443: Adds context menu to the roadmap issue lists
+* #443: Subtasking
+* #741: Description preview while editing an issue
+* #1131: Add support for alternate (non-LDAP) authentication
+* #1214: REST API for Issues
+* #1223: File upload on wiki edit form
+* #1755: add "blocked by" as a related issues option
+* #2420: Fetching emails from an POP server
+* #2482: Named scopes in Issue and ActsAsWatchable plus some view refactoring (logic extraction).
+* #2924: Make the right click menu more discoverable using a cursor property
+* #2985: Make syntax highlighting pluggable
+* #3201: Workflow Check/Uncheck All Rows/Columns
+* #3359: Update CodeRay 0.9
+* #3706: Allow assigned_to field configuration on Issue creation by email
+* #3936: configurable list of models to include in search
+* #4480: Create a link to the user profile from the administration interface
+* #4482: Cache textile rendering
+* #4572: Make it harder to ruin your database
+* #4573: Move github gems to Gemcutter
+* #4664: Add pagination to forum threads
+* #4732: Make login case-insensitive also for PostgreSQL
+* #4812: Create links to other projects
+* #4819: Replace images with smushed ones for speed
+* #4945: Allow custom fields attached to project to be searchable
+* #5121: Fix issues list layout overflow
+* #5169: Issue list view hook request
+* #5208: Aibility to edit wiki sidebar
+* #5281: Remove empty ul tags in the issue history
+* #5291: Updated basque translations
+* #5328: Automatically add "Repository" menu_item after repository creation
+* #5415: Fewer SQL statements generated for watcher_recipients
+* #5416: Exclude "fields_for" from overridden methods in TabularFormBuilder
+* #5573: Allow issue assignment in email
+* #5595: Allow start date and due dates to be set via incoming email
+* #5752: The projects view (/projects) renders ul's wrong
+* #5781: Allow to use more macros on the welcome page and project list
+* Fixed #1288: Unable to past escaped wiki syntax in an issue description
+* Fixed #1334: Wiki formatting character *_ and _*
+* Fixed #1416: Inline code with less-then/greater-than produces @lt; and @gt; respectively
+* Fixed #2473: Login and mail should not be case sensitive
+* Fixed #2990: Ruby 1.9 - wrong number of arguments (1 for 0) on rake db:migrate
+* Fixed #3089: Text formatting sometimes breaks when combined
+* Fixed #3690: Status change info duplicates on the issue screen
+* Fixed #3691: Redmine allows two files with the same file name to be uploaded to the same issue
+* Fixed #3764: ApplicationHelperTest fails with JRuby
+* Fixed #4265: Unclosed code tags in issue descriptions affects main UI
+* Fixed #4745: Bug in index.xml.builder (issues)
+* Fixed #4852: changing user/roles of project member not possible without javascript
+* Fixed #4857: Week number calculation in date picker is wrong if a week starts with Sunday
+* Fixed #4883: Bottom "contextual" placement in issue with associated changeset
+* Fixed #4918: Revisions r3453 and r3454 broke On-the-fly user creation with LDAP
+* Fixed #4935: Navigation to the Master Timesheet page (time_entries)
+* Fixed #5043: Flash messages are not displayed after the project settings[module/activity] saved
+* Fixed #5081: Broken links on public/help/wiki_syntax_detailed.html
+* Fixed #5104: Description of document not wikified on documents index
+* Fixed #5108: Issue linking fails inside of []s
+* Fixed #5199: diff code coloring using coderay
+* Fixed #5233: Add a hook to the issue report (Summary) view
+* Fixed #5265: timetracking: subtasks time is added to the main task
+* Fixed #5343: acts_as_event Doesn't Accept Outside URLs
+* Fixed #5440: UI Inconsistency : Administration > Enumerations table row headers should be enclosed in 
+* Fixed #5463: 0.9.4 INSTALL and/or UPGRADE, missing session_store.rb
+* Fixed #5524: Update_parent_attributes doesn't work for the old parent issue when reparenting
+* Fixed #5548: SVN Repository: Can not list content of a folder which includes square brackets.
+* Fixed #5589: "with subproject" malfunction
+* Fixed #5676: Search for Numeric Value
+* Fixed #5696: Redmine + PostgreSQL 8.4.4 fails on _dir_list_content.rhtml
+* Fixed #5698: redmine:email:receive_imap fails silently for mails with subject longer than 255 characters
+* Fixed #5700: TimelogController#destroy assumes success
+* Fixed #5751: developer role is mispelled
+* Fixed #5769: Popup Calendar doesn't Advance in Chrome
+* Fixed #5771: Problem when importing git repository
+* Fixed #5823: Error in comments in plugin.rb
+
+
+== 2010-07-07 v0.9.6
+
+* Fixed: Redmine.pm access by unauthorized users
+
+== 2010-06-24 v0.9.5
+
+* Linkify folder names on revision view
+* "fiters" and "options" should be hidden in print view via css
+* Fixed: NoMethodError when no issue params are submitted
+* Fixed: projects.atom with required authentication
+* Fixed: External links not correctly displayed in Wiki TOC
+* Fixed: Member role forms in project settings are not hidden after member added
+* Fixed: pre can't be inside p
+* Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT
+* Fixed: mail handler fails when the from address is empty
+
+
+== 2010-05-01 v0.9.4
+
+* Filters collapsed by default on issues index page for a saved query
+* Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list)
+* Fixed: remove "main-menu" div when the menu is empty
+* Fixed: Code syntax highlighting not working in Document page
+* Fixed: Git blame/annotate fails on moved files
+* Fixed: Failing test in test_show_atom
+* Fixed: Migrate from trac - not displayed Wikis
+* Fixed: Email notifications on file upload sent to empty recipient list
+* Fixed: Migrating from trac is not possible, fails to allocate memory
+* Fixed: Lost password no longer flashes a confirmation message
+* Fixed: Crash while deleting in-use enumeration
+* Fixed: Hard coded English string at the selection of issue watchers
+* Fixed: Bazaar v2.1.0 changed behaviour
+* Fixed: Roadmap display can raise an exception if no trackers are selected
+* Fixed: Gravatar breaks layout of "logged in" page
+* Fixed: Reposman.rb on Windows
+* Fixed: Possible error 500 while moving an issue to another project with SQLite
+* Fixed: backslashes in issue description/note should be escaped when quoted
+* Fixed: Long text in 
 disrupts Associated revisions
+* Fixed: Links to missing wiki pages not red on project overview page
+* Fixed: Cannot delete a project with subprojects that shares versions
+* Fixed: Update of Subversion changesets broken under Solaris
+* Fixed: "Move issues" permission not working for Non member
+* Fixed: Sidebar overlap on Users tab of Group editor
+* Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
+* Fixed: Report shows sub-projects for non-members
+* Fixed: 500 internal error when browsing any Redmine page in epiphany
+* Fixed: Watchers selection lost when issue creation fails
+* Fixed: When copying projects, redmine should not generate an email to people who created issues
+* Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
+* Fixed: Plugin generators should display help if no parameter is given
+
+
+== 2010-02-28 v0.9.3
+
+* Adds filter for system shared versions on the cross project issue list
+* Makes project identifiers searchable
+* Remove invalid utf8 sequences from commit comments and author name
+* Fixed: Wrong link when "http" not included in project "Homepage" link
+* Fixed: Escaping in html email templates
+* Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
+* Fixed: Deselecting textile text formatting causes interning empty string errors
+* Fixed: error with postgres when entering a non-numeric id for an issue relation
+* Fixed: div.task incorrectly wrapping on Gantt Chart
+* Fixed: Project copy loses wiki pages hierarchy
+* Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
+* Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
+* Fixed: Duplicated project name for subproject version on gantt chart
+* Fixed: roadmap shows subprojects issues even if subprojects is unchecked
+* Fixed: IndexError if all the :last menu items are deleted from a menu
+* Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
+
+
+== 2010-02-07 v0.9.2
+
+* Fixed: Sub-project repository commits not displayed on parent project issues
+* Fixed: Potential security leak on my page calendar
+* Fixed: Project tree structure is broken by deleting the project with the subproject
+* Fixed: Error message shown duplicated when creating a new group
+* Fixed: Firefox cuts off large pages
+* Fixed: Invalid format parameter returns a DoubleRenderError on issues index
+* Fixed: Unnecessary Quote button on locked forum message
+* Fixed: Error raised when trying to view the gantt or calendar with a grouped query
+* Fixed: PDF support for Korean locale
+* Fixed: Deprecation warning in extra/svn/reposman.rb
+
+
+== 2010-01-30 v0.9.1
+
+* Vertical alignment for inline images in formatted text set to 'middle'
+* Fixed: Redmine.pm error "closing dbh with active statement handles at /usr/lib/perl5/Apache/Redmine.pm"
+* Fixed: copyright year in footer set to 2010
+* Fixed: Trac migration script may not output query lines
+* Fixed: Email notifications may affect language of notice messages on the UI
+* Fixed: Can not search for 2 letters word
+* Fixed: Attachments get saved on issue update even if validation fails
+* Fixed: Tab's 'border-bottom' not absent when selected
+* Fixed: Issue summary tables that list by user are not sorted
+* Fixed: Issue pdf export fails if target version is set
+* Fixed: Issue list export to PDF breaks when issues are sorted by a custom field
+* Fixed: SQL error when adding a group
+* Fixes: Min password length during password reset always displays as 4 chars
+
+
+== 2010-01-09 v0.9.0 (Release candidate)
+
+* Unlimited subproject nesting
+* Multiple roles per user per project
+* User groups
+* Inheritence of versions
+* OpenID login
+* "Watched by me" issue filter
+* Project copy
+* Project creation by non admin users
+* Accept emails from anyone on a private project
+* Add email notification on Wiki changes
+* Make issue description non-required field
+* Custom fields for Versions
+* Being able to sort the issue list by custom fields
+* Ability to close versions
+* User display/editing of custom fields attached to their user profile
+* Add "follows" issue relation
+* Copy workflows between trackers and roles
+* Defaults enabled modules list for project creation
+* Weighted version completion percentage on the roadmap
+* Autocreate user account when user submits email that creates new issue
+* CSS class on overdue issues on the issue list
+* Enable tracker update on issue edit form
+* Remove issue watchers
+* Ability to move threads between project forums
+* Changed custom field "Possible values" to a textarea
+* Adds projects association on tracker form
+* Set session store to cookie store by default
+* Set a default wiki page on project creation
+* Roadmap for main project should see Roadmaps for sub projects
+* Ticket grouping on the issue list
+* Hierarchical Project links in the page header
+* Allow My Page blocks to be added to from a plugin
+* Sort issues by multiple columns
+* Filters of saved query are now visible and be adjusted without editing the query
+* Saving "sort order" in custom queries
+* Url to fetch changesets for a repository
+* Managers able to create subprojects
+* Issue Totals on My Page Modules
+* Convert Enumerations to single table inheritance (STI)
+* Allow custom my_page blocks to define drop-down names
+* "View Issues" user permission added
+* Ask user what to do with child pages when deleting a parent wiki page
+* Contextual quick search
+* Allow resending of password by email
+* Change reply subject to be a link to the reply itself
+* Include Logged Time as part of the project's Activity history
+* REST API for authentication
+* Browse through Git branches
+* Setup Object Daddy to replace test fixtures
+* Setup shoulda to make it easier to test
+* Custom fields and overrides on Enumerations
+* Add or remove columns from the issue list
+* Ability to add new version from issues screen
+* Setting to choose which day calendars start
+* Asynchronous email delivery method
+* RESTful URLs for (almost) everything
+* Include issue status in search results and activity pages
+* Add email to admin user search filter
+* Proper content type for plain text mails
+* Default value of project jump box
+* Tree based menus
+* Ability to use issue status to update percent done
+* Second set of issue "Action Links" at the bottom of an issue page
+* Proper exist status code for rdm-mailhandler.rb
+* Remove incoming email body via a delimiter
+* Fixed: Custom querry 'Export to PDF' ignores field selection
+* Fixed: Related e-mail notifications aren't threaded
+* Fixed: No warning when the creation of a categories from the issue form fails
+* Fixed: Actually block issues from closing when relation 'blocked by' isn't closed
+* Fixed: Include both first and last name when sorting by users
+* Fixed: Table cell with multiple line text
+* Fixed: Project overview page shows disabled trackers
+* Fixed: Cross project issue relations and user permissions
+* Fixed: My page shows tickets the user doesn't have access to
+* Fixed: TOC does not parse wiki page reference links with description
+* Fixed: Target version-list on bulk edit form is incorrectly sorted
+* Fixed: Cannot modify/delete project named "Documents"
+* Fixed: Email address in brackets breaks html
+* Fixed: Timelog detail loose issue filter passing to report tab
+* Fixed: Inform about custom field's name maximum length
+* Fixed: Activity page and Atom feed links contain project id instead of identifier
+* Fixed: no Atom key for forums with only 1 forum
+* Fixed: When reading RSS feed in MS Outlook, the inline links are broken.
+* Fixed: Sometimes new posts don't show up in the topic list of a forum.
+* Fixed: The all/active filter selection in the project view does not stick.
+* Fixed: Login box has Different width
+* Fixed: User removed from project - still getting project update emails
+* Fixed: Project with the identifier of 'new' cannot be viewed
+* Fixed: Artefacts in search view (Cyrillic)
+* Fixed: Allow [#id] as subject to reply by email
+* Fixed: Wrong language used when closing an issue via a commit message
+* Fixed: email handler drops emails for new issues with no subject
+* Fixed: Calendar misspelled under Roles/Permissions
+* Fixed: Emails from no-reply redmine's address hell cycle
+* Fixed: child_pages macro fails on wiki page history
+* Fixed: Pre-filled time tracking date ignores timezone
+* Fixed: Links on locked users lead to 404 page
+* Fixed: Page changes in issue-list when using context menu
+* Fixed: diff parser removes lines starting with multiple dashes
+* Fixed: Quoting in forums resets message subject
+* Fixed: Editing issue comment removes quote link
+* Fixed: Redmine.pm ignore browse_repository permission
+* Fixed: text formatting breaks on [msg1][msg2]
+* Fixed: Spent Time Default Value of 0.0
+* Fixed: Wiki pages in search results are referenced by project number, not by project identifier.
+* Fixed: When logging in via an autologin cookie the user's last_login_on should be updated
+* Fixed: 50k users cause problems in project->settings->members screen
+* Fixed: Document timestamp needs to show updated timestamps
+* Fixed: Users getting notifications for issues they are no longer allowed to view
+* Fixed: issue summary counts should link to the issue list without subprojects
+* Fixed: 'Delete' link on LDAP list has no effect
+
+
+== 2009-11-15 v0.8.7
+
+* Fixed: Hide paragraph terminator at the end of headings on html export
+* Fixed: pre tags containing "
') + output.wrap_in! line_numbers_table_template + output.wrapped_in = :div + + when :list + raise NotImplementedError, 'The :list option is no longer available. Use :table.' + + else + raise ArgumentError, 'Unknown value %p for mode: expected one of %p' % + [mode, [:table, :inline]] + end + + output + end + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/56/56493cc79ece7ebee244c20a035044b3abd7b20d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/56/56493cc79ece7ebee244c20a035044b3abd7b20d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,192 @@ +module CodeRay +module Scanners + + class CSS < Scanner + + register_for :css + + KINDS_NOT_LOC = [ + :comment, + :class, :pseudo_class, :type, + :constant, :directive, + :key, :value, :operator, :color, :float, :string, + :error, :important, + ] # :nodoc: + + module RE # :nodoc: + Hex = /[0-9a-fA-F]/ + Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too + Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/ + NMChar = /[-_a-zA-Z0-9]|#{Escape}/ + NMStart = /[_a-zA-Z]|#{Escape}/ + NL = /\r\n|\r|\n|\f/ + String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # TODO: buggy regexp + String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # TODO: buggy regexp + String = /#{String1}|#{String2}/ + + HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/ + Color = /#{HexColor}/ + + Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/ + Name = /#{NMChar}+/ + Ident = /-?#{NMStart}#{NMChar}*/ + AtKeyword = /@#{Ident}/ + Percentage = /#{Num}%/ + + reldimensions = %w[em ex px] + absdimensions = %w[in cm mm pt pc] + Unit = Regexp.union(*(reldimensions + absdimensions)) + + Dimension = /#{Num}#{Unit}/ + + Comment = %r! /\* (?: .*? \*/ | .* ) !mx + Function = /(?:url|alpha|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/ + + Id = /##{Name}/ + Class = /\.#{Name}/ + PseudoClass = /:#{Name}/ + AttributeSelector = /\[[^\]]*\]?/ + end + + protected + + def scan_tokens encoder, options + + value_expected = nil + states = [:initial] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif case states.last + when :initial, :media + if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox) + encoder.text_token match, :type + next + elsif match = scan(RE::Class) + encoder.text_token match, :class + next + elsif match = scan(RE::Id) + encoder.text_token match, :constant + next + elsif match = scan(RE::PseudoClass) + encoder.text_token match, :pseudo_class + next + elsif match = scan(RE::AttributeSelector) + # TODO: Improve highlighting inside of attribute selectors. + encoder.text_token match[0,1], :operator + encoder.text_token match[1..-2], :attribute_name if match.size > 2 + encoder.text_token match[-1,1], :operator if match[-1] == ?] + next + elsif match = scan(/@media/) + encoder.text_token match, :directive + states.push :media_before_name + next + end + + when :block + if match = scan(/(?>#{RE::Ident})(?!\()/ox) + if value_expected + encoder.text_token match, :value + else + encoder.text_token match, :key + end + next + end + + when :media_before_name + if match = scan(RE::Ident) + encoder.text_token match, :type + states[-1] = :media_after_name + next + end + + when :media_after_name + if match = scan(/\{/) + encoder.text_token match, :operator + states[-1] = :media + next + end + + else + #:nocov: + raise_inspect 'Unknown state', encoder + #:nocov: + + end + + elsif match = scan(/\/\*(?:.*?\*\/|\z)/m) + encoder.text_token match, :comment + + elsif match = scan(/\{/) + value_expected = false + encoder.text_token match, :operator + states.push :block + + elsif match = scan(/\}/) + value_expected = false + if states.last == :block || states.last == :media + encoder.text_token match, :operator + states.pop + else + encoder.text_token match, :error + end + + elsif match = scan(/#{RE::String}/o) + encoder.begin_group :string + encoder.text_token match[0, 1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1, 1], :delimiter if match.size >= 2 + encoder.end_group :string + + elsif match = scan(/#{RE::Function}/o) + encoder.begin_group :string + start = match[/^\w+\(/] + encoder.text_token start, :delimiter + if match[-1] == ?) + encoder.text_token match[start.size..-2], :content + encoder.text_token ')', :delimiter + else + encoder.text_token match[start.size..-1], :content + end + encoder.end_group :string + + elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) + encoder.text_token match, :float + + elsif match = scan(/#{RE::Color}/o) + encoder.text_token match, :color + + elsif match = scan(/! *important/) + encoder.text_token match, :important + + elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/) + encoder.text_token match, :color + + elsif match = scan(RE::AtKeyword) + encoder.text_token match, :directive + + elsif match = scan(/ [+>:;,.=()\/] /x) + if match == ':' + value_expected = true + elsif match == ';' + value_expected = false + end + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/56/567345e0e32dd6f82490d70b7b1bc18c0d3da0e8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/56/567345e0e32dd6f82490d70b7b1bc18c0d3da0e8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +david: + id: 1 + name: David + salary: 80000 + +jamis: + id: 2 + name: Jamis + salary: 150000 + +<% for digit in 3..10 %> +dev_<%= digit %>: + id: <%= digit %> + name: fixture_<%= digit %> + salary: 100000 +<% end %> + +poor_jamis: + id: 11 + name: Jamis + salary: 9000 \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/56/56f658e30dbfa38e86f4cb2d7cdd7b971352ed59.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/56/56f658e30dbfa38e86f4cb2d7cdd7b971352ed59.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,373 @@ +require 'SVG/Graph/Plot' +require 'parsedate' + +module SVG + module Graph + # === For creating SVG plots of scalar temporal data + # + # = Synopsis + # + # require 'SVG/Graph/Schedule' + # + # # Data sets are label, start, end tripples. + # data1 = [ + # "Housesitting", "6/17/04", "6/19/04", + # "Summer Session", "6/15/04", "8/15/04", + # ] + # + # graph = SVG::Graph::Schedule.new( { + # :width => 640, + # :height => 480, + # :graph_title => title, + # :show_graph_title => true, + # :no_css => true, + # :scale_x_integers => true, + # :scale_y_integers => true, + # :min_x_value => 0, + # :min_y_value => 0, + # :show_data_labels => true, + # :show_x_guidelines => true, + # :show_x_title => true, + # :x_title => "Time", + # :stagger_x_labels => true, + # :stagger_y_labels => true, + # :x_label_format => "%m/%d/%y", + # }) + # + # graph.add_data({ + # :data => data1, + # :title => 'Data', + # }) + # + # print graph.burn() + # + # = Description + # + # Produces a graph of temporal scalar data. + # + # = Examples + # + # http://www.germane-software/repositories/public/SVG/test/schedule.rb + # + # = Notes + # + # The default stylesheet handles upto 10 data sets, if you + # use more you must create your own stylesheet and add the + # additional settings for the extra data sets. You will know + # if you go over 10 data sets as they will have no style and + # be in black. + # + # Note that multiple data sets within the same chart can differ in + # length, and that the data in the datasets needn't be in order; + # they will be ordered by the plot along the X-axis. + # + # The dates must be parseable by ParseDate, but otherwise can be + # any order of magnitude (seconds within the hour, or years) + # + # = See also + # + # * SVG::Graph::Graph + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Bar + # * SVG::Graph::Line + # * SVG::Graph::Pie + # * SVG::Graph::Plot + # * SVG::Graph::TimeSeries + # + # == Author + # + # Sean E. Russell + # + # Copyright 2004 Sean E. Russell + # This software is available under the Ruby license[LICENSE.txt] + # + class Schedule < Graph + # In addition to the defaults set by Graph::initialize and + # Plot::set_defaults, sets: + # [x_label_format] '%Y-%m-%d %H:%M:%S' + # [popup_format] '%Y-%m-%d %H:%M:%S' + def set_defaults + init_with( + :x_label_format => '%Y-%m-%d %H:%M:%S', + :popup_format => '%Y-%m-%d %H:%M:%S', + :scale_x_divisions => false, + :scale_x_integers => false, + :bar_gap => true + ) + end + + # The format string use do format the X axis labels. + # See Time::strformat + attr_accessor :x_label_format + # Use this to set the spacing between dates on the axis. The value + # must be of the form + # "\d+ ?(days|weeks|months|years|hours|minutes|seconds)?" + # + # EG: + # + # graph.timescale_divisions = "2 weeks" + # + # will cause the chart to try to divide the X axis up into segments of + # two week periods. + attr_accessor :timescale_divisions + # The formatting used for the popups. See x_label_format + attr_accessor :popup_format + attr_accessor :min_x_value + attr_accessor :scale_x_divisions + attr_accessor :scale_x_integers + attr_accessor :bar_gap + + # Add data to the plot. + # + # # A data set with 1 point: Lunch from 12:30 to 14:00 + # d1 = [ "Lunch", "12:30", "14:00" ] + # # A data set with 2 points: "Cats" runs from 5/11/03 to 7/15/04, and + # # "Henry V" runs from 6/12/03 to 8/20/03 + # d2 = [ "Cats", "5/11/03", "7/15/04", + # "Henry V", "6/12/03", "8/20/03" ] + # + # graph.add_data( + # :data => d1, + # :title => 'Meetings' + # ) + # graph.add_data( + # :data => d2, + # :title => 'Plays' + # ) + # + # Note that the data must be in time,value pairs, and that the date format + # may be any date that is parseable by ParseDate. + # Also note that, in this example, we're mixing scales; the data from d1 + # will probably not be discernable if both data sets are plotted on the same + # graph, since d1 is too granular. + def add_data data + @data = [] unless @data + + raise "No data provided by #{conf.inspect}" unless data[:data] and + data[:data].kind_of? Array + raise "Data supplied must be title,from,to tripples! "+ + "The data provided contained an odd set of "+ + "data points" unless data[:data].length % 3 == 0 + return if data[:data].length == 0 + + + y = [] + x_start = [] + x_end = [] + data[:data].each_index {|i| + im3 = i%3 + if im3 == 0 + y << data[:data][i] + else + arr = ParseDate.parsedate( data[:data][i] ) + t = Time.local( *arr[0,6].compact ) + (im3 == 1 ? x_start : x_end) << t.to_i + end + } + sort( x_start, x_end, y ) + @data = [x_start, x_end, y ] + end + + + protected + + def min_x_value=(value) + arr = ParseDate.parsedate( value ) + @min_x_value = Time.local( *arr[0,6].compact ).to_i + end + + + def format x, y + Time.at( x ).strftime( popup_format ) + end + + def get_x_labels + rv = get_x_values.collect { |v| Time.at(v).strftime( x_label_format ) } + end + + def y_label_offset( height ) + height / -2.0 + end + + def get_y_labels + @data[2] + end + + def draw_data + fieldheight = field_height + fieldwidth = field_width + + bargap = bar_gap ? (fieldheight < 10 ? fieldheight / 2 : 10) : 0 + subbar_height = fieldheight - bargap + + field_count = 1 + y_mod = (subbar_height / 2) + (font_size / 2) + min,max,div = x_range + scale = (@graph_width.to_f - font_size*2) / (max-min) + @data[0].each_index { |i| + x_start = @data[0][i] + x_end = @data[1][i] + y = @graph_height - (fieldheight * field_count) + bar_width = (x_end-x_start) * scale + bar_start = x_start * scale - (min * scale) + + @graph.add_element( "rect", { + "x" => bar_start.to_s, + "y" => y.to_s, + "width" => bar_width.to_s, + "height" => subbar_height.to_s, + "class" => "fill#{field_count+1}" + }) + field_count += 1 + } + end + + def get_css + return < 12 + arr[5] += (arr[4] / 12).to_i + arr[4] = (arr[4] % 12) + end + cur = Time.local(*arr).to_i + end + when "years" + cur = min + while cur < max + rv << cur + arr = Time.at( cur ).to_a + arr[5] += amount + cur = Time.local(*arr).to_i + end + when "weeks" + step = 7 * 24 * 60 * 60 * amount + when "days" + step = 24 * 60 * 60 * amount + when "hours" + step = 60 * 60 * amount + when "minutes" + step = 60 * amount + when "seconds" + step = amount + end + min.step( max, step ) {|v| rv << v} if step + + return rv + end + end + min.step( max, scale_division ) {|v| rv << v} + return rv + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/57/574191f7c915eaa8e65f1af70ca9c1adffa02889.svn-base Binary file .svn/pristine/57/574191f7c915eaa8e65f1af70ca9c1adffa02889.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/57/5743d81934695d3c76c9de1e610ada18ddc3f631.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/57/5743d81934695d3c76c9de1e610ada18ddc3f631.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,138 @@ +# One of the magic features that that engines plugin provides is the ability to +# override selected methods in controllers and helpers from your application. +# This is achieved by trapping requests to load those files, and then mixing in +# code from plugins (in the order the plugins were loaded) before finally loading +# any versions from the main +app+ directory. +# +# The behaviour of this extension is output to the log file for help when +# debugging. +# +# == Example +# +# A plugin contains the following controller in plugin/app/controllers/my_controller.rb: +# +# class MyController < ApplicationController +# def index +# @name = "HAL 9000" +# end +# def list +# @robots = Robot.find(:all) +# end +# end +# +# In one application that uses this plugin, we decide that the name used in the +# index action should be "Robbie", not "HAL 9000". To override this single method, +# we create the corresponding controller in our application +# (RAILS_ROOT/app/controllers/my_controller.rb), and redefine the method: +# +# class MyController < ApplicationController +# def index +# @name = "Robbie" +# end +# end +# +# The list method remains as it was defined in the plugin controller. +# +# The same basic principle applies to helpers, and also views and partials (although +# view overriding is performed in Engines::RailsExtensions::Templates; see that +# module for more information). +# +# === What about models? +# +# Unfortunately, it's not possible to provide this kind of magic for models. +# The only reason why it's possible for controllers and helpers is because +# they can be recognised by their filenames ("whatever_controller", "jazz_helper"), +# whereas models appear the same as any other typical Ruby library ("node", +# "user", "image", etc.). +# +# If mixing were allowed in models, it would mean code mixing for *every* +# file that was loaded via +require_or_load+, and this could result in +# problems where, for example, a Node model might start to include +# functionality from another file called "node" somewhere else in the +# $LOAD_PATH. +# +# One way to overcome this is to provide model functionality as a module in +# a plugin, which developers can then include into their own model +# implementations. +# +# Another option is to provide an abstract model (see the ActiveRecord::Base +# documentation) and have developers subclass this model in their own +# application if they must. +# +# --- +# +# The Engines::RailsExtensions::Dependencies module includes a method to +# override Dependencies.require_or_load, which is called to load code needed +# by Rails as it encounters constants that aren't defined. +# +# This method is enhanced with the code-mixing features described above. +# +module Engines::RailsExtensions::Dependencies + def self.included(base) #:nodoc: + base.class_eval { alias_method_chain :require_or_load, :engine_additions } + end + + # Attempt to load the given file from any plugins, as well as the application. + # This performs the 'code mixing' magic, allowing application controllers and + # helpers to override single methods from those in plugins. + # If the file can be found in any plugins, it will be loaded first from those + # locations. Finally, the application version is loaded, using Ruby's behaviour + # to replace existing methods with their new definitions. + # + # If Engines.disable_code_mixing == true, the first controller/helper on the + # $LOAD_PATH will be used (plugins' +app+ directories are always lower on the + # $LOAD_PATH than the main +app+ directory). + # + # If Engines.disable_application_code_loading == true, controllers will + # not be loaded from the main +app+ directory *if* they are present in any + # plugins. + # + # Returns true if the file could be loaded (from anywhere); false otherwise - + # mirroring the behaviour of +require_or_load+ from Rails (which mirrors + # that of Ruby's own +require+, I believe). + def require_or_load_with_engine_additions(file_name, const_path=nil) + return require_or_load_without_engine_additions(file_name, const_path) if Engines.disable_code_mixing + + file_loaded = false + + # try and load the plugin code first + # can't use model, as there's nothing in the name to indicate that the file is a 'model' file + # rather than a library or anything else. + Engines.code_mixing_file_types.each do |file_type| + # if we recognise this type + # (this regexp splits out the module/filename from any instances of app/#{type}, so that + # modules are still respected.) + if file_name =~ /^(.*app\/#{file_type}s\/)+(.*_#{file_type})(\.rb)?$/ + base_name = $2 + # ... go through the plugins from first started to last, so that + # code with a high precedence (started later) will override lower precedence + # implementations + Engines.plugins.each do |plugin| + plugin_file_name = File.expand_path(File.join(plugin.directory, 'app', "#{file_type}s", base_name)) + if File.file?("#{plugin_file_name}.rb") + file_loaded = true if require_or_load_without_engine_additions(plugin_file_name, const_path) + end + end + + # finally, load any application-specific controller classes using the 'proper' + # rails load mechanism, EXCEPT when we're testing engines and could load this file + # from an engine + unless Engines.disable_application_code_loading + # Ensure we are only loading from the /app directory at this point + app_file_name = File.join(RAILS_ROOT, 'app', "#{file_type}s", "#{base_name}") + if File.file?("#{app_file_name}.rb") + file_loaded = true if require_or_load_without_engine_additions(app_file_name, const_path) + end + end + end + end + + # if we managed to load a file, return true. If not, default to the original method. + # Note that this relies on the RHS of a boolean || not to be evaluated if the LHS is true. + file_loaded || require_or_load_without_engine_additions(file_name, const_path) + end +end + +module ActiveSupport::Dependencies #:nodoc: + include Engines::RailsExtensions::Dependencies +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/57/578512e6dbb7e9eb217c19a44b7964235d402a37.svn-base Binary file .svn/pristine/57/578512e6dbb7e9eb217c19a44b7964235d402a37.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/57/57a3ca6236cc4e5539fa3337ae1a20668f37ff47.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/57/57a3ca6236cc4e5539fa3337ae1a20668f37ff47.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,192 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class VersionsController < ApplicationController + menu_item :roadmap + model_object Version + before_filter :find_model_object, :except => [:index, :new, :create, :close_completed] + before_filter :find_project_from_association, :except => [:index, :new, :create, :close_completed] + before_filter :find_project, :only => [:index, :new, :create, :close_completed] + before_filter :authorize + + accept_api_auth :index, :create, :update, :destroy + + helper :custom_fields + helper :projects + + def index + respond_to do |format| + format.html { + @trackers = @project.trackers.find(:all, :order => 'position') + retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) + @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] + + @versions = @project.shared_versions || [] + @versions += @project.rolled_up_versions.visible if @with_subprojects + @versions = @versions.uniq.sort + @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed] + + @issues_by_version = {} + unless @selected_tracker_ids.empty? + @versions.each do |version| + issues = version.fixed_issues.visible.find(:all, + :include => [:project, :status, :tracker, :priority], + :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids}, + :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") + @issues_by_version[version] = issues + end + end + @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} + } + format.api { + @versions = @project.shared_versions.all + } + end + end + + def show + respond_to do |format| + format.html { + @issues = @version.fixed_issues.visible.find(:all, + :include => [:status, :tracker, :priority], + :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") + } + format.api + end + end + + def new + @version = @project.versions.build + if params[:version] + attributes = params[:version].dup + attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) + @version.attributes = attributes + end + end + + def create + # TODO: refactor with code above in #new + @version = @project.versions.build + if params[:version] + attributes = params[:version].dup + attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) + @version.attributes = attributes + end + + if request.post? + if @version.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + end + format.js do + # IE doesn't support the replace_html rjs method for select box options + render(:update) {|page| page.replace "issue_fixed_version_id", + content_tag('select', '' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]') + } + end + format.api do + render :action => 'show', :status => :created, :location => version_url(@version) + end + end + else + respond_to do |format| + format.html { render :action => 'new' } + format.js do + render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) } + end + format.api { render_validation_errors(@version) } + end + end + end + end + + def edit + end + + def update + if request.put? && params[:version] + attributes = params[:version].dup + attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) + if @version.update_attributes(attributes) + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + } + format.api { head :ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@version) } + end + end + end + end + + def close_completed + if request.put? + @project.close_completed_versions + end + redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + end + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } + def destroy + if @version.fixed_issues.empty? + @version.destroy + respond_to do |format| + format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project } + format.api { head :ok } + end + else + respond_to do |format| + format.html { + flash[:error] = l(:notice_unable_delete_version) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + } + format.api { head :unprocessable_entity } + end + end + end + + def status_by + respond_to do |format| + format.html { render :action => 'show' } + format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} } + end + end + +private + def find_project + @project = Project.find(params[:project_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil) + if ids = params[:tracker_ids] + @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } + else + @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s } + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/57/57c1667a6b0b8222beaeafcee0db4e38818fa2d0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/57/57c1667a6b0b8222beaeafcee0db4e38818fa2d0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +require File.dirname(__FILE__) + "/rails/init" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/57/57d9fc955c1c0bed1abfed5bf47b0ed281a3ff4b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/57/57d9fc955c1c0bed1abfed5bf47b0ed281a3ff4b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1009 @@ +mn: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%b %d" + long: "%Y, %B %d" + + day_names: [Даваа, Мягмар, Лхагва, Пүрэв, Баасан, Бямба, Ням] + abbr_day_names: [Дав, Мяг, Лха, Пүр, Бсн, Бям, Ням] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 1-р сар, 2-р сар, 3-р сар, 4-р сар, 5-р сар, 6-р сар, 7-р сар, 8-р сар, 9-р сар, 10-р сар, 11-р сар, 12-р сар] + abbr_month_names: [~, 1сар, 2сар, 3сар, 4сар, 5сар, 6сар, 7сар, 8сар, 9сар, 10сар, 11сар, 12сар] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%Y/%m/%d %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%Y, %B %d %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "хагас минут" + less_than_x_seconds: + one: "секунд орчим" + other: "%{count} секундээс бага хугацаа" + x_seconds: + one: "1 секунд" + other: "%{count} секунд" + less_than_x_minutes: + one: "минутаас бага хугацаа" + other: "%{count} минутаас бага хугацаа" + x_minutes: + one: "1 минут" + other: "%{count} минут" + about_x_hours: + one: "1 цаг орчим" + other: "ойролцоогоор %{count} цаг" + x_days: + one: "1 өдөр" + other: "%{count} өдөр" + about_x_months: + one: "1 сар орчим" + other: "ойролцоогоор %{count} сар" + x_months: + one: "1 сар" + other: "%{count} сар" + about_x_years: + one: "ойролцоогоор 1 жил" + other: "ойролцоогоор %{count} жил" + over_x_years: + one: "1 жилээс их" + other: "%{count} жилээс их" + almost_x_years: + one: "бараг 1 жил" + other: "бараг %{count} жил" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Байт" + other: "Байт" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "бас" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "жагсаалтад заагдаагүй байна" + exclusion: "нөөцлөгдсөн" + invalid: "буруу" + confirmation: "баталгаажсан өгөгдөлтэй таарахгүй байна" + accepted: "хүлээж авах ёстой" + empty: "хоосон байж болохгүй" + blank: "бланк байж болохгүй" + too_long: "дэндүү урт байна (хамгийн ихдээ %{count} тэмдэгт)" + too_short: "дэндүү богино байна (хамгийн багадаа %{count} тэмдэгт)" + wrong_length: "буруу урттай байна (заавал %{count} тэмдэгт)" + taken: "аль хэдийнэ авсан байна" + not_a_number: "тоо биш байна" + not_a_date: "зөв огноо биш байна" + greater_than: "%{count} их байх ёстой" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "заавал сондгой" + even: "заавал тэгш" + greater_than_start_date: "must be greater than start date" + not_same_project: "нэг ижил төсөлд хамаарахгүй байна" + circular_dependency: "Энэ харьцаа нь гинжин(рекурсив) харьцаа үүсгэх юм байна" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Сонгоно уу + + general_text_No: 'Үгүй' + general_text_Yes: 'Тийм' + general_text_no: 'үгүй' + general_text_yes: 'тийм' + general_lang_name: 'Mongolian (Монгол)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Дансыг амжилттай өөрчиллөө. + notice_account_invalid_creditentials: Хэрэглэгчийн нэр эсвэл нууц үг буруу байна + notice_account_password_updated: Нууц үгийг амжилттай өөрчиллөө. + notice_account_wrong_password: Буруу нууц үг + notice_account_register_done: Шинэ хэрэглэгч амжилттай үүсгэлээ. Идэвхжүүлэхийн тулд, бидний тань луу илгээсэн мэйл дотор байгаа холбоос дээр дараарай. + notice_account_unknown_email: Үл мэдэгдэх хэрэглэгч. + notice_can_t_change_password: Энэ эрх гадаад нэвтрэлтэд ашигладаг учраас нууц үгийг өөрчлөх боломжгүй. + notice_account_lost_email_sent: Бид таньд мэйлээр нууц үгээ өөрчлөх зааврыг илгээсэн байгаа. + notice_account_activated: Таны данс идэвхжлээ. Одоо нэвтэрч орж болно. + notice_successful_create: Амжилттай үүсгэлээ. + notice_successful_update: Амжилттай өөрчиллөө. + notice_successful_delete: Амжилттай устгалаа. + notice_successful_connection: Амжилттай холбогдлоо. + notice_file_not_found: Таны үзэх гэсэн хуудас байхгүй юмуу устгагдсан байна. + notice_locking_conflict: Өгөгдлийг өөр хүн өөрчилсөн байна. + notice_not_authorized: Танд энэ хуудсыг үзэх эрх байхгүй байна. + notice_email_sent: "%{value} - руу мэйл илгээлээ" + notice_email_error: "Мэйл илгээхэд алдаа гарлаа (%{value})" + notice_feeds_access_key_reseted: Таны RSS хандалтын түлхүүрийг дахин эхлүүллээ. + notice_api_access_key_reseted: Your API access key was reset. + notice_failed_to_save_issues: "%{total} асуудал сонгогдсоноос %{count} асуудлыг нь хадгалахад алдаа гарлаа: %{ids}." + notice_no_issue_selected: "Ямар ч асуудал сонгогдоогүй байна! Засварлах асуудлуудаа сонгоно уу." + notice_account_pending: "Таны дансыг үүсгэж дууслаа, администратор баталгаажуулах хүртэл хүлээнэ үү." + notice_default_data_loaded: Стандарт тохиргоог амжилттай ачааллаа. + notice_unable_delete_version: Хувилбарыг устгах боломжгүй. + notice_issue_done_ratios_updated: Issue done ratios updated. + + error_can_t_load_default_data: "Стандарт тохиргоог ачаалж чадсангүй: %{value}" + error_scm_not_found: "Repository дотор тухайн бичлэг эсвэл хувилбарыг олсонгүй." + error_scm_command_failed: "Repository-д хандахад алдаа гарлаа: %{value}" + error_scm_annotate: "Бичлэг байхгүй байна, эсвэл бичлэгт тайлбар хавсаргаж болохгүй." + error_issue_not_found_in_project: 'Сонгосон асуудал энэ төсөлд хамаардаггүй юм уу эсвэл системд байхгүй байна.' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version can not be reopened' + error_can_not_archive_project: This project can not be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + + warning_attachments_not_saved: "%{count} file(s) файлыг хадгалж чадсангүй." + + mail_subject_lost_password: "Таны %{value} нууц үг" + mail_body_lost_password: 'Нууц үгээ өөрчлөхийн тулд доорх холбоос дээр дарна уу:' + mail_subject_register: "Таны %{value} дансыг идэвхжүүлэх" + mail_body_register: 'Дансаа идэвхжүүлэхийн тулд доорх холбоос дээр дарна уу:' + mail_body_account_information_external: "Та өөрийнхөө %{value} дансыг ашиглаж холбогдож болно." + mail_body_account_information: Таны дансны тухай мэдээлэл + mail_subject_account_activation_request: "%{value} дансыг идэвхжүүлэх хүсэлт" + mail_body_account_activation_request: "Шинэ хэрэглэгч (%{value}) бүртгүүлсэн байна. Таны баталгаажуулахыг хүлээж байна:" + mail_subject_reminder: "Дараагийн өдрүүдэд %{count} асуудлыг шийдэх хэрэгтэй (%{days})" + mail_body_reminder: "Танд оноогдсон %{count} асуудлуудыг дараагийн %{days} өдрүүдэд шийдэх хэрэгтэй:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + gui_validation_error: 1 алдаа + gui_validation_error_plural: "%{count} алдаа" + + field_name: Нэр + field_description: Тайлбар + field_summary: Дүгнэлт + field_is_required: Зайлшгүй + field_firstname: Таны нэр + field_lastname: Овог + field_mail: Имэйл + field_filename: Файл + field_filesize: Хэмжээ + field_downloads: Татаж авах зүйлс + field_author: Зохиогч + field_created_on: Үүссэн + field_updated_on: Өөрчилсөн + field_field_format: Формат + field_is_for_all: Бүх төслийн хувьд + field_possible_values: Боломжтой утгууд + field_regexp: Энгийн илэрхийлэл + field_min_length: Минимум урт + field_max_length: Максимум урт + field_value: Утга + field_category: Төрөл + field_title: Гарчиг + field_project: Төсөл + field_issue: Асуудал + field_status: Төлөв + field_notes: Тэмдэглэлүүд + field_is_closed: Асуудал хаагдсан + field_is_default: Стандарт утга + field_tracker: Чиглэл + field_subject: Гарчиг + field_due_date: Дуусах огноо + field_assigned_to: Оноогдсон + field_priority: Зэрэглэл + field_fixed_version: Хувилбар + field_user: Хэрэглэгч + field_role: Хандалтын эрх + field_homepage: Нүүр хуудас + field_is_public: Олон нийтийн + field_parent: Эцэг төсөл нь + field_is_in_roadmap: Асуудлуудыг явцын зураг дээр харуулах + field_login: Нэвтрэх нэр + field_mail_notification: Имэйл мэдэгдлүүд + field_admin: Администратор + field_last_login_on: Сүүлийн холбоо + field_language: Хэл + field_effective_date: Огноо + field_password: Нууц үг + field_new_password: Шннэ нууц үг + field_password_confirmation: Баталгаажуулах + field_version: Хувилбар + field_type: Төрөл + field_host: Хост + field_port: Порт + field_account: Данс + field_base_dn: Үндсэн ДН + field_attr_login: Нэвтрэх аттрибут + field_attr_firstname: Таны нэр аттрибут + field_attr_lastname: Овог аттрибут + field_attr_mail: Имэйл аттрибут + field_onthefly: Хүссэн үедээ хэрэглэгч үүсгэх + field_start_date: Эхлэл + field_done_ratio: "%% Гүйцэтгэсэн" + field_auth_source: Нэвтрэх арга + field_hide_mail: Миний имэйл хаягийг нуу + field_comments: Тайлбар + field_url: URL Хаяг + field_start_page: Тэргүүн хуудас + field_subproject: Дэд төсөл + field_hours: Цаг + field_activity: Үйл ажиллагаа + field_spent_on: Огноо + field_identifier: Төслийн глобал нэр + field_is_filter: Шүүлтүүр болгон хэрэглэгддэг + field_issue_to: Хамаатай асуудал + field_delay: Хоцролт + field_assignable: Энэ хандалтын эрхэд асуудлуудыг оноож өгч болно + field_redirect_existing_links: Байгаа холбоосуудыг дахин чиглүүлэх + field_estimated_hours: Барагцаалсан цаг + field_column_names: Баганууд + field_time_zone: Цагын бүс + field_searchable: Хайж болох + field_default_value: Стандарт утга + field_comments_sorting: Тайлбаруудыг харуул + field_parent_title: Эцэг хуудас + field_editable: Засварлагдана + field_watcher: Харна + field_identity_url: OpenID URL + field_content: Агуулга + field_group_by: Үр дүнгээр бүлэглэх + field_sharing: Sharing + + setting_app_title: Программын гарчиг + setting_app_subtitle: Программын дэд гарчиг + setting_welcome_text: Мэндчилгээ + setting_default_language: Стандарт хэл + setting_login_required: Нэвтрэх шаардлагатай + setting_self_registration: Өөрийгөө бүртгүүлэх + setting_attachment_max_size: Хавсралт файлын дээд хэмжээ + setting_issues_export_limit: Асуудал экспортлох хязгаар + setting_mail_from: Ямар имэйл хаяг үүсгэх + setting_bcc_recipients: BCC талбарын хаягууд (bcc) + setting_plain_text_mail: дан текст мэйл (HTML биш) + setting_host_name: Хостын нэр болон зам + setting_text_formatting: Текст хэлбэржүүлэлт + setting_wiki_compression: Вики хуудсуудын түүх дээр шахалт хийх + setting_feeds_limit: Фийд агуулгын хязгаар + setting_default_projects_public: Шинэ төслүүд автоматаар олон нийтийнх байна + setting_autofetch_changesets: Комитуудыг автоматаар татаж авах + setting_sys_api_enabled: Репозитори менежментэд зориулан WS-ийг идэвхжүүлэх + setting_commit_ref_keywords: Хамааруулах түлхүүр үгс + setting_commit_fix_keywords: Зоолттой түлхүүр үгс + setting_autologin: Компьютер дээр санах + setting_date_format: Огнооны формат + setting_time_format: Цагийн формат + setting_cross_project_issue_relations: Төсөл хооронд асуудал хамааруулахыг зөвшөөрөх + setting_issue_list_default_columns: Асуудлуудыг харуулах стандарт баганууд + setting_emails_footer: Имэйлүүдийн хөл хэсэг + setting_protocol: Протокол + setting_per_page_options: Нэг хуудсанд байх обьектуудын тохиргоо + setting_user_format: Хэрэглэгчдийг харуулах формат + setting_activity_days_default: Төслийн үйл ажиллагаа хэсэгт үзүүлэх өдрийн тоо + setting_display_subprojects_issues: Дэд төслүүдийн асуудлуудыг автоматаар гол төсөл дээр харуулах + setting_enabled_scm: SCM - ийг идэвхжүүлэх + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Ирсэн мэйлүүдийн хувьд WS-ийг идэвхжүүлэх + setting_mail_handler_api_key: API түлхүүр + setting_sequential_project_identifiers: Дэс дараалсан төслийн глобал нэр үүсгэж байх + setting_gravatar_enabled: Gravatar дүрсүүдийг хэрэглэгчдэд хэрэглэж байх + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Ялгаатай мөрүүдийн тоо (дээд тал нь) + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + + permission_add_project: Create project + permission_add_subprojects: Create subprojects + permission_edit_project: Төслийг засварлах + permission_select_project_modules: Төслийн модулуудийг сонгоно уу + permission_manage_members: Системийн хэрэглэгчид + permission_manage_project_activities: Manage project activities + permission_manage_versions: Хувилбарууд + permission_manage_categories: Асуудлын ангиллууд + permission_view_issues: Асуудлуудыг харах + permission_add_issues: Асуудлууд нэмэх + permission_edit_issues: Асуудлуудыг засварлах + permission_manage_issue_relations: Асуудлын хамаарлыг зохицуулах + permission_add_issue_notes: Тэмдэглэл нэмэх + permission_edit_issue_notes: Тэмдэглэлүүд засварлах + permission_edit_own_issue_notes: Өөрийн үлдээсэн тэмдэглэлүүдийг засварлах + permission_move_issues: Асуудлуудыг зөөх + permission_delete_issues: Асуудлуудыг устгах + permission_manage_public_queries: Олон нийтийн асуултууд + permission_save_queries: Асуултуудыг хадгалах + permission_view_gantt: Гант диаграмыг үзэх + permission_view_calendar: Календарь үзэх + permission_view_issue_watchers: Ажиглагчдын жагсаалтыг харах + permission_add_issue_watchers: Ажиглагчид нэмэх + permission_delete_issue_watchers: Ажиглагчдыг устгах + permission_log_time: Зарцуулсан хугацааг лог хийх + permission_view_time_entries: Зарцуулсан хугацааг харах + permission_edit_time_entries: Хугацааны логуудыг засварлах + permission_edit_own_time_entries: Өөрийн хугацааны логуудыг засварлах + permission_manage_news: Мэдээ мэдээллүүд + permission_comment_news: Мэдээнд тайлбар үлдээх + permission_manage_documents: Бичиг баримтууд + permission_view_documents: Бичиг баримтуудыг харах + permission_manage_files: Файлууд + permission_view_files: Файлуудыг харах + permission_manage_wiki: Вики удирдах + permission_rename_wiki_pages: Вики хуудсуудыг дахиж нэрлэх + permission_delete_wiki_pages: Вики хуудсуудыг устгах + permission_view_wiki_pages: Вики үзэх + permission_view_wiki_edits: Вики түүх үзэх + permission_edit_wiki_pages: Вики хуудсуудыг засварлах + permission_delete_wiki_pages_attachments: Хавсралтуудыг устгах + permission_protect_wiki_pages: Вики хуудсуудыг хамгаалах + permission_manage_repository: Репозитори + permission_browse_repository: Репозиторийг үзэх + permission_view_changesets: Өөрчлөлтүүдийг харах + permission_commit_access: Коммит хандалт + permission_manage_boards: Самбарууд + permission_view_messages: Зурвасуудыг харах + permission_add_messages: Зурвас илгээх + permission_edit_messages: Зурвасуудыг засварлах + permission_edit_own_messages: Өөрийн зурвасуудыг засварлах + permission_delete_messages: Зурвасуудыг устгах + permission_delete_own_messages: Өөрийн зурвасуудыг устгах + permission_export_wiki_pages: Вики хуудсуудыг экспорт хийх + + project_module_issue_tracking: Асуудал хянах + project_module_time_tracking: Хугацаа хянах + project_module_news: Мэдээ мэдээллүүд + project_module_documents: Бичиг баримтууд + project_module_files: Файлууд + project_module_wiki: Вики + project_module_repository: Репозитори + project_module_boards: Самбарууд + + label_user: Хэрэглэгч + label_user_plural: Хэрэглэгчид + label_user_new: Шинэ хэрэглэгч + label_user_anonymous: Хамаагүй хэрэглэгч + label_project: Төсөл + label_project_new: Шинэ төсөл + label_project_plural: Төслүүд + label_x_projects: + zero: төсөл байхгүй + one: 1 төсөл + other: "%{count} төслүүд" + label_project_all: Бүх Төслүүд + label_project_latest: Сүүлийн үеийн төслүүд + label_issue: Асуудал + label_issue_new: Шинэ асуудал + label_issue_plural: Асуудлууд + label_issue_view_all: Бүх асуудлуудыг харах + label_issues_by: "%{value} - н асуудлууд" + label_issue_added: Асуудал нэмэгдлээ + label_issue_updated: Асуудал өөрчлөгдлөө + label_document: Бичиг баримт + label_document_new: Шинэ бичиг баримт + label_document_plural: Бичиг баримтууд + label_document_added: Бичиг баримт нэмэгдлээ + label_role: Хандалтын эрх + label_role_plural: Хандалтын эрхүүд + label_role_new: Шинэ хандалтын эрх + label_role_and_permissions: Хандалтын эрхүүд болон зөвшөөрлүүд + label_member: Гишүүн + label_member_new: Шинэ гишүүн + label_member_plural: Гишүүд + label_tracker: Чиглэл + label_tracker_plural: Чиглэлүүд + label_tracker_new: Шинэ чиглэл + label_workflow: Ажлын дараалал + label_issue_status: Асуудлын төлөв + label_issue_status_plural: Асуудлын төлвүүд + label_issue_status_new: Шинэ төлөв + label_issue_category: Асуудлын ангилал + label_issue_category_plural: Асуудлын ангиллууд + label_issue_category_new: Шинэ ангилал + label_custom_field: Хэрэглэгчийн тодорхойлсон талбар + label_custom_field_plural: Хэрэглэгчийн тодорхойлсон талбарууд + label_custom_field_new: Шинээр хэрэглэгчийн тодорхойлсон талбар үүсгэх + label_enumerations: Ангиллууд + label_enumeration_new: Шинэ утга + label_information: Мэдээлэл + label_information_plural: Мэдээллүүд + label_please_login: Нэвтэрч орно уу + label_register: Бүртгүүлэх + label_login_with_open_id_option: or login with OpenID + label_password_lost: Нууц үгээ алдсан + label_home: Нүүр + label_my_page: Миний хуудас + label_my_account: Миний данс + label_my_projects: Миний төслүүд + label_administration: Админ хэсэг + label_login: Нэвтрэх + label_logout: Гарах + label_help: Тусламж + label_reported_issues: Мэдэгдсэн асуудлууд + label_assigned_to_me_issues: Надад оноогдсон асуудлууд + label_last_login: Сүүлийн холболт + label_registered_on: Бүртгүүлсэн огноо + label_activity: Үйл ажиллагаа + label_overall_activity: Ерөнхий үйл ажиллагаа + label_user_activity: "%{value}-ийн үйл ажиллагаа" + label_new: Шинэ + label_logged_as: Холбогдсон нэр + label_environment: Орчин + label_authentication: Нэвтрэх + label_auth_source: Нэвтрэх арга + label_auth_source_new: Шинэ нэвтрэх арга + label_auth_source_plural: Нэвтрэх аргууд + label_subproject_plural: Дэд төслүүд + label_subproject_new: Шинэ дэд төсөл + label_and_its_subprojects: "%{value} болон холбогдох дэд төслүүд" + label_min_max_length: Дээд - Доод урт + label_list: Жагсаалт + label_date: Огноо + label_integer: Бүхэл тоо + label_float: Бутархай тоо + label_boolean: Үнэн худал утга + label_string: Текст + label_text: Урт текст + label_attribute: Аттрибут + label_attribute_plural: Аттрибутууд + label_download: "%{count} Татаж авсан зүйл" + label_download_plural: "%{count} Татаж авсан зүйлс" + label_no_data: Үзүүлэх өгөгдөл байхгүй байна + label_change_status: Төлвийг өөрчлөх + label_history: Түүх + label_attachment: Файл + label_attachment_new: Шинэ файл + label_attachment_delete: Файл устгах + label_attachment_plural: Файлууд + label_file_added: Файл нэмэгдлээ + label_report: Тайлан + label_report_plural: Тайлангууд + label_news: Мэдээ + label_news_new: Шинэ мэдээ + label_news_plural: Мэдээ + label_news_latest: Сүүлийн үеийн мэдээнүүд + label_news_view_all: Бүх мэдээг харах + label_news_added: Мэдээ нэмэгдлээ + label_change_log: Өөрчлөлтийн лог + label_settings: Тохиргоо + label_overview: Эхлэл + label_version: Хувилбар + label_version_new: Шинэ хувилбар + label_version_plural: Хувилбарууд + label_close_versions: Гүйцэт хувилбаруудыг хаалаа + label_confirmation: Баталгаажуулах + label_export_to: 'Өөр авч болох формат:' + label_read: Унших... + label_public_projects: Олон нийтийн төслүүд + label_open_issues: нээлттэй + label_open_issues_plural: нээлттэй + label_closed_issues: хаалттай + label_closed_issues_plural: хаалттай + label_x_open_issues_abbr_on_total: + zero: 0 нээлттэй / %{total} + one: 1 нээлттэй / %{total} + other: "%{count} нээлттэй / %{total}" + label_x_open_issues_abbr: + zero: 0 нээлттэй + one: 1 нээлттэй + other: "%{count} нээлттэй" + label_x_closed_issues_abbr: + zero: 0 хаалттай + one: 1 хаалттай + other: "%{count} хаалттай" + label_total: Нийт + label_permissions: Зөвшөөрлүүд + label_current_status: Одоогийн төлөв + label_new_statuses_allowed: Шинээр олгож болох төлвүүд + label_all: бүгд + label_none: хоосон + label_nobody: хэн ч биш + label_next: Дараагийн + label_previous: Өмнөх + label_used_by: Хэрэглэгддэг + label_details: Дэлгэрэнгүй + label_add_note: Тэмдэглэл нэмэх + label_per_page: Нэг хуудсанд + label_calendar: Календарь + label_months_from: Саруудыг хаанаас + label_gantt: Гант диаграм + label_internal: Дотоод + label_last_changes: "сүүлийн %{count} өөрчлөлтүүд" + label_change_view_all: Бүх өөрчлөлтүүдийг харах + label_personalize_page: Энэ хуудсыг өөрт зориулан өөрчлөх + label_comment: Тайлбар + label_comment_plural: Тайлбарууд + label_x_comments: + zero: сэтгэгдэл байхгүй + one: 1 сэтгэгдэлтэй + other: "%{count} сэтгэгдэлтэй" + label_comment_add: Тайлбар нэмэх + label_comment_added: Тайлбар нэмэгдлээ + label_comment_delete: Тайлбарууд устгах + label_query: Хэрэглэгчийн тодорхойлсон асуулт + label_query_plural: Хэрэглэгчийн тодорхойлсон асуултууд + label_query_new: Шинээр хэрэглэгчийн тодорхойлсон асуулт үүсгэх + label_filter_add: Шүүлтүүр нэмэх + label_filter_plural: Шүүлтүүрүүд + label_equals: бол + label_not_equals: биш + label_in_less_than: аас бага + label_in_more_than: аас их + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: дотор + label_today: өнөөдөр + label_all_time: бүх хугацаа + label_yesterday: өчигдөр + label_this_week: энэ долоо хоног + label_last_week: өнгөрсөн долоо хоног + label_last_n_days: "сүүлийн %{count} өдрүүд" + label_this_month: энэ сар + label_last_month: сүүлийн сар + label_this_year: энэ жил + label_date_range: Хязгаар огноо + label_less_than_ago: бага өдрийн дотор + label_more_than_ago: их өдрийн дотор + label_ago: өдрийн өмнө + label_contains: агуулж байгаа + label_not_contains: агуулаагүй + label_day_plural: өдрүүд + label_repository: Репозитори + label_repository_plural: Репозиторууд + label_browse: Үзэх + label_modification: "%{count} өөрчлөлт" + label_modification_plural: "%{count} өөрчлөлтүүд" + label_branch: Салбар + label_tag: Шошго + label_revision: Хувилбар + label_revision_plural: Хувилбарууд + label_revision_id: "%{value} Хувилбар" + label_associated_revisions: Хамааралтай хувилбарууд + label_added: нэмэгдсэн + label_modified: өөрчлөгдсөн + label_copied: хуулсан + label_renamed: нэрийг нь өөрчилсөн + label_deleted: устгасан + label_latest_revision: Сүүлийн үеийн хувилбар + label_latest_revision_plural: Сүүлийн үеийн хувилбарууд + label_view_revisions: Хувилбаруудыг харах + label_view_all_revisions: Бүх хувилбаруудыг харах + label_max_size: Maximum size + label_sort_highest: Хамгийн дээр + label_sort_higher: Дээш нь + label_sort_lower: Доош нь + label_sort_lowest: Хамгийн доор + label_roadmap: Хөтөч + label_roadmap_due_in: "%{value} дотор дуусгах" + label_roadmap_overdue: "%{value} оройтсон" + label_roadmap_no_issues: Энэ хувилбарт асуудал байхгүй байна + label_search: Хайх + label_result_plural: Үр дүн + label_all_words: Бүх үгс + label_wiki: Вики + label_wiki_edit: Вики засвар + label_wiki_edit_plural: Вики засварууд + label_wiki_page: Вики хуудас + label_wiki_page_plural: Вики хуудас + label_index_by_title: Гарчгаар эрэмбэлэх + label_index_by_date: Огноогоор эрэмбэлэх + label_current_version: Одоогийн хувилбар + label_preview: Ямар харагдахыг шалгах + label_feed_plural: Feeds + label_changes_details: Бүх өөрчлөлтүүдийн дэлгэрэнгүй + label_issue_tracking: Асуудал хянах + label_spent_time: Зарцуулсан хугацаа + label_f_hour: "%{value} цаг" + label_f_hour_plural: "%{value} цаг" + label_time_tracking: Хугацааг хянах + label_change_plural: Өөрчлөлтүүд + label_statistics: Статистик + label_commits_per_month: Сард хийсэн коммитын тоо + label_commits_per_author: Зохиогч бүрийн хувьд коммитын тоо + label_view_diff: Ялгаануудыг харах + label_diff_inline: дотор нь + label_diff_side_by_side: зэрэгцүүлж + label_options: Тохиргоо + label_copy_workflow_from: Ажлын дарааллыг хуулах + label_permissions_report: Зөвшөөрлүүдийн таблиц + label_watched_issues: Ажиглагдаж байгаа асуудлууд + label_related_issues: Хамааралтай асуудлууд + label_applied_status: Олгосон төлөв + label_loading: Ачаалж байна... + label_relation_new: Шинэ хамаарал + label_relation_delete: Хамаарлыг устгах + label_relates_to: энгийн хамааралтай + label_duplicates: хос хамааралтай + label_duplicated_by: давхардуулсан эзэн + label_blocks: шаардах хамааралтай + label_blocked_by: блоколсон эзэн + label_precedes: урьдчилах хамааралтай + label_follows: дагаж + label_end_to_start: хойноос нь урагшаа + label_end_to_end: хойноос нь хойшоо + label_start_to_start: урдаас нь урагаа + label_start_to_end: урдаас нь хойшоо + label_stay_logged_in: Энэ комьютер дээр санах + label_disabled: идэвхгүй болсон + label_show_completed_versions: Гүйцэд хувилбаруудыг харуулах + label_me: би + label_board: Форум + label_board_new: Шинэ форум + label_board_plural: Форумууд + label_board_locked: Түгжээтэй + label_board_sticky: Sticky + label_topic_plural: Сэдвүүд + label_message_plural: Зурвасууд + label_message_last: Сүүлийн зурвас + label_message_new: Шинэ зурвас + label_message_posted: Зурвас нэмэгдлээ + label_reply_plural: Хариултууд + label_send_information: Дансны мэдээллийг хэрэглэгчид илгээх + label_year: Жил + label_month: Сар + label_week: Долоо хоног + label_date_from: Хэзээнээс + label_date_to: Хэдий хүртэл + label_language_based: Хэрэглэгчийн хэлнас шалтгаалан + label_sort_by: "%{value} талбараар нь эрэмбэлэх" + label_send_test_email: Турших мэйл илгээх + label_feeds_access_key: RSS хандах түлхүүр + label_missing_feeds_access_key: RSS хандах түлхүүр алга + label_feeds_access_key_created_on: "RSS хандалтын түлхүүр %{value}-ийн өмнө үүссэн" + label_module_plural: Модулууд + label_added_time_by: "%{author} %{age}-ийн өмнө нэмсэн" + label_updated_time_by: "%{author} %{age}-ийн өмнө өөрчилсөн" + label_updated_time: "%{value} -ийн өмнө өөрчлөгдсөн" + label_jump_to_a_project: Төсөл рүү очих... + label_file_plural: Файлууд + label_changeset_plural: Өөрчлөлтүүд + label_default_columns: Стандарт баганууд + label_no_change_option: (Өөрчлөлт байхгүй) + label_bulk_edit_selected_issues: Сонгогдсон асуудлуудыг бөөнөөр засварлах + label_theme: Системийн Дизайн + label_default: Стандарт + label_search_titles_only: Зөвхөн гарчиг хайх + label_user_mail_option_all: "Миний бүх төсөл дээрх бүх үзэгдлүүдийн хувьд" + label_user_mail_option_selected: "Сонгогдсон төслүүдийн хувьд бүх үзэгдэл дээр..." + label_user_mail_no_self_notified: "Миний өөрийн хийсэн өөрчлөлтүүдийн тухай надад мэдэгдэх хэрэггүй" + label_registration_activation_by_email: дансыг имэйлээр идэвхжүүлэх + label_registration_manual_activation: дансыг гараар идэвхжүүлэх + label_registration_automatic_activation: дансыг автоматаар идэвхжүүлэх + label_display_per_page: 'Нэг хуудсанд: %{value}' + label_age: Нас + label_change_properties: Тохиргоог өөрчлөх + label_general: Ерөнхий + label_more: Цааш нь + label_scm: SCM + label_plugins: Модулууд + label_ldap_authentication: LDAP нэвтрэх горим + label_downloads_abbr: D/L + label_optional_description: Дурын тайлбар + label_add_another_file: Дахин файл нэмэх + label_preferences: Тохиргоо + label_chronological_order: Цагаан толгойн үсгийн дарааллаар + label_reverse_chronological_order: Урвуу цагаан толгойн үсгийн дарааллаар + label_planning: Төлөвлөлт + label_incoming_emails: Ирсэн мэйлүүд + label_generate_key: Түлхүүр үүсгэх + label_issue_watchers: Ажиглагчид + label_example: Жишээ + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Groups + label_group_new: New group + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + + button_login: Нэвтрэх + button_submit: Илгээх + button_save: Хадгалах + button_check_all: Бүгдийг сонго + button_uncheck_all: Бүгдийг үл сонго + button_delete: Устгах + button_create: Үүсгэх + button_create_and_continue: Үүсгээд цааш үргэлжлүүлэх + button_test: Турших + button_edit: Засварлах + button_add: Нэмэх + button_change: Өөрчлөх + button_apply: Өөрчлөлтийг хадгалах + button_clear: Цэвэрлэх + button_lock: Түгжих + button_unlock: Түгжээг тайлах + button_download: Татах + button_list: Жагсаалт + button_view: Харах + button_move: Зөөх + button_move_and_follow: Зөө бас дага + button_back: Буцах + button_cancel: Болих + button_activate: Идэвхжүүлэх + button_sort: Эрэмбэлэх + button_log_time: Лог хийсэн хугацаа + button_rollback: Энэ хувилбар руу буцах + button_watch: Ажиглах + button_unwatch: Ажиглахаа болих + button_reply: Хариулах + button_archive: Архивлах + button_unarchive: Архивыг задлах + button_reset: Анхны утгууд + button_rename: Нэрийг нь солих + button_change_password: Нууц үгээ өөрчлөх + button_copy: Хуулах + button_copy_and_follow: Зөө бас дага + button_annotate: Тайлбар хавсаргах + button_update: Шинэчлэх + button_configure: Тохируулах + button_quote: Ишлэл + button_duplicate: Хуулбар + button_show: Үзэх + + status_active: идэвхтэй + status_registered: бүртгүүлсэн + status_locked: түгжээтэй + + version_status_open: нээлттэй + version_status_locked: түгжээтэй + version_status_closed: хаалттай + + field_active: идэвхтэй + + text_select_mail_notifications: Ямар үед имэйлээр мэдэгдэл илгээхийг сонгоно уу. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 гэвэл ямар ч хязгааргүй гэсэн үг + text_project_destroy_confirmation: Та энэ төсөл болоод бусад мэдээллийг нь үнэхээр устгамаар байна уу ? + text_subprojects_destroy_warning: "Уг төслийн дэд төслүүд : %{value} нь бас устгагдах болно." + text_workflow_edit: Ажлын дарааллыг өөрчлөхийн тулд хандалтын эрх болон асуудлын чиглэлийг сонгоно уу + text_are_you_sure: Та итгэлтэй байна уу ? + text_journal_changed: "%{label} %{old} байсан нь %{new} болов" + text_journal_set_to: "%{label} %{value} болгож өөрчиллөө" + text_journal_deleted: "%{label} устсан (%{old})" + text_journal_added: "%{label} %{value} нэмэгдсэн" + text_tip_issue_begin_day: энэ өдөр эхлэх ажил + text_tip_issue_end_day: энэ өдөр дуусах ажил + text_tip_issue_begin_end_day: энэ өдөр эхлээд мөн дуусч байгаа ажил + text_project_identifier_info: 'Зөвхөн жижиг үсгүүд болон (a-z), тоо and дундуур зураас ашиглаж болно.
Нэгэнт хадгалсан хойно, төслийн глобал нэрийг өөрлчөх боломжгүй.' + text_caracters_maximum: "дээд тал нь %{count} үсэг." + text_caracters_minimum: "Хамгийн багадаа ядаж %{count} тэмдэгт байх." + text_length_between: "Урт нь багадаа %{min}, ихдээ %{max} тэмдэгт." + text_tracker_no_workflow: Энэхүү асуудлын чиглэлд ямар ч ажлын дараалал тодорхойлогдоогүй байна + text_unallowed_characters: Хэрэглэж болохгүй тэмдэгтүүд + text_comma_separated: Таслалаар зааглан олон утга оруулж болно. + text_line_separated: Multiple values allowed (one line for each value). + text_issues_ref_in_commit_messages: Коммитийн зурвасуудад хамааруулсан болон байнгын асуудлууд + text_issue_added: "Асуудал %{id} - ийг хэрэглэгч %{author} мэдэгдсэн байна." + text_issue_updated: "Асуудал %{id} - ийг хэрэглэгч %{author} өөрчилсөн байна." + text_wiki_destroy_confirmation: Та энэ вики болон холбогдох бүх мэдээллийг үнэхээр устгамаар байна уу ? + text_issue_category_destroy_question: "Энэ ангилалд зарим асуудлууд (%{count}) орсон байна. Та яах вэ ?" + text_issue_category_destroy_assignments: Асуудлуудыг энэ ангиллаас авах + text_issue_category_reassign_to: Асуудлуудыг энэ ангилалд дахин оноох + text_user_mail_option: "Сонгогдоогүй төслүүдийн хувьд, та зөвхөн өөрийнхөө ажиглаж байгаа зүйлс юмуу танд хамаатай зүйлсийн талаар мэдэгдэл авах болно (Таны оруулсан асуудал, эсвэл танд оноосон гэх мэт)." + text_no_configuration_data: "Хандалтын эрхүүд, чиглэлүүд, асуудлын төлвүүд болон ажлын дарааллын тухай мэдээллийг хараахан оруулаагүй байна.\nТа стандарт өгөгдлүүдийг даруйхан оруулахыг зөвлөж байна, оруулсан хойно та засварлаж болно." + text_load_default_configuration: Стандарт өгөгдлийг ачаалах + text_status_changed_by_changeset: "%{value} өөрчлөлтөд хийгдсэн." + text_issues_destroy_confirmation: 'Та сонгогдсон асуудлуудыг үнэхээр устгамаар байна уу ?' + text_select_project_modules: 'Энэ төслийн хувьд идэвхжүүлэх модулуудаа сонгоно уу:' + text_default_administrator_account_changed: Стандарт администраторын бүртгэл өөрчлөгдлөө + text_file_repository_writable: Хавсралт файл хадгалах хавтас руу бичих эрхтэй + text_plugin_assets_writable: Плагин модулийн ассет хавтас руу бичих эрхтэй + text_rmagick_available: RMagick суулгагдсан (заавал биш) + text_destroy_time_entries_question: "Таны устгах гэж байгаа асуудлууд дээр нийт %{hours} цаг зарцуулсан юм байна, та яах вэ ?" + text_destroy_time_entries: Мэдэгдсэн цагуудыг устгах + text_assign_time_entries_to_project: Мэдэгдсэн асуудлуудыг төсөлд оноох + text_reassign_time_entries: 'Мэдэгдсэн асуудлуудыг энэ асуудалд дахин оноо:' + text_user_wrote: "%{value} бичихдээ:" + text_enumeration_destroy_question: "Энэ утгад %{count} обьект оноогдсон байна." + text_enumeration_category_reassign_to: 'Тэдгээрийг энэ утгад дахин оноо:' + text_email_delivery_not_configured: "Имэйлийн тохиргоог хараахан тохируулаагүй байна, тиймээс имэйл мэдэгдэл явуулах боломжгүй байна.\nSMTP сервэрээ config/configuration.yml файл дотор тохируулаад төслийн менежерээ дахиад эхлүүлээрэй." + text_repository_usernames_mapping: "Репозиторийн логд байгаа бүх хэрэглэгчийн нэрүүдэд харгалзсан Төслийн Менежер системд бүртгэлтэй хэрэглэгчдийг Сонгох юмуу шинэчилнэ үү.\nТөслийн менежер болон репозиторид байгаа ижилхэн нэр юмуу имэйлтэй хэрэглэгчид харилцан харгалзна." + text_diff_truncated: '... Файлын ялгаврын хэмжээ үзүүлэхэд дэндүү урт байгаа учраас төгсгөлөөс нь хасч үзүүлэв.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + + default_role_manager: Менежер + default_role_developer: Хөгжүүлэгч + default_role_reporter: Мэдэгдэгч + default_tracker_bug: Алдаа + default_tracker_feature: Онцлог + default_tracker_support: Тусламж + default_issue_status_new: Шинэ + default_issue_status_in_progress: Ахицтай + default_issue_status_assigned: Оноогдсон + default_issue_status_resolved: Шийдвэрлэгдсэн + default_issue_status_feedback: Feedback + default_issue_status_closed: Хаагдсан + default_issue_status_rejected: Хүлээж аваагүй + default_doc_category_user: Хэрэглэгчийн бичиг баримт + default_doc_category_tech: Техникийн бичиг баримт + default_priority_low: Бага + default_priority_normal: Хэвийн + default_priority_high: Өндөр + default_priority_urgent: Нэн яаралтай + default_priority_immediate: Нэн даруй + default_activity_design: Дизайн + default_activity_development: Хөгжүүлэлт + + enumeration_issue_priorities: Асуудлын зэрэглэлүүд + enumeration_doc_categories: Бичиг баримтын ангиллууд + enumeration_activities: Үйл ажиллагаанууд (хугацааг хянах) + enumeration_system_activity: Системийн үйл ажиллагаа + + permission_manage_subtasks: Manage subtasks + label_profile: Profile + field_parent_issue: Parent task + error_unable_delete_issue_status: Unable to delete issue status + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Коммит хийх үед харуулах текстүүдийн энкодинг + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/581d6465316c7aa11955243aa80ebe0764644088.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/581d6465316c7aa11955243aa80ebe0764644088.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ += Redmine + +Redmine is a flexible project management web application written using Ruby on Rails framework. + +More details can be found in the doc directory or on the official website http://www.redmine.org diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/5822b09752fa0149f57efed74cf7dcc3c9694bb5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/5822b09752fa0149f57efed74cf7dcc3c9694bb5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Utils + class << self + # Returns the relative root url of the application + def relative_url_root + ActionController::Base.respond_to?('relative_url_root') ? + ActionController::Base.relative_url_root.to_s : + ActionController::AbstractRequest.relative_url_root.to_s + end + + # Sets the relative root url of the application + def relative_url_root=(arg) + if ActionController::Base.respond_to?('relative_url_root=') + ActionController::Base.relative_url_root=arg + else + ActionController::AbstractRequest.relative_url_root=arg + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58261982049d3b7dd925c22de2f64cf02067af2f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58261982049d3b7dd925c22de2f64cf02067af2f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Bold'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Subliniat'; +jsToolBar.strings['Deleted'] = 'Șters'; +jsToolBar.strings['Code'] = 'Fragment de cod'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Listă pe puncte'; +jsToolBar.strings['Ordered list'] = 'Listă ordonată'; +jsToolBar.strings['Quote'] = 'Citează'; +jsToolBar.strings['Unquote'] = 'Fără citat'; +jsToolBar.strings['Preformatted text'] = 'Text preformatat'; +jsToolBar.strings['Wiki link'] = 'Trimitere către o pagină wiki'; +jsToolBar.strings['Image'] = 'Imagine'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/5852d7fa42575c6a27e640ff68cec09c3d3e0a43.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/5852d7fa42575c6a27e640ff68cec09c3d3e0a43.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,157 @@ +# = Redmine configuration file +# +# Each environment has it's own configuration options. If you are only +# running in production, only the production block needs to be configured. +# Environment specific configuration options override the default ones. +# +# Note that this file needs to be a valid YAML file. +# DO NOT USE TABS! Use 2 spaces instead of tabs for identation. +# +# == Outgoing email settings (email_delivery setting) +# +# === Common configurations +# +# ==== Sendmail command +# +# production: +# email_delivery: +# delivery_method: :sendmail +# +# ==== Simple SMTP server at localhost +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "localhost" +# port: 25 +# +# ==== SMTP server at example.com using LOGIN authentication and checking HELO for foo.com +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "example.com" +# port: 25 +# authentication: :login +# domain: 'foo.com' +# user_name: 'myaccount' +# password: 'password' +# +# ==== SMTP server at example.com using PLAIN authentication +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "example.com" +# port: 25 +# authentication: :plain +# domain: 'example.com' +# user_name: 'myaccount' +# password: 'password' +# +# ==== SMTP server at using TLS (GMail) +# +# This requires some additional configuration. See the article at: +# http://redmineblog.com/articles/setup-redmine-to-send-email-using-gmail/ +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# tls: true +# enable_starttls_auto: true +# address: "smtp.gmail.com" +# port: 587 +# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps +# authentication: :plain +# user_name: "your_email@gmail.com" +# password: "your_password" +# +# +# === More configuration options +# +# See the "Configuration options" at the following website for a list of the +# full options allowed: +# +# http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer + + +# default configuration options for all environments +default: + # Outgoing emails configuration (see examples above) + email_delivery: + delivery_method: :smtp + smtp_settings: + address: smtp.example.net + port: 25 + domain: example.net + authentication: :login + user_name: "redmine@example.net" + password: "redmine" + + # Absolute path to the directory where attachments are stored. + # The default is the 'files' directory in your Redmine instance. + # Your Redmine instance needs to have write permission on this + # directory. + # Examples: + # attachments_storage_path: /var/redmine/files + # attachments_storage_path: D:/redmine/files + attachments_storage_path: + + # Configuration of the autologin cookie. + # autologin_cookie_name: the name of the cookie (default: autologin) + # autologin_cookie_path: the cookie path (default: /) + # autologin_cookie_secure: true sets the cookie secure flag (default: false) + autologin_cookie_name: + autologin_cookie_path: + autologin_cookie_secure: + + # Configuration of SCM executable command. + # + # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe) + # On Windows + CRuby, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work. + # + # On Windows + JRuby 1.6.2, path which contains spaces does not work. + # For example, "C:\Program Files\TortoiseHg\hg.exe". + # If you want to this feature, you need to install to the path which does not contains spaces. + # For example, "C:\TortoiseHg\hg.exe". + # + # Examples: + # scm_subversion_command: svn # (default: svn) + # scm_mercurial_command: C:\Program Files\TortoiseHg\hg.exe # (default: hg) + # scm_git_command: /usr/local/bin/git # (default: git) + # scm_cvs_command: cvs # (default: cvs) + # scm_bazaar_command: bzr.exe # (default: bzr) + # scm_darcs_command: darcs-1.0.9-i386-linux # (default: darcs) + # + scm_subversion_command: + scm_mercurial_command: + scm_git_command: + scm_cvs_command: + scm_bazaar_command: + scm_darcs_command: + + # Key used to encrypt sensitive data in the database (SCM and LDAP passwords). + # If you don't want to enable data encryption, just leave it blank. + # WARNING: losing/changing this key will make encrypted data unreadable. + # + # If you want to encrypt existing passwords in your database: + # * set the cipher key here in your configuration file + # * encrypt data using 'rake db:encrypt RAILS_ENV=production' + # + # If you have encrypted data and want to change this key, you have to: + # * decrypt data using 'rake db:decrypt RAILS_ENV=production' first + # * change the cipher key here in your configuration file + # * encrypt data using 'rake db:encrypt RAILS_ENV=production' + database_cipher_key: + +# specific configuration options for production environment +# that overrides the default ones +production: + +# specific configuration options for development environment +# that overrides the default ones +development: diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58798d95d2677f7c2652f875b5506cce3ae90864.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58798d95d2677f7c2652f875b5506cce3ae90864.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddDeleteWikiPagesAttachmentsPermission < ActiveRecord::Migration + def self.up + Role.find(:all).each do |r| + r.add_permission!(:delete_wiki_pages_attachments) if r.has_permission?(:edit_wiki_pages) + end + end + + def self.down + Role.find(:all).each do |r| + r.remove_permission!(:delete_wiki_pages_attachments) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/587f513ddb7f708d124448f5d5cd571d4d406ca2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/587f513ddb7f708d124448f5d5cd571d4d406ca2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,87 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssueMovesController < ApplicationController + menu_item :issues + + default_search_scope :issues + before_filter :find_issues, :check_project_uniqueness + before_filter :authorize + + def new + prepare_for_issue_move + render :layout => false if request.xhr? + end + + def create + prepare_for_issue_move + + if request.post? + new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) + unsaved_issue_ids = [] + moved_issues = [] + @issues.each do |issue| + issue.reload + issue.init_journal(User.current) + issue.current_journal.notes = @notes if @notes.present? + call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) + if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => extract_changed_attributes_for_move(params)}) + moved_issues << r + else + unsaved_issue_ids << issue.id + end + end + set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) + + if params[:follow] + if @issues.size == 1 && moved_issues.size == 1 + redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first + else + redirect_to :controller => 'issues', :action => 'index', :project_id => (@target_project || @project) + end + else + redirect_to :controller => 'issues', :action => 'index', :project_id => @project + end + return + end + end + + private + + def prepare_for_issue_move + @issues.sort! + @copy = params[:copy_options] && params[:copy_options][:copy] + @allowed_projects = Issue.allowed_target_projects_on_move + @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] + @target_project ||= @project + @trackers = @target_project.trackers + @available_statuses = Workflow.available_statuses(@project) + @notes = params[:notes] + @notes ||= '' + end + + def extract_changed_attributes_for_move(params) + changed_attributes = {} + [:assigned_to_id, :status_id, :start_date, :due_date, :priority_id].each do |valid_attribute| + unless params[valid_attribute].blank? + changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) + end + end + changed_attributes + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58995322e1c9bf3bd9846c83b63229838be0f932.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58995322e1c9bf3bd9846c83b63229838be0f932.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +caged: + id: 1 + name: caged +mly: + id: 2 + name: mly \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58b49876d90ca4f57b376fabd8862c7bd7f14741.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58b49876d90ca4f57b376fabd8862c7bd7f14741.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,172 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class GroupsController < ApplicationController + layout 'admin' + + before_filter :require_admin + + helper :custom_fields + + # GET /groups + # GET /groups.xml + def index + @groups = Group.find(:all, :order => 'lastname') + + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @groups } + end + end + + # GET /groups/1 + # GET /groups/1.xml + def show + @group = Group.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.xml { render :xml => @group } + end + end + + # GET /groups/new + # GET /groups/new.xml + def new + @group = Group.new + + respond_to do |format| + format.html # new.html.erb + format.xml { render :xml => @group } + end + end + + # GET /groups/1/edit + def edit + @group = Group.find(params[:id], :include => :projects) + end + + # POST /groups + # POST /groups.xml + def create + @group = Group.new(params[:group]) + + respond_to do |format| + if @group.save + format.html { + flash[:notice] = l(:notice_successful_create) + redirect_to(params[:continue] ? new_group_path : groups_path) + } + format.xml { render :xml => @group, :status => :created, :location => @group } + else + format.html { render :action => "new" } + format.xml { render :xml => @group.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /groups/1 + # PUT /groups/1.xml + def update + @group = Group.find(params[:id]) + + respond_to do |format| + if @group.update_attributes(params[:group]) + flash[:notice] = l(:notice_successful_update) + format.html { redirect_to(groups_path) } + format.xml { head :ok } + else + format.html { render :action => "edit" } + format.xml { render :xml => @group.errors, :status => :unprocessable_entity } + end + end + end + + # DELETE /groups/1 + # DELETE /groups/1.xml + def destroy + @group = Group.find(params[:id]) + @group.destroy + + respond_to do |format| + format.html { redirect_to(groups_url) } + format.xml { head :ok } + end + end + + def add_users + @group = Group.find(params[:id]) + users = User.find_all_by_id(params[:user_ids]) + @group.users << users if request.post? + respond_to do |format| + format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } + format.js { + render(:update) {|page| + page.replace_html "tab-content-users", :partial => 'groups/users' + users.each {|user| page.visual_effect(:highlight, "user-#{user.id}") } + } + } + end + end + + def remove_user + @group = Group.find(params[:id]) + @group.users.delete(User.find(params[:user_id])) if request.delete? + respond_to do |format| + format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } + format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} } + end + end + + def autocomplete_for_user + @group = Group.find(params[:id]) + @users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100) + render :layout => false + end + + def edit_membership + @group = Group.find(params[:id]) + @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) + @membership.save if request.post? + respond_to do |format| + if @membership.valid? + format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' } + format.js { + render(:update) {|page| + page.replace_html "tab-content-memberships", :partial => 'groups/memberships' + page.visual_effect(:highlight, "member-#{@membership.id}") + } + } + else + format.js { + render(:update) {|page| + page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', '))) + } + } + end + end + end + + def destroy_membership + @group = Group.find(params[:id]) + Member.find(params[:membership_id]).destroy if request.post? + respond_to do |format| + format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' } + format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'groups/memberships'} } + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58db9baf0f6d2aa4b263068238c559860f800493.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58db9baf0f6d2aa4b263068238c559860f800493.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,59 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::ThemesTest < ActiveSupport::TestCase + + def test_themes + themes = Redmine::Themes.themes + assert_kind_of Array, themes + assert_kind_of Redmine::Themes::Theme, themes.first + end + + def test_rescan + Redmine::Themes.themes.pop + + assert_difference 'Redmine::Themes.themes.size' do + Redmine::Themes.rescan + end + end + + def test_theme_loaded + theme = Redmine::Themes.themes.last + + assert_equal theme, Redmine::Themes.theme(theme.id) + end + + def test_theme_loaded_without_rescan + theme = Redmine::Themes.themes.last + + assert_equal theme, Redmine::Themes.theme(theme.id, :rescan => false) + end + + def test_theme_not_loaded + theme = Redmine::Themes.themes.pop + + assert_equal theme, Redmine::Themes.theme(theme.id) + end + + def test_theme_not_loaded_without_rescan + theme = Redmine::Themes.themes.pop + + assert_nil Redmine::Themes.theme(theme.id, :rescan => false) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58e6527d4086f1819267e25b6b03c3312d2d52cf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58e6527d4086f1819267e25b6b03c3312d2d52cf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMessagesLocked < ActiveRecord::Migration + def self.up + add_column :messages, :locked, :boolean, :default => false + end + + def self.down + remove_column :messages, :locked + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/58/58fc215fd544eb8c78c674a116477a7653252be9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/58/58fc215fd544eb8c78c674a116477a7653252be9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,48 @@ +#============================================================+ +# File name : eng.rb +# Begin : 2004-03-03 +# Last Update : 2005-03-19 +# +# Description : Language module for TCPDF +# (contains translated texts) +# +# +# Author: Nicola Asuni +# +# (c) Copyright: +# Tecnick.com S.r.l. +# Via Ugo Foscolo n.19 +# 09045 Quartu Sant'Elena (CA) +# ITALY +# www.tecnick.com +# info@tecnick.com +#============================================================+ + +# +# TCPDF language file (contains translated texts). +# @package com.tecnick.tcpdf +# @abstract TCPDF language file. +# @author Nicola Asuni +# @copyright 2004 Tecnick.com S.r.l (www.tecnick.com) Via Ugo Foscolo n.19 - 09045 Quartu Sant'Elena (CA) - ITALY - www.tecnick.com - info@tecnick.com +# @link http://tcpdf.sourceforge.net +# @license http://www.gnu.org/copyleft/lesser.html LGPL +# @since 2004-03-03 +# + +# ENGLISH + +@l = [] + +# PAGE META DESCRIPTORS -------------------------------------- + +@l['a_meta_charset'] = "UTF-8"; +@l['a_meta_dir'] = "ltr"; +@l['a_meta_language'] = "en"; + +# TRANSLATIONS -------------------------------------- +@l['w_page'] = "page"; + +#============================================================+ +# END OF FILE +#============================================================+ + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/590eaa24ab9f834ac16f2b590030d2f8381b4376.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/590eaa24ab9f834ac16f2b590030d2f8381b4376.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,111 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class RoleTest < ActiveSupport::TestCase + fixtures :roles, :workflows + + def test_copy_workflows + source = Role.find(1) + assert_equal 90, source.workflows.size + + target = Role.new(:name => 'Target') + assert target.save + target.workflows.copy(source) + target.reload + assert_equal 90, target.workflows.size + end + + def test_add_permission + role = Role.find(1) + size = role.permissions.size + role.add_permission!("apermission", "anotherpermission") + role.reload + assert role.permissions.include?(:anotherpermission) + assert_equal size + 2, role.permissions.size + end + + def test_remove_permission + role = Role.find(1) + size = role.permissions.size + perm = role.permissions[0..1] + role.remove_permission!(*perm) + role.reload + assert ! role.permissions.include?(perm[0]) + assert_equal size - 2, role.permissions.size + end + + def test_name + I18n.locale = 'fr' + assert_equal 'Manager', Role.find(1).name + assert_equal 'Anonyme', Role.anonymous.name + assert_equal 'Non membre', Role.non_member.name + end + + context "#anonymous" do + should "return the anonymous role" do + role = Role.anonymous + assert role.builtin? + assert_equal Role::BUILTIN_ANONYMOUS, role.builtin + end + + context "with a missing anonymous role" do + setup do + Role.delete_all("builtin = #{Role::BUILTIN_ANONYMOUS}") + end + + should "create a new anonymous role" do + assert_difference('Role.count') do + Role.anonymous + end + end + + should "return the anonymous role" do + role = Role.anonymous + assert role.builtin? + assert_equal Role::BUILTIN_ANONYMOUS, role.builtin + end + end + end + + context "#non_member" do + should "return the non-member role" do + role = Role.non_member + assert role.builtin? + assert_equal Role::BUILTIN_NON_MEMBER, role.builtin + end + + context "with a missing non-member role" do + setup do + Role.delete_all("builtin = #{Role::BUILTIN_NON_MEMBER}") + end + + should "create a new non-member role" do + assert_difference('Role.count') do + Role.non_member + end + end + + should "return the non-member role" do + role = Role.non_member + assert role.builtin? + assert_equal Role::BUILTIN_NON_MEMBER, role.builtin + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/59155925e9732d73904dad9c2f63d90a3de31c6a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/59155925e9732d73904dad9c2f63d90a3de31c6a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Podebljano'; +jsToolBar.strings['Italic'] = 'Kurziv'; +jsToolBar.strings['Underline'] = 'Podvučeno'; +jsToolBar.strings['Deleted'] = 'Obrisano'; +jsToolBar.strings['Code'] = 'Ugrađeni kôd'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Lista nabrajanja'; +jsToolBar.strings['Ordered list'] = 'Uređena lista'; +jsToolBar.strings['Quote'] = 'Pod navodnicima'; +jsToolBar.strings['Unquote'] = 'Ukloni navodnike'; +jsToolBar.strings['Preformatted text'] = 'Prethodno formatiran tekst'; +jsToolBar.strings['Wiki link'] = 'Veza prema Wiki strani'; +jsToolBar.strings['Image'] = 'Slika'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/594645e33ca990837dd2f730162a5f369b707902.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/594645e33ca990837dd2f730162a5f369b707902.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,449 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'tree' # gem install rubytree + +# Monkey patch the TreeNode to add on a few more methods :nodoc: +module TreeNodePatch + def self.included(base) + base.class_eval do + attr_reader :last_items_count + + alias :old_initilize :initialize + def initialize(name, content = nil) + old_initilize(name, content) + @childrenHash ||= {} + @last_items_count = 0 + extend(InstanceMethods) + end + end + end + + module InstanceMethods + # Adds the specified child node to the receiver node. The child node's + # parent is set to be the receiver. The child is added as the first child in + # the current list of children for the receiver node. + def prepend(child) + raise "Child already added" if @childrenHash.has_key?(child.name) + + @childrenHash[child.name] = child + @children = [child] + @children + child.parent = self + return child + + end + + # Adds the specified child node to the receiver node. The child node's + # parent is set to be the receiver. The child is added at the position + # into the current list of children for the receiver node. + def add_at(child, position) + raise "Child already added" if @childrenHash.has_key?(child.name) + + @childrenHash[child.name] = child + @children = @children.insert(position, child) + child.parent = self + return child + + end + + def add_last(child) + raise "Child already added" if @childrenHash.has_key?(child.name) + + @childrenHash[child.name] = child + @children << child + @last_items_count += 1 + child.parent = self + return child + + end + + # Adds the specified child node to the receiver node. The child node's + # parent is set to be the receiver. The child is added as the last child in + # the current list of children for the receiver node. + def add(child) + raise "Child already added" if @childrenHash.has_key?(child.name) + + @childrenHash[child.name] = child + position = @children.size - @last_items_count + @children.insert(position, child) + child.parent = self + return child + + end + + # Wrapp remove! making sure to decrement the last_items counter if + # the removed child was a last item + def remove!(child) + @last_items_count -= +1 if child && child.last + super + end + + + # Will return the position (zero-based) of the current child in + # it's parent + def position + self.parent.children.index(self) + end + end +end +Tree::TreeNode.send(:include, TreeNodePatch) + +module Redmine + module MenuManager + class MenuError < StandardError #:nodoc: + end + + module MenuController + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}} + mattr_accessor :menu_items + + # Set the menu item name for a controller or specific actions + # Examples: + # * menu_item :tickets # => sets the menu name to :tickets for the whole controller + # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only + # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only + # + # The default menu item name for a controller is controller_name by default + # Eg. the default menu item name for ProjectsController is :projects + def menu_item(id, options = {}) + if actions = options[:only] + actions = [] << actions unless actions.is_a?(Array) + actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id} + else + menu_items[controller_name.to_sym][:default] = id + end + end + end + + def menu_items + self.class.menu_items + end + + # Returns the menu item name according to the current action + def current_menu_item + @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] || + menu_items[controller_name.to_sym][:default] + end + + # Redirects user to the menu item of the given project + # Returns false if user is not authorized + def redirect_to_project_menu_item(project, name) + item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s} + if item && User.current.allowed_to?(item.url, project) && (item.condition.nil? || item.condition.call(project)) + redirect_to({item.param => project}.merge(item.url)) + return true + end + false + end + end + + module MenuHelper + # Returns the current menu item name + def current_menu_item + controller.current_menu_item + end + + # Renders the application main menu + def render_main_menu(project) + render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project) + end + + def display_main_menu?(project) + menu_name = project && !project.new_record? ? :project_menu : :application_menu + Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root + end + + def render_menu(menu, project=nil) + links = [] + menu_items_for(menu, project) do |node| + links << render_menu_node(node, project) + end + links.empty? ? nil : content_tag('ul', links.join("\n").html_safe) + end + + def render_menu_node(node, project=nil) + if node.hasChildren? || !node.child_menus.nil? + return render_menu_node_with_children(node, project) + else + caption, url, selected = extract_node_details(node, project) + return content_tag('li', + render_single_menu_node(node, caption, url, selected)) + end + end + + def render_menu_node_with_children(node, project=nil) + caption, url, selected = extract_node_details(node, project) + + html = [].tap do |html| + html << '
  • ' + # Parent + html << render_single_menu_node(node, caption, url, selected) + + # Standard children + standard_children_list = "".tap do |child_html| + node.children.each do |child| + child_html << render_menu_node(child, project) + end + end + + html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty? + + # Unattached children + unattached_children_list = render_unattached_children_menu(node, project) + html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank? + + html << '
  • ' + end + return html.join("\n") + end + + # Returns a list of unattached children menu items + def render_unattached_children_menu(node, project) + return nil unless node.child_menus + + "".tap do |child_html| + unattached_children = node.child_menus.call(project) + # Tree nodes support #each so we need to do object detection + if unattached_children.is_a? Array + unattached_children.each do |child| + child_html << content_tag(:li, render_unattached_menu_item(child, project)) + end + else + raise MenuError, ":child_menus must be an array of MenuItems" + end + end + end + + def render_single_menu_node(item, caption, url, selected) + link_to(h(caption), url, item.html_options(:selected => selected)) + end + + def render_unattached_menu_item(menu_item, project) + raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem + + if User.current.allowed_to?(menu_item.url, project) + link_to(h(menu_item.caption), + menu_item.url, + menu_item.html_options) + end + end + + def menu_items_for(menu, project=nil) + items = [] + Redmine::MenuManager.items(menu).root.children.each do |node| + if allowed_node?(node, User.current, project) + if block_given? + yield node + else + items << node # TODO: not used? + end + end + end + return block_given? ? nil : items + end + + def extract_node_details(node, project=nil) + item = node + url = case item.url + when Hash + project.nil? ? item.url : {item.param => project}.merge(item.url) + when Symbol + send(item.url) + else + item.url + end + caption = item.caption(project) + return [caption, url, (current_menu_item == item.name)] + end + + # Checks if a user is allowed to access the menu item by: + # + # * Checking the conditions of the item + # * Checking the url target (project only) + def allowed_node?(node, user, project) + if node.condition && !node.condition.call(project) + # Condition that doesn't pass + return false + end + + if project + return user && user.allowed_to?(node.url, project) + else + # outside a project, all menu items allowed + return true + end + end + end + + class << self + def map(menu_name) + @items ||= {} + mapper = Mapper.new(menu_name.to_sym, @items) + if block_given? + yield mapper + else + mapper + end + end + + def items(menu_name) + @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {}) + end + end + + class Mapper + def initialize(menu, items) + items[menu] ||= Tree::TreeNode.new(:root, {}) + @menu = menu + @menu_items = items[menu] + end + + @@last_items_count = Hash.new {|h,k| h[k] = 0} + + # Adds an item at the end of the menu. Available options: + # * param: the parameter name that is used for the project id (default is :id) + # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true + # * caption that can be: + # * a localized string Symbol + # * a String + # * a Proc that can take the project as argument + # * before, after: specify where the menu item should be inserted (eg. :after => :activity) + # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues) + # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item. + # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] } + # * last: menu item will stay at the end (eg. :last => true) + # * html_options: a hash of html options that are passed to link_to + def push(name, url, options={}) + options = options.dup + + if options[:parent] + subtree = self.find(options[:parent]) + if subtree + target_root = subtree + else + target_root = @menu_items.root + end + + else + target_root = @menu_items.root + end + + # menu item position + if first = options.delete(:first) + target_root.prepend(MenuItem.new(name, url, options)) + elsif before = options.delete(:before) + + if exists?(before) + target_root.add_at(MenuItem.new(name, url, options), position_of(before)) + else + target_root.add(MenuItem.new(name, url, options)) + end + + elsif after = options.delete(:after) + + if exists?(after) + target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1) + else + target_root.add(MenuItem.new(name, url, options)) + end + + elsif options[:last] # don't delete, needs to be stored + target_root.add_last(MenuItem.new(name, url, options)) + else + target_root.add(MenuItem.new(name, url, options)) + end + end + + # Removes a menu item + def delete(name) + if found = self.find(name) + @menu_items.remove!(found) + end + end + + # Checks if a menu item exists + def exists?(name) + @menu_items.any? {|node| node.name == name} + end + + def find(name) + @menu_items.find {|node| node.name == name} + end + + def position_of(name) + @menu_items.each do |node| + if node.name == name + return node.position + end + end + end + end + + class MenuItem < Tree::TreeNode + include Redmine::I18n + attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last + + def initialize(name, url, options) + raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) + raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash) + raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym + raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call) + @name = name + @url = url + @condition = options[:if] + @param = options[:param] || :id + @caption = options[:caption] + @html_options = options[:html] || {} + # Adds a unique class to each menu item based on its name + @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') + @parent = options[:parent] + @child_menus = options[:children] + @last = options[:last] || false + super @name.to_sym + end + + def caption(project=nil) + if @caption.is_a?(Proc) + c = @caption.call(project).to_s + c = @name.to_s.humanize if c.blank? + c + else + if @caption.nil? + l_or_humanize(name, :prefix => 'label_') + else + @caption.is_a?(Symbol) ? l(@caption) : @caption + end + end + end + + def html_options(options={}) + if options[:selected] + o = @html_options.dup + o[:class] += ' selected' + o + else + @html_options + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/595569d84d22df6ad4296b4d377f37df66d05fc6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/595569d84d22df6ad4296b4d377f37df66d05fc6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,298 @@ +# -*- coding: utf-8 -*- +require File.expand_path('../../test_helper', __FILE__) + +class TimeEntryReportsControllerTest < ActionController::TestCase + fixtures :projects, :enabled_modules, :roles, :members, :member_roles, + :issues, :time_entries, :users, :trackers, :enumerations, + :issue_statuses, :custom_fields, :custom_values + + include Redmine::I18n + + def setup + Setting.default_language = "en" + end + + def test_report_at_project_level + get :report, :project_id => 'ecookbook' + assert_response :success + assert_template 'report' + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries/report", :id => 'query_form'} + end + + def test_report_all_projects + get :report + assert_response :success + assert_template 'report' + assert_tag :form, + :attributes => {:action => "/time_entries/report", :id => 'query_form'} + end + + def test_report_all_projects_denied + r = Role.anonymous + r.permissions.delete(:view_time_entries) + r.permissions_will_change! + r.save + get :report + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport' + end + + def test_report_all_projects_one_criteria + get :report, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project'] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "8.65", "%.2f" % assigns(:total_hours) + end + + def test_report_all_time + get :report, :project_id => 1, :criterias => ['project', 'issue'] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "162.90", "%.2f" % assigns(:total_hours) + end + + def test_report_all_time_by_day + get :report, :project_id => 1, :criterias => ['project', 'issue'], :columns => 'day' + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "162.90", "%.2f" % assigns(:total_hours) + assert_tag :tag => 'th', :content => '2007-03-12' + end + + def test_report_one_criteria + get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project'] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "8.65", "%.2f" % assigns(:total_hours) + end + + def test_report_two_criterias + get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "162.90", "%.2f" % assigns(:total_hours) + end + + def test_report_one_day + get :report, :project_id => 1, :columns => 'day', :from => "2007-03-23", :to => "2007-03-23", :criterias => ["member", "activity"] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "4.25", "%.2f" % assigns(:total_hours) + end + + def test_report_at_issue_level + get :report, :project_id => 1, :issue_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "154.25", "%.2f" % assigns(:total_hours) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/issues/1/time_entries/report", :id => 'query_form'} + end + + def test_report_custom_field_criteria + get :report, :project_id => 1, :criterias => ['project', 'cf_1', 'cf_7'] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_not_nil assigns(:criterias) + assert_equal 3, assigns(:criterias).size + assert_equal "162.90", "%.2f" % assigns(:total_hours) + # Custom field column + assert_tag :tag => 'th', :content => 'Database' + # Custom field row + assert_tag :tag => 'td', :content => 'MySQL', + :sibling => { :tag => 'td', :attributes => { :class => 'hours' }, + :child => { :tag => 'span', :attributes => { :class => 'hours hours-int' }, + :content => '1' }} + # Second custom field column + assert_tag :tag => 'th', :content => 'Billable' + end + + def test_report_one_criteria_no_result + get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criterias => ['project'] + assert_response :success + assert_template 'report' + assert_not_nil assigns(:total_hours) + assert_equal "0.00", "%.2f" % assigns(:total_hours) + end + + def test_report_all_projects_csv_export + get :report, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", + :criterias => ["project", "member", "activity"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', + lines.first + # Total row + assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last + end + + def test_report_csv_export + get :report, :project_id => 1, :columns => 'month', + :from => "2007-01-01", :to => "2007-06-30", + :criterias => ["project", "member", "activity"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', + lines.first + # Total row + assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last + end + + def test_csv_big_5 + Setting.default_language = "zh-TW" + str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88" + str_big5 = "\xa4@\xa4\xeb" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + str_big5.force_encoding('Big5') + end + user = User.find_by_id(3) + user.firstname = str_utf8 + user.lastname = "test-lastname" + assert user.save + comments = "test_csv_big_5" + te1 = TimeEntry.create(:spent_on => '2011-11-11', + :hours => 7.3, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => comments) + + te2 = TimeEntry.find_by_comments(comments) + assert_not_nil te2 + assert_equal 7.3, te2.hours + assert_equal 3, te2.user_id + + get :report, :project_id => 1, :columns => 'day', + :from => "2011-11-11", :to => "2011-11-11", + :criterias => ["member"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + s1 = "\xa6\xa8\xad\xfb,2011-11-11,\xc1`\xadp" + s2 = "\xc1`\xadp" + if s1.respond_to?(:force_encoding) + s1.force_encoding('Big5') + s2.force_encoding('Big5') + end + assert_equal s1, lines.first + # Total row + assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1] + assert_equal "#{s2},7.30,7.30", lines[2] + + str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)" + if str_tw.respond_to?(:force_encoding) + str_tw.force_encoding('UTF-8') + end + assert_equal str_tw, l(:general_lang_name) + assert_equal 'Big5', l(:general_csv_encoding) + assert_equal ',', l(:general_csv_separator) + assert_equal '.', l(:general_csv_decimal_separator) + end + + def test_csv_cannot_convert_should_be_replaced_big_5 + Setting.default_language = "zh-TW" + str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + end + user = User.find_by_id(3) + user.firstname = str_utf8 + user.lastname = "test-lastname" + assert user.save + comments = "test_replaced" + te1 = TimeEntry.create(:spent_on => '2011-11-11', + :hours => 7.3, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => comments) + + te2 = TimeEntry.find_by_comments(comments) + assert_not_nil te2 + assert_equal 7.3, te2.hours + assert_equal 3, te2.user_id + + get :report, :project_id => 1, :columns => 'day', + :from => "2011-11-11", :to => "2011-11-11", + :criterias => ["member"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + s1 = "\xa6\xa8\xad\xfb,2011-11-11,\xc1`\xadp" + if s1.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert_equal s1, lines.first + # Total row + s2 = "" + if s2.respond_to?(:force_encoding) + s2 = "\xa5H?" + s2.force_encoding('Big5') + elsif RUBY_PLATFORM == 'java' + s2 = "??" + else + s2 = "\xa5H???" + end + assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1] + end + + def test_csv_fr + with_settings :default_language => "fr" do + str1 = "test_csv_fr" + user = User.find_by_id(3) + te1 = TimeEntry.create(:spent_on => '2011-11-11', + :hours => 7.3, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => str1) + + te2 = TimeEntry.find_by_comments(str1) + assert_not_nil te2 + assert_equal 7.3, te2.hours + assert_equal 3, te2.user_id + + get :report, :project_id => 1, :columns => 'day', + :from => "2011-11-11", :to => "2011-11-11", + :criterias => ["member"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + s1 = "Membre;2011-11-11;Total" + s2 = "Total" + if s1.respond_to?(:force_encoding) + s1.force_encoding('ISO-8859-1') + s2.force_encoding('ISO-8859-1') + end + assert_equal s1, lines.first + # Total row + assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1] + assert_equal "#{s2};7,30;7,30", lines[2] + + str_fr = "Fran\xc3\xa7ais" + if str_fr.respond_to?(:force_encoding) + str_fr.force_encoding('UTF-8') + end + assert_equal str_fr, l(:general_lang_name) + assert_equal 'ISO-8859-1', l(:general_csv_encoding) + assert_equal ';', l(:general_csv_separator) + assert_equal ',', l(:general_csv_decimal_separator) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/596c198f119f4338d149538588dba74545c206cb.svn-base Binary file .svn/pristine/59/596c198f119f4338d149538588dba74545c206cb.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/596c4ee05a418a7e56adf127a2d9eee293893855.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/596c4ee05a418a7e56adf127a2d9eee293893855.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +<%= l(:mail_body_wiki_content_added, :id => h(@wiki_content.page.pretty_title), + :author => h(@wiki_content.author)) %> +<%= @wiki_content.comments %> + +<%= @wiki_content_url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/59aca64abbe8279f6a8e6795b265ac2c66a49a15.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/59aca64abbe8279f6a8e6795b265ac2c66a49a15.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1005 @@ +th: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + precision: 1 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "ไม่อยู่ในรายการ" + exclusion: "ถูกสงวนไว้" + invalid: "ไม่ถูกต้อง" + confirmation: "พิมพ์ไม่เหมือนเดิม" + accepted: "ต้องยอมรับ" + empty: "ต้องเติม" + blank: "ต้องเติม" + too_long: "ยาวเกินไป" + too_short: "สั้นเกินไป" + wrong_length: "ความยาวไม่ถูกต้อง" + taken: "ถูกใช้ไปแล้ว" + not_a_number: "ไม่ใช่ตัวเลข" + not_a_date: "ไม่ใช่วันที่ ที่ถูกต้อง" + greater_than: "must be greater than %{count}" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "ต้องมากกว่าวันเริ่ม" + not_same_project: "ไม่ได้อยู่ในโครงการเดียวกัน" + circular_dependency: "ความสัมพันธ์อ้างอิงเป็นวงกลม" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: กรุณาเลือก + + general_text_No: 'ไม่' + general_text_Yes: 'ใช่' + general_text_no: 'ไม่' + general_text_yes: 'ใช่' + general_lang_name: 'Thai (ไทย)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: Windows-874 + general_pdf_encoding: cp874 + general_first_day_of_week: '1' + + notice_account_updated: บัญชีได้ถูกปรับปรุงแล้ว. + notice_account_invalid_creditentials: ชื้ผู้ใช้หรือรหัสผ่านไม่ถูกต้อง + notice_account_password_updated: รหัสได้ถูกปรับปรุงแล้ว. + notice_account_wrong_password: รหัสผ่านไม่ถูกต้อง + notice_account_register_done: บัญชีถูกสร้างแล้ว. กรุณาเช็คเมล์ แล้วคลิ๊กที่ลิงค์ในอีเมล์เพื่อเปิดใช้บัญชี + notice_account_unknown_email: ไม่มีผู้ใช้ที่ใช้อีเมล์นี้. + notice_can_t_change_password: บัญชีนี้ใช้การยืนยันตัวตนจากแหล่งภายนอก. ไม่สามารถปลี่ยนรหัสผ่านได้. + notice_account_lost_email_sent: เราได้ส่งอีเมล์พร้อมวิธีการสร้างรหัีสผ่านใหม่ให้คุณแล้ว กรุณาเช็คเมล์. + notice_account_activated: บัญชีของคุณได้เปิดใช้แล้ว. ตอนนี้คุณสามารถเข้าสู่ระบบได้แล้ว. + notice_successful_create: สร้างเสร็จแล้ว. + notice_successful_update: ปรับปรุงเสร็จแล้ว. + notice_successful_delete: ลบเสร็จแล้ว. + notice_successful_connection: ติดต่อสำเร็จแล้ว. + notice_file_not_found: หน้าที่คุณต้องการดูไม่มีอยู่จริง หรือถูกลบไปแล้ว. + notice_locking_conflict: ข้อมูลถูกปรับปรุงโดยผู้ใช้คนอื่น. + notice_not_authorized: คุณไม่มีสิทธิเข้าถึงหน้านี้. + notice_email_sent: "อีเมล์ได้ถูกส่งถึง %{value}" + notice_email_error: "เกิดความผิดพลาดขณะกำส่งอีเมล์ (%{value})" + notice_feeds_access_key_reseted: RSS access key ของคุณถูก reset แล้ว. + notice_failed_to_save_issues: "%{count} ปัญหาจาก %{total} ปัญหาที่ถูกเลือกไม่สามารถจัดเก็บ: %{ids}." + notice_no_issue_selected: "ไม่มีปัญหาที่ถูกเลือก! กรุณาเลือกปัญหาที่คุณต้องการแก้ไข." + notice_account_pending: "บัญชีของคุณสร้างเสร็จแล้ว ขณะนี้รอการอนุมัติจากผู้บริหารจัดการ." + notice_default_data_loaded: ค่าเริ่มต้นโหลดเสร็จแล้ว. + + error_can_t_load_default_data: "ค่าเริ่มต้นโหลดไม่สำเร็จ: %{value}" + error_scm_not_found: "ไม่พบรุ่นที่ต้องการในแหล่งเก็บต้นฉบับ." + error_scm_command_failed: "เกิดความผิดพลาดในการเข้าถึงแหล่งเก็บต้นฉบับ: %{value}" + error_scm_annotate: "entry ไม่มีอยู่จริง หรือไม่สามารถเขียนหมายเหตุประกอบ." + error_issue_not_found_in_project: 'ไม่พบปัญหานี้ หรือปัญหาไม่ได้อยู่ในโครงการนี้' + + mail_subject_lost_password: "รหัสผ่าน %{value} ของคุณ" + mail_body_lost_password: 'คลิ๊กที่ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่าน:' + mail_subject_register: "เปิดบัญชี %{value} ของคุณ" + mail_body_register: 'คลิ๊กที่ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่าน:' + mail_body_account_information_external: "คุณสามารถใช้บัญชี %{value} เพื่อเข้าสู่ระบบ." + mail_body_account_information: ข้อมูลบัญชีของคุณ + mail_subject_account_activation_request: "กรุณาเปิดบัญชี %{value}" + mail_body_account_activation_request: "ผู้ใช้ใหม่ (%{value}) ได้ลงทะเบียน. บัญชีของเขากำลังรออนุมัติ:" + + gui_validation_error: 1 ข้อผิดพลาด + gui_validation_error_plural: "%{count} ข้อผิดพลาด" + + field_name: ชื่อ + field_description: รายละเอียด + field_summary: สรุปย่อ + field_is_required: ต้องใส่ + field_firstname: ชื่อ + field_lastname: นามสกุล + field_mail: อีเมล์ + field_filename: แฟ้ม + field_filesize: ขนาด + field_downloads: ดาวน์โหลด + field_author: ผู้แต่ง + field_created_on: สร้าง + field_updated_on: ปรับปรุง + field_field_format: รูปแบบ + field_is_for_all: สำหรับทุกโครงการ + field_possible_values: ค่าที่เป็นไปได้ + field_regexp: Regular expression + field_min_length: สั้นสุด + field_max_length: ยาวสุด + field_value: ค่า + field_category: ประเภท + field_title: ชื่อเรื่อง + field_project: โครงการ + field_issue: ปัญหา + field_status: สถานะ + field_notes: บันทึก + field_is_closed: ปัญหาจบ + field_is_default: ค่าเริ่มต้น + field_tracker: การติดตาม + field_subject: เรื่อง + field_due_date: วันครบกำหนด + field_assigned_to: มอบหมายให้ + field_priority: ความสำคัญ + field_fixed_version: รุ่น + field_user: ผู้ใช้ + field_role: บทบาท + field_homepage: หน้าแรก + field_is_public: สาธารณะ + field_parent: โครงการย่อยของ + field_is_in_roadmap: ปัญหาแสดงใน แผนงาน + field_login: ชื่อที่ใช้เข้าระบบ + field_mail_notification: การแจ้งเตือนทางอีเมล์ + field_admin: ผู้บริหารจัดการ + field_last_login_on: เข้าระบบครั้งสุดท้าย + field_language: ภาษา + field_effective_date: วันที่ + field_password: รหัสผ่าน + field_new_password: รหัสผ่านใหม่ + field_password_confirmation: ยืนยันรหัสผ่าน + field_version: รุ่น + field_type: ชนิด + field_host: โฮสต์ + field_port: พอร์ต + field_account: บัญชี + field_base_dn: Base DN + field_attr_login: เข้าระบบ attribute + field_attr_firstname: ชื่อ attribute + field_attr_lastname: นามสกุล attribute + field_attr_mail: อีเมล์ attribute + field_onthefly: สร้างผู้ใช้ทันที + field_start_date: เริ่ม + field_done_ratio: "% สำเร็จ" + field_auth_source: วิธีการยืนยันตัวตน + field_hide_mail: ซ่อนอีเมล์ของฉัน + field_comments: ความเห็น + field_url: URL + field_start_page: หน้าเริ่มต้น + field_subproject: โครงการย่อย + field_hours: ชั่วโมง + field_activity: กิจกรรม + field_spent_on: วันที่ + field_identifier: ชื่อเฉพาะ + field_is_filter: ใช้เป็นตัวกรอง + field_issue_to: ปัญหาที่เกี่ยวข้อง + field_delay: เลื่อน + field_assignable: ปัญหาสามารถมอบหมายให้คนที่ทำบทบาทนี้ + field_redirect_existing_links: ย้ายจุดเชื่อมโยงนี้ + field_estimated_hours: เวลาที่ใช้โดยประมาณ + field_column_names: สดมภ์ + field_time_zone: ย่านเวลา + field_searchable: ค้นหาได้ + field_default_value: ค่าเริ่มต้น + field_comments_sorting: แสดงความเห็น + + setting_app_title: ชื่อโปรแกรม + setting_app_subtitle: ชื่อโปรแกรมรอง + setting_welcome_text: ข้อความต้อนรับ + setting_default_language: ภาษาเริ่มต้น + setting_login_required: ต้องป้อนผู้ใช้-รหัสผ่าน + setting_self_registration: ลงทะเบียนด้วยตนเอง + setting_attachment_max_size: ขนาดแฟ้มแนบสูงสุด + setting_issues_export_limit: การส่งออกปัญหาสูงสุด + setting_mail_from: อีเมล์ที่ใช้ส่ง + setting_bcc_recipients: ไม่ระบุชื่อผู้รับ (bcc) + setting_host_name: ชื่อโฮสต์ + setting_text_formatting: การจัดรูปแบบข้อความ + setting_wiki_compression: บีบอัดประวัติ Wiki + setting_feeds_limit: จำนวน Feed + setting_default_projects_public: โครงการใหม่มีค่าเริ่มต้นเป็น สาธารณะ + setting_autofetch_changesets: ดึง commits อัตโนมัติ + setting_sys_api_enabled: เปิดใช้ WS สำหรับการจัดการที่เก็บต้นฉบับ + setting_commit_ref_keywords: คำสำคัญ Referencing + setting_commit_fix_keywords: คำสำคัญ Fixing + setting_autologin: เข้าระบบอัตโนมัติ + setting_date_format: รูปแบบวันที่ + setting_time_format: รูปแบบเวลา + setting_cross_project_issue_relations: อนุญาตให้ระบุปัญหาข้ามโครงการ + setting_issue_list_default_columns: สดมภ์เริ่มต้นแสดงในรายการปัญหา + setting_emails_footer: คำลงท้ายอีเมล์ + setting_protocol: Protocol + setting_per_page_options: ตัวเลือกจำนวนต่อหน้า + setting_user_format: รูปแบบการแสดงชื่อผู้ใช้ + setting_activity_days_default: จำนวนวันที่แสดงในกิจกรรมของโครงการ + setting_display_subprojects_issues: แสดงปัญหาของโครงการย่อยในโครงการหลัก + + project_module_issue_tracking: การติดตามปัญหา + project_module_time_tracking: การใช้เวลา + project_module_news: ข่าว + project_module_documents: เอกสาร + project_module_files: แฟ้ม + project_module_wiki: Wiki + project_module_repository: ที่เก็บต้นฉบับ + project_module_boards: กระดานข้อความ + + label_user: ผู้ใช้ + label_user_plural: ผู้ใช้ + label_user_new: ผู้ใช้ใหม่ + label_project: โครงการ + label_project_new: โครงการใหม่ + label_project_plural: โครงการ + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: โครงการทั้งหมด + label_project_latest: โครงการล่าสุด + label_issue: ปัญหา + label_issue_new: ปัญหาใหม่ + label_issue_plural: ปัญหา + label_issue_view_all: ดูปัญหาทั้งหมด + label_issues_by: "ปัญหาโดย %{value}" + label_issue_added: ปัญหาถูกเพิ่ม + label_issue_updated: ปัญหาถูกปรับปรุง + label_document: เอกสาร + label_document_new: เอกสารใหม่ + label_document_plural: เอกสาร + label_document_added: เอกสารถูกเพิ่ม + label_role: บทบาท + label_role_plural: บทบาท + label_role_new: บทบาทใหม่ + label_role_and_permissions: บทบาทและสิทธิ + label_member: สมาชิก + label_member_new: สมาชิกใหม่ + label_member_plural: สมาชิก + label_tracker: การติดตาม + label_tracker_plural: การติดตาม + label_tracker_new: การติดตามใหม่ + label_workflow: ลำดับงาน + label_issue_status: สถานะของปัญหา + label_issue_status_plural: สถานะของปัญหา + label_issue_status_new: สถานะใหม + label_issue_category: ประเภทของปัญหา + label_issue_category_plural: ประเภทของปัญหา + label_issue_category_new: ประเภทใหม่ + label_custom_field: เขตข้อมูลแบบระบุเอง + label_custom_field_plural: เขตข้อมูลแบบระบุเอง + label_custom_field_new: สร้างเขตข้อมูลแบบระบุเอง + label_enumerations: รายการ + label_enumeration_new: สร้างใหม่ + label_information: ข้อมูล + label_information_plural: ข้อมูล + label_please_login: กรุณาเข้าระบบก่อน + label_register: ลงทะเบียน + label_password_lost: ลืมรหัสผ่าน + label_home: หน้าแรก + label_my_page: หน้าของฉัน + label_my_account: บัญชีของฉัน + label_my_projects: โครงการของฉัน + label_administration: บริหารจัดการ + label_login: เข้าระบบ + label_logout: ออกระบบ + label_help: ช่วยเหลือ + label_reported_issues: ปัญหาที่แจ้งไว้ + label_assigned_to_me_issues: ปัญหาที่มอบหมายให้ฉัน + label_last_login: ติดต่อครั้งสุดท้าย + label_registered_on: ลงทะเบียนเมื่อ + label_activity: กิจกรรม + label_activity_plural: กิจกรรม + label_activity_latest: กิจกรรมล่าสุด + label_overall_activity: กิจกรรมโดยรวม + label_new: ใหม่ + label_logged_as: เข้าระบบในชื่อ + label_environment: สภาพแวดล้อม + label_authentication: การยืนยันตัวตน + label_auth_source: วิธีการการยืนยันตัวตน + label_auth_source_new: สร้างวิธีการยืนยันตัวตนใหม่ + label_auth_source_plural: วิธีการ Authentication + label_subproject_plural: โครงการย่อย + label_min_max_length: สั้น-ยาว สุดที่ + label_list: รายการ + label_date: วันที่ + label_integer: จำนวนเต็ม + label_float: จำนวนจริง + label_boolean: ถูกผิด + label_string: ข้อความ + label_text: ข้อความขนาดยาว + label_attribute: คุณลักษณะ + label_attribute_plural: คุณลักษณะ + label_download: "%{count} ดาวน์โหลด" + label_download_plural: "%{count} ดาวน์โหลด" + label_no_data: จำนวนข้อมูลที่แสดง + label_change_status: เปลี่ยนสถานะ + label_history: ประวัติ + label_attachment: แฟ้ม + label_attachment_new: แฟ้มใหม่ + label_attachment_delete: ลบแฟ้ม + label_attachment_plural: แฟ้ม + label_file_added: แฟ้มถูกเพิ่ม + label_report: รายงาน + label_report_plural: รายงาน + label_news: ข่าว + label_news_new: เพิ่มข่าว + label_news_plural: ข่าว + label_news_latest: ข่าวล่าสุด + label_news_view_all: ดูข่าวทั้งหมด + label_news_added: ข่าวถูกเพิ่ม + label_settings: ปรับแต่ง + label_overview: ภาพรวม + label_version: รุ่น + label_version_new: รุ่นใหม่ + label_version_plural: รุ่น + label_confirmation: ยืนยัน + label_export_to: 'รูปแบบอื่นๆ :' + label_read: อ่าน... + label_public_projects: โครงการสาธารณะ + label_open_issues: เปิด + label_open_issues_plural: เปิด + label_closed_issues: ปิด + label_closed_issues_plural: ปิด + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: จำนวนรวม + label_permissions: สิทธิ + label_current_status: สถานะปัจจุบัน + label_new_statuses_allowed: อนุญาตให้มีสถานะใหม่ + label_all: ทั้งหมด + label_none: ไม่มี + label_nobody: ไม่มีใคร + label_next: ต่อไป + label_previous: ก่อนหน้า + label_used_by: ถูกใช้โดย + label_details: รายละเอียด + label_add_note: เพิ่มบันทึก + label_per_page: ต่อหน้า + label_calendar: ปฏิทิน + label_months_from: เดือนจาก + label_gantt: Gantt + label_internal: ภายใน + label_last_changes: "last %{count} เปลี่ยนแปลง" + label_change_view_all: ดูการเปลี่ยนแปลงทั้งหมด + label_personalize_page: ปรับแต่งหน้านี้ + label_comment: ความเห็น + label_comment_plural: ความเห็น + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: เพิ่มความเห็น + label_comment_added: ความเห็นถูกเพิ่ม + label_comment_delete: ลบความเห็น + label_query: แบบสอบถามแบบกำหนดเอง + label_query_plural: แบบสอบถามแบบกำหนดเอง + label_query_new: แบบสอบถามใหม่ + label_filter_add: เพิ่มตัวกรอง + label_filter_plural: ตัวกรอง + label_equals: คือ + label_not_equals: ไม่ใช่ + label_in_less_than: น้อยกว่า + label_in_more_than: มากกว่า + label_in: ในช่วง + label_today: วันนี้ + label_all_time: ตลอดเวลา + label_yesterday: เมื่อวาน + label_this_week: อาทิตย์นี้ + label_last_week: อาทิตย์ที่แล้ว + label_last_n_days: "%{count} วันย้อนหลัง" + label_this_month: เดือนนี้ + label_last_month: เดือนที่แล้ว + label_this_year: ปีนี้ + label_date_range: ช่วงวันที่ + label_less_than_ago: น้อยกว่าหนึ่งวัน + label_more_than_ago: มากกว่าหนึ่งวัน + label_ago: วันผ่านมาแล้ว + label_contains: มี... + label_not_contains: ไม่มี... + label_day_plural: วัน + label_repository: ที่เก็บต้นฉบับ + label_repository_plural: ที่เก็บต้นฉบับ + label_browse: เปิดหา + label_modification: "%{count} เปลี่ยนแปลง" + label_modification_plural: "%{count} เปลี่ยนแปลง" + label_revision: การแก้ไข + label_revision_plural: การแก้ไข + label_associated_revisions: การแก้ไขที่เกี่ยวข้อง + label_added: ถูกเพิ่ม + label_modified: ถูกแก้ไข + label_deleted: ถูกลบ + label_latest_revision: รุ่นการแก้ไขล่าสุด + label_latest_revision_plural: รุ่นการแก้ไขล่าสุด + label_view_revisions: ดูการแก้ไข + label_max_size: ขนาดใหญ่สุด + label_sort_highest: ย้ายไปบนสุด + label_sort_higher: ย้ายขึ้น + label_sort_lower: ย้ายลง + label_sort_lowest: ย้ายไปล่างสุด + label_roadmap: แผนงาน + label_roadmap_due_in: "ถึงกำหนดใน %{value}" + label_roadmap_overdue: "%{value} ช้ากว่ากำหนด" + label_roadmap_no_issues: ไม่มีปัญหาสำหรับรุ่นนี้ + label_search: ค้นหา + label_result_plural: ผลการค้นหา + label_all_words: ทุกคำ + label_wiki: Wiki + label_wiki_edit: แก้ไข Wiki + label_wiki_edit_plural: แก้ไข Wiki + label_wiki_page: หน้า Wiki + label_wiki_page_plural: หน้า Wiki + label_index_by_title: เรียงตามชื่อเรื่อง + label_index_by_date: เรียงตามวัน + label_current_version: รุ่นปัจจุบัน + label_preview: ตัวอย่างก่อนจัดเก็บ + label_feed_plural: Feeds + label_changes_details: รายละเอียดการเปลี่ยนแปลงทั้งหมด + label_issue_tracking: ติดตามปัญหา + label_spent_time: เวลาที่ใช้ + label_f_hour: "%{value} ชั่วโมง" + label_f_hour_plural: "%{value} ชั่วโมง" + label_time_tracking: ติดตามการใช้เวลา + label_change_plural: เปลี่ยนแปลง + label_statistics: สถิติ + label_commits_per_month: Commits ต่อเดือน + label_commits_per_author: Commits ต่อผู้แต่ง + label_view_diff: ดูความแตกต่าง + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: ตัวเลือก + label_copy_workflow_from: คัดลอกลำดับงานจาก + label_permissions_report: รายงานสิทธิ + label_watched_issues: เฝ้าดูปัญหา + label_related_issues: ปัญหาที่เกี่ยวข้อง + label_applied_status: จัดเก็บสถานะ + label_loading: กำลังโหลด... + label_relation_new: ความสัมพันธ์ใหม่ + label_relation_delete: ลบความสัมพันธ์ + label_relates_to: สัมพันธ์กับ + label_duplicates: ซ้ำ + label_blocks: กีดกัน + label_blocked_by: กีดกันโดย + label_precedes: นำหน้า + label_follows: ตามหลัง + label_end_to_start: จบ-เริ่ม + label_end_to_end: จบ-จบ + label_start_to_start: เริ่ม-เริ่ม + label_start_to_end: เริ่ม-จบ + label_stay_logged_in: อยู่ในระบบต่อ + label_disabled: ไม่ใช้งาน + label_show_completed_versions: แสดงรุ่นที่สมบูรณ์ + label_me: ฉัน + label_board: สภากาแฟ + label_board_new: สร้างสภากาแฟ + label_board_plural: สภากาแฟ + label_topic_plural: หัวข้อ + label_message_plural: ข้อความ + label_message_last: ข้อความล่าสุด + label_message_new: เขียนข้อความใหม่ + label_message_posted: ข้อความถูกเพิ่มแล้ว + label_reply_plural: ตอบกลับ + label_send_information: ส่งรายละเอียดของบัญชีให้ผู้ใช้ + label_year: ปี + label_month: เดือน + label_week: สัปดาห์ + label_date_from: จาก + label_date_to: ถึง + label_language_based: ขึ้นอยู่กับภาษาของผู้ใช้ + label_sort_by: "เรียงโดย %{value}" + label_send_test_email: ส่งจดหมายทดสอบ + label_feeds_access_key_created_on: "RSS access key สร้างเมื่อ %{value} ที่ผ่านมา" + label_module_plural: ส่วนประกอบ + label_added_time_by: "เพิ่มโดย %{author} %{age} ที่ผ่านมา" + label_updated_time: "ปรับปรุง %{value} ที่ผ่านมา" + label_jump_to_a_project: ไปที่โครงการ... + label_file_plural: แฟ้ม + label_changeset_plural: กลุ่มการเปลี่ยนแปลง + label_default_columns: สดมภ์เริ่มต้น + label_no_change_option: (ไม่เปลี่ยนแปลง) + label_bulk_edit_selected_issues: แก้ไขปัญหาที่เลือกทั้งหมด + label_theme: ชุดรูปแบบ + label_default: ค่าเริ่มต้น + label_search_titles_only: ค้นหาจากชื่อเรื่องเท่านั้น + label_user_mail_option_all: "ทุกๆ เหตุการณ์ในโครงการของฉัน" + label_user_mail_option_selected: "ทุกๆ เหตุการณ์ในโครงการที่เลือก..." + label_user_mail_no_self_notified: "ฉันไม่ต้องการได้รับการแจ้งเตือนในสิ่งที่ฉันทำเอง" + label_registration_activation_by_email: เปิดบัญชีผ่านอีเมล์ + label_registration_manual_activation: อนุมัติโดยผู้บริหารจัดการ + label_registration_automatic_activation: เปิดบัญชีอัตโนมัติ + label_display_per_page: "ต่อหน้า: %{value}" + label_age: อายุ + label_change_properties: เปลี่ยนคุณสมบัติ + label_general: ทั่วๆ ไป + label_more: อื่น ๆ + label_scm: ตัวจัดการต้นฉบับ + label_plugins: ส่วนเสริม + label_ldap_authentication: การยืนยันตัวตนโดยใช้ LDAP + label_downloads_abbr: D/L + label_optional_description: รายละเอียดเพิ่มเติม + label_add_another_file: เพิ่มแฟ้มอื่นๆ + label_preferences: ค่าที่ชอบใจ + label_chronological_order: เรียงจากเก่าไปใหม่ + label_reverse_chronological_order: เรียงจากใหม่ไปเก่า + label_planning: การวางแผน + + button_login: เข้าระบบ + button_submit: จัดส่งข้อมูล + button_save: จัดเก็บ + button_check_all: เลือกทั้งหมด + button_uncheck_all: ไม่เลือกทั้งหมด + button_delete: ลบ + button_create: สร้าง + button_test: ทดสอบ + button_edit: แก้ไข + button_add: เพิ่ม + button_change: เปลี่ยนแปลง + button_apply: ประยุกต์ใช้ + button_clear: ล้างข้อความ + button_lock: ล็อค + button_unlock: ยกเลิกการล็อค + button_download: ดาวน์โหลด + button_list: รายการ + button_view: มุมมอง + button_move: ย้าย + button_back: กลับ + button_cancel: ยกเลิก + button_activate: เปิดใช้ + button_sort: จัดเรียง + button_log_time: บันทึกเวลา + button_rollback: ถอยกลับมาที่รุ่นนี้ + button_watch: เฝ้าดู + button_unwatch: เลิกเฝ้าดู + button_reply: ตอบกลับ + button_archive: เก็บเข้าโกดัง + button_unarchive: เอาออกจากโกดัง + button_reset: เริ่มใหมท + button_rename: เปลี่ยนชื่อ + button_change_password: เปลี่ยนรหัสผ่าน + button_copy: คัดลอก + button_annotate: หมายเหตุประกอบ + button_update: ปรับปรุง + button_configure: ปรับแต่ง + + status_active: เปิดใช้งานแล้ว + status_registered: รอการอนุมัติ + status_locked: ล็อค + + text_select_mail_notifications: เลือกการกระทำที่ต้องการให้ส่งอีเมล์แจ้ง. + text_regexp_info: ตัวอย่าง ^[A-Z0-9]+$ + text_min_max_length_info: 0 หมายถึงไม่จำกัด + text_project_destroy_confirmation: คุณแน่ใจไหมว่าต้องการลบโครงการและข้อมูลที่เกี่ยวข้่อง ? + text_subprojects_destroy_warning: "โครงการย่อย: %{value} จะถูกลบด้วย." + text_workflow_edit: เลือกบทบาทและการติดตาม เพื่อแก้ไขลำดับงาน + text_are_you_sure: คุณแน่ใจไหม ? + text_tip_issue_begin_day: งานที่เริ่มวันนี้ + text_tip_issue_end_day: งานที่จบวันนี้ + text_tip_issue_begin_end_day: งานที่เริ่มและจบวันนี้ + text_project_identifier_info: 'ภาษาอังกฤษตัวเล็ก(a-z), ตัวเลข(0-9) และขีด (-) เท่านั้น.
    เมื่อจัดเก็บแล้ว, ชื่อเฉพาะไม่สามารถเปลี่ยนแปลงได้' + text_caracters_maximum: "สูงสุด %{count} ตัวอักษร." + text_caracters_minimum: "ต้องยาวอย่างน้อย %{count} ตัวอักษร." + text_length_between: "ความยาวระหว่าง %{min} ถึง %{max} ตัวอักษร." + text_tracker_no_workflow: ไม่ได้บัญญัติลำดับงานสำหรับการติดตามนี้ + text_unallowed_characters: ตัวอักษรต้องห้าม + text_comma_separated: ใส่ได้หลายค่า โดยคั่นด้วยลูกน้ำ( ,). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "ปัญหา %{id} ถูกแจ้งโดย %{author}." + text_issue_updated: "ปัญหา %{id} ถูกปรับปรุงโดย %{author}." + text_wiki_destroy_confirmation: คุณแน่ใจหรือว่าต้องการลบ wiki นี้พร้อมทั้งเนี้อหา? + text_issue_category_destroy_question: "บางปัญหา (%{count}) อยู่ในประเภทนี้. คุณต้องการทำอย่างไร ?" + text_issue_category_destroy_assignments: ลบประเภทนี้ + text_issue_category_reassign_to: ระบุปัญหาในประเภทนี้ + text_user_mail_option: "ในโครงการที่ไม่ได้เลือก, คุณจะได้รับการแจ้งเกี่ยวกับสิ่งที่คุณเฝ้าดูหรือมีส่วนเกี่ยวข้อง (เช่นปัญหาที่คุณแจ้งไว้หรือได้รับมอบหมาย)." + text_no_configuration_data: "บทบาท, การติดตาม, สถานะปัญหา และลำดับงานยังไม่ได้ถูกตั้งค่า.\nขอแนะนำให้โหลดค่าเริ่มต้น. คุณสามารถแก้ไขค่าได้หลังจากโหลดแล้ว." + text_load_default_configuration: โหลดค่าเริ่มต้น + text_status_changed_by_changeset: "ประยุกต์ใช้ในกลุ่มการเปลี่ยนแปลง %{value}." + text_issues_destroy_confirmation: 'คุณแน่ใจไหมว่าต้องการลบปัญหา(ทั้งหลาย)ที่เลือกไว้?' + text_select_project_modules: 'เลือกส่วนประกอบที่ต้องการใช้งานสำหรับโครงการนี้:' + text_default_administrator_account_changed: ค่าเริ่มต้นของบัญชีผู้บริหารจัดการถูกเปลี่ยนแปลง + text_file_repository_writable: ที่เก็บต้นฉบับสามารถเขียนได้ + text_rmagick_available: RMagick มีให้ใช้ (เป็นตัวเลือก) + text_destroy_time_entries_question: "%{hours} ชั่วโมงที่ถูกแจ้งในปัญหานี้จะโดนลบ. คุณต้องการทำอย่างไร?" + text_destroy_time_entries: ลบเวลาที่รายงานไว้ + text_assign_time_entries_to_project: ระบุเวลาที่ใช้ในโครงการนี้ + text_reassign_time_entries: 'ระบุเวลาที่ใช้ในโครงการนี่อีกครั้ง:' + + default_role_manager: ผู้จัดการ + default_role_developer: ผู้พัฒนา + default_role_reporter: ผู้รายงาน + default_tracker_bug: บั๊ก + default_tracker_feature: ลักษณะเด่น + default_tracker_support: สนับสนุน + default_issue_status_new: เกิดขึ้น + default_issue_status_in_progress: In Progress + default_issue_status_resolved: ดำเนินการ + default_issue_status_feedback: รอคำตอบ + default_issue_status_closed: จบ + default_issue_status_rejected: ยกเลิก + default_doc_category_user: เอกสารของผู้ใช้ + default_doc_category_tech: เอกสารทางเทคนิค + default_priority_low: ต่ำ + default_priority_normal: ปกติ + default_priority_high: สูง + default_priority_urgent: เร่งด่วน + default_priority_immediate: ด่วนมาก + default_activity_design: ออกแบบ + default_activity_development: พัฒนา + + enumeration_issue_priorities: ความสำคัญของปัญหา + enumeration_doc_categories: ประเภทเอกสาร + enumeration_activities: กิจกรรม (ใช้ในการติดตามเวลา) + label_and_its_subprojects: "%{value} and its subprojects" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + text_user_wrote: "%{value} wrote:" + label_duplicated_by: duplicated by + setting_enabled_scm: Enabled SCM + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + field_parent_title: Parent page + label_issue_watchers: Watchers + button_quote: Quote + setting_sequential_project_identifiers: Generate sequential project identifiers + notice_unable_delete_version: Unable to delete version + label_renamed: renamed + label_copied: copied + setting_plain_text_mail: plain text only (no HTML) + permission_view_files: View files + permission_edit_issues: Edit issues + permission_edit_own_time_entries: Edit own time logs + permission_manage_public_queries: Manage public queries + permission_add_issues: Add issues + permission_log_time: Log spent time + permission_view_changesets: View changesets + permission_view_time_entries: View spent time + permission_manage_versions: Manage versions + permission_manage_wiki: Manage wiki + permission_manage_categories: Manage issue categories + permission_protect_wiki_pages: Protect wiki pages + permission_comment_news: Comment news + permission_delete_messages: Delete messages + permission_select_project_modules: Select project modules + permission_manage_documents: Manage documents + permission_edit_wiki_pages: Edit wiki pages + permission_add_issue_watchers: Add watchers + permission_view_gantt: View gantt chart + permission_move_issues: Move issues + permission_manage_issue_relations: Manage issue relations + permission_delete_wiki_pages: Delete wiki pages + permission_manage_boards: Manage boards + permission_delete_wiki_pages_attachments: Delete attachments + permission_view_wiki_edits: View wiki history + permission_add_messages: Post messages + permission_view_messages: View messages + permission_manage_files: Manage files + permission_edit_issue_notes: Edit notes + permission_manage_news: Manage news + permission_view_calendar: View calendrier + permission_manage_members: Manage members + permission_edit_messages: Edit messages + permission_delete_issues: Delete issues + permission_view_issue_watchers: View watchers list + permission_manage_repository: Manage repository + permission_commit_access: Commit access + permission_browse_repository: Browse repository + permission_view_documents: View documents + permission_edit_project: Edit project + permission_add_issue_notes: Add notes + permission_save_queries: Save queries + permission_view_wiki_pages: View wiki + permission_rename_wiki_pages: Rename wiki pages + permission_edit_time_entries: Edit time logs + permission_edit_own_issue_notes: Edit own notes + setting_gravatar_enabled: Use Gravatar user icons + label_example: Example + text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + permission_edit_own_messages: Edit own messages + permission_delete_own_messages: Delete own messages + label_user_activity: "%{value}'s activity" + label_updated_time_by: "Updated by %{author} %{age} ago" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} file(s) could not be saved." + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + label_display: Display + field_editable: Editable + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/59/59de5ceebde6ea8ac36e39033a149f119d1f604c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/59/59de5ceebde6ea8ac36e39033a149f119d1f604c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stranicu'; +jsToolBar.strings['Image'] = 'Slika'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5a62234b780985b2a0def003065d9dfb9410c414.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5a/5a62234b780985b2a0def003065d9dfb9410c414.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ += Redmine + +Redmine is a flexible project management web application written using Ruby on Rails framework. + +More details can be found at http://www.redmine.org diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5a6564a54f44ce0a2f2a1f8ee7e59d575551ecf9.svn-base Binary file .svn/pristine/5a/5a6564a54f44ce0a2f2a1f8ee7e59d575551ecf9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5a873e9e9e84bc33d66d92fc3026e83347d34fe0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5a/5a873e9e9e84bc33d66d92fc3026e83347d34fe0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Tučné'; +jsToolBar.strings['Italic'] = 'Kurzíva'; +jsToolBar.strings['Underline'] = 'Podtržené'; +jsToolBar.strings['Deleted'] = 'Přeškrtnuté '; +jsToolBar.strings['Code'] = 'Zobrazení kódu'; +jsToolBar.strings['Heading 1'] = 'Záhlaví 1'; +jsToolBar.strings['Heading 2'] = 'Záhlaví 2'; +jsToolBar.strings['Heading 3'] = 'Záhlaví 3'; +jsToolBar.strings['Unordered list'] = 'Seznam'; +jsToolBar.strings['Ordered list'] = 'Uspořádaný seznam'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Předformátovaný text'; +jsToolBar.strings['Wiki link'] = 'Vložit odkaz na Wiki stránku'; +jsToolBar.strings['Image'] = 'Vložit obrázek'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5a8940b17850ed112d980a704ec100e86fd3848a.svn-base Binary file .svn/pristine/5a/5a8940b17850ed112d980a704ec100e86fd3848a.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5aa3c5fccf79f48430b6e2714bcb9f02b7096762.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5a/5aa3c5fccf79f48430b6e2714bcb9f02b7096762.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class CommentsControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :news, :comments + + def setup + User.current = nil + end + + def test_add_comment + @request.session[:user_id] = 2 + post :create, :id => 1, :comment => { :comments => 'This is a test comment' } + assert_redirected_to '/news/1' + + comment = News.find(1).comments.find(:first, :order => 'created_on DESC') + assert_not_nil comment + assert_equal 'This is a test comment', comment.comments + assert_equal User.find(2), comment.author + end + + def test_empty_comment_should_not_be_added + @request.session[:user_id] = 2 + assert_no_difference 'Comment.count' do + post :create, :id => 1, :comment => { :comments => '' } + assert_response :redirect + assert_redirected_to '/news/1' + end + end + + def test_destroy_comment + comments_count = News.find(1).comments.size + @request.session[:user_id] = 2 + delete :destroy, :id => 1, :comment_id => 2 + assert_redirected_to '/news/1' + assert_nil Comment.find_by_id(2) + assert_equal comments_count - 1, News.find(1).comments.size + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5ac168e788123edaa826d60386a14a4bc19dc01c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5a/5ac168e788123edaa826d60386a14a4bc19dc01c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0401 afii10023 +!A2 U+0402 afii10051 +!A3 U+0403 afii10052 +!A4 U+0404 afii10053 +!A5 U+0405 afii10054 +!A6 U+0406 afii10055 +!A7 U+0407 afii10056 +!A8 U+0408 afii10057 +!A9 U+0409 afii10058 +!AA U+040A afii10059 +!AB U+040B afii10060 +!AC U+040C afii10061 +!AD U+00AD hyphen +!AE U+040E afii10062 +!AF U+040F afii10145 +!B0 U+0410 afii10017 +!B1 U+0411 afii10018 +!B2 U+0412 afii10019 +!B3 U+0413 afii10020 +!B4 U+0414 afii10021 +!B5 U+0415 afii10022 +!B6 U+0416 afii10024 +!B7 U+0417 afii10025 +!B8 U+0418 afii10026 +!B9 U+0419 afii10027 +!BA U+041A afii10028 +!BB U+041B afii10029 +!BC U+041C afii10030 +!BD U+041D afii10031 +!BE U+041E afii10032 +!BF U+041F afii10033 +!C0 U+0420 afii10034 +!C1 U+0421 afii10035 +!C2 U+0422 afii10036 +!C3 U+0423 afii10037 +!C4 U+0424 afii10038 +!C5 U+0425 afii10039 +!C6 U+0426 afii10040 +!C7 U+0427 afii10041 +!C8 U+0428 afii10042 +!C9 U+0429 afii10043 +!CA U+042A afii10044 +!CB U+042B afii10045 +!CC U+042C afii10046 +!CD U+042D afii10047 +!CE U+042E afii10048 +!CF U+042F afii10049 +!D0 U+0430 afii10065 +!D1 U+0431 afii10066 +!D2 U+0432 afii10067 +!D3 U+0433 afii10068 +!D4 U+0434 afii10069 +!D5 U+0435 afii10070 +!D6 U+0436 afii10072 +!D7 U+0437 afii10073 +!D8 U+0438 afii10074 +!D9 U+0439 afii10075 +!DA U+043A afii10076 +!DB U+043B afii10077 +!DC U+043C afii10078 +!DD U+043D afii10079 +!DE U+043E afii10080 +!DF U+043F afii10081 +!E0 U+0440 afii10082 +!E1 U+0441 afii10083 +!E2 U+0442 afii10084 +!E3 U+0443 afii10085 +!E4 U+0444 afii10086 +!E5 U+0445 afii10087 +!E6 U+0446 afii10088 +!E7 U+0447 afii10089 +!E8 U+0448 afii10090 +!E9 U+0449 afii10091 +!EA U+044A afii10092 +!EB U+044B afii10093 +!EC U+044C afii10094 +!ED U+044D afii10095 +!EE U+044E afii10096 +!EF U+044F afii10097 +!F0 U+2116 afii61352 +!F1 U+0451 afii10071 +!F2 U+0452 afii10099 +!F3 U+0453 afii10100 +!F4 U+0454 afii10101 +!F5 U+0455 afii10102 +!F6 U+0456 afii10103 +!F7 U+0457 afii10104 +!F8 U+0458 afii10105 +!F9 U+0459 afii10106 +!FA U+045A afii10107 +!FB U+045B afii10108 +!FC U+045C afii10109 +!FD U+00A7 section +!FE U+045E afii10110 +!FF U+045F afii10193 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5a/5aec509994867416f5eba53e85b834a9d0a37215.svn-base Binary file .svn/pristine/5a/5aec509994867416f5eba53e85b834a9d0a37215.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5b/5b2198e662de16967edb81f88103c24ee0daeb81.svn-base Binary file .svn/pristine/5b/5b2198e662de16967edb81f88103c24ee0daeb81.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5b/5b2317c90ed81995ffba20202367b84382beccbf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5b/5b2317c90ed81995ffba20202367b84382beccbf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class WikiContentTest < ActiveSupport::TestCase + fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :users + + def setup + @wiki = Wiki.find(1) + @page = @wiki.pages.first + end + + def test_create + page = WikiPage.new(:wiki => @wiki, :title => "Page") + page.content = WikiContent.new(:text => "Content text", :author => User.find(1), :comments => "My comment") + assert page.save + page.reload + + content = page.content + assert_kind_of WikiContent, content + assert_equal 1, content.version + assert_equal 1, content.versions.length + assert_equal "Content text", content.text + assert_equal "My comment", content.comments + assert_equal User.find(1), content.author + assert_equal content.text, content.versions.last.text + end + + def test_create_should_send_email_notification + Setting.notified_events = ['wiki_content_added'] + ActionMailer::Base.deliveries.clear + page = WikiPage.new(:wiki => @wiki, :title => "A new page") + page.content = WikiContent.new(:text => "Content text", :author => User.find(1), :comments => "My comment") + assert page.save + + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_update + content = @page.content + version_count = content.version + content.text = "My new content" + assert content.save + content.reload + assert_equal version_count+1, content.version + assert_equal version_count+1, content.versions.length + end + + def test_update_should_send_email_notification + Setting.notified_events = ['wiki_content_updated'] + ActionMailer::Base.deliveries.clear + content = @page.content + content.text = "My new content" + assert content.save + + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_fetch_history + assert !@page.content.versions.empty? + @page.content.versions.each do |version| + assert_kind_of String, version.text + end + end + + def test_large_text_should_not_be_truncated_to_64k + page = WikiPage.new(:wiki => @wiki, :title => "Big page") + page.content = WikiContent.new(:text => "a" * 500.kilobyte, :author => User.find(1)) + assert page.save + page.reload + assert_equal 500.kilobyte, page.content.text.size + end + + def test_current_version + content = WikiContent.find(11) + assert_equal true, content.current_version? + assert_equal true, content.versions.first(:order => 'version DESC').current_version? + assert_equal false, content.versions.first(:order => 'version ASC').current_version? + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5b/5ba499ead951b0f7092a76c82d09ab18e9ef0b47.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5b/5ba499ead951b0f7092a76c82d09ab18e9ef0b47.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +# $Id: testber.rb 57 2006-04-18 00:18:48Z blackhedd $ +# +# + + +$:.unshift "lib" + +require 'net/ldap' +require 'stringio' + + +class TestBer < Test::Unit::TestCase + + def setup + end + + # TODO: Add some much bigger numbers + # 5000000000 is a Bignum, which hits different code. + def test_ber_integers + assert_equal( "\002\001\005", 5.to_ber ) + assert_equal( "\002\002\203t", 500.to_ber ) + assert_equal( "\002\003\203\206P", 50000.to_ber ) + assert_equal( "\002\005\222\320\227\344\000", 5000000000.to_ber ) + end + + def test_ber_parsing + assert_equal( 6, "\002\001\006".read_ber( Net::LDAP::AsnSyntax )) + assert_equal( "testing", "\004\007testing".read_ber( Net::LDAP::AsnSyntax )) + end + + + def test_ber_parser_on_ldap_bind_request + s = StringIO.new "0$\002\001\001`\037\002\001\003\004\rAdministrator\200\vad_is_bogus" + assert_equal( [1, [3, "Administrator", "ad_is_bogus"]], s.read_ber( Net::LDAP::AsnSyntax )) + end + + + + +end + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5b/5ba4b3bae1ac655e0a9cb68df6a092b2c3782db0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5b/5ba4b3bae1ac655e0a9cb68df6a092b2c3782db0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class <%= migration_name %> < ActiveRecord::Migration + def self.up + create_table :<%= table_name %> do |t| +<% for attribute in attributes -%> + t.column :<%= attribute.name %>, :<%= attribute.type %> +<% end -%> + end + end + + def self.down + drop_table :<%= table_name %> + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5c/5c0a303ec427da4568cb1c19ef950684f2d5b39b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5c/5c0a303ec427da4568cb1c19ef950684f2d5b39b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Krepko'; +jsToolBar.strings['Italic'] = 'Poševno'; +jsToolBar.strings['Underline'] = 'Podčrtano'; +jsToolBar.strings['Deleted'] = 'Izbrisano'; +jsToolBar.strings['Code'] = 'Koda med vrsticami'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Neurejen seznam'; +jsToolBar.strings['Ordered list'] = 'Urejen seznam'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Odstrani citat'; +jsToolBar.strings['Preformatted text'] = 'Predoblikovano besedilo'; +jsToolBar.strings['Wiki link'] = 'Povezava na Wiki stran'; +jsToolBar.strings['Image'] = 'Slika'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5c/5c0d725f7c169077f48040da16fb4cb01381f158.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5c/5c0d725f7c169077f48040da16fb4cb01381f158.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +issue_relation_001: + id: 1 + issue_from_id: 10 + issue_to_id: 9 + relation_type: blocks + delay: +issue_relation_002: + id: 2 + issue_from_id: 2 + issue_to_id: 3 + relation_type: relates + delay: + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5d08d1e25f5add23341eebe953f9997482bf5a56.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5d08d1e25f5add23341eebe953f9997482bf5a56.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,69 @@ +# $Id: testldif.rb 61 2006-04-18 20:55:55Z blackhedd $ +# +# + + +$:.unshift "lib" + +require 'test/unit' + +require 'net/ldap' +require 'net/ldif' + +require 'sha1' +require 'base64' + +class TestLdif < Test::Unit::TestCase + + TestLdifFilename = "tests/testdata.ldif" + + def test_empty_ldif + ds = Net::LDAP::Dataset::read_ldif( StringIO.new ) + assert_equal( true, ds.empty? ) + end + + def test_ldif_with_comments + str = ["# Hello from LDIF-land", "# This is an unterminated comment"] + io = StringIO.new( str[0] + "\r\n" + str[1] ) + ds = Net::LDAP::Dataset::read_ldif( io ) + assert_equal( str, ds.comments ) + end + + def test_ldif_with_password + psw = "goldbricks" + hashed_psw = "{SHA}" + Base64::encode64( SHA1.new(psw).digest ).chomp + + ldif_encoded = Base64::encode64( hashed_psw ).chomp + ds = Net::LDAP::Dataset::read_ldif( StringIO.new( "dn: Goldbrick\r\nuserPassword:: #{ldif_encoded}\r\n\r\n" )) + recovered_psw = ds["Goldbrick"][:userpassword].shift + assert_equal( hashed_psw, recovered_psw ) + end + + def test_ldif_with_continuation_lines + ds = Net::LDAP::Dataset::read_ldif( StringIO.new( "dn: abcdefg\r\n hijklmn\r\n\r\n" )) + assert_equal( true, ds.has_key?( "abcdefg hijklmn" )) + end + + # TODO, INADEQUATE. We need some more tests + # to verify the content. + def test_ldif + File.open( TestLdifFilename, "r" ) {|f| + ds = Net::LDAP::Dataset::read_ldif( f ) + assert_equal( 13, ds.length ) + } + end + + # TODO, need some tests. + # Must test folded lines and base64-encoded lines as well as normal ones. + def test_to_ldif + File.open( TestLdifFilename, "r" ) {|f| + ds = Net::LDAP::Dataset::read_ldif( f ) + ds.to_ldif + assert_equal( true, false ) # REMOVE WHEN WE HAVE SOME TESTS HERE. + } + end + + +end + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5d110403425d734bbec061b5ba503df5df3a724f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5d110403425d734bbec061b5ba503df5df3a724f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +begin + require 'yard' + + YARD::Rake::YardocTask.new do |t| + files = ['lib/**/*.rb', 'app/**/*.rb'] + files << Dir['vendor/plugins/**/*.rb'].reject {|f| f.match(/test/) } # Exclude test files + t.files = files + + static_files = ['doc/CHANGELOG', + 'doc/COPYING', + 'doc/INSTALL', + 'doc/RUNNING_TESTS', + 'doc/UPGRADING'].join(',') + + t.options += ['--output-dir', './doc/app', '--files', static_files] + end + +rescue LoadError + # yard not installed (gem install yard) + # http://yardoc.org +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5d325fbf1da8575532e913088f466027c523ae21.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5d325fbf1da8575532e913088f466027c523ae21.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddVersionedTables < ActiveRecord::Migration + def self.up + create_table("things") do |t| + t.column :title, :text + end + Thing.create_versioned_table + end + + def self.down + Thing.drop_versioned_table + drop_table "things" rescue nil + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5d3d445e6a2c90ebc1a3730a84d68683aaccf4dc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5d3d445e6a2c90ebc1a3730a84d68683aaccf4dc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +require File.expand_path('../../../test_helper', __FILE__) + +class IssueMovesHelperTest < ActionView::TestCase +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5d571492c7244e04873692cfed4f26cbc16d0c77.svn-base Binary file .svn/pristine/5d/5d571492c7244e04873692cfed4f26cbc16d0c77.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5d94857704d99231f1b0ea1e206666d924acf9ab.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5d94857704d99231f1b0ea1e206666d924acf9ab.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,284 @@ +module CodeRay + + # = PluginHost + # + # A simple subclass/subfolder plugin system. + # + # Example: + # class Generators + # extend PluginHost + # plugin_path 'app/generators' + # end + # + # class Generator + # extend Plugin + # PLUGIN_HOST = Generators + # end + # + # class FancyGenerator < Generator + # register_for :fancy + # end + # + # Generators[:fancy] #-> FancyGenerator + # # or + # CodeRay.require_plugin 'Generators/fancy' + # # or + # Generators::Fancy + module PluginHost + + # Raised if Encoders::[] fails because: + # * a file could not be found + # * the requested Plugin is not registered + PluginNotFound = Class.new LoadError + HostNotFound = Class.new LoadError + + PLUGIN_HOSTS = [] + PLUGIN_HOSTS_BY_ID = {} # dummy hash + + # Loads all plugins using list and load. + def load_all + for plugin in list + load plugin + end + end + + # Returns the Plugin for +id+. + # + # Example: + # yaml_plugin = MyPluginHost[:yaml] + def [] id, *args, &blk + plugin = validate_id(id) + begin + plugin = plugin_hash.[] plugin, *args, &blk + end while plugin.is_a? Symbol + plugin + end + + alias load [] + + # Tries to +load+ the missing plugin by translating +const+ to the + # underscore form (eg. LinesOfCode becomes lines_of_code). + def const_missing const + id = const.to_s. + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + downcase + load id + end + + class << self + + # Adds the module/class to the PLUGIN_HOSTS list. + def extended mod + PLUGIN_HOSTS << mod + end + + end + + # The path where the plugins can be found. + def plugin_path *args + unless args.empty? + @plugin_path = File.expand_path File.join(*args) + end + @plugin_path ||= '' + end + + # Map a plugin_id to another. + # + # Usage: Put this in a file plugin_path/_map.rb. + # + # class MyColorHost < PluginHost + # map :navy => :dark_blue, + # :maroon => :brown, + # :luna => :moon + # end + def map hash + for from, to in hash + from = validate_id from + to = validate_id to + plugin_hash[from] = to unless plugin_hash.has_key? from + end + end + + # Define the default plugin to use when no plugin is found + # for a given id, or return the default plugin. + # + # See also map. + # + # class MyColorHost < PluginHost + # map :navy => :dark_blue + # default :gray + # end + # + # MyColorHost.default # loads and returns the Gray plugin + def default id = nil + if id + id = validate_id id + raise "The default plugin can't be named \"default\"." if id == :default + plugin_hash[:default] = id + else + load :default + end + end + + # Every plugin must register itself for +id+ by calling register_for, + # which calls this method. + # + # See Plugin#register_for. + def register plugin, id + plugin_hash[validate_id(id)] = plugin + end + + # A Hash of plugion_id => Plugin pairs. + def plugin_hash + @plugin_hash ||= make_plugin_hash + end + + # Returns an array of all .rb files in the plugin path. + # + # The extension .rb is not included. + def list + Dir[path_to('*')].select do |file| + File.basename(file)[/^(?!_)\w+\.rb$/] + end.map do |file| + File.basename(file, '.rb').to_sym + end + end + + # Returns an array of all Plugins. + # + # Note: This loads all plugins using load_all. + def all_plugins + load_all + plugin_hash.values.grep(Class) + end + + # Loads the map file (see map). + # + # This is done automatically when plugin_path is called. + def load_plugin_map + mapfile = path_to '_map' + @plugin_map_loaded = true + if File.exist? mapfile + require mapfile + true + else + false + end + end + + protected + + # Return a plugin hash that automatically loads plugins. + def make_plugin_hash + @plugin_map_loaded ||= false + Hash.new do |h, plugin_id| + id = validate_id(plugin_id) + path = path_to id + begin + raise LoadError, "#{path} not found" unless File.exist? path + require path + rescue LoadError => boom + if @plugin_map_loaded + if h.has_key?(:default) + warn '%p could not load plugin %p; falling back to %p' % [self, id, h[:default]] + h[:default] + else + raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom] + end + else + load_plugin_map + h[plugin_id] + end + else + # Plugin should have registered by now + if h.has_key? id + h[id] + else + raise PluginNotFound, "No #{self.name} plugin for #{id.inspect} found in #{path}." + end + end + end + end + + # Returns the expected path to the plugin file for the given id. + def path_to plugin_id + File.join plugin_path, "#{plugin_id}.rb" + end + + # Converts +id+ to a Symbol if it is a String, + # or returns +id+ if it already is a Symbol. + # + # Raises +ArgumentError+ for all other objects, or if the + # given String includes non-alphanumeric characters (\W). + def validate_id id + if id.is_a? Symbol or id.nil? + id + elsif id.is_a? String + if id[/\w+/] == id + id.downcase.to_sym + else + raise ArgumentError, "Invalid id given: #{id}" + end + else + raise ArgumentError, "String or Symbol expected, but #{id.class} given." + end + end + + end + + + # = Plugin + # + # Plugins have to include this module. + # + # IMPORTANT: Use extend for this module. + # + # See CodeRay::PluginHost for examples. + module Plugin + + attr_reader :plugin_id + + # Register this class for the given +id+. + # + # Example: + # class MyPlugin < PluginHost::BaseClass + # register_for :my_id + # ... + # end + # + # See PluginHost.register. + def register_for id + @plugin_id = id + plugin_host.register self, id + end + + # Returns the title of the plugin, or sets it to the + # optional argument +title+. + def title title = nil + if title + @title = title.to_s + else + @title ||= name[/([^:]+)$/, 1] + end + end + + # The PluginHost for this Plugin class. + def plugin_host host = nil + if host.is_a? PluginHost + const_set :PLUGIN_HOST, host + end + self::PLUGIN_HOST + end + + def aliases + plugin_host.load_plugin_map + plugin_host.plugin_hash.inject [] do |aliases, (key, _)| + aliases << key if plugin_host[key] == self + aliases + end + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5da0b4c4bee024389ce63f0775bf42e759cc86ef.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5da0b4c4bee024389ce63f0775bf42e759cc86ef.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ + +require File.expand_path('../../../../../../test_helper', __FILE__) + +class FilesystemAdapterTest < ActiveSupport::TestCase + REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s + + if File.directory?(REPOSITORY_PATH) + def setup + @adapter = Redmine::Scm::Adapters::FilesystemAdapter.new(REPOSITORY_PATH) + end + + def test_entries + assert_equal 3, @adapter.entries.size + assert_equal ["dir", "japanese", "test"], @adapter.entries.collect(&:name) + assert_equal ["dir", "japanese", "test"], @adapter.entries(nil).collect(&:name) + assert_equal ["dir", "japanese", "test"], @adapter.entries("/").collect(&:name) + ["dir", "/dir", "/dir/", "dir/"].each do |path| + assert_equal ["subdir", "dirfile"], @adapter.entries(path).collect(&:name) + end + # If y try to use "..", the path is ignored + ["/../","dir/../", "..", "../", "/..", "dir/.."].each do |path| + assert_equal ["dir", "japanese", "test"], @adapter.entries(path).collect(&:name), + ".. must be ignored in path argument" + end + end + + def test_cat + assert_equal "TEST CAT\n", @adapter.cat("test") + assert_equal "TEST CAT\n", @adapter.cat("/test") + # Revision number is ignored + assert_equal "TEST CAT\n", @adapter.cat("/test", 1) + end + + def test_path_encoding_default_utf8 + adpt1 = Redmine::Scm::Adapters::FilesystemAdapter.new( + REPOSITORY_PATH + ) + assert_equal "UTF-8", adpt1.path_encoding + adpt2 = Redmine::Scm::Adapters::FilesystemAdapter.new( + REPOSITORY_PATH, + nil, + nil, + nil, + "" + ) + assert_equal "UTF-8", adpt2.path_encoding + end + else + puts "Filesystem test repository NOT FOUND. Skipping unit tests !!! See doc/RUNNING_TESTS." + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5dc200a9880b49ee8adf93752f95bd14fc23a33e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5dc200a9880b49ee8adf93752f95bd14fc23a33e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,98 @@ +# Generates a migration which migrates all plugins to their latest versions +# within the database. +class PluginMigrationGenerator < Rails::Generator::Base + + # 255 characters max for Windows NTFS (http://en.wikipedia.org/wiki/Filename) + # minus 14 for timestamp, minus some extra chars for dot, underscore, file + # extension. So let's have 230. + MAX_FILENAME_LENGTH = 230 + + def initialize(runtime_args, runtime_options={}) + super + @options = {:assigns => {}} + ensure_schema_table_exists + get_plugins_to_migrate(runtime_args) + + if @plugins_to_migrate.empty? + puts "All plugins are migrated to their latest versions" + exit(0) + end + + @options[:migration_file_name] = build_migration_name + @options[:assigns][:class_name] = build_migration_name.classify + end + + def manifest + record do |m| + m.migration_template 'plugin_migration.erb', 'db/migrate', @options + end + end + + protected + + # Create the schema table if it doesn't already exist. + def ensure_schema_table_exists + ActiveRecord::Base.connection.initialize_schema_migrations_table + end + + # Determine all the plugins which have migrations that aren't present + # according to the plugin schema information from the database. + def get_plugins_to_migrate(plugin_names) + + # First, grab all the plugins which exist and have migrations + @plugins_to_migrate = if plugin_names.empty? + Engines.plugins + else + plugin_names.map do |name| + Engines.plugins[name] ? Engines.plugins[name] : raise("Cannot find the plugin '#{name}'") + end + end + + @plugins_to_migrate.reject! { |p| !p.respond_to?(:latest_migration) || p.latest_migration.nil? } + + # Then find the current versions from the database + @current_versions = {} + @plugins_to_migrate.each do |plugin| + @current_versions[plugin.name] = Engines::Plugin::Migrator.current_version(plugin) + end + + # Then find the latest versions from their migration directories + @new_versions = {} + @plugins_to_migrate.each do |plugin| + @new_versions[plugin.name] = plugin.latest_migration + end + + # Remove any plugins that don't need migration + @plugins_to_migrate.map { |p| p.name }.each do |name| + @plugins_to_migrate.delete(Engines.plugins[name]) if @current_versions[name] == @new_versions[name] + end + + @options[:assigns][:plugins] = @plugins_to_migrate + @options[:assigns][:new_versions] = @new_versions + @options[:assigns][:current_versions] = @current_versions + end + + # Returns a migration name. If the descriptive migration name based on the + # plugin names involved is shorter than 230 characters that one will be + # used. Otherwise a shorter name will be returned. + def build_migration_name + descriptive_migration_name.tap do |name| + name.replace short_migration_name if name.length > MAX_FILENAME_LENGTH + end + end + + # Construct a unique migration name based on the plugins involved and the + # versions they should reach after this migration is run. The name constructed + # needs to be lowercase + def descriptive_migration_name + @plugins_to_migrate.map do |plugin| + "#{plugin.name}_to_version_#{@new_versions[plugin.name]}" + end.join("_and_").downcase + end + + # Short migration name that will be used if the descriptive_migration_name + # exceeds 230 characters + def short_migration_name + 'plugin_migrations' + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5d/5dc63759de7dfd35f5bca9ebf67da227968a751f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5d/5dc63759de7dfd35f5bca9ebf67da227968a751f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,395 @@ +require 'SVG/Graph/Graph' + +module SVG + module Graph + # === Create presentation quality SVG pie graphs easily + # + # == Synopsis + # + # require 'SVG/Graph/Pie' + # + # fields = %w(Jan Feb Mar) + # data_sales_02 = [12, 45, 21] + # + # graph = SVG::Graph::Pie.new({ + # :height => 500, + # :width => 300, + # :fields => fields, + # }) + # + # graph.add_data({ + # :data => data_sales_02, + # :title => 'Sales 2002', + # }) + # + # print "Content-type: image/svg+xml\r\n\r\n" + # print graph.burn(); + # + # == Description + # + # This object aims to allow you to easily create high quality + # SVG pie graphs. You can either use the default style sheet + # or supply your own. Either way there are many options which can + # be configured to give you control over how the graph is + # generated - with or without a key, display percent on pie chart, + # title, subtitle etc. + # + # = Examples + # + # http://www.germane-software/repositories/public/SVG/test/single.rb + # + # == See also + # + # * SVG::Graph::Graph + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Bar + # * SVG::Graph::Line + # * SVG::Graph::Plot + # * SVG::Graph::TimeSeries + # + # == Author + # + # Sean E. Russell + # + # Copyright 2004 Sean E. Russell + # This software is available under the Ruby license[LICENSE.txt] + # + class Pie < Graph + # Defaults are those set by Graph::initialize, and + # [show_shadow] true + # [shadow_offset] 10 + # [show_data_labels] false + # [show_actual_values] false + # [show_percent] true + # [show_key_data_labels] true + # [show_key_actual_values] true + # [show_key_percent] false + # [expanded] false + # [expand_greatest] false + # [expand_gap] 10 + # [show_x_labels] false + # [show_y_labels] false + # [datapoint_font_size] 12 + def set_defaults + init_with( + :show_shadow => true, + :shadow_offset => 10, + + :show_data_labels => false, + :show_actual_values => false, + :show_percent => true, + + :show_key_data_labels => true, + :show_key_actual_values => true, + :show_key_percent => false, + + :expanded => false, + :expand_greatest => false, + :expand_gap => 10, + + :show_x_labels => false, + :show_y_labels => false, + :datapoint_font_size => 12 + ) + @data = [] + end + + # Adds a data set to the graph. + # + # graph.add_data( { :data => [1,2,3,4] } ) + # + # Note that the :title is not necessary. If multiple + # data sets are added to the graph, the pie chart will + # display the +sums+ of the data. EG: + # + # graph.add_data( { :data => [1,2,3,4] } ) + # graph.add_data( { :data => [2,3,5,9] } ) + # + # is the same as: + # + # graph.add_data( { :data => [3,5,8,13] } ) + def add_data arg + arg[:data].each_index {|idx| + @data[idx] = 0 unless @data[idx] + @data[idx] += arg[:data][idx] + } + end + + # If true, displays a drop shadow for the chart + attr_accessor :show_shadow + # Sets the offset of the shadow from the pie chart + attr_accessor :shadow_offset + # If true, display the data labels on the chart + attr_accessor :show_data_labels + # If true, display the actual field values in the data labels + attr_accessor :show_actual_values + # If true, display the percentage value of each pie wedge in the data + # labels + attr_accessor :show_percent + # If true, display the labels in the key + attr_accessor :show_key_data_labels + # If true, display the actual value of the field in the key + attr_accessor :show_key_actual_values + # If true, display the percentage value of the wedges in the key + attr_accessor :show_key_percent + # If true, "explode" the pie (put space between the wedges) + attr_accessor :expanded + # If true, expand the largest pie wedge + attr_accessor :expand_greatest + # The amount of space between expanded wedges + attr_accessor :expand_gap + # The font size of the data point labels + attr_accessor :datapoint_font_size + + + protected + + def add_defs defs + gradient = defs.add_element( "filter", { + "id"=>"dropshadow", + "width" => "1.2", + "height" => "1.2", + } ) + gradient.add_element( "feGaussianBlur", { + "stdDeviation" => "4", + "result" => "blur" + }) + end + + # We don't need the graph + def draw_graph + end + + def get_y_labels + [""] + end + + def get_x_labels + [""] + end + + def keys + total = 0 + max_value = 0 + @data.each {|x| total += x } + percent_scale = 100.0 / total + count = -1 + a = @config[:fields].collect{ |x| + count += 1 + v = @data[count] + perc = show_key_percent ? " "+(v * percent_scale).round.to_s+"%" : "" + x + " [" + v.to_s + "]" + perc + } + end + + RADIANS = Math::PI/180 + + def draw_data + @graph = @root.add_element( "g" ) + background = @graph.add_element("g") + midground = @graph.add_element("g") + + diameter = @graph_height > @graph_width ? @graph_width : @graph_height + diameter -= expand_gap if expanded or expand_greatest + diameter -= datapoint_font_size if show_data_labels + diameter -= 10 if show_shadow + radius = diameter / 2.0 + + xoff = (width - diameter) / 2 + yoff = (height - @border_bottom - diameter) + yoff -= 10 if show_shadow + @graph.attributes['transform'] = "translate( #{xoff} #{yoff} )" + + wedge_text_pad = 5 + wedge_text_pad = 20 if show_percent and show_data_labels + + total = 0 + max_value = 0 + @data.each {|x| + max_value = max_value < x ? x : max_value + total += x + } + percent_scale = 100.0 / total + + prev_percent = 0 + rad_mult = 3.6 * RADIANS + @config[:fields].each_index { |count| + value = @data[count] + percent = percent_scale * value + + radians = prev_percent * rad_mult + x_start = radius+(Math.sin(radians) * radius) + y_start = radius-(Math.cos(radians) * radius) + radians = (prev_percent+percent) * rad_mult + x_end = radius+(Math.sin(radians) * radius) + x_end -= 0.00001 if @data.length == 1 + y_end = radius-(Math.cos(radians) * radius) + path = "M#{radius},#{radius} L#{x_start},#{y_start} "+ + "A#{radius},#{radius} "+ + "0, #{percent >= 50 ? '1' : '0'},1, "+ + "#{x_end} #{y_end} Z" + + + wedge = @foreground.add_element( "path", { + "d" => path, + "class" => "fill#{count+1}" + }) + + translate = nil + tx = 0 + ty = 0 + half_percent = prev_percent + percent / 2 + radians = half_percent * rad_mult + + if show_shadow + shadow = background.add_element( "path", { + "d" => path, + "filter" => "url(#dropshadow)", + "style" => "fill: #ccc; stroke: none;" + }) + clear = midground.add_element( "path", { + "d" => path, + "style" => "fill: #fff; stroke: none;" + }) + end + + if expanded or (expand_greatest && value == max_value) + tx = (Math.sin(radians) * expand_gap) + ty = -(Math.cos(radians) * expand_gap) + translate = "translate( #{tx} #{ty} )" + wedge.attributes["transform"] = translate + clear.attributes["transform"] = translate if clear + end + + if show_shadow + shadow.attributes["transform"] = + "translate( #{tx+shadow_offset} #{ty+shadow_offset} )" + end + + if show_data_labels and value != 0 + label = "" + label += @config[:fields][count] if show_key_data_labels + label += " ["+value.to_s+"]" if show_actual_values + label += " "+percent.round.to_s+"%" if show_percent + + msr = Math.sin(radians) + mcr = Math.cos(radians) + tx = radius + (msr * radius) + ty = radius -(mcr * radius) + + if expanded or (expand_greatest && value == max_value) + tx += (msr * expand_gap) + ty -= (mcr * expand_gap) + end + @foreground.add_element( "text", { + "x" => tx.to_s, + "y" => ty.to_s, + "class" => "dataPointLabel", + "style" => "stroke: #fff; stroke-width: 2;" + }).text = label.to_s + @foreground.add_element( "text", { + "x" => tx.to_s, + "y" => ty.to_s, + "class" => "dataPointLabel", + }).text = label.to_s + end + + prev_percent += percent + } + end + + + def round val, to + up = 10**to.to_f + (val * up).to_i / up + end + + + def get_css + return <= 2 && Rails::VERSION::MINOR >= 3 && Rails::VERSION::TINY >= 2 + raise "This version of the engines plugin requires Rails 2.3.2 or later!" + end +end + +require File.join(File.dirname(__FILE__), 'lib/engines') + +# initialize Rails::Configuration with our own default values to spare users +# some hassle with the installation and keep the environment cleaner + +{ :default_plugin_locators => (defined?(Gem) ? [Rails::Plugin::GemLocator] : []).push(Engines::Plugin::FileSystemLocator), + :default_plugin_loader => Engines::Plugin::Loader, + :default_plugins => [:engines, :all] }.each do |name, default| + Rails::Configuration.send(:define_method, name) { default } +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5e/5e37d42ab73a7b90b18f47c2e9486d6d1d7f855f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5e/5e37d42ab73a7b90b18f47c2e9486d6d1d7f855f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +

    <%=l(:label_issue_category)%>: <%=h @category.name %>

    + +<% form_tag(issue_category_path(@category), :method => :delete) do %> +
    +

    <%= l(:text_issue_category_destroy_question, @issue_count) %>

    +


    +<% if @categories.size > 0 %> +: +<%= label_tag "reassign_to_id", l(:description_issue_category_reassign), :class => "hidden-for-sighted" %> +<%= select_tag 'reassign_to_id', options_from_collection_for_select(@categories, 'id', 'name') %>

    +<% end %> +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5e/5e390d048451969a2cf8ae5ceb1da6dd876fe459.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5e/5e390d048451969a2cf8ae5ceb1da6dd876fe459.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +<% if @entry && @entry.kind == 'file' %> + +

    +<%= link_to_if action_name != 'changes', l(:label_history), {:action => 'changes', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | +<% if @repository.supports_cat? %> + <%= link_to_if action_name != 'entry', l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | +<% end %> +<% if @repository.supports_annotate? %> + <%= link_to_if action_name != 'annotate', l(:button_annotate), {:action => 'annotate', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | +<% end %> +<%= link_to(l(:button_download), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev, :format => 'raw' }) if @repository.supports_cat? %> +<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %> +

    + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5e/5e76196c9e35c9b7b34f45d88fc793cafc843bca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5e/5e76196c9e35c9b7b34f45d88fc793cafc843bca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +api.array :versions, api_meta(:total_count => @versions.size) do + @versions.each do |version| + api.version do + api.id version.id + api.project(:id => version.project_id, :name => version.project.name) unless version.project.nil? + + api.name version.name + api.description version.description + api.status version.status + api.due_date version.effective_date + + render_api_custom_values version.custom_field_values, api + + api.created_on version.created_on + api.updated_on version.updated_on + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5e/5e8f42d64fea2eb401973c8a48a2ac702f5d9e4c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5e/5e8f42d64fea2eb401973c8a48a2ac702f5d9e4c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddIssuesEstimatedHours < ActiveRecord::Migration + def self.up + add_column :issues, :estimated_hours, :float + end + + def self.down + remove_column :issues, :estimated_hours + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5e/5ea13b75716eac3a96472978f3ec5fb6a73f65c5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5e/5ea13b75716eac3a96472978f3ec5fb6a73f65c5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,444 @@ +require 'SVG/Graph/Graph' + +module SVG + module Graph + # === Create presentation quality SVG line graphs easily + # + # = Synopsis + # + # require 'SVG/Graph/Line' + # + # fields = %w(Jan Feb Mar); + # data_sales_02 = [12, 45, 21] + # data_sales_03 = [15, 30, 40] + # + # graph = SVG::Graph::Line.new({ + # :height => 500, + # :width => 300, + # :fields => fields, + # }) + # + # graph.add_data({ + # :data => data_sales_02, + # :title => 'Sales 2002', + # }) + # + # graph.add_data({ + # :data => data_sales_03, + # :title => 'Sales 2003', + # }) + # + # print "Content-type: image/svg+xml\r\n\r\n"; + # print graph.burn(); + # + # = Description + # + # This object aims to allow you to easily create high quality + # SVG line graphs. You can either use the default style sheet + # or supply your own. Either way there are many options which can + # be configured to give you control over how the graph is + # generated - with or without a key, data elements at each point, + # title, subtitle etc. + # + # = Examples + # + # http://www.germane-software/repositories/public/SVG/test/single.rb + # + # = Notes + # + # The default stylesheet handles upto 10 data sets, if you + # use more you must create your own stylesheet and add the + # additional settings for the extra data sets. You will know + # if you go over 10 data sets as they will have no style and + # be in black. + # + # = See also + # + # * SVG::Graph::Graph + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Bar + # * SVG::Graph::Pie + # * SVG::Graph::Plot + # * SVG::Graph::TimeSeries + # + # == Author + # + # Sean E. Russell + # + # Copyright 2004 Sean E. Russell + # This software is available under the Ruby license[LICENSE.txt] + # + class Line < SVG::Graph::Graph + # Show a small circle on the graph where the line + # goes from one point to the next. + attr_accessor :show_data_points + # Accumulates each data set. (i.e. Each point increased by sum of + # all previous series at same point). Default is 0, set to '1' to show. + attr_accessor :stacked + # Fill in the area under the plot if true + attr_accessor :area_fill + + # The constructor takes a hash reference, fields (the names for each + # field on the X axis) MUST be set, all other values are defaulted to + # those shown above - with the exception of style_sheet which defaults + # to using the internal style sheet. + def initialize config + raise "fields was not supplied or is empty" unless config[:fields] && + config[:fields].kind_of?(Array) && + config[:fields].length > 0 + super + end + + # In addition to the defaults set in Graph::initialize, sets + # [show_data_points] true + # [show_data_values] true + # [stacked] false + # [area_fill] false + def set_defaults + init_with( + :show_data_points => true, + :show_data_values => true, + :stacked => false, + :area_fill => false + ) + + self.top_align = self.top_font = self.right_align = self.right_font = 1 + end + + protected + + def max_value + max = 0 + + if (stacked == true) then + sums = Array.new(@config[:fields].length).fill(0) + + @data.each do |data| + sums.each_index do |i| + sums[i] += data[:data][i].to_f + end + end + + max = sums.max + else + max = @data.collect{|x| x[:data].max}.max + end + + return max + end + + def min_value + min = 0 + + if (min_scale_value.nil? == false) then + min = min_scale_value + elsif (stacked == true) then + min = @data[-1][:data].min + else + min = @data.collect{|x| x[:data].min}.min + end + + return min + end + + def get_x_labels + @config[:fields] + end + + def calculate_left_margin + super + label_left = @config[:fields][0].length / 2 * font_size * 0.6 + @border_left = label_left if label_left > @border_left + end + + def get_y_labels + maxvalue = max_value + minvalue = min_value + range = maxvalue - minvalue + top_pad = range == 0 ? 10 : range / 20.0 + scale_range = (maxvalue + top_pad) - minvalue + + scale_division = scale_divisions || (scale_range / 10.0) + + if scale_integers + scale_division = scale_division < 1 ? 1 : scale_division.round + end + + rv = [] + maxvalue = maxvalue%scale_division == 0 ? + maxvalue : maxvalue + scale_division + minvalue.step( maxvalue, scale_division ) {|v| rv << v} + return rv + end + + def calc_coords(field, value, width = field_width, height = field_height) + coords = {:x => 0, :y => 0} + coords[:x] = width * field + coords[:y] = @graph_height - value * height + + return coords + end + + def draw_data + minvalue = min_value + fieldheight = (@graph_height.to_f - font_size*2*top_font) / + (get_y_labels.max - get_y_labels.min) + fieldwidth = field_width + line = @data.length + + prev_sum = Array.new(@config[:fields].length).fill(0) + cum_sum = Array.new(@config[:fields].length).fill(-minvalue) + + for data in @data.reverse + lpath = "" + apath = "" + + if not stacked then cum_sum.fill(-minvalue) end + + data[:data].each_index do |i| + cum_sum[i] += data[:data][i] + + c = calc_coords(i, cum_sum[i], fieldwidth, fieldheight) + + lpath << "#{c[:x]} #{c[:y]} " + end + + if area_fill + if stacked then + (prev_sum.length - 1).downto 0 do |i| + c = calc_coords(i, prev_sum[i], fieldwidth, fieldheight) + + apath << "#{c[:x]} #{c[:y]} " + end + + c = calc_coords(0, prev_sum[0], fieldwidth, fieldheight) + else + apath = "V#@graph_height" + c = calc_coords(0, 0, fieldwidth, fieldheight) + end + + @graph.add_element("path", { + "d" => "M#{c[:x]} #{c[:y]} L" + lpath + apath + "Z", + "class" => "fill#{line}" + }) + end + + @graph.add_element("path", { + "d" => "M0 #@graph_height L" + lpath, + "class" => "line#{line}" + }) + + if show_data_points || show_data_values + cum_sum.each_index do |i| + if show_data_points + @graph.add_element( "circle", { + "cx" => (fieldwidth * i).to_s, + "cy" => (@graph_height - cum_sum[i] * fieldheight).to_s, + "r" => "2.5", + "class" => "dataPoint#{line}" + }) + end + make_datapoint_text( + fieldwidth * i, + @graph_height - cum_sum[i] * fieldheight - 6, + cum_sum[i] + minvalue + ) + end + end + + prev_sum = cum_sum.dup + line -= 1 + end + end + + + def get_css + return <A Hash subclass designed for mapping word lists to token types. + # + # Copyright (c) 2006-2011 by murphy (Kornelius Kalnbach) + # + # License:: LGPL / ask the author + # Version:: 2.0 (2011-05-08) + # + # A WordList is a Hash with some additional features. + # It is intended to be used for keyword recognition. + # + # WordList is optimized to be used in Scanners, + # typically to decide whether a given ident is a special token. + # + # For case insensitive words use WordList::CaseIgnoring. + # + # Example: + # + # # define word arrays + # RESERVED_WORDS = %w[ + # asm break case continue default do else + # ] + # + # PREDEFINED_TYPES = %w[ + # int long short char void + # ] + # + # # make a WordList + # IDENT_KIND = WordList.new(:ident). + # add(RESERVED_WORDS, :reserved). + # add(PREDEFINED_TYPES, :predefined_type) + # + # ... + # + # def scan_tokens tokens, options + # ... + # + # elsif scan(/[A-Za-z_][A-Za-z_0-9]*/) + # # use it + # kind = IDENT_KIND[match] + # ... + class WordList < Hash + + # Create a new WordList with +default+ as default value. + def initialize default = false + super default + end + + # Add words to the list and associate them with +value+. + # + # Returns +self+, so you can concat add calls. + def add words, value = true + words.each { |word| self[word] = value } + self + end + + end + + + # A CaseIgnoring WordList is like a WordList, only that + # keys are compared case-insensitively (normalizing keys using +downcase+). + class WordList::CaseIgnoring < WordList + + def [] key + super key.downcase + end + + def []= key, value + super key.downcase, value + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5f/5f0a13fce17c6abc15fce65d4826f03678f86c58.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5f/5f0a13fce17c6abc15fce65d4826f03678f86c58.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,87 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class AuthSourcesController < ApplicationController + layout 'admin' + + before_filter :require_admin + + # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) + verify :method => :post, :only => [ :destroy, :create, :update ], + :redirect_to => { :template => :index } + + def index + @auth_source_pages, @auth_sources = paginate auth_source_class.name.tableize, :per_page => 10 + render "auth_sources/index" + end + + def new + @auth_source = auth_source_class.new + render 'auth_sources/new' + end + + def create + @auth_source = auth_source_class.new(params[:auth_source]) + if @auth_source.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'index' + else + render 'auth_sources/new' + end + end + + def edit + @auth_source = AuthSource.find(params[:id]) + render 'auth_sources/edit' + end + + def update + @auth_source = AuthSource.find(params[:id]) + if @auth_source.update_attributes(params[:auth_source]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'index' + else + render 'auth_sources/edit' + end + end + + def test_connection + @auth_method = AuthSource.find(params[:id]) + begin + @auth_method.test_connection + flash[:notice] = l(:notice_successful_connection) + rescue => text + flash[:error] = l(:error_unable_to_connect, text.message) + end + redirect_to :action => 'index' + end + + def destroy + @auth_source = AuthSource.find(params[:id]) + unless @auth_source.users.find(:first) + @auth_source.destroy + flash[:notice] = l(:notice_successful_delete) + end + redirect_to :action => 'index' + end + + protected + + def auth_source_class + AuthSource + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5f/5f2c1ff7bb00e3dbe21424d6a9413b8369316e8a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5f/5f2c1ff7bb00e3dbe21424d6a9413b8369316e8a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class MemberRole < ActiveRecord::Base + generator_for :member, :method => :generate_member + generator_for :role, :method => :generate_role + + def self.generate_role + Role.generate! + end + + def self.generate_member + Member.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5f/5f8859116475dd06123c2a90756b26148236e7e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5f/5f8859116475dd06123c2a90756b26148236e7e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +# The PluginList class is an array, enhanced to allow access to loaded plugins +# by name, and iteration over loaded plugins in order of priority. This array is used +# by Engines::RailsExtensions::RailsInitializer to create the Engines.plugins array. +# +# Each loaded plugin has a corresponding Plugin instance within this array, and +# the order the plugins were loaded is reflected in the entries in this array. +# +# For more information, see the Rails module. +module Engines + class Plugin + class List < Array + # Finds plugins with the set with the given name (accepts Strings or Symbols), or + # index. So, Engines.plugins[0] returns the first-loaded Plugin, and Engines.plugins[:engines] + # returns the Plugin instance for the engines plugin itself. + def [](name_or_index) + if name_or_index.is_a?(Fixnum) + super + else + self.find { |plugin| plugin.name.to_s == name_or_index.to_s } + end + end + + # Go through each plugin, highest priority first (last loaded first). Effectively, + # this is like Engines.plugins.reverse + def by_precedence + reverse + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5f/5fecd3aab73cee6c904a7c8ebc0ed878f6a6619b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5f/5fecd3aab73cee6c904a7c8ebc0ed878f6a6619b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ + + +Redmine 404 error + + +

    Page not found

    +

    The page you were trying to access doesn't exist or has been removed.

    +

    Back

    + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/5f/5ffda40b0da33ea2cbd4a1b56f89be0bef6f6786.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/5f/5ffda40b0da33ea2cbd4a1b56f89be0bef6f6786.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +
    +<%= link_to_if_authorized l(:label_query_new), new_project_query_path(:project_id => @project), :class => 'icon icon-add' %> +
    + +

    <%= l(:label_query_plural) %>

    + +<% if @queries.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> + + <% @queries.each do |query| %> + + + + + <% end %> +
    + <%= link_to h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %> + + + <% if query.editable_by?(User.current) %> + <%= link_to l(:button_edit), edit_query_path(query), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), query_path(query), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> + + <% end %> +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/60/6089c129623045cd6c157b0be5cbb46ac9a89d00.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/60/6089c129623045cd6c157b0be5cbb46ac9a89d00.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +if @journal.frozen? + # journal was destroyed + page.remove "change-#{@journal.id}" +else + page.replace "journal-#{@journal.id}-notes", render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit')) + page.show "journal-#{@journal.id}-notes" + page.remove "journal-#{@journal.id}-form" +end + +call_hook(:view_journals_update_rjs_bottom, { :page => page, :journal => @journal }) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/60/60a7eaf3b71f4ea5a952f91807abdd540583522f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/60/60a7eaf3b71f4ea5a952f91807abdd540583522f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,205 @@ +# $Id: pdu.rb 126 2006-05-31 15:55:16Z blackhedd $ +# +# LDAP PDU support classes +# +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Gmail: garbagecat10 +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +#--------------------------------------------------------------------------- +# + + + +module Net + + +class LdapPduError < Exception; end + + +class LdapPdu + + BindResult = 1 + SearchReturnedData = 4 + SearchResult = 5 + ModifyResponse = 7 + AddResponse = 9 + DeleteResponse = 11 + ModifyRDNResponse = 13 + SearchResultReferral = 19 + + attr_reader :msg_id, :app_tag + attr_reader :search_dn, :search_attributes, :search_entry + attr_reader :search_referrals + + # + # initialize + # An LDAP PDU always looks like a BerSequence with + # at least two elements: an integer (message-id number), and + # an application-specific sequence. + # Some LDAPv3 packets also include an optional + # third element, which is a sequence of "controls" + # (See RFC 2251, section 4.1.12). + # The application-specific tag in the sequence tells + # us what kind of packet it is, and each kind has its + # own format, defined in RFC-1777. + # Observe that many clients (such as ldapsearch) + # do not necessarily enforce the expected application + # tags on received protocol packets. This implementation + # does interpret the RFC strictly in this regard, and + # it remains to be seen whether there are servers out + # there that will not work well with our approach. + # + # Added a controls-processor to SearchResult. + # Didn't add it everywhere because it just _feels_ + # like it will need to be refactored. + # + def initialize ber_object + begin + @msg_id = ber_object[0].to_i + @app_tag = ber_object[1].ber_identifier - 0x60 + rescue + # any error becomes a data-format error + raise LdapPduError.new( "ldap-pdu format error" ) + end + + case @app_tag + when BindResult + parse_ldap_result ber_object[1] + when SearchReturnedData + parse_search_return ber_object[1] + when SearchResultReferral + parse_search_referral ber_object[1] + when SearchResult + parse_ldap_result ber_object[1] + parse_controls(ber_object[2]) if ber_object[2] + when ModifyResponse + parse_ldap_result ber_object[1] + when AddResponse + parse_ldap_result ber_object[1] + when DeleteResponse + parse_ldap_result ber_object[1] + when ModifyRDNResponse + parse_ldap_result ber_object[1] + else + raise LdapPduError.new( "unknown pdu-type: #{@app_tag}" ) + end + end + + # + # result_code + # This returns an LDAP result code taken from the PDU, + # but it will be nil if there wasn't a result code. + # That can easily happen depending on the type of packet. + # + def result_code code = :resultCode + @ldap_result and @ldap_result[code] + end + + # Return RFC-2251 Controls if any. + # Messy. Does this functionality belong somewhere else? + def result_controls + @ldap_controls || [] + end + + + # + # parse_ldap_result + # + def parse_ldap_result sequence + sequence.length >= 3 or raise LdapPduError + @ldap_result = {:resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2]} + end + private :parse_ldap_result + + # + # parse_search_return + # Definition from RFC 1777 (we're handling application-4 here) + # + # Search Response ::= + # CHOICE { + # entry [APPLICATION 4] SEQUENCE { + # objectName LDAPDN, + # attributes SEQUENCE OF SEQUENCE { + # AttributeType, + # SET OF AttributeValue + # } + # }, + # resultCode [APPLICATION 5] LDAPResult + # } + # + # We concoct a search response that is a hash of the returned attribute values. + # NOW OBSERVE CAREFULLY: WE ARE DOWNCASING THE RETURNED ATTRIBUTE NAMES. + # This is to make them more predictable for user programs, but it + # may not be a good idea. Maybe this should be configurable. + # ALTERNATE IMPLEMENTATION: In addition to @search_dn and @search_attributes, + # we also return @search_entry, which is an LDAP::Entry object. + # If that works out well, then we'll remove the first two. + # + # Provisionally removed obsolete search_attributes and search_dn, 04May06. + # + def parse_search_return sequence + sequence.length >= 2 or raise LdapPduError + @search_entry = LDAP::Entry.new( sequence[0] ) + #@search_dn = sequence[0] + #@search_attributes = {} + sequence[1].each {|seq| + @search_entry[seq[0]] = seq[1] + #@search_attributes[seq[0].downcase.intern] = seq[1] + } + end + + # + # A search referral is a sequence of one or more LDAP URIs. + # Any number of search-referral replies can be returned by the server, interspersed + # with normal replies in any order. + # Until I can think of a better way to do this, we'll return the referrals as an array. + # It'll be up to higher-level handlers to expose something reasonable to the client. + def parse_search_referral uris + @search_referrals = uris + end + + + # Per RFC 2251, an LDAP "control" is a sequence of tuples, each consisting + # of an OID, a boolean criticality flag defaulting FALSE, and an OPTIONAL + # Octet String. If only two fields are given, the second one may be + # either criticality or data, since criticality has a default value. + # Someday we may want to come back here and add support for some of + # more-widely used controls. RFC-2696 is a good example. + # + def parse_controls sequence + @ldap_controls = sequence.map do |control| + o = OpenStruct.new + o.oid,o.criticality,o.value = control[0],control[1],control[2] + if o.criticality and o.criticality.is_a?(String) + o.value = o.criticality + o.criticality = false + end + o + end + end + private :parse_controls + + +end + + +end # module Net + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/60/60b442ee90e3b26f595ed2865e1f3dfc9222dd1c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/60/60b442ee90e3b26f595ed2865e1f3dfc9222dd1c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Comment < ActiveRecord::Base + belongs_to :commented, :polymorphic => true, :counter_cache => true + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + + validates_presence_of :commented, :author, :comments +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/60/60c7c698ddb29ef3812a4b75182c078fbc9cc19b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/60/60c7c698ddb29ef3812a4b75182c078fbc9cc19b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Helpers + class Diff + include ERB::Util + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TextHelper + attr_reader :diff, :words + + def initialize(content_to, content_from) + @words = content_to.to_s.split(/(\s+)/) + @words = @words.select {|word| word != ' '} + words_from = content_from.to_s.split(/(\s+)/) + words_from = words_from.select {|word| word != ' '} + @diff = words_from.diff @words + end + + def to_html + words = self.words.collect{|word| h(word)} + words_add = 0 + words_del = 0 + dels = 0 + del_off = 0 + diff.diffs.each do |diff| + add_at = nil + add_to = nil + del_at = nil + deleted = "" + diff.each do |change| + pos = change[1] + if change[0] == "+" + add_at = pos + dels unless add_at + add_to = pos + dels + words_add += 1 + else + del_at = pos unless del_at + deleted << ' ' + h(change[2]) + words_del += 1 + end + end + if add_at + words[add_at] = '' + words[add_at] + words[add_to] = words[add_to] + '' + end + if del_at + words.insert del_at - del_off + dels + words_add, '' + deleted + '' + dels += 1 + del_off += words_del + words_del = 0 + end + end + words.join(' ').html_safe + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/60/60f6cd76a2cf878fbe57eea952f6c764270ac27b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/60/60f6cd76a2cf878fbe57eea952f6c764270ac27b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar FI language +// Author: Antti Perkiömäki +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sunnuntai", + "Maanantai", + "Tiistai", + "Keskiviikko", + "Torstai", + "Perjantai", + "Lauantai", + "Sunnuntai"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Su", + "Ma", + "Ti", + "Ke", + "To", + "Pe", + "La", + "Su"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Tammikuu", + "Helmikuu", + "Maaliskuu", + "Huhtikuu", + "Toukokuu", + "Kesäkuu", + "Heinäkuu", + "Elokuu", + "Syyskuu", + "Lokakuu", + "Marraskuu", + "Joulukuu"); + +// short month names +Calendar._SMN = new Array +("Tammi", + "Helmi", + "Maalis", + "Huhti", + "Touko", + "Kesä", + "Heinä", + "Elo", + "Syys", + "Loka", + "Marras", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Tietoa kalenterista"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Tekijä: Mihai Bazon\n" + // don't translate this this ;-) +"Viimeisin versio: http://www.dynarch.com/projects/calendar/\n" + +"Jaettu GNU LGPL alaisena. Katso lisätiedot http://gnu.org/licenses/lgpl.html" + +"\n\n" + +"Päivä valitsin:\n" + +"- Käytä \xab, \xbb painikkeita valitaksesi vuoden\n" + +"- Käytä " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " painikkeita valitaksesi kuukauden\n" + +"- Pidä alhaalla hiiren painiketta missä tahansa yllämainituissa painikkeissa valitaksesi nopeammin."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Ajan valinta:\n" + +"- Paina mitä tahansa ajan osaa kasvattaaksesi sitä\n" + +"- tai Vaihtonäppäin-paina laskeaksesi sitä\n" + +"- tai paina ja raahaa valitaksesi nopeammin."; + +Calendar._TT["PREV_YEAR"] = "Edellinen vuosi (valikko tulee painaessa)"; +Calendar._TT["PREV_MONTH"] = "Edellinen kuukausi (valikko tulee painaessa)"; +Calendar._TT["GO_TODAY"] = "Siirry Tänään"; +Calendar._TT["NEXT_MONTH"] = "Seuraava kuukausi (valikko tulee painaessa)"; +Calendar._TT["NEXT_YEAR"] = "Seuraava vuosi (valikko tulee painaessa)"; +Calendar._TT["SEL_DATE"] = "Valitse päivä"; +Calendar._TT["DRAG_TO_MOVE"] = "Rahaa siirtääksesi"; +Calendar._TT["PART_TODAY"] = " (tänään)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Näytä %s ensin"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "6,0"; + +Calendar._TT["CLOSE"] = "Sulje"; +Calendar._TT["TODAY"] = "Tänään"; +Calendar._TT["TIME_PART"] = "(Vaihtonäppäin-)Paina tai raahaa vaihtaaksesi arvoa"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "vko"; +Calendar._TT["TIME"] = "Aika:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/60/60fb53c461a41fb9a73cca759c107e76107c0242.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/60/60fb53c461a41fb9a73cca759c107e76107c0242.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,176 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Role < ActiveRecord::Base + # Built-in roles + BUILTIN_NON_MEMBER = 1 + BUILTIN_ANONYMOUS = 2 + + ISSUES_VISIBILITY_OPTIONS = [ + ['all', :label_issues_visibility_all], + ['default', :label_issues_visibility_public], + ['own', :label_issues_visibility_own] + ] + + named_scope :givable, { :conditions => "builtin = 0", :order => 'position' } + named_scope :builtin, lambda { |*args| + compare = 'not' if args.first == true + { :conditions => "#{compare} builtin = 0" } + } + + before_destroy :check_deletable + has_many :workflows, :dependent => :delete_all do + def copy(source_role) + Workflow.copy(nil, source_role, nil, proxy_owner) + end + end + + has_many :member_roles, :dependent => :destroy + has_many :members, :through => :member_roles + acts_as_list + + serialize :permissions, Array + attr_protected :builtin + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 30 + validates_inclusion_of :issues_visibility, + :in => ISSUES_VISIBILITY_OPTIONS.collect(&:first), + :if => lambda {|role| role.respond_to?(:issues_visibility)} + + def permissions + read_attribute(:permissions) || [] + end + + def permissions=(perms) + perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms + write_attribute(:permissions, perms) + end + + def add_permission!(*perms) + self.permissions = [] unless permissions.is_a?(Array) + + permissions_will_change! + perms.each do |p| + p = p.to_sym + permissions << p unless permissions.include?(p) + end + save! + end + + def remove_permission!(*perms) + return unless permissions.is_a?(Array) + permissions_will_change! + perms.each { |p| permissions.delete(p.to_sym) } + save! + end + + # Returns true if the role has the given permission + def has_permission?(perm) + !permissions.nil? && permissions.include?(perm.to_sym) + end + + def <=>(role) + role ? position <=> role.position : -1 + end + + def to_s + name + end + + def name + case builtin + when 1; l(:label_role_non_member, :default => read_attribute(:name)) + when 2; l(:label_role_anonymous, :default => read_attribute(:name)) + else; read_attribute(:name) + end + end + + # Return true if the role is a builtin role + def builtin? + self.builtin != 0 + end + + # Return true if the role is a project member role + def member? + !self.builtin? + end + + # Return true if role is allowed to do the specified action + # action can be: + # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') + # * a permission Symbol (eg. :edit_project) + def allowed_to?(action) + if action.is_a? Hash + allowed_actions.include? "#{action[:controller]}/#{action[:action]}" + else + allowed_permissions.include? action + end + end + + # Return all the permissions that can be given to the role + def setable_permissions + setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions + setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER + setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS + setable_permissions + end + + # Find all the roles that can be given to a project member + def self.find_all_givable + find(:all, :conditions => {:builtin => 0}, :order => 'position') + end + + # Return the builtin 'non member' role. If the role doesn't exist, + # it will be created on the fly. + def self.non_member + find_or_create_system_role(BUILTIN_NON_MEMBER, 'Non member') + end + + # Return the builtin 'anonymous' role. If the role doesn't exist, + # it will be created on the fly. + def self.anonymous + find_or_create_system_role(BUILTIN_ANONYMOUS, 'Anonymous') + end + +private + + def allowed_permissions + @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name} + end + + def allowed_actions + @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten + end + + def check_deletable + raise "Can't delete role" if members.any? + raise "Can't delete builtin role" if builtin? + end + + def self.find_or_create_system_role(builtin, name) + role = first(:conditions => {:builtin => builtin}) + if role.nil? + role = create(:name => name, :position => 0) do |r| + r.builtin = builtin + end + raise "Unable to create the #{name} role." if role.new_record? + end + role + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/610244da27aff83a2186d4b44964a68bed322fdc.svn-base Binary file .svn/pristine/61/610244da27aff83a2186d4b44964a68bed322fdc.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/61309acbc5f96ce770001ad1501caa18b7f75258.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/61/61309acbc5f96ce770001ad1501caa18b7f75258.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,176 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class TimeEntryTest < ActiveSupport::TestCase + fixtures :issues, :projects, :users, :time_entries, + :members, :roles, :member_roles, :auth_sources, + :trackers, :issue_statuses, + :projects_trackers, + :journals, :journal_details, + :issue_categories, :enumerations, + :groups_users, + :enabled_modules, + :workflows + + def test_hours_format + assertions = { "2" => 2.0, + "21.1" => 21.1, + "2,1" => 2.1, + "1,5h" => 1.5, + "7:12" => 7.2, + "10h" => 10.0, + "10 h" => 10.0, + "45m" => 0.75, + "45 m" => 0.75, + "3h15" => 3.25, + "3h 15" => 3.25, + "3 h 15" => 3.25, + "3 h 15m" => 3.25, + "3 h 15 m" => 3.25, + "3 hours" => 3.0, + "12min" => 0.2, + } + + assertions.each do |k, v| + t = TimeEntry.new(:hours => k) + assert_equal v, t.hours, "Converting #{k} failed:" + end + end + + def test_hours_should_default_to_nil + assert_nil TimeEntry.new.hours + end + + def test_spent_on_with_blank + c = TimeEntry.new + c.spent_on = '' + assert_nil c.spent_on + end + + def test_spent_on_with_nil + c = TimeEntry.new + c.spent_on = nil + assert_nil c.spent_on + end + + def test_spent_on_with_string + c = TimeEntry.new + c.spent_on = "2011-01-14" + assert_equal Date.parse("2011-01-14"), c.spent_on + end + + def test_spent_on_with_invalid_string + c = TimeEntry.new + c.spent_on = "foo" + assert_nil c.spent_on + end + + def test_spent_on_with_date + c = TimeEntry.new + c.spent_on = Date.today + assert_equal Date.today, c.spent_on + end + + def test_spent_on_with_time + c = TimeEntry.new + c.spent_on = Time.now + assert_equal Date.today, c.spent_on + end + + def test_validate_time_entry + anon = User.anonymous + project = Project.find(1) + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => anon.id, :status_id => 1, + :priority => IssuePriority.all.first, :subject => 'test_create', + :description => 'IssueTest#test_create', :estimated_hours => '1:30') + assert issue.save + activity = TimeEntryActivity.find_by_name('Design') + te = TimeEntry.create(:spent_on => '2010-01-01', + :hours => 100000, + :issue => issue, + :project => project, + :user => anon, + :activity => activity) + assert_equal 1, te.errors.count + end + + def test_set_project_if_nil + anon = User.anonymous + project = Project.find(1) + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => anon.id, :status_id => 1, + :priority => IssuePriority.all.first, :subject => 'test_create', + :description => 'IssueTest#test_create', :estimated_hours => '1:30') + assert issue.save + activity = TimeEntryActivity.find_by_name('Design') + te = TimeEntry.create(:spent_on => '2010-01-01', + :hours => 10, + :issue => issue, + :user => anon, + :activity => activity) + assert_equal project.id, te.project.id + end + + context "#earilest_date_for_project" do + setup do + User.current = nil + @public_project = Project.generate!(:is_public => true) + @issue = Issue.generate_for_project!(@public_project) + TimeEntry.generate!(:spent_on => '2010-01-01', + :issue => @issue, + :project => @public_project) + end + + context "without a project" do + should "return the lowest spent_on value that is visible to the current user" do + assert_equal "2007-03-12", TimeEntry.earilest_date_for_project.to_s + end + end + + context "with a project" do + should "return the lowest spent_on value that is visible to the current user for that project and it's subprojects only" do + assert_equal "2010-01-01", TimeEntry.earilest_date_for_project(@public_project).to_s + end + end + + end + + context "#latest_date_for_project" do + setup do + User.current = nil + @public_project = Project.generate!(:is_public => true) + @issue = Issue.generate_for_project!(@public_project) + TimeEntry.generate!(:spent_on => '2010-01-01', + :issue => @issue, + :project => @public_project) + end + + context "without a project" do + should "return the highest spent_on value that is visible to the current user" do + assert_equal "2010-01-01", TimeEntry.latest_date_for_project.to_s + end + end + + context "with a project" do + should "return the highest spent_on value that is visible to the current user for that project and it's subprojects only" do + project = Project.find(1) + assert_equal "2007-04-22", TimeEntry.latest_date_for_project(project).to_s + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/61668dfcefb644406f6147ff8d4029159a7244df.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/61/61668dfcefb644406f6147ff8d4029159a7244df.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +<% form_tag({:action => 'edit', :tab => 'authentication'}) do %> + +
    +

    <%= setting_check_box :login_required %>

    + +

    <%= setting_select :autologin, [[l(:label_disabled), 0]] + [1, 7, 30, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), days.to_s]} %>

    + +

    <%= setting_select :self_registration, [[l(:label_disabled), "0"], + [l(:label_registration_activation_by_email), "1"], + [l(:label_registration_manual_activation), "2"], + [l(:label_registration_automatic_activation), "3"]] %>

    + +

    <%= setting_text_field :password_min_length, :size => 6 %>

    + +

    <%= setting_check_box :lost_password, :label => :label_password_lost %>

    + +

    <%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %>

    + +

    <%= setting_check_box :rest_api_enabled %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/619c54c9f730a5777baad077923b8717bed20d2f.svn-base Binary file .svn/pristine/61/619c54c9f730a5777baad077923b8717bed20d2f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/61a91d37bba4f376ceeb50ad99e25e5c58c85000.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/61/61a91d37bba4f376ceeb50ad99e25e5c58c85000.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ExceptionNotificationCompatibilityTest < ActionController::TestCase + ExceptionNotifier.exception_recipients = %w(joe@schmoe.com bill@schmoe.com) + class SimpleController < ApplicationController + include ExceptionNotifiable + local_addresses.clear + consider_all_requests_local = false + def index + begin + raise "Fail!" + rescue Exception => e + rescue_action_in_public(e) + end + end + end + + def setup + @controller = SimpleController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_work + assert_nothing_raised do + get :index + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/61b65742b8b81ec430e2510c699672b59ba4470d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/61/61b65742b8b81ec430e2510c699672b59ba4470d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// Translator: David Duret, from previous french version + +// full day names +Calendar._DN = new Array +("Dimanche", + "Lundi", + "Mardi", + "Mercredi", + "Jeudi", + "Vendredi", + "Samedi", + "Dimanche"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dim", + "Lun", + "Mar", + "Mer", + "Jeu", + "Ven", + "Sam", + "Dim"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Janvier", + "Février", + "Mars", + "Avril", + "Mai", + "Juin", + "Juillet", + "Août", + "Septembre", + "Octobre", + "Novembre", + "Décembre"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Fev", + "Mar", + "Avr", + "Mai", + "Juin", + "Juil", + "Aout", + "Sep", + "Oct", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "A propos du calendrier"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Heure Selecteur\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Pour la derniere version visitez : http://www.dynarch.com/projects/calendar/\n" + +"Distribué par GNU LGPL. Voir http://gnu.org/licenses/lgpl.html pour les details." + +"\n\n" + +"Selection de la date :\n" + +"- Utiliser les bouttons \xab, \xbb pour selectionner l\'annee\n" + +"- Utiliser les bouttons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pour selectionner les mois\n" + +"- Garder la souris sur n'importe quels boutons pour une selection plus rapide"; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selection de l\'heure :\n" + +"- Cliquer sur heures ou minutes pour incrementer\n" + +"- ou Maj-clic pour decrementer\n" + +"- ou clic et glisser-deplacer pour une selection plus rapide"; + +Calendar._TT["PREV_YEAR"] = "Année préc. (maintenir pour menu)"; +Calendar._TT["PREV_MONTH"] = "Mois préc. (maintenir pour menu)"; +Calendar._TT["GO_TODAY"] = "Atteindre la date du jour"; +Calendar._TT["NEXT_MONTH"] = "Mois suiv. (maintenir pour menu)"; +Calendar._TT["NEXT_YEAR"] = "Année suiv. (maintenir pour menu)"; +Calendar._TT["SEL_DATE"] = "Sélectionner une date"; +Calendar._TT["DRAG_TO_MOVE"] = "Déplacer"; +Calendar._TT["PART_TODAY"] = " (Aujourd'hui)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Afficher %s en premier"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Fermer"; +Calendar._TT["TODAY"] = "Aujourd'hui"; +Calendar._TT["TIME_PART"] = "(Maj-)Clic ou glisser pour modifier la valeur"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "Sem."; +Calendar._TT["TIME"] = "Heure :"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/61e50703af02347b6cb421c714576454eb248e4a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/61/61e50703af02347b6cb421c714576454eb248e4a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,82 @@ +require File.expand_path('../../../../../../test_helper', __FILE__) +begin + require 'mocha' + + class CvsAdapterTest < ActiveSupport::TestCase + REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s + REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? + MODULE_NAME = 'test' + + if File.directory?(REPOSITORY_PATH) + def setup + @adapter = Redmine::Scm::Adapters::CvsAdapter.new(MODULE_NAME, REPOSITORY_PATH) + end + + def test_scm_version + to_test = { "\nConcurrent Versions System (CVS) 1.12.13 (client/server)\n" => [1,12,13], + "\r\n1.12.12\r\n1.12.11" => [1,12,12], + "1.12.11\r\n1.12.10\r\n" => [1,12,11]} + to_test.each do |s, v| + test_scm_version_for(s, v) + end + end + + def test_revisions_all + cnt = 0 + @adapter.revisions('', nil, nil, :log_encoding => 'UTF-8') do |revision| + cnt += 1 + end + assert_equal 16, cnt + end + + def test_revisions_from_rev3 + rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22) + cnt = 0 + @adapter.revisions('', rev3_committed_on, nil, :log_encoding => 'UTF-8') do |revision| + cnt += 1 + end + assert_equal 4, cnt + end + + def test_entries_rev3 + rev3_committed_on = Time.gm(2007, 12, 13, 16, 27, 22) + entries = @adapter.entries('sources', rev3_committed_on) + assert_equal 2, entries.size + assert_equal entries[0].name, "watchers_controller.rb" + assert_equal entries[0].lastrev.time, Time.gm(2007, 12, 13, 16, 27, 22) + end + + def test_path_encoding_default_utf8 + adpt1 = Redmine::Scm::Adapters::CvsAdapter.new( + MODULE_NAME, + REPOSITORY_PATH + ) + assert_equal "UTF-8", adpt1.path_encoding + adpt2 = Redmine::Scm::Adapters::CvsAdapter.new( + MODULE_NAME, + REPOSITORY_PATH, + nil, + nil, + "" + ) + assert_equal "UTF-8", adpt2.path_encoding + end + + private + + def test_scm_version_for(scm_command_version, version) + @adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version) + assert_equal version, @adapter.class.scm_command_version + end + else + puts "Cvs test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end + end + +rescue LoadError + class CvsMochaFake < ActiveSupport::TestCase + def test_fake; assert(false, "Requires mocha to run those tests") end + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/61/61f7f063ffaec55dad0c8a315b8506b208b3d80d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/61/61f7f063ffaec55dad0c8a315b8506b208b3d80d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +<% if @workflow_counts.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +
    + + + + + <% @workflow_counts.first.last.each do |role, count| %> + + + <% end %> + + + +<% @workflow_counts.each do |tracker, roles| -%> + + + <% roles.each do |role, count| -%> + + <% end -%> + +<% end -%> + +
    + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> +
    <%= h tracker %> + <%= link_to((count > 0 ? count : image_tag('false.png')), {:action => 'edit', :role_id => role, :tracker_id => tracker}, :title => l(:button_edit)) %> +
    +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/62/622a96ef316ae7336ae7048be84a5832435b74d1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/62/622a96ef316ae7336ae7048be84a5832435b74d1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fett'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Unterstrichen'; +jsToolBar.strings['Deleted'] = 'Durchgestrichen'; +jsToolBar.strings['Code'] = 'Quelltext'; +jsToolBar.strings['Heading 1'] = 'Überschrift 1. Ordnung'; +jsToolBar.strings['Heading 2'] = 'Überschrift 2. Ordnung'; +jsToolBar.strings['Heading 3'] = 'Überschrift 3. Ordnung'; +jsToolBar.strings['Unordered list'] = 'Aufzählungsliste'; +jsToolBar.strings['Ordered list'] = 'Nummerierte Liste'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Präformatierter Text'; +jsToolBar.strings['Wiki link'] = 'Verweis (Link) zu einer Wiki-Seite'; +jsToolBar.strings['Image'] = 'Grafik'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/62/6230957c0e4d32e6d5ac196562d742563883d7c0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/62/6230957c0e4d32e6d5ac196562d742563883d7c0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,500 @@ +require 'SVG/Graph/Graph' + +module SVG + module Graph + # === For creating SVG plots of scalar data + # + # = Synopsis + # + # require 'SVG/Graph/Plot' + # + # # Data sets are x,y pairs + # # Note that multiple data sets can differ in length, and that the + # # data in the datasets needn't be in order; they will be ordered + # # by the plot along the X-axis. + # projection = [ + # 6, 11, 0, 5, 18, 7, 1, 11, 13, 9, 1, 2, 19, 0, 3, 13, + # 7, 9 + # ] + # actual = [ + # 0, 18, 8, 15, 9, 4, 18, 14, 10, 2, 11, 6, 14, 12, + # 15, 6, 4, 17, 2, 12 + # ] + # + # graph = SVG::Graph::Plot.new({ + # :height => 500, + # :width => 300, + # :key => true, + # :scale_x_integers => true, + # :scale_y_integerrs => true, + # }) + # + # graph.add_data({ + # :data => projection + # :title => 'Projected', + # }) + # + # graph.add_data({ + # :data => actual, + # :title => 'Actual', + # }) + # + # print graph.burn() + # + # = Description + # + # Produces a graph of scalar data. + # + # This object aims to allow you to easily create high quality + # SVG[http://www.w3c.org/tr/svg] scalar plots. You can either use the + # default style sheet or supply your own. Either way there are many options + # which can be configured to give you control over how the graph is + # generated - with or without a key, data elements at each point, title, + # subtitle etc. + # + # = Examples + # + # http://www.germane-software/repositories/public/SVG/test/plot.rb + # + # = Notes + # + # The default stylesheet handles upto 10 data sets, if you + # use more you must create your own stylesheet and add the + # additional settings for the extra data sets. You will know + # if you go over 10 data sets as they will have no style and + # be in black. + # + # Unlike the other types of charts, data sets must contain x,y pairs: + # + # [ 1, 2 ] # A data set with 1 point: (1,2) + # [ 1,2, 5,6] # A data set with 2 points: (1,2) and (5,6) + # + # = See also + # + # * SVG::Graph::Graph + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Bar + # * SVG::Graph::Line + # * SVG::Graph::Pie + # * SVG::Graph::TimeSeries + # + # == Author + # + # Sean E. Russell + # + # Copyright 2004 Sean E. Russell + # This software is available under the Ruby license[LICENSE.txt] + # + class Plot < Graph + + # In addition to the defaults set by Graph::initialize, sets + # [show_data_values] true + # [show_data_points] true + # [area_fill] false + # [stacked] false + def set_defaults + init_with( + :show_data_values => true, + :show_data_points => true, + :area_fill => false, + :stacked => false + ) + self.top_align = self.right_align = self.top_font = self.right_font = 1 + end + + # Determines the scaling for the X axis divisions. + # + # graph.scale_x_divisions = 2 + # + # would cause the graph to attempt to generate labels stepped by 2; EG: + # 0,2,4,6,8... + attr_accessor :scale_x_divisions + # Determines the scaling for the Y axis divisions. + # + # graph.scale_y_divisions = 0.5 + # + # would cause the graph to attempt to generate labels stepped by 0.5; EG: + # 0, 0.5, 1, 1.5, 2, ... + attr_accessor :scale_y_divisions + # Make the X axis labels integers + attr_accessor :scale_x_integers + # Make the Y axis labels integers + attr_accessor :scale_y_integers + # Fill the area under the line + attr_accessor :area_fill + # Show a small circle on the graph where the line + # goes from one point to the next. + attr_accessor :show_data_points + # Set the minimum value of the X axis + attr_accessor :min_x_value + # Set the minimum value of the Y axis + attr_accessor :min_y_value + + + # Adds data to the plot. The data must be in X,Y pairs; EG + # [ 1, 2 ] # A data set with 1 point: (1,2) + # [ 1,2, 5,6] # A data set with 2 points: (1,2) and (5,6) + def add_data data + @data = [] unless @data + + raise "No data provided by #{conf.inspect}" unless data[:data] and + data[:data].kind_of? Array + raise "Data supplied must be x,y pairs! "+ + "The data provided contained an odd set of "+ + "data points" unless data[:data].length % 2 == 0 + return if data[:data].length == 0 + + x = [] + y = [] + data[:data].each_index {|i| + (i%2 == 0 ? x : y) << data[:data][i] + } + sort( x, y ) + data[:data] = [x,y] + @data << data + end + + + protected + + def keys + @data.collect{ |x| x[:title] } + end + + def calculate_left_margin + super + label_left = get_x_labels[0].to_s.length / 2 * font_size * 0.6 + @border_left = label_left if label_left > @border_left + end + + def calculate_right_margin + super + label_right = get_x_labels[-1].to_s.length / 2 * font_size * 0.6 + @border_right = label_right if label_right > @border_right + end + + + X = 0 + Y = 1 + def x_range + max_value = @data.collect{|x| x[:data][X][-1] }.max + min_value = @data.collect{|x| x[:data][X][0] }.min + min_value = min_value "M#{x_start} #@graph_height #{lpath} V#@graph_height Z", + "class" => "fill#{line}" + }) + end + + @graph.add_element( "path", { + "d" => "M#{x_start} #{y_start} #{lpath}", + "class" => "line#{line}" + }) + + if show_data_points || show_data_values + x_points.each_index { |idx| + x = (x_points[idx] - x_min) * x_step + y = @graph_height - (y_points[idx] - y_min) * y_step + if show_data_points + @graph.add_element( "circle", { + "cx" => x.to_s, + "cy" => y.to_s, + "r" => "2.5", + "class" => "dataPoint#{line}" + }) + add_popup(x, y, format( x_points[idx], y_points[idx] )) if add_popups + end + make_datapoint_text( x, y-6, y_points[idx] ) if show_data_values + } + end + line += 1 + end + end + + def format x, y + "(#{(x * 100).to_i / 100}, #{(y * 100).to_i / 100})" + end + + def get_css + return < +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("星期日", + "星期一", + "星期二", + "星期三", + "星期四", + "星期五", + "星期六", + "星期日"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("日", + "一", + "二", + "三", + "四", + "五", + "六", + "日"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("1月", + "2月", + "3月", + "4月", + "5月", + "6月", + "7月", + "8月", + "9月", + "10月", + "11月", + "12月"); + +// short month names +Calendar._SMN = new Array +("1月", + "2月", + "3月", + "4月", + "5月", + "6月", + "7月", + "8月", + "9月", + "10月", + "11月", + "12月"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "关于日历"; + +Calendar._TT["ABOUT"] = +"DHTML 日期/时间 选择器\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"最新版本请访问: http://www.dynarch.com/projects/calendar/\n" + +"遵循 GNU LGPL 发布。详情请查阅 http://gnu.org/licenses/lgpl.html " + +"\n\n" + +"日期选择:\n" + +"- 使用 \xab,\xbb 按钮选择年\n" + +"- 使用 " + String.fromCharCode(0x2039) + "," + String.fromCharCode(0x203a) + " 按钮选择月\n" + +"- 在上述按钮上按住不放可以快速选择"; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"时间选择:\n" + +"- 点击时间的任意部分来增加\n" + +"- Shift加点击来减少\n" + +"- 点击后拖动进行快速选择"; + +Calendar._TT["PREV_YEAR"] = "上年(按住不放显示菜单)"; +Calendar._TT["PREV_MONTH"] = "上月(按住不放显示菜单)"; +Calendar._TT["GO_TODAY"] = "回到今天"; +Calendar._TT["NEXT_MONTH"] = "下月(按住不放显示菜单)"; +Calendar._TT["NEXT_YEAR"] = "下年(按住不放显示菜单)"; +Calendar._TT["SEL_DATE"] = "选择日期"; +Calendar._TT["DRAG_TO_MOVE"] = "拖动"; +Calendar._TT["PART_TODAY"] = " (今日)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "一周开始于 %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "关闭"; +Calendar._TT["TODAY"] = "今天"; +Calendar._TT["TIME_PART"] = "Shift加点击或者拖动来变更"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "星期%a %b%e日"; + +Calendar._TT["WK"] = "周"; +Calendar._TT["TIME"] = "时间:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/62/62d25b06b15c0b260279da71be5d88bfab79f61e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/62/62d25b06b15c0b260279da71be5d88bfab79f61e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,131 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class WikiPageTest < ActiveSupport::TestCase + fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions + + def setup + @wiki = Wiki.find(1) + @page = @wiki.pages.first + end + + def test_create + page = WikiPage.new(:wiki => @wiki) + assert !page.save + assert_equal 1, page.errors.count + + page.title = "Page" + assert page.save + page.reload + assert !page.protected? + + @wiki.reload + assert @wiki.pages.include?(page) + end + + def test_sidebar_should_be_protected_by_default + page = @wiki.find_or_new_page('sidebar') + assert page.new_record? + assert page.protected? + end + + def test_find_or_new_page + page = @wiki.find_or_new_page("CookBook documentation") + assert_kind_of WikiPage, page + assert !page.new_record? + + page = @wiki.find_or_new_page("Non existing page") + assert_kind_of WikiPage, page + assert page.new_record? + end + + def test_parent_title + page = WikiPage.find_by_title('Another_page') + assert_nil page.parent_title + + page = WikiPage.find_by_title('Page_with_an_inline_image') + assert_equal 'CookBook documentation', page.parent_title + end + + def test_assign_parent + page = WikiPage.find_by_title('Another_page') + page.parent_title = 'CookBook documentation' + assert page.save + page.reload + assert_equal WikiPage.find_by_title('CookBook_documentation'), page.parent + end + + def test_unassign_parent + page = WikiPage.find_by_title('Page_with_an_inline_image') + page.parent_title = '' + assert page.save + page.reload + assert_nil page.parent + end + + def test_parent_validation + page = WikiPage.find_by_title('CookBook_documentation') + + # A page that doesn't exist + page.parent_title = 'Unknown title' + assert !page.save + assert_equal I18n.translate('activerecord.errors.messages.invalid'), page.errors.on(:parent_title) + # A child page + page.parent_title = 'Page_with_an_inline_image' + assert !page.save + assert_equal I18n.translate('activerecord.errors.messages.circular_dependency'), page.errors.on(:parent_title) + # The page itself + page.parent_title = 'CookBook_documentation' + assert !page.save + assert_equal I18n.translate('activerecord.errors.messages.circular_dependency'), page.errors.on(:parent_title) + + page.parent_title = 'Another_page' + assert page.save + end + + def test_destroy + page = WikiPage.find(1) + page.destroy + assert_nil WikiPage.find_by_id(1) + # make sure that page content and its history are deleted + assert WikiContent.find_all_by_page_id(1).empty? + assert WikiContent.versioned_class.find_all_by_page_id(1).empty? + end + + def test_destroy_should_not_nullify_children + page = WikiPage.find(2) + child_ids = page.child_ids + assert child_ids.any? + page.destroy + assert_nil WikiPage.find_by_id(2) + + children = WikiPage.find_all_by_id(child_ids) + assert_equal child_ids.size, children.size + children.each do |child| + assert_nil child.parent_id + end + end + + def test_updated_on_eager_load + page = WikiPage.with_updated_on.first + assert page.is_a?(WikiPage) + assert_not_nil page.read_attribute(:updated_on) + assert_equal page.content.updated_on, page.updated_on + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/63/634fa24a02c5bb6db30eef5565a1a7bdf8877051.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/63/634fa24a02c5bb6db30eef5565a1a7bdf8877051.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,202 @@ +# redMine - project management software +# Copyright (C) 2006-2007 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. + + +# DO NOT MODIFY THIS FILE !!! +# Settings can be defined through the application in Admin -> Settings + +app_title: + default: Redmine +app_subtitle: + default: Project management +welcome_text: + default: +login_required: + default: 0 +self_registration: + default: '2' +lost_password: + default: 1 +password_min_length: + format: int + default: 4 +attachment_max_size: + format: int + default: 5120 +issues_export_limit: + format: int + default: 500 +activity_days_default: + format: int + default: 30 +per_page_options: + default: '25,50,100' +mail_from: + default: redmine@example.net +bcc_recipients: + default: 1 +plain_text_mail: + default: 0 +text_formatting: + default: textile +cache_formatted_text: + default: 0 +wiki_compression: + default: "" +default_language: + default: en +host_name: + default: localhost:3000 +protocol: + default: http +feeds_limit: + format: int + default: 15 +gantt_items_limit: + format: int + default: 500 +# Maximum size of files that can be displayed +# inline through the file viewer (in KB) +file_max_size_displayed: + format: int + default: 512 +diff_max_lines_displayed: + format: int + default: 1500 +enabled_scm: + serialized: true + default: + - Subversion + - Darcs + - Mercurial + - Cvs + - Bazaar + - Git +autofetch_changesets: + default: 1 +sys_api_enabled: + default: 0 +sys_api_key: + default: '' +commit_ref_keywords: + default: 'refs,references,IssueID' +commit_fix_keywords: + default: 'fixes,closes' +commit_fix_status_id: + format: int + default: 0 +commit_fix_done_ratio: + default: 100 +commit_logtime_enabled: + default: 0 +commit_logtime_activity_id: + format: int + default: 0 +# autologin duration in days +# 0 means autologin is disabled +autologin: + format: int + default: 0 +# date format +date_format: + default: '' +time_format: + default: '' +user_format: + default: :firstname_lastname + format: symbol +cross_project_issue_relations: + default: 0 +issue_group_assignment: + default: 0 +default_issue_start_date_to_creation_date: + default: 1 +notified_events: + serialized: true + default: + - issue_added + - issue_updated +mail_handler_body_delimiters: + default: '' +mail_handler_api_enabled: + default: 0 +mail_handler_api_key: + default: +issue_list_default_columns: + serialized: true + default: + - tracker + - status + - priority + - subject + - assigned_to + - updated_on +display_subprojects_issues: + default: 1 +issue_done_ratio: + default: 'issue_field' +default_projects_public: + default: 1 +default_projects_modules: + serialized: true + default: + - issue_tracking + - time_tracking + - news + - documents + - files + - wiki + - repository + - boards + - calendar + - gantt +# Role given to a non-admin user who creates a project +new_project_user_role_id: + format: int + default: '' +sequential_project_identifiers: + default: 0 +# encodings used to convert repository files content to UTF-8 +# multiple values accepted, comma separated +repositories_encodings: + default: '' +# encoding used to convert commit logs to UTF-8 +commit_logs_encoding: + default: 'UTF-8' +repository_log_display_limit: + format: int + default: 100 +ui_theme: + default: '' +emails_footer: + default: |- + You have received this notification because you have either subscribed to it, or are involved in it. + To change your notification preferences, please click here: http://hostname/my/account +gravatar_enabled: + default: 0 +openid: + default: 0 +gravatar_default: + default: '' +start_of_week: + default: '' +rest_api_enabled: + default: 0 +default_notification_option: + default: 'only_my_events' +emails_header: + default: '' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/63/6363e04d893f5e743cf860de53b9bf91e0dfa927.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/63/6363e04d893f5e743cf860de53b9bf91e0dfa927.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    + +

    <%= render :partial => 'link_to_functions' %>

    + +<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/63/636943525457e5c4d4d0c3e654c86a8a51ed59f5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/63/636943525457e5c4d4d0c3e654c86a8a51ed59f5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,159 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::I18nTest < ActiveSupport::TestCase + include Redmine::I18n + include ActionView::Helpers::NumberHelper + + def setup + @hook_module = Redmine::Hook + end + + def test_date_format_default + set_language_if_valid 'en' + today = Date.today + Setting.date_format = '' + assert_equal I18n.l(today), format_date(today) + end + + def test_date_format + set_language_if_valid 'en' + today = Date.today + Setting.date_format = '%d %m %Y' + assert_equal today.strftime('%d %m %Y'), format_date(today) + end + + def test_date_and_time_for_each_language + Setting.date_format = '' + valid_languages.each do |lang| + set_language_if_valid lang + assert_nothing_raised "#{lang} failure" do + format_date(Date.today) + format_time(Time.now) + format_time(Time.now, false) + assert_not_equal 'default', ::I18n.l(Date.today, :format => :default), + "date.formats.default missing in #{lang}" + assert_not_equal 'time', ::I18n.l(Time.now, :format => :time), + "time.formats.time missing in #{lang}" + end + assert l('date.day_names').is_a?(Array) + assert_equal 7, l('date.day_names').size + + assert l('date.month_names').is_a?(Array) + assert_equal 13, l('date.month_names').size + end + end + + def test_time_format + set_language_if_valid 'en' + now = Time.parse('2011-02-20 15:45:22') + with_settings :time_format => '%H:%M' do + with_settings :date_format => '' do + assert_equal '02/20/2011 15:45', format_time(now) + assert_equal '15:45', format_time(now, false) + end + with_settings :date_format => '%Y-%m-%d' do + assert_equal '2011-02-20 15:45', format_time(now) + assert_equal '15:45', format_time(now, false) + end + end + end + + def test_time_format_default + set_language_if_valid 'en' + now = Time.parse('2011-02-20 15:45:22') + with_settings :time_format => '' do + with_settings :date_format => '' do + assert_equal '02/20/2011 03:45 pm', format_time(now) + assert_equal '03:45 pm', format_time(now, false) + end + with_settings :date_format => '%Y-%m-%d' do + assert_equal '2011-02-20 03:45 pm', format_time(now) + assert_equal '03:45 pm', format_time(now, false) + end + end + end + + def test_time_format + set_language_if_valid 'en' + now = Time.now + Setting.date_format = '%d %m %Y' + Setting.time_format = '%H %M' + assert_equal now.strftime('%d %m %Y %H %M'), format_time(now) + assert_equal now.strftime('%H %M'), format_time(now, false) + end + + def test_utc_time_format + set_language_if_valid 'en' + now = Time.now + Setting.date_format = '%d %m %Y' + Setting.time_format = '%H %M' + assert_equal now.strftime('%d %m %Y %H %M'), format_time(now.utc) + assert_equal now.strftime('%H %M'), format_time(now.utc, false) + end + + def test_number_to_human_size_for_each_language + valid_languages.each do |lang| + set_language_if_valid lang + assert_nothing_raised "#{lang} failure" do + number_to_human_size(1024*1024*4) + end + end + end + + def test_valid_languages + assert valid_languages.is_a?(Array) + assert valid_languages.first.is_a?(Symbol) + end + + def test_valid_language + to_test = {'fr' => :fr, + 'Fr' => :fr, + 'zh' => :zh, + 'zh-tw' => :"zh-TW", + 'zh-TW' => :"zh-TW", + 'zh-ZZ' => nil } + to_test.each {|lang, expected| assert_equal expected, find_language(lang)} + end + + def test_fallback + ::I18n.backend.store_translations(:en, {:untranslated => "Untranslated string"}) + ::I18n.locale = 'en' + assert_equal "Untranslated string", l(:untranslated) + ::I18n.locale = 'fr' + assert_equal "Untranslated string", l(:untranslated) + + ::I18n.backend.store_translations(:fr, {:untranslated => "Pas de traduction"}) + ::I18n.locale = 'en' + assert_equal "Untranslated string", l(:untranslated) + ::I18n.locale = 'fr' + assert_equal "Pas de traduction", l(:untranslated) + end + + def test_utf8 + set_language_if_valid 'ja' + str_ja_yes = "\xe3\x81\xaf\xe3\x81\x84" + i18n_ja_yes = l(:general_text_Yes) + if str_ja_yes.respond_to?(:force_encoding) + str_ja_yes.force_encoding('UTF-8') + assert_equal "UTF-8", i18n_ja_yes.encoding.to_s + end + assert_equal str_ja_yes, i18n_ja_yes + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/63/63a7211a153e3b9ab2735ad4855dd71d9e56bc6b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/63/63a7211a153e3b9ab2735ad4855dd71d9e56bc6b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddIssueCategoriesAssignedToId < ActiveRecord::Migration + def self.up + add_column :issue_categories, :assigned_to_id, :integer + end + + def self.down + remove_column :issue_categories, :assigned_to_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/63/63ab165c5d9aefdb49df1a8bc5d36c75c1c75e7e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/63/63ab165c5d9aefdb49df1a8bc5d36c75c1c75e7e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,151 @@ +require File.expand_path('../../test_helper', __FILE__) + +class ContextMenusControllerTest < ActionController::TestCase + fixtures :projects, + :trackers, + :projects_trackers, + :roles, + :member_roles, + :members, + :auth_sources, + :enabled_modules, + :workflows, + :journals, :journal_details, + :versions, + :issues, :issue_statuses, :issue_categories, + :users, + :enumerations + + def test_context_menu_one_issue + @request.session[:user_id] = 2 + get :issues, :ids => [1] + assert_response :success + assert_template 'context_menu' + assert_tag :tag => 'a', :content => 'Edit', + :attributes => { :href => '/issues/1/edit', + :class => 'icon-edit' } + assert_tag :tag => 'a', :content => 'Closed', + :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bstatus_id%5D=5', + :class => '' } + assert_tag :tag => 'a', :content => 'Immediate', + :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bpriority_id%5D=8', + :class => '' } + assert_no_tag :tag => 'a', :content => 'Inactive Priority' + # Versions + assert_tag :tag => 'a', :content => '2.0', + :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bfixed_version_id%5D=3', + :class => '' } + assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0', + :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bfixed_version_id%5D=4', + :class => '' } + + assert_tag :tag => 'a', :content => 'Dave Lopper', + :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bassigned_to_id%5D=3', + :class => '' } + assert_tag :tag => 'a', :content => 'Duplicate', + :attributes => { :href => '/projects/ecookbook/issues/1/copy', + :class => 'icon-duplicate' } + assert_tag :tag => 'a', :content => 'Copy', + :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&ids%5B%5D=1', + :class => 'icon-copy' } + assert_tag :tag => 'a', :content => 'Move', + :attributes => { :href => '/issues/move/new?ids%5B%5D=1', + :class => 'icon-move' } + assert_tag :tag => 'a', :content => 'Delete', + :attributes => { :href => '/issues/destroy?ids%5B%5D=1', + :class => 'icon-del' } + end + + def test_context_menu_one_issue_by_anonymous + get :issues, :ids => [1] + assert_response :success + assert_template 'context_menu' + assert_tag :tag => 'a', :content => 'Delete', + :attributes => { :href => '#', + :class => 'icon-del disabled' } + end + + def test_context_menu_multiple_issues_of_same_project + @request.session[:user_id] = 2 + get :issues, :ids => [1, 2] + assert_response :success + assert_template 'context_menu' + assert_not_nil assigns(:issues) + assert_equal [1, 2], assigns(:issues).map(&:id).sort + + ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&') + assert_tag :tag => 'a', :content => 'Edit', + :attributes => { :href => "/issues/bulk_edit?#{ids}", + :class => 'icon-edit' } + assert_tag :tag => 'a', :content => 'Closed', + :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bstatus_id%5D=5", + :class => '' } + assert_tag :tag => 'a', :content => 'Immediate', + :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bpriority_id%5D=8", + :class => '' } + assert_tag :tag => 'a', :content => 'Dave Lopper', + :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bassigned_to_id%5D=3", + :class => '' } + assert_tag :tag => 'a', :content => 'Copy', + :attributes => { :href => "/issues/move/new?copy_options%5Bcopy%5D=t&#{ids}", + :class => 'icon-copy' } + assert_tag :tag => 'a', :content => 'Move', + :attributes => { :href => "/issues/move/new?#{ids}", + :class => 'icon-move' } + assert_tag :tag => 'a', :content => 'Delete', + :attributes => { :href => "/issues/destroy?#{ids}", + :class => 'icon-del' } + end + + def test_context_menu_multiple_issues_of_different_projects + @request.session[:user_id] = 2 + get :issues, :ids => [1, 2, 6] + assert_response :success + assert_template 'context_menu' + assert_not_nil assigns(:issues) + assert_equal [1, 2, 6], assigns(:issues).map(&:id).sort + + ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&') + assert_tag :tag => 'a', :content => 'Edit', + :attributes => { :href => "/issues/bulk_edit?#{ids}", + :class => 'icon-edit' } + assert_tag :tag => 'a', :content => 'Closed', + :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bstatus_id%5D=5", + :class => '' } + assert_tag :tag => 'a', :content => 'Immediate', + :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bpriority_id%5D=8", + :class => '' } + assert_tag :tag => 'a', :content => 'John Smith', + :attributes => { :href => "/issues/bulk_edit?#{ids}&issue%5Bassigned_to_id%5D=2", + :class => '' } + assert_tag :tag => 'a', :content => 'Delete', + :attributes => { :href => "/issues/destroy?#{ids}", + :class => 'icon-del' } + end + + def test_context_menu_issue_visibility + get :issues, :ids => [1, 4] + assert_response :success + assert_template 'context_menu' + assert_equal [1], assigns(:issues).collect(&:id) + end + + def test_time_entries_context_menu + @request.session[:user_id] = 2 + get :time_entries, :ids => [1, 2] + assert_response :success + assert_template 'time_entries' + assert_tag 'a', :content => 'Edit' + assert_no_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/} + end + + def test_time_entries_context_menu_without_edit_permission + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :edit_time_entries + + get :time_entries, :ids => [1, 2] + assert_response :success + assert_template 'time_entries' + assert_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/64036c3be2c819ccb0429f69ed2813c1f8f00a12.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/64036c3be2c819ccb0429f69ed2813c1f8f00a12.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,250 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'queries_controller' + +# Re-raise errors caught by the controller. +class QueriesController; def rescue_action(e) raise e end; end + +class QueriesControllerTest < ActionController::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values, :queries + + def setup + @controller = QueriesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_get_new_project_query + @request.session[:user_id] = 2 + get :new, :project_id => 1 + assert_response :success + assert_template 'new' + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query[is_public]', + :checked => nil } + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query_is_for_all', + :checked => nil, + :disabled => nil } + end + + def test_get_new_global_query + @request.session[:user_id] = 2 + get :new + assert_response :success + assert_template 'new' + assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query[is_public]' } + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query_is_for_all', + :checked => 'checked', + :disabled => nil } + end + + def test_new_project_public_query + @request.session[:user_id] = 2 + post :create, + :project_id => 'ecookbook', + :default_columns => '1', + :f => ["status_id", "assigned_to_id"], + :op => {"assigned_to_id" => "=", "status_id" => "o"}, + :v => { "assigned_to_id" => ["1"], "status_id" => ["1"]}, + :query => {"name" => "test_new_project_public_query", "is_public" => "1"} + + q = Query.find_by_name('test_new_project_public_query') + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q + assert q.is_public? + assert q.has_default_columns? + assert q.valid? + end + + def test_new_project_private_query + @request.session[:user_id] = 3 + post :create, + :project_id => 'ecookbook', + :default_columns => '1', + :fields => ["status_id", "assigned_to_id"], + :operators => {"assigned_to_id" => "=", "status_id" => "o"}, + :values => { "assigned_to_id" => ["1"], "status_id" => ["1"]}, + :query => {"name" => "test_new_project_private_query", "is_public" => "1"} + + q = Query.find_by_name('test_new_project_private_query') + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q + assert !q.is_public? + assert q.has_default_columns? + assert q.valid? + end + + def test_new_global_private_query_with_custom_columns + @request.session[:user_id] = 3 + post :create, + :fields => ["status_id", "assigned_to_id"], + :operators => {"assigned_to_id" => "=", "status_id" => "o"}, + :values => { "assigned_to_id" => ["me"], "status_id" => ["1"]}, + :query => {"name" => "test_new_global_private_query", "is_public" => "1"}, + :c => ["", "tracker", "subject", "priority", "category"] + + q = Query.find_by_name('test_new_global_private_query') + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q + assert !q.is_public? + assert !q.has_default_columns? + assert_equal [:tracker, :subject, :priority, :category], q.columns.collect {|c| c.name} + assert q.valid? + end + + def test_new_global_query_with_custom_filters + @request.session[:user_id] = 3 + post :create, + :fields => ["assigned_to_id"], + :operators => {"assigned_to_id" => "="}, + :values => { "assigned_to_id" => ["me"]}, + :query => {"name" => "test_new_global_query"} + + q = Query.find_by_name('test_new_global_query') + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q + assert !q.has_filter?(:status_id) + assert_equal ['assigned_to_id'], q.filters.keys + assert q.valid? + end + + def test_new_with_sort + @request.session[:user_id] = 1 + post :create, + :default_columns => '1', + :operators => {"status_id" => "o"}, + :values => {"status_id" => ["1"]}, + :query => {:name => "test_new_with_sort", + :is_public => "1", + :sort_criteria => {"0" => ["due_date", "desc"], "1" => ["tracker", ""]}} + + query = Query.find_by_name("test_new_with_sort") + assert_not_nil query + assert_equal [['due_date', 'desc'], ['tracker', 'asc']], query.sort_criteria + end + + def test_get_edit_global_public_query + @request.session[:user_id] = 1 + get :edit, :id => 4 + assert_response :success + assert_template 'edit' + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query[is_public]', + :checked => 'checked' } + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query_is_for_all', + :checked => 'checked', + :disabled => 'disabled' } + end + + def test_edit_global_public_query + @request.session[:user_id] = 1 + put :update, + :id => 4, + :default_columns => '1', + :fields => ["status_id", "assigned_to_id"], + :operators => {"assigned_to_id" => "=", "status_id" => "o"}, + :values => { "assigned_to_id" => ["1"], "status_id" => ["1"]}, + :query => {"name" => "test_edit_global_public_query", "is_public" => "1"} + + assert_redirected_to :controller => 'issues', :action => 'index', :query_id => 4 + q = Query.find_by_name('test_edit_global_public_query') + assert q.is_public? + assert q.has_default_columns? + assert q.valid? + end + + def test_get_edit_global_private_query + @request.session[:user_id] = 3 + get :edit, :id => 3 + assert_response :success + assert_template 'edit' + assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query[is_public]' } + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query_is_for_all', + :checked => 'checked', + :disabled => 'disabled' } + end + + def test_edit_global_private_query + @request.session[:user_id] = 3 + put :update, + :id => 3, + :default_columns => '1', + :fields => ["status_id", "assigned_to_id"], + :operators => {"assigned_to_id" => "=", "status_id" => "o"}, + :values => { "assigned_to_id" => ["me"], "status_id" => ["1"]}, + :query => {"name" => "test_edit_global_private_query", "is_public" => "1"} + + assert_redirected_to :controller => 'issues', :action => 'index', :query_id => 3 + q = Query.find_by_name('test_edit_global_private_query') + assert !q.is_public? + assert q.has_default_columns? + assert q.valid? + end + + def test_get_edit_project_private_query + @request.session[:user_id] = 3 + get :edit, :id => 2 + assert_response :success + assert_template 'edit' + assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query[is_public]' } + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query_is_for_all', + :checked => nil, + :disabled => nil } + end + + def test_get_edit_project_public_query + @request.session[:user_id] = 2 + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query[is_public]', + :checked => 'checked' + } + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'query_is_for_all', + :checked => nil, + :disabled => 'disabled' } + end + + def test_get_edit_sort_criteria + @request.session[:user_id] = 1 + get :edit, :id => 5 + assert_response :success + assert_template 'edit' + assert_tag :tag => 'select', :attributes => { :name => 'query[sort_criteria][0][]' }, + :child => { :tag => 'option', :attributes => { :value => 'priority', + :selected => 'selected' } } + assert_tag :tag => 'select', :attributes => { :name => 'query[sort_criteria][0][]' }, + :child => { :tag => 'option', :attributes => { :value => 'desc', + :selected => 'selected' } } + end + + def test_destroy + @request.session[:user_id] = 2 + delete :destroy, :id => 1 + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :set_filter => 1, :query_id => nil + assert_nil Query.find_by_id(1) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/6405eab4a4b9b92dcff2e2c358f9c728d763c20e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/6405eab4a4b9b92dcff2e2c358f9c728d763c20e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../test_helper' + +module CollectiveIdea + module Acts #:nodoc: + module NestedSet #:nodoc: + class AwesomeNestedSetTest < Test::Unit::TestCase + include Helper + fixtures :categories + + def test_nested_set_options + expected = [ + [" Top Level", 1], + ["- Child 1", 2], + ['- Child 2', 3], + ['-- Child 2.1', 4], + ['- Child 3', 5], + [" Top Level 2", 6] + ] + actual = nested_set_options(Category) do |c| + "#{'-' * c.level} #{c.name}" + end + assert_equal expected, actual + end + + def test_nested_set_options_with_mover + expected = [ + [" Top Level", 1], + ["- Child 1", 2], + ['- Child 3', 5], + [" Top Level 2", 6] + ] + actual = nested_set_options(Category, categories(:child_2)) do |c| + "#{'-' * c.level} #{c.name}" + end + assert_equal expected, actual + end + + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/64193c4fd7f0ccb5b77918982fede9d3c48236e0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/64193c4fd7f0ccb5b77918982fede9d3c48236e0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +class ChangeProjectsDescriptionToText < ActiveRecord::Migration + def self.up + change_column :projects, :description, :text, :null => true, :default => nil + end + + def self.down + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/642c69f33e7614a977979878c1ccc6e65c0c0226.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/642c69f33e7614a977979878c1ccc6e65c0c0226.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/breakpointer' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/643e94db4aed32471bbf1bd1d5bd4f887d610b4b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/643e94db4aed32471bbf1bd1d5bd4f887d610b4b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,100 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class AttachmentsController < ApplicationController + before_filter :find_project + before_filter :file_readable, :read_authorize, :except => :destroy + before_filter :delete_authorize, :only => :destroy + + accept_api_auth :show, :download + + def show + respond_to do |format| + format.html { + if @attachment.is_diff? + @diff = File.new(@attachment.diskfile, "rb").read + @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' + @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) + # Save diff type as user preference + if User.current.logged? && @diff_type != User.current.pref[:diff_type] + User.current.pref[:diff_type] = @diff_type + User.current.preference.save + end + render :action => 'diff' + elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte + @content = File.new(@attachment.diskfile, "rb").read + render :action => 'file' + else + download + end + } + format.api + end + end + + def download + if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) + @attachment.increment_download + end + + # images are sent inline + send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), + :type => detect_content_type(@attachment), + :disposition => (@attachment.image? ? 'inline' : 'attachment') + + end + + verify :method => :delete, :only => :destroy + def destroy + # Make sure association callbacks are called + @attachment.container.attachments.delete(@attachment) + redirect_to :back + rescue ::ActionController::RedirectBackError + redirect_to :controller => 'projects', :action => 'show', :id => @project + end + +private + def find_project + @attachment = Attachment.find(params[:id]) + # Show 404 if the filename in the url is wrong + raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename + @project = @attachment.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Checks that the file exists and is readable + def file_readable + @attachment.readable? ? true : render_404 + end + + def read_authorize + @attachment.visible? ? true : deny_access + end + + def delete_authorize + @attachment.deletable? ? true : deny_access + end + + def detect_content_type(attachment) + content_type = attachment.content_type + if content_type.blank? + content_type = Redmine::MimeType.of(attachment.filename) + end + content_type.to_s + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/6453475106e156ddd20fc32236e1e2b88b1df72a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/6453475106e156ddd20fc32236e1e2b88b1df72a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,110 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 ProjectsHelper + def link_to_version(version, options = {}) + return '' unless version && version.is_a?(Version) + link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options + end + + def project_settings_tabs + tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, + {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, + {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural}, + {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural}, + {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural}, + {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki}, + {:name => 'repository', :action => :manage_repository, :partial => 'projects/settings/repository', :label => :label_repository}, + {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}, + {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities} + ] + tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} + end + + def parent_project_select_tag(project) + selected = project.parent + # retrieve the requested parent project + parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id] + if parent_id + selected = (parent_id.blank? ? nil : Project.find(parent_id)) + end + + options = '' + options << "" if project.allowed_parents.include?(nil) + options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) + content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') + end + + # Renders a tree of projects as a nested set of unordered lists + # The given collection may be a subset of the whole project tree + # (eg. some intermediate nodes are private and can not be seen) + def render_project_hierarchy(projects) + s = '' + if projects.any? + ancestors = [] + original_project = @project + projects.each do |project| + # set the project environment to please macros. + @project = project + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) + s << "
      \n" + else + ancestors.pop + s << "" + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "
    \n" + end + end + classes = (ancestors.empty? ? 'root' : 'child') + s << "
  • " + + link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") + s << "
    #{textilizable(project.short_description, :project => project)}
    " unless project.description.blank? + s << "
    \n" + ancestors << project + end + s << ("
  • \n" * ancestors.size) + @project = original_project + end + s.html_safe + end + + # Returns a set of options for a select field, grouped by project. + def version_options_for_select(versions, selected=nil) + grouped = Hash.new {|h,k| h[k] = []} + versions.each do |version| + grouped[version.project.name] << [version.name, version.id] + end + # Add in the selected + if selected && !versions.include?(selected) + grouped[selected.project.name] << [selected.name, selected.id] + end + + if grouped.keys.size > 1 + grouped_options_for_select(grouped, selected && selected.id) + else + options_for_select((grouped.values.first || []), selected && selected.id) + end + end + + def format_version_sharing(sharing) + sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) + l("label_version_sharing_#{sharing}") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/647e8421eaa1d38af5694b4ab4b6ee0bc18f034f.svn-base Binary file .svn/pristine/64/647e8421eaa1d38af5694b4ab4b6ee0bc18f034f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/64d46ee6e8251803e7c04c919d09da2321bf22b4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/64d46ee6e8251803e7c04c919d09da2321bf22b4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class AppAndPluginLibModel < ActiveRecord::Base + def self.report_location; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/64/64d9599d84742c6f276c43c19ddf01ad011835e1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/64/64d9599d84742c6f276c43c19ddf01ad011835e1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar RU language +// Translation: Sly Golovanov, http://golovanov.net, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("воскресенье", + "понедельник", + "вторник", + "среда", + "четверг", + "пятница", + "суббота", + "воскресенье"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("вск", + "пон", + "втр", + "срд", + "чет", + "пят", + "суб", + "вск"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("январь", + "февраль", + "март", + "апрель", + "май", + "июнь", + "июль", + "август", + "сентябрь", + "октябрь", + "ноябрь", + "декабрь"); + +// short month names +Calendar._SMN = new Array +("янв", + "фев", + "мар", + "апр", + "май", + "июн", + "июл", + "авг", + "сен", + "окт", + "ноя", + "дек"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "О календаре..."; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Как выбрать дату:\n" + +"- При помощи кнопок \xab, \xbb можно выбрать год\n" + +"- При помощи кнопок " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " можно выбрать месяц\n" + +"- Подержите эти кнопки нажатыми, чтобы появилось меню быстрого выбора."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Как выбрать время:\n" + +"- При клике на часах или минутах они увеличиваются\n" + +"- при клике с нажатой клавишей Shift они уменьшаются\n" + +"- если нажать и двигать мышкой влево/вправо, они будут меняться быстрее."; + +Calendar._TT["PREV_YEAR"] = "На год назад (удерживать для меню)"; +Calendar._TT["PREV_MONTH"] = "На месяц назад (удерживать для меню)"; +Calendar._TT["GO_TODAY"] = "Сегодня"; +Calendar._TT["NEXT_MONTH"] = "На месяц вперед (удерживать для меню)"; +Calendar._TT["NEXT_YEAR"] = "На год вперед (удерживать для меню)"; +Calendar._TT["SEL_DATE"] = "Выберите дату"; +Calendar._TT["DRAG_TO_MOVE"] = "Перетаскивайте мышкой"; +Calendar._TT["PART_TODAY"] = " (сегодня)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Первый день недели будет %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Закрыть"; +Calendar._TT["TODAY"] = "Сегодня"; +Calendar._TT["TIME_PART"] = "(Shift-)клик или нажать и двигать"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%e %b, %a"; + +Calendar._TT["WK"] = "нед"; +Calendar._TT["TIME"] = "Время:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/6514caff2f9e9a210142d5cdd20b0807c7fb9b2f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/6514caff2f9e9a210142d5cdd20b0807c7fb9b2f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 IssueCategoriesHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/652cee5115cd618a1d7b1b071076d6439b22f7ec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/652cee5115cd618a1d7b1b071076d6439b22f7ec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,60 @@ +class ContextMenusController < ApplicationController + helper :watchers + helper :issues + + def issues + @issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project) + + if (@issues.size == 1) + @issue = @issues.first + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + else + @allowed_statuses = @issues.map do |i| + i.new_statuses_allowed_to(User.current) + end.inject do |memo,s| + memo & s + end + end + @projects = @issues.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + + @can = {:edit => User.current.allowed_to?(:edit_issues, @projects), + :log_time => (@project && User.current.allowed_to?(:log_time, @project)), + :update => (User.current.allowed_to?(:edit_issues, @projects) || (User.current.allowed_to?(:change_status, @projects) && !@allowed_statuses.blank?)), + :move => (@project && User.current.allowed_to?(:move_issues, @project)), + :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)), + :delete => User.current.allowed_to?(:delete_issues, @projects) + } + if @project + if @issue + @assignables = @issue.assignable_users + else + @assignables = @project.assignable_users + end + @trackers = @project.trackers + else + #when multiple projects, we only keep the intersection of each set + @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a} + @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t} + end + + @priorities = IssuePriority.active.reverse + @statuses = IssueStatus.find(:all, :order => 'position') + @back = back_url + + render :layout => false + end + + def time_entries + @time_entries = TimeEntry.all( + :conditions => {:id => params[:ids]}, :include => :project) + @projects = @time_entries.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + @activities = TimeEntryActivity.shared.active + @can = {:edit => User.current.allowed_to?(:edit_time_entries, @projects), + :delete => User.current.allowed_to?(:edit_time_entries, @projects) + } + @back = back_url + render :layout => false + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/65538df31e36234b3f7b2e1412df21f4d984c90c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/65538df31e36234b3f7b2e1412df21f4d984c90c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +

    <%= l(:label_settings) %>: <%=h @plugin.name %>

    + +
    +<% form_tag({:action => 'plugin'}) do %> +
    +<%= render :partial => @partial, :locals => {:settings => @settings}%> +
    +<%= submit_tag l(:button_apply) %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/65761dc96875890d24f44eea0c8e51f6640664b9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/65761dc96875890d24f44eea0c8e51f6640664b9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,173 @@ +var commits = chunk.commits, + comms = {}, + pixelsX = [], + pixelsY = [], + mmax = Math.max, + max_rdmid = 0, + max_space = 0, + parents = {}; +for (var i = 0, ii = commits.length; i < ii; i++) { + for (var j = 0, jj = commits[i].parents.length; j < jj; j++) { + parents[commits[i].parents[j][0]] = true; + } + max_rdmid = Math.max(max_rdmid, commits[i].rdmid); + max_space = Math.max(max_space, commits[i].space); +} + +for (i = 0; i < ii; i++) { + if (commits[i].scmid in parents) { + commits[i].isParent = true; + } + comms[commits[i].scmid] = commits[i]; +} +var colors = ["#000"]; +for (var k = 0; k < max_space; k++) { + colors.push(Raphael.getColor()); +} + +function branchGraph(holder) { + var xstep = 20; + var ystep = $$('tr.changeset')[0].getHeight(); + var ch, cw; + cw = max_space * xstep + xstep; + ch = max_rdmid * ystep + ystep; + var r = Raphael("holder", cw, ch), + top = r.set(); + var cuday = 0, cumonth = ""; + + for (i = 0; i < ii; i++) { + var x, y; + y = 10 + ystep *(max_rdmid - commits[i].rdmid); + x = 3 + xstep * commits[i].space; + var stroke = "none"; + r.circle(x, y, 3).attr({fill: colors[commits[i].space], stroke: stroke}); + if (commits[i].refs != null && commits[i].refs != "") { + var longrefs = commits[i].refs + var shortrefs = commits[i].refs; + if (shortrefs.length > 15) { + shortrefs = shortrefs.substr(0,13) + "..."; + } + var t = r.text(x+5,y+5,shortrefs).attr({font: "12px Fontin-Sans, Arial", fill: "#666", + title: longrefs, cursor: "pointer", rotation: "0"}); + + var textbox = t.getBBox(); + t.translate(textbox.width / 2, textbox.height / -3); + } + for (var j = 0, jj = commits[i].parents.length; j < jj; j++) { + var c = comms[commits[i].parents[j][0]]; + var p,arrow; + if (c) { + var cy, cx; + cy = 10 + ystep * (max_rdmid - c.rdmid), + cx = 3 + xstep * c.space; + + if (c.space == commits[i].space) { + p = r.path("M" + x + "," + y + "L" + cx + "," + cy); + } else { + p = r.path(["M", x, y, "C",x,y,x, y+(cy-y)/2,x+(cx-x)/2, y+(cy-y)/2, + "C", x+(cx-x)/2,y+(cy-y)/2, cx, cy-(cy-y)/2, cx, cy]); + } + } else { + p = r.path("M" + x + "," + y + "L" + x + "," + ch); + } + p.attr({stroke: colors[commits[i].space], "stroke-width": 1.5}); + } + (function (c, x, y) { + top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, + cursor: "pointer", href: commits[i].href}) + .hover(function () {}, function () {}) + ); + }(commits[i], x, y)); + } + top.toFront(); + var hw = holder.offsetWidth, + hh = holder.offsetHeight, + drag, + dragger = function (e) { + if (drag) { + e = e || window.event; + holder.scrollLeft = drag.sl - (e.clientX - drag.x); + holder.scrollTop = drag.st - (e.clientY - drag.y); + } + }; + holder.onmousedown = function (e) { + e = e || window.event; + drag = {x: e.clientX, y: e.clientY, st: holder.scrollTop, sl: holder.scrollLeft}; + document.onmousemove = dragger; + }; + document.onmouseup = function () { + drag = false; + document.onmousemove = null; + }; + holder.scrollLeft = cw; +}; + +Raphael.fn.popupit = function (x, y, set, dir, size) { + dir = dir == null ? 2 : dir; + size = size || 5; + x = Math.round(x); + y = Math.round(y); + var bb = set.getBBox(), + w = Math.round(bb.width / 2), + h = Math.round(bb.height / 2), + dx = [0, w + size * 2, 0, -w - size * 2], + dy = [-h * 2 - size * 3, -h - size, 0, -h - size], + p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), + 0, "a", size, size, 0, 0, 1, -size, -size, + "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, + -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, + "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), + 0, "a", size, size, 0, 0, 1, size, size, + "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, + mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, + "l", -mmax(w - size, 0), 0, "z"].join(","), + xy = [{x: x, y: y + size * 2 + h}, + {x: x - size * 2 - w, y: y}, + {x: x, y: y - size * 2 - h}, + {x: x + size * 2 + w, y: y}] + [dir]; + set.translate(xy.x - w - bb.x, xy.y - h - bb.y); + return this.set(this.path(p).attr({fill: "#234", stroke: "none"}) + .insertBefore(set.node ? set : set[0]), set); +}; + +Raphael.fn.popup = function (x, y, text, dir, size) { + dir = dir == null ? 2 : dir > 3 ? 3 : dir; + size = size || 5; + text = text || "$9.99"; + var res = this.set(), + d = 3; + res.push(this.path().attr({fill: "#000", stroke: "#000"})); + res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"})); + res.update = function (X, Y, withAnimation) { + X = X || x; + Y = Y || y; + var bb = this[1].getBBox(), + w = bb.width / 2, + h = bb.height / 2, + dx = [0, w + size * 2, 0, -w - size * 2], + dy = [-h * 2 - size * 3, -h - size, 0, -h - size], + p = ["M", X - dx[dir], Y - dy[dir], "l", -size, (dir == 2) * -size, + -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, + "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, + 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, + "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), + 0, "a", size, size, 0, 0, 1, size, size, + "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, + mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, + "l", -mmax(w - size, 0), 0, "z"].join(","), + xy = [{x: X, y: Y + size * 2 + h}, + {x: X - size * 2 - w, y: Y}, + {x: X, y: Y - size * 2 - h}, + {x: X + size * 2 + w, y: Y}] + [dir]; + xy.path = p; + if (withAnimation) { + this.animate(xy, 500, ">"); + } else { + this.attr(xy); + } + return this; + }; + return res.update(x, y); +}; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/657bd14b118043b9ebda19a4d6192af1ad0ce4ac.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/657bd14b118043b9ebda19a4d6192af1ad0ce4ac.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,60 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +From: "John Smith" +To: +Subject: New ticket on a given project +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris --- Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +--- This line starts with a delimiter and should not be stripped + +This paragraph is before delimiters. + +BREAK + +This paragraph is between delimiters. + +--- + +This paragraph is after the delimiter so it shouldn't appear. + +Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque +sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. +Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, +dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, +massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo +pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. + +Project: onlinestore +Status: Resolved +due date: 2010-12-31 +Start Date:2010-01-01 +Assigned to: John Smith +fixed version: alpha +estimated hours: 2.5 +done ratio: 30 + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/659cc1b107566502a54373a80e2f28e678539ea0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/659cc1b107566502a54373a80e2f28e678539ea0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,140 @@ +module CodeRay +module Scanners + + # Scanner for YAML. + # + # Based on the YAML scanner from Syntax by Jamis Buck. + class YAML < Scanner + + register_for :yaml + file_extension 'yml' + + KINDS_NOT_LOC = :all + + protected + + def scan_tokens encoder, options + + state = :initial + key_indent = string_indent = 0 + + until eos? + + key_indent = nil if bol? + + if match = scan(/ +[\t ]*/) + encoder.text_token match, :space + + elsif match = scan(/\n+/) + encoder.text_token match, :space + state = :initial if match.index(?\n) + + elsif match = scan(/#.*/) + encoder.text_token match, :comment + + elsif bol? and case + when match = scan(/---|\.\.\./) + encoder.begin_group :head + encoder.text_token match, :head + encoder.end_group :head + next + when match = scan(/%.*/) + encoder.text_token match, :doctype + next + end + + elsif state == :value and case + when !check(/(?:"[^"]*")(?=: |:$)/) && match = scan(/"/) + encoder.begin_group :string + encoder.text_token match, :delimiter + encoder.text_token match, :content if match = scan(/ [^"\\]* (?: \\. [^"\\]* )* /mx) + encoder.text_token match, :delimiter if match = scan(/"/) + encoder.end_group :string + next + when match = scan(/[|>][-+]?/) + encoder.begin_group :string + encoder.text_token match, :delimiter + string_indent = key_indent || column(pos - match.size) - 1 + encoder.text_token matched, :content if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) + encoder.end_group :string + next + when match = scan(/(?![!"*&]).+?(?=$|\s+#)/) + encoder.begin_group :string + encoder.text_token match, :content + string_indent = key_indent || column(pos - match.size) - 1 + encoder.text_token matched, :content if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) + encoder.end_group :string + next + end + + elsif case + when match = scan(/[-:](?= |$)/) + state = :value if state == :colon && (match == ':' || match == '-') + state = :value if state == :initial && match == '-' + encoder.text_token match, :operator + next + when match = scan(/[,{}\[\]]/) + encoder.text_token match, :operator + next + when state == :initial && match = scan(/[\w.() ]*\S(?= *:(?: |$))/) + encoder.text_token match, :key + key_indent = column(pos - match.size) - 1 + state = :colon + next + when match = scan(/(?:"[^"\n]*"|'[^'\n]*')(?= *:(?: |$))/) + encoder.begin_group :key + encoder.text_token match[0,1], :delimiter + encoder.text_token match[1..-2], :content + encoder.text_token match[-1,1], :delimiter + encoder.end_group :key + key_indent = column(pos - match.size) - 1 + state = :colon + next + when match = scan(/(![\w\/]+)(:([\w:]+))?/) + encoder.text_token self[1], :type + if self[2] + encoder.text_token ':', :operator + encoder.text_token self[3], :class + end + next + when match = scan(/&\S+/) + encoder.text_token match, :variable + next + when match = scan(/\*\w+/) + encoder.text_token match, :global_variable + next + when match = scan(/< + AddHandler fastcgi-script .fcgi + + + AddHandler fcgid-script .fcgi + + + AddHandler cgi-script .cgi + +Options +FollowSymLinks +ExecCGI + +# If you don't want Rails to look in certain directories, +# use the following rewrite rules so that Apache won't rewrite certain requests +# +# Example: +# RewriteCond %{REQUEST_URI} ^/notrails.* +# RewriteRule .* - [L] + +# Redirect all requests not available on the filesystem to Rails +# By default the cgi dispatcher is used which is very slow +# +# For better performance replace the dispatcher with the fastcgi one +# +# Example: +# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] +RewriteEngine On + +# If your Rails application is accessed via an Alias directive, +# then you MUST also set the RewriteBase in this htaccess file. +# +# Example: +# Alias /myrailsapp /path/to/myrailsapp/public +# RewriteBase /myrailsapp + +RewriteRule ^$ index.html [QSA] +RewriteRule ^([^.]+)$ $1.html [QSA] +RewriteCond %{REQUEST_FILENAME} !-f + + RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] + + + RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] + + + RewriteRule ^(.*)$ dispatch.cgi [QSA,L] + + +# In case Rails experiences terminal errors +# Instead of displaying this message you can supply a file here which will be rendered instead +# +# Example: +# ErrorDocument 500 /500.html + +ErrorDocument 500 "

    Application error

    Rails application failed to start properly" \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/65c5b75bcbba1fbaf22708af1f4a17c1f33951f9.svn-base Binary file .svn/pristine/65/65c5b75bcbba1fbaf22708af1f4a17c1f33951f9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/65e2150090afe156bea78b2331174b4febb817ab.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/65e2150090afe156bea78b2331174b4febb817ab.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +--- +time_entries_001: + created_on: 2007-03-23 12:54:18 +01:00 + tweek: 12 + tmonth: 3 + project_id: 1 + comments: My hours + updated_on: 2007-03-23 12:54:18 +01:00 + activity_id: 9 + spent_on: 2007-03-23 + issue_id: 1 + id: 1 + hours: 4.25 + user_id: 2 + tyear: 2007 +time_entries_002: + created_on: 2007-03-23 14:11:04 +01:00 + tweek: 11 + tmonth: 3 + project_id: 1 + comments: "" + updated_on: 2007-03-23 14:11:04 +01:00 + activity_id: 9 + spent_on: 2007-03-12 + issue_id: 1 + id: 2 + hours: 150.0 + user_id: 1 + tyear: 2007 +time_entries_003: + created_on: 2007-04-21 12:20:48 +02:00 + tweek: 16 + tmonth: 4 + project_id: 1 + comments: "" + updated_on: 2007-04-21 12:20:48 +02:00 + activity_id: 9 + spent_on: 2007-04-21 + issue_id: 3 + id: 3 + hours: 1.0 + user_id: 1 + tyear: 2007 +time_entries_004: + created_on: 2007-04-22 12:20:48 +02:00 + tweek: 16 + tmonth: 4 + project_id: 3 + comments: Time spent on a subproject + updated_on: 2007-04-22 12:20:48 +02:00 + activity_id: 10 + spent_on: 2007-04-22 + issue_id: + id: 4 + hours: 7.65 + user_id: 1 + tyear: 2007 +time_entries_005: + created_on: 2011-03-22 12:20:48 +02:00 + tweek: 12 + tmonth: 3 + project_id: 5 + comments: Time spent on a subproject + updated_on: 2011-03-22 12:20:48 +02:00 + activity_id: 10 + spent_on: 2011-03-22 + issue_id: + id: 5 + hours: 7.65 + user_id: 1 + tyear: 2011 + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/65/65ef890cea4ede6b19d9b1202dd3caee109782b0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/65/65ef890cea4ede6b19d9b1202dd3caee109782b0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %> + +
      +<% for detail in @journal.details %> +
    • <%= show_detail(detail, true) %>
    • +<% end %> +
    + +<%= textilizable(@journal, :notes, :only_path => false) %> +
    +<%= render :partial => "issue.html.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/66131eee4b40e2c9d9cbb2ef1cd7414a3df88d2c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/66131eee4b40e2c9d9cbb2ef1cd7414a3df88d2c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,36 @@ +module Engines + module Assets + class << self + @@readme = %{Files in this directory are automatically generated from your plugins. +They are copied from the 'assets' directories of each plugin into this directory +each time Rails starts (script/server, script/console... and so on). +Any edits you make will NOT persist across the next server restart; instead you +should edit the files within the /assets/ directory itself.} + + # Ensure that the plugin asset subdirectory of RAILS_ROOT/public exists, and + # that we've added a little warning message to instruct developers not to mess with + # the files inside, since they're automatically generated. + def initialize_base_public_directory + dir = Engines.public_directory + unless File.exist?(dir) + FileUtils.mkdir_p(dir) + end + readme = File.join(dir, "README") + File.open(readme, 'w') { |f| f.puts @@readme } unless File.exist?(readme) + end + + # Replicates the subdirectories under the plugins's +assets+ (or +public+) + # directory into the corresponding public directory. See also + # Plugin#public_directory for more. + def mirror_files_for(plugin) + return if plugin.public_directory.nil? + begin + Engines.mirror_files_from(plugin.public_directory, File.join(Engines.public_directory, plugin.name)) + rescue Exception => e + Engines.logger.warn "WARNING: Couldn't create the public file structure for plugin '#{plugin.name}'; Error follows:" + Engines.logger.warn e + end + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/663789eca58e876d153068fefa7b8a820ba9edca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/663789eca58e876d153068fefa7b8a820ba9edca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddWikiPagesProtected < ActiveRecord::Migration + def self.up + add_column :wiki_pages, :protected, :boolean, :default => false, :null => false + end + + def self.down + remove_column :wiki_pages, :protected + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/665335962ecb9e0672e62f281339799d0339e4f1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/665335962ecb9e0672e62f281339799d0339e4f1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/plugin' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/6653bba19b2648bf78a9587cfaa0d1c40a201319.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/6653bba19b2648bf78a9587cfaa0d1c40a201319.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +To embed TrueType fonts (.TTF) files, you need to extract the font metrics and +build the required tables using the provided utility (/fonts/ttf2ufm). + +TTF2UFM is a modified version of Mark Heath's TTF 2 PT1 converter +(http://ttf2pt1.sourceforge.net/) by Steven Wittens +(http://www.acko.net/blog/ufpdf). ttf2ufm, is included in /ttf2ufm-src. +The /fonts/ttf2ufm folder contains a compiled Windows binary. +TTF 2 UFM is identical to TTF 2 PT1 except that it also generates a .ufm file +for usage with makefontuni.php or makefontuni.rb. + + +Setting up a Truetype font for usage with UFPDF: + 1) Generate the font's .ufm metrics file by processing it with the provided + ttf2ufm program (modified ttf2pt1). For example: + $ ttf2ufm -a -F myfont.ttf + + 2) Run makefontuni_ruby.php with the .ttf and .ufm filenames as argument: + $ php -q makefontuni_ruby.php myfont.ttf myfont.ufm + + 3) Copy the resulting .rb, .z and .ctg.z file to the TCPDF font directory. + + 4) Rename php font files variations for bold and italic using the following schema: + [basic-font-name]b.rb for bold variation + [basic-font-name]i.rb for oblique variation + [basic-font-name]bi.rb for bold oblique variation + + 5) Rename the name of the font in the first line of each .rb file: + TCPDFFontDescriptor.define('dtlargotitalic') do |font| + becomes: + TCPDFFontDescriptor.define('dtlargoti') do |font| diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/66aa08562a330b659bb4aa3903977c6e536a5787.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/66aa08562a330b659bb4aa3903977c6e536a5787.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +#context-menu { position: absolute; z-index: 40; font-size: 0.9em;} + +#context-menu ul, #context-menu li, #context-menu a { + display:block; + margin:0; + padding:0; + border:0; +} + +#context-menu ul { + width:150px; + border-top:1px solid #ddd; + border-left:1px solid #ddd; + border-bottom:1px solid #777; + border-right:1px solid #777; + background:white; + list-style:none; +} + +#context-menu li { + position:relative; + padding:1px; + z-index:39; + border:1px solid white; +} +#context-menu li.folder ul { position:absolute; left:168px; /* IE6 */ top:-2px; max-height:300px; overflow:hidden; overflow-y: auto; } +#context-menu li.folder>ul { left:148px; } + +#context-menu.reverse-y li.folder>ul { top:auto; bottom:0; } +#context-menu.reverse-x li.folder ul { left:auto; right:168px; /* IE6 */ } +#context-menu.reverse-x li.folder>ul { right:148px; } + +#context-menu a { + text-decoration:none !important; + background-repeat: no-repeat; + background-position: 1px 50%; + padding: 1px 0px 1px 20px; + width:100%; /* IE */ +} +#context-menu li>a { width:auto; } /* others */ +#context-menu a.disabled, #context-menu a.disabled:hover {color: #ccc;} +#context-menu li a.submenu { background:url("../images/bullet_arrow_right.png") right no-repeat; } +#context-menu li:hover { border:1px solid gray; background-color:#eee; } +#context-menu a:hover {color:#2A5685;} +#context-menu li.folder:hover { z-index:40; } +#context-menu ul ul, #context-menu li:hover ul ul { display:none; } +#context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; } + +/* selected element */ +.context-menu-selection { background-color:#507AAA !important; color:#f8f8f8 !important; } +.context-menu-selection a, .context-menu-selection a:hover { color:#f8f8f8 !important; } +.context-menu-selection:hover { background-color:#507AAA !important; color:#f8f8f8 !important; } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/66ab50d76f6f50210c09955e4a16c4d364df47ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/66ab50d76f6f50210c09955e4a16c4d364df47ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,111 @@ +module CodeRay +module Encoders + + load :filter + + # A Filter that selects tokens based on their token kind. + # + # == Options + # + # === :exclude + # + # One or many symbols (in an Array) which shall be excluded. + # + # Default: [] + # + # === :include + # + # One or many symbols (in an array) which shall be included. + # + # Default: :all, which means all tokens are included. + # + # Exclusion wins over inclusion. + # + # See also: CommentFilter + class TokenKindFilter < Filter + + register_for :token_kind_filter + + DEFAULT_OPTIONS = { + :exclude => [], + :include => :all + } + + protected + def setup options + super + + @group_excluded = false + @exclude = options[:exclude] + @exclude = Array(@exclude) unless @exclude == :all + @include = options[:include] + @include = Array(@include) unless @include == :all + end + + def include_text_token? text, kind + include_group? kind + end + + def include_group? kind + (@include == :all || @include.include?(kind)) && + !(@exclude == :all || @exclude.include?(kind)) + end + + public + + # Add the token to the output stream if +kind+ matches the conditions. + def text_token text, kind + super if !@group_excluded && include_text_token?(text, kind) + end + + # Add the token group to the output stream if +kind+ matches the + # conditions. + # + # If it does not, all tokens inside the group are excluded from the + # stream, even if their kinds match. + def begin_group kind + if @group_excluded + @group_excluded += 1 + elsif include_group? kind + super + else + @group_excluded = 1 + end + end + + # See +begin_group+. + def begin_line kind + if @group_excluded + @group_excluded += 1 + elsif include_group? kind + super + else + @group_excluded = 1 + end + end + + # Take care of re-enabling the delegation of tokens to the output stream + # if an exluded group has ended. + def end_group kind + if @group_excluded + @group_excluded -= 1 + @group_excluded = false if @group_excluded.zero? + else + super + end + end + + # See +end_group+. + def end_line kind + if @group_excluded + @group_excluded -= 1 + @group_excluded = false if @group_excluded.zero? + else + super + end + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/66dfb65ecc4431408ec461d6daa3720b2fb4b2a0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/66dfb65ecc4431408ec461d6daa3720b2fb4b2a0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1008 @@ +ar: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: rtl + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [الاحد, الاثنين, الثلاثاء, الاربعاء, الخميس, الجمعة, السبت] + abbr_day_names: [أح, اث, ث, ار, خ, ج, س] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, كانون الثاني, شباط, آذار, نيسان, أيار, حزيران, تموز, آب, أيلول, تشرين الأول, تشرين الثاني, كانون الأول] + abbr_month_names: [~, كانون الثاني, شباط, آذار, نيسان, أيار, حزيران, تموز, آب, أيلول, تشرين الأول, تشرين الثاني, كانون الأول] + # Used in date_select and datime_select. + order: + - :السنة + - :الشهر + - :اليوم + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "صباحا" + pm: "مساءا" + + datetime: + distance_in_words: + half_a_minute: "نصف دقيقة" + less_than_x_seconds: + one: "أقل من ثانية" + other: "ثواني %{count}أقل من " + x_seconds: + one: "ثانية" + other: "%{count}ثواني " + less_than_x_minutes: + one: "أقل من دقيقة" + other: "دقائق%{count}أقل من " + x_minutes: + one: "دقيقة" + other: "%{count} دقائق" + about_x_hours: + one: "حوالي ساعة" + other: "ساعات %{count}حوالي " + x_days: + one: "يوم" + other: "%{count} أيام" + about_x_months: + one: "حوالي شهر" + other: "أشهر %{count} حوالي" + x_months: + one: "شهر" + other: "%{count} أشهر" + about_x_years: + one: "حوالي سنة" + other: "سنوات %{count}حوالي " + over_x_years: + one: "اكثر من سنة" + other: "سنوات %{count}أكثر من " + almost_x_years: + one: "تقريبا سنة" + other: "سنوات %{count} نقريبا" + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "kB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "و" + skip_last_comma: خطأ + + activerecord: + errors: + template: + header: + one: " %{model} خطأ يمنع تخزين" + other: " %{model} يمنع تخزين%{count}خطأ رقم " + messages: + inclusion: "غير مدرجة على القائمة" + exclusion: "محجوز" + invalid: "غير صالح" + confirmation: "غير متطابق" + accepted: "مقبولة" + empty: "لا يمكن ان تكون فارغة" + blank: "لا يمكن ان تكون فارغة" + too_long: " %{count}طويلة جدا، الحد الاقصى هو )" + too_short: " %{count}قصيرة جدا، الحد الادنى هو)" + wrong_length: " %{count}خطأ في الطول، يجب ان يكون )" + taken: "لقد اتخذت سابقا" + not_a_number: "ليس رقما" + not_a_date: "ليس تاريخا صالحا" + greater_than: "%{count}يجب ان تكون اكثر من " + greater_than_or_equal_to: "%{count}يجب ان تكون اكثر من او تساوي" + equal_to: "%{count}يجب ان تساوي" + less_than: " %{count}يجب ان تكون اقل من" + less_than_or_equal_to: " %{count}يجب ان تكون اقل من او تساوي" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "يجب ان تكون اكثر من تاريخ البداية" + not_same_project: "لا ينتمي الى نفس المشروع" + circular_dependency: "هذه العلاقة سوف تخلق علاقة تبعية دائرية" + cant_link_an_issue_with_a_descendant: "لا يمكن ان تكون المشكلة مرتبطة بواحدة من المهام الفرعية" + + actionview_instancetag_blank_option: الرجاء التحديد + + general_text_No: 'لا' + general_text_Yes: 'نعم' + general_text_no: 'لا' + general_text_yes: 'نعم' + general_lang_name: 'Arabic (عربي)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: لقد تم تجديد الحساب بنجاح. + notice_account_invalid_creditentials: اسم المستخدم او كلمة المرور غير صحيحة + notice_account_password_updated: لقد تم تجديد كلمة المرور بنجاح. + notice_account_wrong_password: كلمة المرور غير صحيحة + notice_account_register_done: لقد تم انشاء حسابك بنجاح، الرجاء تأكيد الطلب من البريد الالكتروني + notice_account_unknown_email: مستخدم غير معروف. + notice_can_t_change_password: هذا الحساب يستخدم جهاز خارجي غير مصرح به لا يمكن تغير كلمة المرور + notice_account_lost_email_sent: لقد تم ارسال رسالة على بريدك بالتعليمات اللازمة لتغير كلمة المرور + notice_account_activated: لقد تم تفعيل حسابك، يمكنك الدخول الان + notice_successful_create: لقد تم الانشاء بنجاح + notice_successful_update: لقد تم التحديث بنجاح + notice_successful_delete: لقد تم الحذف بنجاح + notice_successful_connection: لقد تم الربط بنجاح + notice_file_not_found: الصفحة التي تحاول الدخول اليها غير موجوده او تم حذفها + notice_locking_conflict: تم تحديث البيانات عن طريق مستخدم آخر. + notice_not_authorized: غير مصرح لك الدخول الى هذه المنطقة. + notice_not_authorized_archived_project: المشروع الذي تحاول الدخول اليه تم ارشفته + notice_email_sent: "%{value}تم ارسال رسالة الى " + notice_email_error: " (%{value})لقد حدث خطأ ما اثناء ارسال الرسالة الى " + notice_feeds_access_key_reseted: كلمة الدخول RSSلقد تم تعديل . + notice_api_access_key_reseted: كلمة الدخولAPIلقد تم تعديل . + notice_failed_to_save_issues: "فشل في حفظ الملف" + notice_failed_to_save_members: "فشل في حفظ الاعضاء: %{errors}." + notice_no_issue_selected: "لم يتم تحديد شيء، الرجاء تحديد المسألة التي تريد" + notice_account_pending: "لقد تم انشاء حسابك، الرجاء الانتظار حتى تتم الموافقة" + notice_default_data_loaded: تم تحميل التكوين الافتراضي بنجاح + notice_unable_delete_version: غير قادر على مسح النسخة. + notice_unable_delete_time_entry: غير قادر على مسح وقت الدخول. + notice_issue_done_ratios_updated: لقد تم تحديث النسب. + notice_gantt_chart_truncated: " (%{max})لقد تم اقتطاع الرسم البياني لانه تجاوز الاحد الاقصى لعدد العناصر المسموح عرضها " + notice_issue_successful_create: "%{id}لقد تم انشاء " + + + error_can_t_load_default_data: "لم يتم تحميل التكوين الافتراضي كاملا %{value}" + error_scm_not_found: "لم يتم العثور على ادخال في المستودع" + error_scm_command_failed: "حدث خطأ عند محاولة الوصول الى المستودع: %{value}" + error_scm_annotate: "الادخال غير موجود." + error_scm_annotate_big_text_file: "لا يمكن حفظ الادخال لانه تجاوز الحد الاقصى لحجم الملف." + error_issue_not_found_in_project: 'لم يتم العثور على المخرج او انه ينتمي الى مشروع اخر' + error_no_tracker_in_project: 'لا يوجد متتبع لهذا المشروع، الرجاء التحقق من إعدادات المشروع. ' + error_no_default_issue_status: 'لم يتم التعرف على اي وضع افتراضي، الرجاء التحقق من التكوين الخاص بك (اذهب الى إدارة-إصدار الحالات)' + error_can_not_delete_custom_field: غير قادر على حذف الحقل المظلل + error_can_not_delete_tracker: "هذا المتتبع يحتوي على مسائل نشطة ولا يمكن حذفه" + error_can_not_remove_role: "هذا الدور قيد الاستخدام، لا يمكن حذفه" + error_can_not_reopen_issue_on_closed_version: 'لا يمكن إعادة فتح قضية معينه لاصدار مقفل' + error_can_not_archive_project: لا يمكن ارشفة هذا المشروع + error_issue_done_ratios_not_updated: "لم يتم تحديث النسب" + error_workflow_copy_source: 'الرجاء اختيار المتتبع او الادوار' + error_workflow_copy_target: 'الرجاء اختيار هدف المتتبع او هدف الادوار' + error_unable_delete_issue_status: 'غير قادر على حذف حالة القضية' + error_unable_to_connect: "تعذر الاتصال(%{value})" + error_attachment_too_big: " (%{max_size})لا يمكن تحميل هذا الملف، لقد تجاوز الحد الاقصى المسموح به " + warning_attachments_not_saved: "%{count}تعذر حفظ الملف" + + mail_subject_lost_password: " %{value}كلمة المرور الخاصة بك " + mail_body_lost_password: 'لتغير كلمة المرور، انقر على الروابط التالية:' + mail_subject_register: " %{value}تفعيل حسابك " + mail_body_register: 'لتفعيل حسابك، انقر على الروابط التالية:' + mail_body_account_information_external: " %{value}اصبح بامكانك استخدام حسابك للدخول" + mail_body_account_information: معلومات حسابك + mail_subject_account_activation_request: "%{value}طلب تفعيل الحساب " + mail_body_account_activation_request: " (%{value})تم تسجيل حساب جديد، بانتظار الموافقة:" + mail_subject_reminder: "%{count}تم تأجيل المهام التالية " + mail_body_reminder: "%{count}يجب ان تقوم بتسليم المهام التالية :" + mail_subject_wiki_content_added: "'%{id}' تم اضافة صفحة ويكي" + mail_body_wiki_content_added: "The '%{id}' تم اضافة صفحة ويكي من قبل %{author}." + mail_subject_wiki_content_updated: "'%{id}' تم تحديث صفحة ويكي" + mail_body_wiki_content_updated: "The '%{id}'تم تحديث صفحة ويكي من قبل %{author}." + + gui_validation_error: خطأ + gui_validation_error_plural: "%{count}أخطاء" + + field_name: الاسم + field_description: الوصف + field_summary: الملخص + field_is_required: مطلوب + field_firstname: الاسم الاول + field_lastname: الاسم الاخير + field_mail: البريد الالكتروني + field_filename: اسم الملف + field_filesize: حجم الملف + field_downloads: التنزيل + field_author: المؤلف + field_created_on: تم الانشاء في + field_updated_on: تم التحديث + field_field_format: تنسيق الحقل + field_is_for_all: لكل المشروعات + field_possible_values: قيم محتملة + field_regexp: التعبير العادي + field_min_length: الحد الادنى للطول + field_max_length: الحد الاعلى للطول + field_value: القيمة + field_category: الفئة + field_title: العنوان + field_project: المشروع + field_issue: القضية + field_status: الحالة + field_notes: ملاحظات + field_is_closed: القضية مغلقة + field_is_default: القيمة الافتراضية + field_tracker: المتتبع + field_subject: الموضوع + field_due_date: تاريخ الاستحقاق + field_assigned_to: المحال اليه + field_priority: الأولوية + field_fixed_version: الاصدار المستهدف + field_user: المستخدم + field_principal: الرئيسي + field_role: دور + field_homepage: الصفحة الرئيسية + field_is_public: عام + field_parent: مشروع فرعي من + field_is_in_roadmap: القضايا المعروضة في خارطة الطريق + field_login: تسجيل الدخول + field_mail_notification: ملاحظات على البريد الالكتروني + field_admin: المدير + field_last_login_on: اخر اتصال + field_language: لغة + field_effective_date: تاريخ + field_password: كلمة المرور + field_new_password: كلمة المرور الجديدة + field_password_confirmation: تأكيد + field_version: إصدار + field_type: نوع + field_host: المضيف + field_port: المنفذ + field_account: الحساب + field_base_dn: DN قاعدة + field_attr_login: سمة الدخول + field_attr_firstname: سمة الاسم الاول + field_attr_lastname: سمة الاسم الاخير + field_attr_mail: سمة البريد الالكتروني + field_onthefly: إنشاء حساب مستخدم على تحرك + field_start_date: تاريخ البدية + field_done_ratio: "% تم" + field_auth_source: وضع المصادقة + field_hide_mail: إخفاء بريدي الإلكتروني + field_comments: تعليق + field_url: رابط + field_start_page: صفحة البداية + field_subproject: المشروع الفرعي + field_hours: ساعات + field_activity: النشاط + field_spent_on: تاريخ + field_identifier: المعرف + field_is_filter: استخدم كتصفية + field_issue_to: القضايا المتصلة + field_delay: تأخير + field_assignable: يمكن ان تستند القضايا الى هذا الدور + field_redirect_existing_links: إعادة توجيه الروابط الموجودة + field_estimated_hours: الوقت المتوقع + field_column_names: أعمدة + field_time_entries: وقت الدخول + field_time_zone: المنطقة الزمنية + field_searchable: يمكن البحث فيه + field_default_value: القيمة الافتراضية + field_comments_sorting: اعرض التعليقات + field_parent_title: صفحة الوالدين + field_editable: يمكن اعادة تحريره + field_watcher: مراقب + field_identity_url: افتح الرابط الخاص بالهوية الشخصية + field_content: المحتويات + field_group_by: مجموعة النتائج عن طريق + field_sharing: مشاركة + field_parent_issue: مهمة الوالدين + field_member_of_group: "مجموعة المحال" + field_assigned_to_role: "دور المحال" + field_text: حقل نصي + field_visible: غير مرئي + field_warn_on_leaving_unsaved: "الرجاء التحذير عند مغادرة صفحة والنص غير محفوظ" + field_issues_visibility: القضايا المرئية + field_is_private: خاص + field_commit_logs_encoding: رسائل الترميز + field_scm_path_encoding: ترميز المسار + field_path_to_repository: مسار المستودع + field_root_directory: دليل الجذر + field_cvsroot: CVSجذر + field_cvs_module: وحدة + + setting_app_title: عنوان التطبيق + setting_app_subtitle: العنوان الفرعي للتطبيق + setting_welcome_text: نص الترحيب + setting_default_language: اللغة الافتراضية + setting_login_required: مطلوب المصادقة + setting_self_registration: التسجيل الذاتي + setting_attachment_max_size: الحد الاقصى للملفات المرفقة + setting_issues_export_limit: الحد الاقصى لقضايا التصدير + setting_mail_from: انبعاثات عنوان بريدك + setting_bcc_recipients: مستلمين النسخ المخفية (bcc) + setting_plain_text_mail: نص عادي (no HTML) + setting_host_name: اسم ومسار المستخدم + setting_text_formatting: تنسيق النص + setting_wiki_compression: ضغط تاريخ الويكي + setting_feeds_limit: Atom feeds الحد الاقصى لعدد البنود في + setting_default_projects_public: المشاريع الجديده متاحة للجميع افتراضيا + setting_autofetch_changesets: الإحضار التلقائي + setting_sys_api_enabled: من ادارة المستودع WS تمكين + setting_commit_ref_keywords: مرجعية الكلمات المفتاحية + setting_commit_fix_keywords: تصحيح الكلمات المفتاحية + setting_autologin: الدخول التلقائي + setting_date_format: تنسيق التاريخ + setting_time_format: تنسيق الوقت + setting_cross_project_issue_relations: السماح بادارج القضايا في هذا المشروع + setting_issue_list_default_columns: الاعمدة الافتراضية المعروضة في قائمة القضية + setting_repositories_encodings: ترميز المرفقات والمستودعات + setting_emails_header: رأس رسائل البريد الإلكتروني + setting_emails_footer: ذيل رسائل البريد الإلكتروني + setting_protocol: بروتوكول + setting_per_page_options: الكائنات لكل خيارات الصفحة + setting_user_format: تنسيق عرض المستخدم + setting_activity_days_default: الايام المعروضة على نشاط المشروع + setting_display_subprojects_issues: عرض القضايا الفرعية للمشارع الرئيسية بشكل افتراضي + setting_enabled_scm: SCM تمكين + setting_mail_handler_body_delimiters: "اقتطاع رسائل البريد الإلكتروني بعد هذه الخطوط" + setting_mail_handler_api_enabled: للرسائل الواردةWS تمكين + setting_mail_handler_api_key: API مفتاح + setting_sequential_project_identifiers: انشاء معرفات المشروع المتسلسلة + setting_gravatar_enabled: كأيقونة مستخدمGravatar استخدام + setting_gravatar_default: الافتراضيةGravatar صورة + setting_diff_max_lines_displayed: الحد الاقصى لعدد الخطوط + setting_file_max_size_displayed: الحد الأقصى لحجم النص المعروض على الملفات المرفقة + setting_repository_log_display_limit: الحد الاقصى لعدد التنقيحات المعروضة على ملف السجل + setting_openid: السماح بدخول اسم المستخدم المفتوح والتسجيل + setting_password_min_length: الحد الادني لطول كلمة المرور + setting_new_project_user_role_id: الدور المسند الى المستخدم غير المسؤول الذي يقوم بإنشاء المشروع + setting_default_projects_modules: تمكين الوحدات النمطية للمشاريع الجديدة بشكل افتراضي + setting_issue_done_ratio: حساب نسبة القضية المنتهية + setting_issue_done_ratio_issue_field: استخدم حقل القضية + setting_issue_done_ratio_issue_status: استخدم وضع القضية + setting_start_of_week: بدأ التقويم + setting_rest_api_enabled: تمكين باقي خدمات الويب + setting_cache_formatted_text: النص المسبق تنسيقه في ذاكرة التخزين المؤقت + setting_default_notification_option: خيار الاعلام الافتراضي + setting_commit_logtime_enabled: تميكن وقت الدخول + setting_commit_logtime_activity_id: النشاط في وقت الدخول + setting_gantt_items_limit: الحد الاقصى لعدد العناصر المعروضة على المخطط + setting_issue_group_assignment: السماح للإحالة الى المجموعات + setting_default_issue_start_date_to_creation_date: استخدام التاريخ الحالي كتاريخ بدأ للقضايا الجديدة + + permission_add_project: إنشاء مشروع + permission_add_subprojects: إنشاء مشاريع فرعية + permission_edit_project: تعديل مشروع + permission_select_project_modules: تحديد شكل المشروع + permission_manage_members: إدارة الاعضاء + permission_manage_project_activities: ادارة اصدارات المشروع + permission_manage_versions: ادارة الاصدارات + permission_manage_categories: ادارة انواع القضايا + permission_view_issues: عرض القضايا + permission_add_issues: اضافة القضايا + permission_edit_issues: تعديل القضايا + permission_manage_issue_relations: ادارة علاقات القضايا + permission_set_issues_private: تعين قضايا عامة او خاصة + permission_set_own_issues_private: تعين القضايا الخاصة بك كقضايا عامة او خاصة + permission_add_issue_notes: اضافة ملاحظات + permission_edit_issue_notes: تعديل ملاحظات + permission_edit_own_issue_notes: تعديل ملاحظاتك + permission_move_issues: تحريك القضايا + permission_delete_issues: حذف القضايا + permission_manage_public_queries: ادارة الاستعلامات العامة + permission_save_queries: حفظ الاستعلامات + permission_view_gantt: عرض طريقة"جانت" + permission_view_calendar: عرض التقويم + permission_view_issue_watchers: عرض قائمة المراقبين + permission_add_issue_watchers: اضافة مراقبين + permission_delete_issue_watchers: حذف مراقبين + permission_log_time: الوقت المستغرق بالدخول + permission_view_time_entries: عرض الوقت المستغرق + permission_edit_time_entries: تعديل الدخولات الزمنية + permission_edit_own_time_entries: تعديل الدخولات الشخصية + permission_manage_news: ادارة الاخبار + permission_comment_news: اخبار التعليقات + permission_manage_documents: ادارة المستندات + permission_view_documents: عرض المستندات + permission_manage_files: ادارة الملفات + permission_view_files: عرض الملفات + permission_manage_wiki: ادارة ويكي + permission_rename_wiki_pages: اعادة تسمية صفحات ويكي + permission_delete_wiki_pages: حذق صفحات ويكي + permission_view_wiki_pages: عرض ويكي + permission_view_wiki_edits: عرض تاريخ ويكي + permission_edit_wiki_pages: تعديل صفحات ويكي + permission_delete_wiki_pages_attachments: حذف المرفقات + permission_protect_wiki_pages: حماية صفحات ويكي + permission_manage_repository: ادارة المستودعات + permission_browse_repository: استعراض المستودعات + permission_view_changesets: عرض طاقم التغيير + permission_commit_access: الوصول + permission_manage_boards: ادارة المنتديات + permission_view_messages: عرض الرسائل + permission_add_messages: نشر الرسائل + permission_edit_messages: تحرير الرسائل + permission_edit_own_messages: تحرير الرسائل الخاصة + permission_delete_messages: حذف الرسائل + permission_delete_own_messages: حذف الرسائل الخاصة + permission_export_wiki_pages: تصدير صفحات ويكي + permission_manage_subtasks: ادارة المهام الفرعية + + project_module_issue_tracking: تعقب القضايا + project_module_time_tracking: التعقب الزمني + project_module_news: الاخبار + project_module_documents: المستندات + project_module_files: الملفات + project_module_wiki: ويكي + project_module_repository: المستودع + project_module_boards: المنتديات + project_module_calendar: التقويم + project_module_gantt: جانت + + label_user: المستخدم + label_user_plural: المستخدمين + label_user_new: مستخدم جديد + label_user_anonymous: مجهول الهوية + label_project: مشروع + label_project_new: مشروع جديد + label_project_plural: مشاريع + label_x_projects: + zero: لا يوجد مشاريع + one: مشروع واحد + other: "%{count} مشاريع" + label_project_all: كل المشاريع + label_project_latest: احدث المشاريع + label_issue: قضية + label_issue_new: قضية جديدة + label_issue_plural: قضايا + label_issue_view_all: عرض كل القضايا + label_issues_by: " %{value}القضية لصحابها" + label_issue_added: تم اضافة القضية + label_issue_updated: تم تحديث القضية + label_issue_note_added: تم اضافة الملاحظة + label_issue_status_updated: تم تحديث الحالة + label_issue_priority_updated: تم تحديث الاولويات + label_document: مستند + label_document_new: مستند جديد + label_document_plural: مستندات + label_document_added: تم اضافة مستند + label_role: دور + label_role_plural: ادوار + label_role_new: دور جديد + label_role_and_permissions: الادوار والاذن + label_role_anonymous: مجهول الهوية + label_role_non_member: ليس عضو + label_member: عضو + label_member_new: عضو جديد + label_member_plural: اعضاء + label_tracker: المتتبع + label_tracker_plural: المتتبعين + label_tracker_new: متتبع جديد + label_workflow: سير العمل + label_issue_status: وضع القضية + label_issue_status_plural: اوضاع القضية + label_issue_status_new: وضع جديد + label_issue_category: نوع القضية + label_issue_category_plural: انواع القضايا + label_issue_category_new: نوع جديد + label_custom_field: تخصيص حقل + label_custom_field_plural: تخصيص حقول + label_custom_field_new: حقل مخصص جديد + label_enumerations: التعدادات + label_enumeration_new: قيمة جديدة + label_information: معلومة + label_information_plural: معلومات + label_please_login: برجى تسجيل الدخول + label_register: تسجيل + label_login_with_open_id_option: او الدخول بهوية مفتوحة + label_password_lost: فقدت كلمة السر + label_home: الصفحة الرئيسية + label_my_page: الصفحة الخاصة بي + label_my_account: حسابي + label_my_projects: مشاريعي الخاصة + label_my_page_block: حجب صفحتي الخاصة + label_administration: الإدارة + label_login: تسجيل الدخول + label_logout: تسجيل الخروج + label_help: مساعدة + label_reported_issues: أبلغ القضايا + label_assigned_to_me_issues: المسائل المعنية إلى + label_last_login: آخر اتصال + label_registered_on: مسجل على + label_activity: النشاط + label_overall_activity: النشاط العام + label_user_activity: "قيمة النشاط" + label_new: جديدة + label_logged_as: تم تسجيل دخولك + label_environment: البيئة + label_authentication: المصادقة + label_auth_source: وضع المصادقة + label_auth_source_new: وضع مصادقة جديدة + label_auth_source_plural: أوضاع المصادقة + label_subproject_plural: مشاريع فرعية + label_subproject_new: مشروع فرعي جديد + label_and_its_subprojects: "قيمةالمشاريع الفرعية الخاصة بك" + label_min_max_length: الحد الاقصى والادنى للطول + label_list: قائمة + label_date: تاريخ + label_integer: عدد صحيح + label_float: تعويم + label_boolean: منطقية + label_string: النص + label_text: نص طويل + label_attribute: سمة + label_attribute_plural: السمات + label_download: "تحميل" + label_download_plural: "تحميل" + label_no_data: لا توجد بيانات للعرض + label_change_status: تغيير الوضع + label_history: التاريخ + label_attachment: الملف + label_attachment_new: ملف جديد + label_attachment_delete: حذف الملف + label_attachment_plural: الملفات + label_file_added: الملف المضاف + label_report: تقرير + label_report_plural: التقارير + label_news: الأخبار + label_news_new: إضافة الأخبار + label_news_plural: الأخبار + label_news_latest: آخر الأخبار + label_news_view_all: عرض كل الأخبار + label_news_added: الأخبار المضافة + label_news_comment_added: إضافة التعليقات على أخبار + label_settings: إعدادات + label_overview: لمحة عامة + label_version: الإصدار + label_version_new: الإصدار الجديد + label_version_plural: الإصدارات + label_close_versions: أكملت إغلاق الإصدارات + label_confirmation: تأكيد + label_export_to: 'متوفرة أيضا في:' + label_read: القراءة... + label_public_projects: المشاريع العامة + label_open_issues: فتح قضية + label_open_issues_plural: فتح قضايا + label_closed_issues: قضية مغلقة + label_closed_issues_plural: قضايا مغلقة + label_x_open_issues_abbr_on_total: + zero: 0 مفتوح / %{total} + one: 1 مفتوح / %{total} + other: "%{count} مفتوح / %{total}" + label_x_open_issues_abbr: + zero: 0 مفتوح + one: 1 مقتوح + other: "%{count} مفتوح" + label_x_closed_issues_abbr: + zero: 0 مغلق + one: 1 مغلق + other: "%{count} مغلق" + label_total: الإجمالي + label_permissions: أذونات + label_current_status: الوضع الحالي + label_new_statuses_allowed: يسمح بادراج حالات جديدة + label_all: جميع + label_none: لا شيء + label_nobody: لا أحد + label_next: القادم + label_previous: السابق + label_used_by: التي يستخدمها + label_details: التفاصيل + label_add_note: إضافة ملاحظة + label_per_page: كل صفحة + label_calendar: التقويم + label_months_from: بعد أشهر من + label_gantt: جانت + label_internal: الداخلية + label_last_changes: "آخر التغييرات %{count}" + label_change_view_all: عرض كافة التغييرات + label_personalize_page: تخصيص هذه الصفحة + label_comment: تعليق + label_comment_plural: تعليقات + label_x_comments: + zero: لا يوجد تعليقات + one: تعليق واحد + other: "%{count} تعليقات" + label_comment_add: إضافة تعليق + label_comment_added: تم إضافة التعليق + label_comment_delete: حذف التعليقات + label_query: استعلام مخصص + label_query_plural: استعلامات مخصصة + label_query_new: استعلام جديد + label_my_queries: استعلاماتي المخصصة + label_filter_add: إضافة عامل تصفية + label_filter_plural: عوامل التصفية + label_equals: يساوي + label_not_equals: لا يساوي + label_in_less_than: في أقل من + label_in_more_than: في أكثر من + label_greater_or_equal: '>=' + label_less_or_equal: '< =' + label_between: بين + label_in: في + label_today: اليوم + label_all_time: كل الوقت + label_yesterday: بالأمس + label_this_week: هذا الأسبوع + label_last_week: الأسبوع الماضي + label_last_n_days: "ايام %{count} اخر" + label_this_month: هذا الشهر + label_last_month: الشهر الماضي + label_this_year: هذا العام + label_date_range: نطاق التاريخ + label_less_than_ago: أقل من قبل أيام + label_more_than_ago: أكثر من قبل أيام + label_ago: منذ أيام + label_contains: يحتوي على + label_not_contains: لا يحتوي على + label_day_plural: أيام + label_repository: المستودع + label_repository_plural: المستودعات + label_browse: تصفح + label_modification: "%{count} تغير" + label_modification_plural: "%{count}تغيرات " + label_branch: فرع + label_tag: ربط + label_revision: مراجعة + label_revision_plural: تنقيحات + label_revision_id: " %{value}مراجعة" + label_associated_revisions: التنقيحات المرتبطة + label_added: إضافة + label_modified: تعديل + label_copied: نسخ + label_renamed: إعادة تسمية + label_deleted: حذف + label_latest_revision: آخر تنقيح + label_latest_revision_plural: أحدث المراجعات + label_view_revisions: عرض التنقيحات + label_view_all_revisions: عرض كافة المراجعات + label_max_size: الحد الأقصى للحجم + label_sort_highest: التحرك إلى أعلى + label_sort_higher: تحريك لأعلى + label_sort_lower: تحريك لأسفل + label_sort_lowest: الانتقال إلى أسفل + label_roadmap: خارطة الطريق + label_roadmap_due_in: " %{value}تستحق في " + label_roadmap_overdue: "%{value}تأخير" + label_roadmap_no_issues: لا يوجد قضايا لهذا الإصدار + label_search: البحث + label_result_plural: النتائج + label_all_words: كل الكلمات + label_wiki: ويكي + label_wiki_edit: تحرير ويكي + label_wiki_edit_plural: عمليات تحرير ويكي + label_wiki_page: صفحة ويكي + label_wiki_page_plural: ويكي صفحات + label_index_by_title: الفهرس حسب العنوان + label_index_by_date: الفهرس حسب التاريخ + label_current_version: الإصدار الحالي + label_preview: معاينة + label_feed_plural: موجز ويب + label_changes_details: تفاصيل جميع التغييرات + label_issue_tracking: تعقب القضايا + label_spent_time: أمضى بعض الوقت + label_overall_spent_time: الوقت الذي تم انفاقه كاملا + label_f_hour: "%{value} ساعة" + label_f_hour_plural: "%{value} ساعات" + label_time_tracking: تعقب الوقت + label_change_plural: التغييرات + label_statistics: إحصاءات + label_commits_per_month: يثبت في الشهر + label_commits_per_author: يثبت لكل مؤلف + label_diff: الاختلافات + label_view_diff: عرض الاختلافات + label_diff_inline: مضمنة + label_diff_side_by_side: جنبا إلى جنب + label_options: خيارات + label_copy_workflow_from: نسخ سير العمل من + label_permissions_report: تقرير أذونات + label_watched_issues: شاهد القضايا + label_related_issues: القضايا ذات الصلة + label_applied_status: تطبيق مركز + label_loading: تحميل... + label_relation_new: علاقة جديدة + label_relation_delete: حذف العلاقة + label_relates_to: ذات الصلة إلى + label_duplicates: التكرارات + label_duplicated_by: ازدواج + label_blocks: حظر + label_blocked_by: حظر بواسطة + label_precedes: يسبق + label_follows: يتبع + label_end_to_start: نهاية لبدء + label_end_to_end: نهاية إلى نهاية + label_start_to_start: بدء إلى بدء + label_start_to_end: بداية لنهاية + label_stay_logged_in: تسجيل الدخول في + label_disabled: تعطيل + label_show_completed_versions: أكملت إظهار إصدارات + label_me: لي + label_board: المنتدى + label_board_new: منتدى جديد + label_board_plural: المنتديات + label_board_locked: تأمين + label_board_sticky: لزجة + label_topic_plural: المواضيع + label_message_plural: رسائل + label_message_last: آخر رسالة + label_message_new: رسالة جديدة + label_message_posted: تم اضافة الرسالة + label_reply_plural: الردود + label_send_information: إرسال معلومات الحساب للمستخدم + label_year: سنة + label_month: شهر + label_week: أسبوع + label_date_from: من + label_date_to: إلى + label_language_based: استناداً إلى لغة المستخدم + label_sort_by: " %{value}الترتيب حسب " + label_send_test_email: ارسل رسالة الكترونية كاختبار + label_feeds_access_key: RSS مفتاح دخول + label_missing_feeds_access_key: مفقودRSS مفتاح دخول + label_feeds_access_key_created_on: "RSS تم انشاء مفتاح %{value} منذ" + label_module_plural: الوحدات النمطية + label_added_time_by: " تم اضافته من قبل%{author} %{age} منذ" + label_updated_time_by: " تم تحديثه من قبل%{author} %{age} منذ" + label_updated_time: "تم التحديث %{value} منذ" + label_jump_to_a_project: الانتقال إلى مشروع... + label_file_plural: الملفات + label_changeset_plural: اعدادات التغير + label_default_columns: الاعمدة الافتراضية + label_no_change_option: (أي تغيير) + label_bulk_edit_selected_issues: تحرير القضايا المظللة + label_bulk_edit_selected_time_entries: تعديل كل الإدخالات في كل الاوقات + label_theme: الموضوع + label_default: الافتراضي + label_search_titles_only: البحث في العناوين فقط + label_user_mail_option_all: "جميع الخيارات" + label_user_mail_option_selected: "الخيارات المظللة فقط" + label_user_mail_option_none: "لم يتم تحديد اي خيارات" + label_user_mail_option_only_my_events: "السماح لي فقط بمشاهدة الاحداث الخاصة" + label_user_mail_option_only_assigned: "فقط الخيارات التي تم تعيينها" + label_user_mail_option_only_owner: "فقط للخيارات التي املكها" + label_user_mail_no_self_notified: "لا تريد اعلامك بالتغيرات التي تجريها بنفسك" + label_registration_activation_by_email: حساب التنشيط عبر البريد الإلكتروني + label_registration_manual_activation: تنشيط الحساب اليدوي + label_registration_automatic_activation: تنشيط الحساب التلقائي + label_display_per_page: "لكل صفحة: %{value}" + label_age: العمر + label_change_properties: تغيير الخصائص + label_general: عامة + label_more: أكثر + label_scm: scm + label_plugins: الإضافات + label_ldap_authentication: مصادقة LDAP + label_downloads_abbr: D/L + label_optional_description: وصف اختياري + label_add_another_file: إضافة ملف آخر + label_preferences: تفضيلات + label_chronological_order: في ترتيب زمني + label_reverse_chronological_order: في ترتيب زمني عكسي + label_planning: التخطيط + label_incoming_emails: رسائل البريد الإلكتروني الوارد + label_generate_key: إنشاء مفتاح + label_issue_watchers: المراقبون + label_example: مثال + label_display: العرض + label_sort: فرز + label_ascending: تصاعدي + label_descending: تنازلي + label_date_from_to: من %{start} الى %{end} + label_wiki_content_added: إضافة صفحة ويكي + label_wiki_content_updated: تحديث صفحة ويكي + label_group: مجموعة + label_group_plural: المجموعات + label_group_new: مجموعة جديدة + label_time_entry_plural: أمضى بعض الوقت + label_version_sharing_none: لم يشارك + label_version_sharing_descendants: يشارك + label_version_sharing_hierarchy: مع التسلسل الهرمي للمشروع + label_version_sharing_tree: مع شجرة المشروع + label_version_sharing_system: مع جميع المشاريع + label_update_issue_done_ratios: تحديث قضيةالنسب + label_copy_source: مصدر + label_copy_target: الهدف + label_copy_same_as_target: نفس الهدف + label_display_used_statuses_only: عرض الحالات المستخدمة من قبل هذا "تعقب" فقط + label_api_access_key: مفتاح الوصول إلى API + label_missing_api_access_key: API لم يتم الحصول على مفتاح الوصول + label_api_access_key_created_on: " API إنشاء مفتاح الوصول إلى" + label_profile: الملف الشخصي + label_subtask_plural: المهام الفرعية + label_project_copy_notifications: إرسال إشعار الى البريد الإلكتروني عند نسخ المشروع + label_principal_search: "البحث عن مستخدم أو مجموعة:" + label_user_search: "البحث عن المستخدم:" + label_additional_workflow_transitions_for_author: الانتقالات الإضافية المسموح بها عند المستخدم صاحب البلاغ + label_additional_workflow_transitions_for_assignee: الانتقالات الإضافية المسموح بها عند المستخدم المحال إليه + label_issues_visibility_all: جميع القضايا + label_issues_visibility_public: جميع القضايا الخاصة + label_issues_visibility_own: القضايا التي أنشأها المستخدم + label_git_report_last_commit: اعتماد التقرير الأخير للملفات والدلائل + label_parent_revision: الوالدين + label_child_revision: الطفل + label_export_options: "%{export_format} خيارات التصدير" + + button_login: دخول + button_submit: تثبيت + button_save: حفظ + button_check_all: نحديد الكل + button_uncheck_all: عدم تحديد الكل + button_collapse_all: تقليص الكل + button_expand_all: عرض الكل + button_delete: حذف + button_create: انشاء + button_create_and_continue: انشاء واستمرار + button_test: اختبار + button_edit: تعديل + button_edit_associated_wikipage: "تغير صفحة ويكي: %{page_title}" + button_add: اضافة + button_change: تغير + button_apply: تطبيق + button_clear: واضح + button_lock: قفل + button_unlock: الغاء القفل + button_download: تنزيل + button_list: قائمة + button_view: عرض + button_move: تحرك + button_move_and_follow: تحرك واتبع + button_back: رجوع + button_cancel: إلغاء + button_activate: تنشيط + button_sort: ترتيب + button_log_time: وقت الدخول + button_rollback: الرجوع الى هذا الاصدار + button_watch: يشاهد + button_unwatch: إلغاء المشاهدة + button_reply: رد + button_archive: الارشيف + button_unarchive: إلغاء الارشفة + button_reset: إعادة + button_rename: إعادة التسمية + button_change_password: تغير كلمة المرور + button_copy: نسخ + button_copy_and_follow: نسخ واتباع + button_annotate: تعليق + button_update: تحديث + button_configure: تكوين + button_quote: يقتبس + button_duplicate: يضاعف + button_show: يظهر + button_edit_section: يعدل هذا الجزء + button_export: يستورد + + status_active: نشيط + status_registered: مسجل + status_locked: مقفل + + version_status_open: مفتوح + version_status_locked: مقفل + version_status_closed: مغلق + + field_active: فعال + + text_select_mail_notifications: حدد الامور التي يجب ابلاغك بها عن طريق البريد الالكتروني + text_regexp_info: مثال. ^[A-Z0-9]+$ + text_min_max_length_info: الحد الاقصى والادني لطول المعلومات + text_project_destroy_confirmation: هل أنت متأكد من أنك تريد حذف هذا المشروع والبيانات ذات الصلة؟ + text_subprojects_destroy_warning: "subproject(s): سيتم حذف أيضا." + text_workflow_edit: حدد دوراً وتعقب لتحرير سير العمل + text_are_you_sure: هل أنت متأكد؟ + text_are_you_sure_with_children: "حذف الموضوع وجميع المسائل المتعلقة بالطفل؟" + text_journal_changed: "%{label} تغير %{old} الى %{new}" + text_journal_changed_no_detail: "%{label} تم التحديث" + text_journal_set_to: "%{label} تغير الى %{value}" + text_journal_deleted: "%{label} تم الحذف (%{old})" + text_journal_added: "%{label} %{value} تم الاضافة" + text_tip_issue_begin_day: قضية بدأت اليوم + text_tip_issue_end_day: قضية انتهت اليوم + text_tip_issue_begin_end_day: قضية بدأت وانتهت اليوم + text_caracters_maximum: "%{count} الحد الاقصى." + text_caracters_minimum: "الحد الادنى %{count}" + text_length_between: "الطول %{min} بين %{max} رمز" + text_tracker_no_workflow: لم يتم تحديد سير العمل لهذا المتتبع + text_unallowed_characters: رموز غير مسموحة + text_comma_separated: مسموح رموز متنوعة يفصلها فاصلة . + text_line_separated: مسموح رموز متنوعة يفصلها سطور + text_issues_ref_in_commit_messages: الرجوع واصلاح القضايا في رسائل المشتكين + text_issue_added: "القضية %{id} تم ابلاغها عن طريق %{author}." + text_issue_updated: "القضية %{id} تم تحديثها عن طريق %{author}." + text_wiki_destroy_confirmation: هل انت متأكد من رغبتك في حذف هذا الويكي ومحتوياته؟ + text_issue_category_destroy_question: "بعض القضايا (%{count}) مرتبطة بهذه الفئة، ماذا تريد ان تفعل بها؟" + text_issue_category_destroy_assignments: حذف الفئة + text_issue_category_reassign_to: اعادة تثبيت البنود في الفئة + text_user_mail_option: "بالنسبة للمشاريع غير المحددة، سوف يتم ابلاغك عن المشاريع التي تشاهدها او تشارك بها فقط!" + text_no_configuration_data: "الادوار والمتتبع وحالات القضية ومخطط سير العمل لم يتم تحديد وضعها الافتراضي بعد. " + text_load_default_configuration: احمل الاعدادات الافتراضية + text_status_changed_by_changeset: " طبق التغيرات المعينة على %{value}." + text_time_logged_by_changeset: "تم تطبيق التغيرات المعينة على %{value}." + text_issues_destroy_confirmation: هل انت متأكد من حذف البنود المظللة؟' + text_issues_destroy_descendants_confirmation: "سوف يؤدي هذا الى حذف %{count} المهام الفرعية ايضا." + text_time_entries_destroy_confirmation: "هل انت متأكد من رغبتك في حذف الادخالات الزمنية المحددة؟" + text_select_project_modules: قم بتحديد الوضع المناسب لهذا المشروع:' + text_default_administrator_account_changed: تم تعديل الاعدادات الافتراضية لحساب المدير + text_file_repository_writable: المرفقات قابلة للكتابة + text_plugin_assets_writable: الدليل المساعد قابل للكتابة + text_destroy_time_entries_question: " ساعة على القضية التي تود حذفها، ماذا تريد ان تفعل؟ %{hours} تم تثبيت" + text_destroy_time_entries: قم بحذف الساعات المسجلة + text_assign_time_entries_to_project: ثبت الساعات المسجلة على التقرير + text_reassign_time_entries: 'اعادة تثبيت الساعات المسجلة لهذه القضية:' + text_user_wrote: "%{value} كتب:" + text_enumeration_destroy_question: "%{count} الكائنات المعنية لهذه القيمة" + text_enumeration_category_reassign_to: اعادة تثبيت الكائنات التالية لهذه القيمة:' + text_email_delivery_not_configured: "لم يتم تسليم البريد الالكتروني" + text_diff_truncated: '... لقد تم اقتطلع هذا الجزء لانه تجاوز الحد الاقصى المسموح بعرضه' + text_custom_field_possible_values_info: 'سطر لكل قيمة' + text_wiki_page_nullify_children: "الاحتفاظ بصفحات الطفل كصفحات جذر" + text_wiki_page_destroy_children: "حذف صفحات الطفل وجميع أولادهم" + text_wiki_page_reassign_children: "إعادة تعيين صفحات تابعة لهذه الصفحة الأصلية" + text_own_membership_delete_confirmation: "انت على وشك إزالة بعض أو كافة الأذونات الخاصة بك، لن تكون قادراً على تحرير هذا المشروع بعد ذلك. هل أنت متأكد من أنك تريد المتابعة؟" + text_zoom_in: تصغير + text_zoom_out: تكبير + text_warn_on_leaving_unsaved: "الصفحة تحتوي على نص غير مخزن، سوف يفقد النص اذا تم الخروج من الصفحة." + text_scm_path_encoding_note: "الافتراضي: UTF-8" + text_git_repository_note: مستودع فارغ ومحلي + text_mercurial_repository_note: مستودع محلي + text_scm_command: امر + text_scm_command_version: اصدار + text_scm_config: الرجاء اعادة تشغيل التطبيق + text_scm_command_not_available: الامر غير متوفر، الرجاء التحقق من لوحة التحكم + + default_role_manager: مدير + default_role_developer: مطور + default_role_reporter: مراسل + default_tracker_bug: الشوائب + default_tracker_feature: خاصية + default_tracker_support: دعم + default_issue_status_new: جديد + default_issue_status_in_progress: جاري التحميل + default_issue_status_resolved: الحل + default_issue_status_feedback: التغذية الراجعة + default_issue_status_closed: مغلق + default_issue_status_rejected: مرفوض + default_doc_category_user: مستندات المستخدم + default_doc_category_tech: المستندات التقنية + default_priority_low: قليل + default_priority_normal: عادي + default_priority_high: عالي + default_priority_urgent: طارئ + default_priority_immediate: مباشرة + default_activity_design: تصميم + default_activity_development: تطوير + + enumeration_issue_priorities: الاولويات + enumeration_doc_categories: تصنيف المستندات + enumeration_activities: الانشطة + enumeration_system_activity: نشاط النظام + description_filter: فلترة + description_search: حقل البحث + description_choose_project: مشاريع + description_project_scope: مجال البحث + description_notes: ملاحظات + description_message_content: محتويات الرسالة + description_query_sort_criteria_attribute: نوع الترتيب + description_query_sort_criteria_direction: اتجاه الترتيب + description_user_mail_notification: إعدادات البريد الالكتروني + description_available_columns: الاعمدة المتوفرة + description_selected_columns: الاعمدة المحددة + description_all_columns: كل الاعمدة + description_issue_category_reassign: اختر التصنيف + description_wiki_subpages_reassign: اختر صفحة جديدة + description_date_range_list: اختر المجال من القائمة + description_date_range_interval: اختر المدة عن طريق اختيار تاريخ البداية والنهاية + description_date_from: ادخل تاريخ البداية + description_date_to: ادخل تاريخ الانتهاء + text_rmagick_available: RMagick available (optional) + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_project_identifier_info: Only lower case letters (a-z), numbers and dashes are allowed.
    Once saved, the identifier cannot be changed. + text_repository_usernames_mapping: |- + Select or update the Redmine user mapped to each username found in the repository log. + Users with the same Redmine and repository username or email are automatically mapped. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/66/66e6d91872e5c58f97ccd121d804011ad75f7898.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/66/66e6d91872e5c58f97ccd121d804011ad75f7898.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class SerializePossiblesValues < ActiveRecord::Migration + def self.up + CustomField.find(:all).each do |field| + if field.possible_values and field.possible_values.is_a? String + field.possible_values = field.possible_values.split('|') + field.save + end + end + end + + def self.down + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/67/67033650beede216a5816e08cbac9739681ad082.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/67/67033650beede216a5816e08cbac9739681ad082.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +class AddEnumerationsPosition < ActiveRecord::Migration + def self.up + add_column(:enumerations, :position, :integer, :default => 1) unless Enumeration.column_names.include?('position') + Enumeration.find(:all).group_by(&:opt).each do |opt, enums| + enums.each_with_index do |enum, i| + # do not call model callbacks + Enumeration.update_all "position = #{i+1}", {:id => enum.id} + end + end + end + + def self.down + remove_column :enumerations, :position + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/67/674b8036a925ccf2c9ef3d3610ab9b8e2eef3746.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/67/674b8036a925ccf2c9ef3d3610ab9b8e2eef3746.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +def deprecated_task(name, new_name) + task name=>new_name do + $stderr.puts "\nNote: The rake task #{name} has been deprecated, please use the replacement version #{new_name}" + end +end + +deprecated_task :load_default_data, "redmine:load_default_data" +deprecated_task :migrate_from_mantis, "redmine:migrate_from_mantis" +deprecated_task :migrate_from_trac, "redmine:migrate_from_trac" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/67/678e754152b31db4a116543a8765e0c34974f4c8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/67/678e754152b31db4a116543a8765e0c34974f4c8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to_project(news.project) + ': ' unless @project %> +<%= link_to h(news.title), news_path(news) %> +<%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %> +
    +<% unless news.summary.blank? %><%=h news.summary %>
    <% end %> +<%= authoring news.created_on, news.author %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/67/67aa4777ed1332a8a87bb44f4455573440b70d60.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/67/67aa4777ed1332a8a87bb44f4455573440b70d60.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +/* ssh views */ + +CREATE OR REPLACE VIEW ssh_users as +select login as username, hashed_password as password +from users +where status = 1; + + +/* nss views */ + +CREATE OR REPLACE VIEW nss_groups AS +select identifier AS name, (id + 5000) AS gid, 'x' AS password +from projects; + +CREATE OR REPLACE VIEW nss_users AS +select login AS username, CONCAT_WS(' ', firstname, lastname) as realname, (id + 5000) AS uid, 'x' AS password +from users +where status = 1; + +CREATE OR REPLACE VIEW nss_grouplist AS +select (members.project_id + 5000) AS gid, users.login AS username +from users, members +where users.id = members.user_id +and users.status = 1; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/67/67eae16abb4cc62ae1c332a26c83543b3586d5d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/67/67eae16abb4cc62ae1c332a26c83543b3586d5d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +class AddOpenIdAuthenticationTables < ActiveRecord::Migration + def self.up + create_table :open_id_authentication_associations, :force => true do |t| + t.integer :issued, :lifetime + t.string :handle, :assoc_type + t.binary :server_url, :secret + end + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_associations + drop_table :open_id_authentication_nonces + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/67/67f3eefb3b2c497cfa5d20b68f15bca1281bb897.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/67/67f3eefb3b2c497cfa5d20b68f15bca1281bb897.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +<%= error_messages_for 'category' %> + +
    +

    <%= f.text_field :name, :size => 30, :required => true %>

    +

    <%= f.select :assigned_to_id, principals_options_for_select(@project.assignable_users, @category.assigned_to), :include_blank => true %>

    +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/6868bae4892efaa793d57d13538c445e84b6efeb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/68/6868bae4892efaa793d57d13538c445e84b6efeb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<%= error_messages_for 'tracker' %> + +
    +
    + +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.check_box :is_in_roadmap %>

    + +<% if IssueCustomField.all.any? %> +

    + + <% IssueCustomField.all.each do |field| %> + + <% end %> +

    +<%= hidden_field_tag 'tracker[custom_field_ids][]', '' %> +<% end %> + +<% if @tracker.new_record? && @trackers.any? %> +

    +<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@trackers, :id, :name)) %>

    +<% end %> + +
    +<%= submit_tag l(@tracker.new_record? ? :button_create : :button_save) %> +
    + +
    +<% if @projects.any? %> +
    <%= l(:label_project_plural) %> +<%= project_nested_ul(@projects) do |p| + content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p)) +end %> +<%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %> +

    <%= check_all_links 'tracker_project_ids' %>

    +
    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/6874652db7eb983bce24a5b3ff17d04dc1a731fd.svn-base Binary file .svn/pristine/68/6874652db7eb983bce24a5b3ff17d04dc1a731fd.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/6879000e58347aae2d239ff118e15a1cadd798ce.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/68/6879000e58347aae2d239ff118e15a1cadd798ce.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1121 @@ +# Russian localization for Ruby on Rails 2.2+ +# by Yaroslav Markin +# +# Be sure to check out "russian" gem (http://github.com/yaroslav/russian) for +# full Russian language support in Rails (month names, pluralization, etc). +# The following is an excerpt from that gem. +# +# Для полноценной поддержки русского языка (варианты названий месяцев, +# плюрализация и так далее) в Rails 2.2 нужно использовать gem "russian" +# (http://github.com/yaroslav/russian). Следующие данные -- выдержка их него, чтобы +# была возможность минимальной локализации приложения на русский язык. + +ru: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%d %b" + long: "%d %B %Y" + + day_names: [воскресенье, понедельник, вторник, среда, четверг, пятница, суббота] + standalone_day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота] + abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб] + + month_names: [~, января, февраля, марта, апреля, мая, июня, июля, августа, сентября, октября, ноября, декабря] + # see russian gem for info on "standalone" day names + standalone_month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь] + abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.] + standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.] + + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%d %B %Y, %H:%M" + + am: "утра" + pm: "вечера" + + number: + format: + separator: "," + delimiter: " " + precision: 3 + + currency: + format: + format: "%n %u" + unit: "руб." + separator: "." + delimiter: " " + precision: 2 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 2 + # Rails 2.2 + # storage_units: [байт, КБ, МБ, ГБ, ТБ] + + # Rails 2.3 + storage_units: + # Storage units output formatting. + # %u is the storage unit, %n is the number (default: 2 MB) + format: "%n %u" + units: + byte: + one: "байт" + few: "байта" + many: "байт" + other: "байта" + kb: "КБ" + mb: "МБ" + gb: "ГБ" + tb: "ТБ" + + datetime: + distance_in_words: + half_a_minute: "меньше минуты" + less_than_x_seconds: + one: "меньше %{count} секунды" + few: "меньше %{count} секунд" + many: "меньше %{count} секунд" + other: "меньше %{count} секунды" + x_seconds: + one: "%{count} секунда" + few: "%{count} секунды" + many: "%{count} секунд" + other: "%{count} секунды" + less_than_x_minutes: + one: "меньше %{count} минуты" + few: "меньше %{count} минут" + many: "меньше %{count} минут" + other: "меньше %{count} минуты" + x_minutes: + one: "%{count} минуту" + few: "%{count} минуты" + many: "%{count} минут" + other: "%{count} минуты" + about_x_hours: + one: "около %{count} часа" + few: "около %{count} часов" + many: "около %{count} часов" + other: "около %{count} часа" + x_days: + one: "%{count} день" + few: "%{count} дня" + many: "%{count} дней" + other: "%{count} дня" + about_x_months: + one: "около %{count} месяца" + few: "около %{count} месяцев" + many: "около %{count} месяцев" + other: "около %{count} месяца" + x_months: + one: "%{count} месяц" + few: "%{count} месяца" + many: "%{count} месяцев" + other: "%{count} месяца" + about_x_years: + one: "около %{count} года" + few: "около %{count} лет" + many: "около %{count} лет" + other: "около %{count} лет" + over_x_years: + one: "больше %{count} года" + few: "больше %{count} лет" + many: "больше %{count} лет" + other: "больше %{count} лет" + almost_x_years: + one: "почти 1 год" + few: "почти %{count} года" + many: "почти %{count} лет" + other: "почти %{count} года" + prompts: + year: "Год" + month: "Месяц" + day: "День" + hour: "Часов" + minute: "Минут" + second: "Секунд" + + activerecord: + errors: + template: + header: + one: "%{model}: сохранение не удалось из-за %{count} ошибки" + few: "%{model}: сохранение не удалось из-за %{count} ошибок" + many: "%{model}: сохранение не удалось из-за %{count} ошибок" + other: "%{model}: сохранение не удалось из-за %{count} ошибки" + + body: "Проблемы возникли со следующими полями:" + + messages: + inclusion: "имеет непредусмотренное значение" + exclusion: "имеет зарезервированное значение" + invalid: "имеет неверное значение" + confirmation: "не совпадает с подтверждением" + accepted: "нужно подтвердить" + empty: "не может быть пустым" + blank: "не может быть пустым" + too_long: + one: "слишком большой длины (не может быть больше чем %{count} символ)" + few: "слишком большой длины (не может быть больше чем %{count} символа)" + many: "слишком большой длины (не может быть больше чем %{count} символов)" + other: "слишком большой длины (не может быть больше чем %{count} символа)" + too_short: + one: "недостаточной длины (не может быть меньше %{count} символа)" + few: "недостаточной длины (не может быть меньше %{count} символов)" + many: "недостаточной длины (не может быть меньше %{count} символов)" + other: "недостаточной длины (не может быть меньше %{count} символа)" + wrong_length: + one: "неверной длины (может быть длиной ровно %{count} символ)" + few: "неверной длины (может быть длиной ровно %{count} символа)" + many: "неверной длины (может быть длиной ровно %{count} символов)" + other: "неверной длины (может быть длиной ровно %{count} символа)" + taken: "уже существует" + not_a_number: "не является числом" + greater_than: "может иметь значение большее %{count}" + greater_than_or_equal_to: "может иметь значение большее или равное %{count}" + equal_to: "может иметь лишь значение, равное %{count}" + less_than: "может иметь значение меньшее чем %{count}" + less_than_or_equal_to: "может иметь значение меньшее или равное %{count}" + odd: "может иметь лишь нечетное значение" + even: "может иметь лишь четное значение" + greater_than_start_date: "должна быть позднее даты начала" + not_same_project: "не относится к одному проекту" + circular_dependency: "Такая связь приведет к циклической зависимости" + cant_link_an_issue_with_a_descendant: "Задача не может быть связана со своей подзадачей" + + support: + array: + # Rails 2.2 + sentence_connector: "и" + skip_last_comma: true + + # Rails 2.3 + words_connector: ", " + two_words_connector: " и " + last_word_connector: " и " + + actionview_instancetag_blank_option: Выберите + + button_activate: Активировать + button_add: Добавить + button_annotate: Авторство + button_apply: Применить + button_archive: Архивировать + button_back: Назад + button_cancel: Отмена + button_change_password: Изменить пароль + button_change: Изменить + button_check_all: Отметить все + button_clear: Очистить + button_configure: Параметры + button_copy: Копировать + button_create: Создать + button_create_and_continue: Создать и продолжить + button_delete: Удалить + button_download: Загрузить + button_edit: Редактировать + button_edit_associated_wikipage: "Редактировать связанную wiki-страницу: %{page_title}" + button_list: Список + button_lock: Заблокировать + button_login: Вход + button_log_time: Затраченное время + button_move: Переместить + button_quote: Цитировать + button_rename: Переименовать + button_reply: Ответить + button_reset: Сбросить + button_rollback: Вернуться к данной версии + button_save: Сохранить + button_sort: Сортировать + button_submit: Принять + button_test: Проверить + button_unarchive: Разархивировать + button_uncheck_all: Очистить + button_unlock: Разблокировать + button_unwatch: Не следить + button_update: Обновить + button_view: Просмотреть + button_watch: Следить + + default_activity_design: Проектирование + default_activity_development: Разработка + default_doc_category_tech: Техническая документация + default_doc_category_user: Пользовательская документация + default_issue_status_in_progress: В работе + default_issue_status_closed: Закрыта + default_issue_status_feedback: Обратная связь + default_issue_status_new: Новая + default_issue_status_rejected: Отклонена + default_issue_status_resolved: Решена + default_priority_high: Высокий + default_priority_immediate: Немедленный + default_priority_low: Низкий + default_priority_normal: Нормальный + default_priority_urgent: Срочный + default_role_developer: Разработчик + default_role_manager: Менеджер + default_role_reporter: Репортёр + default_tracker_bug: Ошибка + default_tracker_feature: Улучшение + default_tracker_support: Поддержка + + enumeration_activities: Действия (учет времени) + enumeration_doc_categories: Категории документов + enumeration_issue_priorities: Приоритеты задач + + error_can_not_remove_role: Эта роль используется и не может быть удалена. + error_can_not_delete_custom_field: Невозможно удалить настраиваемое поле + error_can_not_delete_tracker: Этот трекер содержит задачи и не может быть удален. + error_can_t_load_default_data: "Конфигурация по умолчанию не была загружена: %{value}" + error_issue_not_found_in_project: Задача не была найдена или не прикреплена к этому проекту + error_scm_annotate: "Данные отсутствуют или не могут быть подписаны." + error_scm_command_failed: "Ошибка доступа к хранилищу: %{value}" + error_scm_not_found: Хранилище не содержит записи и/или исправления. + error_unable_to_connect: Невозможно подключиться (%{value}) + error_unable_delete_issue_status: Невозможно удалить статус задачи + + field_account: Учетная запись + field_activity: Деятельность + field_admin: Администратор + field_assignable: Задача может быть назначена этой роли + field_assigned_to: Назначена + field_attr_firstname: Имя + field_attr_lastname: Фамилия + field_attr_login: Атрибут Login + field_attr_mail: email + field_author: Автор + field_auth_source: Режим аутентификации + field_base_dn: BaseDN + field_category: Категория + field_column_names: Столбцы + field_comments: Комментарий + field_comments_sorting: Отображение комментариев + field_content: Content + field_created_on: Создано + field_default_value: Значение по умолчанию + field_delay: Отложить + field_description: Описание + field_done_ratio: Готовность + field_downloads: Загрузки + field_due_date: Дата выполнения + field_editable: Редактируемое + field_effective_date: Дата + field_estimated_hours: Оценка времени + field_field_format: Формат + field_filename: Файл + field_filesize: Размер + field_firstname: Имя + field_fixed_version: Версия + field_hide_mail: Скрывать мой email + field_homepage: Стартовая страница + field_host: Компьютер + field_hours: час(а,ов) + field_identifier: Уникальный идентификатор + field_identity_url: OpenID URL + field_is_closed: Задача закрыта + field_is_default: Значение по умолчанию + field_is_filter: Используется в качестве фильтра + field_is_for_all: Для всех проектов + field_is_in_roadmap: Задачи, отображаемые в оперативном плане + field_is_public: Общедоступный + field_is_required: Обязательное + field_issue_to: Связанные задачи + field_issue: Задача + field_language: Язык + field_last_login_on: Последнее подключение + field_lastname: Фамилия + field_login: Пользователь + field_mail: Email + field_mail_notification: Уведомления по email + field_max_length: Максимальная длина + field_min_length: Минимальная длина + field_name: Имя + field_new_password: Новый пароль + field_notes: Примечания + field_onthefly: Создание пользователя на лету + field_parent_title: Родительская страница + field_parent: Родительский проект + field_parent_issue: Родительская задача + field_password_confirmation: Подтверждение + field_password: Пароль + field_port: Порт + field_possible_values: Возможные значения + field_priority: Приоритет + field_project: Проект + field_redirect_existing_links: Перенаправить существующие ссылки + field_regexp: Регулярное выражение + field_role: Роль + field_searchable: Доступно для поиска + field_spent_on: Дата + field_start_date: Начата + field_start_page: Стартовая страница + field_status: Статус + field_subject: Тема + field_subproject: Подпроект + field_summary: Краткое описание + field_text: Текстовое поле + field_time_entries: Затраченное время + field_time_zone: Часовой пояс + field_title: Заголовок + field_tracker: Трекер + field_type: Тип + field_updated_on: Обновлено + field_url: URL + field_user: Пользователь + field_value: Значение + field_version: Версия + field_watcher: Наблюдатель + + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Russian (Русский)' + general_pdf_encoding: UTF-8 + general_text_no: 'нет' + general_text_No: 'Нет' + general_text_yes: 'да' + general_text_Yes: 'Да' + + gui_validation_error: 1 ошибка + gui_validation_error_plural: "%{count} ошибок" + gui_validation_error_plural2: "%{count} ошибки" + gui_validation_error_plural5: "%{count} ошибок" + + label_activity: Действия + label_add_another_file: Добавить ещё один файл + label_added_time_by: "Добавил(а) %{author} %{age} назад" + label_added: добавлено + label_add_note: Добавить замечание + label_administration: Администрирование + label_age: Возраст + label_ago: дней(я) назад + label_all_time: всё время + label_all_words: Все слова + label_all: все + label_and_its_subprojects: "%{value} и все подпроекты" + label_applied_status: Применимый статус + label_ascending: По возрастанию + label_assigned_to_me_issues: Мои задачи + label_associated_revisions: Связанные редакции + label_attachment: Файл + label_attachment_delete: Удалить файл + label_attachment_new: Новый файл + label_attachment_plural: Файлы + label_attribute: Атрибут + label_attribute_plural: Атрибуты + label_authentication: Аутентификация + label_auth_source: Режим аутентификации + label_auth_source_new: Новый режим аутентификации + label_auth_source_plural: Режимы аутентификации + label_blocked_by: блокируется + label_blocks: блокирует + label_board: Форум + label_board_new: Новый форум + label_board_plural: Форумы + label_boolean: Логический + label_browse: Обзор + label_bulk_edit_selected_issues: Редактировать все выбранные задачи + label_calendar: Календарь + label_calendar_filter: Включая + label_calendar_no_assigned: не мои + label_change_plural: Правки + label_change_properties: Изменить свойства + label_change_status: Изменить статус + label_change_view_all: Просмотреть все изменения + label_changes_details: Подробности по всем изменениям + label_changeset_plural: Изменения + label_chronological_order: В хронологическом порядке + label_closed_issues: закрыто + label_closed_issues_plural: закрыто + label_closed_issues_plural2: закрыто + label_closed_issues_plural5: закрыто + label_comment: комментарий + label_comment_add: Оставить комментарий + label_comment_added: Добавленный комментарий + label_comment_delete: Удалить комментарии + label_comment_plural: Комментарии + label_comment_plural2: комментария + label_comment_plural5: комментариев + label_commits_per_author: Изменений на пользователя + label_commits_per_month: Изменений в месяц + label_confirmation: Подтверждение + label_contains: содержит + label_copied: скопировано + label_copy_workflow_from: Скопировать последовательность действий из + label_current_status: Текущий статус + label_current_version: Текущая версия + label_custom_field: Настраиваемое поле + label_custom_field_new: Новое настраиваемое поле + label_custom_field_plural: Настраиваемые поля + label_date_from: С + label_date_from_to: С %{start} по %{end} + label_date_range: временной интервал + label_date_to: по + label_date: Дата + label_day_plural: дней(я) + label_default: По умолчанию + label_default_columns: Столбцы по умолчанию + label_deleted: удалено + label_descending: По убыванию + label_details: Подробности + label_diff_inline: в тексте + label_diff_side_by_side: рядом + label_disabled: отключено + label_display: Отображение + label_display_per_page: "На страницу: %{value}" + label_document: Документ + label_document_added: Добавлен документ + label_document_new: Новый документ + label_document_plural: Документы + label_download: "%{count} загрузка" + label_download_plural: "%{count} скачиваний" + label_download_plural2: "%{count} загрузки" + label_download_plural5: "%{count} загрузок" + label_downloads_abbr: Скачиваний + label_duplicated_by: дублируется + label_duplicates: дублирует + label_end_to_end: с конца к концу + label_end_to_start: с конца к началу + label_enumeration_new: Новое значение + label_enumerations: Списки значений + label_environment: Окружение + label_equals: является + label_example: Пример + label_export_to: Экспортировать в + label_feed_plural: RSS + label_feeds_access_key_created_on: "Ключ доступа RSS создан %{value} назад" + label_f_hour: "%{value} час" + label_f_hour_plural: "%{value} часов" + label_file_added: Добавлен файл + label_file_plural: Файлы + label_filter_add: Добавить фильтр + label_filter_plural: Фильтры + label_float: С плавающей точкой + label_follows: предыдущая + label_gantt: Диаграмма Ганта + label_general: Общее + label_generate_key: Сгенерировать ключ + label_greater_or_equal: ">=" + label_help: Помощь + label_history: История + label_home: Домашняя страница + label_incoming_emails: Приём сообщений + label_index_by_date: История страниц + label_index_by_title: Оглавление + label_information_plural: Информация + label_information: Информация + label_in_less_than: менее чем + label_in_more_than: более чем + label_integer: Целый + label_internal: Внутренний + label_in: в + label_issue: Задача + label_issue_added: Добавлена задача + label_issue_category_new: Новая категория + label_issue_category_plural: Категории задачи + label_issue_category: Категория задачи + label_issue_new: Новая задача + label_issue_plural: Задачи + label_issues_by: "Сортировать по %{value}" + label_issue_status_new: Новый статус + label_issue_status_plural: Статусы задач + label_issue_status: Статус задачи + label_issue_tracking: Задачи + label_issue_updated: Обновлена задача + label_issue_view_all: Просмотреть все задачи + label_issue_watchers: Наблюдатели + label_jump_to_a_project: Перейти к проекту... + label_language_based: На основе языка + label_last_changes: "менее %{count} изменений" + label_last_login: Последнее подключение + label_last_month: последний месяц + label_last_n_days: "последние %{count} дней" + label_last_week: последняя неделя + label_latest_revision: Последняя редакция + label_latest_revision_plural: Последние редакции + label_ldap_authentication: Авторизация с помощью LDAP + label_less_or_equal: <= + label_less_than_ago: менее, чем дней(я) назад + label_list: Список + label_loading: Загрузка... + label_logged_as: Вошли как + label_login: Войти + label_login_with_open_id_option: или войти с помощью OpenID + label_logout: Выйти + label_max_size: Максимальный размер + label_member_new: Новый участник + label_member: Участник + label_member_plural: Участники + label_message_last: Последнее сообщение + label_message_new: Новое сообщение + label_message_plural: Сообщения + label_message_posted: Добавлено сообщение + label_me: мне + label_min_max_length: Минимальная - максимальная длина + label_modification: "%{count} изменение" + label_modification_plural: "%{count} изменений" + label_modification_plural2: "%{count} изменения" + label_modification_plural5: "%{count} изменений" + label_modified: изменено + label_module_plural: Модули + label_months_from: месяцев(ца) с + label_month: Месяц + label_more_than_ago: более, чем дней(я) назад + label_more: Больше + label_my_account: Моя учетная запись + label_my_page: Моя страница + label_my_page_block: Блок моей страницы + label_my_projects: Мои проекты + label_new: Новый + label_new_statuses_allowed: Разрешенные новые статусы + label_news_added: Добавлена новость + label_news_latest: Последние новости + label_news_new: Добавить новость + label_news_plural: Новости + label_news_view_all: Посмотреть все новости + label_news: Новости + label_next: Следующее + label_nobody: никто + label_no_change_option: (Нет изменений) + label_no_data: Нет данных для отображения + label_none: отсутствует + label_not_contains: не содержит + label_not_equals: не является + label_open_issues: открыто + label_open_issues_plural: открыто + label_open_issues_plural2: открыто + label_open_issues_plural5: открыто + label_optional_description: Описание (необязательно) + label_options: Опции + label_overall_activity: Сводный отчет действий + label_overview: Обзор + label_password_lost: Восстановление пароля + label_permissions_report: Отчет по правам доступа + label_permissions: Права доступа + label_per_page: На страницу + label_personalize_page: Персонализировать данную страницу + label_planning: Планирование + label_please_login: Пожалуйста, войдите. + label_plugins: Модули + label_precedes: следующая + label_preferences: Предпочтения + label_preview: Предпросмотр + label_previous: Предыдущее + label_profile: Профиль + label_project: Проект + label_project_all: Все проекты + label_project_copy_notifications: Отправлять уведомления по электронной почте при копировании проекта + label_project_latest: Последние проекты + label_project_new: Новый проект + label_project_plural: Проекты + label_project_plural2: проекта + label_project_plural5: проектов + label_public_projects: Общие проекты + label_query: Сохраненный запрос + label_query_new: Новый запрос + label_query_plural: Сохраненные запросы + label_read: Чтение... + label_register: Регистрация + label_registered_on: Зарегистрирован(а) + label_registration_activation_by_email: активация учетных записей по email + label_registration_automatic_activation: автоматическая активация учетных записей + label_registration_manual_activation: активировать учетные записи вручную + label_related_issues: Связанные задачи + label_relates_to: связана с + label_relation_delete: Удалить связь + label_relation_new: Новое отношение + label_renamed: переименовано + label_reply_plural: Ответы + label_report: Отчет + label_report_plural: Отчеты + label_reported_issues: Созданные задачи + label_repository: Хранилище + label_repository_plural: Хранилища + label_result_plural: Результаты + label_reverse_chronological_order: В обратном порядке + label_revision: Редакция + label_revision_plural: Редакции + label_roadmap: Оперативный план + label_roadmap_due_in: "В срок %{value}" + label_roadmap_no_issues: Нет задач для данной версии + label_roadmap_overdue: "опоздание %{value}" + label_role: Роль + label_role_and_permissions: Роли и права доступа + label_role_new: Новая роль + label_role_plural: Роли + label_scm: Тип хранилища + label_search: Поиск + label_search_titles_only: Искать только в названиях + label_send_information: Отправить пользователю информацию по учетной записи + label_send_test_email: Послать email для проверки + label_settings: Настройки + label_show_completed_versions: Показывать завершенные версии + label_sort: Сортировать + label_sort_by: "Сортировать по %{value}" + label_sort_higher: Вверх + label_sort_highest: В начало + label_sort_lower: Вниз + label_sort_lowest: В конец + label_spent_time: Затраченное время + label_start_to_end: с начала к концу + label_start_to_start: с начала к началу + label_statistics: Статистика + label_stay_logged_in: Оставаться в системе + label_string: Текст + label_subproject_plural: Подпроекты + label_subtask_plural: Подзадачи + label_text: Длинный текст + label_theme: Тема + label_this_month: этот месяц + label_this_week: на этой неделе + label_this_year: этот год + label_time_tracking: Учет времени + label_timelog_today: Расход времени на сегодня + label_today: сегодня + label_topic_plural: Темы + label_total: Всего + label_tracker: Трекер + label_tracker_new: Новый трекер + label_tracker_plural: Трекеры + label_updated_time: "Обновлено %{value} назад" + label_updated_time_by: "Обновлено %{author} %{age} назад" + label_used_by: Используется + label_user: Пользователь + label_user_activity: "Действия пользователя %{value}" + label_user_mail_no_self_notified: "Не извещать об изменениях, которые я сделал сам" + label_user_mail_option_all: "О всех событиях во всех моих проектах" + label_user_mail_option_selected: "О всех событиях только в выбранном проекте..." + label_user_mail_option_only_owner: Только для объектов, для которых я являюсь владельцем + label_user_mail_option_only_my_events: Только для объектов, которые я отслеживаю или в которых участвую + label_user_mail_option_only_assigned: Только для объектов, которые назначены мне + label_user_new: Новый пользователь + label_user_plural: Пользователи + label_version: Версия + label_version_new: Новая версия + label_version_plural: Версии + label_view_diff: Просмотреть отличия + label_view_revisions: Просмотреть редакции + label_watched_issues: Отслеживаемые задачи + label_week: Неделя + label_wiki: Wiki + label_wiki_edit: Редактирование Wiki + label_wiki_edit_plural: Wiki + label_wiki_page: Страница Wiki + label_wiki_page_plural: Страницы Wiki + label_workflow: Последовательность действий + label_x_closed_issues_abbr: + zero: "0 закрыто" + one: "1 закрыт" + few: "%{count} закрыто" + many: "%{count} закрыто" + other: "%{count} закрыто" + label_x_comments: + zero: "нет комментариев" + one: "1 комментарий" + few: "%{count} комментария" + many: "%{count} комментариев" + other: "%{count} комментариев" + label_x_open_issues_abbr: + zero: "0 открыто" + one: "1 открыт" + few: "%{count} открыто" + many: "%{count} открыто" + other: "%{count} открыто" + label_x_open_issues_abbr_on_total: + zero: "0 открыто / %{total}" + one: "1 открыт / %{total}" + few: "%{count} открыто / %{total}" + many: "%{count} открыто / %{total}" + other: "%{count} открыто / %{total}" + label_x_projects: + zero: "нет проектов" + one: "1 проект" + few: "%{count} проекта" + many: "%{count} проектов" + other: "%{count} проектов" + label_year: Год + label_yesterday: вчера + + mail_body_account_activation_request: "Зарегистрирован новый пользователь (%{value}). Учетная запись ожидает Вашего утверждения:" + mail_body_account_information: Информация о Вашей учетной записи + mail_body_account_information_external: "Вы можете использовать Вашу %{value} учетную запись для входа." + mail_body_lost_password: 'Для изменения пароля пройдите по следующей ссылке:' + mail_body_register: 'Для активации учетной записи пройдите по следующей ссылке:' + mail_body_reminder: "%{count} назначенных на Вас задач на следующие %{days} дней:" + mail_subject_account_activation_request: "Запрос на активацию пользователя в системе %{value}" + mail_subject_lost_password: "Ваш %{value} пароль" + mail_subject_register: "Активация учетной записи %{value}" + mail_subject_reminder: "%{count} назначенных на Вас задач в ближайшие %{days} дней" + + notice_account_activated: Ваша учетная запись активирована. Вы можете войти. + notice_account_invalid_creditentials: Неправильное имя пользователя или пароль + notice_account_lost_email_sent: Вам отправлено письмо с инструкциями по выбору нового пароля. + notice_account_password_updated: Пароль успешно обновлен. + notice_account_pending: "Ваша учетная запись создана и ожидает подтверждения администратора." + notice_account_register_done: Учетная запись успешно создана. Для активации Вашей учетной записи пройдите по ссылке, которая выслана Вам по электронной почте. + notice_account_unknown_email: Неизвестный пользователь. + notice_account_updated: Учетная запись успешно обновлена. + notice_account_wrong_password: Неверный пароль + notice_can_t_change_password: Для данной учетной записи используется источник внешней аутентификации. Невозможно изменить пароль. + notice_default_data_loaded: Была загружена конфигурация по умолчанию. + notice_email_error: "Во время отправки письма произошла ошибка (%{value})" + notice_email_sent: "Отправлено письмо %{value}" + notice_failed_to_save_issues: "Не удалось сохранить %{count} пункт(ов) из %{total} выбранных: %{ids}." + notice_failed_to_save_members: "Не удалось сохранить участника(ов): %{errors}." + notice_feeds_access_key_reseted: Ваш ключ доступа RSS был сброшен. + notice_file_not_found: Страница, на которую Вы пытаетесь зайти, не существует или удалена. + notice_locking_conflict: Информация обновлена другим пользователем. + notice_no_issue_selected: "Не выбрано ни одной задачи! Пожалуйста, отметьте задачи, которые Вы хотите отредактировать." + notice_not_authorized: У Вас нет прав для посещения данной страницы. + notice_successful_connection: Подключение успешно установлено. + notice_successful_create: Создание успешно. + notice_successful_delete: Удаление успешно. + notice_successful_update: Обновление успешно. + notice_unable_delete_version: Невозможно удалить версию. + + permission_add_issues: Добавление задач + permission_add_issue_notes: Добавление примечаний + permission_add_issue_watchers: Добавление наблюдателей + permission_add_messages: Отправка сообщений + permission_browse_repository: Просмотр хранилища + permission_comment_news: Комментирование новостей + permission_commit_access: Изменение файлов в хранилище + permission_delete_issues: Удаление задач + permission_delete_messages: Удаление сообщений + permission_delete_own_messages: Удаление собственных сообщений + permission_delete_wiki_pages: Удаление wiki-страниц + permission_delete_wiki_pages_attachments: Удаление прикрепленных файлов + permission_edit_issue_notes: Редактирование примечаний + permission_edit_issues: Редактирование задач + permission_edit_messages: Редактирование сообщений + permission_edit_own_issue_notes: Редактирование собственных примечаний + permission_edit_own_messages: Редактирование собственных сообщений + permission_edit_own_time_entries: Редактирование собственного учета времени + permission_edit_project: Редактирование проектов + permission_edit_time_entries: Редактирование учета времени + permission_edit_wiki_pages: Редактирование wiki-страниц + permission_export_wiki_pages: Экспорт wiki-страниц + permission_log_time: Учет затраченного времени + permission_view_changesets: Просмотр изменений хранилища + permission_view_time_entries: Просмотр затраченного времени + permission_manage_project_activities: Управление типами действий для проекта + permission_manage_boards: Управление форумами + permission_manage_categories: Управление категориями задач + permission_manage_documents: Управление документами + permission_manage_files: Управление файлами + permission_manage_issue_relations: Управление связыванием задач + permission_manage_members: Управление участниками + permission_manage_news: Управление новостями + permission_manage_public_queries: Управление общими запросами + permission_manage_repository: Управление хранилищем + permission_manage_subtasks: Управление подзадачами + permission_manage_versions: Управление версиями + permission_manage_wiki: Управление Wiki + permission_move_issues: Перенос задач + permission_protect_wiki_pages: Блокирование wiki-страниц + permission_rename_wiki_pages: Переименование wiki-страниц + permission_save_queries: Сохранение запросов + permission_select_project_modules: Выбор модулей проекта + permission_view_calendar: Просмотр календаря + permission_view_documents: Просмотр документов + permission_view_files: Просмотр файлов + permission_view_gantt: Просмотр диаграммы Ганта + permission_view_issue_watchers: Просмотр списка наблюдателей + permission_view_messages: Просмотр сообщение + permission_view_wiki_edits: Просмотр истории Wiki + permission_view_wiki_pages: Просмотр Wiki + + project_module_boards: Форумы + project_module_documents: Документы + project_module_files: Файлы + project_module_issue_tracking: Задачи + project_module_news: Новости + project_module_repository: Хранилище + project_module_time_tracking: Учет времени + project_module_wiki: Wiki + project_module_gantt: Диаграмма Ганта + project_module_calendar: Календарь + + setting_activity_days_default: Количество дней, отображаемых в Действиях + setting_app_subtitle: Подзаголовок приложения + setting_app_title: Название приложения + setting_attachment_max_size: Максимальный размер вложения + setting_autofetch_changesets: Автоматически следить за изменениями хранилища + setting_autologin: Автоматический вход + setting_bcc_recipients: Использовать скрытые копии (BCC) + setting_cache_formatted_text: Кешировать форматированный текст + setting_commit_fix_keywords: Назначение ключевых слов + setting_commit_ref_keywords: Ключевые слова для поиска + setting_cross_project_issue_relations: Разрешить пересечение задач по проектам + setting_date_format: Формат даты + setting_default_language: Язык по умолчанию + setting_default_notification_option: Способ оповещения по умолчанию + setting_default_projects_public: Новые проекты являются общедоступными + setting_diff_max_lines_displayed: Максимальное число строк для diff + setting_display_subprojects_issues: Отображение подпроектов по умолчанию + setting_emails_footer: Подстрочные примечания письма + setting_enabled_scm: Разрешенные SCM + setting_feeds_limit: Ограничение количества заголовков для RSS потока + setting_file_max_size_displayed: Максимальный размер текстового файла для отображения + setting_gravatar_enabled: Использовать аватар пользователя из Gravatar + setting_host_name: Имя компьютера + setting_issue_list_default_columns: Столбцы, отображаемые в списке задач по умолчанию + setting_issues_export_limit: Ограничение по экспортируемым задачам + setting_login_required: Необходима аутентификация + setting_mail_from: Исходящий email адрес + setting_mail_handler_api_enabled: Включить веб-сервис для входящих сообщений + setting_mail_handler_api_key: API ключ + setting_openid: Разрешить OpenID для входа и регистрации + setting_per_page_options: Количество записей на страницу + setting_plain_text_mail: Только простой текст (без HTML) + setting_protocol: Протокол + setting_repository_log_display_limit: Максимальное количество редакций, отображаемых в журнале изменений + setting_self_registration: Саморегистрация + setting_sequential_project_identifiers: Генерировать последовательные идентификаторы проектов + setting_sys_api_enabled: Включить веб-сервис для управления хранилищем + setting_text_formatting: Форматирование текста + setting_time_format: Формат времени + setting_user_format: Формат отображения имени + setting_welcome_text: Текст приветствия + setting_wiki_compression: Сжатие истории Wiki + + status_active: активен + status_locked: заблокирован + status_registered: зарегистрирован + + text_are_you_sure_with_children: Удалить задачу и все ее подзадачи? + text_are_you_sure: Вы уверены? + text_assign_time_entries_to_project: Прикрепить зарегистрированное время к проекту + text_caracters_maximum: "Максимум %{count} символов(а)." + text_caracters_minimum: "Должно быть не менее %{count} символов." + text_comma_separated: Допустимы несколько значений (через запятую). + text_custom_field_possible_values_info: 'По одному значению в каждой строке' + text_default_administrator_account_changed: Учетная запись администратора по умолчанию изменена + text_destroy_time_entries_question: "На эту задачу зарегистрировано %{hours} часа(ов) затраченного времени. Что Вы хотите предпринять?" + text_destroy_time_entries: Удалить зарегистрированное время + text_diff_truncated: '... Этот diff ограничен, так как превышает максимальный отображаемый размер.' + text_email_delivery_not_configured: "Параметры работы с почтовым сервером не настроены и функция уведомления по email не активна.\nНастроить параметры для Вашего SMTP-сервера Вы можете в файле config/configuration.yml. Для применения изменений перезапустите приложение." + text_enumeration_category_reassign_to: 'Назначить им следующее значение:' + text_enumeration_destroy_question: "%{count} объект(а,ов) связаны с этим значением." + text_file_repository_writable: Хранилище с доступом на запись + text_issue_added: "Создана новая задача %{id} (%{author})." + text_issue_category_destroy_assignments: Удалить назначения категории + text_issue_category_destroy_question: "Несколько задач (%{count}) назначено в данную категорию. Что Вы хотите предпринять?" + text_issue_category_reassign_to: Переназначить задачи для данной категории + text_issues_destroy_confirmation: 'Вы уверены, что хотите удалить выбранные задачи?' + text_issues_ref_in_commit_messages: Сопоставление и изменение статуса задач исходя из текста сообщений + text_issue_updated: "Задача %{id} была обновлена (%{author})." + text_journal_changed: "Параметр %{label} изменился с %{old} на %{new}" + text_journal_deleted: "Значение %{old} параметра %{label} удалено" + text_journal_set_to: "Параметр %{label} изменился на %{value}" + text_length_between: "Длина между %{min} и %{max} символов." + text_load_default_configuration: Загрузить конфигурацию по умолчанию + text_min_max_length_info: 0 означает отсутствие ограничений + text_no_configuration_data: "Роли, трекеры, статусы задач и оперативный план не были сконфигурированы.\nНастоятельно рекомендуется загрузить конфигурацию по-умолчанию. Вы сможете её изменить потом." + text_plugin_assets_writable: Каталог модулей доступен для записи + text_project_destroy_confirmation: Вы настаиваете на удалении данного проекта и всей относящейся к нему информации? + text_project_identifier_info: 'Допустимы строчные буквы (a-z), цифры и дефис.
    Сохраненный идентификатор не может быть изменен.' + text_reassign_time_entries: 'Перенести зарегистрированное время на следующую задачу:' + text_regexp_info: "например: ^[A-Z0-9]+$" + text_repository_usernames_mapping: "Выберите или обновите пользователя Redmine, связанного с найденными именами в журнале хранилища.\nПользователи с одинаковыми именами или email в Redmine и хранилище связываются автоматически." + text_rmagick_available: Доступно использование RMagick (опционально) + text_select_mail_notifications: Выберите действия, при которых будет отсылаться уведомление на электронную почту. + text_select_project_modules: 'Выберите модули, которые будут использованы в проекте:' + text_status_changed_by_changeset: "Реализовано в %{value} редакции." + text_subprojects_destroy_warning: "Подпроекты: %{value} также будут удалены." + text_tip_issue_begin_day: дата начала задачи + text_tip_issue_begin_end_day: начало задачи и окончание ее в этот же день + text_tip_issue_end_day: дата завершения задачи + text_tracker_no_workflow: Для этого трекера последовательность действий не определена + text_unallowed_characters: Запрещенные символы + text_user_mail_option: "Для невыбранных проектов, Вы будете получать уведомления только о том, что просматриваете или в чем участвуете (например, задачи, автором которых Вы являетесь, или которые Вам назначены)." + text_user_wrote: "%{value} писал(а):" + text_wiki_destroy_confirmation: Вы уверены, что хотите удалить данную Wiki и все ее содержимое? + text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний + + warning_attachments_not_saved: "%{count} файл(ов) невозможно сохранить." + text_wiki_page_destroy_question: Эта страница имеет %{descendants} дочерних страниц и их потомков. Что вы хотите предпринять? + text_wiki_page_reassign_children: Переопределить дочерние страницы на текущую страницу + text_wiki_page_nullify_children: Сделать дочерние страницы главными страницами + text_wiki_page_destroy_children: Удалить дочерние страницы и всех их потомков + setting_password_min_length: Минимальная длина пароля + field_group_by: Группировать результаты по + mail_subject_wiki_content_updated: "Wiki-страница '%{id}' была обновлена" + label_wiki_content_added: Добавлена wiki-страница + mail_subject_wiki_content_added: "Wiki-страница '%{id}' была добавлена" + mail_body_wiki_content_added: "%{author} добавил(а) wiki-страницу '%{id}'." + label_wiki_content_updated: Обновлена wiki-страница + mail_body_wiki_content_updated: "%{author} обновил(а) wiki-страницу '%{id}'." + permission_add_project: Создание проекта + setting_new_project_user_role_id: Роль, назначаемая пользователю, создавшему проект + label_view_all_revisions: Показать все ревизии + label_tag: Метка + label_branch: Ветвь + error_no_tracker_in_project: С этим проектом не ассоциирован ни один трекер. Проверьте настройки проекта. + error_no_default_issue_status: Не определен статус задач по умолчанию. Проверьте настройки (см. "Администрирование -> Статусы задач"). + label_group_plural: Группы + label_group: Группа + label_group_new: Новая группа + label_time_entry_plural: Затраченное время + text_journal_added: "%{label} %{value} добавлен" + field_active: Активно + enumeration_system_activity: Системное + permission_delete_issue_watchers: Удаление наблюдателей + version_status_closed: закрыт + version_status_locked: заблокирован + version_status_open: открыт + error_can_not_reopen_issue_on_closed_version: Задача, назначенная к закрытой версии, не сможет быть открыта снова + label_user_anonymous: Аноним + button_move_and_follow: Переместить и перейти + setting_default_projects_modules: Включенные по умолчанию модули для новых проектов + setting_gravatar_default: Изображение Gravatar по умолчанию + field_sharing: Совместное использование + label_version_sharing_hierarchy: С иерархией проектов + label_version_sharing_system: Со всеми проектами + label_version_sharing_descendants: С подпроектами + label_version_sharing_tree: С деревом проектов + label_version_sharing_none: Без совместного использования + error_can_not_archive_project: Этот проект не может быть заархивирован + button_duplicate: Дублировать + button_copy_and_follow: Копировать и продолжить + label_copy_source: Источник + setting_issue_done_ratio: Рассчитывать готовность задачи с помощью поля + setting_issue_done_ratio_issue_status: Статус задачи + error_issue_done_ratios_not_updated: Параметр готовность задач не обновлен + error_workflow_copy_target: Выберите целевые трекеры и роли + setting_issue_done_ratio_issue_field: Готовность задачи + label_copy_same_as_target: То же, что и у цели + label_copy_target: Цель + notice_issue_done_ratios_updated: Параметр «готовность» обновлен. + error_workflow_copy_source: Выберите исходный трекер или роль + label_update_issue_done_ratios: Обновить готовность задач + setting_start_of_week: День начала недели + label_api_access_key: Ключ доступа к API + text_line_separated: Разрешено несколько значений (по одному значению в строку). + label_revision_id: Ревизия %{value} + permission_view_issues: Просмотр задач + label_display_used_statuses_only: Отображать только те статусы, которые используются в этом трекере + label_api_access_key_created_on: Ключ доступ к API был создан %{value} назад + label_feeds_access_key: Ключ доступа к RSS + notice_api_access_key_reseted: Ваш ключ доступа к API был сброшен. + setting_rest_api_enabled: Включить веб-сервис REST + button_show: Показать + label_missing_api_access_key: Отсутствует ключ доступа к API + label_missing_feeds_access_key: Отсутствует ключ доступа к RSS + setting_mail_handler_body_delimiters: Урезать письмо после одной из этих строк + permission_add_subprojects: Создание подпроектов + label_subproject_new: Новый подпроект + text_own_membership_delete_confirmation: |- + Вы собираетесь удалить некоторые или все права, из-за чего могут пропасть права на редактирование этого проекта. + Продолжить? + label_close_versions: Закрыть завершенные версии + label_board_sticky: Прикреплена + label_board_locked: Заблокирована + field_principal: Имя + text_zoom_out: Отдалить + text_zoom_in: Приблизить + notice_unable_delete_time_entry: Невозможно удалить запись журнала. + label_overall_spent_time: Всего затрачено времени + label_user_mail_option_none: Нет событий + field_member_of_group: Группа назначенного + field_assigned_to_role: Роль назначенного + notice_not_authorized_archived_project: Запрашиваемый проект был архивирован. + label_principal_search: "Найти пользователя или группу:" + label_user_search: "Найти пользователя:" + field_visible: Видимое + setting_emails_header: Заголовок письма + + setting_commit_logtime_activity_id: Действие для учета времени + text_time_logged_by_changeset: Учтено в редакции %{value}. + setting_commit_logtime_enabled: Включить учет времени + notice_gantt_chart_truncated: Диаграмма будет усечена, поскольку превышено максимальное кол-во элементов, которые могут отображаться (%{max}) + setting_gantt_items_limit: Максимальное кол-во элементов отображаемых на диаграмме Ганта + field_warn_on_leaving_unsaved: Предупреждать при закрытии страницы с несохраненным текстом + text_warn_on_leaving_unsaved: Текущая страница содержит несохраненный текст, который будет потерян, если вы покинете эту страницу. + label_my_queries: Мои сохраненные запросы + text_journal_changed_no_detail: "%{label} обновлено" + label_news_comment_added: Добавлен комментарий к новости + button_expand_all: Развернуть все + button_collapse_all: Свернуть все + label_additional_workflow_transitions_for_assignee: Дополнительные переходы, когда пользователь является исполнителем + label_additional_workflow_transitions_for_author: Дополнительные переходы, когда пользователь является автором + label_bulk_edit_selected_time_entries: Массовое изменение выбранных записей затраченного времени + text_time_entries_destroy_confirmation: Вы уверены что хотите удалить выбранные записи затраченного времени? + label_role_anonymous: Аноним + label_role_non_member: Не участник + label_issue_note_added: Примечание добавлено + label_issue_status_updated: Статус обновлен + label_issue_priority_updated: Приоритет обновлен + label_issues_visibility_own: Задачи созданные или назначенные пользователю + field_issues_visibility: Видимость задач + label_issues_visibility_all: Все задачи + permission_set_own_issues_private: Установление видимости (общая/частная) для собственных задач + field_is_private: Частная + permission_set_issues_private: Установление видимости (общая/частная) для задач + label_issues_visibility_public: Только общие задачи + text_issues_destroy_descendants_confirmation: Так же будет удалено %{count} задач(и). + field_commit_logs_encoding: Кодировка комментариев в хранилище + field_scm_path_encoding: Кодировка пути + text_scm_path_encoding_note: "По умолчанию: UTF-8" + field_path_to_repository: Путь к хранилищу + field_root_directory: Корневая директория + field_cvs_module: Модуль + field_cvsroot: CVSROOT + text_mercurial_repository_note: Локальное хранилище (например, /hgrepo, c:\hgrepo) + text_scm_command: Команда + text_scm_command_version: Версия + label_git_report_last_commit: Указывать последнее изменения для файлов и директорий + text_scm_config: Вы можете настроить команды SCM в файле config/configuration.yml. Пожалуйста, перезапустите приложение после редактирования этого файла. + text_scm_command_not_available: Команда системы контроля версий недоступна. Пожалуйста, проверьте настройки в административной панели. + notice_issue_successful_create: Задача %{id} создана. + label_between: между + setting_issue_group_assignment: Разрешить назначение задач группам пользователей + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/689ac1bb7ff5cc9966ab0877e8f6f03c5f72ee2b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/68/689ac1bb7ff5cc9966ab0877e8f6f03c5f72ee2b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,282 @@ +module RedmineDiff + class Diff + + VERSION = 0.3 + + def Diff.lcs(a, b) + astart = 0 + bstart = 0 + afinish = a.length-1 + bfinish = b.length-1 + mvector = [] + + # First we prune off any common elements at the beginning + while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart]) + mvector[astart] = bstart + astart += 1 + bstart += 1 + end + + # now the end + while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish]) + mvector[afinish] = bfinish + afinish -= 1 + bfinish -= 1 + end + + bmatches = b.reverse_hash(bstart..bfinish) + thresh = [] + links = [] + + (astart..afinish).each { |aindex| + aelem = a[aindex] + next unless bmatches.has_key? aelem + k = nil + bmatches[aelem].reverse.each { |bindex| + if k && (thresh[k] > bindex) && (thresh[k-1] < bindex) + thresh[k] = bindex + else + k = thresh.replacenextlarger(bindex, k) + end + links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k + } + } + + if !thresh.empty? + link = links[thresh.length-1] + while link + mvector[link[1]] = link[2] + link = link[0] + end + end + + return mvector + end + + def makediff(a, b) + mvector = Diff.lcs(a, b) + ai = bi = 0 + while ai < mvector.length + bline = mvector[ai] + if bline + while bi < bline + discardb(bi, b[bi]) + bi += 1 + end + match(ai, bi) + bi += 1 + else + discarda(ai, a[ai]) + end + ai += 1 + end + while ai < a.length + discarda(ai, a[ai]) + ai += 1 + end + while bi < b.length + discardb(bi, b[bi]) + bi += 1 + end + match(ai, bi) + 1 + end + + def compactdiffs + diffs = [] + @diffs.each { |df| + i = 0 + curdiff = [] + while i < df.length + whot = df[i][0] + s = @isstring ? df[i][2].chr : [df[i][2]] + p = df[i][1] + last = df[i][1] + i += 1 + while df[i] && df[i][0] == whot && df[i][1] == last+1 + s << df[i][2] + last = df[i][1] + i += 1 + end + curdiff.push [whot, p, s] + end + diffs.push curdiff + } + return diffs + end + + attr_reader :diffs, :difftype + + def initialize(diffs_or_a, b = nil, isstring = nil) + if b.nil? + @diffs = diffs_or_a + @isstring = isstring + else + @diffs = [] + @curdiffs = [] + makediff(diffs_or_a, b) + @difftype = diffs_or_a.class + end + end + + def match(ai, bi) + @diffs.push @curdiffs unless @curdiffs.empty? + @curdiffs = [] + end + + def discarda(i, elem) + @curdiffs.push ['-', i, elem] + end + + def discardb(i, elem) + @curdiffs.push ['+', i, elem] + end + + def compact + return Diff.new(compactdiffs) + end + + def compact! + @diffs = compactdiffs + end + + def inspect + @diffs.inspect + end + + end +end + +module Diffable + def diff(b) + RedmineDiff::Diff.new(self, b) + end + + # Create a hash that maps elements of the array to arrays of indices + # where the elements are found. + + def reverse_hash(range = (0...self.length)) + revmap = {} + range.each { |i| + elem = self[i] + if revmap.has_key? elem + revmap[elem].push i + else + revmap[elem] = [i] + end + } + return revmap + end + + def replacenextlarger(value, high = nil) + high ||= self.length + if self.empty? || value > self[-1] + push value + return high + end + # binary search for replacement point + low = 0 + while low < high + index = (high+low)/2 + found = self[index] + return nil if value == found + if value > found + low = index + 1 + else + high = index + end + end + + self[low] = value + # $stderr << "replace #{value} : 0/#{low}/#{init_high} (#{steps} steps) (#{init_high-low} off )\n" + # $stderr.puts self.inspect + #gets + #p length - low + return low + end + + def patch(diff) + newary = nil + if diff.difftype == String + newary = diff.difftype.new('') + else + newary = diff.difftype.new + end + ai = 0 + bi = 0 + diff.diffs.each { |d| + d.each { |mod| + case mod[0] + when '-' + while ai < mod[1] + newary << self[ai] + ai += 1 + bi += 1 + end + ai += 1 + when '+' + while bi < mod[1] + newary << self[ai] + ai += 1 + bi += 1 + end + newary << mod[2] + bi += 1 + else + raise "Unknown diff action" + end + } + } + while ai < self.length + newary << self[ai] + ai += 1 + bi += 1 + end + return newary + end +end + +class Array + include Diffable +end + +class String + include Diffable +end + +=begin + = Diff + (({diff.rb})) - computes the differences between two arrays or + strings. Copyright (C) 2001 Lars Christensen + + == Synopsis + + diff = Diff.new(a, b) + b = a.patch(diff) + + == Class Diff + === Class Methods + --- Diff.new(a, b) + --- a.diff(b) + Creates a Diff object which represent the differences between + ((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays + of any objects, strings, or object of any class that include + module ((|Diffable|)) + + == Module Diffable + The module ((|Diffable|)) is intended to be included in any class for + which differences are to be computed. Diffable is included into String + and Array when (({diff.rb})) is (({require}))'d. + + Classes including Diffable should implement (({[]})) to get element at + integer indices, (({<<})) to append elements to the object and + (({ClassName#new})) should accept 0 arguments to create a new empty + object. + + === Instance Methods + --- Diffable#patch(diff) + Applies the differences from ((|diff|)) to the object ((|obj|)) + and return the result. ((|obj|)) is not changed. ((|obj|)) and + can be either an array or a string, but must match the object + from which the ((|diff|)) was created. +=end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/68b00a7a7b3e47a6b7ab9ab847a8664cc85e3341.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/68/68b00a7a7b3e47a6b7ab9ab847a8664cc85e3341.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +default: + somesetting: foo + +production: + +development: + +test: diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/68ece530a0ccbfc8971b82acf79987aea8d5c3f8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/68/68ece530a0ccbfc8971b82acf79987aea8d5c3f8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +<% form_tag({}, :method => :delete) do %> +
    +

    <%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %>

    +


    + +<% if @reassignable_to.any? %> +
    +: +<%= label_tag "reassign_to_id", l(:description_wiki_subpages_reassign), :class => "hidden-for-sighted" %> +<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to), + :onclick => "$('todo_reassign').checked = true;" %> +<% end %> +

    +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/68/68f2959a12b15f675878392447e35e71f3fc6417.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/68/68f2959a12b15f675878392447e35e71f3fc6417.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class RenameCommentToComments < ActiveRecord::Migration + def self.up + rename_column(:comments, :comment, :comments) if ActiveRecord::Base.connection.columns(Comment.table_name).detect{|c| c.name == "comment"} + rename_column(:wiki_contents, :comment, :comments) if ActiveRecord::Base.connection.columns(WikiContent.table_name).detect{|c| c.name == "comment"} + rename_column(:wiki_content_versions, :comment, :comments) if ActiveRecord::Base.connection.columns(WikiContent.versioned_table_name).detect{|c| c.name == "comment"} + rename_column(:time_entries, :comment, :comments) if ActiveRecord::Base.connection.columns(TimeEntry.table_name).detect{|c| c.name == "comment"} + rename_column(:changesets, :comment, :comments) if ActiveRecord::Base.connection.columns(Changeset.table_name).detect{|c| c.name == "comment"} + end + + def self.down + raise IrreversibleMigration + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/69158657960dc5c8b5881d15914dd410bb7c7a73.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/69158657960dc5c8b5881d15914dd410bb7c7a73.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Namespace::AppAndPluginController < ApplicationController + def an_action + render_class_and_action 'from app' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/6975387439910072689171fac66ca5755876b0a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/6975387439910072689171fac66ca5755876b0a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,107 @@ +require File.expand_path('../../test_helper', __FILE__) +require 'issue_statuses_controller' + +# Re-raise errors caught by the controller. +class IssueStatusesController; def rescue_action(e) raise e end; end + + +class IssueStatusesControllerTest < ActionController::TestCase + fixtures :issue_statuses, :issues + + def setup + @controller = IssueStatusesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 1 # admin + end + + def test_index + get :index + assert_response :success + assert_template 'index' + end + + def test_index_by_anonymous_should_redirect_to_login_form + @request.session[:user_id] = nil + get :index + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fissue_statuses' + end + + def test_index_by_user_should_respond_with_406 + @request.session[:user_id] = 2 + get :index + assert_response 406 + end + + def test_new + get :new + assert_response :success + assert_template 'new' + end + + def test_create + assert_difference 'IssueStatus.count' do + post :create, :issue_status => {:name => 'New status'} + end + assert_redirected_to :action => 'index' + status = IssueStatus.find(:first, :order => 'id DESC') + assert_equal 'New status', status.name + end + + def test_edit + get :edit, :id => '3' + assert_response :success + assert_template 'edit' + end + + def test_update + put :update, :id => '3', :issue_status => {:name => 'Renamed status'} + assert_redirected_to :action => 'index' + status = IssueStatus.find(3) + assert_equal 'Renamed status', status.name + end + + def test_destroy + Issue.delete_all("status_id = 1") + + assert_difference 'IssueStatus.count', -1 do + delete :destroy, :id => '1' + end + assert_redirected_to :action => 'index' + assert_nil IssueStatus.find_by_id(1) + end + + def test_destroy_should_block_if_status_in_use + assert_not_nil Issue.find_by_status_id(1) + + assert_no_difference 'IssueStatus.count' do + delete :destroy, :id => '1' + end + assert_redirected_to :action => 'index' + assert_not_nil IssueStatus.find_by_id(1) + end + + context "on POST to :update_issue_done_ratio" do + context "with Setting.issue_done_ratio using the issue_field" do + setup do + Setting.issue_done_ratio = 'issue_field' + post :update_issue_done_ratio + end + + should_set_the_flash_to /not updated/ + should_redirect_to('the index') { '/issue_statuses' } + end + + context "with Setting.issue_done_ratio using the issue_status" do + setup do + Setting.issue_done_ratio = 'issue_status' + post :update_issue_done_ratio + end + + should_set_the_flash_to /Issue done ratios updated/ + should_redirect_to('the index') { '/issue_statuses' } + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/6985b7da5db7388f839f13e1c4ad6f39ec6acc94.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/6985b7da5db7388f839f13e1c4ad6f39ec6acc94.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,94 @@ +require File.expand_path('../../test_helper', __FILE__) + +class AuthSourcesControllerTest < ActionController::TestCase + + def setup + @request.session[:user_id] = 1 + end + + context "get :index" do + setup do + get :index + end + + should_assign_to :auth_sources + should_assign_to :auth_source_pages + should_respond_with :success + should_render_template :index + end + + context "get :new" do + setup do + get :new + end + + should_assign_to :auth_source + should_respond_with :success + should_render_template :new + + should "initilize a new AuthSource" do + assert_equal AuthSource, assigns(:auth_source).class + assert assigns(:auth_source).new_record? + end + end + + context "post :create" do + setup do + post :create, :auth_source => {:name => 'Test'} + end + + should_respond_with :redirect + should_redirect_to("index") {{:action => 'index'}} + should_set_the_flash_to /success/i + end + + context "get :edit" do + setup do + @auth_source = AuthSource.generate!(:name => 'TestEdit') + get :edit, :id => @auth_source.id + end + + should_assign_to(:auth_source) {@auth_source} + should_respond_with :success + should_render_template :edit + end + + context "post :update" do + setup do + @auth_source = AuthSource.generate!(:name => 'TestEdit') + post :update, :id => @auth_source.id, :auth_source => {:name => 'TestUpdate'} + end + + should_respond_with :redirect + should_redirect_to("index") {{:action => 'index'}} + should_set_the_flash_to /update/i + end + + context "post :destroy" do + setup do + @auth_source = AuthSource.generate!(:name => 'TestEdit') + end + + context "without users" do + setup do + post :destroy, :id => @auth_source.id + end + + should_respond_with :redirect + should_redirect_to("index") {{:action => 'index'}} + should_set_the_flash_to /deletion/i + end + + context "with users" do + setup do + User.generate!(:auth_source => @auth_source) + post :destroy, :id => @auth_source.id + end + + should_respond_with :redirect + should "not destroy the AuthSource" do + assert AuthSource.find(@auth_source.id) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/698f61b75b6827fc986074ba0064676c404b5ac4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/698f61b75b6827fc986074ba0064676c404b5ac4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar LV language +// Translation: Dzintars Bergs, dzintars.bergs@gmail.com +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Svētdiena", + "Pirmdiena", + "Otrdiena", + "Trešdiena", + "Ceturtdiena", + "Piektdiena", + "Sestdiena", + "Svētdiena"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Sv", + "Pr", + "Ot", + "Tr", + "Ct", + "Pk", + "St", + "Sv"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Janvāris", + "Februāris", + "Marts", + "Aprīlis", + "Maijs", + "Jūnijs", + "Jūlijs", + "Augusts", + "Septembris", + "Oktobris", + "Novembris", + "Decembris"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Mai", + "Jūn", + "Jūl", + "Aug", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Par kalendāru"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Iepriekšējais gads (pieturēt, lai atvērtu izvēlni)"; +Calendar._TT["PREV_MONTH"] = "Iepriekšējais mēnesis (pieturēt, lai atvērtu izvēlni)"; +Calendar._TT["GO_TODAY"] = "Iet uz šodienu"; +Calendar._TT["NEXT_MONTH"] = "Nākošais mēnesis (pieturēt, lai atvērtu izvēlni)"; +Calendar._TT["NEXT_YEAR"] = "Nākošais gads (pieturēt, lai atvērtu izvēlni)"; +Calendar._TT["SEL_DATE"] = "Izvēlieties datumu"; +Calendar._TT["DRAG_TO_MOVE"] = "Vilkt, lai pārvietotu"; +Calendar._TT["PART_TODAY"] = "(šodiena)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Rādīt %s pirmo"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Aizvērt"; +Calendar._TT["TODAY"] = "Šodiena"; +Calendar._TT["TIME_PART"] = "(Shift-)Click vai ievilkt, lai mainītu vērtību"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = " %b, %a %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Laiks:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/699a58897b9f326128b2eda7e3ea2de970223d84.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/699a58897b9f326128b2eda7e3ea2de970223d84.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +
    +<%= link_to(l(:button_edit), edit_version_path(@version), :class => 'icon icon-edit') if User.current.allowed_to?(:manage_versions, @version.project) %> +<%= link_to_if_authorized(l(:button_edit_associated_wikipage, :page_title => @version.wiki_page_title), {:controller => 'wiki', :action => 'edit', :project_id => @version.project, :id => Wiki.titleize(@version.wiki_page_title)}, :class => 'icon icon-edit') unless @version.wiki_page_title.blank? || @version.project.wiki.nil? %> +<%= link_to(l(:button_delete), version_path(@version, :back_url => url_for(:controller => 'versions', :action => 'index', :project_id => @version.project)), + :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current.allowed_to?(:manage_versions, @version.project) %> +<%= call_hook(:view_versions_show_contextual, { :version => @version, :project => @project }) %> +
    + +

    <%= h(@version.name) %>

    + +
    +<%= render :partial => 'versions/overview', :locals => {:version => @version} %> +<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> + +
    +<% if @version.estimated_hours > 0 || User.current.allowed_to?(:view_time_entries, @project) %> +
    <%= l(:label_time_tracking) %> + + + + + +<% if User.current.allowed_to?(:view_time_entries, @project) %> + + + + +<% end %> +
    <%= l(:field_estimated_hours) %><%= html_hours(l_hours(@version.estimated_hours)) %>
    <%= l(:label_spent_time) %><%= html_hours(l_hours(@version.spent_hours)) %>
    +
    +<% end %> + +
    +<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %> +
    +
    + +<% if @issues.present? %> +<% form_tag({}) do -%> + + + <%- @issues.each do |issue| -%> + + + + + <% end %> + +<% end %> +<%= context_menu issues_context_menu_path %> +<% end %> +
    + +<%= call_hook :view_versions_show_bottom, :version => @version %> + +<% html_title @version.name %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/69aea32e67c1e43bf9542a209fc02cf6c1b5854c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/69aea32e67c1e43bf9542a209fc02cf6c1b5854c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,193 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'repositories_controller' + +# Re-raise errors caught by the controller. +class RepositoriesController; def rescue_action(e) raise e end; end + +class RepositoriesBazaarControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules + + REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository/trunk').to_s + PRJ_ID = 3 + + def setup + @controller = RepositoriesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @project = Project.find(PRJ_ID) + @repository = Repository::Bazaar.create( + :project => @project, + :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8') + assert @repository + end + + if File.directory?(REPOSITORY_PATH) + def test_browse_root + get :show, :id => PRJ_ID + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal 2, assigns(:entries).size + assert assigns(:entries).detect {|e| e.name == 'directory' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'doc-mkdir.txt' && e.kind == 'file'} + end + + def test_browse_directory + get :show, :id => PRJ_ID, :path => ['directory'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['doc-ls.txt', 'document.txt', 'edit.png'], assigns(:entries).collect(&:name) + entry = assigns(:entries).detect {|e| e.name == 'edit.png'} + assert_not_nil entry + assert_equal 'file', entry.kind + assert_equal 'directory/edit.png', entry.path + end + + def test_browse_at_given_revision + get :show, :id => PRJ_ID, :path => [], :rev => 3 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['directory', 'doc-deleted.txt', 'doc-ls.txt', 'doc-mkdir.txt'], + assigns(:entries).collect(&:name) + end + + def test_changes + get :changes, :id => PRJ_ID, :path => ['doc-mkdir.txt'] + assert_response :success + assert_template 'changes' + assert_tag :tag => 'h2', :content => 'doc-mkdir.txt' + end + + def test_entry_show + get :entry, :id => PRJ_ID, :path => ['directory', 'doc-ls.txt'] + assert_response :success + assert_template 'entry' + # Line 19 + assert_tag :tag => 'th', + :content => /29/, + :attributes => { :class => /line-num/ }, + :sibling => { :tag => 'td', :content => /Show help message/ } + end + + def test_entry_download + get :entry, :id => PRJ_ID, :path => ['directory', 'doc-ls.txt'], :format => 'raw' + assert_response :success + # File content + assert @response.body.include?('Show help message') + end + + def test_directory_entry + get :entry, :id => PRJ_ID, :path => ['directory'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entry) + assert_equal 'directory', assigns(:entry).name + end + + def test_diff + # Full diff of changeset 3 + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 3, :type => dt + assert_response :success + assert_template 'diff' + # Line 11 removed + assert_tag :tag => 'th', + :content => '11', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /Display more information/ } + end + end + + def test_annotate + get :annotate, :id => PRJ_ID, :path => ['doc-mkdir.txt'] + assert_response :success + assert_template 'annotate' + assert_tag :tag => 'th', :content => '2', + :sibling => { + :tag => 'td', + :child => { + :tag => 'a', + :content => '3' + } + } + assert_tag :tag => 'th', :content => '2', + :sibling => { :tag => 'td', :content => /jsmith/ } + assert_tag :tag => 'th', :content => '2', + :sibling => { + :tag => 'td', + :child => { + :tag => 'a', + :content => '3' + } + } + assert_tag :tag => 'th', :content => '2', + :sibling => { :tag => 'td', :content => /Main purpose/ } + end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert @repository.changesets.count > 0 + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert @repository.changesets.count > 0 + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Bazaar.create( + :project => @project, + :url => "/invalid", + :log_encoding => 'UTF-8') + assert @repository + @repository.fetch_changesets + @repository.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + else + puts "Bazaar test repository NOT FOUND. Skipping functional tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/69d93dae7af0a934d2b88863b74d127eebc3a82f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/69d93dae7af0a934d2b88863b74d127eebc3a82f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +Description: + The plugin generator creates stubs for a new Redmine plugin. + +Example: + ./script/generate redmine_plugin meetings + create vendor/plugins/redmine_meetings/app/controllers + create vendor/plugins/redmine_meetings/app/helpers + create vendor/plugins/redmine_meetings/app/models + create vendor/plugins/redmine_meetings/app/views + create vendor/plugins/redmine_meetings/db/migrate + create vendor/plugins/redmine_meetings/lib/tasks + create vendor/plugins/redmine_meetings/assets/images + create vendor/plugins/redmine_meetings/assets/javascripts + create vendor/plugins/redmine_meetings/assets/stylesheets + create vendor/plugins/redmine_meetings/lang + create vendor/plugins/redmine_meetings/README + create vendor/plugins/redmine_meetings/init.rb + create vendor/plugins/redmine_meetings/lang/en.yml + create vendor/plugins/redmine_meetings/config/locales/en.yml + create vendor/plugins/redmine_meetings/test/test_helper.rb diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/69/69f952b81bb3ec0bda0f3e3b36510faab9da8bc9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/69/69f952b81bb3ec0bda0f3e3b36510faab9da8bc9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,100 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class MembersController < ApplicationController + model_object Member + before_filter :find_model_object, :except => [:new, :autocomplete_for_member] + before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member] + before_filter :find_project, :only => [:new, :autocomplete_for_member] + before_filter :authorize + + def new + members = [] + if params[:member] && request.post? + attrs = params[:member].dup + if (user_ids = attrs.delete(:user_ids)) + user_ids.each do |user_id| + members << Member.new(attrs.merge(:user_id => user_id)) + end + else + members << Member.new(attrs) + end + @project.members << members + end + respond_to do |format| + if members.present? && members.all? {|m| m.valid? } + + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } + + format.js { + render(:update) {|page| + page.replace_html "tab-content-members", :partial => 'projects/settings/members' + page << 'hideOnLoad()' + members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") } + } + } + else + + format.js { + render(:update) {|page| + errors = members.collect {|m| + m.errors.full_messages + }.flatten.uniq + + page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', '))) + } + } + + end + end + end + + def edit + if request.post? and @member.update_attributes(params[:member]) + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } + format.js { + render(:update) {|page| + page.replace_html "tab-content-members", :partial => 'projects/settings/members' + page << 'hideOnLoad()' + page.visual_effect(:highlight, "member-#{@member.id}") + } + } + end + end + end + + def destroy + if request.post? && @member.deletable? + @member.destroy + end + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } + format.js { render(:update) {|page| + page.replace_html "tab-content-members", :partial => 'projects/settings/members' + page << 'hideOnLoad()' + } + } + end + end + + def autocomplete_for_member + @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals + render :layout => false + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a042b60ae039f1f3e97486dd768e4cda28fdc3f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a042b60ae039f1f3e97486dd768e4cda28fdc3f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +== Creating the test database + +The default name for the test databases is "activerecord_versioned". If you +want to use another database name then be sure to update the connection +adapter setups you want to test with in test/connections//connection.rb. +When you have the database online, you can import the fixture tables with +the test/fixtures/db_definitions/*.sql files. + +Make sure that you create database objects with the same user that you specified in i +connection.rb otherwise (on Postgres, at least) tests for default values will fail. + +== Running with Rake + +The easiest way to run the unit tests is through Rake. The default task runs +the entire test suite for all the adapters. You can also run the suite on just +one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite, +or test_postresql. For more information, checkout the full array of rake tasks with "rake -T" + +Rake can be found at http://rake.rubyforge.org + +== Running by hand + +Unit tests are located in test directory. If you only want to run a single test suite, +or don't want to bother with Rake, you can do so with something like: + + cd test; ruby -I "connections/native_mysql" base_test.rb + +That'll run the base suite using the MySQL-Ruby adapter. Change the adapter +and test suite name as needed. + +== Faster tests + +If you are using a database that supports transactions, you can set the +"AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures. +This gives a very large speed boost. With rake: + + rake AR_TX_FIXTURES=yes + +Or, by hand: + + AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a0944d7e583de44e8a1af8231e3395612ce51a0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a0944d7e583de44e8a1af8231e3395612ce51a0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +<% form_tag({}, :id => 'workflow_copy_form') do %> +
    +<%= l(:label_copy_source) %> +

    + + <%= select_tag('source_tracker_id', + "" + + "" + + options_from_collection_for_select(@trackers, 'id', 'name', @source_tracker && @source_tracker.id)) %> +

    +

    + + <%= select_tag('source_role_id', + "" + + "" + + options_from_collection_for_select(@roles, 'id', 'name', @source_role && @source_role.id)) %> +

    +
    + +
    +<%= l(:label_copy_target) %> +

    + + <%= select_tag 'target_tracker_ids', + "" + + options_from_collection_for_select(@trackers, 'id', 'name', @target_trackers && @target_trackers.map(&:id)), :multiple => true %> +

    +

    + + <%= select_tag 'target_role_ids', + "" + + options_from_collection_for_select(@roles, 'id', 'name', @target_roles && @target_roles.map(&:id)), :multiple => true %> +

    +
    +<%= submit_tag l(:button_copy) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a0a12aaeac0ff15bef28f0de0c8fb02733425c0.svn-base Binary file .svn/pristine/6a/6a0a12aaeac0ff15bef28f0de0c8fb02733425c0.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a446c0fabce93b01244d29a3a538026070a8b28.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a446c0fabce93b01244d29a3a538026070a8b28.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,125 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssueCategoriesController < ApplicationController + menu_item :settings + model_object IssueCategory + before_filter :find_model_object, :except => [:index, :new, :create] + before_filter :find_project_from_association, :except => [:index, :new, :create] + before_filter :find_project, :only => [:index, :new, :create] + before_filter :authorize + accept_api_auth :index, :show, :create, :update, :destroy + + def index + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project } + format.api { @categories = @project.issue_categories.all } + end + end + + def show + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project } + format.api + end + end + + def new + @category = @project.issue_categories.build(params[:issue_category]) + end + + verify :method => :post, :only => :create + def create + @category = @project.issue_categories.build(params[:issue_category]) + if @category.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project + end + format.js do + # IE doesn't support the replace_html rjs method for select box options + render(:update) {|page| page.replace "issue_category_id", + content_tag('select', '' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') + } + end + format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) } + end + else + respond_to do |format| + format.html { render :action => 'new'} + format.js do + render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) } + end + format.api { render_validation_errors(@category) } + end + end + end + + def edit + end + + verify :method => :put, :only => :update + def update + if @category.update_attributes(params[:issue_category]) + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project + } + format.api { head :ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@category) } + end + end + end + + verify :method => :delete, :only => :destroy + def destroy + @issue_count = @category.issues.size + if @issue_count == 0 || params[:todo] || api_request? + reassign_to = nil + if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?) + reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) + end + @category.destroy(reassign_to) + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' } + format.api { head :ok } + end + return + end + @categories = @project.issue_categories - [@category] + end + +private + # Wrap ApplicationController's find_model_object method to set + # @category instead of just @issue_category + def find_model_object + super + @category = @object + end + + def find_project + @project = Project.find(params[:project_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a4fdd885d26844cca5f9f69058f8424de0ff4e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a4fdd885d26844cca5f9f69058f8424de0ff4e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Activity + # Class used to retrieve activity events + class Fetcher + attr_reader :user, :project, :scope + + # Needs to be unloaded in development mode + @@constantized_providers = Hash.new {|h,k| h[k] = Redmine::Activity.providers[k].collect {|t| t.constantize } } + + def initialize(user, options={}) + options.assert_valid_keys(:project, :with_subprojects, :author) + @user = user + @project = options[:project] + @options = options + + @scope = event_types + end + + # Returns an array of available event types + def event_types + return @event_types unless @event_types.nil? + + @event_types = Redmine::Activity.available_event_types + @event_types = @event_types.select {|o| @project.self_and_descendants.detect {|p| @user.allowed_to?("view_#{o}".to_sym, p)}} if @project + @event_types + end + + # Yields to filter the activity scope + def scope_select(&block) + @scope = @scope.select {|t| yield t } + end + + # Sets the scope + # Argument can be :all, :default or an array of event types + def scope=(s) + case s + when :all + @scope = event_types + when :default + default_scope! + else + @scope = s & event_types + end + end + + # Resets the scope to the default scope + def default_scope! + @scope = Redmine::Activity.default_event_types + end + + # Returns an array of events for the given date range + # sorted in reverse chronological order + def events(from = nil, to = nil, options={}) + e = [] + @options[:limit] = options[:limit] + + @scope.each do |event_type| + constantized_providers(event_type).each do |provider| + e += provider.find_events(event_type, @user, from, to, @options) + end + end + + e.sort! {|a,b| b.event_datetime <=> a.event_datetime} + + if options[:limit] + e = e.slice(0, options[:limit]) + end + e + end + + private + + def constantized_providers(event_type) + @@constantized_providers[event_type] + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a60898740de505326813cfa3f1724d25fce3f5e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a60898740de505326813cfa3f1724d25fce3f5e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> + » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %> + » <%=h @custom_field.name %>

    + +<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "edit", :id => @custom_field } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a90c258580c8739754206289754513f15068486.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a90c258580c8739754206289754513f15068486.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,207 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'my_controller' + +# Re-raise errors caught by the controller. +class MyController; def rescue_action(e) raise e end; end + +class MyControllerTest < ActionController::TestCase + fixtures :users, :user_preferences, :roles, :projects, :issues, :issue_statuses, :trackers, :enumerations, :custom_fields + + def setup + @controller = MyController.new + @request = ActionController::TestRequest.new + @request.session[:user_id] = 2 + @response = ActionController::TestResponse.new + end + + def test_index + get :index + assert_response :success + assert_template 'page' + end + + def test_page + get :page + assert_response :success + assert_template 'page' + end + + def test_my_account_should_show_editable_custom_fields + get :account + assert_response :success + assert_template 'account' + assert_equal User.find(2), assigns(:user) + + assert_tag :input, :attributes => { :name => 'user[custom_field_values][4]'} + end + + def test_my_account_should_not_show_non_editable_custom_fields + UserCustomField.find(4).update_attribute :editable, false + + get :account + assert_response :success + assert_template 'account' + assert_equal User.find(2), assigns(:user) + + assert_no_tag :input, :attributes => { :name => 'user[custom_field_values][4]'} + end + + def test_update_account + post :account, + :user => { + :firstname => "Joe", + :login => "root", + :admin => 1, + :group_ids => ['10'], + :custom_field_values => {"4" => "0100562500"} + } + + assert_redirected_to '/my/account' + user = User.find(2) + assert_equal user, assigns(:user) + assert_equal "Joe", user.firstname + assert_equal "jsmith", user.login + assert_equal "0100562500", user.custom_value_for(4).value + # ignored + assert !user.admin? + assert user.groups.empty? + end + + def test_change_password + get :password + assert_response :success + assert_template 'password' + + # non matching password confirmation + post :password, :password => 'jsmith', + :new_password => 'hello', + :new_password_confirmation => 'hello2' + assert_response :success + assert_template 'password' + assert_tag :tag => "div", :attributes => { :class => "errorExplanation" } + + # wrong password + post :password, :password => 'wrongpassword', + :new_password => 'hello', + :new_password_confirmation => 'hello' + assert_response :success + assert_template 'password' + assert_equal 'Wrong password', flash[:error] + + # good password + post :password, :password => 'jsmith', + :new_password => 'hello', + :new_password_confirmation => 'hello' + assert_redirected_to '/my/account' + assert User.try_to_login('jsmith', 'hello') + end + + def test_page_layout + get :page_layout + assert_response :success + assert_template 'page_layout' + end + + def test_add_block + xhr :post, :add_block, :block => 'issuesreportedbyme' + assert_response :success + assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme') + end + + def test_remove_block + xhr :post, :remove_block, :block => 'issuesassignedtome' + assert_response :success + assert !User.find(2).pref[:my_page_layout].values.flatten.include?('issuesassignedtome') + end + + def test_order_blocks + xhr :post, :order_blocks, :group => 'left', 'list-left' => ['documents', 'calendar', 'latestnews'] + assert_response :success + assert_equal ['documents', 'calendar', 'latestnews'], User.find(2).pref[:my_page_layout]['left'] + end + + context "POST to reset_rss_key" do + context "with an existing rss_token" do + setup do + @previous_token_value = User.find(2).rss_key # Will generate one if it's missing + post :reset_rss_key + end + + should "destroy the existing token" do + assert_not_equal @previous_token_value, User.find(2).rss_key + end + + should "create a new token" do + assert User.find(2).rss_token + end + + should_set_the_flash_to /reset/ + should_redirect_to('my account') {'/my/account' } + end + + context "with no rss_token" do + setup do + assert_nil User.find(2).rss_token + post :reset_rss_key + end + + should "create a new token" do + assert User.find(2).rss_token + end + + should_set_the_flash_to /reset/ + should_redirect_to('my account') {'/my/account' } + end + end + + context "POST to reset_api_key" do + context "with an existing api_token" do + setup do + @previous_token_value = User.find(2).api_key # Will generate one if it's missing + post :reset_api_key + end + + should "destroy the existing token" do + assert_not_equal @previous_token_value, User.find(2).api_key + end + + should "create a new token" do + assert User.find(2).api_token + end + + should_set_the_flash_to /reset/ + should_redirect_to('my account') {'/my/account' } + end + + context "with no api_token" do + setup do + assert_nil User.find(2).api_token + post :reset_api_key + end + + should "create a new token" do + assert User.find(2).api_token + end + + should_set_the_flash_to /reset/ + should_redirect_to('my account') {'/my/account' } + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6a9c386ccf2c264a40620729b91d0fe746a9b0e1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6a9c386ccf2c264a40620729b91d0fe746a9b0e1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +default: + +production: + +development: + +test: + somesetting: foo diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6ae02e008b39a032972c4d067b7e08a8c9bd1a60.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6ae02e008b39a032972c4d067b7e08a8c9bd1a60.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class PluginsTest < Test::Unit::TestCase + + def test_should_allow_access_to_plugins_by_strings_or_symbols + p = Engines.plugins["alpha_plugin"] + q = Engines.plugins[:alpha_plugin] + assert_kind_of Engines::Plugin, p + assert_equal p, q + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6a/6af6e8ac0e3a74e02bdf5cc6d1f6d7050cfd38b0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6a/6af6e8ac0e3a74e02bdf5cc6d1f6d7050cfd38b0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + + +namespace :db do + desc 'Encrypts SCM and LDAP passwords in the database.' + task :encrypt => :environment do + unless (Repository.encrypt_all(:password) && + AuthSource.encrypt_all(:account_password)) + raise "Some objects could not be saved after encryption, update was rollback'ed." + end + end + + desc 'Decrypts SCM and LDAP passwords in the database.' + task :decrypt => :environment do + unless (Repository.decrypt_all(:password) && + AuthSource.decrypt_all(:account_password)) + raise "Some objects could not be saved after decryption, update was rollback'ed." + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6b/6b06747ad022f4eb0ac6c92934c96fc7168f6460.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6b/6b06747ad022f4eb0ac6c92934c96fc7168f6460.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'หนา'; +jsToolBar.strings['Italic'] = 'เอียง'; +jsToolBar.strings['Underline'] = 'ขีดเส้นใต้'; +jsToolBar.strings['Deleted'] = 'ขีดฆ่า'; +jsToolBar.strings['Code'] = 'โค๊ดโปรแกรม'; +jsToolBar.strings['Heading 1'] = 'หัวข้อ 1'; +jsToolBar.strings['Heading 2'] = 'หัวข้อ 2'; +jsToolBar.strings['Heading 3'] = 'หัวข้อ 3'; +jsToolBar.strings['Unordered list'] = 'รายการ'; +jsToolBar.strings['Ordered list'] = 'ลำดับเลข'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'รูปแบบข้อความคงที่'; +jsToolBar.strings['Wiki link'] = 'เชื่อมโยงไปหน้า Wiki อื่น'; +jsToolBar.strings['Image'] = 'รูปภาพ'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6b/6b54a0eb8e943798ef2435d13b405e9ba04b4b70.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6b/6b54a0eb8e943798ef2435d13b405e9ba04b4b70.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,49 @@ +# Redmine - project management software +# Copyright (C) 2006-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.expand_path('../../test_helper', __FILE__) + +class TrackerTest < ActiveSupport::TestCase + fixtures :trackers, :workflows, :issue_statuses, :roles + + def test_copy_workflows + source = Tracker.find(1) + assert_equal 89, source.workflows.size + + target = Tracker.new(:name => 'Target') + assert target.save + target.workflows.copy(source) + target.reload + assert_equal 89, target.workflows.size + end + + def test_issue_statuses + tracker = Tracker.find(1) + Workflow.delete_all + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3) + Workflow.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5) + + assert_kind_of Array, tracker.issue_statuses + assert_kind_of IssueStatus, tracker.issue_statuses.first + assert_equal [2, 3, 5], Tracker.find(1).issue_statuses.collect(&:id) + end + + def test_issue_statuses_empty + Workflow.delete_all("tracker_id = 1") + assert_equal [], Tracker.find(1).issue_statuses + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6b/6b5b987c21a18cc797539b6f0cafd0fae162a091.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6b/6b5b987c21a18cc797539b6f0cafd0fae162a091.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +

    <%= l(:mail_body_lost_password) %>
    +<%= auto_link(@url) %>

    + +

    <%= l(:field_login) %>: <%=h @token.user.login %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6b/6b825f96e86174ddd396f80166966bf671099ba1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6b/6b825f96e86174ddd396f80166966bf671099ba1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar HU language +// Author: Takács Gábor +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Vasárnap", + "Hétfő", + "Kedd", + "Szerda", + "Csütörtök", + "Péntek", + "Szombat", + "Vasárnap"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Vas", + "Hét", + "Ked", + "Sze", + "Csü", + "Pén", + "Szo", + "Vas"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Január", + "Február", + "Március", + "Április", + "Május", + "Június", + "Július", + "Augusztus", + "Szeptember", + "Október", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Már", + "Ápr", + "Máj", + "Jún", + "Júl", + "Aug", + "Szep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "A naptár leírása"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Előző év (nyomvatart = menü)"; +Calendar._TT["PREV_MONTH"] = "Előző hónap (nyomvatart = menü)"; +Calendar._TT["GO_TODAY"] = "Irány a Ma"; +Calendar._TT["NEXT_MONTH"] = "Következő hónap (nyomvatart = menü)"; +Calendar._TT["NEXT_YEAR"] = "Következő év (nyomvatart = menü)"; +Calendar._TT["SEL_DATE"] = "Válasszon dátumot"; +Calendar._TT["DRAG_TO_MOVE"] = "Fogd és vidd"; +Calendar._TT["PART_TODAY"] = " (ma)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s megjelenítése elsőként"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Bezár"; +Calendar._TT["TODAY"] = "Ma"; +Calendar._TT["TIME_PART"] = "(Shift-)Click vagy húzd az érték változtatásához"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y.%m.%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%B %e, %A"; + +Calendar._TT["WK"] = "hét"; +Calendar._TT["TIME"] = "Idő:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6b/6b9da48548a1beb99525f99aa84dd3c7f5182449.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6b/6b9da48548a1beb99525f99aa84dd3c7f5182449.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +

    <%=l(:label_spent_time)%> (<%= l(:label_last_n_days, 7) %>)

    +<% +entries = TimeEntry.find(:all, + :conditions => ["#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", @user.id, Date.today - 6, Date.today], + :include => [:activity, :project, {:issue => [:tracker, :status]}], + :order => "#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC") +entries_by_day = entries.group_by(&:spent_on) +%> + +
    +

    <%= l(:label_total) %>: <%= html_hours("%.2f" % entries.sum(&:hours).to_f) %>

    +
    + +<% if entries.any? %> + + + + + + + + + +<% entries_by_day.keys.sort.reverse.each do |day| %> + + + + + + + <% entries_by_day[day].each do |entry| -%> + + + + + + + + <% end -%> +<% end -%> + +
    <%= l(:label_activity) %><%= l(:label_project) %><%= l(:field_comments) %><%= l(:field_hours) %>
    <%= day == Date.today ? l(:label_today).titleize : format_date(day) %><%= html_hours("%.2f" % entries_by_day[day].sum(&:hours).to_f) %>
    <%=h entry.activity %><%=h entry.project %> <%= ' - ' + link_to_issue(entry.issue, :truncate => 50) if entry.issue %><%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> + <% if entry.editable_by?(@user) -%> + <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry}, + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry}, + :confirm => l(:text_are_you_sure), + :method => :delete, + :title => l(:button_delete) %> + <% end -%> +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6b/6bbafbe405df07af73d1843fdf80d06a981e814b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6b/6bbafbe405df07af73d1843fdf80d06a981e814b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +class AddCustomFieldsVisible < ActiveRecord::Migration + def self.up + add_column :custom_fields, :visible, :boolean, :null => false, :default => true + CustomField.update_all("visible = #{CustomField.connection.quoted_true}") + end + + def self.down + remove_column :custom_fields, :visible + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c0616986104fa86ed47ef83a0066e97c4dd3dae.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6c0616986104fa86ed47ef83a0066e97c4dd3dae.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<% labelled_form_for @group do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c0e19438f110843f0c7e7fd334474d7ed2fdc3d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6c0e19438f110843f0c7e7fd334474d7ed2fdc3d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +--- +trackers_001: + name: Bug + id: 1 + is_in_chlog: true + position: 1 +trackers_002: + name: Feature request + id: 2 + is_in_chlog: true + position: 2 +trackers_003: + name: Support request + id: 3 + is_in_chlog: false + position: 3 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c1bc2cf6fdcda95eb68095dcabf8689b24d2903.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6c1bc2cf6fdcda95eb68095dcabf8689b24d2903.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) +require 'iconv' + +class PdfTest < ActiveSupport::TestCase + fixtures :users, :projects, :roles, :members, :member_roles, + :enabled_modules, :issues, :trackers, :attachments + + def test_fix_text_encoding_nil + assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(nil, "UTF-8") + assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(nil, "ISO-8859-1") + end + + def test_rdm_pdf_iconv_cannot_convert_ja_cp932 + encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" ) + utf8_txt_1 = "\xe7\x8b\x80\xe6\x85\x8b" + utf8_txt_2 = "\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80" + utf8_txt_3 = "\xe7\x8b\x80\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80" + if utf8_txt_1.respond_to?(:force_encoding) + txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding) + txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding) + txt_3 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding) + assert_equal "?\x91\xd4", txt_1 + assert_equal "?\x91\xd4?", txt_2 + assert_equal "??\x91\xd4?", txt_3 + assert_equal "ASCII-8BIT", txt_1.encoding.to_s + assert_equal "ASCII-8BIT", txt_2.encoding.to_s + assert_equal "ASCII-8BIT", txt_3.encoding.to_s + elsif RUBY_PLATFORM == 'java' + assert_equal "??", + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding) + assert_equal "???", + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding) + assert_equal "????", + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding) + else + assert_equal "???\x91\xd4", + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding) + assert_equal "???\x91\xd4???", + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding) + assert_equal "??????\x91\xd4???", + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding) + end + end + + def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_en + str1 = "Texte encod\xe9 en ISO-8859-1" + str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test" + str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding) + str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding) + txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, 'UTF-8') + txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, 'UTF-8') + if txt_1.respond_to?(:force_encoding) + assert_equal "ASCII-8BIT", txt_1.encoding.to_s + assert_equal "ASCII-8BIT", txt_2.encoding.to_s + end + assert_equal "Texte encod? en ISO-8859-1", txt_1 + assert_equal "?a?b?c?d?e test", txt_2 + end + + def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_ja + str1 = "Texte encod\xe9 en ISO-8859-1" + str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test" + str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding) + str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding) + encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" ) + txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, encoding) + txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, encoding) + if txt_1.respond_to?(:force_encoding) + assert_equal "ASCII-8BIT", txt_1.encoding.to_s + assert_equal "ASCII-8BIT", txt_2.encoding.to_s + end + assert_equal "Texte encod? en ISO-8859-1", txt_1 + assert_equal "?a?b?c?d?e test", txt_2 + end + + def test_attach + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + + str2 = "\x83e\x83X\x83g" + str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding) + encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" ) + + a1 = Attachment.find(17) + a2 = Attachment.find(19) + + User.current = User.find(1) + assert a1.readable? + assert a1.visible? + assert a2.readable? + assert a2.visible? + + aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8") + assert_equal 17, aa1.id + aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding) + assert_equal 19, aa2.id + + User.current = nil + assert a1.readable? + assert (! a1.visible?) + assert a2.readable? + assert (! a2.visible?) + + aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8") + assert_equal nil, aa1 + aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding) + assert_equal nil, aa2 + + set_tmp_attachments_directory + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c1e26b54fdd47501d3a107c6cb94b31dc942cde.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6c1e26b54fdd47501d3a107c6cb94b31dc942cde.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 RolesHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c4dd8ce0226a8bc5d18fafda9466bf4106576da.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6c4dd8ce0226a8bc5d18fafda9466bf4106576da.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1062 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 'forwardable' +require 'cgi' + +module ApplicationHelper + include Redmine::WikiFormatting::Macros::Definitions + include Redmine::I18n + include GravatarHelper::PublicMethods + + extend Forwardable + def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter + + # Return true if user is authorized for controller/action, otherwise false + def authorize_for(controller, action) + User.current.allowed_to?({:controller => controller, :action => action}, @project) + end + + # Display a link if user is authorized + # + # @param [String] name Anchor text (passed to link_to) + # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized + # @param [optional, Hash] html_options Options passed to link_to + # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to + def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) + link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action]) + end + + # Display a link to remote if user is authorized + def link_to_remote_if_authorized(name, options = {}, html_options = nil) + url = options[:url] || {} + link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action]) + end + + # Displays a link to user's account page if active + def link_to_user(user, options={}) + if user.is_a?(User) + name = h(user.name(options[:format])) + if user.active? + link_to name, :controller => 'users', :action => 'show', :id => user + else + name + end + else + h(user.to_s) + end + end + + # Displays a link to +issue+ with its subject. + # Examples: + # + # link_to_issue(issue) # => Defect #6: This is the subject + # link_to_issue(issue, :truncate => 6) # => Defect #6: This i... + # link_to_issue(issue, :subject => false) # => Defect #6 + # link_to_issue(issue, :project => true) # => Foo - Defect #6 + # + def link_to_issue(issue, options={}) + title = nil + subject = nil + if options[:subject] == false + title = truncate(issue.subject, :length => 60) + else + subject = issue.subject + if options[:truncate] + subject = truncate(subject, :length => options[:truncate]) + end + end + s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, + :class => issue.css_classes, + :title => title + s << ": #{h subject}" if subject + s = "#{h issue.project} - " + s if options[:project] + s + end + + # Generates a link to an attachment. + # Options: + # * :text - Link text (default to attachment filename) + # * :download - Force download (default: false) + def link_to_attachment(attachment, options={}) + text = options.delete(:text) || attachment.filename + action = options.delete(:download) ? 'download' : 'show' + link_to(h(text), + {:controller => 'attachments', :action => action, + :id => attachment, :filename => attachment.filename }, + options) + end + + # Generates a link to a SCM revision + # Options: + # * :text - Link text (default to the formatted revision) + def link_to_revision(revision, project, options={}) + text = options.delete(:text) || format_revision(revision) + rev = revision.respond_to?(:identifier) ? revision.identifier : revision + + link_to(h(text), {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev}, + :title => l(:label_revision_id, format_revision(revision))) + end + + # Generates a link to a message + def link_to_message(message, options={}, html_options = nil) + link_to( + h(truncate(message.subject, :length => 60)), + { :controller => 'messages', :action => 'show', + :board_id => message.board_id, + :id => message.root, + :r => (message.parent_id && message.id), + :anchor => (message.parent_id ? "message-#{message.id}" : nil) + }.merge(options), + html_options + ) + end + + # Generates a link to a project if active + # Examples: + # + # link_to_project(project) # => link to the specified project overview + # link_to_project(project, :action=>'settings') # => link to project settings + # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options + # link_to_project(project, {}, :class => "project") # => html options with default url (project overview) + # + def link_to_project(project, options={}, html_options = nil) + if project.active? + url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) + link_to(h(project), url, html_options) + else + h(project) + end + end + + def toggle_link(name, id, options={}) + onclick = "Element.toggle('#{id}'); " + onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ") + onclick << "return false;" + link_to(name, "#", :onclick => onclick) + end + + def image_to_function(name, function, html_options = {}) + html_options.symbolize_keys! + tag(:input, html_options.merge({ + :type => "image", :src => image_path(name), + :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" + })) + end + + def prompt_to_remote(name, text, param, url, html_options = {}) + html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;" + link_to name, {}, html_options + end + + def format_activity_title(text) + h(truncate_single_line(text, :length => 100)) + end + + def format_activity_day(date) + date == Date.today ? l(:label_today).titleize : format_date(date) + end + + def format_activity_description(text) + h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "
    ") + end + + def format_version_name(version) + if version.project == @project + h(version) + else + h("#{version.project} - #{version}") + end + end + + def due_date_distance_in_words(date) + if date + l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) + end + end + + def render_page_hierarchy(pages, node=nil, options={}) + content = '' + if pages[node] + content << "
      \n" + pages[node].each do |page| + content << "
    • " + content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}, + :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil)) + content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id] + content << "
    • \n" + end + content << "
    \n" + end + content.html_safe + end + + # Renders flash messages + def render_flash_messages + s = '' + flash.each do |k,v| + s << content_tag('div', v, :class => "flash #{k}") + end + s.html_safe + end + + # Renders tabs and their content + def render_tabs(tabs) + if tabs.any? + render :partial => 'common/tabs', :locals => {:tabs => tabs} + else + content_tag 'p', l(:label_no_data), :class => "nodata" + end + end + + # Renders the project quick-jump box + def render_project_jump_box + return unless User.current.logged? + projects = User.current.memberships.collect(&:project).compact.uniq + if projects.any? + s = '' + s.html_safe + end + end + + def project_tree_options_for_select(projects, options = {}) + s = '' + project_tree(projects) do |project, level| + name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '') + tag_options = {:value => project.id} + if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project)) + tag_options[:selected] = 'selected' + else + tag_options[:selected] = nil + end + tag_options.merge!(yield(project)) if block_given? + s << content_tag('option', name_prefix + h(project), tag_options) + end + s.html_safe + end + + # Yields the given block for each project with its level in the tree + # + # Wrapper for Project#project_tree + def project_tree(projects, &block) + Project.project_tree(projects, &block) + end + + def project_nested_ul(projects, &block) + s = '' + if projects.any? + ancestors = [] + projects.sort_by(&:lft).each do |project| + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) + s << "
      \n" + else + ancestors.pop + s << "" + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "
    \n" + end + end + s << "
  • " + s << yield(project).to_s + ancestors << project + end + s << ("
  • \n" * ancestors.size) + end + s.html_safe + end + + def principals_check_box_tags(name, principals) + s = '' + principals.sort.each do |principal| + s << "\n" + end + s.html_safe + end + + # Returns a string for users/groups option tags + def principals_options_for_select(collection, selected=nil) + s = '' + groups = '' + collection.sort.each do |element| + selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) + (element.is_a?(Group) ? groups : s) << %() + end + unless groups.empty? + s << %(#{groups}) + end + s + end + + # Truncates and returns the string as a single line + def truncate_single_line(string, *args) + truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ') + end + + # Truncates at line break after 250 characters or options[:length] + def truncate_lines(string, options={}) + length = options[:length] || 250 + if string.to_s =~ /\A(.{#{length}}.*?)$/m + "#{$1}..." + else + string + end + end + + def html_hours(text) + text.gsub(%r{(\d+)\.(\d+)}, '\1.\2').html_safe + end + + def authoring(created, author, options={}) + l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe + end + + def time_tag(time) + text = distance_of_time_in_words(Time.now, time) + if @project + link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => time.to_date}, :title => format_time(time)) + else + content_tag('acronym', text, :title => format_time(time)) + end + end + + def syntax_highlight(name, content) + Redmine::SyntaxHighlighting.highlight_by_filename(content, name) + end + + def to_path_param(path) + path.to_s.split(%r{[/\\]}).select {|p| !p.blank?} + end + + def pagination_links_full(paginator, count=nil, options={}) + page_param = options.delete(:page_param) || :page + per_page_links = options.delete(:per_page_links) + url_param = params.dup + + html = '' + if paginator.current.previous + # \xc2\xab(utf-8) = « + html << link_to_content_update( + "\xc2\xab " + l(:label_previous), + url_param.merge(page_param => paginator.current.previous)) + ' ' + end + + html << (pagination_links_each(paginator, options) do |n| + link_to_content_update(n.to_s, url_param.merge(page_param => n)) + end || '') + + if paginator.current.next + # \xc2\xbb(utf-8) = » + html << ' ' + link_to_content_update( + (l(:label_next) + " \xc2\xbb"), + url_param.merge(page_param => paginator.current.next)) + end + + unless count.nil? + html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})" + if per_page_links != false && links = per_page_links(paginator.items_per_page) + html << " | #{links}" + end + end + + html.html_safe + end + + def per_page_links(selected=nil) + links = Setting.per_page_options_array.collect do |n| + n == selected ? n : link_to_content_update(n, params.merge(:per_page => n)) + end + links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil + end + + def reorder_links(name, url, method = :post) + link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), + url.merge({"#{name}[move_to]" => 'highest'}), + :method => method, :title => l(:label_sort_highest)) + + link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), + url.merge({"#{name}[move_to]" => 'higher'}), + :method => method, :title => l(:label_sort_higher)) + + link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), + url.merge({"#{name}[move_to]" => 'lower'}), + :method => method, :title => l(:label_sort_lower)) + + link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), + url.merge({"#{name}[move_to]" => 'lowest'}), + :method => method, :title => l(:label_sort_lowest)) + end + + def breadcrumb(*args) + elements = args.flatten + elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil + end + + def other_formats_links(&block) + concat('

    '.html_safe + l(:label_export_to)) + yield Redmine::Views::OtherFormatsBuilder.new(self) + concat('

    '.html_safe) + end + + def page_header_title + if @project.nil? || @project.new_record? + h(Setting.app_title) + else + b = [] + ancestors = (@project.root? ? [] : @project.ancestors.visible.all) + if ancestors.any? + root = ancestors.shift + b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') + if ancestors.size > 2 + b << "\xe2\x80\xa6" + ancestors = ancestors[-2, 2] + end + b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } + end + b << h(@project) + b.join(" \xc2\xbb ").html_safe + end + end + + def html_title(*args) + if args.empty? + title = @html_title || [] + title << @project.name if @project + title << Setting.app_title unless Setting.app_title == title.last + title.select {|t| !t.blank? }.join(' - ') + else + @html_title ||= [] + @html_title += args + end + end + + # Returns the theme, controller name, and action as css classes for the + # HTML body. + def body_css_classes + css = [] + if theme = Redmine::Themes.theme(Setting.ui_theme) + css << 'theme-' + theme.name + end + + css << 'controller-' + params[:controller] + css << 'action-' + params[:action] + css.join(' ') + end + + def accesskey(s) + Redmine::AccessKeys.key_for s + end + + # Formats text according to system settings. + # 2 ways to call this method: + # * with a String: textilizable(text, options) + # * with an object and one of its attribute: textilizable(issue, :description, options) + def textilizable(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + case args.size + when 1 + obj = options[:object] + text = args.shift + when 2 + obj = args.shift + attr = args.shift + text = obj.send(attr).to_s + else + raise ArgumentError, 'invalid arguments to textilizable' + end + return '' if text.blank? + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) + only_path = options.delete(:only_path) == false ? false : true + + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) + + @parsed_headings = [] + @current_section = 0 if options[:edit_section_links] + text = parse_non_pre_blocks(text) do |text| + [:parse_sections, :parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros, :parse_headings].each do |method_name| + send method_name, text, project, obj, attr, only_path, options + end + end + + if @parsed_headings.any? + replace_toc(text, @parsed_headings) + end + + text + end + + def parse_non_pre_blocks(text) + s = StringScanner.new(text) + tags = [] + parsed = '' + while !s.eos? + s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) + text, full_tag, closing, tag = s[1], s[2], s[3], s[4] + if tags.empty? + yield text + end + parsed << text + if tag + if closing + if tags.last == tag.downcase + tags.pop + end + else + tags << tag.downcase + end + parsed << full_tag + end + end + # Close any non closing tags + while tag = tags.pop + parsed << "" + end + parsed.html_safe + end + + def parse_inline_attachments(text, project, obj, attr, only_path, options) + # when using an image link, try to use an attachment, if possible + if options[:attachments] || (obj && obj.respond_to?(:attachments)) + attachments = options[:attachments] || obj.attachments + text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| + filename, ext, alt, alttext = $1.downcase, $2, $3, $4 + # search for the picture in attachments + if found = Attachment.latest_attach(attachments, filename) + image_url = url_for :only_path => only_path, :controller => 'attachments', + :action => 'download', :id => found + desc = found.description.to_s.gsub('"', '') + if !desc.blank? && alttext.blank? + alt = " title=\"#{desc}\" alt=\"#{desc}\"" + end + "src=\"#{image_url}\"#{alt}".html_safe + else + m.html_safe + end + end + end + end + + # Wiki links + # + # Examples: + # [[mypage]] + # [[mypage|mytext]] + # wiki links can refer other project wikis, using project name or identifier: + # [[project:]] -> wiki starting page + # [[project:|mytext]] + # [[project:mypage]] + # [[project:mypage|mytext]] + def parse_wiki_links(text, project, obj, attr, only_path, options) + text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| + link_project = project + esc, all, page, title = $1, $2, $3, $5 + if esc.nil? + if page =~ /^([^\:]+)\:(.*)$/ + link_project = Project.find_by_identifier($1) || Project.find_by_name($1) + page = $2 + title ||= $1 if page.blank? + end + + if link_project && link_project.wiki + # extract anchor + anchor = nil + if page =~ /^(.+?)\#(.+)$/ + page, anchor = $1, $2 + end + anchor = sanitize_anchor_name(anchor) if anchor.present? + # check if page exists + wiki_page = link_project.wiki.find_page(page) + url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page + "##{anchor}" + else + case options[:wiki_links] + when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') + when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export + else + wiki_page_id = page.present? ? Wiki.titleize(page) : nil + url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor) + end + end + link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) + else + # project or wiki doesn't exist + all.html_safe + end + else + all.html_safe + end + end + end + + # Redmine links + # + # Examples: + # Issues: + # #52 -> Link to issue #52 + # Changesets: + # r52 -> Link to revision 52 + # commit:a85130f -> Link to scmid starting with a85130f + # Documents: + # document#17 -> Link to document with id 17 + # document:Greetings -> Link to the document with title "Greetings" + # document:"Some document" -> Link to the document with title "Some document" + # Versions: + # version#3 -> Link to version with id 3 + # version:1.0.0 -> Link to version named "1.0.0" + # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" + # Attachments: + # attachment:file.zip -> Link to the attachment of the current object named file.zip + # Source files: + # source:some/file -> Link to the file located at /some/file in the project's repository + # source:some/file@52 -> Link to the file's revision 52 + # source:some/file#L120 -> Link to line 120 of the file + # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 + # export:some/file -> Force the download of the file + # Forum messages: + # message#1218 -> Link to message with id 1218 + # + # Links can refer other objects from other projects, using project identifier: + # identifier:r52 + # identifier:document:"Some document" + # identifier:version:1.0.0 + # identifier:source:some/file + def parse_redmine_links(text, project, obj, attr, only_path, options) + text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m| + leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10 + link = nil + if project_identifier + project = Project.visible.find_by_identifier(project_identifier) + end + if esc.nil? + if prefix.nil? && sep == 'r' + # project.changesets.visible raises an SQL error because of a double join on repositories + if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier)) + link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100)) + end + elsif sep == '#' + oid = identifier.to_i + case prefix + when nil + if issue = Issue.visible.find_by_id(oid, :include => :status) + link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid}, + :class => issue.css_classes, + :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") + end + when 'document' + if document = Document.visible.find_by_id(oid) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if version = Version.visible.find_by_id(oid) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'message' + if message = Message.visible.find_by_id(oid, :include => :parent) + link = link_to_message(message, {:only_path => only_path}, :class => 'message') + end + when 'forum' + if board = Board.visible.find_by_id(oid) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if news = News.visible.find_by_id(oid) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'project' + if p = Project.visible.find_by_id(oid) + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + elsif sep == ':' + # removes the double quotes if any + name = identifier.gsub(%r{^"(.*)"$}, "\\1") + case prefix + when 'document' + if project && document = project.documents.visible.find_by_title(name) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if project && version = project.versions.visible.find_by_name(name) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'forum' + if project && board = project.boards.visible.find_by_name(name) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if project && news = project.news.visible.find_by_title(name) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'commit' + if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"])) + link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier}, + :class => 'changeset', + :title => truncate_single_line(h(changeset.comments), :length => 100) + end + when 'source', 'export' + if project && project.repository && User.current.allowed_to?(:browse_repository, project) + name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$} + path, rev, anchor = $1, $3, $5 + link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, + :path => to_path_param(path), + :rev => rev, + :anchor => anchor, + :format => (prefix == 'export' ? 'raw' : nil)}, + :class => (prefix == 'export' ? 'source download' : 'source') + end + when 'attachment' + attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) + if attachments && attachment = attachments.detect {|a| a.filename == name } + link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, + :class => 'attachment' + end + when 'project' + if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}]) + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + end + end + (leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe + end + end + + HEADING_RE = /(]+)?>(.+?)<\/h(1|2|3|4)>)/i unless const_defined?(:HEADING_RE) + + def parse_sections(text, project, obj, attr, only_path, options) + return unless options[:edit_section_links] + text.gsub!(HEADING_RE) do + @current_section += 1 + if @current_section > 1 + content_tag('div', + link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)), + :class => 'contextual', + :title => l(:button_edit_section)) + $1 + else + $1 + end + end + end + + # Headings and TOC + # Adds ids and links to headings unless options[:headings] is set to false + def parse_headings(text, project, obj, attr, only_path, options) + return if options[:headings] == false + + text.gsub!(HEADING_RE) do + level, attrs, content = $2.to_i, $3, $4 + item = strip_tags(content).strip + anchor = sanitize_anchor_name(item) + # used for single-file wiki export + anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) + @parsed_headings << [level, anchor, item] + "\n#{content}" + end + end + + MACROS_RE = / + (!)? # escaping + ( + \{\{ # opening tag + ([\w]+) # macro name + (\(([^\}]*)\))? # optional arguments + \}\} # closing tag + ) + /x unless const_defined?(:MACROS_RE) + + # Macros substitution + def parse_macros(text, project, obj, attr, only_path, options) + text.gsub!(MACROS_RE) do + esc, all, macro = $1, $2, $3.downcase + args = ($5 || '').split(',').each(&:strip) + if esc.nil? + begin + exec_macro(macro, obj, args) + rescue => e + "
    Error executing the #{macro} macro (#{e})
    " + end || all + else + all + end + end + end + + TOC_RE = /

    \{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) + + # Renders the TOC with given headings + def replace_toc(text, headings) + text.gsub!(TOC_RE) do + if headings.empty? + '' + else + div_class = 'toc' + div_class << ' right' if $1 == '>' + div_class << ' left' if $1 == '<' + out = "

    • " + root = headings.map(&:first).min + current = root + started = false + headings.each do |level, anchor, item| + if level > current + out << '
      • ' * (level - current) + elsif level < current + out << "
      \n" * (current - level) + "
    • " + elsif started + out << '
    • ' + end + out << "#{item}" + current = level + started = true + end + out << '
    ' * (current - root) + out << '' + end + end + end + + # Same as Rails' simple_format helper without using paragraphs + def simple_format_without_paragraph(text) + text.to_s. + gsub(/\r\n?/, "\n"). # \r\n and \r -> \n + gsub(/\n\n+/, "

    "). # 2+ newline -> 2 br + gsub(/([^\n]\n)(?=[^\n])/, '\1
    '). # 1 newline -> br + html_safe + end + + def lang_options_for_select(blank=true) + (blank ? [["(auto)", ""]] : []) + + valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last } + end + + def label_tag_for(name, option_tags = nil, options = {}) + label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") + content_tag("label", label_text) + end + + def labelled_tabular_form_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + options[:html] ||= {} + options[:html][:class] = 'tabular' unless options[:html].has_key?(:class) + options.merge!({:builder => TabularFormBuilder}) + form_for(*args, &proc) + end + + def labelled_form_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + options.merge!({:builder => TabularFormBuilder}) + form_for(*args, &proc) + end + + def back_url_hidden_field_tag + back_url = params[:back_url] || request.env['HTTP_REFERER'] + back_url = CGI.unescape(back_url.to_s) + hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank? + end + + def check_all_links(form_name) + link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + + " | ".html_safe + + link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") + end + + def progress_bar(pcts, options={}) + pcts = [pcts, pcts] unless pcts.is_a?(Array) + pcts = pcts.collect(&:round) + pcts[1] = pcts[1] - pcts[0] + pcts << (100 - pcts[1] - pcts[0]) + width = options[:width] || '100px;' + legend = options[:legend] || '' + content_tag('table', + content_tag('tr', + (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + + (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + + (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) + ), :class => 'progress', :style => "width: #{width};").html_safe + + content_tag('p', legend, :class => 'pourcent').html_safe + end + + def checked_image(checked=true) + if checked + image_tag 'toggle_check.png' + end + end + + def context_menu(url) + unless @context_menu_included + content_for :header_tags do + javascript_include_tag('context_menu') + + stylesheet_link_tag('context_menu') + end + if l(:direction) == 'rtl' + content_for :header_tags do + stylesheet_link_tag('context_menu_rtl') + end + end + @context_menu_included = true + end + javascript_tag "new ContextMenu('#{ url_for(url) }')" + end + + def context_menu_link(name, url, options={}) + options[:class] ||= '' + if options.delete(:selected) + options[:class] << ' icon-checked disabled' + options[:disabled] = true + end + if options.delete(:disabled) + options.delete(:method) + options.delete(:confirm) + options.delete(:onclick) + options[:class] << ' disabled' + url = '#' + end + link_to h(name), url, options + end + + def calendar_for(field_id) + include_calendar_headers_tags + image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) + + javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });") + end + + def include_calendar_headers_tags + unless @calendar_headers_tags_included + @calendar_headers_tags_included = true + content_for :header_tags do + start_of_week = case Setting.start_of_week.to_i + when 1 + 'Calendar._FD = 1;' # Monday + when 7 + 'Calendar._FD = 0;' # Sunday + when 6 + 'Calendar._FD = 6;' # Saturday + else + '' # use language + end + + javascript_include_tag('calendar/calendar') + + javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") + + javascript_tag(start_of_week) + + javascript_include_tag('calendar/calendar-setup') + + stylesheet_link_tag('calendar') + end + end + end + + def content_for(name, content = nil, &block) + @has_content ||= {} + @has_content[name] = true + super(name, content, &block) + end + + def has_content?(name) + (@has_content && @has_content[name]) || false + end + + def email_delivery_enabled? + !!ActionMailer::Base.perform_deliveries + end + + # Returns the avatar image tag for the given +user+ if avatars are enabled + # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe ') + def avatar(user, options = { }) + if Setting.gravatar_enabled? + options.merge!({:ssl => (defined?(request) && request.ssl?), :default => Setting.gravatar_default}) + email = nil + if user.respond_to?(:mail) + email = user.mail + elsif user.to_s =~ %r{<(.+?)>} + email = $1 + end + return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil + else + '' + end + end + + def sanitize_anchor_name(anchor) + anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + end + + # Returns the javascript tags that are included in the html layout head + def javascript_heads + tags = javascript_include_tag(:defaults) + unless User.current.pref.warn_on_leaving_unsaved == '0' + tags << "\n".html_safe + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });") + end + tags + end + + def favicon + "".html_safe + end + + def robot_exclusion_tag + ''.html_safe + end + + # Returns true if arg is expected in the API response + def include_in_api_response?(arg) + unless @included_in_api_response + param = params[:include] + @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',') + @included_in_api_response.collect!(&:strip) + end + @included_in_api_response.include?(arg.to_s) + end + + # Returns options or nil if nometa param or X-Redmine-Nometa header + # was set in the request + def api_meta(options) + if params[:nometa].present? || request.headers['X-Redmine-Nometa'] + # compatibility mode for activeresource clients that raise + # an error when unserializing an array with attributes + nil + else + options + end + end + + private + + def wiki_helper + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper + return self + end + + def link_to_content_update(text, url_params = {}, html_options = {}) + link_to(text, url_params, html_options) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c5422ed0dce695a568f6fb2acde79357b8cbed3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6c5422ed0dce695a568f6fb2acde79357b8cbed3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,110 @@ +module ActiveRecord + module Acts + module Tree + def self.included(base) + base.extend(ClassMethods) + end + + # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children + # association. This requires that you have a foreign key column, which by default is called +parent_id+. + # + # class Category < ActiveRecord::Base + # acts_as_tree :order => "name" + # end + # + # Example: + # root + # \_ child1 + # \_ subchild1 + # \_ subchild2 + # + # root = Category.create("name" => "root") + # child1 = root.children.create("name" => "child1") + # subchild1 = child1.children.create("name" => "subchild1") + # + # root.parent # => nil + # child1.parent # => root + # root.children # => [child1] + # root.children.first.children.first # => subchild1 + # + # In addition to the parent and children associations, the following instance methods are added to the class + # after calling acts_as_tree: + # * siblings - Returns all the children of the parent, excluding the current node ([subchild2] when called on subchild1) + # * self_and_siblings - Returns all the children of the parent, including the current node ([subchild1, subchild2] when called on subchild1) + # * ancestors - Returns all the ancestors of the current node ([child1, root] when called on subchild2) + # * root - Returns the root of the current node (root when called on subchild2) + module ClassMethods + # Configuration options are: + # + # * foreign_key - specifies the column name to use for tracking of the tree (default: +parent_id+) + # * order - makes it possible to sort the children according to this SQL snippet. + # * counter_cache - keeps a count in a +children_count+ column if set to +true+ (default: +false+). + def acts_as_tree(options = {}) + configuration = { :foreign_key => "parent_id", :dependent => :destroy, :order => nil, :counter_cache => nil } + configuration.update(options) if options.is_a?(Hash) + + belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache] + has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent] + + class_eval <<-EOV + include ActiveRecord::Acts::Tree::InstanceMethods + + def self.roots + find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}) + end + + def self.root + find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}) + end + EOV + end + end + + module InstanceMethods + # Returns list of ancestors, starting from parent until root. + # + # subchild1.ancestors # => [child1, root] + def ancestors + node, nodes = self, [] + nodes << node = node.parent while node.parent + nodes + end + + # Returns list of descendants. + # + # root.descendants # => [child1, subchild1, subchild2] + def descendants + children + children.collect(&:children).flatten + end + + # Returns list of descendants and a reference to the current node. + # + # root.self_and_descendants # => [root, child1, subchild1, subchild2] + def self_and_descendants + [self] + descendants + end + + # Returns the root node of the tree. + def root + node = self + node = node.parent while node.parent + node + end + + # Returns all siblings of the current node. + # + # subchild1.siblings # => [subchild2] + def siblings + self_and_siblings - [self] + end + + # Returns all siblings and a reference to the current node. + # + # subchild1.self_and_siblings # => [subchild1, subchild2] + def self_and_siblings + parent ? parent.children : self.class.roots + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6c58ec568c138a736f4dc3c040f363ed8782982e.svn-base Binary file .svn/pristine/6c/6c58ec568c138a736f4dc3c040f363ed8782982e.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6cbb31787f87074f8260891401b8d0cb7419e27e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6cbb31787f87074f8260891401b8d0cb7419e27e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class <%= class_name %>ControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6c/6cda2c2cd26c7545900827e5478deaa9348538cb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6c/6cda2c2cd26c7545900827e5478deaa9348538cb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +
    +<%= link_to(l(:button_change_password), {:action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %> +<%= call_hook(:view_my_account_contextual, :user => @user)%> +
    + +

    <%=l(:label_my_account)%>

    +<%= error_messages_for 'user' %> + +<% form_for :user, @user, :url => { :action => "account" }, + :builder => TabularFormBuilder, + :lang => current_language, + :html => { :id => 'my_account_form' } do |f| %> +
    +
    + <%=l(:label_information_plural)%> +

    <%= f.text_field :firstname, :required => true %>

    +

    <%= f.text_field :lastname, :required => true %>

    +

    <%= f.text_field :mail, :required => true %>

    +

    <%= f.select :language, lang_options_for_select %>

    + <% if Setting.openid? %> +

    <%= f.text_field :identity_url %>

    + <% end %> + + <% @user.custom_field_values.select(&:editable?).each do |value| %> +

    <%= custom_field_tag_with_label :user, value %>

    + <% end %> + <%= call_hook(:view_my_account, :user => @user, :form => f) %> +
    + +<%= submit_tag l(:button_save) %> +
    + +
    +
    + <%=l(:field_mail_notification)%> + <%= render :partial => 'users/mail_notifications' %> +
    + +
    + <%=l(:label_preferences)%> + <%= render :partial => 'users/preferences' %> +
    + +
    +<% end %> + +<% content_for :sidebar do %> +<%= render :partial => 'sidebar' %> +<% end %> + +<% html_title(l(:label_my_account)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d24a0dc5e3b6f9a7f6072591c406a9d6ee664eb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d24a0dc5e3b6f9a7f6072591c406a9d6ee664eb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +# Tests in this file ensure that: +# +# * translations in the application take precedence over those in plugins +# * translations in subsequently loaded plugins take precendence over those in previously loaded plugins + +require File.dirname(__FILE__) + '/../test_helper' + +class LocaleLoadingTest < ActionController::TestCase + def setup + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + # app takes precedence over plugins + + def test_WITH_a_translation_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app + assert_equal I18n.t('hello'), 'Hello world' + end + + # subsequently loaded plugins take precendence over previously loaded plugins + + def test_WITH_a_translation_defined_in_two_plugins_IT_should_find_the_latter_of_both + assert_equal I18n.t('plugin'), 'beta' + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d32a640a3c2069ba7ef1e74006b7b011511dc61.svn-base Binary file .svn/pristine/6d/6d32a640a3c2069ba7ef1e74006b7b011511dc61.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d3a9ec3988f863e3be7aaa093486440ac25eb2d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d3a9ec3988f863e3be7aaa093486440ac25eb2d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +module Redmine + class About + def self.print_plugin_info + plugins = Redmine::Plugin.registered_plugins + + if !plugins.empty? + column_with = plugins.map {|internal_name, plugin| plugin.name.length}.max + puts "\nAbout your Redmine plugins" + + plugins.each do |internal_name, plugin| + puts sprintf("%-#{column_with}s %s", plugin.name, plugin.version) + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d3caa4ed6a43a4bdaff9ded0c658d9c377a52de.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d3caa4ed6a43a4bdaff9ded0c658d9c377a52de.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +# English strings go here +my_label: "My label" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d3d606895d40c8ee59c23f5387ffb55aef3493a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d3d606895d40c8ee59c23f5387ffb55aef3493a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +
    +<%= link_to l(:button_edit), {:action => 'edit'}, :class => 'icon icon-edit' %> +<%= link_to l(:button_copy), {:action => 'copy'}, :class => 'icon icon-copy' %> +<%= link_to l(:field_summary), {:action => 'index'}, :class => 'icon icon-summary' %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d6109d0a05e56194e4d35c31ae6b55d51c938dc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d6109d0a05e56194e4d35c31ae6b55d51c938dc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddViewWikiEditsPermission < ActiveRecord::Migration + def self.up + Role.find(:all).each do |r| + r.add_permission!(:view_wiki_edits) if r.has_permission?(:view_wiki_pages) + end + end + + def self.down + Role.find(:all).each do |r| + r.remove_permission!(:view_wiki_edits) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d7d58f8eaab5d307f2462af49611d6e47d8e3a9.svn-base Binary file .svn/pristine/6d/6d7d58f8eaab5d307f2462af49611d6e47d8e3a9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d8b57d3f9af4fafe2fd6cde3312b234c4375e61.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d8b57d3f9af4fafe2fd6cde3312b234c4375e61.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class Message < ActiveRecord::Base + generator_for :subject, :start => 'A Message' + generator_for :content, :start => 'Some content here' + generator_for :board, :method => :generate_board + + def self.generate_board + Board.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d982d4ca633b1e9bc43d8a5712942f5d7214acb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d982d4ca633b1e9bc43d8a5712942f5d7214acb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToCustomFields < ActiveRecord::Migration + def self.up + add_index :custom_fields, [:id, :type] + end + + def self.down + remove_index :custom_fields, :column => [:id, :type] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6d9eab4fc3d69073fa19994d3c697b56874a4a4e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6d9eab4fc3d69073fa19994d3c697b56874a4a4e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +class AddTrackerPosition < ActiveRecord::Migration + def self.up + add_column :trackers, :position, :integer, :default => 1 + Tracker.find(:all).each_with_index {|tracker, i| tracker.update_attribute(:position, i+1)} + end + + def self.down + remove_column :trackers, :position + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6da4657cfa69c954a9a2eba694b2e889d7bbf4f1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6da4657cfa69c954a9a2eba694b2e889d7bbf4f1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,148 @@ +require 'rexml/document' +require 'SVG/Graph/Graph' +require 'SVG/Graph/BarBase' + +module SVG + module Graph + # === Create presentation quality SVG bar graphs easily + # + # = Synopsis + # + # require 'SVG/Graph/Bar' + # + # fields = %w(Jan Feb Mar); + # data_sales_02 = [12, 45, 21] + # + # graph = SVG::Graph::Bar.new( + # :height => 500, + # :width => 300, + # :fields => fields + # ) + # + # graph.add_data( + # :data => data_sales_02, + # :title => 'Sales 2002' + # ) + # + # print "Content-type: image/svg+xml\r\n\r\n" + # print graph.burn + # + # = Description + # + # This object aims to allow you to easily create high quality + # SVG[http://www.w3c.org/tr/svg bar graphs. You can either use the default + # style sheet or supply your own. Either way there are many options which + # can be configured to give you control over how the graph is generated - + # with or without a key, data elements at each point, title, subtitle etc. + # + # = Notes + # + # The default stylesheet handles upto 12 data sets, if you + # use more you must create your own stylesheet and add the + # additional settings for the extra data sets. You will know + # if you go over 12 data sets as they will have no style and + # be in black. + # + # = Examples + # + # * http://germane-software.com/repositories/public/SVG/test/test.rb + # + # = See also + # + # * SVG::Graph::Graph + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Line + # * SVG::Graph::Pie + # * SVG::Graph::Plot + # * SVG::Graph::TimeSeries + class Bar < BarBase + include REXML + + # See Graph::initialize and BarBase::set_defaults + def set_defaults + super + self.top_align = self.top_font = 1 + end + + protected + + def get_x_labels + @config[:fields] + end + + def get_y_labels + maxvalue = max_value + minvalue = min_value + range = maxvalue - minvalue + + top_pad = range == 0 ? 10 : range / 20.0 + scale_range = (maxvalue + top_pad) - minvalue + + scale_division = scale_divisions || (scale_range / 10.0) + + if scale_integers + scale_division = scale_division < 1 ? 1 : scale_division.round + end + + rv = [] + maxvalue = maxvalue%scale_division == 0 ? + maxvalue : maxvalue + scale_division + minvalue.step( maxvalue, scale_division ) {|v| rv << v} + return rv + end + + def x_label_offset( width ) + width / 2.0 + end + + def draw_data + minvalue = min_value + fieldwidth = field_width + + unit_size = (@graph_height.to_f - font_size*2*top_font) / + (get_y_labels.max - get_y_labels.min) + bargap = bar_gap ? (fieldwidth < 10 ? fieldwidth / 2 : 10) : 0 + + bar_width = fieldwidth - bargap + bar_width /= @data.length if stack == :side + x_mod = (@graph_width-bargap)/2 - (stack==:side ? bar_width/2 : 0) + + bottom = @graph_height + + field_count = 0 + @config[:fields].each_index { |i| + dataset_count = 0 + for dataset in @data + + # cases (assume 0 = +ve): + # value min length + # +ve +ve value - min + # +ve -ve value - 0 + # -ve -ve value.abs - 0 + + value = dataset[:data][i] + + left = (fieldwidth * field_count) + + length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size + # top is 0 if value is negative + top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size) + left += bar_width * dataset_count if stack == :side + + @graph.add_element( "rect", { + "x" => left.to_s, + "y" => top.to_s, + "width" => bar_width.to_s, + "height" => length.to_s, + "class" => "fill#{dataset_count+1}" + }) + + make_datapoint_text(left + bar_width/2.0, top - 6, value.to_s) + dataset_count += 1 + end + field_count += 1 + } + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6dad2f916633562b35a4d9142a89ec57e9e90e43.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6dad2f916633562b35a4d9142a89ec57e9e90e43.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>

    + +
      +<% @issues.each do |issue| -%> +
    • <%=h issue.project %> - <%=link_to(h("#{issue.tracker} ##{issue.id}"), :controller => 'issues', :action => 'show', :id => issue, :only_path => false)%>: <%=h issue.subject %>
    • +<% end -%> +
    + +

    <%= link_to l(:label_issue_view_all), @issues_url %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6dba3f08ae1fe5df2485633031e4b22aeed22b6d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6dba3f08ae1fe5df2485633031e4b22aeed22b6d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +class AddUsersType < ActiveRecord::Migration + def self.up + add_column :users, :type, :string + User.update_all "type = 'User'" + end + + def self.down + remove_column :users, :type + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6dbc9c710fb965b8c65653004923b7333ec3b49d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6dbc9c710fb965b8c65653004923b7333ec3b49d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +Gem::Specification.new do |s| + s.name = "awesome_nested_set" + s.version = "1.1.1" + s.summary = "An awesome replacement for acts_as_nested_set and better_nested_set." + s.description = s.summary + + s.files = %w(init.rb MIT-LICENSE Rakefile README.rdoc lib/awesome_nested_set.rb lib/awesome_nested_set/compatability.rb lib/awesome_nested_set/helper.rb lib/awesome_nested_set/named_scope.rb rails/init.rb test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml) + + s.add_dependency "activerecord", ['>= 1.1'] + + s.has_rdoc = true + s.extra_rdoc_files = [ "README.rdoc"] + s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"] + + s.test_files = %w(test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml) + s.require_path = 'lib' + s.author = "Collective Idea" + s.email = "info@collectiveidea.com" + s.homepage = "http://collectiveidea.com" +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6d/6dcc3a263131f2160989fed213e79d95e99859f8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6d/6dcc3a263131f2160989fed213e79d95e99859f8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("星期日", + "星期一", + "星期二", + "星期三", + "星期四", + "星期五", + "星期六", + "星期日"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("日", + "一", + "二", + "三", + "四", + "五", + "六", + "日"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("一月", + "二月", + "三月", + "四月", + "五月", + "六月", + "七月", + "八月", + "九月", + "十月", + "十一月", + "十二月"); + +// short month names +Calendar._SMN = new Array +("一月", + "二月", + "三月", + "四月", + "五月", + "六月", + "七月", + "八月", + "九月", + "十月", + "十一月", + "十二月"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "關於 calendar"; + +Calendar._TT["ABOUT"] = +"DHTML 日期/時間 選擇器\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"最新版本取得位址: http://www.dynarch.com/projects/calendar/\n" + +"使用 GNU LGPL 發行. 參考 http://gnu.org/licenses/lgpl.html 以取得更多關於 LGPL 之細節。" + +"\n\n" + +"日期選擇方式:\n" + +"- 使用滑鼠點擊 \xab 、 \xbb 按鈕選擇年份\n" + +"- 使用滑鼠點擊 " + String.fromCharCode(0x2039) + " 、 " + String.fromCharCode(0x203a) + " 按鈕選擇月份\n" + +"- 使用滑鼠點擊上述按鈕並按住不放,可開啟快速選單。"; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"時間選擇方式:\n" + +"- 「單擊」時分秒為遞增\n" + +"- 或 「Shift-單擊」為遞減\n" + +"- 或 「單擊且拖拉」為快速選擇"; + +Calendar._TT["PREV_YEAR"] = "前一年 (按住不放可顯示選單)"; +Calendar._TT["PREV_MONTH"] = "前一個月 (按住不放可顯示選單)"; +Calendar._TT["GO_TODAY"] = "選擇今天"; +Calendar._TT["NEXT_MONTH"] = "後一個月 (按住不放可顯示選單)"; +Calendar._TT["NEXT_YEAR"] = "下一年 (按住不放可顯式選單)"; +Calendar._TT["SEL_DATE"] = "請點選日期"; +Calendar._TT["DRAG_TO_MOVE"] = "按住不放可拖拉視窗"; +Calendar._TT["PART_TODAY"] = " (今天)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "以 %s 做為一週的首日"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "關閉視窗"; +Calendar._TT["TODAY"] = "今天"; +Calendar._TT["TIME_PART"] = "(Shift-)加「單擊」或「拖拉」可變更值"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "星期 %a, %b %e 日"; + +Calendar._TT["WK"] = "週"; +Calendar._TT["TIME"] = "時間:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6e054c706d00d186090b4624c3e7d460d0636103.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6e054c706d00d186090b4624c3e7d460d0636103.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,168 @@ +module CodeRay +module Scanners + + load :ruby + load :html + load :java_script + + class HAML < Scanner + + register_for :haml + title 'HAML Template' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + protected + + def setup + super + @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true + @embedded_ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true, :state => @ruby_scanner.interpreted_string_state + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true + end + + def scan_tokens encoder, options + + match = nil + code = '' + + until eos? + + if bol? + if match = scan(/!!!.*/) + encoder.text_token match, :doctype + next + end + + if match = scan(/(?>( *)(\/(?!\[if)|-\#|:javascript|:ruby|:\w+) *)(?=\n)/) + encoder.text_token match, :comment + + code = self[2] + if match = scan(/(?:\n+#{self[1]} .*)+/) + case code + when '/', '-#' + encoder.text_token match, :comment + when ':javascript' + # TODO: recognize #{...} snippets inside JavaScript + @java_script_scanner ||= CodeRay.scanner :java_script, :tokens => @tokens, :keep_tokens => true + @java_script_scanner.tokenize match, :tokens => encoder + when ':ruby' + @ruby_scanner.tokenize match, :tokens => encoder + when /:\w+/ + encoder.text_token match, :comment + else + raise 'else-case reached: %p' % [code] + end + end + end + + if match = scan(/ +/) + encoder.text_token match, :space + end + + if match = scan(/\/.*/) + encoder.text_token match, :comment + next + end + + if match = scan(/\\/) + encoder.text_token match, :plain + if match = scan(/.+/) + @html_scanner.tokenize match, :tokens => encoder + end + next + end + + tag = false + + if match = scan(/%[\w:]+\/?/) + encoder.text_token match, :tag + # if match = scan(/( +)(.+)/) + # encoder.text_token self[1], :space + # @embedded_ruby_scanner.tokenize self[2], :tokens => encoder + # end + tag = true + end + + while match = scan(/([.#])[-\w]*\w/) + encoder.text_token match, self[1] == '#' ? :constant : :class + tag = true + end + + if tag && match = scan(/(\()([^)]+)?(\))?/) + # TODO: recognize title=@title, class="widget_#{@widget.number}" + encoder.text_token self[1], :plain + @html_scanner.tokenize self[2], :tokens => encoder, :state => :attribute if self[2] + encoder.text_token self[3], :plain if self[3] + end + + if tag && match = scan(/\{/) + encoder.text_token match, :plain + + code = '' + level = 1 + while true + code << scan(/([^\{\},\n]|, *\n?)*/) + case match = getch + when '{' + level += 1 + code << match + when '}' + level -= 1 + if level > 0 + code << match + else + break + end + when "\n", ",", nil + break + end + end + @ruby_scanner.tokenize code, :tokens => encoder unless code.empty? + + encoder.text_token match, :plain if match + end + + if tag && match = scan(/(\[)([^\]\n]+)?(\])?/) + encoder.text_token self[1], :plain + @ruby_scanner.tokenize self[2], :tokens => encoder if self[2] + encoder.text_token self[3], :plain if self[3] + end + + if tag && match = scan(/\//) + encoder.text_token match, :tag + end + + if scan(/(>? encoder + else + @ruby_scanner.tokenize self[4], :tokens => encoder + end + end + elsif match = scan(/((?:<|> encoder if self[2] + end + + elsif match = scan(/.+/) + @html_scanner.tokenize match, :tokens => encoder + + end + + if match = scan(/\n/) + encoder.text_token match, :space + end + end + + encoder + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6e2879c545234404374d4007620d9c471722b1c4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6e2879c545234404374d4007620d9c471722b1c4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= principals_check_box_tags 'member[user_ids][]', @principals %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6e6cea014fed1f742039b10aedb19881f893006f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6e6cea014fed1f742039b10aedb19881f893006f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +// Italian translation +// by Diego Pierotto (ita.translations@tiscali.it) + +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Grassetto'; +jsToolBar.strings['Italic'] = 'Corsivo'; +jsToolBar.strings['Underline'] = 'Sottolineato'; +jsToolBar.strings['Deleted'] = 'Barrato'; +jsToolBar.strings['Code'] = 'Codice sorgente'; +jsToolBar.strings['Heading 1'] = 'Titolo 1'; +jsToolBar.strings['Heading 2'] = 'Titolo 2'; +jsToolBar.strings['Heading 3'] = 'Titolo 3'; +jsToolBar.strings['Unordered list'] = 'Elenco puntato'; +jsToolBar.strings['Ordered list'] = 'Elenco numerato'; +jsToolBar.strings['Quote'] = 'Aumenta rientro'; +jsToolBar.strings['Unquote'] = 'Riduci rientro'; +jsToolBar.strings['Preformatted text'] = 'Testo preformattato'; +jsToolBar.strings['Wiki link'] = 'Collegamento a pagina Wiki'; +jsToolBar.strings['Image'] = 'Immagine'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6eadc5531e55c7dfea168413bcc84110076f8d5b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6eadc5531e55c7dfea168413bcc84110076f8d5b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,96 @@ +module CodeRay +module Encoders + + # Makes a statistic for the given tokens. + # + # Alias: +stats+ + class Statistic < Encoder + + register_for :statistic + + attr_reader :type_stats, :real_token_count # :nodoc: + + TypeStats = Struct.new :count, :size # :nodoc: + + protected + + def setup options + super + + @type_stats = Hash.new { |h, k| h[k] = TypeStats.new 0, 0 } + @real_token_count = 0 + end + + STATS = <<-STATS # :nodoc: + +Code Statistics + +Tokens %8d + Non-Whitespace %8d +Bytes Total %8d + +Token Types (%d): + type count ratio size (average) +------------------------------------------------------------- +%s + STATS + + TOKEN_TYPES_ROW = <<-TKR # :nodoc: + %-20s %8d %6.2f %% %5.1f + TKR + + def finish options + all = @type_stats['TOTAL'] + all_count, all_size = all.count, all.size + @type_stats.each do |type, stat| + stat.size /= stat.count.to_f + end + types_stats = @type_stats.sort_by { |k, v| [-v.count, k.to_s] }.map do |k, v| + TOKEN_TYPES_ROW % [k, v.count, 100.0 * v.count / all_count, v.size] + end.join + @out << STATS % [ + all_count, @real_token_count, all_size, + @type_stats.delete_if { |k, v| k.is_a? String }.size, + types_stats + ] + + super + end + + public + + def text_token text, kind + @real_token_count += 1 unless kind == :space + @type_stats[kind].count += 1 + @type_stats[kind].size += text.size + @type_stats['TOTAL'].size += text.size + @type_stats['TOTAL'].count += 1 + end + + # TODO Hierarchy handling + def begin_group kind + block_token ':begin_group', kind + end + + def end_group kind + block_token ':end_group', kind + end + + def begin_line kind + block_token ':begin_line', kind + end + + def end_line kind + block_token ':end_line', kind + end + + def block_token action, kind + @type_stats['TOTAL'].count += 1 + @type_stats[action].count += 1 + @type_stats[kind].count += 1 + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6eb8f6ba1fb9f77eecb3f59c8c17c2519975f45e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6eb8f6ba1fb9f77eecb3f59c8c17c2519975f45e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,120 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'news_controller' + +# Re-raise errors caught by the controller. +class NewsController; def rescue_action(e) raise e end; end + +class NewsControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :news, :comments + + def setup + @controller = NewsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_index + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:newss) + assert_nil assigns(:project) + end + + def test_index_with_project + get :index, :project_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:newss) + end + + def test_show + get :show, :id => 1 + assert_response :success + assert_template 'show' + assert_tag :tag => 'h2', :content => /eCookbook first release/ + end + + def test_show_not_found + get :show, :id => 999 + assert_response 404 + end + + def test_get_new + @request.session[:user_id] = 2 + get :new, :project_id => 1 + assert_response :success + assert_template 'new' + end + + def test_post_create + ActionMailer::Base.deliveries.clear + Setting.notified_events << 'news_added' + + @request.session[:user_id] = 2 + post :create, :project_id => 1, :news => { :title => 'NewsControllerTest', + :description => 'This is the description', + :summary => '' } + assert_redirected_to '/projects/ecookbook/news' + + news = News.find_by_title('NewsControllerTest') + assert_not_nil news + assert_equal 'This is the description', news.description + assert_equal User.find(2), news.author + assert_equal Project.find(1), news.project + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_get_edit + @request.session[:user_id] = 2 + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + end + + def test_put_update + @request.session[:user_id] = 2 + put :update, :id => 1, :news => { :description => 'Description changed by test_post_edit' } + assert_redirected_to '/news/1' + news = News.find(1) + assert_equal 'Description changed by test_post_edit', news.description + end + + def test_post_create_with_validation_failure + @request.session[:user_id] = 2 + post :create, :project_id => 1, :news => { :title => '', + :description => 'This is the description', + :summary => '' } + assert_response :success + assert_template 'new' + assert_not_nil assigns(:news) + assert assigns(:news).new_record? + assert_tag :tag => 'div', :attributes => { :id => 'errorExplanation' }, + :content => /1 error/ + end + + def test_destroy + @request.session[:user_id] = 2 + delete :destroy, :id => 1 + assert_redirected_to '/projects/ecookbook/news' + assert_nil News.find_by_id(1) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6ed00895e314aeaec84d2e309911a6ab1bb54af7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6ed00895e314aeaec84d2e309911a6ab1bb54af7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +module CodeRay +module Scanners + + load :html + + # Scanner for XML. + # + # Currently this is the same scanner as Scanners::HTML. + class XML < HTML + + register_for :xml + file_extension 'xml' + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6ee18bb17d137e4f0b4784f2e268e5d69c2ef948.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6ee18bb17d137e4f0b4784f2e268e5d69c2ef948.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class IssueAddNote < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "issues", :action => "add_note", :description => "label_add_note", :sort => 1057, :mail_option => 1, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'add_note']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6e/6efef8bd002ccaaa2a3bc87ce49cd01e47ed4daa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6e/6efef8bd002ccaaa2a3bc87ce49cd01e47ed4daa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +# English strings go here for Rails i18n +en: + my_label: "My label" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6f/6f1d2fd545f7dc1fe9896fc80a8a9990c3a19370.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6f/6f1d2fd545f7dc1fe9896fc80a8a9990c3a19370.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,99 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'boards_controller' + +# Re-raise errors caught by the controller. +class BoardsController; def rescue_action(e) raise e end; end + +class BoardsControllerTest < ActionController::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, :boards, :messages, :enabled_modules + + def setup + @controller = BoardsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_index + get :index, :project_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:boards) + assert_not_nil assigns(:project) + end + + def test_index_not_found + get :index, :project_id => 97 + assert_response 404 + end + + def test_index_should_show_messages_if_only_one_board + Project.find(1).boards.slice(1..-1).each(&:destroy) + + get :index, :project_id => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:topics) + end + + def test_post_new + @request.session[:user_id] = 2 + assert_difference 'Board.count' do + post :new, :project_id => 1, :board => { :name => 'Testing', :description => 'Testing board creation'} + end + assert_redirected_to '/projects/ecookbook/settings/boards' + end + + def test_show + get :show, :project_id => 1, :id => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:board) + assert_not_nil assigns(:project) + assert_not_nil assigns(:topics) + end + + def test_show_atom + get :show, :project_id => 1, :id => 1, :format => 'atom' + assert_response :success + assert_template 'common/feed.atom' + assert_not_nil assigns(:board) + assert_not_nil assigns(:project) + assert_not_nil assigns(:messages) + end + + def test_post_edit + @request.session[:user_id] = 2 + assert_no_difference 'Board.count' do + post :edit, :project_id => 1, :id => 2, :board => { :name => 'Testing', :description => 'Testing board update'} + end + assert_redirected_to '/projects/ecookbook/settings/boards' + assert_equal 'Testing', Board.find(2).name + end + + def test_post_destroy + @request.session[:user_id] = 2 + assert_difference 'Board.count', -1 do + post :destroy, :project_id => 1, :id => 2 + end + assert_redirected_to '/projects/ecookbook/settings/boards' + assert_nil Board.find_by_id(2) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6f/6f3eae848dd2627dfa6aa6d53a27862ad05c9e96.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6f/6f3eae848dd2627dfa6aa6d53a27862ad05c9e96.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,83 @@ +The engines plugin enhances Rails' own plugin framework, making it simple to share controllers, helpers, models, public assets, routes and migrations in plugins. + +For more information, see http://rails-engines.org + += Using the plugin + +Once you've installed the engines plugin, you'll need to add a single line to the top of config/environment.rb: + + require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot') + +You should add this line just below the require for Rails' own boot.rb file. This will enabled the enhanced plugin loading mechanism automatically for you (i.e. you don't need to set config.plugin_loader manually). + +With that aside, you're now ready to start using more powerful plugins in your application. Read on to find out more about what the engines plugin enables. + + +== Better plugins + +In addition to the regular set of plugin-supported files (lib, init.rb, tasks, generators, tests), plugins can carry the following when the engines plugin is also installed. + + +=== Controllers, Helpers, and Views + +Include these files in an app directory just like you would in a normal Rails application. If you need to override a method, view or partial, create the corresponding file in your main app directory and it will be used instead. + +* Controllers & Helpers: See Engines::RailsExtensions::Dependencies for more information. +* Views: now handled almost entirely by ActionView itself (see Engines::Plugin#add_plugin_view_paths for more information) + +=== Models + +Model code can similarly be placed in an app/models/ directory. Unfortunately, it's not possible to automatically override methods within a model; if your application needs to change the way a model behaves, consider creating a subclass, or replacing the model entirely within your application's app/models/ directory. See Engines::RailsExtensions::Dependencies for more information. + +IMPORTANT NOTE: when you load code from within plugins, it is typically not handled well by Rails in terms of unloading and reloading changes. Look here for more information - http://rails-engines.org/development/common-issues-when-overloading-code-from-plugins/ + +=== Routes + +Include your route declarations in a routes.rb file at the root of your plugins, e.g.: + + connect "/my/url", :controller => "some_controller" + my_named_route "do_stuff", :controller => "blah", :action => "stuff" + # etc. + +You can then load these files into your application by declaring their inclusion in the application's config/routes.rb: + + map.from_plugin :plugin_name + +See Engines::RailsExtensions::Routing for more information. + +=== Migrations + +Migrations record the changes in your database as your application evolves. With engines 1.2, migrations from plugins can also join in this evolution as first-class entities. To add migrations to a plugin, include a db/migrate/ folder and add migrations there as normal. These migrations can then be integrated into the main flow of database evolution by running the plugin_migration generator: + + script/generate plugin_migration + +This will produce a migration in your application. Running this migration (via rake db:migrate, as normal) will migrate the database according to the latest migrations in each plugin. See Engines::RailsExtensions::Migrations for more information. + + +=== More powerful Rake tasks + +The engines plugin enhances and adds to the suite of default rake tasks for working with plugins. The doc:plugins task now includes controllers, helpers and models under app, and anything other code found under the plugin's code_paths attribute. New testing tasks have been added to run unit, functional and integration tests from plugins, whilst making it easier to load fixtures from plugins. See Engines::Testing for more details about testing, and run + + rake -T + +to see the set of rake tasks available. + += Testing the engines plugin itself + +Because of the way the engines plugin modifies Rails, the simplest way to consistently test it against multiple versions is by generating a test harness application - a full Rails application that includes tests to verify the engines plugin behaviour in a real, running environment. + +Run the tests like this: + + $ cd engines + $ rake test + +This will generate a test_app directory within the engines plugin (using the default 'rails' command), import tests and code into that application and then run the test suite. + +If you wish to test against a specific version of Rails, run the tests with the RAILS environment variable set to the local directory containing your Rails checkout + + $ rake test RAILS=/Users/james/Code/rails_edge_checkout + +Alternatively, you can clone the latest version of Rails ('edge rails') from github like so: + + $ rake test RAILS=edge + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6f/6f698b7e19aa2a0b60b2198d129cd28a41bdf55a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6f/6f698b7e19aa2a0b60b2198d129cd28a41bdf55a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +== Sample plugin + +This is a sample plugin for Redmine + +== Installation + +1. Copy the plugin directory into the vendor/plugins directory + +2. Migrate plugin: + rake db:migrate_plugins + +3. Start Redmine + +Installed plugins are listed and can be configured from 'Admin -> Plugins' screen. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6f/6f938056d9ea2cfe9c4f2e93944e625cd1a36508.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6f/6f938056d9ea2cfe9c4f2e93944e625cd1a36508.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,341 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/abstract_adapter' +require 'cgi' + +module Redmine + module Scm + module Adapters + class MercurialAdapter < AbstractAdapter + + # Mercurial executable name + HG_BIN = Redmine::Configuration['scm_mercurial_command'] || "hg" + HELPERS_DIR = File.dirname(__FILE__) + "/mercurial" + HG_HELPER_EXT = "#{HELPERS_DIR}/redminehelper.py" + TEMPLATE_NAME = "hg-template" + TEMPLATE_EXTENSION = "tmpl" + + # raised if hg command exited with error, e.g. unknown revision. + class HgCommandAborted < CommandFailed; end + + class << self + def client_command + @@bin ||= HG_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (hgversion || []) + end + + def client_available + client_version_above?([1, 2]) + end + + def hgversion + # The hg version is expressed either as a + # release number (eg 0.9.5 or 1.0) or as a revision + # id composed of 12 hexa characters. + theversion = hgversion_from_command_line.dup + if theversion.respond_to?(:force_encoding) + theversion.force_encoding('ASCII-8BIT') + end + if m = theversion.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def hgversion_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + + def template_path + @@template_path ||= template_path_for(client_version) + end + + def template_path_for(version) + "#{HELPERS_DIR}/#{TEMPLATE_NAME}-1.0.#{TEMPLATE_EXTENSION}" + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + super + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def info + tip = summary['repository']['tip'] + Info.new(:root_url => CGI.unescape(summary['repository']['root']), + :lastrev => Revision.new(:revision => tip['revision'], + :scmid => tip['node'])) + # rescue HgCommandAborted + rescue Exception => e + logger.error "hg: error during getting info: #{e.message}" + nil + end + + def tags + as_ary(summary['repository']['tag']).map { |e| e['name'] } + end + + # Returns map of {'tag' => 'nodeid', ...} + def tagmap + alist = as_ary(summary['repository']['tag']).map do |e| + e.values_at('name', 'node') + end + Hash[*alist.flatten] + end + + def branches + brs = [] + as_ary(summary['repository']['branch']).each do |e| + br = Branch.new(e['name']) + br.revision = e['revision'] + br.scmid = e['node'] + brs << br + end + brs + end + + # Returns map of {'branch' => 'nodeid', ...} + def branchmap + alist = as_ary(summary['repository']['branch']).map do |e| + e.values_at('name', 'node') + end + Hash[*alist.flatten] + end + + def summary + return @summary if @summary + hg 'rhsummary' do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + @summary = ActiveSupport::XmlMini.parse(output)['rhsummary'] + rescue + end + end + end + private :summary + + def entries(path=nil, identifier=nil, options={}) + p1 = scm_iconv(@path_encoding, 'UTF-8', path) + manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)), + CGI.escape(without_leading_slash(p1.to_s))) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + ActiveSupport::XmlMini.parse(output)['rhmanifest']['repository']['manifest'] + rescue + end + end + path_prefix = path.blank? ? '' : with_trailling_slash(path) + + entries = Entries.new + as_ary(manifest['dir']).each do |e| + n = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['name'])) + p = "#{path_prefix}#{n}" + entries << Entry.new(:name => n, :path => p, :kind => 'dir') + end + + as_ary(manifest['file']).each do |e| + n = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['name'])) + p = "#{path_prefix}#{n}" + lr = Revision.new(:revision => e['revision'], :scmid => e['node'], + :identifier => e['node'], + :time => Time.at(e['time'].to_i)) + entries << Entry.new(:name => n, :path => p, :kind => 'file', + :size => e['size'].to_i, :lastrev => lr) + end + + entries + rescue HgCommandAborted + nil # means not found + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + revs = Revisions.new + each_revision(path, identifier_from, identifier_to, options) { |e| revs << e } + revs + end + + # Iterates the revisions by using a template file that + # makes Mercurial produce a xml output. + def each_revision(path=nil, identifier_from=nil, identifier_to=nil, options={}) + hg_args = ['log', '--debug', '-C', '--style', self.class.template_path] + hg_args << '-r' << "#{hgrev(identifier_from)}:#{hgrev(identifier_to)}" + hg_args << '--limit' << options[:limit] if options[:limit] + hg_args << hgtarget(path) unless path.blank? + log = hg(*hg_args) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + # Mercurial < 1.5 does not support footer template for '' + ActiveSupport::XmlMini.parse("#{output}")['log'] + rescue + end + end + as_ary(log['logentry']).each do |le| + cpalist = as_ary(le['paths']['path-copied']).map do |e| + [e['__content__'], e['copyfrom-path']].map do |s| + scm_iconv('UTF-8', @path_encoding, CGI.unescape(s)) + end + end + cpmap = Hash[*cpalist.flatten] + paths = as_ary(le['paths']['path']).map do |e| + p = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['__content__']) ) + {:action => e['action'], + :path => with_leading_slash(p), + :from_path => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil), + :from_revision => (cpmap.member?(p) ? le['node'] : nil)} + end.sort { |a, b| a[:path] <=> b[:path] } + parents_ary = [] + as_ary(le['parents']['parent']).map do |par| + parents_ary << par['__content__'] if par['__content__'] != "000000000000" + end + yield Revision.new(:revision => le['revision'], + :scmid => le['node'], + :author => (le['author']['__content__'] rescue ''), + :time => Time.parse(le['date']['__content__']), + :message => le['msg']['__content__'], + :paths => paths, + :parents => parents_ary) + end + self + end + + # Returns list of nodes in the specified branch + def nodes_in_branch(branch, options={}) + hg_args = ['rhlog', '--template', '{node|short}\n', '--rhbranch', CGI.escape(branch)] + hg_args << '--from' << CGI.escape(branch) + hg_args << '--to' << '0' + hg_args << '--limit' << options[:limit] if options[:limit] + hg(*hg_args) { |io| io.readlines.map { |e| e.chomp } } + end + + def diff(path, identifier_from, identifier_to=nil) + hg_args = %w|rhdiff| + if identifier_to + hg_args << '-r' << hgrev(identifier_to) << '-r' << hgrev(identifier_from) + else + hg_args << '-c' << hgrev(identifier_from) + end + unless path.blank? + p = scm_iconv(@path_encoding, 'UTF-8', path) + hg_args << CGI.escape(hgtarget(p)) + end + diff = [] + hg *hg_args do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue HgCommandAborted + nil # means not found + end + + def cat(path, identifier=nil) + p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) + hg 'rhcat', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io| + io.binmode + io.read + end + rescue HgCommandAborted + nil # means not found + end + + def annotate(path, identifier=nil) + p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) + blame = Annotate.new + hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io| + io.each_line do |line| + line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding) + next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$} + r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3, + :identifier => $3) + blame.add_line($4.rstrip, r) + end + end + blame + rescue HgCommandAborted + # means not found or cannot be annotated + Annotate.new + end + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + "#{revision}:#{scmid}" + end + end + + # Runs 'hg' command with the given args + def hg(*args, &block) + repo_path = root_url || url + full_args = ['-R', repo_path, '--encoding', 'utf-8'] + full_args << '--config' << "extensions.redminehelper=#{HG_HELPER_EXT}" + full_args << '--config' << 'diff.git=false' + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise HgCommandAborted, "hg exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :hg + + # Returns correct revision identifier + def hgrev(identifier, sq=false) + rev = identifier.blank? ? 'tip' : identifier.to_s + rev = shell_quote(rev) if sq + rev + end + private :hgrev + + def hgtarget(path) + path ||= '' + root_url + '/' + without_leading_slash(path) + end + private :hgtarget + + def as_ary(o) + return [] unless o + o.is_a?(Array) ? o : Array[o] + end + private :as_ary + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6f/6fc3080d660626f975ab483d311285aeb4746301.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6f/6fc3080d660626f975ab483d311285aeb4746301.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +<% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> +<%= f.hidden_field :version %> +<% if @section %> +<%= hidden_field_tag 'section', @section %> +<%= hidden_field_tag 'section_hash', @section_hash %> +<% end %> +<%= error_messages_for 'content' %> + +

    <%= text_area_tag 'content[text]', @text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %>

    +


    <%= f.text_field :comments, :size => 120 %>

    +


    <%= render :partial => 'attachments/form' %>

    + +

    <%= submit_tag l(:button_save) %> + <%= link_to_remote l(:label_preview), + { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title }, + :method => :post, + :update => 'preview', + :with => "Form.serialize('wiki_form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %>

    +<%= wikitoolbar_for 'content_text' %> +<% end %> + +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> + <%= robot_exclusion_tag %> +<% end %> + +<% html_title @page.pretty_title %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/6f/6fd3e6a84c471925f6b78ad778e38965d133a8ba.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/6f/6fd3e6a84c471925f6b78ad778e38965d133a8ba.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +api.array :users, api_meta(:total_count => @user_count, :offset => @offset, :limit => @limit) do + @users.each do |user| + api.user do + api.id user.id + api.login user.login + api.firstname user.firstname + api.lastname user.lastname + api.mail user.mail + api.created_on user.created_on + api.last_login_on user.last_login_on + + render_api_custom_values user.visible_custom_field_values, api + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/70/706a81236a3578317d828beb9423327b5b69e98d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/70/706a81236a3578317d828beb9423327b5b69e98d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + <%- plugins.each do |plugin| -%> + Engines.plugins["<%= plugin.name %>"].migrate(<%= new_versions[plugin.name] %>) + <%- end -%> + end + + def self.down + <%- plugins.each do |plugin| -%> + Engines.plugins["<%= plugin.name %>"].migrate(<%= current_versions[plugin.name] %>) + <%- end -%> + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/70/70b84ab9e3add639c1ef335fb9d7383dcdf7f5f5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/70/70b84ab9e3add639c1ef335fb9d7383dcdf7f5f5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +require File.expand_path('../../test_helper', __FILE__) + +class LdapAuthSourcesControllerTest < ActionController::TestCase + + def setup + @request.session[:user_id] = 1 + end + + context "get :new" do + setup do + get :new + end + + should_assign_to :auth_source + should_respond_with :success + should_render_template :new + + should "initilize a new AuthSource" do + assert_equal AuthSourceLdap, assigns(:auth_source).class + assert assigns(:auth_source).new_record? + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/70/70dfef569a65ef5db9a25ad36d19a3ee38afe71d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/70/70dfef569a65ef5db9a25ad36d19a3ee38afe71d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +class CopyRepositoriesLogEncoding < ActiveRecord::Migration + def self.up + encoding = Setting.commit_logs_encoding.to_s.strip + encoding = encoding.blank? ? 'UTF-8' : encoding + Repository.find(:all).each do |repo| + scm = repo.scm_name + case scm + when 'Subversion', 'Mercurial', 'Git', 'Filesystem' + repo.update_attribute(:log_encoding, nil) + else + repo.update_attribute(:log_encoding, encoding) + end + end + end + + def self.down + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/70/70fcc81fd15a480f7d8ac6f47bf3e67d8c9739ca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/70/70fcc81fd15a480f7d8ac6f47bf3e67d8c9739ca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +module CodeRay +module Encoders + + load :html + + # Wraps the output into a HTML page, using CSS classes and + # line numbers in the table format by default. + # + # See Encoders::HTML for available options. + class Page < HTML + + FILE_EXTENSION = 'html' + + register_for :page + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :class, + :wrap => :page, + :line_numbers => :table + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/71/710a574af3758681edb3f0bdf65b848f12ddaee7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/71/710a574af3758681edb3f0bdf65b848f12ddaee7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class ChangeChangesPathLengthLimit < ActiveRecord::Migration + def self.up + # these are two steps to please MySQL 5 on Win32 + change_column :changes, :path, :text, :default => nil, :null => true + change_column :changes, :path, :text, :null => false + + change_column :changes, :from_path, :text + end + + def self.down + change_column :changes, :path, :string, :default => "", :null => false + change_column :changes, :from_path, :string + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/71/7127b36f6a0a8457967e5fc607a740e9a4f582c9.svn-base Binary file .svn/pristine/71/7127b36f6a0a8457967e5fc607a740e9a4f582c9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/71/71a04e6b84c5e5e34c0d6c551f0d7eaa530db489.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/71/71a04e6b84c5e5e34c0d6c551f0d7eaa530db489.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,255 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0402 afii10051 +!81 U+0403 afii10052 +!82 U+201A quotesinglbase +!83 U+0453 afii10100 +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+20AC Euro +!89 U+2030 perthousand +!8A U+0409 afii10058 +!8B U+2039 guilsinglleft +!8C U+040A afii10059 +!8D U+040C afii10061 +!8E U+040B afii10060 +!8F U+040F afii10145 +!90 U+0452 afii10099 +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0459 afii10106 +!9B U+203A guilsinglright +!9C U+045A afii10107 +!9D U+045C afii10109 +!9E U+045B afii10108 +!9F U+045F afii10193 +!A0 U+00A0 space +!A1 U+040E afii10062 +!A2 U+045E afii10110 +!A3 U+0408 afii10057 +!A4 U+00A4 currency +!A5 U+0490 afii10050 +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+0401 afii10023 +!A9 U+00A9 copyright +!AA U+0404 afii10053 +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+0407 afii10056 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+0406 afii10055 +!B3 U+0456 afii10103 +!B4 U+0491 afii10098 +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0451 afii10071 +!B9 U+2116 afii61352 +!BA U+0454 afii10101 +!BB U+00BB guillemotright +!BC U+0458 afii10105 +!BD U+0405 afii10054 +!BE U+0455 afii10102 +!BF U+0457 afii10104 +!C0 U+0410 afii10017 +!C1 U+0411 afii10018 +!C2 U+0412 afii10019 +!C3 U+0413 afii10020 +!C4 U+0414 afii10021 +!C5 U+0415 afii10022 +!C6 U+0416 afii10024 +!C7 U+0417 afii10025 +!C8 U+0418 afii10026 +!C9 U+0419 afii10027 +!CA U+041A afii10028 +!CB U+041B afii10029 +!CC U+041C afii10030 +!CD U+041D afii10031 +!CE U+041E afii10032 +!CF U+041F afii10033 +!D0 U+0420 afii10034 +!D1 U+0421 afii10035 +!D2 U+0422 afii10036 +!D3 U+0423 afii10037 +!D4 U+0424 afii10038 +!D5 U+0425 afii10039 +!D6 U+0426 afii10040 +!D7 U+0427 afii10041 +!D8 U+0428 afii10042 +!D9 U+0429 afii10043 +!DA U+042A afii10044 +!DB U+042B afii10045 +!DC U+042C afii10046 +!DD U+042D afii10047 +!DE U+042E afii10048 +!DF U+042F afii10049 +!E0 U+0430 afii10065 +!E1 U+0431 afii10066 +!E2 U+0432 afii10067 +!E3 U+0433 afii10068 +!E4 U+0434 afii10069 +!E5 U+0435 afii10070 +!E6 U+0436 afii10072 +!E7 U+0437 afii10073 +!E8 U+0438 afii10074 +!E9 U+0439 afii10075 +!EA U+043A afii10076 +!EB U+043B afii10077 +!EC U+043C afii10078 +!ED U+043D afii10079 +!EE U+043E afii10080 +!EF U+043F afii10081 +!F0 U+0440 afii10082 +!F1 U+0441 afii10083 +!F2 U+0442 afii10084 +!F3 U+0443 afii10085 +!F4 U+0444 afii10086 +!F5 U+0445 afii10087 +!F6 U+0446 afii10088 +!F7 U+0447 afii10089 +!F8 U+0448 afii10090 +!F9 U+0449 afii10091 +!FA U+044A afii10092 +!FB U+044B afii10093 +!FC U+044C afii10094 +!FD U+044D afii10095 +!FE U+044E afii10096 +!FF U+044F afii10097 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/71/71a3fd6764dd58793b16c5a6e5745dac290e1aec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/71/71a3fd6764dd58793b16c5a6e5745dac290e1aec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/71/71b946892675c8d9da6aad0e18888da37353be5f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/71/71b946892675c8d9da6aad0e18888da37353be5f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,239 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+0385 dieresistonos +!A2 U+0386 Alphatonos +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/71/71c72fcec779c58b3cb29e26161e013284f30b8a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/71/71c72fcec779c58b3cb29e26161e013284f30b8a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class ApplicationTest < ActionController::IntegrationTest + include Redmine::I18n + + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def test_set_localization + Setting.default_language = 'en' + + # a french user + get 'projects', { }, 'Accept-Language' => 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' + assert_response :success + assert_tag :tag => 'h2', :content => 'Projets' + assert_equal :fr, current_language + + # then an italien user + get 'projects', { }, 'Accept-Language' => 'it;q=0.8,en-us;q=0.5,en;q=0.3' + assert_response :success + assert_tag :tag => 'h2', :content => 'Progetti' + assert_equal :it, current_language + + # not a supported language: default language should be used + get 'projects', { }, 'Accept-Language' => 'zz' + assert_response :success + assert_tag :tag => 'h2', :content => 'Projects' + end + + def test_token_based_access_should_not_start_session + # issue of a private project + get 'issues/4.atom' + assert_response 302 + + rss_key = User.find(2).rss_key + get "issues/4.atom?key=#{rss_key}" + assert_response 200 + assert_nil session[:user_id] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/72/7206c2f048a430c2b450227be9a8b2adfead5fc9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/72/7206c2f048a430c2b450227be9a8b2adfead5fc9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 MembersHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/72/7274c695571e958f3ca2e7a9525c8d48e60fc42c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/72/7274c695571e958f3ca2e7a9525c8d48e60fc42c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class AddRepositoriesChangesPermission < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => 'repositories', :action => 'changes', :description => 'label_change_plural', :sort => 1475, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('repositories', 'changes').destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/72/727874d7bc35b744eb4b647417de27d95212b4b8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/72/727874d7bc35b744eb4b647417de27d95212b4b8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1150 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class IssueTest < ActiveSupport::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, + :trackers, :projects_trackers, + :enabled_modules, + :versions, + :issue_statuses, :issue_categories, :issue_relations, :workflows, + :enumerations, + :issues, + :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, + :time_entries + + def test_create + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'test_create', + :description => 'IssueTest#test_create', :estimated_hours => '1:30') + assert issue.save + issue.reload + assert_equal 1.5, issue.estimated_hours + end + + def test_create_minimal + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'test_create') + assert issue.save + assert issue.description.nil? + end + + def test_create_with_required_custom_field + field = IssueCustomField.find_by_name('Database') + field.update_attribute(:is_required, true) + + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :subject => 'test_create', + :description => 'IssueTest#test_create_with_required_custom_field') + assert issue.available_custom_fields.include?(field) + # No value for the custom field + assert !issue.save + assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) + # Blank value + issue.custom_field_values = { field.id => '' } + assert !issue.save + assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) + # Invalid value + issue.custom_field_values = { field.id => 'SQLServer' } + assert !issue.save + assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) + # Valid value + issue.custom_field_values = { field.id => 'PostgreSQL' } + assert issue.save + issue.reload + assert_equal 'PostgreSQL', issue.custom_value_for(field).value + end + + def test_create_with_group_assignment + with_settings :issue_group_assignment => '1' do + assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, + :subject => 'Group assignment', + :assigned_to_id => 11).save + issue = Issue.first(:order => 'id DESC') + assert_kind_of Group, issue.assigned_to + assert_equal Group.find(11), issue.assigned_to + end + end + + def assert_visibility_match(user, issues) + assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort + end + + def test_visible_scope_for_anonymous + # Anonymous user should see issues of public projects only + issues = Issue.visible(User.anonymous).all + assert issues.any? + assert_nil issues.detect {|issue| !issue.project.is_public?} + assert_nil issues.detect {|issue| issue.is_private?} + assert_visibility_match User.anonymous, issues + end + + def test_visible_scope_for_anonymous_with_own_issues_visibility + Role.anonymous.update_attribute :issues_visibility, 'own' + Issue.create!(:project_id => 1, :tracker_id => 1, + :author_id => User.anonymous.id, + :subject => 'Issue by anonymous') + + issues = Issue.visible(User.anonymous).all + assert issues.any? + assert_nil issues.detect {|issue| issue.author != User.anonymous} + assert_visibility_match User.anonymous, issues + end + + def test_visible_scope_for_anonymous_without_view_issues_permissions + # Anonymous user should not see issues without permission + Role.anonymous.remove_permission!(:view_issues) + issues = Issue.visible(User.anonymous).all + assert issues.empty? + assert_visibility_match User.anonymous, issues + end + + def test_visible_scope_for_non_member + user = User.find(9) + assert user.projects.empty? + # Non member user should see issues of public projects only + issues = Issue.visible(user).all + assert issues.any? + assert_nil issues.detect {|issue| !issue.project.is_public?} + assert_nil issues.detect {|issue| issue.is_private?} + assert_visibility_match user, issues + end + + def test_visible_scope_for_non_member_with_own_issues_visibility + Role.non_member.update_attribute :issues_visibility, 'own' + Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member') + user = User.find(9) + + issues = Issue.visible(user).all + assert issues.any? + assert_nil issues.detect {|issue| issue.author != user} + assert_visibility_match user, issues + end + + def test_visible_scope_for_non_member_without_view_issues_permissions + # Non member user should not see issues without permission + Role.non_member.remove_permission!(:view_issues) + user = User.find(9) + assert user.projects.empty? + issues = Issue.visible(user).all + assert issues.empty? + assert_visibility_match user, issues + end + + def test_visible_scope_for_member + user = User.find(9) + # User should see issues of projects for which he has view_issues permissions only + Role.non_member.remove_permission!(:view_issues) + Member.create!(:principal => user, :project_id => 3, :role_ids => [2]) + issues = Issue.visible(user).all + assert issues.any? + assert_nil issues.detect {|issue| issue.project_id != 3} + assert_nil issues.detect {|issue| issue.is_private?} + assert_visibility_match user, issues + end + + def test_visible_scope_for_member_with_groups_should_return_assigned_issues + user = User.find(8) + assert user.groups.any? + Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2]) + Role.non_member.remove_permission!(:view_issues) + + issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Assignment test', + :assigned_to => user.groups.first, + :is_private => true) + + Role.find(2).update_attribute :issues_visibility, 'default' + issues = Issue.visible(User.find(8)).all + assert issues.any? + assert issues.include?(issue) + + Role.find(2).update_attribute :issues_visibility, 'own' + issues = Issue.visible(User.find(8)).all + assert issues.any? + assert issues.include?(issue) + end + + def test_visible_scope_for_admin + user = User.find(1) + user.members.each(&:destroy) + assert user.projects.empty? + issues = Issue.visible(user).all + assert issues.any? + # Admin should see issues on private projects that he does not belong to + assert issues.detect {|issue| !issue.project.is_public?} + # Admin should see private issues of other users + assert issues.detect {|issue| issue.is_private? && issue.author != user} + assert_visibility_match user, issues + end + + def test_visible_scope_with_project + project = Project.find(1) + issues = Issue.visible(User.find(2), :project => project).all + projects = issues.collect(&:project).uniq + assert_equal 1, projects.size + assert_equal project, projects.first + end + + def test_visible_scope_with_project_and_subprojects + project = Project.find(1) + issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all + projects = issues.collect(&:project).uniq + assert projects.size > 1 + assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)} + end + + def test_visible_and_nested_set_scopes + assert_equal 0, Issue.find(1).descendants.visible.all.size + end + + def test_errors_full_messages_should_include_custom_fields_errors + field = IssueCustomField.find_by_name('Database') + + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :subject => 'test_create', + :description => 'IssueTest#test_create_with_required_custom_field') + assert issue.available_custom_fields.include?(field) + # Invalid value + issue.custom_field_values = { field.id => 'SQLServer' } + + assert !issue.valid? + assert_equal 1, issue.errors.full_messages.size + assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", + issue.errors.full_messages.first + end + + def test_update_issue_with_required_custom_field + field = IssueCustomField.find_by_name('Database') + field.update_attribute(:is_required, true) + + issue = Issue.find(1) + assert_nil issue.custom_value_for(field) + assert issue.available_custom_fields.include?(field) + # No change to custom values, issue can be saved + assert issue.save + # Blank value + issue.custom_field_values = { field.id => '' } + assert !issue.save + # Valid value + issue.custom_field_values = { field.id => 'PostgreSQL' } + assert issue.save + issue.reload + assert_equal 'PostgreSQL', issue.custom_value_for(field).value + end + + def test_should_not_update_attributes_if_custom_fields_validation_fails + issue = Issue.find(1) + field = IssueCustomField.find_by_name('Database') + assert issue.available_custom_fields.include?(field) + + issue.custom_field_values = { field.id => 'Invalid' } + issue.subject = 'Should be not be saved' + assert !issue.save + + issue.reload + assert_equal "Can't print recipes", issue.subject + end + + def test_should_not_recreate_custom_values_objects_on_update + field = IssueCustomField.find_by_name('Database') + + issue = Issue.find(1) + issue.custom_field_values = { field.id => 'PostgreSQL' } + assert issue.save + custom_value = issue.custom_value_for(field) + issue.reload + issue.custom_field_values = { field.id => 'MySQL' } + assert issue.save + issue.reload + assert_equal custom_value.id, issue.custom_value_for(field).id + end + + def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields + issue = Issue.new(:project_id => 1) + issue.attributes = {:tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'Test', :custom_field_values => {'2' => 'Test'}} + issue.save! + + assert !Tracker.find(2).custom_field_ids.include?(2) + + issue = Issue.find(issue.id) + issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}} + + issue = Issue.find(issue.id) + custom_value = issue.custom_value_for(2) + assert_not_nil custom_value + assert_equal 'Test', custom_value.value + end + + def test_assigning_tracker_id_should_reload_custom_fields_values + issue = Issue.new(:project => Project.find(1)) + assert issue.custom_field_values.empty? + issue.tracker_id = 1 + assert issue.custom_field_values.any? + end + + def test_assigning_attributes_should_assign_tracker_id_first + attributes = ActiveSupport::OrderedHash.new + attributes['custom_field_values'] = { '1' => 'MySQL' } + attributes['tracker_id'] = '1' + issue = Issue.new(:project => Project.find(1)) + issue.attributes = attributes + assert_not_nil issue.custom_value_for(1) + assert_equal 'MySQL', issue.custom_value_for(1).value + end + + def test_should_update_issue_with_disabled_tracker + p = Project.find(1) + issue = Issue.find(1) + + p.trackers.delete(issue.tracker) + assert !p.trackers.include?(issue.tracker) + + issue.reload + issue.subject = 'New subject' + assert issue.save + end + + def test_should_not_set_a_disabled_tracker + p = Project.find(1) + p.trackers.delete(Tracker.find(2)) + + issue = Issue.find(1) + issue.tracker_id = 2 + issue.subject = 'New subject' + assert !issue.save + assert_not_nil issue.errors[:tracker_id] + end + + def test_category_based_assignment + issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Assignment test', + :description => 'Assignment test', :category_id => 1) + assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to + end + + def test_new_statuses_allowed_to + Workflow.delete_all + + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false) + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false) + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true) + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true) + status = IssueStatus.find(1) + role = Role.find(1) + tracker = Tracker.find(1) + user = User.find(2) + + issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1) + assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id) + + issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user) + assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id) + + issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user) + assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) + + issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user) + assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) + end + + def test_copy + issue = Issue.new.copy_from(1) + assert issue.save + issue.reload + orig = Issue.find(1) + assert_equal orig.subject, issue.subject + assert_equal orig.tracker, issue.tracker + assert_equal "125", issue.custom_value_for(2).value + end + + def test_copy_should_copy_status + orig = Issue.find(8) + assert orig.status != IssueStatus.default + + issue = Issue.new.copy_from(orig) + assert issue.save + issue.reload + assert_equal orig.status, issue.status + end + + def test_should_close_duplicates + # Create 3 issues + issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Duplicates test', :description => 'Duplicates test') + assert issue1.save + issue2 = issue1.clone + assert issue2.save + issue3 = issue1.clone + assert issue3.save + + # 2 is a dupe of 1 + IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) + # And 3 is a dupe of 2 + IssueRelation.create(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES) + # And 3 is a dupe of 1 (circular duplicates) + IssueRelation.create(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) + + assert issue1.reload.duplicates.include?(issue2) + + # Closing issue 1 + issue1.init_journal(User.find(:first), "Closing issue1") + issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true} + assert issue1.save + # 2 and 3 should be also closed + assert issue2.reload.closed? + assert issue3.reload.closed? + end + + def test_should_not_close_duplicated_issue + # Create 3 issues + issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Duplicates test', :description => 'Duplicates test') + assert issue1.save + issue2 = issue1.clone + assert issue2.save + + # 2 is a dupe of 1 + IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) + # 2 is a dup of 1 but 1 is not a duplicate of 2 + assert !issue2.reload.duplicates.include?(issue1) + + # Closing issue 2 + issue2.init_journal(User.find(:first), "Closing issue2") + issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true} + assert issue2.save + # 1 should not be also closed + assert !issue1.reload.closed? + end + + def test_assignable_versions + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') + assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq + end + + def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') + assert !issue.save + assert_not_nil issue.errors[:fixed_version_id] + end + + def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue') + assert !issue.save + assert_not_nil issue.errors[:fixed_version_id] + end + + def test_should_be_able_to_assign_a_new_issue_to_an_open_version + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue') + assert issue.save + end + + def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version + issue = Issue.find(11) + assert_equal 'closed', issue.fixed_version.status + issue.subject = 'Subject changed' + assert issue.save + end + + def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version + issue = Issue.find(11) + issue.status_id = 1 + assert !issue.save + assert_not_nil issue.errors[:base] + end + + def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version + issue = Issue.find(11) + issue.status_id = 1 + issue.fixed_version_id = 3 + assert issue.save + end + + def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version + issue = Issue.find(12) + assert_equal 'locked', issue.fixed_version.status + issue.status_id = 1 + assert issue.save + end + + def test_move_to_another_project_with_same_category + issue = Issue.find(1) + assert issue.move_to_project(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Category changes + assert_equal 4, issue.category_id + # Make sure time entries were move to the target project + assert_equal 2, issue.time_entries.first.project_id + end + + def test_move_to_another_project_without_same_category + issue = Issue.find(2) + assert issue.move_to_project(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Category cleared + assert_nil issue.category_id + end + + def test_move_to_another_project_should_clear_fixed_version_when_not_shared + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 1) + assert issue.move_to_project(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Cleared fixed_version + assert_equal nil, issue.fixed_version + end + + def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 4) + assert issue.move_to_project(Project.find(5)) + issue.reload + assert_equal 5, issue.project_id + # Keep fixed_version + assert_equal 4, issue.fixed_version_id + end + + def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 1) + assert issue.move_to_project(Project.find(5)) + issue.reload + assert_equal 5, issue.project_id + # Cleared fixed_version + assert_equal nil, issue.fixed_version + end + + def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 7) + assert issue.move_to_project(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Keep fixed_version + assert_equal 7, issue.fixed_version_id + end + + def test_move_to_another_project_with_disabled_tracker + issue = Issue.find(1) + target = Project.find(2) + target.tracker_ids = [3] + target.save + assert_equal false, issue.move_to_project(target) + issue.reload + assert_equal 1, issue.project_id + end + + def test_copy_to_the_same_project + issue = Issue.find(1) + copy = nil + assert_difference 'Issue.count' do + copy = issue.move_to_project(issue.project, nil, :copy => true) + end + assert_kind_of Issue, copy + assert_equal issue.project, copy.project + assert_equal "125", copy.custom_value_for(2).value + end + + def test_copy_to_another_project_and_tracker + issue = Issue.find(1) + copy = nil + assert_difference 'Issue.count' do + copy = issue.move_to_project(Project.find(3), Tracker.find(2), :copy => true) + end + copy.reload + assert_kind_of Issue, copy + assert_equal Project.find(3), copy.project + assert_equal Tracker.find(2), copy.tracker + # Custom field #2 is not associated with target tracker + assert_nil copy.custom_value_for(2) + end + + context "#move_to_project" do + context "as a copy" do + setup do + @issue = Issue.find(1) + @copy = nil + end + + should "not create a journal" do + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}}) + assert_equal 0, @copy.reload.journals.size + end + + should "allow assigned_to changes" do + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}}) + assert_equal 3, @copy.assigned_to_id + end + + should "allow status changes" do + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}}) + assert_equal 2, @copy.status_id + end + + should "allow start date changes" do + date = Date.today + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}}) + assert_equal date, @copy.start_date + end + + should "allow due date changes" do + date = Date.today + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}}) + + assert_equal date, @copy.due_date + end + + should "set current user as author" do + User.current = User.find(9) + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {}}) + + assert_equal User.current, @copy.author + end + + should "keep journal notes" do + date = Date.today + notes = "Notes added when copying" + User.current = User.find(9) + @issue.init_journal(User.current, notes) + @copy = @issue.move_to_project(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}}) + + assert_equal 1, @copy.journals.size + journal = @copy.journals.first + assert_equal 0, journal.details.size + assert_equal notes, journal.notes + end + end + end + + def test_recipients_should_not_include_users_that_cannot_view_the_issue + issue = Issue.find(12) + assert issue.recipients.include?(issue.author.mail) + # move the issue to a private project + copy = issue.move_to_project(Project.find(5), Tracker.find(2), :copy => true) + # author is not a member of project anymore + assert !copy.recipients.include?(copy.author.mail) + end + + def test_recipients_should_include_the_assigned_group_members + group_member = User.generate_with_protected! + group = Group.generate! + group.users << group_member + + issue = Issue.find(12) + issue.assigned_to = group + assert issue.recipients.include?(group_member.mail) + end + + def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue + user = User.find(3) + issue = Issue.find(9) + Watcher.create!(:user => user, :watchable => issue) + assert issue.watched_by?(user) + assert !issue.watcher_recipients.include?(user.mail) + end + + def test_issue_destroy + Issue.find(1).destroy + assert_nil Issue.find_by_id(1) + assert_nil TimeEntry.find_by_issue_id(1) + end + + def test_blocked + blocked_issue = Issue.find(9) + blocking_issue = Issue.find(10) + + assert blocked_issue.blocked? + assert !blocking_issue.blocked? + end + + def test_blocked_issues_dont_allow_closed_statuses + blocked_issue = Issue.find(9) + + allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002)) + assert !allowed_statuses.empty? + closed_statuses = allowed_statuses.select {|st| st.is_closed?} + assert closed_statuses.empty? + end + + def test_unblocked_issues_allow_closed_statuses + blocking_issue = Issue.find(10) + + allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002)) + assert !allowed_statuses.empty? + closed_statuses = allowed_statuses.select {|st| st.is_closed?} + assert !closed_statuses.empty? + end + + def test_rescheduling_an_issue_should_reschedule_following_issue + issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => '-', :start_date => Date.today, :due_date => Date.today + 2) + issue2 = Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => '-', :start_date => Date.today, :due_date => Date.today + 2) + IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES) + assert_equal issue1.due_date + 1, issue2.reload.start_date + + issue1.due_date = Date.today + 5 + issue1.save! + assert_equal issue1.due_date + 1, issue2.reload.start_date + end + + def test_overdue + assert Issue.new(:due_date => 1.day.ago.to_date).overdue? + assert !Issue.new(:due_date => Date.today).overdue? + assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue? + assert !Issue.new(:due_date => nil).overdue? + assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue? + end + + context "#behind_schedule?" do + should "be false if the issue has no start_date" do + assert !Issue.new(:start_date => nil, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule? + end + + should "be false if the issue has no end_date" do + assert !Issue.new(:start_date => 1.day.from_now.to_date, :due_date => nil, :done_ratio => 0).behind_schedule? + end + + should "be false if the issue has more done than it's calendar time" do + assert !Issue.new(:start_date => 50.days.ago.to_date, :due_date => 50.days.from_now.to_date, :done_ratio => 90).behind_schedule? + end + + should "be true if the issue hasn't been started at all" do + assert Issue.new(:start_date => 1.day.ago.to_date, :due_date => 1.day.from_now.to_date, :done_ratio => 0).behind_schedule? + end + + should "be true if the issue has used more calendar time than it's done ratio" do + assert Issue.new(:start_date => 100.days.ago.to_date, :due_date => Date.today, :done_ratio => 90).behind_schedule? + end + end + + context "#assignable_users" do + should "be Users" do + assert_kind_of User, Issue.find(1).assignable_users.first + end + + should "include the issue author" do + project = Project.find(1) + non_project_member = User.generate! + issue = Issue.generate_for_project!(project, :author => non_project_member) + + assert issue.assignable_users.include?(non_project_member) + end + + should "include the current assignee" do + project = Project.find(1) + user = User.generate! + issue = Issue.generate_for_project!(project, :assigned_to => user) + user.lock! + + assert Issue.find(issue.id).assignable_users.include?(user) + end + + should "not show the issue author twice" do + assignable_user_ids = Issue.find(1).assignable_users.collect(&:id) + assert_equal 2, assignable_user_ids.length + + assignable_user_ids.each do |user_id| + assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once" + end + end + + context "with issue_group_assignment" do + should "include groups" do + issue = Issue.new(:project => Project.find(2)) + + with_settings :issue_group_assignment => '1' do + assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort + assert issue.assignable_users.include?(Group.find(11)) + end + end + end + + context "without issue_group_assignment" do + should "not include groups" do + issue = Issue.new(:project => Project.find(2)) + + with_settings :issue_group_assignment => '0' do + assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort + assert !issue.assignable_users.include?(Group.find(11)) + end + end + end + end + + def test_create_should_send_email_notification + ActionMailer::Base.deliveries.clear + issue = Issue.new(:project_id => 1, :tracker_id => 1, + :author_id => 3, :status_id => 1, + :priority => IssuePriority.all.first, + :subject => 'test_create', :estimated_hours => '1:30') + + assert issue.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_stale_issue_should_not_send_email_notification + ActionMailer::Base.deliveries.clear + issue = Issue.find(1) + stale = Issue.find(1) + + issue.init_journal(User.find(1)) + issue.subject = 'Subjet update' + assert issue.save + assert_equal 1, ActionMailer::Base.deliveries.size + ActionMailer::Base.deliveries.clear + + stale.init_journal(User.find(1)) + stale.subject = 'Another subjet update' + assert_raise ActiveRecord::StaleObjectError do + stale.save + end + assert ActionMailer::Base.deliveries.empty? + end + + def test_journalized_description + IssueCustomField.delete_all + + i = Issue.first + old_description = i.description + new_description = "This is the new description" + + i.init_journal(User.find(2)) + i.description = new_description + assert_difference 'Journal.count', 1 do + assert_difference 'JournalDetail.count', 1 do + i.save! + end + end + + detail = JournalDetail.first(:order => 'id DESC') + assert_equal i, detail.journal.journalized + assert_equal 'attr', detail.property + assert_equal 'description', detail.prop_key + assert_equal old_description, detail.old_value + assert_equal new_description, detail.value + end + + def test_blank_descriptions_should_not_be_journalized + IssueCustomField.delete_all + Issue.update_all("description = NULL", "id=1") + + i = Issue.find(1) + i.init_journal(User.find(2)) + i.subject = "blank description" + i.description = "\r\n" + + assert_difference 'Journal.count', 1 do + assert_difference 'JournalDetail.count', 1 do + i.save! + end + end + end + + def test_description_eol_should_be_normalized + i = Issue.new(:description => "CR \r LF \n CRLF \r\n") + assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description + end + + def test_saving_twice_should_not_duplicate_journal_details + i = Issue.find(:first) + i.init_journal(User.find(2), 'Some notes') + # initial changes + i.subject = 'New subject' + i.done_ratio = i.done_ratio + 10 + assert_difference 'Journal.count' do + assert i.save + end + # 1 more change + i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id]) + assert_no_difference 'Journal.count' do + assert_difference 'JournalDetail.count', 1 do + i.save + end + end + # no more change + assert_no_difference 'Journal.count' do + assert_no_difference 'JournalDetail.count' do + i.save + end + end + end + + def test_all_dependent_issues + IssueRelation.delete_all + assert IssueRelation.create!(:issue_from => Issue.find(1), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(2), + :issue_to => Issue.find(3), + :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(3), + :issue_to => Issue.find(8), + :relation_type => IssueRelation::TYPE_PRECEDES) + + assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort + end + + def test_all_dependent_issues_with_persistent_circular_dependency + IssueRelation.delete_all + assert IssueRelation.create!(:issue_from => Issue.find(1), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(2), + :issue_to => Issue.find(3), + :relation_type => IssueRelation::TYPE_PRECEDES) + # Validation skipping + assert IssueRelation.new(:issue_from => Issue.find(3), + :issue_to => Issue.find(1), + :relation_type => IssueRelation::TYPE_PRECEDES).save(false) + + assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort + end + + def test_all_dependent_issues_with_persistent_multiple_circular_dependencies + IssueRelation.delete_all + assert IssueRelation.create!(:issue_from => Issue.find(1), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_RELATES) + assert IssueRelation.create!(:issue_from => Issue.find(2), + :issue_to => Issue.find(3), + :relation_type => IssueRelation::TYPE_RELATES) + assert IssueRelation.create!(:issue_from => Issue.find(3), + :issue_to => Issue.find(8), + :relation_type => IssueRelation::TYPE_RELATES) + # Validation skipping + assert IssueRelation.new(:issue_from => Issue.find(8), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_RELATES).save(false) + assert IssueRelation.new(:issue_from => Issue.find(3), + :issue_to => Issue.find(1), + :relation_type => IssueRelation::TYPE_RELATES).save(false) + + assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort + end + + context "#done_ratio" do + setup do + @issue = Issue.find(1) + @issue_status = IssueStatus.find(1) + @issue_status.update_attribute(:default_done_ratio, 50) + @issue2 = Issue.find(2) + @issue_status2 = IssueStatus.find(2) + @issue_status2.update_attribute(:default_done_ratio, 0) + end + + context "with Setting.issue_done_ratio using the issue_field" do + setup do + Setting.issue_done_ratio = 'issue_field' + end + + should "read the issue's field" do + assert_equal 0, @issue.done_ratio + assert_equal 30, @issue2.done_ratio + end + end + + context "with Setting.issue_done_ratio using the issue_status" do + setup do + Setting.issue_done_ratio = 'issue_status' + end + + should "read the Issue Status's default done ratio" do + assert_equal 50, @issue.done_ratio + assert_equal 0, @issue2.done_ratio + end + end + end + + context "#update_done_ratio_from_issue_status" do + setup do + @issue = Issue.find(1) + @issue_status = IssueStatus.find(1) + @issue_status.update_attribute(:default_done_ratio, 50) + @issue2 = Issue.find(2) + @issue_status2 = IssueStatus.find(2) + @issue_status2.update_attribute(:default_done_ratio, 0) + end + + context "with Setting.issue_done_ratio using the issue_field" do + setup do + Setting.issue_done_ratio = 'issue_field' + end + + should "not change the issue" do + @issue.update_done_ratio_from_issue_status + @issue2.update_done_ratio_from_issue_status + + assert_equal 0, @issue.read_attribute(:done_ratio) + assert_equal 30, @issue2.read_attribute(:done_ratio) + end + end + + context "with Setting.issue_done_ratio using the issue_status" do + setup do + Setting.issue_done_ratio = 'issue_status' + end + + should "change the issue's done ratio" do + @issue.update_done_ratio_from_issue_status + @issue2.update_done_ratio_from_issue_status + + assert_equal 50, @issue.read_attribute(:done_ratio) + assert_equal 0, @issue2.read_attribute(:done_ratio) + end + end + end + + test "#by_tracker" do + User.current = User.anonymous + groups = Issue.by_tracker(Project.find(1)) + assert_equal 3, groups.size + assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + test "#by_version" do + User.current = User.anonymous + groups = Issue.by_version(Project.find(1)) + assert_equal 3, groups.size + assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + test "#by_priority" do + User.current = User.anonymous + groups = Issue.by_priority(Project.find(1)) + assert_equal 4, groups.size + assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + test "#by_category" do + User.current = User.anonymous + groups = Issue.by_category(Project.find(1)) + assert_equal 2, groups.size + assert_equal 3, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + test "#by_assigned_to" do + User.current = User.anonymous + groups = Issue.by_assigned_to(Project.find(1)) + assert_equal 2, groups.size + assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + test "#by_author" do + User.current = User.anonymous + groups = Issue.by_author(Project.find(1)) + assert_equal 4, groups.size + assert_equal 7, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + test "#by_subproject" do + User.current = User.anonymous + groups = Issue.by_subproject(Project.find(1)) + # Private descendant not visible + assert_equal 1, groups.size + assert_equal 2, groups.inject(0) {|sum, group| sum + group['total'].to_i} + end + + context ".allowed_target_projects_on_move" do + should "return all active projects for admin users" do + User.current = User.find(1) + assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size + end + + should "return allowed projects for non admin users" do + User.current = User.find(2) + Role.non_member.remove_permission! :move_issues + assert_equal 3, Issue.allowed_target_projects_on_move.size + + Role.non_member.add_permission! :move_issues + assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size + end + end + + def test_recently_updated_with_limit_scopes + #should return the last updated issue + assert_equal 1, Issue.recently_updated.with_limit(1).length + assert_equal Issue.find(:first, :order => "updated_on DESC"), Issue.recently_updated.with_limit(1).first + end + + def test_on_active_projects_scope + assert Project.find(2).archive + + before = Issue.on_active_project.length + # test inclusion to results + issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first) + assert_equal before + 1, Issue.on_active_project.length + + # Move to an archived project + issue.project = Project.find(2) + assert issue.save + assert_equal before, Issue.on_active_project.length + end + + context "Issue#recipients" do + setup do + @project = Project.find(1) + @author = User.generate_with_protected! + @assignee = User.generate_with_protected! + @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author) + end + + should "include project recipients" do + assert @project.recipients.present? + @project.recipients.each do |project_recipient| + assert @issue.recipients.include?(project_recipient) + end + end + + should "include the author if the author is active" do + assert @issue.author, "No author set for Issue" + assert @issue.recipients.include?(@issue.author.mail) + end + + should "include the assigned to user if the assigned to user is active" do + assert @issue.assigned_to, "No assigned_to set for Issue" + assert @issue.recipients.include?(@issue.assigned_to.mail) + end + + should "not include users who opt out of all email" do + @author.update_attribute(:mail_notification, :none) + + assert !@issue.recipients.include?(@issue.author.mail) + end + + should "not include the issue author if they are only notified of assigned issues" do + @author.update_attribute(:mail_notification, :only_assigned) + + assert !@issue.recipients.include?(@issue.author.mail) + end + + should "not include the assigned user if they are only notified of owned issues" do + @assignee.update_attribute(:mail_notification, :only_owner) + + assert !@issue.recipients.include?(@issue.assigned_to.mail) + end + + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/72/72b134a74f37265288938527276f0807a1362abf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/72/72b134a74f37265288938527276f0807a1362abf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=l(:label_issue_status_new)%>

    + +<% form_for @issue_status, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/72/72f0350ace5f91c2452fe68fefaac12651ddb55a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/72/72f0350ace5f91c2452fe68fefaac12651ddb55a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_query) %>

    + +<% form_tag(query_path(@query), :onsubmit => 'selectAllOptions("selected_columns");', :method => :put) do %> + <%= render :partial => 'form', :locals => {:query => @query} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/7300a4e4784e1a8a94fcf1b6586e7c60896cd357.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/7300a4e4784e1a8a94fcf1b6586e7c60896cd357.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,94 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Wiki < ActiveRecord::Base + belongs_to :project + has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title' + has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all + + acts_as_watchable + + validates_presence_of :start_page + validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/ + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_wiki_pages, project) + end + + # Returns the wiki page that acts as the sidebar content + # or nil if no such page exists + def sidebar + @sidebar ||= find_page('Sidebar', :with_redirect => false) + end + + # find the page with the given title + # if page doesn't exist, return a new page + def find_or_new_page(title) + title = start_page if title.blank? + find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title)) + end + + # find the page with the given title + def find_page(title, options = {}) + @page_found_with_redirect = false + title = start_page if title.blank? + title = Wiki.titleize(title) + page = pages.first(:conditions => ["LOWER(title) = LOWER(?)", title]) + if !page && !(options[:with_redirect] == false) + # search for a redirect + redirect = redirects.first(:conditions => ["LOWER(title) = LOWER(?)", title]) + if redirect + page = find_page(redirect.redirects_to, :with_redirect => false) + @page_found_with_redirect = true + end + end + page + end + + # Returns true if the last page was found with a redirect + def page_found_with_redirect? + @page_found_with_redirect + end + + # Finds a page by title + # The given string can be of one of the forms: "title" or "project:title" + # Examples: + # Wiki.find_page("bar", project => foo) + # Wiki.find_page("foo:bar") + def self.find_page(title, options = {}) + project = options[:project] + if title.to_s =~ %r{^([^\:]+)\:(.*)$} + project_identifier, title = $1, $2 + project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier) + end + if project && project.wiki + page = project.wiki.find_page(title) + if page && page.content + page + end + end + end + + # turn a string into a valid page title + def self.titleize(title) + # replace spaces with _ and remove unwanted caracters + title = title.gsub(/\s+/, '_').delete(',./?;|:') if title + # upcase the first letter + title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title + title + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/7307de1b5462f7be62d7bf6a74adef2b68c39598.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/7307de1b5462f7be62d7bf6a74adef2b68c39598.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +// Translated by: Pedro Araújo +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negrito'; +jsToolBar.strings['Italic'] = 'Itálico'; +jsToolBar.strings['Underline'] = 'Sublinhado'; +jsToolBar.strings['Deleted'] = 'Apagado'; +jsToolBar.strings['Code'] = 'Código Inline'; +jsToolBar.strings['Heading 1'] = 'Cabeçalho 1'; +jsToolBar.strings['Heading 2'] = 'Cabeçalho 2'; +jsToolBar.strings['Heading 3'] = 'Cabeçalho 3'; +jsToolBar.strings['Unordered list'] = 'Lista não ordenada'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citação'; +jsToolBar.strings['Unquote'] = 'Remover citação'; +jsToolBar.strings['Preformatted text'] = 'Texto pré-formatado'; +jsToolBar.strings['Wiki link'] = 'Link para uma página da Wiki'; +jsToolBar.strings['Image'] = 'Imagem'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/730e7c9bc9c48dc81b3322907773ad6f6d8d03cc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/730e7c9bc9c48dc81b3322907773ad6f6d8d03cc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,94 @@ +--- +enumerations_001: + name: Uncategorized + id: 1 + type: DocumentCategory + active: true +enumerations_002: + name: User documentation + id: 2 + type: DocumentCategory + active: true +enumerations_003: + name: Technical documentation + id: 3 + type: DocumentCategory + active: true +enumerations_004: + name: Low + id: 4 + type: IssuePriority + active: true + position: 1 +enumerations_005: + name: Normal + id: 5 + type: IssuePriority + is_default: true + active: true + position: 2 +enumerations_006: + name: High + id: 6 + type: IssuePriority + active: true + position: 3 +enumerations_007: + name: Urgent + id: 7 + type: IssuePriority + active: true + position: 4 +enumerations_008: + name: Immediate + id: 8 + type: IssuePriority + active: true + position: 5 +enumerations_009: + name: Design + id: 9 + type: TimeEntryActivity + position: 1 + active: true +enumerations_010: + name: Development + id: 10 + type: TimeEntryActivity + position: 2 + is_default: true + active: true +enumerations_011: + name: QA + id: 11 + type: TimeEntryActivity + position: 3 + active: true +enumerations_012: + name: Default Enumeration + id: 12 + type: Enumeration + is_default: true + active: true +enumerations_013: + name: Another Enumeration + id: 13 + type: Enumeration + active: true +enumerations_014: + name: Inactive Activity + id: 14 + type: TimeEntryActivity + position: 4 + active: false +enumerations_015: + name: Inactive Priority + id: 15 + type: IssuePriority + position: 6 + active: false +enumerations_016: + name: Inactive Document Category + id: 16 + type: DocumentCategory + active: false diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/7312a1538a08cc5ceaf5579a66a48a6614d8eeab.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/7312a1538a08cc5ceaf5579a66a48a6614d8eeab.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class TimeEntryActivityCustomField < CustomField + def type_name + :enumeration_activities + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/733b596d53c40ed4baf1da5919b8ef878d966efe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/733b596d53c40ed4baf1da5919b8ef878d966efe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h(@page.pretty_title) %>

    + +

    <%= l(:label_history) %>

    + +<% form_tag({:action => "diff"}, :method => :get) do %> + + + + + + + + + + + +<% show_diff = @versions.size > 1 %> +<% line_num = 1 %> +<% @versions.each do |ver| %> +"> + + + + + + + + +<% line_num += 1 %> +<% end %> + +
    #<%= l(:field_updated_on) %><%= l(:field_author) %><%= l(:field_comments) %>
    <%= link_to h(ver.version), :action => 'show', :id => @page.title, :project_id => @page.project, :version => ver.version %><%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < @versions.size) %><%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}") if show_diff && (line_num > 1) %><%= format_time(ver.updated_on) %><%= link_to_user ver.author %><%=h ver.comments %><%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %>
    +<%= submit_tag l(:label_view_diff), :class => 'small' if show_diff %> +<%= pagination_links_full @version_pages, @version_count, :page_param => :p %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/734682732665154f00709d93da629e994804ff9b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/734682732665154f00709d93da629e994804ff9b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +require 'redmine' + +Redmine::Plugin.register :<%= plugin_name %> do + name '<%= plugin_pretty_name %> plugin' + author 'Author name' + description 'This is a plugin for Redmine' + version '0.0.1' + url 'http://example.com/path/to/plugin' + author_url 'http://example.com/about' +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/734f23aed8fb2921f077702e98029d9edca35572.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/734f23aed8fb2921f077702e98029d9edca35572.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,187 @@ +#!/usr/bin/env ruby + +# == Synopsis +# +# Reads an email from standard input and forward it to a Redmine server +# through a HTTP request. +# +# == Usage +# +# rdm-mailhandler [options] --url= --key= +# +# == Arguments +# +# -u, --url URL of the Redmine server +# -k, --key Redmine API key +# +# General options: +# --unknown-user=ACTION how to handle emails from an unknown user +# ACTION can be one of the following values: +# ignore: email is ignored (default) +# accept: accept as anonymous user +# create: create a user account +# --no-permission-check disable permission checking when receiving +# the email +# --key-file=PATH path to a file that contains the Redmine +# API key (use this option instead of --key +# if you don't the key to appear in the +# command line) +# --no-check-certificate do not check server certificate +# -h, --help show this help +# -v, --verbose show extra information +# -V, --version show version information and exit +# +# Issue attributes control options: +# -p, --project=PROJECT identifier of the target project +# -s, --status=STATUS name of the target status +# -t, --tracker=TRACKER name of the target tracker +# --category=CATEGORY name of the target category +# --priority=PRIORITY name of the target priority +# -o, --allow-override=ATTRS allow email content to override attributes +# specified by previous options +# ATTRS is a comma separated list of attributes +# +# == Examples +# No project specified. Emails MUST contain the 'Project' keyword: +# +# rdm-mailhandler --url http://redmine.domain.foo --key secret +# +# Fixed project and default tracker specified, but emails can override +# both tracker and priority attributes using keywords: +# +# rdm-mailhandler --url https://domain.foo/redmine --key secret \\ +# --project foo \\ +# --tracker bug \\ +# --allow-override tracker,priority + +require 'net/http' +require 'net/https' +require 'uri' +require 'getoptlong' +require 'rdoc/usage' + +module Net + class HTTPS < HTTP + def self.post_form(url, params, headers, options={}) + request = Post.new(url.path) + request.form_data = params + request.basic_auth url.user, url.password if url.user + request.initialize_http_header(headers) + http = new(url.host, url.port) + http.use_ssl = (url.scheme == 'https') + if options[:no_check_certificate] + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + end + http.start {|h| h.request(request) } + end + end +end + +class RedmineMailHandler + VERSION = '0.1' + + attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key, :no_check_certificate + + def initialize + self.issue_attributes = {} + + opts = GetoptLong.new( + [ '--help', '-h', GetoptLong::NO_ARGUMENT ], + [ '--version', '-V', GetoptLong::NO_ARGUMENT ], + [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], + [ '--url', '-u', GetoptLong::REQUIRED_ARGUMENT ], + [ '--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + [ '--key-file', GetoptLong::REQUIRED_ARGUMENT], + [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ], + [ '--status', '-s', GetoptLong::REQUIRED_ARGUMENT ], + [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT], + [ '--category', GetoptLong::REQUIRED_ARGUMENT], + [ '--priority', GetoptLong::REQUIRED_ARGUMENT], + [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT], + [ '--unknown-user', GetoptLong::REQUIRED_ARGUMENT], + [ '--no-permission-check', GetoptLong::NO_ARGUMENT], + [ '--no-check-certificate', GetoptLong::NO_ARGUMENT] + ) + + opts.each do |opt, arg| + case opt + when '--url' + self.url = arg.dup + when '--key' + self.key = arg.dup + when '--key-file' + begin + self.key = File.read(arg).strip + rescue Exception => e + $stderr.puts "Unable to read the key from #{arg}: #{e.message}" + exit 1 + end + when '--help' + usage + when '--verbose' + self.verbose = true + when '--version' + puts VERSION; exit + when '--project', '--status', '--tracker', '--category', '--priority' + self.issue_attributes[opt.gsub(%r{^\-\-}, '')] = arg.dup + when '--allow-override' + self.allow_override = arg.dup + when '--unknown-user' + self.unknown_user = arg.dup + when '--no-permission-check' + self.no_permission_check = '1' + when '--no-check-certificate' + self.no_check_certificate = true + end + end + + RDoc.usage if url.nil? + end + + def submit(email) + uri = url.gsub(%r{/*$}, '') + '/mail_handler' + + headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" } + + data = { 'key' => key, 'email' => email, + 'allow_override' => allow_override, + 'unknown_user' => unknown_user, + 'no_permission_check' => no_permission_check} + issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value } + + debug "Posting to #{uri}..." + response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate) + debug "Response received: #{response.code}" + + case response.code.to_i + when 403 + warn "Request was denied by your Redmine server. " + + "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key." + return 77 + when 422 + warn "Request was denied by your Redmine server. " + + "Possible reasons: email is sent from an invalid email address or is missing some information." + return 77 + when 400..499 + warn "Request was denied by your Redmine server (#{response.code})." + return 77 + when 500..599 + warn "Failed to contact your Redmine server (#{response.code})." + return 75 + when 201 + debug "Proccessed successfully" + return 0 + else + return 1 + end + end + + private + + def debug(msg) + puts msg if verbose + end +end + +handler = RedmineMailHandler.new +exit(handler.submit(STDIN.read)) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/736844820e97591097b5dc584954a779de2b5787.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/736844820e97591097b5dc584954a779de2b5787.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,283 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class AccountController < ApplicationController + helper :custom_fields + include CustomFieldsHelper + + # prevents login action to be filtered by check_if_login_required application scope filter + skip_before_filter :check_if_login_required + + # Login request and validation + def login + if request.get? + logout_user + else + authenticate_user + end + end + + # Log out current user and redirect to welcome page + def logout + logout_user + redirect_to home_url + end + + # Enable user to choose a new password + def lost_password + redirect_to(home_url) && return unless Setting.lost_password? + if params[:token] + @token = Token.find_by_action_and_value("recovery", params[:token]) + redirect_to(home_url) && return unless @token and !@token.expired? + @user = @token.user + if request.post? + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if @user.save + @token.destroy + flash[:notice] = l(:notice_account_password_updated) + redirect_to :action => 'login' + return + end + end + render :template => "account/password_recovery" + return + else + if request.post? + user = User.find_by_mail(params[:mail]) + # user not found in db + (flash.now[:error] = l(:notice_account_unknown_email); return) unless user + # user uses an external authentification + (flash.now[:error] = l(:notice_can_t_change_password); return) if user.auth_source_id + # create a new token for password recovery + token = Token.new(:user => user, :action => "recovery") + if token.save + Mailer.deliver_lost_password(token) + flash[:notice] = l(:notice_account_lost_email_sent) + redirect_to :action => 'login' + return + end + end + end + end + + # User self-registration + def register + redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration] + if request.get? + session[:auth_source_registration] = nil + @user = User.new(:language => Setting.default_language) + else + @user = User.new(params[:user]) + @user.admin = false + @user.register + if session[:auth_source_registration] + @user.activate + @user.login = session[:auth_source_registration][:login] + @user.auth_source_id = session[:auth_source_registration][:auth_source_id] + if @user.save + session[:auth_source_registration] = nil + self.logged_user = @user + flash[:notice] = l(:notice_account_activated) + redirect_to :controller => 'my', :action => 'account' + end + else + @user.login = params[:user][:login] + @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] + + case Setting.self_registration + when '1' + register_by_email_activation(@user) + when '3' + register_automatically(@user) + else + register_manually_by_administrator(@user) + end + end + end + end + + # Token based account activation + def activate + redirect_to(home_url) && return unless Setting.self_registration? && params[:token] + token = Token.find_by_action_and_value('register', params[:token]) + redirect_to(home_url) && return unless token and !token.expired? + user = token.user + redirect_to(home_url) && return unless user.registered? + user.activate + if user.save + token.destroy + flash[:notice] = l(:notice_account_activated) + end + redirect_to :action => 'login' + end + + private + + def logout_user + if User.current.logged? + cookies.delete :autologin + Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) + self.logged_user = nil + end + end + + def authenticate_user + if Setting.openid? && using_open_id? + open_id_authenticate(params[:openid_url]) + else + password_authentication + end + end + + def password_authentication + user = User.try_to_login(params[:username], params[:password]) + + if user.nil? + invalid_credentials + elsif user.new_record? + onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id }) + else + # Valid user + successful_authentication(user) + end + end + + def open_id_authenticate(openid_url) + authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration| + if result.successful? + user = User.find_or_initialize_by_identity_url(identity_url) + if user.new_record? + # Self-registration off + redirect_to(home_url) && return unless Setting.self_registration? + + # Create on the fly + user.login = registration['nickname'] unless registration['nickname'].nil? + user.mail = registration['email'] unless registration['email'].nil? + user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil? + user.random_password + user.register + + case Setting.self_registration + when '1' + register_by_email_activation(user) do + onthefly_creation_failed(user) + end + when '3' + register_automatically(user) do + onthefly_creation_failed(user) + end + else + register_manually_by_administrator(user) do + onthefly_creation_failed(user) + end + end + else + # Existing record + if user.active? + successful_authentication(user) + else + account_pending + end + end + end + end + end + + def successful_authentication(user) + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + if params[:autologin] && Setting.autologin? + set_autologin_cookie(user) + end + call_hook(:controller_account_success_authentication_after, {:user => user }) + redirect_back_or_default :controller => 'my', :action => 'page' + end + + def set_autologin_cookie(user) + token = Token.create(:user => user, :action => 'autologin') + cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin' + cookie_options = { + :value => token.value, + :expires => 1.year.from_now, + :path => (Redmine::Configuration['autologin_cookie_path'] || '/'), + :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false), + :httponly => true + } + cookies[cookie_name] = cookie_options + end + + # Onthefly creation failed, display the registration form to fill/fix attributes + def onthefly_creation_failed(user, auth_source_options = { }) + @user = user + session[:auth_source_registration] = auth_source_options unless auth_source_options.empty? + render :action => 'register' + end + + def invalid_credentials + logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}" + flash.now[:error] = l(:notice_account_invalid_creditentials) + end + + # Register a user for email activation. + # + # Pass a block for behavior when a user fails to save + def register_by_email_activation(user, &block) + token = Token.new(:user => user, :action => "register") + if user.save and token.save + Mailer.deliver_register(token) + flash[:notice] = l(:notice_account_register_done) + redirect_to :action => 'login' + else + yield if block_given? + end + end + + # Automatically register a user + # + # Pass a block for behavior when a user fails to save + def register_automatically(user, &block) + # Automatic activation + user.activate + user.last_login_on = Time.now + if user.save + self.logged_user = user + flash[:notice] = l(:notice_account_activated) + redirect_to :controller => 'my', :action => 'account' + else + yield if block_given? + end + end + + # Manual activation by the administrator + # + # Pass a block for behavior when a user fails to save + def register_manually_by_administrator(user, &block) + if user.save + # Sends an email to the administrators + Mailer.deliver_account_activation_request(user) + account_pending + else + yield if block_given? + end + end + + def account_pending + flash[:notice] = l(:notice_account_pending) + redirect_to :action => 'login' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/73e52478bb2597f7b86c76202bd5dc8da0894ff1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/73e52478bb2597f7b86c76202bd5dc8da0894ff1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +begin + require 'metric_fu' +rescue LoadError + # Metric-fu not installed + # http://metric-fu.rubyforge.org/ +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/73/73f54ba2c494fc625d52c6218a1293d90db7ca39.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/73/73f54ba2c494fc625d52c6218a1293d90db7ca39.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' +require 'rake/gempackagetask' +require 'rcov/rcovtask' +require "load_multi_rails_rake_tasks" + +spec = eval(File.read("#{File.dirname(__FILE__)}/awesome_nested_set.gemspec")) +PKG_NAME = spec.name +PKG_VERSION = spec.version + +Rake::GemPackageTask.new(spec) do |pkg| + pkg.need_zip = true + pkg.need_tar = true +end + + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the awesome_nested_set plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the awesome_nested_set plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'AwesomeNestedSet' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +namespace :test do + desc "just rcov minus html output" + Rcov::RcovTask.new(:coverage) do |t| + # t.libs << 'test' + t.test_files = FileList['test/**/*_test.rb'] + t.output_dir = 'coverage' + t.verbose = true + t.rcov_opts = %w(--exclude test,/usr/lib/ruby,/Library/Ruby,lib/awesome_nested_set/named_scope.rb --sort coverage) + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/7404304328de19a679b0fab3d9a0a81e75864fb9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/7404304328de19a679b0fab3d9a0a81e75864fb9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%= l(:text_say_hello) %>

    + +

    : <%= @value %>

    + +<%= link_to_if_authorized 'Good bye', :action => 'say_goodbye', :id => @project %> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag "example.css", :plugin => "sample_plugin", :media => "screen" %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/743a4dc7b2a0298d7100e21b5ae7b16566c99a77.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/743a4dc7b2a0298d7100e21b5ae7b16566c99a77.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,93 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class WatchersController < ApplicationController + before_filter :find_project + before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch] + before_filter :authorize, :only => [:new, :destroy] + + verify :method => :post, + :only => [ :watch, :unwatch ], + :render => { :nothing => true, :status => :method_not_allowed } + + def watch + if @watched.respond_to?(:visible?) && !@watched.visible?(User.current) + render_403 + else + set_watcher(User.current, true) + end + end + + def unwatch + set_watcher(User.current, false) + end + + def new + @watcher = Watcher.new(params[:watcher]) + @watcher.watchable = @watched + @watcher.save if request.post? + respond_to do |format| + format.html { redirect_to :back } + format.js do + render :update do |page| + page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} + end + end + end + rescue ::ActionController::RedirectBackError + render :text => 'Watcher added.', :layout => true + end + + def destroy + @watched.set_watcher(User.find(params[:user_id]), false) if request.post? + respond_to do |format| + format.html { redirect_to :back } + format.js do + render :update do |page| + page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} + end + end + end + end + +private + def find_project + klass = Object.const_get(params[:object_type].camelcase) + return false unless klass.respond_to?('watched_by') + @watched = klass.find(params[:object_id]) + @project = @watched.project + rescue + render_404 + end + + def set_watcher(user, watching) + @watched.set_watcher(user, watching) + respond_to do |format| + format.html { redirect_to :back } + format.js do + render(:update) do |page| + c = watcher_css(@watched) + page.select(".#{c}").each do |item| + page.replace_html item, watcher_link(@watched, user) + end + end + end + end + rescue ::ActionController::RedirectBackError + render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/7454b0c86e4f8493693e8238d3d4dafc54d562c2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/7454b0c86e4f8493693e8238d3d4dafc54d562c2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,64 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class CustomFieldsController < ApplicationController + layout 'admin' + + before_filter :require_admin + + def index + @custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name } + @tab = params[:tab] || 'IssueCustomField' + end + + def new + @custom_field = begin + if params[:type].to_s.match(/.+CustomField$/) + params[:type].to_s.constantize.new(params[:custom_field]) + end + rescue + end + (redirect_to(:action => 'index'); return) unless @custom_field.is_a?(CustomField) + + if request.post? and @custom_field.save + flash[:notice] = l(:notice_successful_create) + call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field) + redirect_to :action => 'index', :tab => @custom_field.class.name + else + @trackers = Tracker.find(:all, :order => 'position') + end + end + + def edit + @custom_field = CustomField.find(params[:id]) + if request.post? and @custom_field.update_attributes(params[:custom_field]) + flash[:notice] = l(:notice_successful_update) + call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field) + redirect_to :action => 'index', :tab => @custom_field.class.name + else + @trackers = Tracker.find(:all, :order => 'position') + end + end + + def destroy + @custom_field = CustomField.find(params[:id]).destroy + redirect_to :action => 'index', :tab => @custom_field.class.name + rescue + flash[:error] = l(:error_can_not_delete_custom_field) + redirect_to :action => 'index' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/74646d64b0858dd62aa32241e9f5deb66f244cbc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/74646d64b0858dd62aa32241e9f5deb66f244cbc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,75 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'blankslate' + +module Redmine + module Views + module Builders + class Structure < BlankSlate + def initialize + @struct = [{}] + end + + def array(tag, options={}, &block) + @struct << [] + block.call(self) + ret = @struct.pop + @struct.last[tag] = ret + @struct.last.merge!(options) if options + end + + def method_missing(sym, *args, &block) + if args.any? + if args.first.is_a?(Hash) + if @struct.last.is_a?(Array) + @struct.last << args.first unless block + else + @struct.last[sym] = args.first + end + else + if @struct.last.is_a?(Array) + @struct.last << (args.last || {}).merge(:value => args.first) + else + @struct.last[sym] = args.first + end + end + end + + if block + @struct << (args.first.is_a?(Hash) ? args.first : {}) + block.call(self) + ret = @struct.pop + if @struct.last.is_a?(Array) + @struct.last << ret + else + if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash) + @struct.last[sym].merge! ret + else + @struct.last[sym] = ret + end + end + end + end + + def output + raise "Need to implement #{self.class.name}#output" + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/746eb676a490baf5ce191dc6543fabe7fb71d84c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/746eb676a490baf5ce191dc6543fabe7fb71d84c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +module CodeRay +module Styles + + default :alpha + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/74927641bda7cc1a1c55b33c1e6f45877ecad9ca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/74927641bda7cc1a1c55b33c1e6f45877ecad9ca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,249 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/74baa228a6f41066c0dc33db778cdbb9594cc8b8.svn-base Binary file .svn/pristine/74/74baa228a6f41066c0dc33db778cdbb9594cc8b8.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/74c381bd74bb7f13d9d8695257e06bccd688238e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/74c381bd74bb7f13d9d8695257e06bccd688238e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +Signup template from application + +Here's a local variable set in the Mail object: <%= @name %>. + +And here's a method called in a mail helper: <%= do_something_helpful(@name) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/74d409eb3149fafa8ec75695ed8465917a65f086.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/74d409eb3149fafa8ec75695ed8465917a65f086.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddUsersSalt < ActiveRecord::Migration + def self.up + add_column :users, :salt, :string, :limit => 64 + end + + def self.down + remove_column :users, :salt + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/74/74d9194a2436a04f76d12b3254f21b2676662dd5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/74/74d9194a2436a04f76d12b3254f21b2676662dd5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +class BuildProjectsTree < ActiveRecord::Migration + def self.up + Project.rebuild! + end + + def self.down + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/7537e9eba2daabb99d2e6fee47a3f35857d9e159.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/7537e9eba2daabb99d2e6fee47a3f35857d9e159.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ArbitraryCodeMixingTest < Test::Unit::TestCase + def setup + Engines.code_mixing_file_types = %w(controller helper) + end + + def test_should_allow_setting_of_different_code_mixing_file_types + assert_nothing_raised { + Engines.mix_code_from :things + } + end + + def test_should_add_new_types_to_existing_code_mixing_file_types + Engines.mix_code_from :things + assert_equal ["controller", "helper", "thing"], Engines.code_mixing_file_types + Engines.mix_code_from :other + assert_equal ["controller", "helper", "thing", "other"], Engines.code_mixing_file_types + end + + def test_should_allow_setting_of_multiple_types_at_once + Engines.mix_code_from :things, :other + assert_equal ["controller", "helper", "thing", "other"], Engines.code_mixing_file_types + end + + def test_should_singularize_elements_to_be_mixed + # this is the only test using mocha, so let's try to work around it + # also, this seems to be already tested with the :things in the tests above + # arg = stub(:to_s => stub(:singularize => "element")) + Engines.mix_code_from :elements + assert Engines.code_mixing_file_types.include?("element") + end + + # TODO doesn't seem to work as expected? + + # def test_should_successfully_mix_custom_types + # Engines.mix_code_from :things + # assert_equal 'Thing (from app)', Thing.from_app + # assert_equal 'Thing (from test_code_mixing)', Thing.from_plugin + # end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/75522763ba10b170086f16465ddd780d56d8e212.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/75522763ba10b170086f16465ddd780d56d8e212.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class CreateWatchers < ActiveRecord::Migration + def self.up + create_table :watchers do |t| + t.column :watchable_type, :string, :default => "", :null => false + t.column :watchable_id, :integer, :default => 0, :null => false + t.column :user_id, :integer + end + end + + def self.down + drop_table :watchers + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/7564d8cc7d8f96cea467c64ec9f7ec7cf4ca759a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/7564d8cc7d8f96cea467c64ec9f7ec7cf4ca759a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssuePriority < Enumeration + has_many :issues, :foreign_key => 'priority_id' + + OptionName = :enumeration_issue_priorities + + def option_name + OptionName + end + + def objects_count + issues.count + end + + def transfer_relations(to) + issues.update_all("priority_id = #{to.id}") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/7564dff632a56de9feef3194aae6511189c0892c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/7564dff632a56de9feef3194aae6511189c0892c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +<%= error_messages_for 'relation' %> + +

    <%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %> +<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 10 %> +

    +<%= javascript_tag "observeRelatedIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> + +<%= submit_tag l(:button_add) %> +<%= toggle_link l(:button_cancel), 'new-relation-form'%> +

    + +<%= javascript_tag "setPredecessorFieldsVisibility();" %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/758168095787922f1105d8ff3607e6e9b11dacbf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/758168095787922f1105d8ff3607e6e9b11dacbf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0105 aogonek +!A3 U+0141 Lslash +!A4 U+20AC Euro +!A5 U+201E quotedblbase +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+0218 Scommaaccent +!AB U+00AB guillemotleft +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017A zacute +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+010C Ccaron +!B3 U+0142 lslash +!B4 U+017D Zcaron +!B5 U+201D quotedblright +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+010D ccaron +!BA U+0219 scommaaccent +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+017C zdotaccent +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0106 Cacute +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+015A Sacute +!D8 U+0170 Uhungarumlaut +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0118 Eogonek +!DE U+021A Tcommaaccent +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+0107 cacute +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+015B sacute +!F8 U+0171 uhungarumlaut +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0119 eogonek +!FE U+021B tcommaaccent +!FF U+00FF ydieresis diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/7582ac57d0446c5241d409e5e3670c3e4ce6c265.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/7582ac57d0446c5241d409e5e3670c3e4ce6c265.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1020 @@ +# Galician (Spain) for Ruby on Rails +# by Marcos Arias Pena (markus@agil-e.com) + +gl: + number: + format: + separator: "," + delimiter: "." + precision: 3 + + currency: + format: + format: "%n %u" + unit: "€" + separator: "," + delimiter: "." + precision: 2 + + percentage: + format: + # separator: + delimiter: "" + # precision: + + precision: + format: + # separator: + delimiter: "" + # precision: + + human: + format: + # separator: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + + direction: ltr + date: + formats: + default: "%e/%m/%Y" + short: "%e %b" + long: "%A %e de %B de %Y" + day_names: [Domingo, Luns, Martes, Mércores, Xoves, Venres, Sábado] + abbr_day_names: [Dom, Lun, Mar, Mer, Xov, Ven, Sab] + month_names: [~, Xaneiro, Febreiro, Marzo, Abril, Maio, Xunio, Xullo, Agosto, Setembro, Outubro, Novembro, Decembro] + abbr_month_names: [~, Xan, Feb, Maz, Abr, Mai, Xun, Xul, Ago, Set, Out, Nov, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %e de %B de %Y, %H:%M hs" + time: "%H:%M hs" + short: "%e/%m, %H:%M hs" + long: "%A %e de %B de %Y ás %H:%M horas" + + am: '' + pm: '' + + datetime: + distance_in_words: + half_a_minute: 'medio minuto' + less_than_x_seconds: + zero: 'menos dun segundo' + one: '1 segundo' + few: 'poucos segundos' + other: '%{count} segundos' + x_seconds: + one: '1 segundo' + other: '%{count} segundos' + less_than_x_minutes: + zero: 'menos dun minuto' + one: '1 minuto' + other: '%{count} minutos' + x_minutes: + one: '1 minuto' + other: '%{count} minuto' + about_x_hours: + one: 'aproximadamente unha hora' + other: '%{count} horas' + x_days: + one: '1 día' + other: '%{count} días' + x_weeks: + one: '1 semana' + other: '%{count} semanas' + about_x_months: + one: 'aproximadamente 1 mes' + other: '%{count} meses' + x_months: + one: '1 mes' + other: '%{count} meses' + about_x_years: + one: 'aproximadamente 1 ano' + other: '%{count} anos' + over_x_years: + one: 'máis dun ano' + other: '%{count} anos' + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + now: 'agora' + today: 'hoxe' + tomorrow: 'mañá' + in: 'dentro de' + + support: + array: + sentence_connector: e + + activerecord: + models: + attributes: + errors: + template: + header: + one: "1 erro evitou que se poidese gardar o %{model}" + other: "%{count} erros evitaron que se poidese gardar o %{model}" + body: "Atopáronse os seguintes problemas:" + messages: + inclusion: "non está incluido na lista" + exclusion: "xa existe" + invalid: "non é válido" + confirmation: "non coincide coa confirmación" + accepted: "debe ser aceptado" + empty: "non pode estar valeiro" + blank: "non pode estar en blanco" + too_long: "é demasiado longo (non máis de %{count} carácteres)" + too_short: "é demasiado curto (non menos de %{count} carácteres)" + wrong_length: "non ten a lonxitude correcta (debe ser de %{count} carácteres)" + taken: "non está dispoñible" + not_a_number: "non é un número" + greater_than: "debe ser maior que %{count}" + greater_than_or_equal_to: "debe ser maior ou igual que %{count}" + equal_to: "debe ser igual a %{count}" + less_than: "debe ser menor que %{count}" + less_than_or_equal_to: "debe ser menor ou igual que %{count}" + odd: "debe ser par" + even: "debe ser impar" + greater_than_start_date: "debe ser posterior á data de comezo" + not_same_project: "non pertence ao mesmo proxecto" + circular_dependency: "Esta relación podería crear unha dependencia circular" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Por favor seleccione + + button_activate: Activar + button_add: Engadir + button_annotate: Anotar + button_apply: Aceptar + button_archive: Arquivar + button_back: Atrás + button_cancel: Cancelar + button_change: Cambiar + button_change_password: Cambiar contrasinal + button_check_all: Seleccionar todo + button_clear: Anular + button_configure: Configurar + button_copy: Copiar + button_create: Crear + button_delete: Borrar + button_download: Descargar + button_edit: Modificar + button_list: Listar + button_lock: Bloquear + button_log_time: Tempo dedicado + button_login: Conexión + button_move: Mover + button_quote: Citar + button_rename: Renomear + button_reply: Respostar + button_reset: Restablecer + button_rollback: Volver a esta versión + button_save: Gardar + button_sort: Ordenar + button_submit: Aceptar + button_test: Probar + button_unarchive: Desarquivar + button_uncheck_all: Non seleccionar nada + button_unlock: Desbloquear + button_unwatch: Non monitorizar + button_update: Actualizar + button_view: Ver + button_watch: Monitorizar + default_activity_design: Deseño + default_activity_development: Desenvolvemento + default_doc_category_tech: Documentación técnica + default_doc_category_user: Documentación de usuario + default_issue_status_in_progress: In Progress + default_issue_status_closed: Pechada + default_issue_status_feedback: Comentarios + default_issue_status_new: Nova + default_issue_status_rejected: Rexeitada + default_issue_status_resolved: Resolta + default_priority_high: Alta + default_priority_immediate: Inmediata + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_urgent: Urxente + default_role_developer: Desenvolvedor + default_role_manager: Xefe de proxecto + default_role_reporter: Informador + default_tracker_bug: Erros + default_tracker_feature: Tarefas + default_tracker_support: Soporte + enumeration_activities: Actividades (tempo dedicado) + enumeration_doc_categories: Categorías do documento + enumeration_issue_priorities: Prioridade das peticións + error_can_t_load_default_data: "Non se puido cargar a configuración por defecto: %{value}" + error_issue_not_found_in_project: 'A petición non se atopa ou non está asociada a este proxecto' + error_scm_annotate: "Non existe a entrada ou non se puido anotar" + error_scm_command_failed: "Aconteceu un erro ao acceder ó repositorio: %{value}" + error_scm_not_found: "A entrada e/ou revisión non existe no repositorio." + field_account: Conta + field_activity: Actividade + field_admin: Administrador + field_assignable: Pódense asignar peticións a este perfil + field_assigned_to: Asignado a + field_attr_firstname: Atributo do nome + field_attr_lastname: Atributo do apelido + field_attr_login: Atributo do identificador + field_attr_mail: Atributo do Email + field_auth_source: Modo de identificación + field_author: Autor + field_base_dn: DN base + field_category: Categoría + field_column_names: Columnas + field_comments: Comentario + field_comments_sorting: Mostrar comentarios + field_created_on: Creado + field_default_value: Estado por defecto + field_delay: Retraso + field_description: Descrición + field_done_ratio: "% Realizado" + field_downloads: Descargas + field_due_date: Data fin + field_effective_date: Data + field_estimated_hours: Tempo estimado + field_field_format: Formato + field_filename: Arquivo + field_filesize: Tamaño + field_firstname: Nome + field_fixed_version: Versión prevista + field_hide_mail: Ocultar a miña dirección de correo + field_homepage: Sitio web + field_host: Anfitrión + field_hours: Horas + field_identifier: Identificador + field_is_closed: Petición resolta + field_is_default: Estado por defecto + field_is_filter: Usado como filtro + field_is_for_all: Para todos os proxectos + field_is_in_roadmap: Consultar as peticións na planificación + field_is_public: Público + field_is_required: Obrigatorio + field_issue: Petición + field_issue_to: Petición relacionada + field_language: Idioma + field_last_login_on: Última conexión + field_lastname: Apelido + field_login: Identificador + field_mail: Correo electrónico + field_mail_notification: Notificacións por correo + field_max_length: Lonxitude máxima + field_min_length: Lonxitude mínima + field_name: Nome + field_new_password: Novo contrasinal + field_notes: Notas + field_onthefly: Creación do usuario "ao voo" + field_parent: Proxecto pai + field_parent_title: Páxina pai + field_password: Contrasinal + field_password_confirmation: Confirmación + field_port: Porto + field_possible_values: Valores posibles + field_priority: Prioridade + field_project: Proxecto + field_redirect_existing_links: Redireccionar enlaces existentes + field_regexp: Expresión regular + field_role: Perfil + field_searchable: Incluír nas búsquedas + field_spent_on: Data + field_start_date: Data de inicio + field_start_page: Páxina principal + field_status: Estado + field_subject: Tema + field_subproject: Proxecto secundario + field_summary: Resumo + field_time_zone: Zona horaria + field_title: Título + field_tracker: Tipo + field_type: Tipo + field_updated_on: Actualizado + field_url: URL + field_user: Usuario + field_value: Valor + field_version: Versión + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Galego' + general_pdf_encoding: UTF-8 + general_text_No: 'Non' + general_text_Yes: 'Si' + general_text_no: 'non' + general_text_yes: 'si' + gui_validation_error: 1 erro + gui_validation_error_plural: "%{count} erros" + label_activity: Actividade + label_add_another_file: Engadir outro arquivo + label_add_note: Engadir unha nota + label_added: engadido + label_added_time_by: "Engadido por %{author} fai %{age}" + label_administration: Administración + label_age: Idade + label_ago: fai + label_all: todos + label_all_time: todo o tempo + label_all_words: Tódalas palabras + label_and_its_subprojects: "%{value} e proxectos secundarios" + label_applied_status: Aplicar estado + label_assigned_to_me_issues: Peticións asignadas a min + label_associated_revisions: Revisións asociadas + label_attachment: Arquivo + label_attachment_delete: Borrar o arquivo + label_attachment_new: Novo arquivo + label_attachment_plural: Arquivos + label_attribute: Atributo + label_attribute_plural: Atributos + label_auth_source: Modo de autenticación + label_auth_source_new: Novo modo de autenticación + label_auth_source_plural: Modos de autenticación + label_authentication: Autenticación + label_blocked_by: bloqueado por + label_blocks: bloquea a + label_board: Foro + label_board_new: Novo foro + label_board_plural: Foros + label_boolean: Booleano + label_browse: Ollar + label_bulk_edit_selected_issues: Editar as peticións seleccionadas + label_calendar: Calendario + label_change_plural: Cambios + label_change_properties: Cambiar propiedades + label_change_status: Cambiar o estado + label_change_view_all: Ver tódolos cambios + label_changes_details: Detalles de tódolos cambios + label_changeset_plural: Cambios + label_chronological_order: En orde cronolóxica + label_closed_issues: pechada + label_closed_issues_plural: pechadas + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_comment: Comentario + label_comment_add: Engadir un comentario + label_comment_added: Comentario engadido + label_comment_delete: Borrar comentarios + label_comment_plural: Comentarios + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_commits_per_author: Commits por autor + label_commits_per_month: Commits por mes + label_confirmation: Confirmación + label_contains: conten + label_copied: copiado + label_copy_workflow_from: Copiar fluxo de traballo dende + label_current_status: Estado actual + label_current_version: Versión actual + label_custom_field: Campo personalizado + label_custom_field_new: Novo campo personalizado + label_custom_field_plural: Campos personalizados + label_date: Data + label_date_from: Dende + label_date_range: Rango de datas + label_date_to: Ata + label_day_plural: días + label_default: Por defecto + label_default_columns: Columnas por defecto + label_deleted: suprimido + label_details: Detalles + label_diff_inline: en liña + label_diff_side_by_side: cara a cara + label_disabled: deshabilitado + label_display_per_page: "Por páxina: %{value}" + label_document: Documento + label_document_added: Documento engadido + label_document_new: Novo documento + label_document_plural: Documentos + label_download: "%{count} Descarga" + label_download_plural: "%{count} Descargas" + label_downloads_abbr: D/L + label_duplicated_by: duplicada por + label_duplicates: duplicada de + label_end_to_end: fin a fin + label_end_to_start: fin a principio + label_enumeration_new: Novo valor + label_enumerations: Listas de valores + label_environment: Entorno + label_equals: igual + label_example: Exemplo + label_export_to: 'Exportar a:' + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_feed_plural: Feeds + label_feeds_access_key_created_on: "Clave de acceso por RSS creada fai %{value}" + label_file_added: Arquivo engadido + label_file_plural: Arquivos + label_filter_add: Engadir o filtro + label_filter_plural: Filtros + label_float: Flotante + label_follows: posterior a + label_gantt: Gantt + label_general: Xeral + label_generate_key: Xerar clave + label_help: Axuda + label_history: Histórico + label_home: Inicio + label_in: en + label_in_less_than: en menos que + label_in_more_than: en mais que + label_incoming_emails: Correos entrantes + label_index_by_date: Índice por data + label_index_by_title: Índice por título + label_information: Información + label_information_plural: Información + label_integer: Número + label_internal: Interno + label_issue: Petición + label_issue_added: Petición engadida + label_issue_category: Categoría das peticións + label_issue_category_new: Nova categoría + label_issue_category_plural: Categorías das peticións + label_issue_new: Nova petición + label_issue_plural: Peticións + label_issue_status: Estado da petición + label_issue_status_new: Novo estado + label_issue_status_plural: Estados das peticións + label_issue_tracking: Peticións + label_issue_updated: Petición actualizada + label_issue_view_all: Ver tódalas peticións + label_issue_watchers: Seguidores + label_issues_by: "Peticións por %{value}" + label_jump_to_a_project: Ir ao proxecto... + label_language_based: Baseado no idioma + label_last_changes: "últimos %{count} cambios" + label_last_login: Última conexión + label_last_month: último mes + label_last_n_days: "últimos %{count} días" + label_last_week: última semana + label_latest_revision: Última revisión + label_latest_revision_plural: Últimas revisións + label_ldap_authentication: Autenticación LDAP + label_less_than_ago: fai menos de + label_list: Lista + label_loading: Cargando... + label_logged_as: Conectado como + label_login: Conexión + label_logout: Desconexión + label_max_size: Tamaño máximo + label_me: eu mesmo + label_member: Membro + label_member_new: Novo membro + label_member_plural: Membros + label_message_last: Última mensaxe + label_message_new: Nova mensaxe + label_message_plural: Mensaxes + label_message_posted: Mensaxe engadida + label_min_max_length: Lonxitude mín - máx + label_modification: "%{count} modificación" + label_modification_plural: "%{count} modificacións" + label_modified: modificado + label_module_plural: Módulos + label_month: Mes + label_months_from: meses de + label_more: Mais + label_more_than_ago: fai mais de + label_my_account: A miña conta + label_my_page: A miña páxina + label_my_projects: Os meus proxectos + label_new: Novo + label_new_statuses_allowed: Novos estados autorizados + label_news: Noticia + label_news_added: Noticia engadida + label_news_latest: Últimas noticias + label_news_new: Nova noticia + label_news_plural: Noticias + label_news_view_all: Ver tódalas noticias + label_next: Seguinte + label_no_change_option: (Sen cambios) + label_no_data: Ningún dato a mostrar + label_nobody: ninguén + label_none: ningún + label_not_contains: non conten + label_not_equals: non igual + label_open_issues: aberta + label_open_issues_plural: abertas + label_optional_description: Descrición opcional + label_options: Opcións + label_overall_activity: Actividade global + label_overview: Vistazo + label_password_lost: ¿Esqueciches o contrasinal? + label_per_page: Por páxina + label_permissions: Permisos + label_permissions_report: Informe de permisos + label_personalize_page: Personalizar esta páxina + label_planning: Planificación + label_please_login: Conexión + label_plugins: Extensións + label_precedes: anterior a + label_preferences: Preferencias + label_preview: Previsualizar + label_previous: Anterior + label_project: Proxecto + label_project_all: Tódolos proxectos + label_project_latest: Últimos proxectos + label_project_new: Novo proxecto + label_project_plural: Proxectos + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_public_projects: Proxectos públicos + label_query: Consulta personalizada + label_query_new: Nova consulta + label_query_plural: Consultas personalizadas + label_read: Ler... + label_register: Rexistrar + label_registered_on: Inscrito o + label_registration_activation_by_email: activación de conta por correo + label_registration_automatic_activation: activación automática de conta + label_registration_manual_activation: activación manual de conta + label_related_issues: Peticións relacionadas + label_relates_to: relacionada con + label_relation_delete: Eliminar relación + label_relation_new: Nova relación + label_renamed: renomeado + label_reply_plural: Respostas + label_report: Informe + label_report_plural: Informes + label_reported_issues: Peticións rexistradas por min + label_repository: Repositorio + label_repository_plural: Repositorios + label_result_plural: Resultados + label_reverse_chronological_order: En orde cronolóxica inversa + label_revision: Revisión + label_revision_plural: Revisións + label_roadmap: Planificación + label_roadmap_due_in: "Remata en %{value}" + label_roadmap_no_issues: Non hai peticións para esta versión + label_roadmap_overdue: "%{value} tarde" + label_role: Perfil + label_role_and_permissions: Perfiles e permisos + label_role_new: Novo perfil + label_role_plural: Perfiles + label_scm: SCM + label_search: Búsqueda + label_search_titles_only: Buscar só en títulos + label_send_information: Enviar información da conta ó usuario + label_send_test_email: Enviar un correo de proba + label_settings: Configuración + label_show_completed_versions: Mostra as versións rematadas + label_sort_by: "Ordenar por %{value}" + label_sort_higher: Subir + label_sort_highest: Primeiro + label_sort_lower: Baixar + label_sort_lowest: Último + label_spent_time: Tempo dedicado + label_start_to_end: comezo a fin + label_start_to_start: comezo a comezo + label_statistics: Estatísticas + label_stay_logged_in: Lembrar contrasinal + label_string: Texto + label_subproject_plural: Proxectos secundarios + label_text: Texto largo + label_theme: Tema + label_this_month: este mes + label_this_week: esta semana + label_this_year: este ano + label_time_tracking: Control de tempo + label_today: hoxe + label_topic_plural: Temas + label_total: Total + label_tracker: Tipo + label_tracker_new: Novo tipo + label_tracker_plural: Tipos de peticións + label_updated_time: "Actualizado fai %{value}" + label_updated_time_by: "Actualizado por %{author} fai %{age}" + label_used_by: Utilizado por + label_user: Usuario + label_user_activity: "Actividade de %{value}" + label_user_mail_no_self_notified: "Non quero ser avisado de cambios feitos por min" + label_user_mail_option_all: "Para calquera evento en tódolos proxectos" + label_user_mail_option_selected: "Para calquera evento dos proxectos seleccionados..." + label_user_new: Novo usuario + label_user_plural: Usuarios + label_version: Versión + label_version_new: Nova versión + label_version_plural: Versións + label_view_diff: Ver diferencias + label_view_revisions: Ver as revisións + label_watched_issues: Peticións monitorizadas + label_week: Semana + label_wiki: Wiki + label_wiki_edit: Wiki edición + label_wiki_edit_plural: Wiki edicións + label_wiki_page: Wiki páxina + label_wiki_page_plural: Wiki páxinas + label_workflow: Fluxo de traballo + label_year: Ano + label_yesterday: onte + mail_body_account_activation_request: "Inscribiuse un novo usuario (%{value}). A conta está pendente de aprobación:" + mail_body_account_information: Información sobre a súa conta + mail_body_account_information_external: "Pode usar a súa conta %{value} para conectarse." + mail_body_lost_password: 'Para cambiar o seu contrasinal, faga clic no seguinte enlace:' + mail_body_register: 'Para activar a súa conta, faga clic no seguinte enlace:' + mail_body_reminder: "%{count} petición(s) asignadas a ti rematan nos próximos %{days} días:" + mail_subject_account_activation_request: "Petición de activación de conta %{value}" + mail_subject_lost_password: "O teu contrasinal de %{value}" + mail_subject_register: "Activación da conta de %{value}" + mail_subject_reminder: "%{count} petición(s) rematarán nos próximos %{days} días" + notice_account_activated: A súa conta foi activada. Xa pode conectarse. + notice_account_invalid_creditentials: Usuario ou contrasinal inválido. + notice_account_lost_email_sent: Enviouse un correo con instrucións para elixir un novo contrasinal. + notice_account_password_updated: Contrasinal modificado correctamente. + notice_account_pending: "A súa conta creouse e está pendente da aprobación por parte do administrador." + notice_account_register_done: Conta creada correctamente. Para activala, faga clic sobre o enlace que se lle enviou por correo. + notice_account_unknown_email: Usuario descoñecido. + notice_account_updated: Conta actualizada correctamente. + notice_account_wrong_password: Contrasinal incorrecto. + notice_can_t_change_password: Esta conta utiliza unha fonte de autenticación externa. Non é posible cambiar o contrasinal. + notice_default_data_loaded: Configuración por defecto cargada correctamente. + notice_email_error: "Ocorreu un error enviando o correo (%{value})" + notice_email_sent: "Enviouse un correo a %{value}" + notice_failed_to_save_issues: "Imposible gravar %{count} petición(s) de %{total} seleccionada(s): %{ids}." + notice_feeds_access_key_reseted: A súa clave de acceso para RSS reiniciouse. + notice_file_not_found: A páxina á que tenta acceder non existe. + notice_locking_conflict: Os datos modificáronse por outro usuario. + notice_no_issue_selected: "Ningunha petición seleccionada. Por favor, comprobe a petición que quere modificar" + notice_not_authorized: Non ten autorización para acceder a esta páxina. + notice_successful_connection: Conexión correcta. + notice_successful_create: Creación correcta. + notice_successful_delete: Borrado correcto. + notice_successful_update: Modificación correcta. + notice_unable_delete_version: Non se pode borrar a versión + permission_add_issue_notes: Engadir notas + permission_add_issue_watchers: Engadir seguidores + permission_add_issues: Engadir peticións + permission_add_messages: Enviar mensaxes + permission_browse_repository: Ollar repositorio + permission_comment_news: Comentar noticias + permission_commit_access: Acceso de escritura + permission_delete_issues: Borrar peticións + permission_delete_messages: Borrar mensaxes + permission_delete_own_messages: Borrar mensaxes propios + permission_delete_wiki_pages: Borrar páxinas wiki + permission_delete_wiki_pages_attachments: Borrar arquivos + permission_edit_issue_notes: Modificar notas + permission_edit_issues: Modificar peticións + permission_edit_messages: Modificar mensaxes + permission_edit_own_issue_notes: Modificar notas propias + permission_edit_own_messages: Editar mensaxes propios + permission_edit_own_time_entries: Modificar tempos dedicados propios + permission_edit_project: Modificar proxecto + permission_edit_time_entries: Modificar tempos dedicados + permission_edit_wiki_pages: Modificar páxinas wiki + permission_log_time: Anotar tempo dedicado + permission_manage_boards: Administrar foros + permission_manage_categories: Administrar categorías de peticións + permission_manage_documents: Administrar documentos + permission_manage_files: Administrar arquivos + permission_manage_issue_relations: Administrar relación con outras peticións + permission_manage_members: Administrar membros + permission_manage_news: Administrar noticias + permission_manage_public_queries: Administrar consultas públicas + permission_manage_repository: Administrar repositorio + permission_manage_versions: Administrar versións + permission_manage_wiki: Administrar wiki + permission_move_issues: Mover peticións + permission_protect_wiki_pages: Protexer páxinas wiki + permission_rename_wiki_pages: Renomear páxinas wiki + permission_save_queries: Gravar consultas + permission_select_project_modules: Seleccionar módulos do proxecto + permission_view_calendar: Ver calendario + permission_view_changesets: Ver cambios + permission_view_documents: Ver documentos + permission_view_files: Ver arquivos + permission_view_gantt: Ver diagrama de Gantt + permission_view_issue_watchers: Ver lista de seguidores + permission_view_messages: Ver mensaxes + permission_view_time_entries: Ver tempo dedicado + permission_view_wiki_edits: Ver histórico do wiki + permission_view_wiki_pages: Ver wiki + project_module_boards: Foros + project_module_documents: Documentos + project_module_files: Arquivos + project_module_issue_tracking: Peticións + project_module_news: Noticias + project_module_repository: Repositorio + project_module_time_tracking: Control de tempo + project_module_wiki: Wiki + setting_activity_days_default: Días a mostrar na actividade do proxecto + setting_app_subtitle: Subtítulo da aplicación + setting_app_title: Título da aplicación + setting_attachment_max_size: Tamaño máximo do arquivo + setting_autofetch_changesets: Autorechear os commits do repositorio + setting_autologin: Conexión automática + setting_bcc_recipients: Ocultar as copias de carbón (bcc) + setting_commit_fix_keywords: Palabras clave para a corrección + setting_commit_ref_keywords: Palabras clave para a referencia + setting_cross_project_issue_relations: Permitir relacionar peticións de distintos proxectos + setting_date_format: Formato da data + setting_default_language: Idioma por defecto + setting_default_projects_public: Os proxectos novos son públicos por defecto + setting_diff_max_lines_displayed: Número máximo de diferencias mostradas + setting_display_subprojects_issues: Mostrar por defecto peticións de prox. secundarios no principal + setting_emails_footer: Pe de mensaxes + setting_enabled_scm: Activar SCM + setting_feeds_limit: Límite de contido para sindicación + setting_gravatar_enabled: Usar iconas de usuario (Gravatar) + setting_host_name: Nome e ruta do servidor + setting_issue_list_default_columns: Columnas por defecto para a lista de peticións + setting_issues_export_limit: Límite de exportación de peticións + setting_login_required: Requírese identificación + setting_mail_from: Correo dende o que enviar mensaxes + setting_mail_handler_api_enabled: Activar SW para mensaxes entrantes + setting_mail_handler_api_key: Clave da API + setting_per_page_options: Obxectos por páxina + setting_plain_text_mail: só texto plano (non HTML) + setting_protocol: Protocolo + setting_self_registration: Rexistro permitido + setting_sequential_project_identifiers: Xerar identificadores de proxecto + setting_sys_api_enabled: Habilitar SW para a xestión do repositorio + setting_text_formatting: Formato de texto + setting_time_format: Formato de hora + setting_user_format: Formato de nome de usuario + setting_welcome_text: Texto de benvida + setting_wiki_compression: Compresión do historial do Wiki + status_active: activo + status_locked: bloqueado + status_registered: rexistrado + text_are_you_sure: ¿Está seguro? + text_assign_time_entries_to_project: Asignar as horas ó proxecto + text_caracters_maximum: "%{count} caracteres como máximo." + text_caracters_minimum: "%{count} caracteres como mínimo" + text_comma_separated: Múltiples valores permitidos (separados por coma). + text_default_administrator_account_changed: Conta de administrador por defecto modificada + text_destroy_time_entries: Borrar as horas + text_destroy_time_entries_question: Existen %{hours} horas asignadas á petición que quere borrar. ¿Que quere facer ? + text_diff_truncated: '... Diferencia truncada por exceder o máximo tamaño visualizable.' + text_email_delivery_not_configured: "O envío de correos non está configurado, e as notificacións desactiváronse. \n Configure o servidor de SMTP en config/configuration.yml e reinicie a aplicación para activar os cambios." + text_enumeration_category_reassign_to: 'Reasignar ó seguinte valor:' + text_enumeration_destroy_question: "%{count} obxectos con este valor asignado." + text_file_repository_writable: Pódese escribir no repositorio + text_issue_added: "Petición %{id} engadida por %{author}." + text_issue_category_destroy_assignments: Deixar as peticións sen categoría + text_issue_category_destroy_question: "Algunhas peticións (%{count}) están asignadas a esta categoría. ¿Que desexa facer?" + text_issue_category_reassign_to: Reasignar as peticións á categoría + text_issue_updated: "A petición %{id} actualizouse por %{author}." + text_issues_destroy_confirmation: '¿Seguro que quere borrar as peticións seleccionadas?' + text_issues_ref_in_commit_messages: Referencia e petición de corrección nas mensaxes + text_length_between: "Lonxitude entre %{min} e %{max} caracteres." + text_load_default_configuration: Cargar a configuración por defecto + text_min_max_length_info: 0 para ningunha restrición + text_no_configuration_data: "Inda non se configuraron perfiles, nin tipos, estados e fluxo de traballo asociado a peticións. Recoméndase encarecidamente cargar a configuración por defecto. Unha vez cargada, poderá modificala." + text_project_destroy_confirmation: ¿Estás seguro de querer eliminar o proxecto? + text_project_identifier_info: 'Letras minúsculas (a-z), números e signos de puntuación permitidos.
    Unha vez gardado, o identificador non pode modificarse.' + text_reassign_time_entries: 'Reasignar as horas a esta petición:' + text_regexp_info: ex. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Estableza a correspondencia entre os usuarios de Redmine e os presentes no log do repositorio.\nOs usuarios co mesmo nome ou correo en Redmine e no repositorio serán asociados automaticamente." + text_rmagick_available: RMagick dispoñible (opcional) + text_select_mail_notifications: Seleccionar os eventos a notificar + text_select_project_modules: 'Seleccione os módulos a activar para este proxecto:' + text_status_changed_by_changeset: "Aplicado nos cambios %{value}" + text_subprojects_destroy_warning: "Os proxectos secundarios: %{value} tamén se eliminarán" + text_tip_issue_begin_day: tarefa que comeza este día + text_tip_issue_begin_end_day: tarefa que comeza e remata este día + text_tip_issue_end_day: tarefa que remata este día + text_tracker_no_workflow: Non hai ningún fluxo de traballo definido para este tipo de petición + text_unallowed_characters: Caracteres non permitidos + text_user_mail_option: "Dos proxectos non seleccionados, só recibirá notificacións sobre elementos monitorizados ou elementos nos que estea involucrado (por exemplo, peticións das que vostede sexa autor ou asignadas a vostede)." + text_user_wrote: "%{value} escribiu:" + text_wiki_destroy_confirmation: ¿Seguro que quere borrar o wiki e todo o seu contido? + text_workflow_edit: Seleccionar un fluxo de traballo para actualizar + warning_attachments_not_saved: "%{count} file(s) could not be saved." + field_editable: Editable + text_plugin_assets_writable: Plugin assets directory writable + label_display: Display + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Codificación das mensaxes de commit + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/75a11254d546a3b3cc5d03a006c9f8483cb3da6f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/75a11254d546a3b3cc5d03a006c9f8483cb3da6f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class AddTimelogPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "timelog", :action => "edit", :description => "button_log_time", :sort => 1520, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('timelog', 'edit').destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/75d422ff426ca18038f7b20b651c5a9f7724a3cd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/75d422ff426ca18038f7b20b651c5a9f7724a3cd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +class Widget < ActiveRecord::Base + acts_as_versioned :sequence_name => 'widgets_seq', :association_options => { + :dependent => :nullify, :order => 'version desc' + } + non_versioned_columns << 'foo' +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/75/75f107e6669aa82c7a67c545bb8556cd17f911cf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/75/75f107e6669aa82c7a67c545bb8556cd17f911cf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +desc 'Load Redmine default configuration data. Language is chosen interactively or by setting REDMINE_LANG environment variable.' + +namespace :redmine do + task :load_default_data => :environment do + include Redmine::I18n + set_language_if_valid('en') + + envlang = ENV['REDMINE_LANG'] + if !envlang || !set_language_if_valid(envlang) + puts + while true + print "Select language: " + print valid_languages.collect(&:to_s).sort.join(", ") + print " [#{current_language}] " + STDOUT.flush + lang = STDIN.gets.chomp! + break if lang.empty? + break if set_language_if_valid(lang) + puts "Unknown language!" + end + STDOUT.flush + puts "====================================" + end + + begin + Redmine::DefaultData::Loader.load(current_language) + puts "Default configuration data loaded." + rescue Redmine::DefaultData::DataAlreadyLoaded => error + puts error + rescue => error + puts "Error: " + error + puts "Default configuration data was not loaded." + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/76/76250042c24ef04826eb632546dd6627448cd0da.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/76/76250042c24ef04826eb632546dd6627448cd0da.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "About the calendar"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)"; +Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)"; +Calendar._TT["GO_TODAY"] = "Go Today"; +Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)"; +Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)"; +Calendar._TT["SEL_DATE"] = "Select date"; +Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; +Calendar._TT["PART_TODAY"] = " (today)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Close"; +Calendar._TT["TODAY"] = "Today"; +Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Time:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/76/764f20578b33c5ef0c99adc3a136111ff27ce87f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/76/764f20578b33c5ef0c99adc3a136111ff27ce87f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,65 @@ +module CodeRay +module Encoders + + class HTML + class CSS # :nodoc: + + attr :stylesheet + + def CSS.load_stylesheet style = nil + CodeRay::Styles[style] + end + + def initialize style = :default + @classes = Hash.new + style = CSS.load_stylesheet style + @stylesheet = [ + style::CSS_MAIN_STYLES, + style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ') + ].join("\n") + parse style::TOKEN_COLORS + end + + def get_style styles + cl = @classes[styles.first] + return '' unless cl + style = '' + 1.upto styles.size do |offset| + break if style = cl[styles[offset .. -1]] + end + # warn 'Style not found: %p' % [styles] if style.empty? + return style + end + + private + + CSS_CLASS_PATTERN = / + ( # $1 = selectors + (?: + (?: \s* \. [-\w]+ )+ + \s* ,? + )+ + ) + \s* \{ \s* + ( [^\}]+ )? # $2 = style + \s* \} \s* + | + ( [^\n]+ ) # $3 = error + /mx + def parse stylesheet + stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error| + raise "CSS parse error: '#{error.inspect}' not recognized" if error + for selector in selectors.split(',') + classes = selector.scan(/[-\w]+/) + cl = classes.pop + @classes[cl] ||= Hash.new + @classes[cl][classes] = style.to_s.strip.delete(' ').chomp(';') + end + end + end + + end + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/76/7653b9d7574c0a4c89892ba03eb88b9209dbb271.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/76/7653b9d7574c0a4c89892ba03eb88b9209dbb271.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,66 @@ +module CodeRay +module Scanners + + # = Debug Scanner + # + # Parses the output of the Encoders::Debug encoder. + class Raydebug < Scanner + + register_for :raydebug + file_extension 'raydebug' + title 'CodeRay Token Dump' + + protected + + def scan_tokens encoder, options + + opened_tokens = [] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif match = scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) /x) + kind = self[1] + encoder.text_token kind, :class + encoder.text_token '(', :operator + match = self[2] + encoder.text_token match, kind.to_sym + encoder.text_token match, :operator if match = scan(/\)/) + + elsif match = scan(/ (\w+) ([<\[]) /x) + kind = self[1] + case self[2] + when '<' + encoder.text_token kind, :class + when '[' + encoder.text_token kind, :class + else + raise 'CodeRay bug: This case should not be reached.' + end + kind = kind.to_sym + opened_tokens << kind + encoder.begin_group kind + encoder.text_token self[2], :operator + + elsif !opened_tokens.empty? && match = scan(/ [>\]] /x) + encoder.text_token match, :operator + encoder.end_group opened_tokens.pop + + else + encoder.text_token getch, :space + + end + + end + + encoder.end_group opened_tokens.pop until opened_tokens.empty? + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/76/765c4d02e29c8c91040d1cddac7513edae190213.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/76/765c4d02e29c8c91040d1cddac7513edae190213.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +

    <%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%=h @message.subject %>

    + +<% form_for :message, @message, :url => {:action => 'edit'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f, :replying => !@message.parent.nil?} %> + <%= submit_tag l(:button_save) %> + <%= link_to_remote l(:label_preview), + { :url => { :controller => 'messages', :action => 'preview', :board_id => @board }, + :method => 'post', + :update => 'preview', + :with => "Form.serialize('message-form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> +<% end %> +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/76/7692f8f9ec64d588c08e89635d4d3bb3b5c0c1d4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/76/7692f8f9ec64d588c08e89635d4d3bb3b5c0c1d4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +--- +projects_trackers_001: + project_id: 4 + tracker_id: 3 +projects_trackers_002: + project_id: 1 + tracker_id: 1 +projects_trackers_003: + project_id: 5 + tracker_id: 1 +projects_trackers_004: + project_id: 1 + tracker_id: 2 +projects_trackers_005: + project_id: 5 + tracker_id: 2 +projects_trackers_006: + project_id: 5 + tracker_id: 3 +projects_trackers_007: + project_id: 2 + tracker_id: 1 +projects_trackers_008: + project_id: 2 + tracker_id: 2 +projects_trackers_009: + project_id: 2 + tracker_id: 3 +projects_trackers_010: + project_id: 3 + tracker_id: 2 +projects_trackers_011: + project_id: 3 + tracker_id: 3 +projects_trackers_012: + project_id: 4 + tracker_id: 1 +projects_trackers_013: + project_id: 4 + tracker_id: 2 +projects_trackers_014: + project_id: 1 + tracker_id: 3 + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/76/76f780ec4f9b2a65e6384949c39d6005bf813ce3.svn-base Binary file .svn/pristine/76/76f780ec4f9b2a65e6384949c39d6005bf813ce3.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/77/7718e8a0efeaa5f26e8369285e5ddf3e72a45738.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/77/7718e8a0efeaa5f26e8369285e5ddf3e72a45738.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +class PluginMail < ActionMailer::Base + def mail_from_plugin(note=nil) + body(:note => note) + end + + def mail_from_plugin_with_application_template(note=nil) + body(:note => note) + end + + def multipart_from_plugin + content_type 'multipart/alternative' + part :content_type => "text/html", :body => render_message("multipart_from_plugin_html", {}) + part "text/plain" do |p| + p.body = render_message("multipart_from_plugin_plain", {}) + end + end + + def multipart_from_plugin_with_application_template + content_type 'multipart/alternative' + part :content_type => "text/html", :body => render_message("multipart_from_plugin_with_application_template_html", {}) + part "text/plain" do |p| + p.body = render_message("multipart_from_plugin_with_application_template_plain", {}) + end + end + +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/77/77535eb0610e7a795a3a338ad92c9bcb966e9ab9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/77/77535eb0610e7a795a3a338ad92c9bcb966e9ab9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class MemberRole < ActiveRecord::Base + belongs_to :member + belongs_to :role + + after_destroy :remove_member_if_empty + + after_create :add_role_to_group_users + after_destroy :remove_role_from_group_users + + validates_presence_of :role + + def validate + errors.add :role_id, :invalid if role && !role.member? + end + + def inherited? + !inherited_from.nil? + end + + private + + def remove_member_if_empty + if member.roles.empty? + member.destroy + end + end + + def add_role_to_group_users + if member.principal.is_a?(Group) + member.principal.users.each do |user| + user_member = Member.find_by_project_id_and_user_id(member.project_id, user.id) || Member.new(:project_id => member.project_id, :user_id => user.id) + user_member.member_roles << MemberRole.new(:role => role, :inherited_from => id) + user_member.save! + end + end + end + + def remove_role_from_group_users + MemberRole.find(:all, :conditions => { :inherited_from => id }).group_by(&:member).each do |member, member_roles| + member_roles.each(&:destroy) + if member && member.user + Watcher.prune(:user => member.user, :project => member.project) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/77/77a5169e43db90f80c29eb648c961bb39923f36a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/77/77a5169e43db90f80c29eb648c961bb39923f36a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddNewsCommentsCount < ActiveRecord::Migration + def self.up + add_column :news, :comments_count, :integer, :default => 0, :null => false + end + + def self.down + remove_column :news, :comments_count + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/77/77af7be63629a8eb1f26884dc343eb555f568c60.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/77/77af7be63629a8eb1f26884dc343eb555f568c60.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +require 'gravatar' +ActionView::Base.send :include, GravatarHelper::PublicMethods diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/77/77c91510676103db2b08bd0c1bb6738d87279b85.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/77/77c91510676103db2b08bd0c1bb6738d87279b85.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1009 @@ +# Italian translations for Ruby on Rails +# by Claudio Poli (masterkain@gmail.com) +# by Diego Pierotto (ita.translations@tiscali.it) +# by Emidio Stani (emidiostani@gmail.com) + +it: + direction: ltr + date: + formats: + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B %Y" + only_day: "%e" + + day_names: [Domenica, Lunedì, Martedì, Mercoledì, Giovedì, Venerdì, Sabato] + abbr_day_names: [Dom, Lun, Mar, Mer, Gio, Ven, Sab] + month_names: [~, Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, Dicembre] + abbr_month_names: [~, Gen, Feb, Mar, Apr, Mag, Giu, Lug, Ago, Set, Ott, Nov, Dic] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B %Y %H:%M" + only_second: "%S" + + datetime: + formats: + default: "%d-%m-%YT%H:%M:%S%Z" + + am: 'am' + pm: 'pm' + + datetime: + distance_in_words: + half_a_minute: "mezzo minuto" + less_than_x_seconds: + one: "meno di un secondo" + other: "meno di %{count} secondi" + x_seconds: + one: "1 secondo" + other: "%{count} secondi" + less_than_x_minutes: + one: "meno di un minuto" + other: "meno di %{count} minuti" + x_minutes: + one: "1 minuto" + other: "%{count} minuti" + about_x_hours: + one: "circa un'ora" + other: "circa %{count} ore" + x_days: + one: "1 giorno" + other: "%{count} giorni" + about_x_months: + one: "circa un mese" + other: "circa %{count} mesi" + x_months: + one: "1 mese" + other: "%{count} mesi" + about_x_years: + one: "circa un anno" + other: "circa %{count} anni" + over_x_years: + one: "oltre un anno" + other: "oltre %{count} anni" + almost_x_years: + one: "quasi 1 anno" + other: "quasi %{count} anni" + + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: '€' + precision: 2 + format: '%n %u' + human: + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "e" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "Non posso salvare questo %{model}: 1 errore" + other: "Non posso salvare questo %{model}: %{count} errori." + body: "Per favore ricontrolla i seguenti campi:" + messages: + inclusion: "non è incluso nella lista" + exclusion: "è riservato" + invalid: "non è valido" + confirmation: "non coincide con la conferma" + accepted: "deve essere accettata" + empty: "non può essere vuoto" + blank: "non può essere lasciato in bianco" + too_long: "è troppo lungo (il massimo è %{count} lettere)" + too_short: "è troppo corto (il minimo è %{count} lettere)" + wrong_length: "è della lunghezza sbagliata (deve essere di %{count} lettere)" + taken: "è già in uso" + not_a_number: "non è un numero" + greater_than: "deve essere superiore a %{count}" + greater_than_or_equal_to: "deve essere superiore o uguale a %{count}" + equal_to: "deve essere uguale a %{count}" + less_than: "deve essere meno di %{count}" + less_than_or_equal_to: "deve essere meno o uguale a %{count}" + odd: "deve essere dispari" + even: "deve essere pari" + greater_than_start_date: "deve essere maggiore della data di partenza" + not_same_project: "non appartiene allo stesso progetto" + circular_dependency: "Questa relazione creerebbe una dipendenza circolare" + cant_link_an_issue_with_a_descendant: "Una segnalazione non può essere collegata a una delle sue discendenti" + + actionview_instancetag_blank_option: Scegli + + general_text_No: 'No' + general_text_Yes: 'Sì' + general_text_no: 'no' + general_text_yes: 'sì' + general_lang_name: 'Italiano' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: L'utente è stato aggiornato. + notice_account_invalid_creditentials: Nome utente o password non validi. + notice_account_password_updated: La password è stata aggiornata. + notice_account_wrong_password: Password errata + notice_account_register_done: L'utente è stato creato. + notice_account_unknown_email: Utente sconosciuto. + notice_can_t_change_password: Questo utente utilizza un metodo di autenticazione esterno. Impossibile cambiare la password. + notice_account_lost_email_sent: Ti è stata spedita una email con le istruzioni per cambiare la password. + notice_account_activated: Il tuo account è stato attivato. Ora puoi effettuare l'accesso. + notice_successful_create: Creazione effettuata. + notice_successful_update: Modifica effettuata. + notice_successful_delete: Eliminazione effettuata. + notice_successful_connection: Connessione effettuata. + notice_file_not_found: La pagina desiderata non esiste o è stata rimossa. + notice_locking_conflict: Le informazioni sono state modificate da un altro utente. + notice_not_authorized: Non sei autorizzato ad accedere a questa pagina. + notice_email_sent: "Una email è stata spedita a %{value}" + notice_email_error: "Si è verificato un errore durante l'invio di una email (%{value})" + notice_feeds_access_key_reseted: La tua chiave di accesso RSS è stata reimpostata. + + error_scm_not_found: "La risorsa e/o la versione non esistono nel repository." + error_scm_command_failed: "Si è verificato un errore durante l'accesso al repository: %{value}" + + mail_subject_lost_password: "Password %{value}" + mail_body_lost_password: 'Per cambiare la password, usa il seguente collegamento:' + mail_subject_register: "Attivazione utente %{value}" + mail_body_register: "Per attivare l'utente, usa il seguente collegamento:" + + gui_validation_error: 1 errore + gui_validation_error_plural: "%{count} errori" + + field_name: Nome + field_description: Descrizione + field_summary: Sommario + field_is_required: Richiesto + field_firstname: Nome + field_lastname: Cognome + field_mail: Email + field_filename: File + field_filesize: Dimensione + field_downloads: Download + field_author: Autore + field_created_on: Creato + field_updated_on: Aggiornato + field_field_format: Formato + field_is_for_all: Per tutti i progetti + field_possible_values: Valori possibili + field_regexp: Espressione regolare + field_min_length: Lunghezza minima + field_max_length: Lunghezza massima + field_value: Valore + field_category: Categoria + field_title: Titolo + field_project: Progetto + field_issue: Segnalazione + field_status: Stato + field_notes: Note + field_is_closed: Chiudi la segnalazione + field_is_default: Stato predefinito + field_tracker: Tracker + field_subject: Oggetto + field_due_date: Scadenza + field_assigned_to: Assegnato a + field_priority: Priorità + field_fixed_version: Versione prevista + field_user: Utente + field_role: Ruolo + field_homepage: Homepage + field_is_public: Pubblico + field_parent: Sottoprogetto di + field_is_in_roadmap: Segnalazioni mostrate nella roadmap + field_login: Utente + field_mail_notification: Notifiche via email + field_admin: Amministratore + field_last_login_on: Ultima connessione + field_language: Lingua + field_effective_date: Data + field_password: Password + field_new_password: Nuova password + field_password_confirmation: Conferma + field_version: Versione + field_type: Tipo + field_host: Host + field_port: Porta + field_account: Utente + field_base_dn: DN base + field_attr_login: Attributo connessione + field_attr_firstname: Attributo nome + field_attr_lastname: Attributo cognome + field_attr_mail: Attributo email + field_onthefly: Creazione utente "al volo" + field_start_date: Inizio + field_done_ratio: "% completato" + field_auth_source: Modalità di autenticazione + field_hide_mail: Nascondi il mio indirizzo email + field_comments: Commento + field_url: URL + field_start_page: Pagina principale + field_subproject: Sottoprogetto + field_hours: Ore + field_activity: Attività + field_spent_on: Data + field_identifier: Identificativo + field_is_filter: Usato come filtro + field_issue_to: Segnalazioni correlate + field_delay: Ritardo + field_assignable: E' possibile assegnare segnalazioni a questo ruolo + field_redirect_existing_links: Redirige i collegamenti esistenti + field_estimated_hours: Tempo stimato + field_default_value: Stato predefinito + + setting_app_title: Titolo applicazione + setting_app_subtitle: Sottotitolo applicazione + setting_welcome_text: Testo di benvenuto + setting_default_language: Lingua predefinita + setting_login_required: Autenticazione richiesta + setting_self_registration: Auto-registrazione abilitata + setting_attachment_max_size: Dimensione massima allegati + setting_issues_export_limit: Limite esportazione segnalazioni + setting_mail_from: Indirizzo sorgente email + setting_host_name: Nome host + setting_text_formatting: Formattazione testo + setting_wiki_compression: Comprimi cronologia wiki + setting_feeds_limit: Limite contenuti del feed + setting_autofetch_changesets: Acquisisci automaticamente le commit + setting_sys_api_enabled: Abilita WS per la gestione del repository + setting_commit_ref_keywords: Parole chiave riferimento + setting_commit_fix_keywords: Parole chiave chiusura + setting_autologin: Connessione automatica + setting_date_format: Formato data + setting_cross_project_issue_relations: Consenti la creazione di relazioni tra segnalazioni in progetti differenti + + label_user: Utente + label_user_plural: Utenti + label_user_new: Nuovo utente + label_project: Progetto + label_project_new: Nuovo progetto + label_project_plural: Progetti + label_x_projects: + zero: nessun progetto + one: 1 progetto + other: "%{count} progetti" + label_project_all: Tutti i progetti + label_project_latest: Ultimi progetti registrati + label_issue: Segnalazione + label_issue_new: Nuova segnalazione + label_issue_plural: Segnalazioni + label_issue_view_all: Mostra tutte le segnalazioni + label_document: Documento + label_document_new: Nuovo documento + label_document_plural: Documenti + label_role: Ruolo + label_role_plural: Ruoli + label_role_new: Nuovo ruolo + label_role_and_permissions: Ruoli e permessi + label_member: Membro + label_member_new: Nuovo membro + label_member_plural: Membri + label_tracker: Tracker + label_tracker_plural: Tracker + label_tracker_new: Nuovo tracker + label_workflow: Workflow + label_issue_status: Stato segnalazione + label_issue_status_plural: Stati segnalazioni + label_issue_status_new: Nuovo stato + label_issue_category: Categoria segnalazione + label_issue_category_plural: Categorie segnalazioni + label_issue_category_new: Nuova categoria + label_custom_field: Campo personalizzato + label_custom_field_plural: Campi personalizzati + label_custom_field_new: Nuovo campo personalizzato + label_enumerations: Enumerazioni + label_enumeration_new: Nuovo valore + label_information: Informazione + label_information_plural: Informazioni + label_please_login: Entra + label_register: Registrati + label_password_lost: Password dimenticata + label_home: Home + label_my_page: Pagina personale + label_my_account: Il mio utente + label_my_projects: I miei progetti + label_administration: Amministrazione + label_login: Entra + label_logout: Esci + label_help: Aiuto + label_reported_issues: Segnalazioni + label_assigned_to_me_issues: Le mie segnalazioni + label_last_login: Ultimo collegamento + label_registered_on: Registrato il + label_activity: Attività + label_new: Nuovo + label_logged_as: Collegato come + label_environment: Ambiente + label_authentication: Autenticazione + label_auth_source: Modalità di autenticazione + label_auth_source_new: Nuova modalità di autenticazione + label_auth_source_plural: Modalità di autenticazione + label_subproject_plural: Sottoprogetti + label_min_max_length: Lunghezza minima - massima + label_list: Elenco + label_date: Data + label_integer: Intero + label_boolean: Booleano + label_string: Testo + label_text: Testo esteso + label_attribute: Attributo + label_attribute_plural: Attributi + label_download: "%{count} Download" + label_download_plural: "%{count} Download" + label_no_data: Nessun dato disponibile + label_change_status: Cambia stato + label_history: Cronologia + label_attachment: File + label_attachment_new: Nuovo file + label_attachment_delete: Elimina file + label_attachment_plural: File + label_report: Report + label_report_plural: Report + label_news: Notizia + label_news_new: Aggiungi notizia + label_news_plural: Notizie + label_news_latest: Utime notizie + label_news_view_all: Tutte le notizie + label_settings: Impostazioni + label_overview: Panoramica + label_version: Versione + label_version_new: Nuova versione + label_version_plural: Versioni + label_confirmation: Conferma + label_export_to: Esporta su + label_read: Leggi... + label_public_projects: Progetti pubblici + label_open_issues: aperta + label_open_issues_plural: aperte + label_closed_issues: chiusa + label_closed_issues_plural: chiuse + label_x_open_issues_abbr_on_total: + zero: 0 aperte / %{total} + one: 1 aperta / %{total} + other: "%{count} aperte / %{total}" + label_x_open_issues_abbr: + zero: 0 aperte + one: 1 aperta + other: "%{count} aperte" + label_x_closed_issues_abbr: + zero: 0 chiuse + one: 1 chiusa + other: "%{count} chiuse" + label_total: Totale + label_permissions: Permessi + label_current_status: Stato attuale + label_new_statuses_allowed: Nuovi stati possibili + label_all: tutti + label_none: nessuno + label_next: Successivo + label_previous: Precedente + label_used_by: Usato da + label_details: Dettagli + label_add_note: Aggiungi una nota + label_per_page: Per pagina + label_calendar: Calendario + label_months_from: mesi da + label_gantt: Gantt + label_internal: Interno + label_last_changes: "ultime %{count} modifiche" + label_change_view_all: Tutte le modifiche + label_personalize_page: Personalizza la pagina + label_comment: Commento + label_comment_plural: Commenti + label_x_comments: + zero: nessun commento + one: 1 commento + other: "%{count} commenti" + label_comment_add: Aggiungi un commento + label_comment_added: Commento aggiunto + label_comment_delete: Elimina commenti + label_query: Query personalizzata + label_query_plural: Query personalizzate + label_query_new: Nuova query + label_filter_add: Aggiungi filtro + label_filter_plural: Filtri + label_equals: è + label_not_equals: non è + label_in_less_than: è minore di + label_in_more_than: è maggiore di + label_in: in + label_today: oggi + label_this_week: questa settimana + label_less_than_ago: meno di giorni fa + label_more_than_ago: più di giorni fa + label_ago: giorni fa + label_contains: contiene + label_not_contains: non contiene + label_day_plural: giorni + label_repository: Repository + label_browse: Sfoglia + label_modification: "%{count} modifica" + label_modification_plural: "%{count} modifiche" + label_revision: Versione + label_revision_plural: Versioni + label_added: aggiunto + label_modified: modificato + label_deleted: eliminato + label_latest_revision: Ultima versione + label_latest_revision_plural: Ultime versioni + label_view_revisions: Mostra versioni + label_max_size: Dimensione massima + label_sort_highest: Sposta in cima + label_sort_higher: Su + label_sort_lower: Giù + label_sort_lowest: Sposta in fondo + label_roadmap: Roadmap + label_roadmap_due_in: "Da ultimare in %{value}" + label_roadmap_overdue: "%{value} di ritardo" + label_roadmap_no_issues: Nessuna segnalazione per questa versione + label_search: Ricerca + label_result_plural: Risultati + label_all_words: Tutte le parole + label_wiki: Wiki + label_wiki_edit: Modifica wiki + label_wiki_edit_plural: Modifiche wiki + label_wiki_page: Pagina Wiki + label_wiki_page_plural: Pagine wiki + label_index_by_title: Ordina per titolo + label_index_by_date: Ordina per data + label_current_version: Versione corrente + label_preview: Anteprima + label_feed_plural: Feed + label_changes_details: Particolari di tutti i cambiamenti + label_issue_tracking: Tracking delle segnalazioni + label_spent_time: Tempo impiegato + label_f_hour: "%{value} ora" + label_f_hour_plural: "%{value} ore" + label_time_tracking: Tracking del tempo + label_change_plural: Modifiche + label_statistics: Statistiche + label_commits_per_month: Commit per mese + label_commits_per_author: Commit per autore + label_view_diff: mostra differenze + label_diff_inline: in linea + label_diff_side_by_side: fianco a fianco + label_options: Opzioni + label_copy_workflow_from: Copia workflow da + label_permissions_report: Report permessi + label_watched_issues: Segnalazioni osservate + label_related_issues: Segnalazioni correlate + label_applied_status: Stato applicato + label_loading: Caricamento... + label_relation_new: Nuova relazione + label_relation_delete: Elimina relazione + label_relates_to: correlato a + label_duplicates: duplicati + label_blocks: blocchi + label_blocked_by: bloccato da + label_precedes: precede + label_follows: segue + label_end_to_start: fine a inizio + label_end_to_end: fine a fine + label_start_to_start: inizio a inizio + label_start_to_end: inizio a fine + label_stay_logged_in: Rimani collegato + label_disabled: disabilitato + label_show_completed_versions: Mostra versioni completate + label_me: me + label_board: Forum + label_board_new: Nuovo forum + label_board_plural: Forum + label_topic_plural: Argomenti + label_message_plural: Messaggi + label_message_last: Ultimo messaggio + label_message_new: Nuovo messaggio + label_reply_plural: Risposte + label_send_information: Invia all'utente le informazioni relative all'account + label_year: Anno + label_month: Mese + label_week: Settimana + label_date_from: Da + label_date_to: A + label_language_based: Basato sul linguaggio + label_sort_by: "Ordina per %{value}" + label_send_test_email: Invia una email di prova + label_feeds_access_key_created_on: "chiave di accesso RSS creata %{value} fa" + label_module_plural: Moduli + label_added_time_by: "Aggiunto da %{author} %{age} fa" + label_updated_time: "Aggiornato %{value} fa" + label_jump_to_a_project: Vai al progetto... + + button_login: Entra + button_submit: Invia + button_save: Salva + button_check_all: Seleziona tutti + button_uncheck_all: Deseleziona tutti + button_delete: Elimina + button_create: Crea + button_test: Prova + button_edit: Modifica + button_add: Aggiungi + button_change: Cambia + button_apply: Applica + button_clear: Pulisci + button_lock: Blocca + button_unlock: Sblocca + button_download: Scarica + button_list: Elenca + button_view: Mostra + button_move: Sposta + button_back: Indietro + button_cancel: Annulla + button_activate: Attiva + button_sort: Ordina + button_log_time: Registra tempo + button_rollback: Ripristina questa versione + button_watch: Osserva + button_unwatch: Dimentica + button_reply: Rispondi + button_archive: Archivia + button_unarchive: Ripristina + button_reset: Reimposta + button_rename: Rinomina + + status_active: attivo + status_registered: registrato + status_locked: bloccato + + text_select_mail_notifications: Seleziona le azioni per cui deve essere inviata una notifica. + text_regexp_info: es. ^[A-Z0-9]+$ + text_min_max_length_info: 0 significa nessuna restrizione + text_project_destroy_confirmation: Sei sicuro di voler eliminare il progetto e tutti i dati ad esso collegati? + text_workflow_edit: Seleziona un ruolo ed un tracker per modificare il workflow + text_are_you_sure: Sei sicuro ? + text_tip_issue_begin_day: attività che iniziano in questa giornata + text_tip_issue_end_day: attività che terminano in questa giornata + text_tip_issue_begin_end_day: attività che iniziano e terminano in questa giornata + text_project_identifier_info: "Lettere minuscole (a-z), numeri e trattini permessi.
    Una volta salvato, l'identificativo non può essere modificato." + text_caracters_maximum: "massimo %{count} caratteri." + text_length_between: "Lunghezza compresa tra %{min} e %{max} caratteri." + text_tracker_no_workflow: Nessun workflow definito per questo tracker + text_unallowed_characters: Caratteri non permessi + text_comma_separated: Valori multipli permessi (separati da virgole). + text_issues_ref_in_commit_messages: Segnalazioni di riferimento e chiusura nei messaggi di commit + text_issue_added: "E' stata segnalata l'anomalia %{id} da %{author}." + text_issue_updated: "L'anomalia %{id} è stata aggiornata da %{author}." + text_wiki_destroy_confirmation: Sicuro di voler eliminare questo wiki e tutti i suoi contenuti? + text_issue_category_destroy_question: "Alcune segnalazioni (%{count}) risultano assegnate a questa categoria. Cosa vuoi fare ?" + text_issue_category_destroy_assignments: Rimuovi le assegnazioni a questa categoria + text_issue_category_reassign_to: Riassegna segnalazioni a questa categoria + + default_role_manager: Gestore + default_role_developer: Sviluppatore + default_role_reporter: Segnalatore + default_tracker_bug: Segnalazione + default_tracker_feature: Funzione + default_tracker_support: Supporto + default_issue_status_new: Nuovo + default_issue_status_in_progress: In elaborazione + default_issue_status_resolved: Risolto + default_issue_status_feedback: Commenti + default_issue_status_closed: Chiuso + default_issue_status_rejected: Rifiutato + default_doc_category_user: Documentazione utente + default_doc_category_tech: Documentazione tecnica + default_priority_low: Bassa + default_priority_normal: Normale + default_priority_high: Alta + default_priority_urgent: Urgente + default_priority_immediate: Immediata + default_activity_design: Progettazione + default_activity_development: Sviluppo + + enumeration_issue_priorities: Priorità segnalazioni + enumeration_doc_categories: Categorie di documenti + enumeration_activities: Attività (time tracking) + label_file_plural: File + label_changeset_plural: Changeset + field_column_names: Colonne + label_default_columns: Colonne predefinite + setting_issue_list_default_columns: Colonne predefinite mostrate nell'elenco segnalazioni + notice_no_issue_selected: "Nessuna segnalazione selezionata! Seleziona le segnalazioni che intendi modificare." + label_bulk_edit_selected_issues: Modifica massiva delle segnalazioni selezionate + label_no_change_option: (Nessuna modifica) + notice_failed_to_save_issues: "Impossibile salvare %{count} segnalazioni su %{total} selezionate: %{ids}." + label_theme: Tema + label_default: Predefinito + label_search_titles_only: Cerca solo nei titoli + label_nobody: nessuno + button_change_password: Modifica password + text_user_mail_option: "Per i progetti non selezionati, riceverai solo le notifiche riguardanti le cose che osservi o nelle quali sei coinvolto (per esempio segnalazioni che hai creato o che ti sono state assegnate)." + label_user_mail_option_selected: "Solo per gli eventi relativi ai progetti selezionati..." + label_user_mail_option_all: "Per ogni evento relativo ad uno dei miei progetti" + setting_emails_footer: Piè di pagina email + label_float: Decimale + button_copy: Copia + mail_body_account_information_external: "Puoi utilizzare il tuo account %{value} per accedere al sistema." + mail_body_account_information: Le informazioni riguardanti il tuo account + setting_protocol: Protocollo + label_user_mail_no_self_notified: "Non voglio notifiche riguardanti modifiche da me apportate" + setting_time_format: Formato ora + label_registration_activation_by_email: attivazione account via email + mail_subject_account_activation_request: "%{value} richiesta attivazione account" + mail_body_account_activation_request: "Un nuovo utente (%{value}) ha effettuato la registrazione. Il suo account è in attesa di abilitazione da parte tua:" + label_registration_automatic_activation: attivazione account automatica + label_registration_manual_activation: attivazione account manuale + notice_account_pending: "Il tuo account è stato creato ed è in attesa di attivazione da parte dell'amministratore." + field_time_zone: Fuso orario + text_caracters_minimum: "Deve essere lungo almeno %{count} caratteri." + setting_bcc_recipients: Destinatari in copia nascosta (bcc) + button_annotate: Annota + label_issues_by: "Segnalazioni di %{value}" + field_searchable: Ricercabile + label_display_per_page: "Per pagina: %{value}" + setting_per_page_options: Opzioni oggetti per pagina + label_age: Età + notice_default_data_loaded: Configurazione predefinita caricata con successo. + text_load_default_configuration: Carica la configurazione predefinita + text_no_configuration_data: "Ruoli, tracker, stati delle segnalazioni e workflow non sono stati ancora configurati.\nE' vivamente consigliato caricare la configurazione predefinita. Potrai modificarla una volta caricata." + error_can_t_load_default_data: "Non è stato possibile caricare la configurazione predefinita : %{value}" + button_update: Aggiorna + label_change_properties: Modifica le proprietà + label_general: Generale + label_repository_plural: Repository + label_associated_revisions: Revisioni associate + setting_user_format: Formato visualizzazione utenti + text_status_changed_by_changeset: "Applicata nel changeset %{value}." + label_more: Altro + text_issues_destroy_confirmation: 'Sei sicuro di voler eliminare le segnalazioni selezionate?' + label_scm: SCM + text_select_project_modules: 'Seleziona i moduli abilitati per questo progetto:' + label_issue_added: Segnalazioni aggiunte + label_issue_updated: Segnalazioni aggiornate + label_document_added: Documenti aggiunti + label_message_posted: Messaggi aggiunti + label_file_added: File aggiunti + label_news_added: Notizie aggiunte + project_module_boards: Forum + project_module_issue_tracking: Tracking delle segnalazioni + project_module_wiki: Wiki + project_module_files: File + project_module_documents: Documenti + project_module_repository: Repository + project_module_news: Notizie + project_module_time_tracking: Time tracking + text_file_repository_writable: Repository dei file scrivibile + text_default_administrator_account_changed: L'account amministrativo predefinito è stato modificato + text_rmagick_available: RMagick disponibile (opzionale) + button_configure: Configura + label_plugins: Plugin + label_ldap_authentication: Autenticazione LDAP + label_downloads_abbr: D/L + label_this_month: questo mese + label_last_n_days: "ultimi %{count} giorni" + label_all_time: sempre + label_this_year: quest'anno + label_date_range: Intervallo di date + label_last_week: ultima settimana + label_yesterday: ieri + label_last_month: ultimo mese + label_add_another_file: Aggiungi un altro file + label_optional_description: Descrizione opzionale + text_destroy_time_entries_question: "%{hours} ore risultano spese sulle segnalazioni che stai per eliminare. Cosa vuoi fare ?" + error_issue_not_found_in_project: 'La segnalazione non è stata trovata o non appartiene al progetto' + text_assign_time_entries_to_project: Assegna le ore segnalate al progetto + text_destroy_time_entries: Elimina le ore segnalate + text_reassign_time_entries: 'Riassegna le ore a questa segnalazione:' + setting_activity_days_default: Giorni mostrati sulle attività di progetto + label_chronological_order: In ordine cronologico + field_comments_sorting: Mostra commenti + label_reverse_chronological_order: In ordine cronologico inverso + label_preferences: Preferenze + setting_display_subprojects_issues: Mostra le segnalazioni dei sottoprogetti nel progetto principale in modo predefinito + label_overall_activity: Attività generale + setting_default_projects_public: I nuovi progetti sono pubblici in modo predefinito + error_scm_annotate: "L'oggetto non esiste o non può essere annotato." + label_planning: Pianificazione + text_subprojects_destroy_warning: "Anche i suoi sottoprogetti: %{value} verranno eliminati." + label_and_its_subprojects: "%{value} ed i suoi sottoprogetti" + mail_body_reminder: "%{count} segnalazioni che ti sono state assegnate scadranno nei prossimi %{days} giorni:" + mail_subject_reminder: "%{count} segnalazioni in scadenza nei prossimi %{days} giorni" + text_user_wrote: "%{value} ha scritto:" + label_duplicated_by: duplicato da + setting_enabled_scm: SCM abilitato + text_enumeration_category_reassign_to: 'Riassegnale a questo valore:' + text_enumeration_destroy_question: "%{count} oggetti hanno un assegnamento su questo valore." + label_incoming_emails: Email in arrivo + label_generate_key: Genera una chiave + setting_mail_handler_api_enabled: Abilita WS per le email in arrivo + setting_mail_handler_api_key: Chiave API + text_email_delivery_not_configured: "La consegna via email non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/configuration.yml e riavvia l'applicazione per abilitarle." + field_parent_title: Pagina principale + label_issue_watchers: Osservatori + button_quote: Quota + setting_sequential_project_identifiers: Genera progetti con identificativi in sequenza + notice_unable_delete_version: Impossibile eliminare la versione + label_renamed: rinominato + label_copied: copiato + setting_plain_text_mail: Solo testo (non HTML) + permission_view_files: Vedi files + permission_edit_issues: Modifica segnalazioni + permission_edit_own_time_entries: Modifica propri time logs + permission_manage_public_queries: Gestisci query pubbliche + permission_add_issues: Aggiungi segnalazioni + permission_log_time: Segna tempo impiegato + permission_view_changesets: Vedi changesets + permission_view_time_entries: Vedi tempi impiegati + permission_manage_versions: Gestisci versioni + permission_manage_wiki: Gestisci wiki + permission_manage_categories: Gestisci categorie segnalazioni + permission_protect_wiki_pages: Proteggi pagine wiki + permission_comment_news: Commenta notizie + permission_delete_messages: Elimina messaggi + permission_select_project_modules: Seleziona moduli progetto + permission_manage_documents: Gestisci documenti + permission_edit_wiki_pages: Modifica pagine wiki + permission_add_issue_watchers: Aggiungi osservatori + permission_view_gantt: Vedi diagrammi gantt + permission_move_issues: Muovi segnalazioni + permission_manage_issue_relations: Gestisci relazioni tra segnalazioni + permission_delete_wiki_pages: Elimina pagine wiki + permission_manage_boards: Gestisci forum + permission_delete_wiki_pages_attachments: Elimina allegati + permission_view_wiki_edits: Vedi cronologia wiki + permission_add_messages: Aggiungi messaggi + permission_view_messages: Vedi messaggi + permission_manage_files: Gestisci files + permission_edit_issue_notes: Modifica note + permission_manage_news: Gestisci notizie + permission_view_calendar: Vedi calendario + permission_manage_members: Gestisci membri + permission_edit_messages: Modifica messaggi + permission_delete_issues: Elimina segnalazioni + permission_view_issue_watchers: Vedi lista osservatori + permission_manage_repository: Gestisci repository + permission_commit_access: Permesso di commit + permission_browse_repository: Sfoglia repository + permission_view_documents: Vedi documenti + permission_edit_project: Modifica progetti + permission_add_issue_notes: Aggiungi note + permission_save_queries: Salva query + permission_view_wiki_pages: Vedi pagine wiki + permission_rename_wiki_pages: Rinomina pagine wiki + permission_edit_time_entries: Modifica time logs + permission_edit_own_issue_notes: Modifica proprie note + setting_gravatar_enabled: Usa icone utente Gravatar + label_example: Esempio + text_repository_usernames_mapping: "Seleziona per aggiornare la corrispondenza tra gli utenti Redmine e quelli presenti nel log del repository.\nGli utenti Redmine e repository con lo stesso note utente o email sono mappati automaticamente." + permission_edit_own_messages: Modifica propri messaggi + permission_delete_own_messages: Elimina propri messaggi + label_user_activity: "attività di %{value}" + label_updated_time_by: "Aggiornato da %{author} %{age} fa" + text_diff_truncated: '... Le differenze sono state troncate perchè superano il limite massimo visualizzabile.' + setting_diff_max_lines_displayed: Limite massimo di differenze (linee) mostrate + text_plugin_assets_writable: Directory attività dei plugins scrivibile + warning_attachments_not_saved: "%{count} file non possono essere salvati." + button_create_and_continue: Crea e continua + text_custom_field_possible_values_info: 'Un valore per ogni riga' + label_display: Mostra + field_editable: Modificabile + setting_repository_log_display_limit: Numero massimo di revisioni elencate nella cronologia file + setting_file_max_size_displayed: Dimensione massima dei contenuti testuali visualizzati + field_watcher: Osservatore + setting_openid: Accetta connessione e registrazione con OpenID + field_identity_url: URL OpenID + label_login_with_open_id_option: oppure autenticati usando OpenID + field_content: Contenuto + label_descending: Discendente + label_sort: Ordina + label_ascending: Ascendente + label_date_from_to: Da %{start} a %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Questa pagina ha %{descendants} pagine figlie. Cosa ne vuoi fare? + text_wiki_page_reassign_children: Riassegna le pagine figlie al padre di questa pagina + text_wiki_page_nullify_children: Mantieni le pagine figlie come pagine radice + text_wiki_page_destroy_children: Elimina le pagine figlie e tutta la discendenza + setting_password_min_length: Lunghezza minima password + field_group_by: Raggruppa risultati per + mail_subject_wiki_content_updated: "La pagina wiki '%{id}' è stata aggiornata" + label_wiki_content_added: Aggiunta pagina al wiki + mail_subject_wiki_content_added: "La pagina '%{id}' è stata aggiunta al wiki" + mail_body_wiki_content_added: La pagina '%{id}' è stata aggiunta al wiki da %{author}. + label_wiki_content_updated: Aggiornata pagina wiki + mail_body_wiki_content_updated: La pagina '%{id}' wiki è stata aggiornata da%{author}. + permission_add_project: Crea progetto + setting_new_project_user_role_id: Ruolo assegnato agli utenti non amministratori che creano un progetto + label_view_all_revisions: Mostra tutte le revisioni + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Nessun tracker è associato a questo progetto. Per favore verifica le impostazioni del Progetto. + error_no_default_issue_status: Nessuno stato predefinito delle segnalazioni è configurato. Per favore verifica le impostazioni (Vai in "Amministrazione -> Stati segnalazioni"). + text_journal_changed: "%{label} modificata da %{old} a %{new}" + text_journal_set_to: "%{label} impostata a %{value}" + text_journal_deleted: "%{label} eliminata (%{old})" + label_group_plural: Gruppi + label_group: Gruppo + label_group_new: Nuovo gruppo + label_time_entry_plural: Tempo impiegato + text_journal_added: "%{value} %{label} aggiunto" + field_active: Attivo + enumeration_system_activity: Attività di sistema + permission_delete_issue_watchers: Elimina osservatori + version_status_closed: chiusa + version_status_locked: bloccata + version_status_open: aperta + error_can_not_reopen_issue_on_closed_version: Una segnalazione assegnata ad una versione chiusa non può essere riaperta + label_user_anonymous: Anonimo + button_move_and_follow: Sposta e segui + setting_default_projects_modules: Moduli predefiniti abilitati per i nuovi progetti + setting_gravatar_default: Immagine Gravatar predefinita + field_sharing: Condivisione + label_version_sharing_hierarchy: Con gerarchia progetto + label_version_sharing_system: Con tutti i progetti + label_version_sharing_descendants: Con sottoprogetti + label_version_sharing_tree: Con progetto padre + label_version_sharing_none: Nessuna condivisione + error_can_not_archive_project: Questo progetto non può essere archiviato + button_duplicate: Duplica + button_copy_and_follow: Copia e segui + label_copy_source: Sorgente + setting_issue_done_ratio: Calcola la percentuale di segnalazioni completate con + setting_issue_done_ratio_issue_status: Usa lo stato segnalazioni + error_issue_done_ratios_not_updated: La percentuale delle segnalazioni completate non è aggiornata. + error_workflow_copy_target: Per favore seleziona trackers finali e ruolo(i) + setting_issue_done_ratio_issue_field: Usa il campo segnalazioni + label_copy_same_as_target: Uguale a destinazione + label_copy_target: Destinazione + notice_issue_done_ratios_updated: La percentuale delle segnalazioni completate è aggiornata. + error_workflow_copy_source: Per favore seleziona un tracker sorgente o ruolo + label_update_issue_done_ratios: Aggiorna la percentuale delle segnalazioni completate + setting_start_of_week: Avvia calendari il + permission_view_issues: Mostra segnalazioni + label_display_used_statuses_only: Mostra solo stati che vengono usati per questo tracker + label_revision_id: Revisione %{value} + label_api_access_key: Chiave di accesso API + label_api_access_key_created_on: Chiave di accesso API creata %{value} fa + label_feeds_access_key: Chiave di accesso RSS + notice_api_access_key_reseted: La chiave di accesso API è stata reimpostata. + setting_rest_api_enabled: Abilita il servizio web REST + label_missing_api_access_key: Chiave di accesso API mancante + label_missing_feeds_access_key: Chiave di accesso RSS mancante + button_show: Mostra + text_line_separated: Valori multipli permessi (un valore per ogni riga). + setting_mail_handler_body_delimiters: Tronca email dopo una di queste righe + permission_add_subprojects: Crea sottoprogetti + label_subproject_new: Nuovo sottoprogetto + text_own_membership_delete_confirmation: |- + Stai per eliminare alcuni o tutti i permessi e non sarai più in grado di modificare questo progetto dopo tale azione. + Sei sicuro di voler continuare? + label_close_versions: Versioni completate chiuse + label_board_sticky: Annunci + label_board_locked: Bloccato + permission_export_wiki_pages: Esporta pagine wiki + setting_cache_formatted_text: Cache testo formattato + permission_manage_project_activities: Gestisci attività progetti + error_unable_delete_issue_status: Impossibile eliminare lo stato segnalazioni + label_profile: Profilo + permission_manage_subtasks: Gestisci sottoattività + field_parent_issue: Attività principale + label_subtask_plural: Sottoattività + label_project_copy_notifications: Invia notifiche email durante la copia del progetto + error_can_not_delete_custom_field: Impossibile eliminare il campo personalizzato + error_unable_to_connect: Impossibile connettersi (%{value}) + error_can_not_remove_role: Questo ruolo è in uso e non può essere eliminato. + error_can_not_delete_tracker: Questo tracker contiene segnalazioni e non può essere eliminato. + field_principal: Principale + label_my_page_block: La mia pagina di blocco + notice_failed_to_save_members: "Impossibile salvare il membro(i): %{errors}." + text_zoom_out: Riduci ingrandimento + text_zoom_in: Aumenta ingrandimento + notice_unable_delete_time_entry: Impossibile eliminare il valore time log. + label_overall_spent_time: Totale tempo impiegato + field_time_entries: Tempo di collegamento + project_module_gantt: Gantt + project_module_calendar: Calendario + button_edit_associated_wikipage: "Modifica la pagina wiki associata: %{page_title}" + text_are_you_sure_with_children: Eliminare la segnalazione e tutte le discendenti? + field_text: Campo di testo + label_user_mail_option_only_owner: Solo se io sono il proprietario + setting_default_notification_option: Opzione di notifica predefinita + label_user_mail_option_only_my_events: Solo se sono un osservatore o sono coinvolto + label_user_mail_option_only_assigned: Solo quando mi assegnano attività + label_user_mail_option_none: Nessun evento + field_member_of_group: Gruppo dell'assegnatario + field_assigned_to_role: Ruolo dell'assegnatario + notice_not_authorized_archived_project: Il progetto a cui stai accedendo è stato archiviato. + label_principal_search: "Cerca utente o gruppo:" + label_user_search: "Cerca utente:" + field_visible: Visibile + setting_emails_header: Intestazione email + setting_commit_logtime_activity_id: Attività per il tempo di collegamento + text_time_logged_by_changeset: Usato nel changeset %{value}. + setting_commit_logtime_enabled: Abilita registrazione del tempo di collegamento + notice_gantt_chart_truncated: Il grafico è stato troncato perchè eccede il numero di oggetti (%{max}) da visualizzare + setting_gantt_items_limit: Massimo numero di oggetti da visualizzare sul diagramma di gantt + field_warn_on_leaving_unsaved: Avvisami quando lascio una pagina con testo non salvato + text_warn_on_leaving_unsaved: La pagina corrente contiene del testo non salvato che verrà perso se lasci questa pagina. + label_my_queries: Le mie queries personalizzate + text_journal_changed_no_detail: "%{label} aggiornato" + label_news_comment_added: Commento aggiunto a una notizia + button_expand_all: Espandi tutto + button_collapse_all: Comprimi tutto + label_additional_workflow_transitions_for_assignee: Transizioni supplementari consentite quando l'utente è l'assegnatario + label_additional_workflow_transitions_for_author: Transizioni supplementari consentite quando l'utente è l'autore + label_bulk_edit_selected_time_entries: Modifica massiva delle ore segnalate selezionate + text_time_entries_destroy_confirmation: Sei sicuro di voler eliminare l'ora\e selezionata\e? + label_role_anonymous: Anonimo + label_role_non_member: Non membro + label_issue_note_added: Nota aggiunta + label_issue_status_updated: Stato aggiornato + label_issue_priority_updated: Priorità aggiornata + label_issues_visibility_own: Segnalazioni create o assegnate all'utente + field_issues_visibility: Visibilità segnalazioni + label_issues_visibility_all: Tutte le segnalazioni + permission_set_own_issues_private: Imposta le proprie segnalazioni pubbliche o private + field_is_private: Privato + permission_set_issues_private: Imposta le segnalazioni pubbliche o private + label_issues_visibility_public: Tutte le segnalazioni non private + text_issues_destroy_descendants_confirmation: Questo eliminerà anche %{count} sottoattività. + field_commit_logs_encoding: Codifica dei messaggi di commit + field_scm_path_encoding: Codifica del percorso + text_scm_path_encoding_note: "Predefinito: UTF-8" + field_path_to_repository: Percorso del repository + field_root_directory: Directory radice + field_cvs_module: Modulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: Repository locale (es. /hgrepo, c:\hgrepo) + text_scm_command: Comando + text_scm_command_version: Versione + label_git_report_last_commit: Riporta l'ultimo commit per files e directories + text_scm_config: Puoi configurare i comandi scm nel file config/configuration.yml. E' necessario riavviare l'applicazione dopo averlo modificato. + text_scm_command_not_available: Il comando scm non è disponibile. Controllare le impostazioni nel pannello di amministrazione. + notice_issue_successful_create: Segnalazione %{id} creata. + label_between: tra + setting_issue_group_assignment: Permetti di assegnare una segnalazione a gruppi + label_diff: diff + text_git_repository_note: Il repository è bare e locale (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Ordinamento + description_project_scope: Search scope + description_filter: Filtro + description_user_mail_notification: Impostazioni notifica via mail + description_date_from: Inserisci la data d'inizio + description_message_content: Contenuto del messaggio + description_available_columns: Colonne disponibili + description_date_range_interval: Scegli l'intervallo selezionando la data di inizio e di fine + description_issue_category_reassign: Scegli la categoria della segnalazione + description_search: Campo di ricerca + description_notes: Note + description_date_range_list: Scegli l'intervallo dalla lista + description_choose_project: Progetti + description_date_to: Inserisci la data di fine + description_query_sort_criteria_attribute: Attributo di ordinamento + description_wiki_subpages_reassign: Scegli la nuova pagina padre + description_selected_columns: Colonne selezionate + label_parent_revision: Padre + label_child_revision: Figlio + error_scm_annotate_big_text_file: La nota non può essere salvata, supera la dimensiona massima del campo di testo. + setting_default_issue_start_date_to_creation_date: Usa la data corrente come data d'inizio per le nuove segnalazioni + button_edit_section: Modifica questa sezione + setting_repositories_encodings: Codifica degli allegati e dei repository + description_all_columns: Tutte le colonne + button_export: Esporta + label_export_options: "%{export_format} opzioni per l'export" + error_attachment_too_big: Questo file non può essere caricato in quanto la sua dimensione supera la massima consentita (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/77/77f164566cbcb4cbb21bb686bf4becc3ff3142ca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/77/77f164566cbcb4cbb21bb686bf4becc3ff3142ca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class AddQueriesPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "add_query", :description => "button_create", :sort => 600, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'add_query']).destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/7828cc0008d3db898fec05425bedf18d84ff5098.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/78/7828cc0008d3db898fec05425bedf18d84ff5098.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +<% if issues && issues.any? %> +<% form_tag({}) do %> + + + + + + + + + <% for issue in issues %> + + + + + + + <% end %> + +
    #<%=l(:field_project)%><%=l(:field_tracker)%><%=l(:field_subject)%>
    + <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> + <%= link_to(h(issue.id), :controller => 'issues', :action => 'show', :id => issue) %> + <%= link_to_project(issue.project) %><%=h issue.tracker %> + <%= link_to h(truncate(issue.subject, :length => 60)), :controller => 'issues', :action => 'show', :id => issue %> (<%=h issue.status %>) +
    +<% end %> +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/784c9b0d2d8855db8c97b7e039fb2ee4a682fc0e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/78/784c9b0d2d8855db8c97b7e039fb2ee4a682fc0e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class TestingTest < Test::Unit::TestCase + def setup + Engines::Testing.set_fixture_path + @filename = File.join(Engines::Testing.temporary_fixtures_directory, 'testing_fixtures.yml') + File.delete(@filename) if File.exists?(@filename) + end + + def teardown + File.delete(@filename) if File.exists?(@filename) + end + + def test_should_copy_fixtures_files_to_tmp_directory + assert !File.exists?(@filename) + Engines::Testing.setup_plugin_fixtures + assert File.exists?(@filename) + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/78656abccdc6e881919c3599b07b9c04e13170fc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/78/78656abccdc6e881919c3599b07b9c04e13170fc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,87 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'reports_controller' + +# Re-raise errors caught by the controller. +class ReportsController; def rescue_action(e) raise e end; end + + +class ReportsControllerTest < ActionController::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions + + def setup + @controller = ReportsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + context "GET :issue_report without details" do + setup do + get :issue_report, :id => 1 + end + + should_respond_with :success + should_render_template :issue_report + + [:issues_by_tracker, :issues_by_version, :issues_by_category, :issues_by_assigned_to, + :issues_by_author, :issues_by_subproject].each do |ivar| + should_assign_to ivar + should "set a value for #{ivar}" do + assert assigns[ivar.to_s].present? + end + end + end + + context "GET :issue_report_details" do + %w(tracker version priority category assigned_to author subproject).each do |detail| + context "for #{detail}" do + setup do + get :issue_report_details, :id => 1, :detail => detail + end + + should_respond_with :success + should_render_template :issue_report_details + should_assign_to :field + should_assign_to :rows + should_assign_to :data + should_assign_to :report_title + end + end + + context "with an invalid detail" do + setup do + get :issue_report_details, :id => 1, :detail => 'invalid' + end + + should_respond_with :redirect + should_redirect_to('the issue report') {{:controller => 'reports', :action => 'issue_report', :id => 'ecookbook'}} + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/7887ac0add3adb74049da4eb63c9169b67eaf06b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/78/7887ac0add3adb74049da4eb63c9169b67eaf06b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,226 @@ +require 'rake' +require 'rake/rdoctask' +require 'tmpdir' + +task :default => :doc + +desc 'Generate documentation for the engines plugin.' +Rake::RDocTask.new(:doc) do |doc| + doc.rdoc_dir = 'doc' + doc.title = 'Engines' + doc.main = "README" + doc.rdoc_files.include("README", "CHANGELOG", "MIT-LICENSE") + doc.rdoc_files.include('lib/**/*.rb') + doc.options << '--line-numbers' << '--inline-source' +end + +desc 'Run the engine plugin tests within their test harness' +task :cruise do + # checkout the project into a temporary directory + version = "rails_2.0" + test_dir = "#{Dir.tmpdir}/engines_plugin_#{version}_test" + puts "Checking out test harness for #{version} into #{test_dir}" + `svn co http://svn.rails-engines.org/test/engines/#{version} #{test_dir}` + + # run all the tests in this project + Dir.chdir(test_dir) + load 'Rakefile' + puts "Running all tests in test harness" + ['db:migrate', 'test', 'test:plugins'].each do |t| + Rake::Task[t].invoke + end +end + +task :clean => [:clobber_doc, "test:clean"] + +namespace :test do + + # Yields a block with STDOUT and STDERR silenced. If you *really* want + # to output something, the block is yielded with the original output + # streams, i.e. + # + # silence do |o, e| + # puts 'hello!' # no output produced + # o.puts 'hello!' # output on STDOUT + # end + # + # (based on silence_stream in ActiveSupport.) + def silence + yield(STDOUT, STDERR) if ENV['VERBOSE'] + streams = [STDOUT, STDERR] + actual_stdout = STDOUT.dup + actual_stderr = STDERR.dup + streams.each do |s| + s.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') + s.sync = true + end + yield actual_stdout, actual_stderr + ensure + STDOUT.reopen(actual_stdout) + STDERR.reopen(actual_stderr) + end + + def test_app_dir + File.join(File.dirname(__FILE__), 'test_app') + end + + def run(cmd) + cmd = cmd.join(" && ") if cmd.is_a?(Array) + system(cmd) || raise("failed running '#{cmd}'") + end + + desc 'Remove the test application' + task :clean do + FileUtils.rm_r(test_app_dir) if File.exist?(test_app_dir) + end + + desc 'Build the test rails application (use RAILS=[edge,] to test against specific version)' + task :generate_app do + silence do |out, err| + out.puts "> Creating test application at #{test_app_dir}" + + if ENV['RAILS'] + vendor_dir = File.join(test_app_dir, 'vendor') + FileUtils.mkdir_p vendor_dir + + if ENV['RAILS'] == 'edge' + out.puts " Cloning Edge Rails from GitHub" + run "cd #{vendor_dir} && git clone --depth 1 git://github.com/rails/rails.git" + elsif ENV['RAILS'] =~ /\d\.\d\.\d/ + if ENV['CURL'] + out.puts " Cloning Rails Tag #{ENV['RAILS']} from GitHub using curl and tar" + run ["cd #{vendor_dir}", + "mkdir rails", + "cd rails", + "curl -s -L http://github.com/rails/rails/tarball/#{ENV['RAILS']} | tar xzv --strip-components 1"] + else + out.puts " Cloning Rails Tag #{ENV['RAILS']} from GitHub (can be slow - set CURL=true to use curl)" + run ["cd #{vendor_dir}", + "git clone git://github.com/rails/rails.git", + "cd rails", + "git pull", + "git checkout v#{ENV['RAILS']}"] + end + elsif File.exist?(ENV['RAILS']) + out.puts " Linking rails from #{ENV['RAILS']}" + run "cd #{vendor_dir} && ln -s #{ENV['RAILS']} rails" + else + raise "Couldn't build test application from '#{ENV['RAILS']}'" + end + + out.puts " generating rails default directory structure" + run "ruby #{File.join(vendor_dir, 'rails', 'railties', 'bin', 'rails')} #{test_app_dir}" + else + version = `rails --version`.chomp.split.last + out.puts " building rails using the 'rails' command (rails version: #{version})" + run "rails #{test_app_dir}" + end + + # get the database config and schema in place + out.puts " writing database.yml" + require 'yaml' + File.open(File.join(test_app_dir, 'config', 'database.yml'), 'w') do |f| + f.write(%w(development test).inject({}) do |h, env| + h[env] = {"adapter" => "sqlite3", "database" => "engines_#{env}.sqlite3"} ; h + end.to_yaml) + end + out.puts " installing exception_notification plugin" + run "cd #{test_app_dir} && ./script/plugin install git://github.com/rails/exception_notification.git" + end + end + + # We can't link the plugin, as it needs to be present for script/generate to find + # the plugin generator. + # TODO: find and +1/create issue for loading generators from symlinked plugins + desc 'Mirror the engines plugin into the test application' + task :copy_engines_plugin do + puts "> Copying engines plugin into test application" + engines_plugin = File.join(test_app_dir, "vendor", "plugins", "engines") + FileUtils.rm_r(engines_plugin) if File.exist?(engines_plugin) + FileUtils.mkdir_p(engines_plugin) + FileList["*"].exclude("test_app").each do |file| + FileUtils.cp_r(file, engines_plugin) + end + end + + def insert_line(line, options) + line = line + "\n" + target_file = File.join(test_app_dir, options[:into]) + lines = File.readlines(target_file) + return if lines.include?(line) + + if options[:after] + if options[:after].is_a?(String) + after_line = options[:after] + "\n" + else + after_line = lines.find { |l| l =~ options[:after] } + raise "couldn't find a line matching #{options[:after].inspect} in #{target_file}" unless after_line + end + index = lines.index(after_line) + raise "couldn't find line '#{after_line}' in #{target_file}" unless index + lines.insert(index + 1, line) + else + lines << line + end + File.open(target_file, 'w') { |f| f.write lines.join } + end + + def mirror_test_files(src, dest=nil) + destination_dir = File.join(*([test_app_dir, dest].compact)) + FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', src), destination_dir) + end + + desc 'Update the plugin and tests files in the test application from the plugin' + task :mirror_engine_files => [:test_app, :copy_engines_plugin] do + puts "> Tweaking generated application to be suitable for testing" + + # Replace the Rails plugin loader with the engines one. + insert_line("require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')", + :into => 'config/environment.rb', + :after => "require File.join(File.dirname(__FILE__), 'boot')") + + # Add the engines test helper to handle fixtures & stuff. + insert_line("require 'engines_test_helper'", :into => 'test/test_helper.rb') + + # Run engine plugin tests when running the application + insert_line("task :test => ['test:engines:all']", :into => 'Rakefile') + + # We want exceptions to be raised + insert_line("def rescue_action(e) raise e end;", + :into => "app/controllers/application_controller.rb", + :after => "class ApplicationController < ActionController::Base") + + # We need this method to test where actions are being rendered from. + insert_line("include RenderInformation", + :into => "app/controllers/application_controller.rb", + :after => "class ApplicationController < ActionController::Base") + + puts "> Mirroring test application files into #{test_app_dir}" + mirror_test_files('app') + mirror_test_files('lib') + mirror_test_files('plugins', 'vendor') + mirror_test_files('unit', 'test') + mirror_test_files('functional', 'test') + end + + desc 'Prepare the engines test environment' + task :test_app do + version_tag = File.join(test_app_dir, 'RAILS_VERSION') + existing_version = File.read(version_tag).chomp rescue 'unknown' + if existing_version == ENV['RAILS'] + puts "> Reusing existing test application (#{ENV['RAILS']})" + else + puts "> Recreating test application" + Rake::Task["test:clean"].invoke + Rake::Task["test:generate_app"].invoke + + File.open(version_tag, "w") { |f| f.write ENV['RAILS'] } + end + end +end + +task :test => "test:mirror_engine_files" do + puts "> Loading the test application environment and running tests" + # We use exec here to replace the current running rake process + exec("cd #{test_app_dir} && rake db:migrate && rake") +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/78a1de16a7f51fffc3afacfeda93104b299506dc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/78/78a1de16a7f51fffc3afacfeda93104b299506dc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,323 @@ +# encoding: utf-8 +require 'strscan' + +module CodeRay + + autoload :WordList, 'coderay/helpers/word_list' + + # = Scanners + # + # This module holds the Scanner class and its subclasses. + # For example, the Ruby scanner is named CodeRay::Scanners::Ruby + # can be found in coderay/scanners/ruby. + # + # Scanner also provides methods and constants for the register + # mechanism and the [] method that returns the Scanner class + # belonging to the given lang. + # + # See PluginHost. + module Scanners + extend PluginHost + plugin_path File.dirname(__FILE__), 'scanners' + + + # = Scanner + # + # The base class for all Scanners. + # + # It is a subclass of Ruby's great +StringScanner+, which + # makes it easy to access the scanning methods inside. + # + # It is also +Enumerable+, so you can use it like an Array of + # Tokens: + # + # require 'coderay' + # + # c_scanner = CodeRay::Scanners[:c].new "if (*p == '{') nest++;" + # + # for text, kind in c_scanner + # puts text if kind == :operator + # end + # + # # prints: (*==)++; + # + # OK, this is a very simple example :) + # You can also use +map+, +any?+, +find+ and even +sort_by+, + # if you want. + class Scanner < StringScanner + + extend Plugin + plugin_host Scanners + + # Raised if a Scanner fails while scanning + ScanError = Class.new StandardError + + # The default options for all scanner classes. + # + # Define @default_options for subclasses. + DEFAULT_OPTIONS = { } + + KINDS_NOT_LOC = [:comment, :doctype, :docstring] + + attr_accessor :state + + class << self + + # Normalizes the given code into a string with UNIX newlines, in the + # scanner's internal encoding, with invalid and undefined charachters + # replaced by placeholders. Always returns a new object. + def normalize code + # original = code + code = code.to_s unless code.is_a? ::String + return code if code.empty? + + if code.respond_to? :encoding + code = encode_with_encoding code, self.encoding + else + code = to_unix code + end + # code = code.dup if code.eql? original + code + end + + # The typical filename suffix for this scanner's language. + def file_extension extension = lang + @file_extension ||= extension.to_s + end + + # The encoding used internally by this scanner. + def encoding name = 'UTF-8' + @encoding ||= defined?(Encoding.find) && Encoding.find(name) + end + + # The lang of this Scanner class, which is equal to its Plugin ID. + def lang + @plugin_id + end + + protected + + def encode_with_encoding code, target_encoding + if code.encoding == target_encoding + if code.valid_encoding? + return to_unix(code) + else + source_encoding = guess_encoding code + end + else + source_encoding = code.encoding + end + # print "encode_with_encoding from #{source_encoding} to #{target_encoding}" + code.encode target_encoding, source_encoding, :universal_newline => true, :undef => :replace, :invalid => :replace + end + + def to_unix code + code.index(?\r) ? code.gsub(/\r\n?/, "\n") : code + end + + def guess_encoding s + #:nocov: + IO.popen("file -b --mime -", "w+") do |file| + file.write s[0, 1024] + file.close_write + begin + Encoding.find file.gets[/charset=([-\w]+)/, 1] + rescue ArgumentError + Encoding::BINARY + end + end + #:nocov: + end + + end + + # Create a new Scanner. + # + # * +code+ is the input String and is handled by the superclass + # StringScanner. + # * +options+ is a Hash with Symbols as keys. + # It is merged with the default options of the class (you can + # overwrite default options here.) + # + # Else, a Tokens object is used. + def initialize code = '', options = {} + if self.class == Scanner + raise NotImplementedError, "I am only the basic Scanner class. I can't scan anything. :( Use my subclasses." + end + + @options = self.class::DEFAULT_OPTIONS.merge options + + super self.class.normalize(code) + + @tokens = options[:tokens] || Tokens.new + @tokens.scanner = self if @tokens.respond_to? :scanner= + + setup + end + + # Sets back the scanner. Subclasses should redefine the reset_instance + # method instead of this one. + def reset + super + reset_instance + end + + # Set a new string to be scanned. + def string= code + code = self.class.normalize(code) + super code + reset_instance + end + + # the Plugin ID for this scanner + def lang + self.class.lang + end + + # the default file extension for this scanner + def file_extension + self.class.file_extension + end + + # Scan the code and returns all tokens in a Tokens object. + def tokenize source = nil, options = {} + options = @options.merge(options) + @tokens = options[:tokens] || @tokens || Tokens.new + @tokens.scanner = self if @tokens.respond_to? :scanner= + case source + when Array + self.string = self.class.normalize(source.join) + when nil + reset + else + self.string = self.class.normalize(source) + end + + begin + scan_tokens @tokens, options + rescue => e + message = "Error in %s#scan_tokens, initial state was: %p" % [self.class, defined?(state) && state] + raise_inspect e.message, @tokens, message, 30, e.backtrace + end + + @cached_tokens = @tokens + if source.is_a? Array + @tokens.split_into_parts(*source.map { |part| part.size }) + else + @tokens + end + end + + # Cache the result of tokenize. + def tokens + @cached_tokens ||= tokenize + end + + # Traverse the tokens. + def each &block + tokens.each(&block) + end + include Enumerable + + # The current line position of the scanner, starting with 1. + # See also: #column. + # + # Beware, this is implemented inefficiently. It should be used + # for debugging only. + def line pos = self.pos + return 1 if pos <= 0 + binary_string[0...pos].count("\n") + 1 + end + + # The current column position of the scanner, starting with 1. + # See also: #line. + def column pos = self.pos + return 1 if pos <= 0 + pos - (binary_string.rindex(?\n, pos - 1) || -1) + end + + # The string in binary encoding. + # + # To be used with #pos, which is the index of the byte the scanner + # will scan next. + def binary_string + @binary_string ||= + if string.respond_to?(:bytesize) && string.bytesize != string.size + #:nocov: + string.dup.force_encoding('binary') + #:nocov: + else + string + end + end + + protected + + # Can be implemented by subclasses to do some initialization + # that has to be done once per instance. + # + # Use reset for initialization that has to be done once per + # scan. + def setup # :doc: + end + + # This is the central method, and commonly the only one a + # subclass implements. + # + # Subclasses must implement this method; it must return +tokens+ + # and must only use Tokens#<< for storing scanned tokens! + def scan_tokens tokens, options # :doc: + raise NotImplementedError, "#{self.class}#scan_tokens not implemented." + end + + # Resets the scanner. + def reset_instance + @tokens.clear if @tokens.respond_to?(:clear) && !@options[:keep_tokens] + @cached_tokens = nil + @binary_string = nil if defined? @binary_string + end + + # Scanner error with additional status information + def raise_inspect msg, tokens, state = self.state || 'No state given!', ambit = 30, backtrace = caller + raise ScanError, <<-EOE % [ + + +***ERROR in %s: %s (after %d tokens) + +tokens: +%s + +current line: %d column: %d pos: %d +matched: %p state: %p +bol? = %p, eos? = %p + +surrounding code: +%p ~~ %p + + +***ERROR*** + + EOE + File.basename(caller[0]), + msg, + tokens.respond_to?(:size) ? tokens.size : 0, + tokens.respond_to?(:last) ? tokens.last(10).map { |t| t.inspect }.join("\n") : '', + line, column, pos, + matched, state, bol?, eos?, + binary_string[pos - ambit, ambit], + binary_string[pos, ambit], + ], backtrace + end + + # Shorthand for scan_until(/\z/). + # This method also avoids a JRuby 1.9 mode bug. + def scan_rest + rest = self.rest + terminate + rest + end + + end + + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/78cbb9f26be10a59d967769f645d28516059e6e0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/78/78cbb9f26be10a59d967769f645d28516059e6e0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,126 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Chủ nhật", + "Thứ Hai", + "Thứ Ba", + "Thứ Tư", + "Thứ Năm", + "Thứ Sáu", + "Thứ Bảy", + "Chủ Nhật"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("C.Nhật", + "Hai", + "Ba", + "Tư", + "Năm", + "Sáu", + "Bảy", + "C.Nhật"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Tháng Giêng", + "Tháng Hai", + "Tháng Ba", + "Tháng Tư", + "Tháng Năm", + "Tháng Sáu", + "Tháng Bảy", + "Tháng Tám", + "Tháng Chín", + "Tháng Mười", + "Tháng M.Một", + "Tháng Chạp"); + +// short month names +Calendar._SMN = new Array +("Mmột", + "Hai", + "Ba", + "Tư", + "Năm", + "Sáu", + "Bảy", + "Tám", + "Chín", + "Mười", + "MMột", + "Chạp"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Giới thiệu"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector (c) dynarch.com 2002-2005 / Tác giả: Mihai Bazon. " + // don't translate this this ;-) +"Phiên bản mới nhất có tại: http://www.dynarch.com/projects/calendar/. " + +"Sản phẩm được phân phối theo giấy phép GNU LGPL. Xem chi tiết tại http://gnu.org/licenses/lgpl.html." + +"\n\n" + +"Chọn ngày:\n" + +"- Dùng nút \xab, \xbb để chọn năm\n" + +"- Dùng nút " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " để chọn tháng\n" + +"- Giữ chuột vào các nút trên để có danh sách năm và tháng."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Chọn thời gian:\n" + +"- Click chuột trên từng phần của thời gian để chỉnh sửa\n" + +"- hoặc nhấn Shift + click chuột để tăng giá trị\n" + +"- hoặc click chuột và kéo (drag) để chọn nhanh."; + +Calendar._TT["PREV_YEAR"] = "Năm trước (giữ chuột để có menu)"; +Calendar._TT["PREV_MONTH"] = "Tháng trước (giữ chuột để có menu)"; +Calendar._TT["GO_TODAY"] = "đến Hôm nay"; +Calendar._TT["NEXT_MONTH"] = "Tháng tới (giữ chuột để có menu)"; +Calendar._TT["NEXT_YEAR"] = "Ngày tới (giữ chuột để có menu)"; +Calendar._TT["SEL_DATE"] = "Chọn ngày"; +Calendar._TT["DRAG_TO_MOVE"] = "Kéo (drag) để di chuyển"; +Calendar._TT["PART_TODAY"] = " (hôm nay)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Hiển thị %s trước"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Đóng"; +Calendar._TT["TODAY"] = "Hôm nay"; +Calendar._TT["TIME_PART"] = "Click, shift-click hoặc kéo (drag) để đổi giá trị"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Time:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/78/78fa522126cd04585596f66d578c6cf6726da19c.svn-base Binary file .svn/pristine/78/78fa522126cd04585596f66d578c6cf6726da19c.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/7969168ad698630c706b297dcac30bf0e2efbeb8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/7969168ad698630c706b297dcac30bf0e2efbeb8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRepositoriesExtraInfo < ActiveRecord::Migration + def self.up + add_column :repositories, :extra_info, :text + end + + def self.down + remove_column :repositories, :extra_info + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79764e68981f37bed805c67099bd3a957d4119fe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/79764e68981f37bed805c67099bd3a957d4119fe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar EU language +// Author: Ales Zabala Alava (Shagi), +// 2010-01-25 +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Igandea", + "Astelehena", + "Asteartea", + "Asteazkena", + "Osteguna", + "Ostirala", + "Larunbata", + "Igandea"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ig.", + "Al.", + "Ar.", + "Az.", + "Og.", + "Or.", + "La.", + "Ig."); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Urtarrila", + "Otsaila", + "Martxoa", + "Apirila", + "Maiatza", + "Ekaina", + "Uztaila", + "Abuztua", + "Iraila", + "Urria", + "Azaroa", + "Abendua"); + +// short month names +Calendar._SMN = new Array +("Urt", + "Ots", + "Mar", + "Api", + "Mai", + "Eka", + "Uzt", + "Abu", + "Ira", + "Urr", + "Aza", + "Abe"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Egutegiari buruz"; + +Calendar._TT["ABOUT"] = +"DHTML Data/Ordu Hautatzailea\n" + +"(c) dynarch.com 2002-2005 / Egilea: Mihai Bazon\n" + // don't translate this this ;-) +"Azken bertsiorako: http://www.dynarch.com/projects/calendar/\n" + +"GNU LGPL Lizentziapean banatuta. Ikusi http://gnu.org/licenses/lgpl.html zehaztasunentzako." + +"\n\n" + +"Data hautapena:\n" + +"- Erabili \xab, \xbb botoiak urtea hautatzeko\n" + +"- Erabili " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " botoiak hilabeteak hautatzeko\n" + +"- Mantendu saguaren botoia edo goiko edozein botoi hautapena bizkortzeko."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Ordu hautapena:\n" + +"- Klikatu orduaren edozein zati handitzeko\n" + +"- edo Shift-klikatu txikiagotzeko\n" + +"- edo klikatu eta arrastatu hautapena bizkortzeko."; + +Calendar._TT["PREV_YEAR"] = "Aurreko urtea (mantendu menuarentzako)"; +Calendar._TT["PREV_MONTH"] = "Aurreko hilabetea (mantendu menuarentzako)"; +Calendar._TT["GO_TODAY"] = "Joan Gaur-era"; +Calendar._TT["NEXT_MONTH"] = "Hurrengo hilabetea (mantendu menuarentzako)"; +Calendar._TT["NEXT_YEAR"] = "Hurrengo urtea (mantendu menuarentzako)"; +Calendar._TT["SEL_DATE"] = "Data hautatu"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrastatu mugitzeko"; +Calendar._TT["PART_TODAY"] = " (gaur)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Erakutsi %s lehenbizi"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Itxi"; +Calendar._TT["TODAY"] = "Gaur"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikatu edo arrastatu balioa aldatzeko"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Ordua:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/798951d93ef15b8ef54ff1fdd4cd90be5520c718.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/798951d93ef15b8ef54ff1fdd4cd90be5520c718.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%=l(:label_information_plural)%>

    + +

    <%= Redmine::Info.versioned_name %> (<%= @db_adapter_name %>)

    + + +<% @checklist.each do |label, result| %> + + + + +<% end %> +
    <%= l(label) %><%= image_tag((result ? 'true.png' : 'exclamation.png'), + :style => "vertical-align:bottom;") %>
    + +<% html_title(l(:label_information_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79b1009c38524632b578aeb38be15a3765999cb6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/79b1009c38524632b578aeb38be15a3765999cb6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%= link_to l(:label_group_plural), groups_path %> » <%= h(@group) %>

    + +<%= render_tabs group_settings_tabs %> + +<% html_title(l(:label_group), @group, l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79bb908ad22d23e6abf39d03e3cb173a74892f6d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/79bb908ad22d23e6abf39d03e3cb173a74892f6d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +<%= @news.title %> +<%= @news_url %> + +<%= l(:text_user_wrote, :value => @comment.author) %> + +<%= @comment.comments %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79bda21daa58137f510c53ebb565cd2e38301958.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/79bda21daa58137f510c53ebb565cd2e38301958.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +Adrian Schroeter +Andrey Valentinovich Panov +Ben Laenen +Bhikkhu Pesala +Clayborne Arevalo +Dafydd Harries +Danilo Segan +Davide Viti +David Jez +David Lawrence Ramsey +Denis Jacquerye +Dwayne Bailey +Eugeniy Meshcheryakov +Gee Fung Sit +Heikki Lindroos +James Cloos +James Crippen +John Karp +Keenan Pepper +Lars Naesbye Christensen +Mashrab Kuvatov +Mederic Boquien +Michael Everson +Misu Moldovan +Nguyen Thai Ngoc Duy +Ognyan Kulev +Ondrej Koala Vacha +Peter Cernak +Remy Oudompheng +Roozbeh Pournader +Sander Vesik +Stepan Roh +Tavmjong Bah +Tim May +Valentin Stoykov +Vasek Stodulka + +$Id: AUTHORS 1491 2007-01-12 20:40:12Z ben_laenen $ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79c8a939d3701e3feac652838cc1b0649abfd617.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/79c8a939d3701e3feac652838cc1b0649abfd617.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,155 @@ + + + + + + + +
    + +<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %> + <% field = filter[0] + options = filter[1] %> + id="tr_<%= field %>" class="filter"> + + + + +<% end %> +
    + <%= check_box_tag 'f[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %> + + + <%= label_tag "op_#{field}", l(:description_filter), :class => "hidden-for-sighted" %> + <%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), + query.operator_for(field)), :id => "operators_#{field}", + :onchange => "toggle_operator('#{field}');" %> + + + +
    +
    +<%= label_tag('add_filter_select', l(:label_filter_add)) %> +<%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), + :onchange => "add_filter();", + :name => nil %> +
    +<%= hidden_field_tag 'f[]', '' %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79c9603ff88ef6de5f1708e6dfc76222a7bf0271.svn-base Binary file .svn/pristine/79/79c9603ff88ef6de5f1708e6dfc76222a7bf0271.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/79/79ebb49968818fca414e007a7d073ecb0152e756.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/79/79ebb49968818fca414e007a7d073ecb0152e756.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,71 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../../test_helper', __FILE__) + +begin + require 'mocha' + + class SubversionAdapterTest < ActiveSupport::TestCase + + if repository_configured?('subversion') + def setup + @adapter = Redmine::Scm::Adapters::SubversionAdapter.new(self.class.subversion_repository_url) + end + + def test_client_version + v = Redmine::Scm::Adapters::SubversionAdapter.client_version + assert v.is_a?(Array) + end + + def test_scm_version + to_test = { "svn, version 1.6.13 (r1002816)\n" => [1,6,13], + "svn, versione 1.6.13 (r1002816)\n" => [1,6,13], + "1.6.1\n1.7\n1.8" => [1,6,1], + "1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]} + to_test.each do |s, v| + test_scm_version_for(s, v) + end + end + + def test_info_not_nil + assert_not_nil @adapter.info + end + + def test_info_nil + adpt = Redmine::Scm::Adapters::SubversionAdapter.new( + "file:///invalid/invalid/" + ) + assert_nil adpt.info + end + + private + + def test_scm_version_for(scm_version, version) + @adapter.class.expects(:scm_version_from_command_line).returns(scm_version) + assert_equal version, @adapter.class.svn_binary_version + end + else + puts "Subversion test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end + end +rescue LoadError + class SubversionMochaFake < ActiveSupport::TestCase + def test_fake; assert(false, "Requires mocha to run those tests") end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a017fdd06e31fbf6cfa542010617fca4f01cf26.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a017fdd06e31fbf6cfa542010617fca4f01cf26.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,88 @@ +require 'digest/md5' +require 'cgi' + +module GravatarHelper + + # These are the options that control the default behavior of the public + # methods. They can be overridden during the actual call to the helper, + # or you can set them in your environment.rb as such: + # + # # Allow racier gravatars + # GravatarHelper::DEFAULT_OPTIONS[:rating] = 'R' + # + DEFAULT_OPTIONS = { + # The URL of a default image to display if the given email address does + # not have a gravatar. + :default => nil, + + # The default size in pixels for the gravatar image (they're square). + :size => 50, + + # The maximum allowed MPAA rating for gravatars. This allows you to + # exclude gravatars that may be out of character for your site. + :rating => 'PG', + + # The alt text to use in the img tag for the gravatar. Since it's a + # decorational picture, the alt text should be empty according to the + # XHTML specs. + :alt => '', + + # The title text to use for the img tag for the gravatar. + :title => '', + + # The class to assign to the img tag for the gravatar. + :class => 'gravatar', + + # Whether or not to display the gravatars using HTTPS instead of HTTP + :ssl => false, + } + + # The methods that will be made available to your views. + module PublicMethods + + # Return the HTML img tag for the given user's gravatar. Presumes that + # the given user object will respond_to "email", and return the user's + # email address. + def gravatar_for(user, options={}) + gravatar(user.email, options) + end + + # Return the HTML img tag for the given email address's gravatar. + def gravatar(email, options={}) + src = h(gravatar_url(email, options)) + options = DEFAULT_OPTIONS.merge(options) + [:class, :alt, :size, :title].each { |opt| options[opt] = h(options[opt]) } + "\"#{options[:alt]}\"" + end + + # Returns the base Gravatar URL for the given email hash. If ssl evaluates to true, + # a secure URL will be used instead. This is required when the gravatar is to be + # displayed on a HTTPS site. + def gravatar_api_url(hash, ssl=false) + if ssl + "https://secure.gravatar.com/avatar/#{hash}" + else + "http://www.gravatar.com/avatar/#{hash}" + end + end + + # Return the gravatar URL for the given email address. + def gravatar_url(email, options={}) + email_hash = Digest::MD5.hexdigest(email) + options = DEFAULT_OPTIONS.merge(options) + options[:default] = CGI::escape(options[:default]) unless options[:default].nil? + gravatar_api_url(email_hash, options.delete(:ssl)).tap do |url| + opts = [] + [:rating, :size, :default].each do |opt| + unless options[opt].nil? + value = h(options[opt]) + opts << [opt, value].join('=') + end + end + url << "?#{opts.join('&')}" unless opts.empty? + end + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a02a2b52dbb9fec21affbfddb6cc6bab3abeeb7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a02a2b52dbb9fec21affbfddb6cc6bab3abeeb7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +namespace :redmine do + desc "List all permissions and the actions registered with them" + task :permissions => :environment do + puts "Permission Name - controller/action pairs" + Redmine::AccessControl.permissions.sort {|a,b| a.name.to_s <=> b.name.to_s }.each do |permission| + puts ":#{permission.name} - #{permission.actions.join(', ')}" + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a09a663c8bfe9a76d00f982be754422b428c51b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a09a663c8bfe9a76d00f982be754422b428c51b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1061 @@ +# Korean translations for Ruby on Rails +# by Kihyun Yoon(ddumbugie@gmail.com),http://plenum.textcube.com/ +# by John Hwang (jhwang@tavon.org),http://github.com/tavon +# by Yonghwan SO(please insert your email), last update at 2009-09-11 +# by Ki Won Kim(xyz37@naver.com, http://xyz37.blog.me, https://x10.mine.nu/redmine), last update at 2012-02-01 +# last update at 2012-02-02 by Ki Won Kim +ko: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%m/%d" + long: "%Y년 %m월 %d일 (%a)" + + day_names: [일요일, 월요일, 화요일, 수요일, 목요일, 금요일, 토요일] + abbr_day_names: [일, 월, 화, 수, 목, 금, 토] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 1월, 2월, 3월, 4월, 5월, 6월, 7월, 8월, 9월, 10월, 11월, 12월] + abbr_month_names: [~, 1월, 2월, 3월, 4월, 5월, 6월, 7월, 8월, 9월, 10월, 11월, 12월] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d %H:%M:%S" + time: "%H:%M" + short: "%y/%m/%d %H:%M" + long: "%Y년 %B월 %d일, %H시 %M분 %S초 %Z" + am: "오전" + pm: "오후" + + datetime: + distance_in_words: + half_a_minute: "30초" + less_than_x_seconds: + one: "일초 이하" + other: "%{count}초 이하" + x_seconds: + one: "일초" + other: "%{count}초" + less_than_x_minutes: + one: "일분 이하" + other: "%{count}분 이하" + x_minutes: + one: "일분" + other: "%{count}분" + about_x_hours: + one: "약 한시간" + other: "약 %{count}시간" + x_days: + one: "하루" + other: "%{count}일" + about_x_months: + one: "약 한달" + other: "약 %{count}달" + x_months: + one: "한달" + other: "%{count}달" + about_x_years: + one: "약 일년" + other: "약 %{count}년" + over_x_years: + one: "일년 이상" + other: "%{count}년 이상" + almost_x_years: + one: "약 1년" + other: "약 %{count}년" + prompts: + year: "년" + month: "월" + day: "일" + hour: "시" + minute: "분" + second: "초" + + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "." + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "," + # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) + precision: 3 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%u%n" + unit: "₩" + # These three are to override number.format and are optional + separator: "." + delimiter: "," + precision: 0 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + words_connector: ", " + two_words_connector: "과 " + last_word_connector: ", " + sentence_connector: "그리고" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "한개의 오류가 발생해 %{model}을(를) 저장하지 않았습니다." + other: "%{count}개의 오류가 발생해 %{model}을(를) 저장하지 않았습니다." + # The variable :count is also available + body: "다음 항목에 문제가 발견했습니다:" + + messages: + inclusion: "은 목록에 포함되어 있지 않습니다" + exclusion: "은 예약되어 있습니다" + invalid: "은 유효하지 않습니다." + confirmation: "은 확인이 되지 않았습니다" + accepted: "은 인정되어야 합니다" + empty: "은 길이가 0이어서는 안됩니다." + blank: "은 빈 값이어서는 안 됩니다" + too_long: "은 너무 깁니다 (최대 %{count}자 까지)" + too_short: "은 너무 짧습니다 (최소 %{count}자 까지)" + wrong_length: "은 길이가 틀렸습니다 (%{count}자이어야 합니다.)" + taken: "은 이미 선택된 겁니다" + not_a_number: "은 숫자가 아닙니다" + greater_than: "은 %{count}보다 커야 합니다." + greater_than_or_equal_to: "은 %{count}보다 크거나 같아야 합니다" + equal_to: "은 %{count}(와)과 같아야 합니다" + less_than: "은 %{count}보다 작어야 합니다" + less_than_or_equal_to: "은 %{count}과 같거나 이하을 요구합니다" + odd: "은 홀수여야 합니다" + even: "은 짝수여야 합니다" + greater_than_start_date: "는 시작날짜보다 커야 합니다" + not_same_project: "는 같은 프로젝트에 속해 있지 않습니다" + circular_dependency: "이 관계는 순환 의존관계를 만들 수 있습니다" + cant_link_an_issue_with_a_descendant: "일감은 그것의 하위 일감과 연결할 수 없습니다." + + actionview_instancetag_blank_option: 선택하세요 + + general_text_No: '아니오' + general_text_Yes: '예' + general_text_no: '아니오' + general_text_yes: '예' + general_lang_name: '한국어(Korean)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: CP949 + general_pdf_encoding: CP949 + general_first_day_of_week: '7' + + notice_account_updated: 계정이 성공적으로 변경되었습니다. + notice_account_invalid_creditentials: 잘못된 계정 또는 비밀번호 + notice_account_password_updated: 비밀번호가 잘 변경되었습니다. + notice_account_wrong_password: 잘못된 비밀번호 + notice_account_register_done: 계정이 잘 만들어졌습니다. 계정을 활성화하시려면 받은 메일의 링크를 클릭해주세요. + notice_account_unknown_email: 알려지지 않은 사용자. + notice_can_t_change_password: 이 계정은 외부 인증을 이용합니다. 비밀번호를 변경할 수 없습니다. + notice_account_lost_email_sent: 새로운 비밀번호를 위한 메일이 발송되었습니다. + notice_account_activated: 계정이 활성화되었습니다. 이제 로그인 하실수 있습니다. + notice_successful_create: 생성 성공. + notice_successful_update: 변경 성공. + notice_successful_delete: 삭제 성공. + notice_successful_connection: 연결 성공. + notice_file_not_found: 요청하신 페이지는 삭제되었거나 옮겨졌습니다. + notice_locking_conflict: 다른 사용자에 의해서 데이터가 변경되었습니다. + notice_not_authorized: 이 페이지에 접근할 권한이 없습니다. + notice_email_sent: "%{value}님에게 메일이 발송되었습니다." + notice_email_error: "메일을 전송하는 과정에 오류가 발생했습니다. (%{value})" + notice_feeds_access_key_reseted: RSS에 접근가능한 열쇠(key)가 생성되었습니다. + notice_failed_to_save_issues: "저장에 실패하였습니다: 실패 %{count}(선택 %{total}): %{ids}." + notice_no_issue_selected: "일감이 선택되지 않았습니다. 수정하기 원하는 일감을 선택하세요" + notice_account_pending: "계정이 만들어졌으며 관리자 승인 대기중입니다." + notice_default_data_loaded: 기본값을 성공적으로 읽어들였습니다. + notice_unable_delete_version: 삭제할 수 없는 버전입니다. + + error_can_t_load_default_data: "기본값을 읽어들일 수 없습니다.: %{value}" + error_scm_not_found: 항목이나 리비젼이 저장소에 존재하지 않습니다. + error_scm_command_failed: "저장소에 접근하는 도중에 오류가 발생하였습니다.: %{value}" + error_scm_annotate: "항목이 없거나 행별 이력을 볼 수 없습니다." + error_issue_not_found_in_project: '일감이 없거나 이 프로젝트의 것이 아닙니다.' + + warning_attachments_not_saved: "%{count}개 파일을 저장할 수 없습니다." + + mail_subject_lost_password: "%{value} 비밀번호" + mail_body_lost_password: '비밀번호를 변경하려면 다음 링크를 클릭하세요.' + mail_subject_register: "%{value} 계정 활성화" + mail_body_register: '계정을 활성화하려면 링크를 클릭하세요.:' + mail_body_account_information_external: "로그인할 때 %{value} 계정을 사용하실 수 있습니다." + mail_body_account_information: 계정 정보 + mail_subject_account_activation_request: "%{value} 계정 활성화 요청" + mail_body_account_activation_request: "새 사용자(%{value})가 등록되었습니다. 관리자님의 승인을 기다리고 있습니다.:" + mail_body_reminder: "당신이 맡고 있는 일감 %{count}개의 완료 기한이 %{days}일 후 입니다." + mail_subject_reminder: "내일이 만기인 일감 %{count}개 (%{days})" + mail_subject_wiki_content_added: "위키페이지 '%{id}'이(가) 추가되었습니다." + mail_subject_wiki_content_updated: "'위키페이지 %{id}'이(가) 수정되었습니다." + mail_body_wiki_content_added: "%{author}이(가) 위키페이지 '%{id}'을(를) 추가하였습니다." + mail_body_wiki_content_updated: "%{author}이(가) 위키페이지 '%{id}'을(를) 수정하였습니다." + + gui_validation_error: 에러 + gui_validation_error_plural: "%{count}개 에러" + + field_name: 이름 + field_description: 설명 + field_summary: 요약 + field_is_required: 필수 + field_firstname: 이름 + field_lastname: 성 + field_mail: 메일 + field_filename: 파일 + field_filesize: 크기 + field_downloads: 다운로드 + field_author: 저자 + field_created_on: 등록 + field_updated_on: 변경 + field_field_format: 형식 + field_is_for_all: 모든 프로젝트 + field_possible_values: 가능한 값들 + field_regexp: 정규식 + field_min_length: 최소 길이 + field_max_length: 최대 길이 + field_value: 값 + field_category: 범주 + field_title: 제목 + field_project: 프로젝트 + field_issue: 일감 + field_status: 상태 + field_notes: 덧글 + field_is_closed: 완료 상태 + field_is_default: 기본값 + field_tracker: 유형 + field_subject: 제목 + field_due_date: 완료 기한 + field_assigned_to: 담당자 + field_priority: 우선순위 + field_fixed_version: 목표버전 + field_user: 사용자 + field_role: 역할 + field_homepage: 홈페이지 + field_is_public: 공개 + field_parent: 상위 프로젝트 + field_is_in_roadmap: 로드맵에 표시 + field_login: 로그인 + field_mail_notification: 메일 알림 + field_admin: 관리자 + field_last_login_on: 마지막 로그인 + field_language: 언어 + field_effective_date: 날짜 + field_password: 비밀번호 + field_new_password: 새 비밀번호 + field_password_confirmation: 비밀번호 확인 + field_version: 버전 + field_type: 방식 + field_host: 호스트 + field_port: 포트 + field_account: 계정 + field_base_dn: 기본 DN + field_attr_login: 로그인 속성 + field_attr_firstname: 이름 속성 + field_attr_lastname: 성 속성 + field_attr_mail: 메일 속성 + field_onthefly: 동적 사용자 생성 + field_start_date: 시작시간 + field_done_ratio: 진척도 + field_auth_source: 인증 공급자 + field_hide_mail: 메일 주소 숨기기 + field_comments: 설명 + field_url: URL + field_start_page: 첫 페이지 + field_subproject: 하위 프로젝트 + field_hours: 시간 + field_activity: 작업종류 + field_spent_on: 작업시간 + field_identifier: 식별자 + field_is_filter: 검색조건으로 사용됨 + field_issue_to_id: 연관된 일감 + field_delay: 지연 + field_assignable: 이 역할에게 일감을 맡길 수 있음 + field_redirect_existing_links: 기존의 링크로 돌려보냄(redirect) + field_estimated_hours: 추정시간 + field_column_names: 컬럼 + field_default_value: 기본값 + field_time_zone: 시간대 + field_searchable: 검색가능 + field_comments_sorting: 댓글 정렬 + field_parent_title: 상위 제목 + field_editable: 편집가능 + field_watcher: 일감지킴이 + field_identity_url: OpenID URL + field_content: 내용 + field_group_by: 결과를 묶어 보여줄 기준 + + setting_app_title: 레드마인 제목 + setting_app_subtitle: 레드마인 부제목 + setting_welcome_text: 환영 메시지 + setting_default_language: 기본 언어 + setting_login_required: 인증이 필요함 + setting_self_registration: 사용자 직접등록 + setting_attachment_max_size: 최대 첨부파일 크기 + setting_issues_export_limit: 일감 내보내기 제한 + setting_mail_from: 발신 메일 주소 + setting_bcc_recipients: 참조자들을 bcc로 숨기기 + setting_plain_text_mail: 텍스트만 (HTML 없이) + setting_host_name: 호스트 이름과 경로 + setting_text_formatting: 본문 형식 + setting_wiki_compression: 위키 이력 압축 + setting_feeds_limit: 피드에 포함할 항목의 수 + setting_default_projects_public: 새 프로젝트를 공개로 설정 + setting_autofetch_changesets: 제출(commit)된 변경묶음을 자동으로 가져오기 + setting_sys_api_enabled: 저장소 관리에 WS를 사용 + setting_commit_ref_keywords: 일감 참조에 사용할 키워드들 + setting_commit_fix_keywords: 일감 해결에 사용할 키워드들 + setting_autologin: 자동 로그인 + setting_date_format: 날짜 형식 + setting_time_format: 시간 형식 + setting_cross_project_issue_relations: 다른 프로젝트의 일감과 연결하는 것을 허용 + setting_issue_list_default_columns: 일감 목록에 표시할 항목 + setting_emails_footer: 메일 꼬리 + setting_protocol: 프로토콜 + setting_per_page_options: 목록에서, 한 페이지에 표시할 행 + setting_user_format: 사용자 표시 형식 + setting_activity_days_default: 프로젝트 작업내역에 표시할 기간 + setting_display_subprojects_issues: 하위 프로젝트의 일감을 함께 표시 + setting_enabled_scm: "지원할 SCM(Source Control Management)" + setting_mail_handler_api_enabled: 수신 메일에 WS를 허용 + setting_mail_handler_api_key: API 키 + setting_sequential_project_identifiers: 프로젝트 식별자를 순차적으로 생성 + setting_gravatar_enabled: 그라바타 사용자 아이콘 사용 + setting_diff_max_lines_displayed: 차이점(diff) 보기에 표시할 최대 줄수 + setting_repository_log_display_limit: 저장소 보기에 표시할 개정판 이력의 최대 갯수 + setting_file_max_size_displayed: 바로 보여줄 텍스트파일의 최대 크기 + setting_openid: OpenID 로그인과 등록 허용 + setting_password_min_length: 최소 암호 길이 + setting_new_project_user_role_id: 프로젝트를 만든 사용자에게 주어질 역할 + + permission_add_project: 프로젝트 생성 + permission_edit_project: 프로젝트 편집 + permission_select_project_modules: 프로젝트 모듈 선택 + permission_manage_members: 구성원 관리 + permission_manage_versions: 버전 관리 + permission_manage_categories: 일감 범주 관리 + permission_add_issues: 일감 추가 + permission_edit_issues: 일감 편집 + permission_manage_issue_relations: 일감 관계 관리 + permission_add_issue_notes: 덧글 추가 + permission_edit_issue_notes: 덧글 편집 + permission_edit_own_issue_notes: 내 덧글 편집 + permission_move_issues: 일감 이동 + permission_delete_issues: 일감 삭제 + permission_manage_public_queries: 공용 검색양식 관리 + permission_save_queries: 검색양식 저장 + permission_view_gantt: Gantt차트 보기 + permission_view_calendar: 달력 보기 + permission_view_issue_watchers: 일감지킴이 보기 + permission_add_issue_watchers: 일감지킴이 추가 + permission_log_time: 작업시간 기록 + permission_view_time_entries: 시간입력 보기 + permission_edit_time_entries: 시간입력 편집 + permission_edit_own_time_entries: 내 시간입력 편집 + permission_manage_news: 뉴스 관리 + permission_comment_news: 뉴스에 댓글달기 + permission_manage_documents: 문서 관리 + permission_view_documents: 문서 보기 + permission_manage_files: 파일관리 + permission_view_files: 파일보기 + permission_manage_wiki: 위키 관리 + permission_rename_wiki_pages: 위키 페이지 이름변경 + permission_delete_wiki_pages: 위치 페이지 삭제 + permission_view_wiki_pages: 위키 보기 + permission_view_wiki_edits: 위키 기록 보기 + permission_edit_wiki_pages: 위키 페이지 편집 + permission_delete_wiki_pages_attachments: 첨부파일 삭제 + permission_protect_wiki_pages: 프로젝트 위키 페이지 + permission_manage_repository: 저장소 관리 + permission_browse_repository: 저장소 둘러보기 + permission_view_changesets: 변경묶음보기 + permission_commit_access: 변경로그 보기 + permission_manage_boards: 게시판 관리 + permission_view_messages: 메시지 보기 + permission_add_messages: 메시지 추가 + permission_edit_messages: 메시지 편집 + permission_edit_own_messages: 자기 메시지 편집 + permission_delete_messages: 메시지 삭제 + permission_delete_own_messages: 자기 메시지 삭제 + + project_module_issue_tracking: 일감관리 + project_module_time_tracking: 시간추적 + project_module_news: 뉴스 + project_module_documents: 문서 + project_module_files: 파일 + project_module_wiki: 위키 + project_module_repository: 저장소 + project_module_boards: 게시판 + + label_user: 사용자 + label_user_plural: 사용자 + label_user_new: 새 사용자 + label_project: 프로젝트 + label_project_new: 새 프로젝트 + label_project_plural: 프로젝트 + label_x_projects: + zero: 없음 + one: "한 프로젝트" + other: "%{count}개 프로젝트" + label_project_all: 모든 프로젝트 + label_project_latest: 최근 프로젝트 + label_issue: 일감 + label_issue_new: 새 일감만들기 + label_issue_plural: 일감 + label_issue_view_all: 모든 일감 보기 + label_issues_by: "%{value}별 일감" + label_issue_added: 일감 추가 + label_issue_updated: 일감 수정 + label_document: 문서 + label_document_new: 새 문서 + label_document_plural: 문서 + label_document_added: 문서 추가 + label_role: 역할 + label_role_plural: 역할 + label_role_new: 새 역할 + label_role_and_permissions: 역할 및 권한 + label_member: 담당자 + label_member_new: 새 담당자 + label_member_plural: 담당자 + label_tracker: 일감 유형 + label_tracker_plural: 일감 유형 + label_tracker_new: 새 일감 유형 + label_workflow: 업무흐름 + label_issue_status: 일감 상태 + label_issue_status_plural: 일감 상태 + label_issue_status_new: 새 일감 상태 + label_issue_category: 일감 범주 + label_issue_category_plural: 일감 범주 + label_issue_category_new: 새 일감 범주 + label_custom_field: 사용자 정의 항목 + label_custom_field_plural: 사용자 정의 항목 + label_custom_field_new: 새 사용자 정의 항목 + label_enumerations: 코드값 + label_enumeration_new: 새 코드값 + label_information: 정보 + label_information_plural: 정보 + label_please_login: 로그인하세요. + label_register: 등록 + label_login_with_open_id_option: 또는 OpenID로 로그인 + label_password_lost: 비밀번호 찾기 + label_home: 초기화면 + label_my_page: 내 페이지 + label_my_account: 내 계정 + label_my_projects: 내 프로젝트 + label_administration: 관리 + label_login: 로그인 + label_logout: 로그아웃 + label_help: 도움말 + label_reported_issues: 보고한 일감 + label_assigned_to_me_issues: 내가 맡은 일감 + label_last_login: 마지막 접속 + label_registered_on: 등록시각 + label_activity: 작업내역 + label_overall_activity: 전체 작업내역 + label_user_activity: "%{value}의 작업내역" + label_new: 새로 만들기 + label_logged_as: '로그인계정:' + label_environment: 환경 + label_authentication: 인증 + label_auth_source: 인증 공급자 + label_auth_source_new: 새 인증 공급자 + label_auth_source_plural: 인증 공급자 + label_subproject_plural: 하위 프로젝트 + label_and_its_subprojects: "%{value}와 하위 프로젝트들" + label_min_max_length: 최소 - 최대 길이 + label_list: 목록 + label_date: 날짜 + label_integer: 정수 + label_float: 부동소수 + label_boolean: 부울린 + label_string: 문자열 + label_text: 텍스트 + label_attribute: 속성 + label_attribute_plural: 속성 + label_download: "%{count}회 다운로드" + label_download_plural: "%{count}회 다운로드" + label_no_data: 표시할 데이터가 없습니다. + label_change_status: 상태 변경 + label_history: 이력 + label_attachment: 파일 + label_attachment_new: 파일추가 + label_attachment_delete: 파일삭제 + label_attachment_plural: 파일 + label_file_added: 파일 추가 + label_report: 보고서 + label_report_plural: 보고서 + label_news: 뉴스 + label_news_new: 새 뉴스 + label_news_plural: 뉴스 + label_news_latest: 최근 뉴스 + label_news_view_all: 모든 뉴스 + label_news_added: 뉴스 추가 + label_settings: 설정 + label_overview: 개요 + label_version: 버전 + label_version_new: 새 버전 + label_version_plural: 버전 + label_confirmation: 확인 + label_export_to: 내보내기 + label_read: 읽기... + label_public_projects: 공개 프로젝트 + label_open_issues: 진행중 + label_open_issues_plural: 진행중 + label_closed_issues: 완료됨 + label_closed_issues_plural: 완료됨 + label_x_open_issues_abbr_on_total: + zero: "총 %{total} 건 모두 완료" + one: "한 건 진행 중 / 총 %{total} 건 중 " + other: "%{count} 건 진행 중 / 총 %{total} 건" + label_x_open_issues_abbr: + zero: 모두 완료 + one: 한 건 진행 중 + other: "%{count} 건 진행 중" + label_x_closed_issues_abbr: + zero: 모두 미완료 + one: 한 건 완료 + other: "%{count} 건 완료" + label_total: 합계 + label_permissions: 권한 + label_current_status: 일감 상태 + label_new_statuses_allowed: 허용되는 일감 상태 + label_all: 모두 + label_none: 없음 + label_nobody: 미지정 + label_next: 다음 + label_previous: 뒤로 + label_used_by: 사용됨 + label_details: 자세히 + label_add_note: 일감덧글 추가 + label_per_page: 페이지별 + label_calendar: 달력 + label_months_from: 개월 동안 | 다음부터 + label_gantt: Gantt 챠트 + label_internal: 내부 + label_last_changes: "최근 %{count}개의 변경사항" + label_change_view_all: 모든 변경 내역 보기 + label_personalize_page: 입맛대로 구성하기 + label_comment: 댓글 + label_comment_plural: 댓글 + label_x_comments: + zero: 댓글 없음 + one: 한 개의 댓글 + other: "%{count} 개의 댓글" + label_comment_add: 댓글 추가 + label_comment_added: 댓글이 추가되었습니다. + label_comment_delete: 댓글 삭제 + label_query: 검색양식 + label_query_plural: 검색양식 + label_query_new: 새 검색양식 + label_filter_add: 검색조건 추가 + label_filter_plural: 검색조건 + label_equals: 이다 + label_not_equals: 아니다 + label_in_less_than: 이내 + label_in_more_than: 이후 + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + label_in: 이내 + label_today: 오늘 + label_all_time: 모든 시간 + label_yesterday: 어제 + label_this_week: 이번주 + label_last_week: 지난 주 + label_last_n_days: "지난 %{count} 일" + label_this_month: 이번 달 + label_last_month: 지난 달 + label_this_year: 올해 + label_date_range: 날짜 범위 + label_less_than_ago: 이전 + label_more_than_ago: 이후 + label_ago: 일 전 + label_contains: 포함되는 키워드 + label_not_contains: 포함하지 않는 키워드 + label_day_plural: 일 + label_repository: 저장소 + label_repository_plural: 저장소 + label_browse: 저장소 둘러보기 + label_modification: "%{count} 변경" + label_modification_plural: "%{count} 변경" + label_revision: 개정판 + label_revision_plural: 개정판 + label_associated_revisions: 관련된 개정판들 + label_added: 추가됨 + label_modified: 변경됨 + label_copied: 복사됨 + label_renamed: 이름바뀜 + label_deleted: 삭제됨 + label_latest_revision: 최근 개정판 + label_latest_revision_plural: 최근 개정판 + label_view_revisions: 개정판 보기 + label_max_size: 최대 크기 + label_sort_highest: 맨 위로 + label_sort_higher: 위로 + label_sort_lower: 아래로 + label_sort_lowest: 맨 아래로 + label_roadmap: 로드맵 + label_roadmap_due_in: "기한 %{value}" + label_roadmap_overdue: "%{value} 지연" + label_roadmap_no_issues: 이 버전에 해당하는 일감 없음 + label_search: 검색 + label_result_plural: 결과 + label_all_words: 모든 단어 + label_wiki: 위키 + label_wiki_edit: 위키 편집 + label_wiki_edit_plural: 위키 편집 + label_wiki_page: 위키 페이지 + label_wiki_page_plural: 위키 페이지 + label_index_by_title: 제목별 색인 + label_index_by_date: 날짜별 색인 + label_current_version: 현재 버전 + label_preview: 미리보기 + label_feed_plural: 피드(Feeds) + label_changes_details: 모든 상세 변경 내역 + label_issue_tracking: 일감 추적 + label_spent_time: 소요 시간 + label_f_hour: "%{value} 시간" + label_f_hour_plural: "%{value} 시간" + label_time_tracking: 시간추적 + label_change_plural: 변경사항들 + label_statistics: 통계 + label_commits_per_month: 월별 제출 내역 + label_commits_per_author: 저자별 제출 내역 + label_view_diff: 차이점 보기 + label_diff_inline: 한줄로 + label_diff_side_by_side: 두줄로 + label_options: 옵션 + label_copy_workflow_from: 업무흐름 복사하기 + label_permissions_report: 권한 보고서 + label_watched_issues: 지켜보고 있는 일감 + label_related_issues: 연결된 일감 + label_applied_status: 적용된 상태 + label_loading: 읽는 중... + label_relation_new: 새 관계 + label_relation_delete: 관계 지우기 + label_relates_to: "다음 일감과 관련됨:" + label_duplicates: "다음 일감과 겹침:" + label_duplicated_by: "다음 일감과 겹침:" + label_blocks: "다음 일감의 해결을 막고 있음:" + label_blocked_by: "다음 일감에게 막혀 있음:" + label_precedes: "다음에 진행할 일감:" + label_follows: "다음 일감을 우선 진행:" + label_end_to_start: "끝에서 시작" + label_end_to_end: "끝에서 끝" + label_start_to_start: "시작에서 시작" + label_start_to_end: "시작에서 끝" + label_stay_logged_in: 로그인 유지 + label_disabled: 비활성화 + label_show_completed_versions: 완료된 버전 보기 + label_me: 나 + label_board: 게시판 + label_board_new: 새 게시판 + label_board_plural: 게시판 + label_topic_plural: 주제 + label_message_plural: 글 + label_message_last: 마지막 글 + label_message_new: 새글쓰기 + label_message_posted: 글 추가 + label_reply_plural: 답글 + label_send_information: 사용자에게 계정정보를 보내기 + label_year: 년 + label_month: 월 + label_week: 주 + label_date_from: '기간:' + label_date_to: ' ~ ' + label_language_based: 언어설정에 따름 + label_sort_by: "%{value}(으)로 정렬" + label_send_test_email: 테스트 메일 보내기 + label_feeds_access_key_created_on: "피드 접근 키가 %{value} 이전에 생성되었습니다." + label_module_plural: 모듈 + label_added_time_by: "%{author}이(가) %{age} 전에 추가함" + label_updated_time_by: "%{author}이(가) %{age} 전에 변경" + label_updated_time: "%{value} 전에 수정됨" + label_jump_to_a_project: 프로젝트 바로가기 + label_file_plural: 파일 + label_changeset_plural: 변경묶음 + label_default_columns: 기본 컬럼 + label_no_change_option: (수정 안함) + label_bulk_edit_selected_issues: 선택된 일감들을 한꺼번에 수정하기 + label_theme: 테마 + label_default: 기본 + label_search_titles_only: 제목에서만 찾기 + label_user_mail_option_all: "내가 속한 프로젝트로들부터 모든 메일 받기" + label_user_mail_option_selected: "선택한 프로젝트들로부터 모든 메일 받기.." + label_user_mail_no_self_notified: "내가 만든 변경사항들에 대해서는 알림메일을 받지 않습니다." + label_registration_activation_by_email: 메일로 계정을 활성화하기 + label_registration_automatic_activation: 자동 계정 활성화 + label_registration_manual_activation: 수동 계정 활성화 + label_display_per_page: "페이지당 줄수: %{value}" + label_age: 마지막 수정일 + label_change_properties: 속성 변경 + label_general: 일반 + label_more: 제목 및 설명 수정 + label_scm: 형상관리시스템 + label_plugins: 플러그인 + label_ldap_authentication: LDAP 인증 + label_downloads_abbr: D/L + label_optional_description: 부가적인 설명 + label_add_another_file: 다른 파일 추가 + label_preferences: 설정 + label_chronological_order: 시간 순으로 정렬 + label_reverse_chronological_order: 시간 역순으로 정렬 + label_planning: 프로젝트계획 + label_incoming_emails: 수신 메일 + label_generate_key: 키 생성 + label_issue_watchers: 일감지킴이 + label_example: 예 + label_display: 표시방식 + label_sort: 정렬 + label_ascending: 오름차순 + label_descending: 내림차순 + label_date_from_to: "%{start}부터 %{end}까지" + label_wiki_content_added: 위키페이지 추가 + label_wiki_content_updated: 위키페이지 수정 + + button_login: 로그인 + button_submit: 확인 + button_save: 저장 + button_check_all: 모두선택 + button_uncheck_all: 선택해제 + button_delete: 삭제 + button_create: 만들기 + button_create_and_continue: 만들고 계속하기 + button_test: 테스트 + button_edit: 편집 + button_add: 추가 + button_change: 변경 + button_apply: 적용 + button_clear: 지우기 + button_lock: 잠금 + button_unlock: 잠금해제 + button_download: 다운로드 + button_list: 목록 + button_view: 보기 + button_move: 이동 + button_back: 뒤로 + button_cancel: 취소 + button_activate: 활성화 + button_sort: 정렬 + button_log_time: 작업시간 기록 + button_rollback: 이 버전으로 되돌리기 + button_watch: 지켜보기 + button_unwatch: 관심끄기 + button_reply: 답글 + button_archive: 잠금보관 + button_unarchive: 잠금보관해제 + button_reset: 초기화 + button_rename: 이름바꾸기 + button_change_password: 비밀번호 바꾸기 + button_copy: 복사 + button_annotate: 이력해설 + button_update: 수정 + button_configure: 설정 + button_quote: 댓글달기 + + status_active: 사용중 + status_registered: 등록대기 + status_locked: 잠김 + + text_select_mail_notifications: 알림메일이 필요한 작업을 선택하세요. + text_regexp_info: 예) ^[A-Z0-9]+$ + text_min_max_length_info: 0 는 제한이 없음을 의미함 + text_project_destroy_confirmation: 이 프로젝트를 삭제하고 모든 데이터를 지우시겠습니까? + text_subprojects_destroy_warning: "하위 프로젝트(%{value})이(가) 자동으로 지워질 것입니다." + text_workflow_edit: 업무흐름 수정하려면 역할과 일감유형을 선택하세요. + text_are_you_sure: 계속 진행 하시겠습니까? + text_tip_issue_begin_day: 오늘 시작하는 업무(task) + text_tip_issue_end_day: 오늘 종료하는 업무(task) + text_tip_issue_begin_end_day: 오늘 시작하고 종료하는 업무(task) + text_project_identifier_info: '영문 소문자(a-z) 및 숫자, 대쉬(-) 가능.
    저장된후에는 식별자 변경 불가능.' + text_caracters_maximum: "최대 %{count} 글자 가능" + text_caracters_minimum: "최소한 %{count} 글자 이상이어야 합니다." + text_length_between: "%{min} 에서 %{max} 글자" + text_tracker_no_workflow: 이 일감 유형에는 업무흐름이 정의되지 않았습니다. + text_unallowed_characters: 허용되지 않는 문자열 + text_comma_separated: "구분자','를 이용해서 여러 개의 값을 입력할 수 있습니다." + text_issues_ref_in_commit_messages: 제출 메시지에서 일감을 참조하거나 해결하기 + text_issue_added: "%{author}이(가) 일감 %{id}을(를) 보고하였습니다." + text_issue_updated: "%{author}이(가) 일감 %{id}을(를) 수정하였습니다." + text_wiki_destroy_confirmation: 이 위키와 모든 내용을 지우시겠습니까? + text_issue_category_destroy_question: "일부 일감들(%{count}개)이 이 범주에 지정되어 있습니다. 어떻게 하시겠습니까?" + text_issue_category_destroy_assignments: 범주 지정 지우기 + text_issue_category_reassign_to: 일감을 이 범주에 다시 지정하기 + text_user_mail_option: "선택하지 않은 프로젝트에서도, 지켜보는 중이거나 속해있는 사항(일감을 발행했거나 할당된 경우)이 있으면 알림메일을 받게 됩니다." + text_no_configuration_data: "역할, 일감 유형, 일감 상태들과 업무흐름이 아직 설정되지 않았습니다.\n기본 설정을 읽어들이는 것을 권장합니다. 읽어들인 후에 수정할 수 있습니다." + text_load_default_configuration: 기본 설정을 읽어들이기 + text_status_changed_by_changeset: "변경묶음 %{value}에 의하여 변경됨" + text_issues_destroy_confirmation: '선택한 일감을 정말로 삭제하시겠습니까?' + text_select_project_modules: '이 프로젝트에서 활성화시킬 모듈을 선택하세요:' + text_default_administrator_account_changed: 기본 관리자 계정이 변경 + text_file_repository_writable: 파일 저장소 쓰기 가능 + text_plugin_assets_writable: 플러그인 전용 디렉토리가 쓰기 가능 + text_rmagick_available: RMagick 사용 가능 (선택적) + text_destroy_time_entries_question: 삭제하려는 일감에 %{hours} 시간이 보고되어 있습니다. 어떻게 하시겠습니까? + text_destroy_time_entries: 보고된 시간을 삭제하기 + text_assign_time_entries_to_project: 보고된 시간을 프로젝트에 할당하기 + text_reassign_time_entries: '이 알림에 보고된 시간을 재할당하기:' + text_user_wrote: "%{value}의 덧글:" + text_enumeration_category_reassign_to: '새로운 값을 설정:' + text_enumeration_destroy_question: "%{count} 개의 일감이 이 값을 사용하고 있습니다." + text_email_delivery_not_configured: "이메일 전달이 설정되지 않았습니다. 그래서 알림이 비활성화되었습니다.\n SMTP서버를 config/configuration.yml에서 설정하고 어플리케이션을 다시 시작하십시오. 그러면 동작합니다." + text_repository_usernames_mapping: "저장소 로그에서 발견된 각 사용자에 레드마인 사용자를 업데이트할때 선택합니다.\n레드마인과 저장소의 이름이나 이메일이 같은 사용자가 자동으로 연결됩니다." + text_diff_truncated: '... 이 차이점은 표시할 수 있는 최대 줄수를 초과해서 이 차이점은 잘렸습니다.' + text_custom_field_possible_values_info: '각 값 당 한 줄' + text_wiki_page_destroy_question: 이 페이지는 %{descendants} 개의 하위 페이지와 관련 내용이 있습니다. 이 내용을 어떻게 하시겠습니까? + text_wiki_page_nullify_children: 하위 페이지를 최상위 페이지 아래로 지정 + text_wiki_page_destroy_children: 모든 하위 페이지와 관련 내용을 삭제 + text_wiki_page_reassign_children: 하위 페이지를 이 페이지 아래로 지정 + + default_role_manager: 관리자 + default_role_developer: 개발자 + default_role_reporter: 보고자 + default_tracker_bug: 결함 + default_tracker_feature: 새기능 + default_tracker_support: 지원 + default_issue_status_new: 신규 + default_issue_status_in_progress: 진행 + default_issue_status_resolved: 해결 + default_issue_status_feedback: 의견 + default_issue_status_closed: 완료 + default_issue_status_rejected: 거절 + default_doc_category_user: 사용자 문서 + default_doc_category_tech: 기술 문서 + default_priority_low: 낮음 + default_priority_normal: 보통 + default_priority_high: 높음 + default_priority_urgent: 긴급 + default_priority_immediate: 즉시 + default_activity_design: 설계 + default_activity_development: 개발 + + enumeration_issue_priorities: 일감 우선순위 + enumeration_doc_categories: 문서 범주 + enumeration_activities: 작업분류(시간추적) + + field_issue_to: 관련 일감 + label_view_all_revisions: 모든 개정판 표시 + label_tag: 표지(票識)저장소 + label_branch: 분기(分岐)저장소 + error_no_tracker_in_project: 사용할 수 있도록 설정된 일감 유형이 없습니다. 프로젝트 설정을 확인하십시오. + error_no_default_issue_status: '기본 상태가 정해져 있지 않습니다. 설정을 확인하십시오. (주 메뉴의 "관리" -> "일감 상태")' + text_journal_changed: "%{label}을(를) %{old}에서 %{new}(으)로 변경되었습니다." + text_journal_set_to: "%{label}을(를) %{value}(으)로 지정되었습니다." + text_journal_deleted: "%{label} 값이 지워졌습니다. (%{old})" + label_group_plural: 그룹 + label_group: 그룹 + label_group_new: 새 그룹 + label_time_entry_plural: 작업시간 + text_journal_added: "%{label}에 %{value}이(가) 추가되었습니다." + field_active: 사용중 + enumeration_system_activity: 시스템 작업 + permission_delete_issue_watchers: 일감지킴이 지우기 + version_status_closed: 닫힘 + version_status_locked: 잠김 + version_status_open: 진행 + error_can_not_reopen_issue_on_closed_version: 닫힌 버전에 할당된 일감은 다시 재발생시킬 수 없습니다. + label_user_anonymous: 이름없음 + button_move_and_follow: 이동하고 따라가기 + setting_default_projects_modules: 새 프로젝트에 기본적으로 활성화될 모듈 + setting_gravatar_default: 기본 그라바타 이미지 + field_sharing: 공유 + label_version_sharing_hierarchy: 상위 및 하위 프로젝트 + label_version_sharing_system: 모든 프로젝트 + label_version_sharing_descendants: 하위 프로젝트 + label_version_sharing_tree: 최상위 및 모든 하위 프로젝트 + label_version_sharing_none: 공유없음 + error_can_not_archive_project: 이 프로젝트를 잠금보관할 수 없습니다. + button_duplicate: 복제 + button_copy_and_follow: 복사하고 따라가기 + label_copy_source: 원본 + setting_issue_done_ratio: 일감의 진척도 계산방법 + setting_issue_done_ratio_issue_status: 일감 상태를 사용하기 + error_issue_done_ratios_not_updated: 일감 진척도가 수정되지 않았습니다. + error_workflow_copy_target: 대상 일감유형과 역할을 선택하세요. + setting_issue_done_ratio_issue_field: 일감 수정에서 진척도 입력하기 + label_copy_same_as_target: 대상과 같음. + label_copy_target: 대상 + notice_issue_done_ratios_updated: 일감 진척도가 수정되었습니다. + error_workflow_copy_source: 원본 일감유형이나 역할을 선택하세요. + label_update_issue_done_ratios: 모든 일감 진척도 갱신하기 + setting_start_of_week: 달력 시작 요일 + permission_view_issues: 일감 보기 + label_display_used_statuses_only: 이 일감유형에서 사용되는 상태만 보여주기 + label_revision_id: 개정판 %{value} + label_api_access_key: API 접근키 + label_api_access_key_created_on: API 접근키가 %{value} 전에 생성되었습니다. + label_feeds_access_key: RSS 접근키 + notice_api_access_key_reseted: API 접근키가 초기화되었습니다. + setting_rest_api_enabled: REST 웹서비스 활성화 + label_missing_api_access_key: API 접근키가 없습니다. + label_missing_feeds_access_key: RSS 접근키가 없습니다. + button_show: 보기 + text_line_separated: 여러 값이 허용됨(값 마다 한 줄씩) + setting_mail_handler_body_delimiters: 메일 본문 구분자 + permission_add_subprojects: 하위 프로젝트 만들기 + label_subproject_new: 새 하위 프로젝트 + text_own_membership_delete_confirmation: |- + 권한들 일부 또는 전부를 막 삭제하려고 하고 있습니다. 그렇게 되면 이 프로젝트를 더이상 수정할 수 없게 됩니다. + 계속하시겠습니까? + label_close_versions: 완료된 버전 닫기 + label_board_sticky: 붙박이 + label_board_locked: 잠금 + permission_export_wiki_pages: 위키 페이지 내보내기 + setting_cache_formatted_text: 형식을 가진 텍스트 빠른 임시 기억 + permission_manage_project_activities: 프로젝트 작업내역 관리 + error_unable_delete_issue_status: 일감 상태를 지울 수 없습니다. + label_profile: 사용자정보 + permission_manage_subtasks: 하위 일감 관리 + field_parent_issue: 상위 일감 + label_subtask_plural: 하위 일감 + label_project_copy_notifications: 프로젝트 복사 중에 이메일 알림 보내기 + error_can_not_delete_custom_field: 사용자 정의 필드를 삭제할 수 없습니다. + error_unable_to_connect: 연결할 수 없습니다((%{value}) + error_can_not_remove_role: 이 역할은 현재 사용 중이이서 삭제할 수 없습니다. + error_can_not_delete_tracker: 이 유형의 일감들이 있어서 삭제할 수 없습니다. + field_principal: 신원 + label_my_page_block: 내 페이지 출력화면 + notice_failed_to_save_members: "%{errors}:구성원을 저장 중 실패하였습니다" + text_zoom_out: 더 작게 + text_zoom_in: 더 크게 + notice_unable_delete_time_entry: 시간 기록 항목을 삭제할 수 없습니다. + label_overall_spent_time: 총 소요시간 + field_time_entries: 기록된 시간 + project_module_gantt: Gantt 챠트 + project_module_calendar: 달력 + button_edit_associated_wikipage: "연관된 위키 페이지 %{page_title} 수정" + text_are_you_sure_with_children: 일감과 모든 하위 일감들을 삭제하시겠습니까? + field_text: 텍스트 영역 + label_user_mail_option_only_owner: 내가 저자인 사항만 + setting_default_notification_option: 기본 알림 옵션 + label_user_mail_option_only_my_events: 내가 지켜보거나 속해있는 사항만 + label_user_mail_option_only_assigned: 내에게 할당된 사항만 + label_user_mail_option_none: 알림 없음 + field_member_of_group: 할당된 사람의 그룹 + field_assigned_to_role: 할당된 사람의 역할 + notice_not_authorized_archived_project: 접근하려는 프로젝트는 이미 잠금보관되어 있습니다. + label_principal_search: "사용자 및 그룹 찾기:" + label_user_search: "사용자 찾기::" + field_visible: 보이기 + setting_emails_header: 이메일 헤더 + setting_commit_logtime_activity_id: 기록된 시간에 적용할 작업분류 + text_time_logged_by_changeset: "변경묶음 %{value}에서 적용되었습니다." + setting_commit_logtime_enabled: 커밋 시점에 작업 시간 기록 활성화 + notice_gantt_chart_truncated: "표시할 수 있는 최대 항목수(%{max})를 초과하여 차트가 잘렸습니다." + setting_gantt_items_limit: "Gantt 차트에 표시되는 최대 항목수" + field_warn_on_leaving_unsaved: "저장하지 않은 페이지를 빠져나갈 때 나에게 알림" + text_warn_on_leaving_unsaved: "현재 페이지는 저장되지 않은 문자가 있습니다. 이 페이지를 빠져나가면 내용을 잃을것입니다." + label_my_queries: "내 검색 양식" + text_journal_changed_no_detail: "%{label}이 변경되었습니다." + label_news_comment_added: "뉴스에 설명이 추가되었습니다." + button_expand_all: "모두 확장" + button_collapse_all: "모두 축소" + label_additional_workflow_transitions_for_assignee: "사용자가 작업자일 때 허용되는 추가 상태" + label_additional_workflow_transitions_for_author: "사용자가 저자일 때 허용되는 추가 상태" + label_bulk_edit_selected_time_entries: "선택된 소요 시간 대량 편집" + text_time_entries_destroy_confirmation: "선택한 소요 시간 항목을 삭제하시겠습니까?" + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: "덧글이 추가되었습니다." + label_issue_status_updated: "상태가 변경되었습니다." + label_issue_priority_updated: "우선 순위가 변경되었습니다." + label_issues_visibility_own: "일감을 생성하거나 할당된 사용자" + field_issues_visibility: "일감 보임" + label_issues_visibility_all: "모든 일감" + permission_set_own_issues_private: "자신의 일감을 공개나 비공개로 설정" + field_is_private: "비공개" + permission_set_issues_private: "일감을 공개나 비공개로 설정" + label_issues_visibility_public: "모든 비공개 일감" + text_issues_destroy_descendants_confirmation: "%{count} 개의 하위 일감을 삭제할 것입니다." + field_commit_logs_encoding: "제출(commit) 기록 인코딩" + field_scm_path_encoding: "경로 인코딩" + text_scm_path_encoding_note: "기본: UTF-8" + field_path_to_repository: "저장소 경로" + field_root_directory: "루트 경로" + field_cvs_module: "모듈" + field_cvsroot: "CVS 루트" + text_mercurial_repository_note: "로컬 저장소 (예: /hgrepo, c:\hgrepo)" + text_scm_command: "명령" + text_scm_command_version: "버전" + label_git_report_last_commit: "파일이나 폴더의 마지막 제출(commit)을 보고" + text_scm_config: "SCM 명령을 config/configuration.yml에서 수정할 수 있습니다. 수정후에는 재시작하십시오." + text_scm_command_not_available: "SCM 명령을 사용할 수 없습니다. 관리 페이지의 설정을 검사하십시오." + notice_issue_successful_create: "%{id} 일감이 생성되었습니다." + label_between: "사이" + setting_issue_group_assignment: "그룹에 일감 할당 허용" + label_diff: "비교(diff)" + text_git_repository_note: "저장소는 노출된 로컬입니다. (예: /gitrepo, c:\gitrepo)" + description_query_sort_criteria_direction: "정렬 방향" + description_project_scope: "검색 범위" + description_filter: "검색 조건" + description_user_mail_notification: "메일 알림 설정" + description_date_from: "시작 날짜 입력" + description_message_content: "메세지 내용" + description_available_columns: "가능한 컬럼" + description_date_range_interval: 시작과 끝 날짜로 범위를 선택하십시오." + description_issue_category_reassign: "일감 범주를 선택하십시오." + description_search: "검색항목" + description_notes: "덧글" + description_date_range_list: "목록에서 범위를 선택 하십시오." + description_choose_project: "프로젝트" + description_date_to: "종료 날짜 입력" + description_query_sort_criteria_attribute: "정렬 속성" + description_wiki_subpages_reassign: "새로운 상위 페이지를 선택하십시오." + description_selected_columns: "선택된 컬럼" + label_parent_revision: "상위" + label_child_revision: "하위" + error_scm_annotate_big_text_file: "최대 텍스트 파일 크기를 초과 하면 항목은 이력화 될 수 없습니다." + setting_default_issue_start_date_to_creation_date: "새로운 일감의 시작 날짜로 오늘 날짜 사용" + button_edit_section: "이 부분 수정" + setting_repositories_encodings: "첨부파일이나 저장소 인코딩" + description_all_columns: "모든 컬럼" + button_export: "내보내기" + label_export_options: "내보내기 옵션: %{export_format}" + error_attachment_too_big: "이 파일은 제한된 크기(%{max_size})를 초과하였기 때문에 업로드 할 수 없습니다." diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a2b37fe2ff5ae9d62a418e469dc500c74dfab37.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a2b37fe2ff5ae9d62a418e469dc500c74dfab37.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,85 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class SortHelperTest < ActionView::TestCase + include SortHelper + + def setup + @session = nil + @sort_param = nil + end + + def test_default_sort_clause_with_array + sort_init 'attr1', 'desc' + sort_update(['attr1', 'attr2']) + + assert_equal 'attr1 DESC', sort_clause + end + + def test_default_sort_clause_with_hash + sort_init 'attr1', 'desc' + sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) + + assert_equal 'table1.attr1 DESC', sort_clause + end + + def test_default_sort_clause_with_multiple_columns + sort_init 'attr1', 'desc' + sort_update({'attr1' => ['table1.attr1', 'table1.attr2'], 'attr2' => 'table2.attr2'}) + + assert_equal 'table1.attr1 DESC, table1.attr2 DESC', sort_clause + end + + def test_params_sort + @sort_param = 'attr1,attr2:desc' + + sort_init 'attr1', 'desc' + sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) + + assert_equal 'table1.attr1, table2.attr2 DESC', sort_clause + assert_equal 'attr1,attr2:desc', @session['foo_bar_sort'] + end + + def test_invalid_params_sort + @sort_param = 'invalid_key' + + sort_init 'attr1', 'desc' + sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) + + assert_equal 'table1.attr1 DESC', sort_clause + assert_equal 'attr1:desc', @session['foo_bar_sort'] + end + + def test_invalid_order_params_sort + @sort_param = 'attr1:foo:bar,attr2' + + sort_init 'attr1', 'desc' + sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) + + assert_equal 'table1.attr1, table2.attr2', sort_clause + assert_equal 'attr1,attr2', @session['foo_bar_sort'] + end + + private + + def controller_name; 'foo'; end + def action_name; 'bar'; end + def params; {:sort => @sort_param}; end + def session; @session ||= {}; end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a59e0de6fb3a65fd73a1071a5762041233e7537.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a59e0de6fb3a65fd73a1071a5762041233e7537.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,494 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'repositories_controller' + +# Re-raise errors caught by the controller. +class RepositoriesController; def rescue_action(e) raise e end; end + +class RepositoriesGitControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules + + REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s + REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? + PRJ_ID = 3 + CHAR_1_HEX = "\xc3\x9c" + NUM_REV = 21 + + ## Git, Mercurial and CVS path encodings are binary. + ## Subversion supports URL encoding for path. + ## Redmine Mercurial adapter and extension use URL encoding. + ## Git accepts only binary path in command line parameter. + ## So, there is no way to use binary command line parameter in JRuby. + JRUBY_SKIP = (RUBY_PLATFORM == 'java') + JRUBY_SKIP_STR = "TODO: This test fails in JRuby" + + def setup + @ruby19_non_utf8_pass = + (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8') + + @controller = RepositoriesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @project = Project.find(PRJ_ID) + @repository = Repository::Git.create( + :project => @project, + :url => REPOSITORY_PATH, + :path_encoding => 'ISO-8859-1' + ) + assert @repository + @char_1 = CHAR_1_HEX.dup + if @char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + end + + Setting.default_language = 'en' + end + + if File.directory?(REPOSITORY_PATH) + def test_browse_root + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :show, :id => PRJ_ID + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal 9, assigns(:entries).size + assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} + assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'} + assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'} + assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'} + assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'} + assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'} + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_browse_branch + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :rev => 'test_branch' + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal 4, assigns(:entries).size + assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} + assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'} + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_browse_tag + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [ + "tag00.lightweight", + "tag01.annotated", + ].each do |t1| + get :show, :id => PRJ_ID, :rev => t1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert assigns(:entries).size > 0 + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + end + + def test_browse_directory + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['edit.png'], assigns(:entries).collect(&:name) + entry = assigns(:entries).detect {|e| e.name == 'edit.png'} + assert_not_nil entry + assert_equal 'file', entry.kind + assert_equal 'images/edit.png', entry.path + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'], + :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518' + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['delete.png'], assigns(:entries).collect(&:name) + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_changes + get :changes, :id => PRJ_ID, :path => ['images', 'edit.png'] + assert_response :success + assert_template 'changes' + assert_tag :tag => 'h2', :content => 'edit.png' + end + + def test_entry_show + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'entry' + # Line 19 + assert_tag :tag => 'th', + :content => '11', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } + end + + def test_entry_show_latin_1 + if @ruby19_non_utf8_pass + puts_ruby19_non_utf8_pass() + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR + else + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1| + get :entry, :id => PRJ_ID, + :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1 + assert_response :success + assert_template 'entry' + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', + :content => /test-#{@char_1}.txt/ } + end + end + end + end + + def test_entry_download + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], + :format => 'raw' + assert_response :success + # File content + assert @response.body.include?('WITHOUT ANY WARRANTY') + end + + def test_directory_entry + get :entry, :id => PRJ_ID, :path => ['sources'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entry) + assert_equal 'sources', assigns(:entry).name + end + + def test_diff + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + # Full diff of changeset 2f9c0091 + ['inline', 'sbs'].each do |dt| + get :diff, + :id => PRJ_ID, + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7', + :type => dt + assert_response :success + assert_template 'diff' + # Line 22 removed + assert_tag :tag => 'th', + :content => /22/, + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /def remove/ } + assert_tag :tag => 'h2', :content => /2f9c0091/ + end + end + + def test_diff_truncated + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + Setting.diff_max_lines_displayed = 5 + + # Truncated diff of changeset 2f9c0091 + with_cache do + get :diff, :id => PRJ_ID, :type => 'inline', + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7' + assert_response :success + assert @response.body.include?("... This diff was truncated") + + Setting.default_language = 'fr' + get :diff, :id => PRJ_ID, :type => 'inline', + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7' + assert_response :success + assert ! @response.body.include?("... This diff was truncated") + assert @response.body.include?("... Ce diff") + end + end + + def test_diff_two_revs + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, + :id => PRJ_ID, + :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1', + :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7', + :type => dt + assert_response :success + assert_template 'diff' + diff = assigns(:diff) + assert_not_nil diff + assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/ + end + end + + def test_diff_latin_1 + if @ruby19_non_utf8_pass + puts_ruby19_non_utf8_pass() + else + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1| + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => r1, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'thead', + :descendant => { + :tag => 'th', + :attributes => { :class => 'filename' } , + :content => /latin-1-dir\/test-#{@char_1}.txt/ , + }, + :sibling => { + :tag => 'tbody', + :descendant => { + :tag => 'td', + :attributes => { :class => /diff_in/ }, + :content => /test-#{@char_1}.txt/ + } + } + end + end + end + end + end + + def test_save_diff_type + @request.session[:user_id] = 1 # admin + user = User.find(1) + get :diff, + :id => PRJ_ID, + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7' + assert_response :success + assert_template 'diff' + user.reload + assert_equal "inline", user.pref[:diff_type] + get :diff, + :id => PRJ_ID, + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7', + :type => 'sbs' + assert_response :success + assert_template 'diff' + user.reload + assert_equal "sbs", user.pref[:diff_type] + end + + def test_annotate + get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'annotate' + # Line 24, changeset 2f9c0091 + assert_tag :tag => 'th', :content => '24', + :sibling => { + :tag => 'td', + :child => { + :tag => 'a', + :content => /2f9c0091/ + } + } + assert_tag :tag => 'th', :content => '24', + :sibling => { :tag => 'td', :content => /jsmith/ } + assert_tag :tag => 'th', :content => '24', + :sibling => { + :tag => 'td', + :child => { + :tag => 'a', + :content => /2f9c0091/ + } + } + assert_tag :tag => 'th', :content => '24', + :sibling => { :tag => 'td', :content => /watcher =/ } + end + + def test_annotate_at_given_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :annotate, :id => PRJ_ID, :rev => 'deff7', + :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'annotate' + assert_tag :tag => 'h2', :content => /@ deff712f/ + end + + def test_annotate_binary_file + get :annotate, :id => PRJ_ID, :path => ['images', 'edit.png'] + assert_response 500 + assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ }, + :content => /cannot be annotated/ + end + + def test_annotate_error_when_too_big + with_settings :file_max_size_displayed => 1 do + get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], :rev => 'deff712f' + assert_response 500 + assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ }, + :content => /exceeds the maximum text file size/ + + get :annotate, :id => PRJ_ID, :path => ['README'], :rev => '7234cb2' + assert_response :success + assert_template 'annotate' + end + end + + def test_annotate_latin_1 + if @ruby19_non_utf8_pass + puts_ruby19_non_utf8_pass() + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR + else + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1| + get :annotate, :id => PRJ_ID, + :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1 + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', + :content => /test-#{@char_1}.txt/ } + end + end + end + end + + def test_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r| + get :revision, :id => PRJ_ID, :rev => r + assert_response :success + assert_template 'revision' + end + end + + def test_empty_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['', ' ', nil].each do |r| + get :revision, :id => PRJ_ID, :rev => r + assert_response 404 + assert_error_tag :content => /was not found/ + end + end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Git.create( + :project => @project, + :url => "/invalid", + :path_encoding => 'ISO-8859-1' + ) + assert @repository + @repository.fetch_changesets + @repository.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + private + + def puts_ruby19_non_utf8_pass + puts "TODO: This test fails in Ruby 1.9 " + + "and Encoding.default_external is not UTF-8. " + + "Current value is '#{Encoding.default_external.to_s}'" + end + else + puts "Git test repository NOT FOUND. Skipping functional tests !!!" + def test_fake; assert true end + end + + private + def with_cache(&block) + before = ActionController::Base.perform_caching + ActionController::Base.perform_caching = true + block.call + ActionController::Base.perform_caching = before + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a8cd1b0e0860947e389cd0337442e3d3a963523.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a8cd1b0e0860947e389cd0337442e3d3a963523.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1001 @@ +ro: + direction: ltr + date: + formats: + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B %Y" + only_day: "%e" + + day_names: [Duminică, Luni, Marti, Miercuri, Joi, Vineri, Sâmbătă] + abbr_day_names: [Dum, Lun, Mar, Mie, Joi, Vin, Sâm] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Ianuarie, Februarie, Martie, Aprilie, Mai, Iunie, Iulie, August, Septembrie, Octombrie, Noiembrie, Decembrie] + abbr_month_names: [~, Ian, Feb, Mar, Apr, Mai, Iun, Iul, Aug, Sep, Oct, Noi, Dec] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "jumătate de minut" + less_than_x_seconds: + one: "mai puțin de o secundă" + other: "mai puțin de %{count} secunde" + x_seconds: + one: "o secundă" + other: "%{count} secunde" + less_than_x_minutes: + one: "mai puțin de un minut" + other: "mai puțin de %{count} minute" + x_minutes: + one: "un minut" + other: "%{count} minute" + about_x_hours: + one: "aproximativ o oră" + other: "aproximativ %{count} ore" + x_days: + one: "o zi" + other: "%{count} zile" + about_x_months: + one: "aproximativ o lună" + other: "aproximativ %{count} luni" + x_months: + one: "o luna" + other: "%{count} luni" + about_x_years: + one: "aproximativ un an" + other: "aproximativ %{count} ani" + over_x_years: + one: "peste un an" + other: "peste %{count} ani" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + human: + format: + precision: 1 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "și" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nu este inclus în listă" + exclusion: "este rezervat" + invalid: "nu este valid" + confirmation: "nu este identică" + accepted: "trebuie acceptat" + empty: "trebuie completat" + blank: "nu poate fi gol" + too_long: "este prea lung" + too_short: "este prea scurt" + wrong_length: "nu are lungimea corectă" + taken: "a fost luat deja" + not_a_number: "nu este un număr" + not_a_date: "nu este o dată validă" + greater_than: "trebuie să fie mai mare de %{count}" + greater_than_or_equal_to: "trebuie să fie mai mare sau egal cu %{count}" + equal_to: "trebuie să fie egal cu {count}}" + less_than: "trebuie să fie mai mic decat %{count}" + less_than_or_equal_to: "trebuie să fie mai mic sau egal cu %{count}" + odd: "trebuie să fie impar" + even: "trebuie să fie par" + greater_than_start_date: "trebuie să fie după data de început" + not_same_project: "trebuie să aparțină aceluiași proiect" + circular_dependency: "Această relație ar crea o dependență circulară" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Selectați + + general_text_No: 'Nu' + general_text_Yes: 'Da' + general_text_no: 'nu' + general_text_yes: 'da' + general_lang_name: 'Română' + general_csv_separator: '.' + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '2' + + notice_account_updated: Cont actualizat. + notice_account_invalid_creditentials: Utilizator sau parola nevalidă + notice_account_password_updated: Parolă actualizată. + notice_account_wrong_password: Parolă greșită + notice_account_register_done: Contul a fost creat. Pentru activare, urmați legătura trimisă prin email. + notice_account_unknown_email: Utilizator necunoscut. + notice_can_t_change_password: Acest cont folosește o sursă externă de autentificare. Nu se poate schimba parola. + notice_account_lost_email_sent: S-a trimis un email cu instrucțiuni de schimbare a parolei. + notice_account_activated: Contul a fost activat. Vă puteți autentifica acum. + notice_successful_create: Creat. + notice_successful_update: Actualizat. + notice_successful_delete: Șters. + notice_successful_connection: Conectat. + notice_file_not_found: Pagina pe care doriți să o accesați nu există sau a fost ștearsă. + notice_locking_conflict: Datele au fost actualizate de alt utilizator. + notice_not_authorized: Nu sunteți autorizat sa accesați această pagină. + notice_email_sent: "S-a trimis un email către %{value}" + notice_email_error: "A intervenit o eroare la trimiterea de email (%{value})" + notice_feeds_access_key_reseted: Cheia de acces RSS a fost resetată. + notice_failed_to_save_issues: "Nu s-au putut salva %{count} tichete din cele %{total} selectate: %{ids}." + notice_no_issue_selected: "Niciun tichet selectat! Vă rugăm să selectați tichetele pe care doriți să le editați." + notice_account_pending: "Contul dumneavoastră a fost creat și așteaptă aprobarea administratorului." + notice_default_data_loaded: S-a încărcat configurația implicită. + notice_unable_delete_version: Nu se poate șterge versiunea. + + error_can_t_load_default_data: "Nu s-a putut încărca configurația implicită: %{value}" + error_scm_not_found: "Nu s-a găsit articolul sau revizia în depozit." + error_scm_command_failed: "A intervenit o eroare la accesarea depozitului: %{value}" + error_scm_annotate: "Nu există sau nu poate fi adnotată." + error_issue_not_found_in_project: 'Tichetul nu a fost găsit sau nu aparține acestui proiect' + + warning_attachments_not_saved: "Nu s-au putut salva %{count} fișiere." + + mail_subject_lost_password: "Parola dumneavoastră: %{value}" + mail_body_lost_password: 'Pentru a schimba parola, accesați:' + mail_subject_register: "Activarea contului %{value}" + mail_body_register: 'Pentru activarea contului, accesați:' + mail_body_account_information_external: "Puteți folosi contul „{value}}” pentru a vă autentifica." + mail_body_account_information: Informații despre contul dumneavoastră + mail_subject_account_activation_request: "Cerere de activare a contului %{value}" + mail_body_account_activation_request: "S-a înregistrat un utilizator nou (%{value}). Contul așteaptă aprobarea dumneavoastră:" + mail_subject_reminder: "%{count} tichete trebuie rezolvate în următoarele %{days} zile" + mail_body_reminder: "%{count} tichete atribuite dumneavoastră trebuie rezolvate în următoarele %{days} zile:" + + gui_validation_error: o eroare + gui_validation_error_plural: "%{count} erori" + + field_name: Nume + field_description: Descriere + field_summary: Rezumat + field_is_required: Obligatoriu + field_firstname: Prenume + field_lastname: Nume + field_mail: Email + field_filename: Fișier + field_filesize: Mărime + field_downloads: Descărcări + field_author: Autor + field_created_on: Creat la + field_updated_on: Actualizat la + field_field_format: Format + field_is_for_all: Pentru toate proiectele + field_possible_values: Valori posibile + field_regexp: Expresie regulară + field_min_length: lungime minimă + field_max_length: lungime maximă + field_value: Valoare + field_category: Categorie + field_title: Titlu + field_project: Proiect + field_issue: Tichet + field_status: Stare + field_notes: Note + field_is_closed: Rezolvat + field_is_default: Implicit + field_tracker: Tip de tichet + field_subject: Subiect + field_due_date: Data finalizării + field_assigned_to: Atribuit + field_priority: Prioritate + field_fixed_version: Versiune țintă + field_user: Utilizator + field_role: Rol + field_homepage: Pagina principală + field_is_public: Public + field_parent: Sub-proiect al + field_is_in_roadmap: Tichete afișate în plan + field_login: Autentificare + field_mail_notification: Notificări prin e-mail + field_admin: Administrator + field_last_login_on: Ultima autentificare în + field_language: Limba + field_effective_date: Data + field_password: Parola + field_new_password: Parola nouă + field_password_confirmation: Confirmare + field_version: Versiune + field_type: Tip + field_host: Gazdă + field_port: Port + field_account: Cont + field_base_dn: Base DN + field_attr_login: Atribut autentificare + field_attr_firstname: Atribut prenume + field_attr_lastname: Atribut nume + field_attr_mail: Atribut email + field_onthefly: Creare utilizator pe loc + field_start_date: Data începerii + field_done_ratio: Realizat (%) + field_auth_source: Mod autentificare + field_hide_mail: Nu se afișează adresa de email + field_comments: Comentariu + field_url: URL + field_start_page: Pagina de start + field_subproject: Subproiect + field_hours: Ore + field_activity: Activitate + field_spent_on: Data + field_identifier: Identificator + field_is_filter: Filtru + field_issue_to: Tichet asociat + field_delay: Întârziere + field_assignable: Se pot atribui tichete acestui rol + field_redirect_existing_links: Redirecționează legăturile existente + field_estimated_hours: Timp estimat + field_column_names: Coloane + field_time_zone: Fus orar + field_searchable: Căutare + field_default_value: Valoare implicita + field_comments_sorting: Afișează comentarii + field_parent_title: Pagina superioara + field_editable: Modificabil + field_watcher: Urmărește + field_identity_url: URL OpenID + field_content: Conținut + + setting_app_title: Titlu aplicație + setting_app_subtitle: Subtitlu aplicație + setting_welcome_text: Text de întâmpinare + setting_default_language: Limba implicita + setting_login_required: Necesita autentificare + setting_self_registration: Înregistrare automată + setting_attachment_max_size: Mărime maxima atașament + setting_issues_export_limit: Limită de tichete exportate + setting_mail_from: Adresa de email a expeditorului + setting_bcc_recipients: Alți destinatari pentru email (BCC) + setting_plain_text_mail: Mesaje text (fără HTML) + setting_host_name: Numele gazdei și calea + setting_text_formatting: Formatare text + setting_wiki_compression: Comprimare istoric Wiki + setting_feeds_limit: Limita de actualizări din feed + setting_default_projects_public: Proiectele noi sunt implicit publice + setting_autofetch_changesets: Preluare automată a modificărilor din depozit + setting_sys_api_enabled: Activare WS pentru gestionat depozitul + setting_commit_ref_keywords: Cuvinte cheie pt. referire tichet + setting_commit_fix_keywords: Cuvinte cheie pt. rezolvare tichet + setting_autologin: Autentificare automată + setting_date_format: Format dată + setting_time_format: Format oră + setting_cross_project_issue_relations: Permite legături de tichete între proiecte + setting_issue_list_default_columns: Coloane implicite afișate în lista de tichete + setting_emails_footer: Subsol email + setting_protocol: Protocol + setting_per_page_options: Număr de obiecte pe pagină + setting_user_format: Stil de afișare pentru utilizator + setting_activity_days_default: Se afișează zile în jurnalul proiectului + setting_display_subprojects_issues: Afișează implicit tichetele sub-proiectelor în proiectele principale + setting_enabled_scm: SCM activat + setting_mail_handler_api_enabled: Activare WS pentru email primit + setting_mail_handler_api_key: cheie API + setting_sequential_project_identifiers: Generează secvențial identificatoarele de proiect + setting_gravatar_enabled: Folosește poze Gravatar pentru utilizatori + setting_diff_max_lines_displayed: Număr maxim de linii de diferență afișate + setting_file_max_size_displayed: Număr maxim de fișiere text afișate în pagină (inline) + setting_repository_log_display_limit: Număr maxim de revizii afișate în istoricul fișierului + setting_openid: Permite înregistrare și autentificare cu OpenID + + permission_edit_project: Editează proiectul + permission_select_project_modules: Alege module pentru proiect + permission_manage_members: Editează membri + permission_manage_versions: Editează versiuni + permission_manage_categories: Editează categorii + permission_add_issues: Adaugă tichete + permission_edit_issues: Editează tichete + permission_manage_issue_relations: Editează relații tichete + permission_add_issue_notes: Adaugă note + permission_edit_issue_notes: Editează note + permission_edit_own_issue_notes: Editează notele proprii + permission_move_issues: Mută tichete + permission_delete_issues: Șterge tichete + permission_manage_public_queries: Editează căutările implicite + permission_save_queries: Salvează căutările + permission_view_gantt: Afișează Gantt + permission_view_calendar: Afișează calendarul + permission_view_issue_watchers: Afișează lista de persoane interesate + permission_add_issue_watchers: Adaugă persoane interesate + permission_log_time: Înregistrează timpul de lucru + permission_view_time_entries: Afișează timpul de lucru + permission_edit_time_entries: Editează jurnalele cu timp de lucru + permission_edit_own_time_entries: Editează jurnalele proprii cu timpul de lucru + permission_manage_news: Editează știri + permission_comment_news: Comentează știrile + permission_manage_documents: Editează documente + permission_view_documents: Afișează documente + permission_manage_files: Editează fișiere + permission_view_files: Afișează fișiere + permission_manage_wiki: Editează wiki + permission_rename_wiki_pages: Redenumește pagini wiki + permission_delete_wiki_pages: Șterge pagini wiki + permission_view_wiki_pages: Afișează wiki + permission_view_wiki_edits: Afișează istoricul wiki + permission_edit_wiki_pages: Editează pagini wiki + permission_delete_wiki_pages_attachments: Șterge atașamente + permission_protect_wiki_pages: Blochează pagini wiki + permission_manage_repository: Gestionează depozitul + permission_browse_repository: Răsfoiește depozitul + permission_view_changesets: Afișează modificările din depozit + permission_commit_access: Acces commit + permission_manage_boards: Editează forum + permission_view_messages: Afișează mesaje + permission_add_messages: Scrie mesaje + permission_edit_messages: Editează mesaje + permission_edit_own_messages: Editează mesajele proprii + permission_delete_messages: Șterge mesaje + permission_delete_own_messages: Șterge mesajele proprii + + project_module_issue_tracking: Tichete + project_module_time_tracking: Timp de lucru + project_module_news: Știri + project_module_documents: Documente + project_module_files: Fișiere + project_module_wiki: Wiki + project_module_repository: Depozit + project_module_boards: Forum + + label_user: Utilizator + label_user_plural: Utilizatori + label_user_new: Utilizator nou + label_project: Proiect + label_project_new: Proiect nou + label_project_plural: Proiecte + label_x_projects: + zero: niciun proiect + one: un proiect + other: "%{count} proiecte" + label_project_all: Toate proiectele + label_project_latest: Proiecte noi + label_issue: Tichet + label_issue_new: Tichet nou + label_issue_plural: Tichete + label_issue_view_all: Afișează toate tichetele + label_issues_by: "Sortează după %{value}" + label_issue_added: Adaugat + label_issue_updated: Actualizat + label_document: Document + label_document_new: Document nou + label_document_plural: Documente + label_document_added: Adăugat + label_role: Rol + label_role_plural: Roluri + label_role_new: Rol nou + label_role_and_permissions: Roluri și permisiuni + label_member: Membru + label_member_new: membru nou + label_member_plural: Membri + label_tracker: Tip de tichet + label_tracker_plural: Tipuri de tichete + label_tracker_new: Tip nou de tichet + label_workflow: Mod de lucru + label_issue_status: Stare tichet + label_issue_status_plural: Stare tichete + label_issue_status_new: Stare nouă + label_issue_category: Categorie de tichet + label_issue_category_plural: Categorii de tichete + label_issue_category_new: Categorie nouă + label_custom_field: Câmp personalizat + label_custom_field_plural: Câmpuri personalizate + label_custom_field_new: Câmp nou personalizat + label_enumerations: Enumerări + label_enumeration_new: Valoare nouă + label_information: Informație + label_information_plural: Informații + label_please_login: Vă rugăm să vă autentificați + label_register: Înregistrare + label_login_with_open_id_option: sau autentificare cu OpenID + label_password_lost: Parolă uitată + label_home: Acasă + label_my_page: Pagina mea + label_my_account: Contul meu + label_my_projects: Proiectele mele + label_administration: Administrare + label_login: Autentificare + label_logout: Ieșire din cont + label_help: Ajutor + label_reported_issues: Tichete + label_assigned_to_me_issues: Tichetele mele + label_last_login: Ultima conectare + label_registered_on: Înregistrat la + label_activity: Activitate + label_overall_activity: Activitate - vedere de ansamblu + label_user_activity: "Activitate %{value}" + label_new: Nou + label_logged_as: Autentificat ca + label_environment: Mediu + label_authentication: Autentificare + label_auth_source: Mod de autentificare + label_auth_source_new: Nou + label_auth_source_plural: Moduri de autentificare + label_subproject_plural: Sub-proiecte + label_and_its_subprojects: "%{value} și sub-proiecte" + label_min_max_length: lungime min - max + label_list: Listă + label_date: Dată + label_integer: Întreg + label_float: Zecimal + label_boolean: Valoare logică + label_string: Text + label_text: Text lung + label_attribute: Atribut + label_attribute_plural: Atribute + label_download: "%{count} descărcare" + label_download_plural: "%{count} descărcări" + label_no_data: Nu există date de afișat + label_change_status: Schimbă starea + label_history: Istoric + label_attachment: Fișier + label_attachment_new: Fișier nou + label_attachment_delete: Șterge fișier + label_attachment_plural: Fișiere + label_file_added: Adăugat + label_report: Raport + label_report_plural: Rapoarte + label_news: Știri + label_news_new: Adaugă știre + label_news_plural: Știri + label_news_latest: Ultimele știri + label_news_view_all: Afișează toate știrile + label_news_added: Adăugat + label_settings: Setări + label_overview: Pagină proiect + label_version: Versiune + label_version_new: Versiune nouă + label_version_plural: Versiuni + label_confirmation: Confirmare + label_export_to: 'Disponibil și în:' + label_read: Citește... + label_public_projects: Proiecte publice + label_open_issues: deschis + label_open_issues_plural: deschise + label_closed_issues: închis + label_closed_issues_plural: închise + label_x_open_issues_abbr_on_total: + zero: 0 deschise / %{total} + one: 1 deschis / %{total} + other: "%{count} deschise / %{total}" + label_x_open_issues_abbr: + zero: 0 deschise + one: 1 deschis + other: "%{count} deschise" + label_x_closed_issues_abbr: + zero: 0 închise + one: 1 închis + other: "%{count} închise" + label_total: Total + label_permissions: Permisiuni + label_current_status: Stare curentă + label_new_statuses_allowed: Stări noi permise + label_all: toate + label_none: niciunul + label_nobody: nimeni + label_next: Înainte + label_previous: Înapoi + label_used_by: Folosit de + label_details: Detalii + label_add_note: Adaugă o notă + label_per_page: pe pagină + label_calendar: Calendar + label_months_from: luni de la + label_gantt: Gantt + label_internal: Intern + label_last_changes: "ultimele %{count} schimbări" + label_change_view_all: Afișează toate schimbările + label_personalize_page: Personalizează aceasta pagina + label_comment: Comentariu + label_comment_plural: Comentarii + label_x_comments: + zero: fara comentarii + one: 1 comentariu + other: "%{count} comentarii" + label_comment_add: Adaugă un comentariu + label_comment_added: Adăugat + label_comment_delete: Șterge comentariul + label_query: Cautare personalizata + label_query_plural: Căutări personalizate + label_query_new: Căutare nouă + label_filter_add: Adaugă filtru + label_filter_plural: Filtre + label_equals: este + label_not_equals: nu este + label_in_less_than: în mai puțin de + label_in_more_than: în mai mult de + label_in: în + label_today: astăzi + label_all_time: oricând + label_yesterday: ieri + label_this_week: săptămâna aceasta + label_last_week: săptămâna trecută + label_last_n_days: "ultimele %{count} zile" + label_this_month: luna aceasta + label_last_month: luna trecută + label_this_year: anul acesta + label_date_range: Perioada + label_less_than_ago: mai puțin de ... zile + label_more_than_ago: mai mult de ... zile + label_ago: în urma + label_contains: conține + label_not_contains: nu conține + label_day_plural: zile + label_repository: Depozit + label_repository_plural: Depozite + label_browse: Afișează + label_modification: "%{count} schimbare" + label_modification_plural: "%{count} schimbări" + label_revision: Revizie + label_revision_plural: Revizii + label_associated_revisions: Revizii asociate + label_added: adaugată + label_modified: modificată + label_copied: copiată + label_renamed: redenumită + label_deleted: ștearsă + label_latest_revision: Ultima revizie + label_latest_revision_plural: Ultimele revizii + label_view_revisions: Afișează revizii + label_max_size: Mărime maximă + label_sort_highest: Prima + label_sort_higher: În sus + label_sort_lower: În jos + label_sort_lowest: Ultima + label_roadmap: Planificare + label_roadmap_due_in: "De terminat în %{value}" + label_roadmap_overdue: "Întârziat cu %{value}" + label_roadmap_no_issues: Nu există tichete pentru această versiune + label_search: Caută + label_result_plural: Rezultate + label_all_words: toate cuvintele + label_wiki: Wiki + label_wiki_edit: Editare Wiki + label_wiki_edit_plural: Editări Wiki + label_wiki_page: Pagină Wiki + label_wiki_page_plural: Pagini Wiki + label_index_by_title: Sortează după titlu + label_index_by_date: Sortează după dată + label_current_version: Versiunea curentă + label_preview: Previzualizare + label_feed_plural: Feed-uri + label_changes_details: Detaliile tuturor schimbărilor + label_issue_tracking: Urmărire tichete + label_spent_time: Timp alocat + label_f_hour: "%{value} oră" + label_f_hour_plural: "%{value} ore" + label_time_tracking: Urmărire timp de lucru + label_change_plural: Schimbări + label_statistics: Statistici + label_commits_per_month: Commit pe luna + label_commits_per_author: Commit per autor + label_view_diff: Afișează diferențele + label_diff_inline: în linie + label_diff_side_by_side: una lângă alta + label_options: Opțiuni + label_copy_workflow_from: Copiază modul de lucru de la + label_permissions_report: Permisiuni + label_watched_issues: Tichete urmărite + label_related_issues: Tichete asociate + label_applied_status: Stare aplicată + label_loading: Încarcă... + label_relation_new: Asociere nouă + label_relation_delete: Șterge asocierea + label_relates_to: asociat cu + label_duplicates: duplicate + label_duplicated_by: la fel ca + label_blocks: blocări + label_blocked_by: blocat de + label_precedes: precede + label_follows: urmează + label_end_to_start: de la sfârșit la început + label_end_to_end: de la sfârșit la sfârșit + label_start_to_start: de la început la început + label_start_to_end: de la început la sfârșit + label_stay_logged_in: Păstrează autentificarea + label_disabled: dezactivat + label_show_completed_versions: Arată versiunile terminate + label_me: eu + label_board: Forum + label_board_new: Forum nou + label_board_plural: Forumuri + label_topic_plural: Subiecte + label_message_plural: Mesaje + label_message_last: Ultimul mesaj + label_message_new: Mesaj nou + label_message_posted: Adăugat + label_reply_plural: Răspunsuri + label_send_information: Trimite utilizatorului informațiile despre cont + label_year: An + label_month: Lună + label_week: Săptămână + label_date_from: De la + label_date_to: La + label_language_based: Un funcție de limba de afișare a utilizatorului + label_sort_by: "Sortează după %{value}" + label_send_test_email: Trimite email de test + label_feeds_access_key_created_on: "Cheie de acces creată acum %{value}" + label_module_plural: Module + label_added_time_by: "Adăugat de %{author} acum %{age}" + label_updated_time_by: "Actualizat de %{author} acum %{age}" + label_updated_time: "Actualizat acum %{value}" + label_jump_to_a_project: Alege proiectul... + label_file_plural: Fișiere + label_changeset_plural: Schimbări + label_default_columns: Coloane implicite + label_no_change_option: (fără schimbări) + label_bulk_edit_selected_issues: Editează toate tichetele selectate + label_theme: Tema + label_default: Implicită + label_search_titles_only: Caută numai în titluri + label_user_mail_option_all: "Pentru orice eveniment, în toate proiectele mele" + label_user_mail_option_selected: " Pentru orice eveniment, în proiectele selectate..." + label_user_mail_no_self_notified: "Nu trimite notificări pentru modificările mele" + label_registration_activation_by_email: activare cont prin email + label_registration_manual_activation: activare manuală a contului + label_registration_automatic_activation: activare automată a contului + label_display_per_page: "pe pagină: %{value}" + label_age: vechime + label_change_properties: Schimbă proprietățile + label_general: General + label_more: Mai mult + label_scm: SCM + label_plugins: Plugin-uri + label_ldap_authentication: autentificare LDAP + label_downloads_abbr: D/L + label_optional_description: Descriere (opțională) + label_add_another_file: Adaugă alt fișier + label_preferences: Preferințe + label_chronological_order: în ordine cronologică + label_reverse_chronological_order: În ordine invers cronologică + label_planning: Planificare + label_incoming_emails: Mesaje primite + label_generate_key: Generează o cheie + label_issue_watchers: Cine urmărește + label_example: Exemplu + label_display: Afișează + + label_sort: Sortează + label_ascending: Crescător + label_descending: Descrescător + label_date_from_to: De la %{start} la %{end} + + + button_login: Autentificare + button_submit: Trimite + button_save: Salvează + button_check_all: Bifează tot + button_uncheck_all: Debifează tot + button_delete: Șterge + button_create: Creează + button_create_and_continue: Creează și continua + button_test: Testează + button_edit: Editează + button_add: Adaugă + button_change: Modifică + button_apply: Aplică + button_clear: Șterge + button_lock: Blochează + button_unlock: Deblochează + button_download: Descarcă + button_list: Listează + button_view: Afișează + button_move: Mută + button_back: Înapoi + button_cancel: Anulează + button_activate: Activează + button_sort: Sortează + button_log_time: Înregistrează timpul de lucru + button_rollback: Revenire la această versiune + button_watch: Urmăresc + button_unwatch: Nu urmăresc + button_reply: Răspunde + button_archive: Arhivează + button_unarchive: Dezarhivează + button_reset: Resetează + button_rename: Redenumește + button_change_password: Schimbare parolă + button_copy: Copiază + button_annotate: Adnotează + button_update: Actualizează + button_configure: Configurează + button_quote: Citează + + status_active: activ + status_registered: înregistrat + status_locked: blocat + + text_select_mail_notifications: Selectați acțiunile notificate prin email. + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 înseamnă fără restricții + text_project_destroy_confirmation: Sigur doriți să ștergeți proiectul și toate datele asociate? + text_subprojects_destroy_warning: "Se vor șterge și sub-proiectele: %{value}." + text_workflow_edit: Selectați un rol și un tip de tichet pentru a edita modul de lucru + text_are_you_sure: Sunteți sigur(ă)? + text_tip_issue_begin_day: sarcină care începe în această zi + text_tip_issue_end_day: sarcină care se termină în această zi + text_tip_issue_begin_end_day: sarcină care începe și se termină în această zi + text_project_identifier_info: 'Sunt permise doar litere mici (a-z), numere și cratime.
    Odată salvat, identificatorul nu mai poate fi modificat.' + text_caracters_maximum: "maxim %{count} caractere." + text_caracters_minimum: "Trebuie să fie minim %{count} caractere." + text_length_between: "Lungime între %{min} și %{max} caractere." + text_tracker_no_workflow: Nu sunt moduri de lucru pentru acest tip de tichet + text_unallowed_characters: Caractere nepermise + text_comma_separated: Sunt permise mai multe valori (separate cu virgulă). + text_issues_ref_in_commit_messages: Referire la tichete și rezolvare în textul mesajului + text_issue_added: "Tichetul %{id} a fost adăugat de %{author}." + text_issue_updated: "Tichetul %{id} a fost actualizat de %{author}." + text_wiki_destroy_confirmation: Sigur doriți ștergerea Wiki și a conținutului asociat? + text_issue_category_destroy_question: "Această categorie conține (%{count}) tichete. Ce doriți să faceți?" + text_issue_category_destroy_assignments: Șterge apartenența la categorie. + text_issue_category_reassign_to: Atribuie tichetele la această categorie + text_user_mail_option: "Pentru proiectele care nu sunt selectate, veți primi notificări doar pentru ceea ce urmăriți sau în ce sunteți implicat (ex: tichete create de dumneavoastră sau care vă sunt atribuite)." + text_no_configuration_data: "Nu s-au configurat încă rolurile, stările tichetelor și modurile de lucru.\nEste recomandat să încărcați configurația implicită. O veți putea modifica ulterior." + text_load_default_configuration: Încarcă configurația implicită + text_status_changed_by_changeset: "Aplicat în setul %{value}." + text_issues_destroy_confirmation: 'Sigur doriți să ștergeți tichetele selectate?' + text_select_project_modules: 'Selectați modulele active pentru acest proiect:' + text_default_administrator_account_changed: S-a schimbat contul administratorului implicit + text_file_repository_writable: Se poate scrie în directorul de atașamente + text_plugin_assets_writable: Se poate scrie în directorul de plugin-uri + text_rmagick_available: Este disponibil RMagick (opțional) + text_destroy_time_entries_question: "%{hours} ore sunt înregistrate la tichetele pe care doriți să le ștergeți. Ce doriți sa faceți?" + text_destroy_time_entries: Șterge orele înregistrate + text_assign_time_entries_to_project: Atribuie orele la proiect + text_reassign_time_entries: 'Atribuie orele înregistrate la tichetul:' + text_user_wrote: "%{value} a scris:" + text_enumeration_destroy_question: "Această valoare are %{count} obiecte." + text_enumeration_category_reassign_to: 'Atribuie la această valoare:' + text_email_delivery_not_configured: "Trimiterea de emailuri nu este configurată și ca urmare, notificările sunt dezactivate.\nConfigurați serverul SMTP în config/configuration.yml și reporniți aplicația pentru a le activa." + text_repository_usernames_mapping: "Selectați sau modificați contul Redmine echivalent contului din istoricul depozitului.\nUtilizatorii cu un cont (sau e-mail) identic în Redmine și depozit sunt echivalate automat." + text_diff_truncated: '... Comparația a fost trunchiată pentru ca depășește lungimea maximă de text care poate fi afișat.' + text_custom_field_possible_values_info: 'O linie pentru fiecare valoare' + + default_role_manager: Manager + default_role_developer: Dezvoltator + default_role_reporter: Creator de rapoarte + default_tracker_bug: Defect + default_tracker_feature: Funcție + default_tracker_support: Suport + default_issue_status_new: Nou + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Rezolvat + default_issue_status_feedback: Așteaptă reacții + default_issue_status_closed: Închis + default_issue_status_rejected: Respins + default_doc_category_user: Documentație + default_doc_category_tech: Documentație tehnică + default_priority_low: mică + default_priority_normal: normală + default_priority_high: mare + default_priority_urgent: urgentă + default_priority_immediate: imediată + default_activity_design: Design + default_activity_development: Dezvoltare + + enumeration_issue_priorities: Priorități tichete + enumeration_doc_categories: Categorii documente + enumeration_activities: Activități (timp de lucru) + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Această pagină are %{descendants} pagini anterioare și descendenți. Ce doriți să faceți? + text_wiki_page_reassign_children: Atribuie paginile la această pagină + text_wiki_page_nullify_children: Menține paginile ca și pagini inițiale (root) + text_wiki_page_destroy_children: Șterge paginile și descendenții + setting_password_min_length: Lungime minimă parolă + field_group_by: Grupează după + mail_subject_wiki_content_updated: "Pagina wiki '%{id}' a fost actualizată" + label_wiki_content_added: Adăugat + mail_subject_wiki_content_added: "Pagina wiki '%{id}' a fost adăugată" + mail_body_wiki_content_added: Pagina wiki '%{id}' a fost adăugată de %{author}. + label_wiki_content_updated: Actualizat + mail_body_wiki_content_updated: Pagina wiki '%{id}' a fost actualizată de %{author}. + permission_add_project: Crează proiect + setting_new_project_user_role_id: Rol atribuit utilizatorului non-admin care crează un proiect. + label_view_all_revisions: Arată toate reviziile + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Nu există un tracker asociat cu proiectul. Verificați vă rog setările proiectului. + error_no_default_issue_status: Nu există un status implicit al tichetelor. Verificați vă rog configurația (Mergeți la "Administrare -> Stări tichete"). + text_journal_changed: "%{label} schimbat din %{old} în %{new}" + text_journal_set_to: "%{label} setat ca %{value}" + text_journal_deleted: "%{label} șters (%{old})" + label_group_plural: Grupuri + label_group: Grup + label_group_new: Grup nou + label_time_entry_plural: Timp alocat + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Codare pentru mesaje + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7a99d287fc3d9f980fb731f44a9408d8010b9694.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7a99d287fc3d9f980fb731f44a9408d8010b9694.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,199 @@ +require File.expand_path('../../test_helper', __FILE__) + +class ProjectEnumerationsControllerTest < ActionController::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :custom_fields, :custom_fields_projects, + :custom_fields_trackers, :custom_values, + :time_entries + + def setup + @request.session[:user_id] = nil + Setting.default_language = 'en' + end + + def test_update_to_override_system_activities + @request.session[:user_id] = 2 # manager + billable_field = TimeEntryActivityCustomField.find_by_name("Billable") + + put :update, :project_id => 1, :enumerations => { + "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design, De-activate + "10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"}, # Development, Change custom value + "14"=>{"parent_id"=>"14", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"}, # Inactive Activity, Activate with custom value + "11"=>{"parent_id"=>"11", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"} # QA, no changes + } + + assert_response :redirect + assert_redirected_to '/projects/ecookbook/settings/activities' + + # Created project specific activities... + project = Project.find('ecookbook') + + # ... Design + design = project.time_entry_activities.find_by_name("Design") + assert design, "Project activity not found" + + assert_equal 9, design.parent_id # Relate to the system activity + assert_not_equal design.parent.id, design.id # Different records + assert_equal design.parent.name, design.name # Same name + assert !design.active? + + # ... Development + development = project.time_entry_activities.find_by_name("Development") + assert development, "Project activity not found" + + assert_equal 10, development.parent_id # Relate to the system activity + assert_not_equal development.parent.id, development.id # Different records + assert_equal development.parent.name, development.name # Same name + assert development.active? + assert_equal "0", development.custom_value_for(billable_field).value + + # ... Inactive Activity + previously_inactive = project.time_entry_activities.find_by_name("Inactive Activity") + assert previously_inactive, "Project activity not found" + + assert_equal 14, previously_inactive.parent_id # Relate to the system activity + assert_not_equal previously_inactive.parent.id, previously_inactive.id # Different records + assert_equal previously_inactive.parent.name, previously_inactive.name # Same name + assert previously_inactive.active? + assert_equal "1", previously_inactive.custom_value_for(billable_field).value + + # ... QA + assert_equal nil, project.time_entry_activities.find_by_name("QA"), "Custom QA activity created when it wasn't modified" + end + + def test_update_will_update_project_specific_activities + @request.session[:user_id] = 2 # manager + + project_activity = TimeEntryActivity.new({ + :name => 'Project Specific', + :parent => TimeEntryActivity.find(:first), + :project => Project.find(1), + :active => true + }) + assert project_activity.save + project_activity_two = TimeEntryActivity.new({ + :name => 'Project Specific Two', + :parent => TimeEntryActivity.find(:last), + :project => Project.find(1), + :active => true + }) + assert project_activity_two.save + + + put :update, :project_id => 1, :enumerations => { + project_activity.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # De-activate + project_activity_two.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"} # De-activate + } + + assert_response :redirect + assert_redirected_to '/projects/ecookbook/settings/activities' + + # Created project specific activities... + project = Project.find('ecookbook') + assert_equal 2, project.time_entry_activities.count + + activity_one = project.time_entry_activities.find_by_name(project_activity.name) + assert activity_one, "Project activity not found" + assert_equal project_activity.id, activity_one.id + assert !activity_one.active? + + activity_two = project.time_entry_activities.find_by_name(project_activity_two.name) + assert activity_two, "Project activity not found" + assert_equal project_activity_two.id, activity_two.id + assert !activity_two.active? + end + + def test_update_when_creating_new_activities_will_convert_existing_data + assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size + + @request.session[:user_id] = 2 # manager + put :update, :project_id => 1, :enumerations => { + "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"} # Design, De-activate + } + assert_response :redirect + + # No more TimeEntries using the system activity + assert_equal 0, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "Time Entries still assigned to system activities" + # All TimeEntries using project activity + project_specific_activity = TimeEntryActivity.find_by_parent_id_and_project_id(9, 1) + assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(project_specific_activity.id, 1).size, "No Time Entries assigned to the project activity" + end + + def test_update_when_creating_new_activities_will_not_convert_existing_data_if_an_exception_is_raised + # TODO: Need to cause an exception on create but these tests + # aren't setup for mocking. Just create a record now so the + # second one is a dupicate + parent = TimeEntryActivity.find(9) + TimeEntryActivity.create!({:name => parent.name, :project_id => 1, :position => parent.position, :active => true}) + TimeEntry.create!({:project_id => 1, :hours => 1.0, :user => User.find(1), :issue_id => 3, :activity_id => 10, :spent_on => '2009-01-01'}) + + assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size + assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size + + @request.session[:user_id] = 2 # manager + put :update, :project_id => 1, :enumerations => { + "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design + "10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"} # Development, Change custom value + } + assert_response :redirect + + # TimeEntries shouldn't have been reassigned on the failed record + assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "Time Entries are not assigned to system activities" + # TimeEntries shouldn't have been reassigned on the saved record either + assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size, "Time Entries are not assigned to system activities" + end + + def test_destroy + @request.session[:user_id] = 2 # manager + project_activity = TimeEntryActivity.new({ + :name => 'Project Specific', + :parent => TimeEntryActivity.find(:first), + :project => Project.find(1), + :active => true + }) + assert project_activity.save + project_activity_two = TimeEntryActivity.new({ + :name => 'Project Specific Two', + :parent => TimeEntryActivity.find(:last), + :project => Project.find(1), + :active => true + }) + assert project_activity_two.save + + delete :destroy, :project_id => 1 + assert_response :redirect + assert_redirected_to '/projects/ecookbook/settings/activities' + + assert_nil TimeEntryActivity.find_by_id(project_activity.id) + assert_nil TimeEntryActivity.find_by_id(project_activity_two.id) + end + + def test_destroy_should_reassign_time_entries_back_to_the_system_activity + @request.session[:user_id] = 2 # manager + project_activity = TimeEntryActivity.new({ + :name => 'Project Specific Design', + :parent => TimeEntryActivity.find(9), + :project => Project.find(1), + :active => true + }) + assert project_activity.save + assert TimeEntry.update_all("activity_id = '#{project_activity.id}'", ["project_id = ? AND activity_id = ?", 1, 9]) + assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size + + delete :destroy, :project_id => 1 + assert_response :redirect + assert_redirected_to '/projects/ecookbook/settings/activities' + + assert_nil TimeEntryActivity.find_by_id(project_activity.id) + assert_equal 0, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size, "TimeEntries still assigned to project specific activity" + assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "TimeEntries still assigned to project specific activity" + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7acfd8a3d508663aeabae0309fddb7dc899a74cf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7acfd8a3d508663aeabae0309fddb7dc899a74cf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +module CodeRay +module Encoders + + # Returns the number of tokens. + # + # Text and block tokens are counted. + class Count < Encoder + + register_for :count + + protected + + def setup options + super + + @count = 0 + end + + def finish options + output @count + end + + public + + def text_token text, kind + @count += 1 + end + + def begin_group kind + @count += 1 + end + alias end_group begin_group + alias begin_line begin_group + alias end_line begin_group + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7ae9d7b6d455faa0f47585102ed9dcb8d8884e01.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7ae9d7b6d455faa0f47585102ed9dcb8d8884e01.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,103 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class BoardsController < ApplicationController + default_search_scope :messages + before_filter :find_project, :find_board_if_available, :authorize + accept_rss_auth :index, :show + + helper :messages + include MessagesHelper + helper :sort + include SortHelper + helper :watchers + include WatchersHelper + + def index + @boards = @project.boards + # show the board if there is only one + if @boards.size == 1 + @board = @boards.first + show + end + end + + def show + respond_to do |format| + format.html { + sort_init 'updated_on', 'desc' + sort_update 'created_on' => "#{Message.table_name}.created_on", + 'replies' => "#{Message.table_name}.replies_count", + 'updated_on' => "#{Message.table_name}.updated_on" + + @topic_count = @board.topics.count + @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page'] + @topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '), + :include => [:author, {:last_reply => :author}], + :limit => @topic_pages.items_per_page, + :offset => @topic_pages.current.offset + @message = Message.new + render :action => 'show', :layout => !request.xhr? + } + format.atom { + @messages = @board.messages.find :all, :order => 'created_on DESC', + :include => [:author, :board], + :limit => Setting.feeds_limit.to_i + render_feed(@messages, :title => "#{@project}: #{@board}") + } + end + end + + verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index } + + def new + @board = Board.new(params[:board]) + @board.project = @project + if request.post? && @board.save + flash[:notice] = l(:notice_successful_create) + redirect_to_settings_in_projects + end + end + + def edit + if request.post? && @board.update_attributes(params[:board]) + redirect_to_settings_in_projects + end + end + + def destroy + @board.destroy + redirect_to_settings_in_projects + end + +private + def redirect_to_settings_in_projects + redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards' + end + + def find_project + @project = Project.find(params[:project_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_board_if_available + @board = @project.boards.find(params[:id]) if params[:id] + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7a/7aeeea98f0311fc269ae1b2bdf4ad43bc1b230a0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7a/7aeeea98f0311fc269ae1b2bdf4ad43bc1b230a0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class EnableCalendarAndGanttModulesWhereAppropriate < ActiveRecord::Migration + def self.up + EnabledModule.find(:all, :conditions => ["name = ?", 'issue_tracking']).each do |e| + EnabledModule.create(:name => 'calendar', :project_id => e.project_id) + EnabledModule.create(:name => 'gantt', :project_id => e.project_id) + end + end + + def self.down + EnabledModule.delete_all("name = 'calendar' OR name = 'gantt'") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7b/7b0091cb7275a16ba6daf28038e36a659196b7a1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7b/7b0091cb7275a16ba6daf28038e36a659196b7a1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +

    <%=l(:label_register)%> <%=link_to l(:label_login_with_open_id_option), signin_url if Setting.openid? %>

    + +<% form_tag({:action => 'register'}, :class => "tabular") do %> +<%= error_messages_for 'user' %> + +
    + +<% if @user.auth_source_id.nil? %> +

    +<%= text_field 'user', 'login', :size => 25 %>

    + +

    +<%= password_field_tag 'password', nil, :size => 25 %>
    +<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    + +

    +<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

    +<% end %> + +

    +<%= text_field 'user', 'firstname' %>

    + +

    +<%= text_field 'user', 'lastname' %>

    + +

    +<%= text_field 'user', 'mail' %>

    + +

    +<%= select("user", "language", lang_options_for_select) %>

    + +<% if Setting.openid? %> +

    +<%= text_field 'user', 'identity_url' %>

    +<% end %> + +<% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %> +

    <%= custom_field_tag_with_label :user, value %>

    +<% end %> + +
    + +<%= submit_tag l(:button_submit) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7b/7b79b629f3da71f401261cf1288a60cb2acf04af.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7b/7b79b629f3da71f401261cf1288a60cb2acf04af.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,93 @@ +# redMine - project management software +# Copyright (C) 2006-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 Acts + module ActivityProvider + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_activity_provider(options = {}) + unless self.included_modules.include?(Redmine::Acts::ActivityProvider::InstanceMethods) + cattr_accessor :activity_provider_options + send :include, Redmine::Acts::ActivityProvider::InstanceMethods + end + + options.assert_valid_keys(:type, :permission, :timestamp, :author_key, :find_options) + self.activity_provider_options ||= {} + + # One model can provide different event types + # We store these options in activity_provider_options hash + event_type = options.delete(:type) || self.name.underscore.pluralize + + options[:timestamp] ||= "#{table_name}.created_on" + options[:find_options] ||= {} + options[:author_key] = "#{table_name}.#{options[:author_key]}" if options[:author_key].is_a?(Symbol) + self.activity_provider_options[event_type] = options + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + # Returns events of type event_type visible by user that occured between from and to + def find_events(event_type, user, from, to, options) + provider_options = activity_provider_options[event_type] + raise "#{self.name} can not provide #{event_type} events." if provider_options.nil? + + scope_options = {} + cond = ARCondition.new + if from && to + cond.add(["#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to]) + end + + if options[:author] + return [] if provider_options[:author_key].nil? + cond.add(["#{provider_options[:author_key]} = ?", options[:author].id]) + end + + if options[:limit] + # id and creation time should be in same order in most cases + scope_options[:order] = "#{table_name}.id DESC" + scope_options[:limit] = options[:limit] + end + + scope = self + if provider_options.has_key?(:permission) + cond.add(Project.allowed_to_condition(user, provider_options[:permission] || :view_project, options)) + elsif respond_to?(:visible) + scope = scope.visible(user, options) + else + ActiveSupport::Deprecation.warn "acts_as_activity_provider with implicit :permission option is deprecated. Add a visible scope to the #{self.name} model or use explicit :permission option." + cond.add(Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym, options)) + end + scope_options[:conditions] = cond.conditions + + with_scope(:find => scope_options) do + scope.find(:all, provider_options[:find_options].dup) + end + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7c/7c0793046e6842f067096f93f3d1b6e963a83b49.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7c/7c0793046e6842f067096f93f3d1b6e963a83b49.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Views + class OtherFormatsBuilder + def initialize(view) + @view = view + end + + def link_to(name, options={}) + url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {}) + caption = options.delete(:caption) || name + html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options) + @view.content_tag('span', @view.link_to(caption, url, html_options)) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7c/7c1301162ea6bb82a007534a13501f191a1f47c9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7c/7c1301162ea6bb82a007534a13501f191a1f47c9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,90 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class JournalTest < ActiveSupport::TestCase + fixtures :projects, :issues, :issue_statuses, :journals, :journal_details, :users, :members, :member_roles + + def setup + @journal = Journal.find 1 + end + + def test_journalized_is_an_issue + issue = @journal.issue + assert_kind_of Issue, issue + assert_equal 1, issue.id + end + + def test_new_status + status = @journal.new_status + assert_not_nil status + assert_kind_of IssueStatus, status + assert_equal 2, status.id + end + + def test_create_should_send_email_notification + ActionMailer::Base.deliveries.clear + issue = Issue.find(:first) + user = User.find(:first) + journal = issue.init_journal(user, issue) + + assert journal.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_visible_scope_for_anonymous + # Anonymous user should see issues of public projects only + journals = Journal.visible(User.anonymous).all + assert journals.any? + assert_nil journals.detect {|journal| !journal.issue.project.is_public?} + # Anonymous user should not see issues without permission + Role.anonymous.remove_permission!(:view_issues) + journals = Journal.visible(User.anonymous).all + assert journals.empty? + end + + def test_visible_scope_for_user + user = User.find(9) + assert user.projects.empty? + # Non member user should see issues of public projects only + journals = Journal.visible(user).all + assert journals.any? + assert_nil journals.detect {|journal| !journal.issue.project.is_public?} + # Non member user should not see issues without permission + Role.non_member.remove_permission!(:view_issues) + user.reload + journals = Journal.visible(user).all + assert journals.empty? + # User should see issues of projects for which he has view_issues permissions only + Member.create!(:principal => user, :project_id => 1, :role_ids => [1]) + user.reload + journals = Journal.visible(user).all + assert journals.any? + assert_nil journals.detect {|journal| journal.issue.project_id != 1} + end + + def test_visible_scope_for_admin + user = User.find(1) + user.members.each(&:destroy) + assert user.projects.empty? + journals = Journal.visible(user).all + assert journals.any? + # Admin should see issues on private projects that he does not belong to + assert journals.detect {|journal| !journal.issue.project.is_public?} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7c/7c5921f65fb9645b9f52a7d0124578fab27871e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7c/7c5921f65fb9645b9f52a7d0124578fab27871e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<% remote_form_for :repository, @repository, + :url => { :controller => 'repositories', :action => 'edit', :id => @project }, + :builder => TabularFormBuilder, + :lang => current_language do |f| %> + +<%= error_messages_for 'repository' %> + +
    +

    +<%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %> +<% if @repository && ! @repository.class.scm_available %> +
    + <%= content_tag 'span', l(:text_scm_command_not_available), :class => 'error' %> +<% end %> +

    +<% button_disabled = true %> +<% if @repository %> +<% button_disabled = ! @repository.class.scm_available %> +<%= repository_field_tags(f, @repository)%> +<% end %> +
    + +
    +<% if @repository && !@repository.new_record? %> +<%= link_to(l(:label_user_plural), + { + :controller => 'repositories', + :action => 'committers', + :id => @project + }, + :class => 'icon icon-user') %> +<%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project}, + :confirm => l(:text_are_you_sure), + :method => :post, + :class => 'icon icon-del') %> +<% end %> +
    + +<%= submit_tag((@repository.nil? || @repository.new_record?) ? l(:button_create) : l(:button_save), + :disabled => button_disabled) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7c/7c8eae02c98b193159d580b9779b53a3e1041ed2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7c/7c8eae02c98b193159d580b9779b53a3e1041ed2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +
    +
      + <%= render_menu :admin_menu %> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7d0c82a8b17bf23c8cab9114300db25398956dda.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7d0c82a8b17bf23c8cab9114300db25398956dda.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,70 @@ +@import url(../../../stylesheets/application.css); + +body, #wrapper { background-color:#EEEEEE; } +#header, #top-menu { margin: 0px 10px 0px 11px; } +#main { background: #EEEEEE; margin: 8px 10px 0px 10px; } +#content, #main.nosidebar #content { background: #fff; border-right: 1px solid #bbb; border-bottom: 1px solid #bbb; border-left: 1px solid #d7d7d7; border-top: 1px solid #d7d7d7; } +#footer { background-color:#EEEEEE; border: 0px; } + +/* Headers */ +h2, h3, h4, .wiki h1, .wiki h2, .wiki h3 {border-bottom: 0px;} + +/* Menu */ +#main-menu li a { background-color: #507AAA; font-weight: bold;} +#main-menu li a:hover { background: #507AAA; text-decoration: underline; } +#main-menu li a.selected, #main-menu li a.selected:hover { background-color:#EEEEEE; } + +/* Tables */ +table.list tbody td, table.list tbody tr:hover td { border: solid 1px #d7d7d7; } +table.list thead th { + border-width: 1px; + border-style: solid; + border-top-color: #d7d7d7; + border-right-color: #d7d7d7; + border-left-color: #d7d7d7; + border-bottom-color: #999999; +} + +/* Issues grid styles by priorities (provided by Wynn Netherland) */ +table.list tr.issue a { color: #666; } + +tr.odd.priority-5, table.list tbody tr.odd.priority-5:hover { color: #900; font-weight: bold; } +tr.odd.priority-5 { background: #ffc4c4; } +tr.even.priority-5, table.list tbody tr.even.priority-5:hover { color: #900; font-weight: bold; } +tr.even.priority-5 { background: #ffd4d4; } +tr.priority-5 a, tr.priority-5:hover a { color: #900; } +tr.odd.priority-5 td, tr.even.priority-5 td { border-color: #ffb4b4; } + +tr.odd.priority-4, table.list tbody tr.odd.priority-4:hover { color: #900; } +tr.odd.priority-4 { background: #ffc4c4; } +tr.even.priority-4, table.list tbody tr.even.priority-4:hover { color: #900; } +tr.even.priority-4 { background: #ffd4d4; } +tr.priority-4 a { color: #900; } +tr.odd.priority-4 td, tr.even.priority-4 td { border-color: #ffb4b4; } + +tr.odd.priority-3, table.list tbody tr.odd.priority-3:hover { color: #900; } +tr.odd.priority-3 { background: #fee; } +tr.even.priority-3, table.list tbody tr.even.priority-3:hover { color: #900; } +tr.even.priority-3 { background: #fff2f2; } +tr.priority-3 a { color: #900; } +tr.odd.priority-3 td, tr.even.priority-3 td { border-color: #fcc; } + +tr.odd.priority-1, table.list tbody tr.odd.priority-1:hover { color: #559; } +tr.odd.priority-1 { background: #eaf7ff; } +tr.even.priority-1, table.list tbody tr.even.priority-1:hover { color: #559; } +tr.even.priority-1 { background: #f2faff; } +tr.priority-1 a { color: #559; } +tr.odd.priority-1 td, tr.even.priority-1 td { border-color: #add7f3; } + +/* Buttons */ +input[type="button"], input[type="submit"], input[type="reset"] { background-color: #f2f2f2; color: #222222; border: 1px outset #cccccc; } +input[type="button"]:hover, input[type="submit"]:hover, input[type="reset"]:hover { background-color: #ccccbb; } + +/* Fields */ +input[type="text"], input[type="password"], textarea, select { padding: 2px; border: 1px solid #d7d7d7; } +input[type="text"], input[type="password"] { padding: 3px; } +input[type="text"]:focus, input[type="password"]:focus, textarea:focus, select:focus { border: 1px solid #888866; } +option { border-bottom: 1px dotted #d7d7d7; } + +/* Misc */ +.box { background-color: #fcfcfc; } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7d0db9ae9f70acc895b7957ff399876fc83ab2bc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7d0db9ae9f70acc895b7957ff399876fc83ab2bc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,405 @@ +module ActionController + # === Action Pack pagination for Active Record collections + # + # The Pagination module aids in the process of paging large collections of + # Active Record objects. It offers macro-style automatic fetching of your + # model for multiple views, or explicit fetching for single actions. And if + # the magic isn't flexible enough for your needs, you can create your own + # paginators with a minimal amount of code. + # + # The Pagination module can handle as much or as little as you wish. In the + # controller, have it automatically query your model for pagination; or, + # if you prefer, create Paginator objects yourself. + # + # Pagination is included automatically for all controllers. + # + # For help rendering pagination links, see + # ActionView::Helpers::PaginationHelper. + # + # ==== Automatic pagination for every action in a controller + # + # class PersonController < ApplicationController + # model :person + # + # paginate :people, :order => 'last_name, first_name', + # :per_page => 20 + # + # # ... + # end + # + # Each action in this controller now has access to a @people + # instance variable, which is an ordered collection of model objects for the + # current page (at most 20, sorted by last name and first name), and a + # @person_pages Paginator instance. The current page is determined + # by the params[:page] variable. + # + # ==== Pagination for a single action + # + # def list + # @person_pages, @people = + # paginate :people, :order => 'last_name, first_name' + # end + # + # Like the previous example, but explicitly creates @person_pages + # and @people for a single action, and uses the default of 10 items + # per page. + # + # ==== Custom/"classic" pagination + # + # def list + # @person_pages = Paginator.new self, Person.count, 10, params[:page] + # @people = Person.find :all, :order => 'last_name, first_name', + # :limit => @person_pages.items_per_page, + # :offset => @person_pages.current.offset + # end + # + # Explicitly creates the paginator from the previous example and uses + # Paginator#to_sql to retrieve @people from the model. + # + module Pagination + unless const_defined?(:OPTIONS) + # A hash holding options for controllers using macro-style pagination + OPTIONS = Hash.new + + # The default options for pagination + DEFAULT_OPTIONS = { + :class_name => nil, + :singular_name => nil, + :per_page => 10, + :conditions => nil, + :order_by => nil, + :order => nil, + :join => nil, + :joins => nil, + :count => nil, + :include => nil, + :select => nil, + :group => nil, + :parameter => 'page' + } + else + DEFAULT_OPTIONS[:group] = nil + end + + def self.included(base) #:nodoc: + super + base.extend(ClassMethods) + end + + def self.validate_options!(collection_id, options, in_action) #:nodoc: + options.merge!(DEFAULT_OPTIONS) {|key, old, new| old} + + valid_options = DEFAULT_OPTIONS.keys + valid_options << :actions unless in_action + + unknown_option_keys = options.keys - valid_options + raise ActionController::ActionControllerError, + "Unknown options: #{unknown_option_keys.join(', ')}" unless + unknown_option_keys.empty? + + options[:singular_name] ||= ActiveSupport::Inflector.singularize(collection_id.to_s) + options[:class_name] ||= ActiveSupport::Inflector.camelize(options[:singular_name]) + end + + # Returns a paginator and a collection of Active Record model instances + # for the paginator's current page. This is designed to be used in a + # single action; to automatically paginate multiple actions, consider + # ClassMethods#paginate. + # + # +options+ are: + # :singular_name:: the singular name to use, if it can't be inferred by singularizing the collection name + # :class_name:: the class name to use, if it can't be inferred by + # camelizing the singular name + # :per_page:: the maximum number of items to include in a + # single page. Defaults to 10 + # :conditions:: optional conditions passed to Model.find(:all, *params) and + # Model.count + # :order:: optional order parameter passed to Model.find(:all, *params) + # :order_by:: (deprecated, used :order) optional order parameter passed to Model.find(:all, *params) + # :joins:: optional joins parameter passed to Model.find(:all, *params) + # and Model.count + # :join:: (deprecated, used :joins or :include) optional join parameter passed to Model.find(:all, *params) + # and Model.count + # :include:: optional eager loading parameter passed to Model.find(:all, *params) + # and Model.count + # :select:: :select parameter passed to Model.find(:all, *params) + # + # :count:: parameter passed as :select option to Model.count(*params) + # + # :group:: :group parameter passed to Model.find(:all, *params). It forces the use of DISTINCT instead of plain COUNT to come up with the total number of records + # + def paginate(collection_id, options={}) + Pagination.validate_options!(collection_id, options, true) + paginator_and_collection_for(collection_id, options) + end + + # These methods become class methods on any controller + module ClassMethods + # Creates a +before_filter+ which automatically paginates an Active + # Record model for all actions in a controller (or certain actions if + # specified with the :actions option). + # + # +options+ are the same as PaginationHelper#paginate, with the addition + # of: + # :actions:: an array of actions for which the pagination is + # active. Defaults to +nil+ (i.e., every action) + def paginate(collection_id, options={}) + Pagination.validate_options!(collection_id, options, false) + module_eval do + before_filter :create_paginators_and_retrieve_collections + OPTIONS[self] ||= Hash.new + OPTIONS[self][collection_id] = options + end + end + end + + def create_paginators_and_retrieve_collections #:nodoc: + Pagination::OPTIONS[self.class].each do |collection_id, options| + next unless options[:actions].include? action_name if + options[:actions] + + paginator, collection = + paginator_and_collection_for(collection_id, options) + + paginator_name = "@#{options[:singular_name]}_pages" + self.instance_variable_set(paginator_name, paginator) + + collection_name = "@#{collection_id.to_s}" + self.instance_variable_set(collection_name, collection) + end + end + + # Returns the total number of items in the collection to be paginated for + # the +model+ and given +conditions+. Override this method to implement a + # custom counter. + def count_collection_for_pagination(model, options) + model.count(:conditions => options[:conditions], + :joins => options[:join] || options[:joins], + :include => options[:include], + :select => (options[:group] ? "DISTINCT #{options[:group]}" : options[:count])) + end + + # Returns a collection of items for the given +model+ and +options[conditions]+, + # ordered by +options[order]+, for the current page in the given +paginator+. + # Override this method to implement a custom finder. + def find_collection_for_pagination(model, options, paginator) + model.find(:all, :conditions => options[:conditions], + :order => options[:order_by] || options[:order], + :joins => options[:join] || options[:joins], :include => options[:include], + :select => options[:select], :limit => options[:per_page], + :group => options[:group], :offset => paginator.current.offset) + end + + protected :create_paginators_and_retrieve_collections, + :count_collection_for_pagination, + :find_collection_for_pagination + + def paginator_and_collection_for(collection_id, options) #:nodoc: + klass = options[:class_name].constantize + page = params[options[:parameter]] + count = count_collection_for_pagination(klass, options) + paginator = Paginator.new(self, count, options[:per_page], page) + collection = find_collection_for_pagination(klass, options, paginator) + + return paginator, collection + end + + private :paginator_and_collection_for + + # A class representing a paginator for an Active Record collection. + class Paginator + include Enumerable + + # Creates a new Paginator on the given +controller+ for a set of items + # of size +item_count+ and having +items_per_page+ items per page. + # Raises ArgumentError if items_per_page is out of bounds (i.e., less + # than or equal to zero). The page CGI parameter for links defaults to + # "page" and can be overridden with +page_parameter+. + def initialize(controller, item_count, items_per_page, current_page=1) + raise ArgumentError, 'must have at least one item per page' if + items_per_page <= 0 + + @controller = controller + @item_count = item_count || 0 + @items_per_page = items_per_page + @pages = {} + + self.current_page = current_page + end + attr_reader :controller, :item_count, :items_per_page + + # Sets the current page number of this paginator. If +page+ is a Page + # object, its +number+ attribute is used as the value; if the page does + # not belong to this Paginator, an ArgumentError is raised. + def current_page=(page) + if page.is_a? Page + raise ArgumentError, 'Page/Paginator mismatch' unless + page.paginator == self + end + page = page.to_i + @current_page_number = has_page_number?(page) ? page : 1 + end + + # Returns a Page object representing this paginator's current page. + def current_page + @current_page ||= self[@current_page_number] + end + alias current :current_page + + # Returns a new Page representing the first page in this paginator. + def first_page + @first_page ||= self[1] + end + alias first :first_page + + # Returns a new Page representing the last page in this paginator. + def last_page + @last_page ||= self[page_count] + end + alias last :last_page + + # Returns the number of pages in this paginator. + def page_count + @page_count ||= @item_count.zero? ? 1 : + (q,r=@item_count.divmod(@items_per_page); r==0? q : q+1) + end + + alias length :page_count + + # Returns true if this paginator contains the page of index +number+. + def has_page_number?(number) + number >= 1 and number <= page_count + end + + # Returns a new Page representing the page with the given index + # +number+. + def [](number) + @pages[number] ||= Page.new(self, number) + end + + # Successively yields all the paginator's pages to the given block. + def each(&block) + page_count.times do |n| + yield self[n+1] + end + end + + # A class representing a single page in a paginator. + class Page + include Comparable + + # Creates a new Page for the given +paginator+ with the index + # +number+. If +number+ is not in the range of valid page numbers or + # is not a number at all, it defaults to 1. + def initialize(paginator, number) + @paginator = paginator + @number = number.to_i + @number = 1 unless @paginator.has_page_number? @number + end + attr_reader :paginator, :number + alias to_i :number + + # Compares two Page objects and returns true when they represent the + # same page (i.e., their paginators are the same and they have the + # same page number). + def ==(page) + return false if page.nil? + @paginator == page.paginator and + @number == page.number + end + + # Compares two Page objects and returns -1 if the left-hand page comes + # before the right-hand page, 0 if the pages are equal, and 1 if the + # left-hand page comes after the right-hand page. Raises ArgumentError + # if the pages do not belong to the same Paginator object. + def <=>(page) + raise ArgumentError unless @paginator == page.paginator + @number <=> page.number + end + + # Returns the item offset for the first item in this page. + def offset + @paginator.items_per_page * (@number - 1) + end + + # Returns the number of the first item displayed. + def first_item + offset + 1 + end + + # Returns the number of the last item displayed. + def last_item + [@paginator.items_per_page * @number, @paginator.item_count].min + end + + # Returns true if this page is the first page in the paginator. + def first? + self == @paginator.first + end + + # Returns true if this page is the last page in the paginator. + def last? + self == @paginator.last + end + + # Returns a new Page object representing the page just before this + # page, or nil if this is the first page. + def previous + if first? then nil else @paginator[@number - 1] end + end + + # Returns a new Page object representing the page just after this + # page, or nil if this is the last page. + def next + if last? then nil else @paginator[@number + 1] end + end + + # Returns a new Window object for this page with the specified + # +padding+. + def window(padding=2) + Window.new(self, padding) + end + + # Returns the limit/offset array for this page. + def to_sql + [@paginator.items_per_page, offset] + end + + def to_param #:nodoc: + @number.to_s + end + end + + # A class for representing ranges around a given page. + class Window + # Creates a new Window object for the given +page+ with the specified + # +padding+. + def initialize(page, padding=2) + @paginator = page.paginator + @page = page + self.padding = padding + end + attr_reader :paginator, :page + + # Sets the window's padding (the number of pages on either side of the + # window page). + def padding=(padding) + @padding = padding < 0 ? 0 : padding + # Find the beginning and end pages of the window + @first = @paginator.has_page_number?(@page.number - @padding) ? + @paginator[@page.number - @padding] : @paginator.first + @last = @paginator.has_page_number?(@page.number + @padding) ? + @paginator[@page.number + @padding] : @paginator.last + end + attr_reader :padding, :first, :last + + # Returns an array of Page objects in the current window. + def pages + (@first.number..@last.number).to_a.collect! {|n| @paginator[n]} + end + alias to_a :pages + end + end + + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7d5542a86c76a11843ec180cbabc95e565d1b1cf.svn-base Binary file .svn/pristine/7d/7d5542a86c76a11843ec180cbabc95e565d1b1cf.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7d7a63dac05990ebb68fcd3fce0da9965a2d6f7a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7d7a63dac05990ebb68fcd3fce0da9965a2d6f7a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,282 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'repositories_controller' + +# Re-raise errors caught by the controller. +class RepositoriesController; def rescue_action(e) raise e end; end + +class RepositoriesCvsControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules + + REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s + REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? + # CVS module + MODULE_NAME = 'test' + PRJ_ID = 3 + NUM_REV = 7 + + def setup + @controller = RepositoriesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + Setting.default_language = 'en' + User.current = nil + + @project = Project.find(PRJ_ID) + @repository = Repository::Cvs.create(:project => Project.find(PRJ_ID), + :root_url => REPOSITORY_PATH, + :url => MODULE_NAME, + :log_encoding => 'UTF-8') + assert @repository + end + + if File.directory?(REPOSITORY_PATH) + def test_browse_root + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal 3, assigns(:entries).size + + entry = assigns(:entries).detect {|e| e.name == 'images'} + assert_equal 'dir', entry.kind + + entry = assigns(:entries).detect {|e| e.name == 'README'} + assert_equal 'file', entry.kind + + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_browse_directory + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name) + entry = assigns(:entries).detect {|e| e.name == 'edit.png'} + assert_not_nil entry + assert_equal 'file', entry.kind + assert_equal 'images/edit.png', entry.path + end + + def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'], :rev => 1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) + end + + def test_entry + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'entry' + assert_no_tag :tag => 'td', + :attributes => { :class => /line-code/}, + :content => /before_filter/ + end + + def test_entry_at_given_revision + # changesets must be loaded + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], :rev => 2 + assert_response :success + assert_template 'entry' + # this line was removed in r3 + assert_tag :tag => 'td', + :attributes => { :class => /line-code/}, + :content => /before_filter/ + end + + def test_entry_not_found + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :entry, :id => PRJ_ID, :path => ['sources', 'zzz.c'] + assert_tag :tag => 'p', + :attributes => { :id => /errorExplanation/ }, + :content => /The entry or revision was not found in the repository/ + end + + def test_entry_download + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], + :format => 'raw' + assert_response :success + end + + def test_directory_entry + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :entry, :id => PRJ_ID, :path => ['sources'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entry) + assert_equal 'sources', assigns(:entry).name + end + + def test_diff + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 3, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_out' }, + :content => /before_filter :require_login/ + assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' }, + :content => /with one change/ + end + end + + def test_diff_new_files + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 1, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' }, + :content => /watched.remove_watcher/ + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/README/ + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/images\/delete.png / + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/images\/edit.png/ + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/sources\/watchers_controller.rb/ + end + end + + def test_annotate + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'annotate' + # 1.1 line + assert_tag :tag => 'th', + :attributes => { :class => 'line-num' }, + :content => '18', + :sibling => { + :tag => 'td', + :attributes => { :class => 'revision' }, + :content => /1.1/, + :sibling => { + :tag => 'td', + :attributes => { :class => 'author' }, + :content => /LANG/ + } + } + # 1.2 line + assert_tag :tag => 'th', + :attributes => { :class => 'line-num' }, + :content => '32', + :sibling => { + :tag => 'td', + :attributes => { :class => 'revision' }, + :content => /1.2/, + :sibling => { + :tag => 'td', + :attributes => { :class => 'author' }, + :content => /LANG/ + } + } + end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Cvs.create( + :project => Project.find(PRJ_ID), + :root_url => "/invalid", + :url => MODULE_NAME, + :log_encoding => 'UTF-8' + ) + assert @repository + @repository.fetch_changesets + @project.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + else + puts "CVS test repository NOT FOUND. Skipping functional tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7d991b7e62a4f89e1face67a97364500bbbfb59d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7d991b7e62a4f89e1face67a97364500bbbfb59d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1632 @@ +# Ruby FPDF 1.53d +# FPDF 1.53 by Olivier Plathey ported to Ruby by Brian Ollenberger +# Copyright 2005 Brian Ollenberger +# Please retain this entire copyright notice. If you distribute any +# modifications, place an additional comment here that clearly indicates +# that it was modified. You may (but are not send any useful modifications that you make +# back to me at http://zeropluszero.com/software/fpdf/ + +# Bug fixes, examples, external fonts, JPEG support, and upgrade to version +# 1.53 contributed by Kim Shrier. +# +# Bookmark support contributed by Sylvain Lafleur. +# +# EPS support contributed by Thiago Jackiw, ported from the PHP version by Valentin Schmidt. +# +# Bookmarks contributed by Sylvain Lafleur. +# +# 1.53 contributed by Ed Moss +# Make sure all \n references are inside double quotes - Fix some multicell bugs +# Handle "\n" at the beginning of a string +# Bookmarks contributed by Sylvain Lafleur. + +require 'date' +require 'zlib' + +class FPDF + include RFPDF + + attr_accessor :default_font + + FPDF_VERSION = '1.53d' + + Charwidths = { + 'courier'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'courierB'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'courierI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'courierBI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600], + + 'helvetica'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500], + + 'helveticaB'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556], + + 'helveticaI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500], + + 'helveticaBI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556], + + 'times'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 350, 500, 350, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 350, 611, 350, 350, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500], + + 'timesB'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 350, 667, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500], + + 'timesI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 350, 500, 350, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 350, 556, 350, 350, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 350, 389, 556, 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444], + + 'timesBI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 350, 611, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 389, 611, 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333, 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444], + + 'symbol'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0], + + 'zapfdingbats'=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0] + } + + def initialize(orientation='P', unit='mm', format='A4') + # Initialization of properties + @page=0 + @n=2 + @buffer='' + @pages=[] + @OrientationChanges=[] + @state=0 + @default_font = "arial" + @fonts={} + @FontFiles={} + @diffs=[] + @images={} + @links=[] + @PageLinks={} + @InFooter=false + @FontFamily='' + @FontStyle='' + @FontSizePt=12 + @underline= false + @DrawColor='0 G' + @FillColor='0 g' + @TextColor='0 g' + @ColorFlag=false + @ws=0 + @offsets=[] + + # Standard fonts + @CoreFonts={} + @CoreFonts['courier']='Courier' + @CoreFonts['courierB']='Courier-Bold' + @CoreFonts['courierI']='Courier-Oblique' + @CoreFonts['courierBI']='Courier-BoldOblique' + @CoreFonts['helvetica']='Helvetica' + @CoreFonts['helveticaB']='Helvetica-Bold' + @CoreFonts['helveticaI']='Helvetica-Oblique' + @CoreFonts['helveticaBI']='Helvetica-BoldOblique' + @CoreFonts['times']='Times-Roman' + @CoreFonts['timesB']='Times-Bold' + @CoreFonts['timesI']='Times-Italic' + @CoreFonts['timesBI']='Times-BoldItalic' + @CoreFonts['symbol']='Symbol' + @CoreFonts['zapfdingbats']='ZapfDingbats' + + # Scale factor + if unit=='pt' + @k=1 + elsif unit=='mm' + @k=72/25.4 + elsif unit=='cm' + @k=72/2.54; + elsif unit=='in' + @k=72 + else + raise 'Incorrect unit: '+unit + end + + # Page format + if format.is_a? String + format.downcase! + if format=='a3' + format=[841.89,1190.55] + elsif format=='a4' + format=[595.28,841.89] + elsif format=='a5' + format=[420.94,595.28] + elsif format=='letter' + format=[612,792] + elsif format=='legal' + format=[612,1008] + else + raise 'Unknown page format: '+format + end + @fwPt,@fhPt=format + else + @fwPt=format[0]*@k + @fhPt=format[1]*@k + end + @fw=@fwPt/@k; + @fh=@fhPt/@k; + + # Page orientation + orientation.downcase! + if orientation=='p' or orientation=='portrait' + @DefOrientation='P' + @wPt=@fwPt + @hPt=@fhPt + elsif orientation=='l' or orientation=='landscape' + @DefOrientation='L' + @wPt=@fhPt + @hPt=@fwPt + else + raise 'Incorrect orientation: '+orientation + end + @CurOrientation=@DefOrientation + @w=@wPt/@k + @h=@hPt/@k + + # Page margins (1 cm) + margin=28.35/@k + SetMargins(margin,margin) + # Interior cell margin (1 mm) + @cMargin=margin/10 + # Line width (0.2 mm) + @LineWidth=0.567/@k + # Automatic page break + SetAutoPageBreak(true,2*margin) + # Full width display mode + SetDisplayMode('fullwidth') + # Enable compression + SetCompression(true) + # Set default PDF version number + @PDFVersion='1.3' + end + + def GetMargins() + return @lMargin, @tMargin, @rMargin + end + + def SetMargins(left, top, right=-1) + # Set left, top and right margins + @lMargin=left + @tMargin=top + right=left if right==-1 + @rMargin=right + end + + def SetLeftMargin(margin) + # Set left margin + @lMargin=margin + @x=margin if @page>0 and @x0 + # Page footer + @InFooter=true + self.Footer + @InFooter=false + # Close page + endpage + end + # Start new page + beginpage(orientation) + # Set line cap style to square + out('2 J') + # Set line width + @LineWidth=lw + out(sprintf('%.2f w',lw*@k)) + # Set font + SetFont(family,style,size) if family + # Set colors + @DrawColor=dc + out(dc) if dc!='0 G' + @FillColor=fc + out(fc) if fc!='0 g' + @TextColor=tc + @ColorFlag=cf + # Page header + self.Header + # Restore line width + if @LineWidth!=lw + @LineWidth=lw + out(sprintf('%.2f w',lw*@k)) + end + # Restore font + self.SetFont(family,style,size) if family + # Restore colors + if @DrawColor!=dc + @DrawColor=dc + out(dc) + end + if @FillColor!=fc + @FillColor=fc + out(fc) + end + @TextColor=tc + @ColorFlag=cf + end + alias_method :add_page, :AddPage + + def Header + # To be implemented in your inherited class + end + + def Footer + # To be implemented in your inherited class + end + + def PageNo + # Get current page number + @page + end + + def SetDrawColor(r,g=-1,b=-1) + # Set color for all stroking operations + if (r==0 and g==0 and b==0) or g==-1 + @DrawColor=sprintf('%.3f G',r/255.0) + else + @DrawColor=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0) + end + out(@DrawColor) if(@page>0) + end + + def SetFillColor(r,g=-1,b=-1) + # Set color for all filling operations + if (r==0 and g==0 and b==0) or g==-1 + @FillColor=sprintf('%.3f g',r/255.0) + else + @FillColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) + end + @ColorFlag=(@FillColor!=@TextColor) + out(@FillColor) if(@page>0) + end + + def SetTextColor(r,g=-1,b=-1) + # Set color for text + if (r==0 and g==0 and b==0) or g==-1 + @TextColor=sprintf('%.3f g',r/255.0) + else + @TextColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) + end + @ColorFlag=(@FillColor!=@TextColor) + end + + def GetCharWidth(widths, index) + if index.is_a?(String) + widths[index.ord] + else + widths[index] + end + end + + def GetStringWidth(s) + # Get width of a string in the current font + cw=@CurrentFont['cw'] + w=0 + s.each_byte do |c| + w=w+GetCharWidth(cw, c) + end + w*@FontSize/1000.0 + end + + def SetLineWidth(width) + # Set line width + @LineWidth=width + out(sprintf('%.2f w',width*@k)) if @page>0 + end + + def Circle(mid_x, mid_y, radius, style='') + mid_y = (@h-mid_y)*@k + out(sprintf("q\n")) # postscript content in pdf + # init line type etc. with /GSD gs G g (grey) RG rg (RGB) w=line witdh etc. + out(sprintf("1 j\n")) # line join + # translate ("move") circle to mid_y, mid_y + out(sprintf("1 0 0 1 %f %f cm", mid_x, mid_y)) + kappa = 0.5522847498307933984022516322796 + # Quadrant 1 + x_s = 0.0 # 12 o'clock + y_s = 0.0 + radius + x_e = 0.0 + radius # 3 o'clock + y_e = 0.0 + out(sprintf("%f %f m\n", x_s, y_s)) # move to 12 o'clock + # cubic bezier control point 1, start height and kappa * radius to the right + bx_e1 = x_s + (radius * kappa) + by_e1 = y_s + # cubic bezier control point 2, end and kappa * radius above + bx_e2 = x_e + by_e2 = y_e + (radius * kappa) + # draw cubic bezier from current point to x_e/y_e with bx_e1/by_e1 and bx_e2/by_e2 as bezier control points + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + # Quadrant 2 + x_s = x_e + y_s = y_e # 3 o'clock + x_e = 0.0 + y_e = 0.0 - radius # 6 o'clock + bx_e1 = x_s # cubic bezier point 1 + by_e1 = y_s - (radius * kappa) + bx_e2 = x_e + (radius * kappa) # cubic bezier point 2 + by_e2 = y_e + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + # Quadrant 3 + x_s = x_e + y_s = y_e # 6 o'clock + x_e = 0.0 - radius + y_e = 0.0 # 9 o'clock + bx_e1 = x_s - (radius * kappa) # cubic bezier point 1 + by_e1 = y_s + bx_e2 = x_e # cubic bezier point 2 + by_e2 = y_e - (radius * kappa) + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + # Quadrant 4 + x_s = x_e + y_s = y_e # 9 o'clock + x_e = 0.0 + y_e = 0.0 + radius # 12 o'clock + bx_e1 = x_s # cubic bezier point 1 + by_e1 = y_s + (radius * kappa) + bx_e2 = x_e - (radius * kappa) # cubic bezier point 2 + by_e2 = y_e + out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e)) + if style=='F' + op='f' + elsif style=='FD' or style=='DF' + op='b' + else + op='s' + end + out(sprintf("#{op}\n")) # stroke circle, do not fill and close path + # for filling etc. b, b*, f, f* + out(sprintf("Q\n")) # finish postscript in PDF + end + + def Line(x1, y1, x2, y2) + # Draw a line + out(sprintf('%.2f %.2f m %.2f %.2f l S', + x1*@k,(@h-y1)*@k,x2*@k,(@h-y2)*@k)) + end + + def Rect(x, y, w, h, style='') + # Draw a rectangle + if style=='F' + op='f' + elsif style=='FD' or style=='DF' + op='B' + else + op='S' + end + # x y width height re + out(sprintf('%.2f %.2f %.2f %.2f re %s', x*@k,(@h-y)*@k,w*@k,-h*@k,op)) + end + + def AddFont(family, style='', file='') + # Add a TrueType or Type1 font + family = family.downcase + family = 'helvetica' if family == 'arial' + + style = style.upcase + style = 'BI' if style == 'IB' + + fontkey = family + style + + if @fonts.has_key?(fontkey) + self.Error("Font already added: #{family} #{style}") + end + + file = family.gsub(' ', '') + style.downcase + '.rb' if file == '' + + if self.class.const_defined? 'FPDF_FONTPATH' + if FPDF_FONTPATH[-1,1] == '/' + file = FPDF_FONTPATH + file + else + file = FPDF_FONTPATH + '/' + file + end + end + + # Changed from "require file" to fix bug reported by Hans Allis. + load file + + if FontDef.desc.nil? + self.Error("Could not include font definition file #{file}") + end + + i = @fonts.length + 1 + + @fonts[fontkey] = {'i' => i, + 'type' => FontDef.type, + 'name' => FontDef.name, + 'desc' => FontDef.desc, + 'up' => FontDef.up, + 'ut' => FontDef.ut, + 'cw' => FontDef.cw, + 'enc' => FontDef.enc, + 'file' => FontDef.file + } + + if FontDef.diff + # Search existing encodings + unless @diffs.include?(FontDef.diff) + @diffs.push(FontDef.diff) + @fonts[fontkey]['diff'] = @diffs.length - 1 + end + end + + if FontDef.file + if FontDef.type == 'TrueType' + @FontFiles[FontDef.file] = {'length1' => FontDef.originalsize} + else + @FontFiles[FontDef.file] = {'length1' => FontDef.size1, 'length2' => FontDef.size2} + end + end + + return self + end + + def SetFont(family, style='', size=0) + # Select a font; size given in points + family.downcase! + family=@FontFamily if family=='' + if family=='arial' + family='helvetica' + elsif family=='symbol' or family=='zapfdingbats' + style='' + end + style.upcase! + unless style.index('U').nil? + @underline=true + style.gsub!('U','') + else + @underline=false; + end + style='BI' if style=='IB' + size=@FontSizePt if size==0 + # Test if font is already selected + return if @FontFamily==family and + @FontStyle==style and @FontSizePt==size + # Test if used for the first time + fontkey=family+style + unless @fonts.has_key?(fontkey) + if @CoreFonts.has_key?(fontkey) + unless Charwidths.has_key?(fontkey) + raise 'Font unavailable' + end + @fonts[fontkey]={ + 'i'=>@fonts.size, + 'type'=>'core', + 'name'=>@CoreFonts[fontkey], + 'up'=>-100, + 'ut'=>50, + 'cw'=>Charwidths[fontkey]} + else + raise 'Font unavailable' + end + end + + #Select it + @FontFamily=family + @FontStyle=style; + @FontSizePt=size + @FontSize=size/@k; + @CurrentFont=@fonts[fontkey] + if @page>0 + out(sprintf('BT /F%d %.2f Tf ET', @CurrentFont['i'], @FontSizePt)) + end + end + + def SetFontSize(size) + # Set font size in points + return if @FontSizePt==size + @FontSizePt=size + @FontSize=size/@k + if @page>0 + out(sprintf('BT /F%d %.2f Tf ET',@CurrentFont['i'],@FontSizePt)) + end + end + + def AddLink + # Create a new internal link + @links.push([0, 0]) + @links.size + end + + def SetLink(link, y=0, page=-1) + # Set destination of internal link + y=@y if y==-1 + page=@page if page==-1 + @links[link]=[page, y] + end + + def Link(x, y, w, h, link) + # Put a link on the page + @PageLinks[@page]=Array.new unless @PageLinks.has_key?(@Page) + @PageLinks[@page].push([x*@k,@hPt-y*@k,w*@k,h*@k,link]) + end + + def Text(x, y, txt) + # Output a string + s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*@k,(@h-y)*@k, escape(txt)); + s=s+' '+dounderline(x,y,txt) if @underline and txt!='' + s='q '+@TextColor+' '+s+' Q' if @ColorFlag + out(s) + end + + def AcceptPageBreak + # Accept automatic page break or not + @AutoPageBreak + end + + def BreakThePage?(h) + if (@y + h) > @PageBreakTrigger and !@InFooter and self.AcceptPageBreak + true + else + false + end + end + + def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') + # Output a cell + if self.BreakThePage?(h) + # Automatic page break + x=@x + ws=@ws + if ws>0 + @ws=0 + out('0 Tw') + end + self.AddPage(@CurOrientation) + @x=x + if ws>0 + @ws=ws + out(sprintf('%.3f Tw',ws*@k)) + end + end + w=@w-@rMargin-@x if w==0 + s='' + if fill==1 or border==1 + if fill==1 + op=(border==1) ? 'B' : 'f' + else + op='S' + end + s=sprintf('%.2f %.2f %.2f %.2f re %s ',@x*@k,(@h-@y)*@k,w*@k,-h*@k,op) + end + if border.is_a? String + x=@x + y=@y + unless border.index('L').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + x*@k,(@h-y)*@k,x*@k,(@h-(y+h))*@k) + end + unless border.index('T').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + x*@k,(@h-y)*@k,(x+w)*@k,(@h-y)*@k) + end + unless border.index('R').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + (x+w)*@k,(@h-y)*@k,(x+w)*@k,(@h-(y+h))*@k) + end + unless border.index('B').nil? + s=s+sprintf('%.2f %.2f m %.2f %.2f l S ', + x*@k,(@h-(y+h))*@k,(x+w)*@k,(@h-(y+h))*@k) + end + end + if txt!='' + if align=='R' + dx=w-@cMargin-self.GetStringWidth(txt) + elsif align=='C' + dx=(w-self.GetStringWidth(txt))/2 + else + dx=@cMargin + end + if @ColorFlag + s=s+'q '+@TextColor+' ' + end + s=s+sprintf('BT %.2f %.2f Td (%s) Tj ET', + (@x+dx)*@k,(@h-(@y+0.5*h+0.3*@FontSize))*@k,escape(txt)) + s=s+' '+dounderline(@x+dx,@y+0.5*h+0.3*@FontSize,txt) if @underline + s=s+' Q' if @ColorFlag + if link and link != '' + Link(@x+dx,@y+0.5*h-0.5*@FontSize,GetStringWidth(txt),@FontSize,link) + end + end + out(s) if s + @lasth=h + if ln>0 + # Go to next line + @y=@y+h + @x=@lMargin if ln==1 + else + @x=@x+w + end + end + + def MultiCell(w,h,txt,border=0,align='J',fill=0) + # Output text with automatic or explicit line breaks + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x if w==0 + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + nb=nb-1 if nb>0 and s[nb-1].chr=="\n" + b=0 + if border!=0 + if border==1 + border='LTRB' + b='LRT' + b2='LR' + else + b2='' + b2='L' unless border.index('L').nil? + b2=b2+'R' unless border.index('R').nil? + b=(not border.index('T').nil?) ? (b2+'T') : b2 + end + end + sep=-1 + to_index=0 + from_j=0 + l=0 + ns=0 + nl=1 + while to_index0 + @ws=0 + out('0 Tw') + end +#Ed Moss + end_i = to_index == 0 ? 0 : to_index - 1 + # Changed from s[from_j..to_index] to fix bug reported by Hans Allis. + self.Cell(w,h,s[from_j..end_i],b,2,align,fill) +# + to_index=to_index+1 + sep=-1 + from_j=to_index + l=0 + ns=0 + nl=nl+1 + b=b2 if border and nl==2 + else + if char==' '[0] + sep=to_index + ls=l + ns=ns+1 + end + l=l+GetCharWidth(cw, char) + if l>wmax + # Automatic line break + if sep==-1 + to_index=to_index+1 if to_index==from_j + if @ws>0 + @ws=0 + out('0 Tw') + end +#Ed Moss + self.Cell(w,h,s[from_j..to_index-1],b,2,align,fill) +# + else + if align=='J' + @ws=(ns>1) ? (wmax-ls)/1000.0*@FontSize/(ns-1) : 0 + out(sprintf('%.3f Tw',@ws*@k)) + end + self.Cell(w,h,s[from_j..sep],b,2,align,fill) + to_index=sep+1 + end + sep=-1 + from_j=to_index + l=0 + ns=0 + nl=nl+1 + b=b2 if border and nl==2 + else + to_index=to_index+1 + end + end + end + + # Last chunk + if @ws>0 + @ws=0 + out('0 Tw') + end + b=b+'B' if border!=0 and not border.index('B').nil? + self.Cell(w,h,s[from_j..to_index],b,2,align,fill) + @x=@lMargin + end + + def Write(h,txt,link='') + # Output text in flowing mode + cw=@CurrentFont['cw'] + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + s=txt.gsub("\r",'') + nb=s.length + sep=-1 + i=0 + j=0 + l=0 + nl=1 + while iwmax + # Automatic line break + if sep==-1 + if @x>@lMargin + # Move to next line + @x=@lMargin + @y=@y+h + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + i=i+1 + nl=nl+1 + next + end + i=i+1 if i==j + self.Cell(w,h,s[j,i-j],0,2,'',0,link) + else + self.Cell(w,h,s[j,sep-j],0,2,'',0,link) + i=sep+1 + end + sep=-1 + j=i + l=0 + if nl==1 + @x=@lMargin + w=@w-@rMargin-@x + wmax=(w-2*@cMargin)*1000/@FontSize + end + nl=nl+1 + else + i=i+1 + end + end + # Last chunk + self.Cell(l/1000.0*@FontSize,h,s[j,i],0,0,'',0,link) if i!=j + end + + def Image(file,x,y,w=0,h=0,type='',link='') + # Put an image on the page + unless @images.has_key?(file) + # First use of image, get info + if type=='' + pos=file.rindex('.') + if pos.nil? + self.Error('Image file has no extension and no type was '+ + 'specified: '+file) + end + type=file[pos+1..-1] + end + type.downcase! + if type=='jpg' or type=='jpeg' + info=parsejpg(file) + elsif type=='png' + info=parsepng(file) + else + self.Error('Unsupported image file type: '+type) + end + info['i']=@images.length+1 + @images[file]=info + else + info=@images[file] + end +#Ed Moss + if(w==0 && h==0) + #Put image at 72 dpi + w=info['w']/@k; + h=info['h']/@k; + end +# + # Automatic width or height calculation + w=h*info['w']/info['h'] if w==0 + h=w*info['h']/info['w'] if h==0 + out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', + w*@k,h*@k,x*@k,(@h-(y+h))*@k,info['i'])) + Link(x,y,w,h,link) if link and link != '' + end + + def Ln(h='') + # Line feed; default value is last cell height + @x=@lMargin + if h.kind_of?(String) + @y=@y+@lasth + else + @y=@y+h + end + end + + def GetX + # Get x position + @x + end + + def SetX(x) + # Set x position + if x>=0 + @x=x + else + @x=@w+x + end + end + + def GetY + # Get y position + @y + end + + def SetY(y) + # Set y position and reset x + @x=@lMargin + if y>=0 + @y=y + else + @y=@h+y + end + end + + def SetXY(x,y) + # Set x and y positions + SetY(y) + SetX(x) + end + + def Output(file=nil) + # Output PDF to file or return as a string + + # Finish document if necessary + self.Close if(@state<3) + + if file.nil? + # Return as a string + return @buffer + else + # Save file locally + open(file,'wb') do |f| + f.write(@buffer) + end + end + end + + private + + def putpages + nb=@page + unless @AliasNbPages.nil? or @AliasNbPages=='' + # Replace number of pages + 1.upto(nb) do |n| + @pages[n].gsub!(@AliasNbPages,nb.to_s) + end + end + if @DefOrientation=='P' + wPt=@fwPt + hPt=@fhPt + else + wPt=@fhPt + hPt=@fwPt + end + filter=(@compress) ? '/Filter /FlateDecode ' : '' + 1.upto(nb) do |n| + # Page + newobj + out('<>>>' + else + l=@links[pl[4]] + h=@OrientationChanges[l[0]].nil? ? hPt : wPt + annots=annots+sprintf( + '/Dest [%d 0 R /XYZ 0 %.2f null]>>', + 1+2*l[0],h-l[1]*@k) + end + end + out(annots+']') + end + out('/Contents '+(@n+1).to_s+' 0 R>>') + out('endobj') + # Page content + p=(@compress) ? Zlib::Deflate.deflate(@pages[n]) : @pages[n] + newobj + out('<<'+filter+'/Length '+p.length.to_s+'>>') + putstream(p) + out('endobj') + end + # Pages root + @offsets[1]=@buffer.length + out('1 0 obj') + out('<>') + out('endobj') + end + + def putfonts + nf=@n + @diffs.each do |diff| + # Encodings + newobj + out('<>') + out('endobj') + end + + @FontFiles.each do |file, info| + # Font file embedding + newobj + @FontFiles[file]['n'] = @n + + if self.class.const_defined? 'FPDF_FONTPATH' then + if FPDF_FONTPATH[-1,1] == '/' then + file = FPDF_FONTPATH + file + else + file = FPDF_FONTPATH + '/' + file + end + end + + size = File.size(file) + unless File.exists?(file) + Error('Font file not found') + end + + out('<>') + open(file, 'rb') do |f| + putstream(f.read()) + end + out('endobj') + end + + file = 0 + @fonts.each do |k, font| + # Font objects + @fonts[k]['n']=@n+1 + type=font['type'] + name=font['name'] + if type=='core' + # Standard font + newobj + out('<>') + out('endobj') + elsif type=='Type1' or type=='TrueType' + # Additional Type1 or TrueType font + newobj + out('<>') + out('endobj') + # Widths + newobj + cw=font['cw'] + s='[' + 32.upto(255) do |i| + s << GetCharWidth(cw, i).to_s + ' ' + end + out(s+']') + out('endobj') + # Descriptor + newobj + s='<>') + out('endobj') + else + # Allow for additional types + mtd='put'+type.downcase + unless self.respond_to?(mtd) + self.Error('Unsupported font type: '+type) + end + self.send(mtd, font) + end + end + end + + def putimages + filter=(@compress) ? '/Filter /FlateDecode ' : '' + @images.each do |file, info| + newobj + @images[file]['n']=@n + out('<>') + putstream(info['data']) + @images[file]['data']=nil + out('endobj') + # Palette + if info['cs']=='Indexed' + newobj + pal=(@compress) ? Zlib::Deflate.deflate(info['pal']) : info['pal'] + out('<<'+filter+'/Length '+pal.length.to_s+'>>') + putstream(pal) + out('endobj') + end + end + end + + def putxobjectdict + @images.each_value do |image| + out('/I'+image['i'].to_s+' '+image['n'].to_s+' 0 R') + end + end + + def putresourcedict + out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]') + out('/Font <<') + @fonts.each_value do |font| + out('/F'+font['i'].to_s+' '+font['n'].to_s+' 0 R') + end + out('>>') + out('/XObject <<') + putxobjectdict + out('>>') + end + + def putresources + putfonts + putimages + # Resource dictionary + @offsets[2]=@buffer.length + out('2 0 obj') + out('<<') + putresourcedict + out('>>') + out('endobj') + end + + def putinfo + out('/Producer '+textstring('Ruby FPDF '+FPDF_VERSION)); + unless @title.nil? + out('/Title '+textstring(@title)) + end + unless @subject.nil? + out('/Subject '+textstring(@subject)) + end + unless @author.nil? + out('/Author '+textstring(@author)) + end + unless @keywords.nil? + out('/Keywords '+textstring(@keywords)) + end + unless @creator.nil? + out('/Creator '+textstring(@creator)) + end + out('/CreationDate '+textstring('D: '+DateTime.now.to_s)) + end + + def putcatalog + out('/Type /Catalog') + out('/Pages 1 0 R') + if @ZoomMode=='fullpage' + out('/OpenAction [3 0 R /Fit]') + elsif @ZoomMode=='fullwidth' + out('/OpenAction [3 0 R /FitH null]') + elsif @ZoomMode=='real' + out('/OpenAction [3 0 R /XYZ null null 1]') + elsif not @ZoomMode.kind_of?(String) + out('/OpenAction [3 0 R /XYZ null null '+(@ZoomMode/100)+']') + end + + if @LayoutMode=='single' + out('/PageLayout /SinglePage') + elsif @LayoutMode=='continuous' + out('/PageLayout /OneColumn') + elsif @LayoutMode=='two' + out('/PageLayout /TwoColumnLeft') + end + end + + def putheader + out('%PDF-'+@PDFVersion) + end + + def puttrailer + out('/Size '+(@n+1).to_s) + out('/Root '+@n.to_s+' 0 R') + out('/Info '+(@n-1).to_s+' 0 R') + end + + def enddoc + putheader + putpages + putresources + # Info + newobj + out('<<') + putinfo + out('>>') + out('endobj') + # Catalog + newobj + out('<<') + putcatalog + out('>>') + out('endobj') + # Cross-ref + o=@buffer.length + out('xref') + out('0 '+(@n+1).to_s) + out('0000000000 65535 f ') + 1.upto(@n) do |i| + out(sprintf('%010d 00000 n ',@offsets[i])) + end + # Trailer + out('trailer') + out('<<') + puttrailer + out('>>') + out('startxref') + out(o) + out('%%EOF') + @state=3 + end + + def beginpage(orientation) + @page=@page+1 + @pages[@page]='' + @state=2 + @x=@lMargin + @y=@tMargin + @lasth=0 + @FontFamily='' + # Page orientation + if orientation=='' + orientation=@DefOrientation + else + orientation=orientation[0].chr.upcase + if orientation!=@DefOrientation + @OrientationChanges[@page]=true + end + end + if orientation!=@CurOrientation + # Change orientation + if orientation=='P' + @wPt=@fwPt + @hPt=@fhPt + @w=@fw + @h=@fh + else + @wPt=@fhPt + @hPt=@fwPt + @w=@fh + @h=@fw + end + @PageBreakTrigger=@h-@bMargin + @CurOrientation=orientation + end + end + + def endpage + # End of page contents + @state=1 + end + + def newobj + # Begin a new object + @n=@n+1 + @offsets[@n]=@buffer.length + out(@n.to_s+' 0 obj') + end + + def dounderline(x,y,txt) + # Underline text + up=@CurrentFont['up'] + ut=@CurrentFont['ut'] + w=GetStringWidth(txt)+@ws*txt.count(' ') + sprintf('%.2f %.2f %.2f %.2f re f', + x*@k,(@h-(y-up/1000.0*@FontSize))*@k,w*@k,-ut/1000.0*@FontSizePt) + end + + def parsejpg(file) + # Extract info from a JPEG file + a=extractjpginfo(file) + raise "Missing or incorrect JPEG file: #{file}" if a.nil? + + if a['channels'].nil? || a['channels']==3 then + colspace='DeviceRGB' + elsif a['channels']==4 then + colspace='DeviceCMYK' + else + colspace='DeviceGray' + end + bpc= a['bits'] ? a['bits'].to_i : 8 + + # Read whole file + data = nil + open(file, 'rb') do |f| + data = f.read + end + return {'w'=>a['width'],'h'=>a['height'],'cs'=>colspace,'bpc'=>bpc,'f'=>'DCTDecode','data'=>data} + end + + def parsepng(file) + # Extract info from a PNG file + f=open(file,'rb') + # Check signature + unless f.read(8)==137.chr+'PNG'+13.chr+10.chr+26.chr+10.chr + self.Error('Not a PNG file: '+file) + end + # Read header chunk + f.read(4) + if f.read(4)!='IHDR' + self.Error('Incorrect PNG file: '+file) + end + w=freadint(f) + h=freadint(f) + bpc=f.read(1)[0] + if bpc>8 + self.Error('16-bit depth not supported: '+file) + end + ct=f.read(1)[0] + if ct==0 + colspace='DeviceGray' + elsif ct==2 + colspace='DeviceRGB' + elsif ct==3 + colspace='Indexed' + else + self.Error('Alpha channel not supported: '+file) + end + if f.read(1)[0]!=0 + self.Error('Unknown compression method: '+file) + end + if f.read(1)[0]!=0 + self.Error('Unknown filter method: '+file) + end + if f.read(1)[0]!=0 + self.Error('Interlacing not supported: '+file) + end + f.read(4) + parms='/DecodeParms <>' + # Scan chunks looking for palette, transparency and image data + pal='' + trns='' + data='' + begin + n=freadint(f) + type=f.read(4) + if type=='PLTE' + # Read palette + pal=f.read(n) + f.read(4) + elsif type=='tRNS' + # Read transparency info + t=f.read(n) + if ct==0 + trns=[t[1]] + elsif ct==2 + trns=[t[1],t[3],t[5]] + else + pos=t.index(0) + trns=[pos] unless pos.nil? + end + f.read(4) + elsif type=='IDAT' + # Read image data block + data << f.read(n) + f.read(4) + elsif type=='IEND' + break + else + f.read(n+4) + end + end while n + if colspace=='Indexed' and pal=='' + self.Error('Missing palette in '+file) + end + f.close + {'w'=>w,'h'=>h,'cs'=>colspace,'bpc'=>bpc,'f'=>'FlateDecode', + 'parms'=>parms,'pal'=>pal,'trns'=>trns,'data'=>data} + end + + def freadint(f) + # Read a 4-byte integer from file + a = f.read(4).unpack('N') + return a[0] + end + + def freadshort(f) + a = f.read(2).unpack('n') + return a[0] + end + + def freadbyte(f) + a = f.read(1).unpack('C') + return a[0] + end + + def textstring(s) + # Format a text string + '('+escape(s)+')' + end + + def escape(s) + # Add \ before \, ( and ) + s.gsub('\\','\\\\\\').gsub('(','\\(').gsub(')','\\)') + end + + def putstream(s) + out('stream') + out(s) + out('endstream') + end + + def out(s) + # Add a line to the document + if @state==2 + @pages[@page]=@pages[@page]+s+"\n" + else + @buffer=@buffer+s.to_s+"\n" + end + end + + # jpeg marker codes + + M_SOF0 = 0xc0 + M_SOF1 = 0xc1 + M_SOF2 = 0xc2 + M_SOF3 = 0xc3 + + M_SOF5 = 0xc5 + M_SOF6 = 0xc6 + M_SOF7 = 0xc7 + + M_SOF9 = 0xc9 + M_SOF10 = 0xca + M_SOF11 = 0xcb + + M_SOF13 = 0xcd + M_SOF14 = 0xce + M_SOF15 = 0xcf + + M_SOI = 0xd8 + M_EOI = 0xd9 + M_SOS = 0xda + + def extractjpginfo(file) + result = nil + + open(file, "rb") do |f| + marker = jpegnextmarker(f) + + if marker != M_SOI + return nil + end + + while true + marker = jpegnextmarker(f) + + case marker + when M_SOF0, M_SOF1, M_SOF2, M_SOF3, + M_SOF5, M_SOF6, M_SOF7, M_SOF9, + M_SOF10, M_SOF11, M_SOF13, M_SOF14, + M_SOF15 then + + length = freadshort(f) + + if result.nil? + result = {} + + result['bits'] = freadbyte(f) + result['height'] = freadshort(f) + result['width'] = freadshort(f) + result['channels'] = freadbyte(f) + + f.seek(length - 8, IO::SEEK_CUR) + else + f.seek(length - 2, IO::SEEK_CUR) + end + when M_SOS, M_EOI then + return result + else + length = freadshort(f) + f.seek(length - 2, IO::SEEK_CUR) + end + end + end + end + + def jpegnextmarker(f) + while true + # look for 0xff + while (c = freadbyte(f)) != 0xff + end + + c = freadbyte(f) + + if c != 0 + return c + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7daf089229959e001c252252526a110de699ba06.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7daf089229959e001c252252526a110de699ba06.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRepositoryRootUrl < ActiveRecord::Migration + def self.up + add_column :repositories, :root_url, :string, :limit => 255, :default => "" + end + + def self.down + remove_column :repositories, :root_url + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7dd0539603ad9e25c32256869656657e4135a1c8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7dd0539603ad9e25c32256869656657e4135a1c8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%= link_to l(:label_group_plural), groups_path %> » <%= l(:label_group_new) %>

    + +<% labelled_form_for @group do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +

    + <%= f.submit l(:button_create) %> + <%= f.submit l(:button_create_and_continue), :name => 'continue' %> +

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7d/7dd1b8397e24cced4bd7016e085055ff385a2960.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7d/7dd1b8397e24cced4bd7016e085055ff385a2960.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +I18n.default_locale = 'en' +# Adds fallback to default locale for untranslated strings +I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) + +require 'redmine' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7e/7e3d39301783d138f7a6d49cba0462adeb117d57.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7e/7e3d39301783d138f7a6d49cba0462adeb117d57.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,223 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'account_controller' + +# Re-raise errors caught by the controller. +class AccountController; def rescue_action(e) raise e end; end + +class AccountControllerTest < ActionController::TestCase + fixtures :users, :roles + + def setup + @controller = AccountController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_login_should_redirect_to_back_url_param + # request.uri is "test.host" in test environment + post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.host%2Fissues%2Fshow%2F1' + assert_redirected_to '/issues/show/1' + end + + def test_login_should_not_redirect_to_another_host + post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.foo%2Ffake' + assert_redirected_to '/my/page' + end + + def test_login_with_wrong_password + post :login, :username => 'admin', :password => 'bad' + assert_response :success + assert_template 'login' + assert_tag 'div', + :attributes => { :class => "flash error" }, + :content => /Invalid user or password/ + end + + if Object.const_defined?(:OpenID) + + def test_login_with_openid_for_existing_user + Setting.self_registration = '3' + Setting.openid = '1' + existing_user = User.new(:firstname => 'Cool', + :lastname => 'User', + :mail => 'user@somedomain.com', + :identity_url => 'http://openid.example.com/good_user') + existing_user.login = 'cool_user' + assert existing_user.save! + + post :login, :openid_url => existing_user.identity_url + assert_redirected_to '/my/page' + end + + def test_login_with_invalid_openid_provider + Setting.self_registration = '0' + Setting.openid = '1' + post :login, :openid_url => 'http;//openid.example.com/good_user' + assert_redirected_to home_url + end + + def test_login_with_openid_for_existing_non_active_user + Setting.self_registration = '2' + Setting.openid = '1' + existing_user = User.new(:firstname => 'Cool', + :lastname => 'User', + :mail => 'user@somedomain.com', + :identity_url => 'http://openid.example.com/good_user', + :status => User::STATUS_REGISTERED) + existing_user.login = 'cool_user' + assert existing_user.save! + + post :login, :openid_url => existing_user.identity_url + assert_redirected_to '/login' + end + + def test_login_with_openid_with_new_user_created + Setting.self_registration = '3' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to '/my/account' + user = User.find_by_login('cool_user') + assert user + assert_equal 'Cool', user.firstname + assert_equal 'User', user.lastname + end + + def test_login_with_openid_with_new_user_and_self_registration_off + Setting.self_registration = '0' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to home_url + user = User.find_by_login('cool_user') + assert ! user + end + + def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token + Setting.self_registration = '1' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to '/login' + user = User.find_by_login('cool_user') + assert user + + token = Token.find_by_user_id_and_action(user.id, 'register') + assert token + end + + def test_login_with_openid_with_new_user_created_with_manual_activation + Setting.self_registration = '2' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to '/login' + user = User.find_by_login('cool_user') + assert user + assert_equal User::STATUS_REGISTERED, user.status + end + + def test_login_with_openid_with_new_user_with_conflict_should_register + Setting.self_registration = '3' + Setting.openid = '1' + existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com') + existing_user.login = 'cool_user' + assert existing_user.save! + + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_response :success + assert_template 'register' + assert assigns(:user) + assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url] + end + + def test_setting_openid_should_return_true_when_set_to_true + Setting.openid = '1' + assert_equal true, Setting.openid? + end + + else + puts "Skipping openid tests." + end + + def test_logout + @request.session[:user_id] = 2 + get :logout + assert_redirected_to '/' + assert_nil @request.session[:user_id] + end + + context "GET #register" do + context "with self registration on" do + setup do + Setting.self_registration = '3' + get :register + end + + should_respond_with :success + should_render_template :register + should_assign_to :user + end + + context "with self registration off" do + setup do + Setting.self_registration = '0' + get :register + end + + should_redirect_to('/') { home_url } + end + end + + # See integration/account_test.rb for the full test + context "POST #register" do + context "with self registration on automatic" do + setup do + Setting.self_registration = '3' + post :register, :user => { + :login => 'register', + :password => 'test', + :password_confirmation => 'test', + :firstname => 'John', + :lastname => 'Doe', + :mail => 'register@example.com' + } + end + + should_respond_with :redirect + should_assign_to :user + should_redirect_to('my page') { {:controller => 'my', :action => 'account'} } + + should_create_a_new_user { User.last(:conditions => {:login => 'register'}) } + + should 'set the user status to active' do + user = User.last(:conditions => {:login => 'register'}) + assert user + assert_equal User::STATUS_ACTIVE, user.status + end + end + + context "with self registration off" do + setup do + Setting.self_registration = '0' + post :register + end + + should_redirect_to('/') { home_url } + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7e/7e3f9cdf448ee38697e8614780073ec72927018c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7e/7e3f9cdf448ee38697e8614780073ec72927018c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +<% roles = Role.find_all_givable %> +<% projects = Project.active.find(:all, :order => 'lft') %> + +
    +<% if @user.memberships.any? %> + + + + + + <%= call_hook(:view_users_memberships_table_header, :user => @user )%> + + + <% @user.memberships.each do |membership| %> + <% next if membership.new_record? %> + + + + + <%= call_hook(:view_users_memberships_table_row, :user => @user, :membership => membership, :roles => roles, :projects => projects )%> + + <% end; reset_cycle %> + +
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    + <%= link_to_project membership.project %> + + <%=h membership.roles.sort.collect(&:to_s).join(', ') %> + <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user, :membership_id => membership }, + :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %> +

    <% roles.each do |role| %> +
    + <% end %>

    + <%= hidden_field_tag 'membership[role_ids][]', '' %> +

    <%= submit_tag l(:button_change) %> + <%= link_to_function l(:button_cancel), "$('member-#{membership.id}-roles').show(); $('member-#{membership.id}-roles-form').hide(); return false;" %>

    + <% end %> +
    + <%= link_to_function l(:button_edit), "$('member-#{membership.id}-roles').hide(); $('member-#{membership.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %> + <%= link_to_remote(l(:button_delete), { :url => { :controller => 'users', :action => 'destroy_membership', :id => @user, :membership_id => membership }, + :method => :post }, + :class => 'icon icon-del') if membership.deletable? %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + +
    +<% if projects.any? %> +
    <%=l(:label_project_new)%> +<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user }) do %> +<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, projects) %> +

    <%= l(:label_role_plural) %>: +<% roles.each do |role| %> + +<% end %>

    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +
    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7e/7e8e9292e4aaad251a7746c0dc0d152386a542fc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7e/7e8e9292e4aaad251a7746c0dc0d152386a542fc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,96 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class RepositoryDarcsTest < ActiveSupport::TestCase + fixtures :projects + + REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s + NUM_REV = 6 + + def setup + @project = Project.find(3) + @repository = Repository::Darcs.create( + :project => @project, + :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8' + ) + assert @repository + end + + if File.directory?(REPOSITORY_PATH) + def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + + assert_equal NUM_REV, @repository.changesets.count + assert_equal 13, @repository.changes.count + assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments + end + + def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + # Remove changesets with revision > 3 + @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3} + @project.reload + assert_equal 3, @repository.changesets.count + + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + end + + def test_entries_invalid_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + assert_nil @repository.entries('', '123') + end + + def test_deleted_files_should_not_be_listed + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + entries = @repository.entries('sources') + assert entries.detect {|e| e.name == 'watchers_controller.rb'} + assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'} + end + + def test_cat + if @repository.scm.supports_cat? + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + cat = @repository.cat("sources/welcome_controller.rb", 2) + assert_not_nil cat + assert cat.include?('class WelcomeController < ApplicationController') + end + end + else + puts "Darcs test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7e/7e97158fcb3c72c9c2b213b5a15fbb3047e5ebe8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7e/7e97158fcb3c72c9c2b213b5a15fbb3047e5ebe8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Задебелен'; +jsToolBar.strings['Italic'] = 'Закосен'; +jsToolBar.strings['Underline'] = 'Подвлечен'; +jsToolBar.strings['Deleted'] = 'Прецртан'; +jsToolBar.strings['Code'] = 'Код'; +jsToolBar.strings['Heading 1'] = 'Заглавје 1'; +jsToolBar.strings['Heading 2'] = 'Заглавје 2'; +jsToolBar.strings['Heading 3'] = 'Заглавје 3'; +jsToolBar.strings['Unordered list'] = 'Неподредена листа'; +jsToolBar.strings['Ordered list'] = 'Подредена листа'; +jsToolBar.strings['Quote'] = 'Цитат'; +jsToolBar.strings['Unquote'] = 'Отстрани цитат'; +jsToolBar.strings['Preformatted text'] = 'Форматиран текст'; +jsToolBar.strings['Wiki link'] = 'Врска до вики страна'; +jsToolBar.strings['Image'] = 'Слика'; + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7e/7ea8be01cd62ea12ccab2b959df562421b7f5a7b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7e/7ea8be01cd62ea12ccab2b959df562421b7f5a7b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class JournalObserver < ActiveRecord::Observer + def after_create(journal) + if journal.notify? && + (Setting.notified_events.include?('issue_updated') || + (Setting.notified_events.include?('issue_note_added') && journal.notes.present?) || + (Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) || + (Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?) + ) + Mailer.deliver_issue_edit(journal) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7e/7ed5ff50178d5fce1b5d6ac8ee201d93fbb97cbe.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7e/7ed5ff50178d5fce1b5d6ac8ee201d93fbb97cbe.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,79 @@ +TCPDFFontDescriptor.define('freesansb') do |font| + font[:type]='TrueTypeUnicode'; + font[:name]='FreeSansBold'; + font[:desc]={'Ascent'=>1159,'Descent'=>-355,'CapHeight'=>1159,'Flags'=>32,'FontBBox'=>'[-459 -355 1300 1159]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>600}; + font[:up]=-155; + font[:ut]=69; + font[:cw]={ + 13=>333, 32=>278, 33=>333, 34=>474, 35=>556, 36=>556, 37=>889, 38=>722, 39=>238, 40=>333, 41=>333, 42=>389, 43=>584, 44=>278, 45=>333, 46=>278, + 47=>278, 48=>556, 49=>556, 50=>556, 51=>556, 52=>556, 53=>556, 54=>556, 55=>556, 56=>556, 57=>556, 58=>333, 59=>333, 60=>584, 61=>584, 62=>584, + 63=>611, 64=>975, 65=>722, 66=>722, 67=>722, 68=>722, 69=>667, 70=>611, 71=>778, 72=>722, 73=>278, 74=>556, 75=>722, 76=>611, 77=>833, 78=>722, + 79=>778, 80=>667, 81=>778, 82=>722, 83=>667, 84=>611, 85=>722, 86=>667, 87=>944, 88=>667, 89=>667, 90=>611, 91=>333, 92=>278, 93=>333, 94=>584, + 95=>556, 96=>333, 97=>556, 98=>611, 99=>556, 100=>611, 101=>556, 102=>333, 103=>611, 104=>611, 105=>278, 106=>278, 107=>556, 108=>278, 109=>889, 110=>611, + 111=>611, 112=>611, 113=>611, 114=>389, 115=>556, 116=>333, 117=>611, 118=>556, 119=>778, 120=>556, 121=>556, 122=>500, 123=>389, 124=>280, 125=>389, 126=>584, + 8364=>556, 1027=>611, 8218=>278, 402=>556, 8222=>500, 8230=>1000, 8224=>556, 8225=>556, 710=>333, 8240=>1000, 352=>667, 8249=>333, 338=>1000, 1036=>722, 381=>611, 1039=>722, + 8216=>278, 8217=>278, 8220=>500, 8221=>500, 8226=>350, 8211=>556, 8212=>1000, 732=>333, 8482=>1000, 353=>556, 8250=>333, 339=>944, 1116=>573, 382=>500, 376=>667, 161=>333, + 162=>556, 163=>556, 164=>556, 165=>556, 166=>280, 167=>556, 168=>333, 169=>737, 170=>370, 171=>556, 172=>584, 174=>737, 175=>333, 176=>606, 177=>584, 178=>351, + 179=>351, 180=>333, 181=>611, 182=>556, 183=>278, 184=>333, 185=>351, 186=>365, 187=>556, 188=>869, 189=>869, 190=>869, 191=>611, 192=>722, 193=>722, 194=>722, + 195=>722, 196=>722, 197=>722, 198=>1000, 199=>722, 200=>667, 201=>667, 202=>667, 203=>667, 204=>278, 205=>278, 206=>278, 207=>278, 208=>722, 209=>722, 210=>778, + 211=>778, 212=>778, 213=>778, 214=>778, 215=>584, 216=>778, 217=>722, 218=>722, 219=>722, 220=>722, 221=>667, 222=>667, 223=>611, 224=>556, 225=>556, 226=>556, + 227=>556, 228=>556, 229=>556, 230=>889, 231=>556, 232=>556, 233=>556, 234=>556, 235=>556, 236=>278, 237=>278, 238=>278, 239=>278, 240=>611, 241=>611, 242=>611, + 243=>611, 244=>611, 245=>611, 246=>611, 247=>584, 248=>611, 249=>611, 250=>611, 251=>611, 252=>611, 253=>556, 254=>611, 255=>556, 256=>722, 257=>556, 258=>722, + 259=>556, 260=>722, 261=>556, 262=>722, 263=>556, 264=>722, 265=>556, 266=>722, 267=>556, 268=>722, 269=>556, 270=>722, 271=>611, 272=>722, 273=>611, 274=>667, + 275=>556, 276=>667, 277=>556, 278=>667, 279=>556, 280=>667, 281=>556, 282=>667, 283=>556, 284=>778, 285=>611, 286=>778, 287=>611, 288=>778, 289=>611, 290=>778, + 291=>611, 292=>722, 293=>611, 294=>722, 295=>611, 296=>278, 297=>278, 298=>278, 299=>278, 300=>278, 301=>278, 302=>278, 303=>278, 304=>278, 305=>278, 306=>808, + 307=>492, 308=>556, 309=>278, 310=>722, 311=>556, 312=>573, 313=>611, 314=>278, 315=>611, 316=>278, 317=>611, 318=>278, 319=>611, 320=>556, 321=>611, 322=>278, + 323=>722, 324=>611, 325=>722, 326=>611, 327=>722, 328=>611, 329=>611, 330=>722, 331=>611, 332=>778, 333=>611, 334=>778, 335=>611, 336=>778, 337=>611, 340=>722, + 341=>389, 342=>722, 343=>389, 344=>722, 345=>389, 346=>667, 347=>556, 348=>667, 349=>556, 350=>667, 351=>556, 354=>611, 355=>333, 356=>611, 357=>333, 358=>611, + 359=>333, 360=>722, 361=>611, 362=>722, 363=>611, 364=>722, 365=>611, 366=>722, 367=>611, 368=>722, 369=>611, 370=>722, 371=>611, 372=>944, 373=>778, 374=>667, + 375=>556, 377=>611, 378=>500, 379=>611, 380=>500, 383=>333, 452=>1333, 453=>1222, 454=>1111, 455=>1167, 456=>889, 457=>556, 458=>1278, 459=>1000, 460=>889, 461=>722, + 462=>556, 463=>278, 464=>278, 465=>778, 466=>611, 467=>722, 468=>611, 469=>722, 470=>611, 471=>722, 472=>611, 473=>722, 474=>611, 475=>722, 476=>611, 478=>722, + 479=>556, 482=>1000, 483=>889, 486=>778, 487=>611, 488=>722, 489=>556, 490=>778, 491=>611, 492=>778, 493=>611, 497=>1333, 498=>1222, 499=>1111, 504=>722, 505=>611, + 506=>722, 507=>556, 508=>1000, 509=>889, 510=>778, 511=>611, 514=>722, 515=>556, 518=>667, 519=>556, 522=>278, 523=>278, 526=>778, 527=>611, 530=>722, 531=>389, + 534=>722, 535=>611, 536=>667, 537=>556, 538=>611, 539=>333, 711=>333, 728=>333, 729=>333, 730=>333, 731=>333, 733=>333, 884=>379, 885=>379, 890=>332, 894=>333, + 900=>325, 901=>658, 902=>761, 903=>474, 904=>706, 905=>733, 906=>285, 908=>785, 910=>823, 911=>819, 913=>722, 914=>722, 915=>642, 916=>726, 917=>667, 918=>611, + 919=>722, 920=>810, 921=>278, 922=>722, 923=>744, 924=>860, 925=>714, 926=>690, 927=>822, 928=>781, 929=>698, 931=>688, 932=>688, 933=>804, 934=>777, 935=>783, + 936=>805, 937=>780, 938=>278, 939=>804, 940=>660, 941=>559, 942=>560, 943=>356, 944=>575, 945=>656, 946=>576, 947=>591, 948=>620, 949=>570, 950=>522, 951=>586, + 952=>586, 953=>346, 954=>576, 955=>620, 956=>667, 957=>564, 958=>530, 959=>610, 960=>721, 961=>626, 962=>595, 963=>676, 964=>592, 965=>575, 966=>801, 967=>632, + 968=>722, 969=>800, 970=>346, 971=>575, 972=>599, 973=>567, 974=>1125, 1024=>667, 1025=>709, 1026=>790, 1028=>722, 1029=>667, 1030=>278, 1031=>278, 1032=>556, 1033=>1110, + 1034=>1113, 1035=>790, 1037=>726, 1038=>718, 1040=>722, 1041=>722, 1042=>722, 1043=>611, 1044=>900, 1045=>709, 1046=>1093, 1047=>672, 1048=>757, 1049=>757, 1050=>750, 1051=>729, + 1052=>874, 1053=>753, 1054=>778, 1055=>753, 1056=>671, 1057=>722, 1058=>611, 1059=>718, 1060=>892, 1061=>667, 1062=>816, 1063=>685, 1064=>1057, 1065=>1183, 1066=>928, 1067=>949, + 1068=>687, 1069=>722, 1070=>1109, 1071=>698, 1072=>556, 1073=>606, 1074=>572, 1075=>454, 1076=>685, 1077=>556, 1078=>809, 1079=>546, 1080=>615, 1081=>615, 1082=>573, 1083=>577, + 1084=>666, 1085=>603, 1086=>611, 1087=>603, 1088=>611, 1089=>556, 1090=>454, 1091=>556, 1092=>957, 1093=>556, 1094=>652, 1095=>578, 1096=>886, 1097=>968, 1098=>693, 1099=>811, + 1100=>562, 1101=>564, 1102=>908, 1103=>596, 1104=>556, 1105=>556, 1106=>606, 1107=>454, 1108=>556, 1109=>556, 1110=>278, 1111=>278, 1112=>278, 1113=>900, 1114=>611, 1115=>606, + 1117=>608, 1118=>556, 1119=>608, 1164=>687, 1165=>562, 1166=>667, 1167=>611, 1168=>611, 1169=>454, 1170=>611, 1171=>454, 1172=>611, 1173=>454, 1174=>1093, 1175=>809, 1176=>672, + 1177=>546, 1178=>722, 1179=>573, 1180=>722, 1181=>573, 1182=>722, 1183=>573, 1184=>722, 1185=>573, 1186=>722, 1187=>608, 1188=>722, 1189=>608, 1190=>722, 1191=>608, 1192=>722, + 1193=>556, 1194=>722, 1195=>556, 1196=>611, 1197=>454, 1198=>667, 1199=>556, 1200=>667, 1201=>556, 1202=>667, 1203=>556, 1204=>814, 1205=>685, 1206=>675, 1207=>580, 1208=>675, + 1209=>580, 1210=>675, 1211=>580, 1212=>722, 1213=>556, 1214=>722, 1215=>556, 1216=>278, 1217=>1093, 1218=>809, 1219=>722, 1220=>573, 1223=>722, 1224=>608, 1227=>675, 1228=>580, + 1232=>722, 1233=>556, 1234=>722, 1235=>556, 1236=>1000, 1237=>889, 1238=>709, 1239=>556, 1240=>722, 1241=>556, 1242=>722, 1243=>556, 1244=>1093, 1245=>809, 1246=>672, 1247=>546, + 1248=>672, 1249=>546, 1250=>757, 1251=>615, 1252=>757, 1253=>615, 1254=>778, 1255=>611, 1256=>778, 1257=>611, 1258=>778, 1259=>611, 1260=>722, 1261=>564, 1262=>718, 1263=>556, + 1264=>718, 1265=>556, 1266=>718, 1267=>556, 1268=>685, 1269=>578, 1272=>949, 1273=>811, 1456=>82, 1457=>347, 1458=>341, 1459=>341, 1460=>82, 1461=>211, 1462=>211, 1463=>200, + 1464=>200, 1465=>82, 1467=>341, 1468=>82, 1469=>82, 1470=>516, 1471=>200, 1472=>297, 1473=>1038, 1474=>1038, 1475=>333, 1476=>82, 1488=>714, 1489=>651, 1490=>557, 1491=>638, + 1492=>682, 1493=>297, 1494=>443, 1495=>682, 1496=>670, 1497=>284, 1498=>590, 1499=>595, 1500=>667, 1501=>683, 1502=>704, 1503=>297, 1504=>429, 1505=>670, 1506=>653, 1507=>661, + 1508=>660, 1509=>616, 1510=>671, 1511=>672, 1512=>600, 1513=>840, 1514=>756, 1520=>554, 1521=>550, 1522=>542, 1523=>238, 1524=>474, 1559=>556, 1560=>778, 1561=>944, 1562=>611, + 1563=>278, 1564=>889, 1569=>844, 1576=>923, 1578=>922, 1579=>922, 1581=>649, 1582=>704, 1587=>1221, 7936=>656, 7937=>656, 7938=>656, 7939=>656, 7940=>656, 7941=>656, 7942=>656, + 7943=>656, 7944=>722, 7945=>722, 7946=>722, 7947=>722, 7948=>722, 7949=>722, 7950=>722, 7951=>722, 7952=>570, 7953=>570, 7954=>570, 7955=>570, 7956=>570, 7957=>570, 7960=>667, + 7961=>667, 7962=>667, 7963=>667, 7964=>667, 7965=>667, 7968=>586, 7969=>586, 7970=>586, 7971=>586, 7972=>586, 7973=>586, 7974=>586, 7975=>586, 7976=>722, 7977=>722, 7978=>722, + 7979=>722, 7980=>722, 7981=>722, 7982=>722, 7983=>722, 7984=>346, 7985=>346, 7986=>346, 7987=>346, 7988=>346, 7989=>346, 7990=>346, 7991=>346, 7992=>278, 7993=>278, 7994=>278, + 7995=>278, 7996=>278, 7997=>278, 7998=>278, 7999=>278, 8000=>610, 8001=>610, 8002=>610, 8003=>610, 8004=>610, 8005=>610, 8008=>822, 8009=>822, 8010=>822, 8011=>822, 8012=>822, + 8013=>822, 8016=>575, 8017=>575, 8018=>575, 8019=>575, 8020=>575, 8021=>575, 8022=>575, 8023=>575, 8025=>804, 8027=>804, 8029=>804, 8031=>804, 8032=>800, 8033=>800, 8034=>800, + 8035=>800, 8036=>800, 8037=>800, 8038=>800, 8039=>800, 8040=>780, 8041=>780, 8042=>780, 8043=>780, 8044=>780, 8045=>780, 8046=>780, 8047=>780, 8048=>656, 8049=>656, 8050=>570, + 8051=>570, 8052=>586, 8053=>586, 8054=>346, 8055=>346, 8056=>610, 8057=>610, 8058=>575, 8059=>575, 8060=>800, 8061=>800, 8064=>656, 8065=>656, 8066=>656, 8067=>656, 8068=>656, + 8069=>656, 8070=>656, 8071=>656, 8072=>968, 8073=>968, 8074=>968, 8075=>968, 8076=>968, 8077=>968, 8078=>968, 8079=>968, 8080=>586, 8081=>586, 8082=>586, 8083=>586, 8084=>586, + 8085=>586, 8086=>586, 8087=>586, 8088=>968, 8089=>968, 8090=>968, 8091=>968, 8092=>968, 8093=>968, 8094=>968, 8095=>968, 8096=>800, 8097=>800, 8098=>800, 8099=>800, 8100=>800, + 8101=>800, 8102=>800, 8103=>800, 8104=>1026, 8105=>1026, 8106=>1026, 8107=>1026, 8108=>1026, 8109=>1026, 8110=>1026, 8111=>1026, 8112=>656, 8113=>656, 8114=>656, 8115=>656, 8116=>660, + 8118=>656, 8119=>656, 8120=>722, 8121=>722, 8122=>722, 8123=>722, 8124=>968, 8125=>278, 8126=>346, 8127=>278, 8128=>278, 8129=>333, 8130=>586, 8131=>586, 8132=>560, 8134=>586, + 8135=>586, 8136=>667, 8137=>667, 8138=>722, 8139=>722, 8140=>968, 8141=>492, 8142=>489, 8143=>394, 8144=>346, 8145=>346, 8146=>346, 8147=>346, 8150=>346, 8151=>346, 8152=>278, + 8153=>278, 8154=>278, 8155=>278, 8157=>481, 8158=>589, 8159=>333, 8160=>575, 8161=>575, 8162=>575, 8163=>575, 8164=>626, 8165=>626, 8166=>575, 8167=>575, 8168=>804, 8169=>804, + 8170=>804, 8171=>804, 8172=>698, 8173=>333, 8174=>333, 8175=>333, 8178=>800, 8179=>800, 8180=>1125, 8182=>800, 8183=>800, 8184=>822, 8185=>822, 8186=>780, 8187=>780, 8188=>1111, + 8189=>333, 8190=>278, 8260=>167, 8308=>351, 8321=>351, 8322=>351, 8323=>351, 8324=>351, 8362=>1049, 8543=>869, 8706=>490, 8710=>729, 8721=>711, 8722=>584, 8730=>542, 8800=>548, + 8804=>584, 8805=>584, 9674=>489, 63033=>556, 63034=>556, 63035=>556, 63036=>556, 63037=>556, 63038=>556, 63039=>556, 63040=>556, 63041=>556, 63171=>333, 63196=>556, 64257=>611, 64258=>611, + 64285=>284, 64286=>305, 64287=>542, 64288=>653, 64289=>964, 64290=>888, 64291=>932, 64292=>845, 64293=>917, 64294=>933, 64295=>850, 64296=>1006, 64297=>584, 64298=>840, 64299=>840, 64300=>840, + 64301=>840, 64302=>714, 64303=>714, 64304=>714, 64305=>651, 64306=>557, 64307=>638, 64308=>682, 64309=>367, 64310=>443, 64312=>670, 64313=>354, 64314=>590, 64315=>595, 64316=>667, 64318=>704, + 64320=>429, 64321=>670, 64323=>661, 64324=>660, 64326=>671, 64327=>672, 64328=>600, 64329=>840, 64330=>756, 64331=>297, 64332=>651, 64333=>595, 64334=>660, 64335=>714, 65182=>636} + font[:enc]=''; + font[:diff]=''; + font[:file]='FreeSansBold.z'; + font[:ctg]='FreeSansBold.ctg.z'; + font[:originalsize]=91432; +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7f25106e046fdb916a3c955f5e8e9ed2f71384db.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7f25106e046fdb916a3c955f5e8e9ed2f71384db.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Podebljano'; +jsToolBar.strings['Italic'] = 'Kurziv'; +jsToolBar.strings['Underline'] = 'Podcrtano'; +jsToolBar.strings['Deleted'] = 'Obrisano'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Graficke oznake'; +jsToolBar.strings['Ordered list'] = 'Numeriranje'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Ukloni citat'; +jsToolBar.strings['Preformatted text'] = 'Izveden tekst'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stranicu'; +jsToolBar.strings['Image'] = 'Slika'; \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7f29e28dea9f944faa0f0c10063d8ae096007167.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7f29e28dea9f944faa0f0c10063d8ae096007167.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1022 @@ +#Ernad Husremovic hernad@bring.out.ba + +bs: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%e. %b" + long: "%e. %B %Y" + only_day: "%e" + + + day_names: [Nedjelja, Ponedjeljak, Utorak, Srijeda, Četvrtak, Petak, Subota] + abbr_day_names: [Ned, Pon, Uto, Sri, Čet, Pet, Sub] + + month_names: [~, Januar, Februar, Mart, April, Maj, Jun, Jul, Avgust, Septembar, Oktobar, Novembar, Decembar] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Avg, Sep, Okt, Nov, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %e. %B %Y, %H:%M" + short: "%e. %B, %H:%M Uhr" + long: "%A, %e. %B %Y, %H:%M" + time: "%H:%M" + + am: "prijepodne" + pm: "poslijepodne" + + datetime: + distance_in_words: + half_a_minute: "pola minute" + less_than_x_seconds: + one: "manje od 1 sekunde" + other: "manje od %{count} sekudni" + x_seconds: + one: "1 sekunda" + other: "%{count} sekundi" + less_than_x_minutes: + one: "manje od 1 minute" + other: "manje od %{count} minuta" + x_minutes: + one: "1 minuta" + other: "%{count} minuta" + about_x_hours: + one: "oko 1 sahat" + other: "oko %{count} sahata" + x_days: + one: "1 dan" + other: "%{count} dana" + about_x_months: + one: "oko 1 mjesec" + other: "oko %{count} mjeseci" + x_months: + one: "1 mjesec" + other: "%{count} mjeseci" + about_x_years: + one: "oko 1 godine" + other: "oko %{count} godina" + over_x_years: + one: "preko 1 godine" + other: "preko %{count} godina" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + + number: + format: + precision: 2 + separator: ',' + delimiter: '.' + currency: + format: + unit: 'KM' + format: '%u %n' + separator: + delimiter: + precision: + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nije uključeno u listu" + exclusion: "je rezervisano" + invalid: "nije ispravno" + confirmation: "ne odgovara potvrdi" + accepted: "mora se prihvatiti" + empty: "ne može biti prazno" + blank: "ne može biti znak razmaka" + too_long: "je predugačko" + too_short: "je prekratko" + wrong_length: "je pogrešne dužine" + taken: "već je zauzeto" + not_a_number: "nije broj" + not_a_date: "nije ispravan datum" + greater_than: "mora bit veći od %{count}" + greater_than_or_equal_to: "mora bit veći ili jednak %{count}" + equal_to: "mora biti jednak %{count}" + less_than: "mora biti manji od %{count}" + less_than_or_equal_to: "mora bit manji ili jednak %{count}" + odd: "mora biti neparan" + even: "mora biti paran" + greater_than_start_date: "mora biti veći nego početni datum" + not_same_project: "ne pripada istom projektu" + circular_dependency: "Ova relacija stvar cirkularnu zavisnost" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Molimo odaberite + + general_text_No: 'Da' + general_text_Yes: 'Ne' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Bosanski' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_activated: Vaš nalog je aktiviran. Možete se prijaviti. + notice_account_invalid_creditentials: Pogrešan korisnik ili lozinka + notice_account_lost_email_sent: Email sa uputstvima o izboru nove šifre je poslat na vašu adresu. + notice_account_password_updated: Lozinka je uspješno promjenjena. + notice_account_pending: "Vaš nalog je kreiran i čeka odobrenje administratora." + notice_account_register_done: Nalog je uspješno kreiran. Da bi ste aktivirali vaš nalog kliknite na link koji vam je poslat. + notice_account_unknown_email: Nepoznati korisnik. + notice_account_updated: Nalog je uspješno promjenen. + notice_account_wrong_password: Pogrešna lozinka + notice_can_t_change_password: Ovaj nalog koristi eksterni izvor prijavljivanja. Ne mogu da promjenim šifru. + notice_default_data_loaded: Podrazumjevana konfiguracija uspječno učitana. + notice_email_error: Došlo je do greške pri slanju emaila (%{value}) + notice_email_sent: "Email je poslan %{value}" + notice_failed_to_save_issues: "Neuspješno snimanje %{count} aktivnosti na %{total} izabrano: %{ids}." + notice_feeds_access_key_reseted: Vaš RSS pristup je resetovan. + notice_file_not_found: Stranica kojoj pokušavate da pristupite ne postoji ili je uklonjena. + notice_locking_conflict: "Konflikt: podaci su izmjenjeni od strane drugog korisnika." + notice_no_issue_selected: "Nijedna aktivnost nije izabrana! Molim, izaberite aktivnosti koje želite za ispravljate." + notice_not_authorized: Niste ovlašćeni da pristupite ovoj stranici. + notice_successful_connection: Uspješna konekcija. + notice_successful_create: Uspješno kreiranje. + notice_successful_delete: Brisanje izvršeno. + notice_successful_update: Promjene uspješno izvršene. + + error_can_t_load_default_data: "Podrazumjevane postavke se ne mogu učitati %{value}" + error_scm_command_failed: "Desila se greška pri pristupu repozitoriju: %{value}" + error_scm_not_found: "Unos i/ili revizija ne postoji u repozitoriju." + + error_scm_annotate: "Ova stavka ne postoji ili nije označena." + error_issue_not_found_in_project: 'Aktivnost nije nađena ili ne pripada ovom projektu' + + warning_attachments_not_saved: "%{count} fajl(ovi) ne mogu biti snimljen(i)." + + mail_subject_lost_password: "Vaša %{value} lozinka" + mail_body_lost_password: 'Za promjenu lozinke, kliknite na sljedeći link:' + mail_subject_register: "Aktivirajte %{value} vaš korisnički račun" + mail_body_register: 'Za aktivaciju vašeg korisničkog računa, kliknite na sljedeći link:' + mail_body_account_information_external: "Možete koristiti vaš %{value} korisnički račun za prijavu na sistem." + mail_body_account_information: Informacija o vašem korisničkom računu + mail_subject_account_activation_request: "%{value} zahtjev za aktivaciju korisničkog računa" + mail_body_account_activation_request: "Novi korisnik (%{value}) se registrovao. Korisnički račun čeka vaše odobrenje za aktivaciju:" + mail_subject_reminder: "%{count} aktivnost(i) u kašnjenju u narednim %{days} danima" + mail_body_reminder: "%{count} aktivnost(i) koje su dodjeljenje vama u narednim %{days} danima:" + + gui_validation_error: 1 greška + gui_validation_error_plural: "%{count} grešaka" + + field_name: Ime + field_description: Opis + field_summary: Pojašnjenje + field_is_required: Neophodno popuniti + field_firstname: Ime + field_lastname: Prezime + field_mail: Email + field_filename: Fajl + field_filesize: Veličina + field_downloads: Downloadi + field_author: Autor + field_created_on: Kreirano + field_updated_on: Izmjenjeno + field_field_format: Format + field_is_for_all: Za sve projekte + field_possible_values: Moguće vrijednosti + field_regexp: '"Regularni izraz"' + field_min_length: Minimalna veličina + field_max_length: Maksimalna veličina + field_value: Vrijednost + field_category: Kategorija + field_title: Naslov + field_project: Projekat + field_issue: Aktivnost + field_status: Status + field_notes: Bilješke + field_is_closed: Aktivnost zatvorena + field_is_default: Podrazumjevana vrijednost + field_tracker: Područje aktivnosti + field_subject: Subjekat + field_due_date: Završiti do + field_assigned_to: Dodijeljeno + field_priority: Prioritet + field_fixed_version: Ciljna verzija + field_user: Korisnik + field_role: Uloga + field_homepage: Naslovna strana + field_is_public: Javni + field_parent: Podprojekt od + field_is_in_roadmap: Aktivnosti prikazane u planu realizacije + field_login: Prijava + field_mail_notification: Email notifikacije + field_admin: Administrator + field_last_login_on: Posljednja konekcija + field_language: Jezik + field_effective_date: Datum + field_password: Lozinka + field_new_password: Nova lozinka + field_password_confirmation: Potvrda + field_version: Verzija + field_type: Tip + field_host: Host + field_port: Port + field_account: Korisnički račun + field_base_dn: Base DN + field_attr_login: Attribut za prijavu + field_attr_firstname: Attribut za ime + field_attr_lastname: Atribut za prezime + field_attr_mail: Atribut za email + field_onthefly: 'Kreiranje korisnika "On-the-fly"' + field_start_date: Početak + field_done_ratio: "% Realizovano" + field_auth_source: Mod za authentifikaciju + field_hide_mail: Sakrij moju email adresu + field_comments: Komentar + field_url: URL + field_start_page: Početna stranica + field_subproject: Podprojekat + field_hours: Sahata + field_activity: Operacija + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Korišteno kao filter + field_issue_to: Povezana aktivnost + field_delay: Odgađanje + field_assignable: Aktivnosti dodijeljene ovoj ulozi + field_redirect_existing_links: Izvrši redirekciju postojećih linkova + field_estimated_hours: Procjena vremena + field_column_names: Kolone + field_time_zone: Vremenska zona + field_searchable: Pretraživo + field_default_value: Podrazumjevana vrijednost + field_comments_sorting: Prikaži komentare + field_parent_title: 'Stranica "roditelj"' + field_editable: Može se mijenjati + field_watcher: Posmatrač + field_identity_url: OpenID URL + field_content: Sadržaj + + setting_app_title: Naslov aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Tekst dobrodošlice + setting_default_language: Podrazumjevani jezik + setting_login_required: Authentifikacija neophodna + setting_self_registration: Samo-registracija + setting_attachment_max_size: Maksimalna veličina prikačenog fajla + setting_issues_export_limit: Limit za eksport aktivnosti + setting_mail_from: Mail adresa - pošaljilac + setting_bcc_recipients: '"BCC" (blind carbon copy) primaoci ' + setting_plain_text_mail: Email sa običnim tekstom (bez HTML-a) + setting_host_name: Ime hosta i putanja + setting_text_formatting: Formatiranje teksta + setting_wiki_compression: Kompresija Wiki istorije + + setting_feeds_limit: 'Limit za "RSS" feed-ove' + setting_default_projects_public: Podrazumjeva se da je novi projekat javni + setting_autofetch_changesets: 'Automatski kupi "commit"-e' + setting_sys_api_enabled: 'Omogući "WS" za upravljanje repozitorijom' + setting_commit_ref_keywords: Ključne riječi za reference + setting_commit_fix_keywords: 'Ključne riječi za status "zatvoreno"' + setting_autologin: Automatski login + setting_date_format: Format datuma + setting_time_format: Format vremena + setting_cross_project_issue_relations: Omogući relacije između aktivnosti na različitim projektima + setting_issue_list_default_columns: Podrazumjevane koleone za prikaz na listi aktivnosti + setting_emails_footer: Potpis na email-ovima + setting_protocol: Protokol + setting_per_page_options: Broj objekata po stranici + setting_user_format: Format korisničkog prikaza + setting_activity_days_default: Prikaz promjena na projektu - opseg dana + setting_display_subprojects_issues: Prikaz podprojekata na glavnom projektima (podrazumjeva se) + setting_enabled_scm: Omogući SCM (source code management) + setting_mail_handler_api_enabled: Omogući automatsku obradu ulaznih emailova + setting_mail_handler_api_key: API ključ (obrada ulaznih mailova) + setting_sequential_project_identifiers: Generiši identifikatore projekta sekvencijalno + setting_gravatar_enabled: 'Koristi "gravatar" korisničke ikone' + setting_diff_max_lines_displayed: Maksimalan broj linija za prikaz razlika između dva fajla + setting_file_max_size_displayed: Maksimalna veličina fajla kod prikaza razlika unutar fajla (inline) + setting_repository_log_display_limit: Maksimalna veličina revizija prikazanih na log fajlu + setting_openid: Omogući OpenID prijavu i registraciju + + permission_edit_project: Ispravke projekta + permission_select_project_modules: Odaberi module projekta + permission_manage_members: Upravljanje članovima + permission_manage_versions: Upravljanje verzijama + permission_manage_categories: Upravljanje kategorijama aktivnosti + permission_add_issues: Dodaj aktivnosti + permission_edit_issues: Ispravka aktivnosti + permission_manage_issue_relations: Upravljaj relacijama među aktivnostima + permission_add_issue_notes: Dodaj bilješke + permission_edit_issue_notes: Ispravi bilješke + permission_edit_own_issue_notes: Ispravi sopstvene bilješke + permission_move_issues: Pomjeri aktivnosti + permission_delete_issues: Izbriši aktivnosti + permission_manage_public_queries: Upravljaj javnim upitima + permission_save_queries: Snimi upite + permission_view_gantt: Pregled gantograma + permission_view_calendar: Pregled kalendara + permission_view_issue_watchers: Pregled liste korisnika koji prate aktivnost + permission_add_issue_watchers: Dodaj onoga koji prati aktivnost + permission_log_time: Evidentiraj utrošak vremena + permission_view_time_entries: Pregled utroška vremena + permission_edit_time_entries: Ispravka utroška vremena + permission_edit_own_time_entries: Ispravka svog utroška vremena + permission_manage_news: Upravljaj novostima + permission_comment_news: Komentiraj novosti + permission_manage_documents: Upravljaj dokumentima + permission_view_documents: Pregled dokumenata + permission_manage_files: Upravljaj fajlovima + permission_view_files: Pregled fajlova + permission_manage_wiki: Upravljaj wiki stranicama + permission_rename_wiki_pages: Ispravi wiki stranicu + permission_delete_wiki_pages: Izbriši wiki stranicu + permission_view_wiki_pages: Pregled wiki sadržaja + permission_view_wiki_edits: Pregled wiki istorije + permission_edit_wiki_pages: Ispravka wiki stranica + permission_delete_wiki_pages_attachments: Brisanje fajlova prikačenih wiki-ju + permission_protect_wiki_pages: Zaštiti wiki stranicu + permission_manage_repository: Upravljaj repozitorijem + permission_browse_repository: Pregled repozitorija + permission_view_changesets: Pregled setova promjena + permission_commit_access: 'Pristup "commit"-u' + permission_manage_boards: Upravljaj forumima + permission_view_messages: Pregled poruka + permission_add_messages: Šalji poruke + permission_edit_messages: Ispravi poruke + permission_edit_own_messages: Ispravka sopstvenih poruka + permission_delete_messages: Prisanje poruka + permission_delete_own_messages: Brisanje sopstvenih poruka + + project_module_issue_tracking: Praćenje aktivnosti + project_module_time_tracking: Praćenje vremena + project_module_news: Novosti + project_module_documents: Dokumenti + project_module_files: Fajlovi + project_module_wiki: Wiki stranice + project_module_repository: Repozitorij + project_module_boards: Forumi + + label_user: Korisnik + label_user_plural: Korisnici + label_user_new: Novi korisnik + label_project: Projekat + label_project_new: Novi projekat + label_project_plural: Projekti + label_x_projects: + zero: 0 projekata + one: 1 projekat + other: "%{count} projekata" + label_project_all: Svi projekti + label_project_latest: Posljednji projekti + label_issue: Aktivnost + label_issue_new: Nova aktivnost + label_issue_plural: Aktivnosti + label_issue_view_all: Vidi sve aktivnosti + label_issues_by: "Aktivnosti po %{value}" + label_issue_added: Aktivnost je dodana + label_issue_updated: Aktivnost je izmjenjena + label_document: Dokument + label_document_new: Novi dokument + label_document_plural: Dokumenti + label_document_added: Dokument je dodan + label_role: Uloga + label_role_plural: Uloge + label_role_new: Nove uloge + label_role_and_permissions: Uloge i dozvole + label_member: Izvršilac + label_member_new: Novi izvršilac + label_member_plural: Izvršioci + label_tracker: Područje aktivnosti + label_tracker_plural: Područja aktivnosti + label_tracker_new: Novo područje aktivnosti + label_workflow: Tok promjena na aktivnosti + label_issue_status: Status aktivnosti + label_issue_status_plural: Statusi aktivnosti + label_issue_status_new: Novi status + label_issue_category: Kategorija aktivnosti + label_issue_category_plural: Kategorije aktivnosti + label_issue_category_new: Nova kategorija + label_custom_field: Proizvoljno polje + label_custom_field_plural: Proizvoljna polja + label_custom_field_new: Novo proizvoljno polje + label_enumerations: Enumeracije + label_enumeration_new: Nova vrijednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Molimo prijavite se + label_register: Registracija + label_login_with_open_id_option: ili prijava sa OpenID-om + label_password_lost: Izgubljena lozinka + label_home: Početna stranica + label_my_page: Moja stranica + label_my_account: Moj korisnički račun + label_my_projects: Moji projekti + label_administration: Administracija + label_login: Prijavi se + label_logout: Odjavi se + label_help: Pomoć + label_reported_issues: Prijavljene aktivnosti + label_assigned_to_me_issues: Aktivnosti dodjeljene meni + label_last_login: Posljednja konekcija + label_registered_on: Registrovan na + label_activity_plural: Promjene + label_activity: Operacija + label_overall_activity: Pregled svih promjena + label_user_activity: "Promjene izvršene od: %{value}" + label_new: Novi + label_logged_as: Prijavljen kao + label_environment: Sistemsko okruženje + label_authentication: Authentifikacija + label_auth_source: Mod authentifikacije + label_auth_source_new: Novi mod authentifikacije + label_auth_source_plural: Modovi authentifikacije + label_subproject_plural: Podprojekti + label_and_its_subprojects: "%{value} i njegovi podprojekti" + label_min_max_length: Min - Maks dužina + label_list: Lista + label_date: Datum + label_integer: Cijeli broj + label_float: Float + label_boolean: Logička varijabla + label_string: Tekst + label_text: Dugi tekst + label_attribute: Atribut + label_attribute_plural: Atributi + label_download: "%{count} download" + label_download_plural: "%{count} download-i" + label_no_data: Nema podataka za prikaz + label_change_status: Promjeni status + label_history: Istorija + label_attachment: Fajl + label_attachment_new: Novi fajl + label_attachment_delete: Izbriši fajl + label_attachment_plural: Fajlovi + label_file_added: Fajl je dodan + label_report: Izvještaj + label_report_plural: Izvještaji + label_news: Novosti + label_news_new: Dodaj novosti + label_news_plural: Novosti + label_news_latest: Posljednje novosti + label_news_view_all: Pogledaj sve novosti + label_news_added: Novosti su dodane + label_settings: Postavke + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_confirmation: Potvrda + label_export_to: 'Takođe dostupno u:' + label_read: Čitaj... + label_public_projects: Javni projekti + label_open_issues: otvoren + label_open_issues_plural: otvoreni + label_closed_issues: zatvoren + label_closed_issues_plural: zatvoreni + label_x_open_issues_abbr_on_total: + zero: 0 otvoreno / %{total} + one: 1 otvorena / %{total} + other: "%{count} otvorene / %{total}" + label_x_open_issues_abbr: + zero: 0 otvoreno + one: 1 otvorena + other: "%{count} otvorene" + label_x_closed_issues_abbr: + zero: 0 zatvoreno + one: 1 zatvorena + other: "%{count} zatvorene" + label_total: Ukupno + label_permissions: Dozvole + label_current_status: Tekući status + label_new_statuses_allowed: Novi statusi dozvoljeni + label_all: sve + label_none: ništa + label_nobody: niko + label_next: Sljedeće + label_previous: Predhodno + label_used_by: Korišteno od + label_details: Detalji + label_add_note: Dodaj bilješku + label_per_page: Po stranici + label_calendar: Kalendar + label_months_from: mjeseci od + label_gantt: Gantt + label_internal: Interno + label_last_changes: "posljednjih %{count} promjena" + label_change_view_all: Vidi sve promjene + label_personalize_page: Personaliziraj ovu stranicu + label_comment: Komentar + label_comment_plural: Komentari + label_x_comments: + zero: bez komentara + one: 1 komentar + other: "%{count} komentari" + label_comment_add: Dodaj komentar + label_comment_added: Komentar je dodan + label_comment_delete: Izbriši komentar + label_query: Proizvoljan upit + label_query_plural: Proizvoljni upiti + label_query_new: Novi upit + label_filter_add: Dodaj filter + label_filter_plural: Filteri + label_equals: je + label_not_equals: nije + label_in_less_than: je manji nego + label_in_more_than: je više nego + label_in: u + label_today: danas + label_all_time: sve vrijeme + label_yesterday: juče + label_this_week: ova hefta + label_last_week: zadnja hefta + label_last_n_days: "posljednjih %{count} dana" + label_this_month: ovaj mjesec + label_last_month: posljednji mjesec + label_this_year: ova godina + label_date_range: Datumski opseg + label_less_than_ago: ranije nego (dana) + label_more_than_ago: starije nego (dana) + label_ago: prije (dana) + label_contains: sadrži + label_not_contains: ne sadrži + label_day_plural: dani + label_repository: Repozitorij + label_repository_plural: Repozitoriji + label_browse: Listaj + label_modification: "%{count} promjena" + label_modification_plural: "%{count} promjene" + label_revision: Revizija + label_revision_plural: Revizije + label_associated_revisions: Doddjeljene revizije + label_added: dodano + label_modified: izmjenjeno + label_copied: kopirano + label_renamed: preimenovano + label_deleted: izbrisano + label_latest_revision: Posljednja revizija + label_latest_revision_plural: Posljednje revizije + label_view_revisions: Vidi revizije + label_max_size: Maksimalna veličina + label_sort_highest: Pomjeri na vrh + label_sort_higher: Pomjeri gore + label_sort_lower: Pomjeri dole + label_sort_lowest: Pomjeri na dno + label_roadmap: Plan realizacije + label_roadmap_due_in: "Obavezan do %{value}" + label_roadmap_overdue: "%{value} kasni" + label_roadmap_no_issues: Nema aktivnosti za ovu verziju + label_search: Traži + label_result_plural: Rezultati + label_all_words: Sve riječi + label_wiki: Wiki stranice + label_wiki_edit: ispravka wiki-ja + label_wiki_edit_plural: ispravke wiki-ja + label_wiki_page: Wiki stranica + label_wiki_page_plural: Wiki stranice + label_index_by_title: Indeks prema naslovima + label_index_by_date: Indeks po datumima + label_current_version: Tekuća verzija + label_preview: Pregled + label_feed_plural: Feeds + label_changes_details: Detalji svih promjena + label_issue_tracking: Evidencija aktivnosti + label_spent_time: Utrošak vremena + label_f_hour: "%{value} sahat" + label_f_hour_plural: "%{value} sahata" + label_time_tracking: Evidencija vremena + label_change_plural: Promjene + label_statistics: Statistika + label_commits_per_month: '"Commit"-a po mjesecu' + label_commits_per_author: '"Commit"-a po autoru' + label_view_diff: Pregled razlika + label_diff_inline: zajedno + label_diff_side_by_side: jedna pored druge + label_options: Opcije + label_copy_workflow_from: Kopiraj tok promjena statusa iz + label_permissions_report: Izvještaj + label_watched_issues: Aktivnosti koje pratim + label_related_issues: Korelirane aktivnosti + label_applied_status: Status je primjenjen + label_loading: Učitavam... + label_relation_new: Nova relacija + label_relation_delete: Izbriši relaciju + label_relates_to: korelira sa + label_duplicates: duplikat + label_duplicated_by: duplicirano od + label_blocks: blokira + label_blocked_by: blokirano on + label_precedes: predhodi + label_follows: slijedi + label_end_to_start: 'kraj -> početak' + label_end_to_end: 'kraja -> kraj' + label_start_to_start: 'početak -> početak' + label_start_to_end: 'početak -> kraj' + label_stay_logged_in: Ostani prijavljen + label_disabled: onemogućen + label_show_completed_versions: Prikaži završene verzije + label_me: ja + label_board: Forum + label_board_new: Novi forum + label_board_plural: Forumi + label_topic_plural: Teme + label_message_plural: Poruke + label_message_last: Posljednja poruka + label_message_new: Nova poruka + label_message_posted: Poruka je dodana + label_reply_plural: Odgovori + label_send_information: Pošalji informaciju o korisničkom računu + label_year: Godina + label_month: Mjesec + label_week: Hefta + label_date_from: Od + label_date_to: Do + label_language_based: Bazirano na korisnikovom jeziku + label_sort_by: "Sortiraj po %{value}" + label_send_test_email: Pošalji testni email + label_feeds_access_key_created_on: "RSS pristupni ključ kreiran prije %{value} dana" + label_module_plural: Moduli + label_added_time_by: "Dodano od %{author} prije %{age}" + label_updated_time_by: "Izmjenjeno od %{author} prije %{age}" + label_updated_time: "Izmjenjeno prije %{value}" + label_jump_to_a_project: Skoči na projekat... + label_file_plural: Fajlovi + label_changeset_plural: Setovi promjena + label_default_columns: Podrazumjevane kolone + label_no_change_option: (Bez promjene) + label_bulk_edit_selected_issues: Ispravi odjednom odabrane aktivnosti + label_theme: Tema + label_default: Podrazumjevano + label_search_titles_only: Pretraži samo naslove + label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" + label_user_mail_option_selected: "Za bilo koji događaj na odabranim projektima..." + label_user_mail_no_self_notified: "Ne želim notifikaciju za promjene koje sam ja napravio" + label_registration_activation_by_email: aktivacija korisničkog računa email-om + label_registration_manual_activation: ručna aktivacija korisničkog računa + label_registration_automatic_activation: automatska kreacija korisničkog računa + label_display_per_page: "Po stranici: %{value}" + label_age: Starost + label_change_properties: Promjena osobina + label_general: Generalno + label_more: Više + label_scm: SCM + label_plugins: Plugin-ovi + label_ldap_authentication: LDAP authentifikacija + label_downloads_abbr: D/L + label_optional_description: Opis (opciono) + label_add_another_file: Dodaj još jedan fajl + label_preferences: Postavke + label_chronological_order: Hronološki poredak + label_reverse_chronological_order: Reverzni hronološki poredak + label_planning: Planiranje + label_incoming_emails: Dolazni email-ovi + label_generate_key: Generiši ključ + label_issue_watchers: Praćeno od + label_example: Primjer + label_display: Prikaz + + button_apply: Primjeni + button_add: Dodaj + button_archive: Arhiviranje + button_back: Nazad + button_cancel: Odustani + button_change: Izmjeni + button_change_password: Izmjena lozinke + button_check_all: Označi sve + button_clear: Briši + button_copy: Kopiraj + button_create: Novi + button_delete: Briši + button_download: Download + button_edit: Ispravka + button_list: Lista + button_lock: Zaključaj + button_log_time: Utrošak vremena + button_login: Prijava + button_move: Pomjeri + button_rename: Promjena imena + button_reply: Odgovor + button_reset: Resetuj + button_rollback: Vrati predhodno stanje + button_save: Snimi + button_sort: Sortiranje + button_submit: Pošalji + button_test: Testiraj + button_unarchive: Otpakuj arhivu + button_uncheck_all: Isključi sve + button_unlock: Otključaj + button_unwatch: Prekini notifikaciju + button_update: Promjena na aktivnosti + button_view: Pregled + button_watch: Notifikacija + button_configure: Konfiguracija + button_quote: Citat + + status_active: aktivan + status_registered: registrovan + status_locked: zaključan + + text_select_mail_notifications: Odaberi događaje za koje će se slati email notifikacija. + text_regexp_info: npr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znači bez restrikcije + text_project_destroy_confirmation: Sigurno želite izbrisati ovaj projekat i njegove podatke ? + text_subprojects_destroy_warning: "Podprojekt(i): %{value} će takođe biti izbrisani." + text_workflow_edit: Odaberite ulogu i područje aktivnosti za ispravku toka promjena na aktivnosti + text_are_you_sure: Da li ste sigurni ? + text_tip_issue_begin_day: zadatak počinje danas + text_tip_issue_end_day: zadatak završava danas + text_tip_issue_begin_end_day: zadatak započinje i završava danas + text_project_identifier_info: 'Samo mala slova (a-z), brojevi i crtice su dozvoljeni.
    Nakon snimanja, identifikator se ne može mijenjati.' + text_caracters_maximum: "maksimum %{count} karaktera." + text_caracters_minimum: "Dužina mora biti najmanje %{count} znakova." + text_length_between: "Broj znakova između %{min} i %{max}." + text_tracker_no_workflow: Tok statusa nije definisan za ovo područje aktivnosti + text_unallowed_characters: Nedozvoljeni znakovi + text_comma_separated: Višestruke vrijednosti dozvoljene (odvojiti zarezom). + text_issues_ref_in_commit_messages: 'Referenciranje i zatvaranje aktivnosti putem "commit" poruka' + text_issue_added: "Aktivnost %{id} je prijavljena od %{author}." + text_issue_updated: "Aktivnost %{id} je izmjenjena od %{author}." + text_wiki_destroy_confirmation: Sigurno želite izbrisati ovaj wiki i čitav njegov sadržaj ? + text_issue_category_destroy_question: "Neke aktivnosti (%{count}) pripadaju ovoj kategoriji. Sigurno to želite uraditi ?" + text_issue_category_destroy_assignments: Ukloni kategoriju + text_issue_category_reassign_to: Ponovo dodijeli ovu kategoriju + text_user_mail_option: "Za projekte koje niste odabrali, primićete samo notifikacije o stavkama koje pratite ili ste u njih uključeni (npr. vi ste autor ili su vama dodjeljenje)." + text_no_configuration_data: "Uloge, područja aktivnosti, statusi aktivnosti i tok promjena statusa nisu konfigurisane.\nKrajnje je preporučeno da učitate tekuđe postavke. Kasnije ćete ih moći mjenjati po svojim potrebama." + text_load_default_configuration: Učitaj tekuću konfiguraciju + text_status_changed_by_changeset: "Primjenjeno u setu promjena %{value}." + text_issues_destroy_confirmation: 'Sigurno želite izbrisati odabranu/e aktivnost/i ?' + text_select_project_modules: 'Odaberi module koje želite u ovom projektu:' + text_default_administrator_account_changed: Tekući administratorski račun je promjenjen + text_file_repository_writable: U direktorij sa fajlovima koji su prilozi se može pisati + text_plugin_assets_writable: U direktorij plugin-ova se može pisati + text_rmagick_available: RMagick je dostupan (opciono) + text_destroy_time_entries_question: "%{hours} sahata je prijavljeno na aktivnostima koje želite brisati. Želite li to učiniti ?" + text_destroy_time_entries: Izbriši prijavljeno vrijeme + text_assign_time_entries_to_project: Dodaj prijavljenoo vrijeme projektu + text_reassign_time_entries: 'Preraspodjeli prijavljeno vrijeme na ovu aktivnost:' + text_user_wrote: "%{value} je napisao/la:" + text_enumeration_destroy_question: "Za %{count} objekata je dodjeljenja ova vrijednost." + text_enumeration_category_reassign_to: 'Ponovo im dodjeli ovu vrijednost:' + text_email_delivery_not_configured: "Email dostava nije konfiguraisana, notifikacija je onemogućena.\nKonfiguriši SMTP server u config/configuration.yml i restartuj aplikaciju nakon toga." + text_repository_usernames_mapping: "Odaberi ili ispravi redmine korisnika mapiranog za svako korisničko ima nađeno u logu repozitorija.\nKorisnici sa istim imenom u redmineu i u repozitoruju se automatski mapiraju." + text_diff_truncated: '... Ovaj prikaz razlike je odsječen pošto premašuje maksimalnu veličinu za prikaz' + text_custom_field_possible_values_info: 'Jedna linija za svaku vrijednost' + + default_role_manager: Menadžer + default_role_developer: Programer + default_role_reporter: Reporter + default_tracker_bug: Greška + default_tracker_feature: Nova funkcija + default_tracker_support: Podrška + default_issue_status_new: Novi + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Riješen + default_issue_status_feedback: Čeka se povratna informacija + default_issue_status_closed: Zatvoren + default_issue_status_rejected: Odbijen + default_doc_category_user: Korisnička dokumentacija + default_doc_category_tech: Tehnička dokumentacija + default_priority_low: Nizak + default_priority_normal: Normalan + default_priority_high: Visok + default_priority_urgent: Urgentno + default_priority_immediate: Odmah + default_activity_design: Dizajn + default_activity_development: Programiranje + + enumeration_issue_priorities: Prioritet aktivnosti + enumeration_doc_categories: Kategorije dokumenata + enumeration_activities: Operacije (utrošak vremena) + notice_unable_delete_version: Ne mogu izbrisati verziju. + button_create_and_continue: Kreiraj i nastavi + button_annotate: Zabilježi + button_activate: Aktiviraj + label_sort: Sortiranje + label_date_from_to: Od %{start} do %{end} + label_ascending: Rastuće + label_descending: Opadajuće + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: 'Enkodiranje "commit" poruka' + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7f2b03891b8623abed7eda3f27f2af99b02de39f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7f2b03891b8623abed7eda3f27f2af99b02de39f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,413 @@ +package Apache::Authn::Redmine; + +=head1 Apache::Authn::Redmine + +Redmine - a mod_perl module to authenticate webdav subversion users +against redmine database + +=head1 SYNOPSIS + +This module allow anonymous users to browse public project and +registred users to browse and commit their project. Authentication is +done against the redmine database or the LDAP configured in redmine. + +This method is far simpler than the one with pam_* and works with all +database without an hassle but you need to have apache/mod_perl on the +svn server. + +=head1 INSTALLATION + +For this to automagically work, you need to have a recent reposman.rb +(after r860) and if you already use reposman, read the last section to +migrate. + +Sorry ruby users but you need some perl modules, at least mod_perl2, +DBI and DBD::mysql (or the DBD driver for you database as it should +work on allmost all databases). + +On debian/ubuntu you must do : + + aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl + +If your Redmine users use LDAP authentication, you will also need +Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used): + + aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl + +=head1 CONFIGURATION + + ## This module has to be in your perl path + ## eg: /usr/lib/perl5/Apache/Authn/Redmine.pm + PerlLoadModule Apache::Authn::Redmine + + DAV svn + SVNParentPath "/var/svn" + + AuthType Basic + AuthName redmine + Require valid-user + + PerlAccessHandler Apache::Authn::Redmine::access_handler + PerlAuthenHandler Apache::Authn::Redmine::authen_handler + + ## for mysql + RedmineDSN "DBI:mysql:database=databasename;host=my.db.server" + ## for postgres + # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server" + + RedmineDbUser "redmine" + RedmineDbPass "password" + ## Optional where clause (fulltext search would be slow and + ## database dependant). + # RedmineDbWhereClause "and members.role_id IN (1,2)" + ## Optional credentials cache size + # RedmineCacheCredsMax 50 + + +To be able to browse repository inside redmine, you must add something +like that : + + + DAV svn + SVNParentPath "/var/svn" + Order deny,allow + Deny from all + # only allow reading orders + + Allow from redmine.server.ip + + + +and you will have to use this reposman.rb command line to create repository : + + reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/ + +=head1 MIGRATION FROM OLDER RELEASES + +If you use an older reposman.rb (r860 or before), you need to change +rights on repositories to allow the apache user to read and write +S + + sudo chown -R www-data /var/svn/* + sudo chmod -R u+w /var/svn/* + +And you need to upgrade at least reposman.rb (after r860). + +=cut + +use strict; +use warnings FATAL => 'all', NONFATAL => 'redefine'; + +use DBI; +use Digest::SHA1; +# optional module for LDAP authentication +my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1"); + +use Apache2::Module; +use Apache2::Access; +use Apache2::ServerRec qw(); +use Apache2::RequestRec qw(); +use Apache2::RequestUtil qw(); +use Apache2::Const qw(:common :override :cmd_how); +use APR::Pool (); +use APR::Table (); + +# use Apache2::Directive qw(); + +my @directives = ( + { + name => 'RedmineDSN', + req_override => OR_AUTHCFG, + args_how => TAKE1, + errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"', + }, + { + name => 'RedmineDbUser', + req_override => OR_AUTHCFG, + args_how => TAKE1, + }, + { + name => 'RedmineDbPass', + req_override => OR_AUTHCFG, + args_how => TAKE1, + }, + { + name => 'RedmineDbWhereClause', + req_override => OR_AUTHCFG, + args_how => TAKE1, + }, + { + name => 'RedmineCacheCredsMax', + req_override => OR_AUTHCFG, + args_how => TAKE1, + errmsg => 'RedmineCacheCredsMax must be decimal number', + }, +); + +sub RedmineDSN { + my ($self, $parms, $arg) = @_; + $self->{RedmineDSN} = $arg; + my $query = "SELECT + hashed_password, salt, auth_source_id, permissions + FROM projects, users, roles + WHERE + users.login=? + AND projects.identifier=? + AND users.status=1 + AND ( + roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id) + OR + (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1')) + ) "; + $self->{RedmineQuery} = trim($query); +} + +sub RedmineDbUser { set_val('RedmineDbUser', @_); } +sub RedmineDbPass { set_val('RedmineDbPass', @_); } +sub RedmineDbWhereClause { + my ($self, $parms, $arg) = @_; + $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." "); +} + +sub RedmineCacheCredsMax { + my ($self, $parms, $arg) = @_; + if ($arg) { + $self->{RedmineCachePool} = APR::Pool->new; + $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg); + $self->{RedmineCacheCredsCount} = 0; + $self->{RedmineCacheCredsMax} = $arg; + } +} + +sub trim { + my $string = shift; + $string =~ s/\s{2,}/ /g; + return $string; +} + +sub set_val { + my ($key, $self, $parms, $arg) = @_; + $self->{$key} = $arg; +} + +Apache2::Module::add(__PACKAGE__, \@directives); + + +my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/; + +sub access_handler { + my $r = shift; + + unless ($r->some_auth_required) { + $r->log_reason("No authentication has been configured"); + return FORBIDDEN; + } + + my $method = $r->method; + return OK unless defined $read_only_methods{$method}; + + my $project_id = get_project_identifier($r); + + $r->set_handlers(PerlAuthenHandler => [\&OK]) + if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r); + + return OK +} + +sub authen_handler { + my $r = shift; + + my ($res, $redmine_pass) = $r->get_basic_auth_pw(); + return $res unless $res == OK; + + if (is_member($r->user, $redmine_pass, $r)) { + return OK; + } else { + $r->note_auth_failure(); + return AUTH_REQUIRED; + } +} + +# check if authentication is forced +sub is_authentication_forced { + my $r = shift; + + my $dbh = connect_database($r); + my $sth = $dbh->prepare( + "SELECT value FROM settings where settings.name = 'login_required';" + ); + + $sth->execute(); + my $ret = 0; + if (my @row = $sth->fetchrow_array) { + if ($row[0] eq "1" || $row[0] eq "t") { + $ret = 1; + } + } + $sth->finish(); + undef $sth; + + $dbh->disconnect(); + undef $dbh; + + $ret; +} + +sub is_public_project { + my $project_id = shift; + my $r = shift; + + if (is_authentication_forced($r)) { + return 0; + } + + my $dbh = connect_database($r); + my $sth = $dbh->prepare( + "SELECT is_public FROM projects WHERE projects.identifier = ?;" + ); + + $sth->execute($project_id); + my $ret = 0; + if (my @row = $sth->fetchrow_array) { + if ($row[0] eq "1" || $row[0] eq "t") { + $ret = 1; + } + } + $sth->finish(); + undef $sth; + $dbh->disconnect(); + undef $dbh; + + $ret; +} + +sub anonymous_role_allows_browse_repository { + my $r = shift; + + my $dbh = connect_database($r); + my $sth = $dbh->prepare( + "SELECT permissions FROM roles WHERE builtin = 2;" + ); + + $sth->execute(); + my $ret = 0; + if (my @row = $sth->fetchrow_array) { + if ($row[0] =~ /:browse_repository/) { + $ret = 1; + } + } + $sth->finish(); + undef $sth; + $dbh->disconnect(); + undef $dbh; + + $ret; +} + +# perhaps we should use repository right (other read right) to check public access. +# it could be faster BUT it doesn't work for the moment. +# sub is_public_project_by_file { +# my $project_id = shift; +# my $r = shift; + +# my $tree = Apache2::Directive::conftree(); +# my $node = $tree->lookup('Location', $r->location); +# my $hash = $node->as_hash; + +# my $svnparentpath = $hash->{SVNParentPath}; +# my $repos_path = $svnparentpath . "/" . $project_id; +# return 1 if (stat($repos_path))[2] & 00007; +# } + +sub is_member { + my $redmine_user = shift; + my $redmine_pass = shift; + my $r = shift; + + my $dbh = connect_database($r); + my $project_id = get_project_identifier($r); + + my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); + + my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W"; + + my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); + my $usrprojpass; + if ($cfg->{RedmineCacheCredsMax}) { + $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode); + return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); + } + my $query = $cfg->{RedmineQuery}; + my $sth = $dbh->prepare($query); + $sth->execute($redmine_user, $project_id); + + my $ret; + while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) { + + unless ($auth_source_id) { + my $method = $r->method; + my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest); + if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) { + $ret = 1; + last; + } + } elsif ($CanUseLDAPAuth) { + my $sthldap = $dbh->prepare( + "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;" + ); + $sthldap->execute($auth_source_id); + while (my @rowldap = $sthldap->fetchrow_array) { + my $ldap = Authen::Simple::LDAP->new( + host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0], + port => $rowldap[1], + basedn => $rowldap[5], + binddn => $rowldap[3] ? $rowldap[3] : "", + bindpw => $rowldap[4] ? $rowldap[4] : "", + filter => "(".$rowldap[6]."=%s)" + ); + my $method = $r->method; + $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/)); + + } + $sthldap->finish(); + undef $sthldap; + } + } + $sth->finish(); + undef $sth; + $dbh->disconnect(); + undef $dbh; + + if ($cfg->{RedmineCacheCredsMax} and $ret) { + if (defined $usrprojpass) { + $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest); + } else { + if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) { + $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest); + $cfg->{RedmineCacheCredsCount}++; + } else { + $cfg->{RedmineCacheCreds}->clear(); + $cfg->{RedmineCacheCredsCount} = 0; + } + } + } + + $ret; +} + +sub get_project_identifier { + my $r = shift; + + my $location = $r->location; + my ($identifier) = $r->uri =~ m{$location/*([^/]+)}; + $identifier; +} + +sub connect_database { + my $r = shift; + + my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); + return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass}); +} + +1; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7f4f3c3fb8b5541145200128eb2877272491e49b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7f4f3c3fb8b5541145200128eb2877272491e49b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeVersionsNameLimit < ActiveRecord::Migration + def self.up + change_column :versions, :name, :string, :limit => nil + end + + def self.down + change_column :versions, :name, :string, :limit => 30 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7f793d123c11e16acd2d74a86ee6e86fa59cf1d2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7f793d123c11e16acd2d74a86ee6e86fa59cf1d2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,97 @@ +== Redmine installation + +Redmine - project management software +Copyright (C) 2006-2011 Jean-Philippe Lang +http://www.redmine.org/ + + +== Requirements + +* Ruby 1.8.6 or 1.8.7 + +* RubyGems 1.3.7 + +* Ruby on Rails 2.3.14 (official downloadable Redmine releases are packaged with + the appropriate Rails version) + +* Rack 1.1.2 gem + +* Rake 0.9.2 gem + +* I18n 0.4.2 gem + +* A database: + * MySQL (tested with MySQL 5.1) + * PostgreSQL (tested with PostgreSQL 8.4) + * SQLite3 (tested with SQLite 3.6) + +Optional: +* SCM binaries (e.g. svn), for repository browsing (must be available in PATH) +* RMagick (to enable Gantt export to png images) +* Ruby OpenID Library >= version 2 (to enable OpenID support) + +== Installation + +1. Uncompress the program archive + +2. Create an empty database: "redmine" for example + +3. Configure the database parameters in config/database.yml + for the "production" environment (default database is MySQL) + +4. Generate a session store secret + + Redmine stores session data in cookies by default, which requires + a secret to be generated. Under the application main directory run: + rake generate_session_store + +5. Create the database structure + + Under the application main directory run: + rake db:migrate RAILS_ENV="production" + + It will create all the tables and an administrator account. + +6. Setting up permissions (Windows users have to skip this section) + + The user who runs Redmine must have write permission on the following + subdirectories: files, log, tmp & public/plugin_assets (create the last + two if they are not yet present). + + Assuming you run Redmine with a user named "redmine": + mkdir tmp public/plugin_assets + sudo chown -R redmine:redmine files log tmp public/plugin_assets + sudo chmod -R 755 files log tmp public/plugin_assets + +7. Test the installation by running the WEBrick web server + + Under the main application directory run: + ruby script/server -e production + + Once WEBrick has started, point your browser to http://localhost:3000/ + You should now see the application welcome page. + +8. Use the default administrator account to log in: + login: admin + password: admin + + Go to "Administration" to load the default configuration data (roles, + trackers, statuses, workflow) and to adjust the application settings + +== SMTP server Configuration + +Copy config/configuration.yml.example to config/configuration.yml and +edit this file to adjust your SMTP settings. +Do not forget to restart the application after any change to this file. + +Please do not enter your SMTP settings in environment.rb. + +== References + +* http://www.redmine.org/wiki/redmine/RedmineInstall +* http://www.redmine.org/wiki/redmine/EmailConfiguration +* http://www.redmine.org/wiki/redmine/RedmineSettings +* http://www.redmine.org/wiki/redmine/RedmineRepositories +* http://www.redmine.org/wiki/redmine/RedmineReceivingEmails +* http://www.redmine.org/wiki/redmine/RedmineReminderEmails +* http://www.redmine.org/wiki/redmine/RedmineLDAP diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7fd2e45fcd400139b222df563299c0b121c16798.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7fd2e45fcd400139b222df563299c0b121c16798.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_query_new) %>

    + +<% form_tag(@project ? project_queries_path : queries_path, :onsubmit => 'selectAllOptions("selected_columns");') do %> + <%= render :partial => 'form', :locals => {:query => @query} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7ff23d5fea408f9d6534a6f5460b6d5d1d871f7f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7ff23d5fea408f9d6534a6f5460b6d5d1d871f7f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +
    +<%= link_to(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit') %> +<%= link_to(l(:label_history), + {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +

    +<%= l(:label_version) %> <%= link_to h(@annotate.content.version), + :action => 'show', :project_id => @project, + :id => @page.title, :version => @annotate.content.version %> +(<%= h(@annotate.content.author ? + @annotate.content.author.name : l(:label_user_anonymous)) + %>, <%= format_time(@annotate.content.updated_on) %>) +

    + +<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> + + + +<% line_num = 1 %> +<% @annotate.lines.each do |line| -%> + + + + + + +<% line_num += 1 %> +<% end -%> + +
    <%= line_num %><%= link_to line[0], :controller => 'wiki', + :action => 'show', :project_id => @project, + :id => @page.title, :version => line[0] %><%= h(line[1]) %>
    <%=h line[2] %>
    + +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/7f/7ff580843dffaee1ae5e2a96cf519330f6f872bc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/7f/7ff580843dffaee1ae5e2a96cf519330f6f872bc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class SaltUserPasswords < ActiveRecord::Migration + + def self.up + say_with_time "Salting user passwords, this may take some time..." do + User.salt_unsalted_passwords! + end + end + + def self.down + # Unsalted passwords can not be restored + raise ActiveRecord::IrreversibleMigration, "Can't decypher salted passwords. This migration can not be rollback'ed." + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/80/8037a24ac1c230918a9d49478ffdf3d5e6485948.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/80/8037a24ac1c230918a9d49478ffdf3d5e6485948.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +action_controller: + id: 2 + name: Active Controller + +active_record: + id: 1 + name: Active Record diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/80/805a8b03f317de442787ef8a23fd231ec228a620.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/80/805a8b03f317de442787ef8a23fd231ec228a620.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,77 @@ +# ActsAsWatchable +module Redmine + module Acts + module Watchable + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_watchable(options = {}) + return if self.included_modules.include?(Redmine::Acts::Watchable::InstanceMethods) + send :include, Redmine::Acts::Watchable::InstanceMethods + + class_eval do + has_many :watchers, :as => :watchable, :dependent => :delete_all + has_many :watcher_users, :through => :watchers, :source => :user, :validate => false + + named_scope :watched_by, lambda { |user_id| + { :include => :watchers, + :conditions => ["#{Watcher.table_name}.user_id = ?", user_id] } + } + attr_protected :watcher_ids, :watcher_user_ids + end + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + end + + # Returns an array of users that are proposed as watchers + def addable_watcher_users + users = self.project.users.sort - self.watcher_users + if respond_to?(:visible?) + users.reject! {|user| !visible?(user)} + end + users + end + + # Adds user as a watcher + def add_watcher(user) + self.watchers << Watcher.new(:user => user) + end + + # Removes user from the watchers list + def remove_watcher(user) + return nil unless user && user.is_a?(User) + Watcher.delete_all "watchable_type = '#{self.class}' AND watchable_id = #{self.id} AND user_id = #{user.id}" + end + + # Adds/removes watcher + def set_watcher(user, watching=true) + watching ? add_watcher(user) : remove_watcher(user) + end + + # Returns true if object is watched by +user+ + def watched_by?(user) + !!(user && self.watcher_user_ids.detect {|uid| uid == user.id }) + end + + # Returns an array of watchers' email addresses + def watcher_recipients + notified = watcher_users.active + notified.reject! {|user| user.mail_notification == 'none'} + + if respond_to?(:visible?) + notified.reject! {|user| !visible?(user)} + end + notified.collect(&:mail).compact + end + + module ClassMethods; end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/80/808c2b8d656d91389ca1e0955ebdc3c622ab9ac0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/80/808c2b8d656d91389ca1e0955ebdc3c622ab9ac0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +

    <%= @query.new_record? ? l(:label_calendar) : h(@query.name) %>

    + +<% form_tag({:controller => 'calendars', :action => 'show', :project_id => @project}, :method => :get, :id => 'query_form') do %> +<%= hidden_field_tag 'set_filter', '1' %> +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +

    + <%= link_to_previous_month(@year, @month) %> | <%= link_to_next_month(@year, @month) %> +

    + +

    +<%= label_tag('month', l(:label_month)) %> +<%= select_month(@month, :prefix => "month", :discard_type => true) %> +<%= label_tag('year', l(:label_year)) %> +<%= select_year(@year, :prefix => "year", :discard_type => true) %> + +<%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %> +<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 }, :class => 'icon icon-reload' %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %> + +

    + <%= l(:text_tip_issue_begin_day) %> + <%= l(:text_tip_issue_end_day) %> + <%= l(:text_tip_issue_begin_end_day) %> +

    +<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> +<% end %> + +<% html_title(l(:label_calendar)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/80/80cc012f0ec91e8ef1adc8047efcacc9dac1c803.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/80/80cc012f0ec91e8ef1adc8047efcacc9dac1c803.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=l(:label_permissions_report)%>

    + +<% form_tag({:action => 'report'}, :id => 'permissions_form') do %> +<%= hidden_field_tag 'permissions[0]', '', :id => nil %> +
    + + + + + <% @roles.each do |role| %> + + <% end %> + + + +<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> +<% perms_by_module.keys.sort.each do |mod| %> + <% unless mod.blank? %> + + + + <% end %> + <% perms_by_module[mod].each do |permission| %> + + + <% @roles.each do |role| %> + + <% end %> + + <% end %> +<% end %> + +
    <%=l(:label_permissions)%> + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.role-#{role.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> +
    +   + <%= l_or_humanize(mod, :prefix => 'project_module_') %> +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('.permission-#{permission.name} input')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%= l_or_humanize(permission.name, :prefix => 'permission_') %> + + <% if role.setable_permissions.include? permission %> + <%= check_box_tag "permissions[#{role.id}][]", permission.name, (role.permissions.include? permission.name), :id => nil, :class => "role-#{role.id}" %> + <% end %> +
    +
    +

    <%= check_all_links 'permissions_form' %>

    +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/810e440c849a25bc21120be8803fc41e09ff0b5e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/810e440c849a25bc21120be8803fc41e09ff0b5e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRolesAssignable < ActiveRecord::Migration + def self.up + add_column :roles, :assignable, :boolean, :default => true + end + + def self.down + remove_column :roles, :assignable + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/81172b2094c31db1f0abe25641889634ec935550.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/81172b2094c31db1f0abe25641889634ec935550.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +<%= javascript_include_tag "raphael.js" %> + +<%= javascript_include_tag "revision_graph.js" %> + + + +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/811f1ba6d3aa9ff895b79ad6fc02919805520105.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/811f1ba6d3aa9ff895b79ad6fc02919805520105.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +# just here so that Rails recognizes this as a plugin \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/815073e9f3bcaa80c2a4ee60b82257dc8dc26440.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/815073e9f3bcaa80c2a4ee60b82257dc8dc26440.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1195 @@ +# vim:ts=4:sw=4: +# = RedCloth - Textile and Markdown Hybrid for Ruby +# +# Homepage:: http://whytheluckystiff.net/ruby/redcloth/ +# Author:: why the lucky stiff (http://whytheluckystiff.net/) +# Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.) +# License:: BSD +# +# (see http://hobix.com/textile/ for a Textile Reference.) +# +# Based on (and also inspired by) both: +# +# PyTextile: http://diveintomark.org/projects/textile/textile.py.txt +# Textism for PHP: http://www.textism.com/tools/textile/ +# +# + +# = RedCloth +# +# RedCloth is a Ruby library for converting Textile and/or Markdown +# into HTML. You can use either format, intermingled or separately. +# You can also extend RedCloth to honor your own custom text stylings. +# +# RedCloth users are encouraged to use Textile if they are generating +# HTML and to use Markdown if others will be viewing the plain text. +# +# == What is Textile? +# +# Textile is a simple formatting style for text +# documents, loosely based on some HTML conventions. +# +# == Sample Textile Text +# +# h2. This is a title +# +# h3. This is a subhead +# +# This is a bit of paragraph. +# +# bq. This is a blockquote. +# +# = Writing Textile +# +# A Textile document consists of paragraphs. Paragraphs +# can be specially formatted by adding a small instruction +# to the beginning of the paragraph. +# +# h[n]. Header of size [n]. +# bq. Blockquote. +# # Numeric list. +# * Bulleted list. +# +# == Quick Phrase Modifiers +# +# Quick phrase modifiers are also included, to allow formatting +# of small portions of text within a paragraph. +# +# \_emphasis\_ +# \_\_italicized\_\_ +# \*strong\* +# \*\*bold\*\* +# ??citation?? +# -deleted text- +# +inserted text+ +# ^superscript^ +# ~subscript~ +# @code@ +# %(classname)span% +# +# ==notextile== (leave text alone) +# +# == Links +# +# To make a hypertext link, put the link text in "quotation +# marks" followed immediately by a colon and the URL of the link. +# +# Optional: text in (parentheses) following the link text, +# but before the closing quotation mark, will become a Title +# attribute for the link, visible as a tool tip when a cursor is above it. +# +# Example: +# +# "This is a link (This is a title) ":http://www.textism.com +# +# Will become: +# +# This is a link +# +# == Images +# +# To insert an image, put the URL for the image inside exclamation marks. +# +# Optional: text that immediately follows the URL in (parentheses) will +# be used as the Alt text for the image. Images on the web should always +# have descriptive Alt text for the benefit of readers using non-graphical +# browsers. +# +# Optional: place a colon followed by a URL immediately after the +# closing ! to make the image into a link. +# +# Example: +# +# !http://www.textism.com/common/textist.gif(Textist)! +# +# Will become: +# +# Textist +# +# With a link: +# +# !/common/textist.gif(Textist)!:http://textism.com +# +# Will become: +# +# Textist +# +# == Defining Acronyms +# +# HTML allows authors to define acronyms via the tag. The definition appears as a +# tool tip when a cursor hovers over the acronym. A crucial aid to clear writing, +# this should be used at least once for each acronym in documents where they appear. +# +# To quickly define an acronym in Textile, place the full text in (parentheses) +# immediately following the acronym. +# +# Example: +# +# ACLU(American Civil Liberties Union) +# +# Will become: +# +# ACLU +# +# == Adding Tables +# +# In Textile, simple tables can be added by seperating each column by +# a pipe. +# +# |a|simple|table|row| +# |And|Another|table|row| +# +# Attributes are defined by style definitions in parentheses. +# +# table(border:1px solid black). +# (background:#ddd;color:red). |{}| | | | +# +# == Using RedCloth +# +# RedCloth is simply an extension of the String class, which can handle +# Textile formatting. Use it like a String and output HTML with its +# RedCloth#to_html method. +# +# doc = RedCloth.new " +# +# h2. Test document +# +# Just a simple test." +# +# puts doc.to_html +# +# By default, RedCloth uses both Textile and Markdown formatting, with +# Textile formatting taking precedence. If you want to turn off Markdown +# formatting, to boost speed and limit the processor: +# +# class RedCloth::Textile.new( str ) + +class RedCloth3 < String + + VERSION = '3.0.4' + DEFAULT_RULES = [:textile, :markdown] + + # + # Two accessor for setting security restrictions. + # + # This is a nice thing if you're using RedCloth for + # formatting in public places (e.g. Wikis) where you + # don't want users to abuse HTML for bad things. + # + # If +:filter_html+ is set, HTML which wasn't + # created by the Textile processor will be escaped. + # + # If +:filter_styles+ is set, it will also disable + # the style markup specifier. ('{color: red}') + # + attr_accessor :filter_html, :filter_styles + + # + # Accessor for toggling hard breaks. + # + # If +:hard_breaks+ is set, single newlines will + # be converted to HTML break tags. This is the + # default behavior for traditional RedCloth. + # + attr_accessor :hard_breaks + + # Accessor for toggling lite mode. + # + # In lite mode, block-level rules are ignored. This means + # that tables, paragraphs, lists, and such aren't available. + # Only the inline markup for bold, italics, entities and so on. + # + # r = RedCloth.new( "And then? She *fell*!", [:lite_mode] ) + # r.to_html + # #=> "And then? She fell!" + # + attr_accessor :lite_mode + + # + # Accessor for toggling span caps. + # + # Textile places `span' tags around capitalized + # words by default, but this wreaks havoc on Wikis. + # If +:no_span_caps+ is set, this will be + # suppressed. + # + attr_accessor :no_span_caps + + # + # Establishes the markup predence. Available rules include: + # + # == Textile Rules + # + # The following textile rules can be set individually. Or add the complete + # set of rules with the single :textile rule, which supplies the rule set in + # the following precedence: + # + # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/) + # block_textile_table:: Textile table block structures + # block_textile_lists:: Textile list structures + # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.) + # inline_textile_image:: Textile inline images + # inline_textile_link:: Textile inline links + # inline_textile_span:: Textile inline spans + # glyphs_textile:: Textile entities (such as em-dashes and smart quotes) + # + # == Markdown + # + # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/) + # block_markdown_setext:: Markdown setext headers + # block_markdown_atx:: Markdown atx headers + # block_markdown_rule:: Markdown horizontal rules + # block_markdown_bq:: Markdown blockquotes + # block_markdown_lists:: Markdown lists + # inline_markdown_link:: Markdown links + attr_accessor :rules + + # Returns a new RedCloth object, based on _string_ and + # enforcing all the included _restrictions_. + # + # r = RedCloth.new( "h1. A bold man", [:filter_html] ) + # r.to_html + # #=>"

    A <b>bold</b> man

    " + # + def initialize( string, restrictions = [] ) + restrictions.each { |r| method( "#{ r }=" ).call( true ) } + super( string ) + end + + # + # Generates HTML from the Textile contents. + # + # r = RedCloth.new( "And then? She *fell*!" ) + # r.to_html( true ) + # #=>"And then? She fell!" + # + def to_html( *rules ) + rules = DEFAULT_RULES if rules.empty? + # make our working copy + text = self.dup + + @urlrefs = {} + @shelf = [] + textile_rules = [:block_textile_table, :block_textile_lists, + :block_textile_prefix, :inline_textile_image, :inline_textile_link, + :inline_textile_code, :inline_textile_span, :glyphs_textile] + markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule, + :block_markdown_bq, :block_markdown_lists, + :inline_markdown_reflink, :inline_markdown_link] + @rules = rules.collect do |rule| + case rule + when :markdown + markdown_rules + when :textile + textile_rules + else + rule + end + end.flatten + + # standard clean up + incoming_entities text + clean_white_space text + + # start processor + @pre_list = [] + rip_offtags text + no_textile text + escape_html_tags text + # need to do this before #hard_break and #blocks + block_textile_quotes text unless @lite_mode + hard_break text + unless @lite_mode + refs text + blocks text + end + inline text + smooth_offtags text + + retrieve text + + text.gsub!( /<\/?notextile>/, '' ) + text.gsub!( /x%x%/, '&' ) + clean_html text if filter_html + text.strip! + text + + end + + ####### + private + ####### + # + # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents. + # (from PyTextile) + # + TEXTILE_TAGS = + + [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230], + [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249], + [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217], + [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732], + [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]]. + + collect! do |a, b| + [a.chr, ( b.zero? and "" or "&#{ b };" )] + end + + # + # Regular expressions to convert to HTML. + # + A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/ + A_VLGN = /[\-^~]/ + C_CLAS = '(?:\([^")]+\))' + C_LNGE = '(?:\[[^"\[\]]+\])' + C_STYL = '(?:\{[^"}]+\})' + S_CSPN = '(?:\\\\\d+)' + S_RSPN = '(?:/\d+)' + A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)" + S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)" + C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)" + # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ) + PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' ) + PUNCT_NOQ = Regexp::quote( '!"#$&\',./:;=?@\\`|' ) + PUNCT_Q = Regexp::quote( '*-_+^~%' ) + HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)' + + # Text markup tags, don't conflict with block tags + SIMPLE_HTML_TAGS = [ + 'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code', + 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br', + 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo' + ] + + QTAGS = [ + ['**', 'b', :limit], + ['*', 'strong', :limit], + ['??', 'cite', :limit], + ['-', 'del', :limit], + ['__', 'i', :limit], + ['_', 'em', :limit], + ['%', 'span', :limit], + ['+', 'ins', :limit], + ['^', 'sup', :limit], + ['~', 'sub', :limit] + ] + QTAGS_JOIN = QTAGS.map {|rc, ht, rtype| Regexp::quote rc}.join('|') + + QTAGS.collect! do |rc, ht, rtype| + rcq = Regexp::quote rc + re = + case rtype + when :limit + /(^|[>\s\(]) # sta + (?!\-\-) + (#{QTAGS_JOIN}|) # oqs + (#{rcq}) # qtag + (\w|[^\s].*?[^\s]) # content + (?!\-\-) + #{rcq} + (#{QTAGS_JOIN}|) # oqa + (?=[[:punct:]]|<|\s|\)|$)/x + else + /(#{rcq}) + (#{C}) + (?::(\S+))? + (\w|[^\s\-].*?[^\s\-]) + #{rcq}/xm + end + [rc, ht, re, rtype] + end + + # Elements to handle + GLYPHS = [ + # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1’\2' ], # single closing + # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1’' ], # single closing + # [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '’' ], # single closing + # [ /\'/, '‘' ], # single opening + # [ //, '>' ], # greater-than + # [ /([^\s\[{(])?"(\s|:|$)/, '\1”\2' ], # double closing + # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1”' ], # double closing + # [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '”' ], # double closing + # [ /"/, '“' ], # double opening + # [ /\b( )?\.{3}/, '\1…' ], # ellipsis + # [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '\1' ], # 3+ uppercase acronym + # [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^\2\3', :no_span_caps ], # 3+ uppercase caps + # [ /(\.\s)?\s?--\s?/, '\1—' ], # em dash + # [ /\s->\s/, ' → ' ], # right arrow + # [ /\s-\s/, ' – ' ], # en dash + # [ /(\d+) ?x ?(\d+)/, '\1×\2' ], # dimension sign + # [ /\b ?[(\[]TM[\])]/i, '™' ], # trademark + # [ /\b ?[(\[]R[\])]/i, '®' ], # registered + # [ /\b ?[(\[]C[\])]/i, '©' ] # copyright + ] + + H_ALGN_VALS = { + '<' => 'left', + '=' => 'center', + '>' => 'right', + '<>' => 'justify' + } + + V_ALGN_VALS = { + '^' => 'top', + '-' => 'middle', + '~' => 'bottom' + } + + # + # Flexible HTML escaping + # + def htmlesc( str, mode=:Quotes ) + if str + str.gsub!( '&', '&' ) + str.gsub!( '"', '"' ) if mode != :NoQuotes + str.gsub!( "'", ''' ) if mode == :Quotes + str.gsub!( '<', '<') + str.gsub!( '>', '>') + end + str + end + + # Search and replace for Textile glyphs (quotes, dashes, other symbols) + def pgl( text ) + #GLYPHS.each do |re, resub, tog| + # next if tog and method( tog ).call + # text.gsub! re, resub + #end + text.gsub!(/\b([A-Z][A-Z0-9]{1,})\b(?:[(]([^)]*)[)])/) do |m| + "#{$1}" + end + end + + # Parses Textile attribute lists and builds an HTML attribute string + def pba( text_in, element = "" ) + + return '' unless text_in + + style = [] + text = text_in.dup + if element == 'td' + colspan = $1 if text =~ /\\(\d+)/ + rowspan = $1 if text =~ /\/(\d+)/ + style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN + end + + style << "#{ htmlesc $1 };" if text.sub!( /\{([^}]*)\}/, '' ) && !filter_styles + + lang = $1 if + text.sub!( /\[([^)]+?)\]/, '' ) + + cls = $1 if + text.sub!( /\(([^()]+?)\)/, '' ) + + style << "padding-left:#{ $1.length }em;" if + text.sub!( /([(]+)/, '' ) + + style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' ) + + style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN + + cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/ + + atts = '' + atts << " style=\"#{ style.join }\"" unless style.empty? + atts << " class=\"#{ cls }\"" unless cls.to_s.empty? + atts << " lang=\"#{ lang }\"" if lang + atts << " id=\"#{ id }\"" if id + atts << " colspan=\"#{ colspan }\"" if colspan + atts << " rowspan=\"#{ rowspan }\"" if rowspan + + atts + end + + TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m + + # Parses a Textile table block, building HTML from the result. + def block_textile_table( text ) + text.gsub!( TABLE_RE ) do |matches| + + tatts, fullrow = $~[1..2] + tatts = pba( tatts, 'table' ) + tatts = shelve( tatts ) if tatts + rows = [] + + fullrow.each_line do |row| + ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m + cells = [] + row.split( /(\|)(?![^\[\|]*\]\])/ )[1..-2].each do |cell| + next if cell == '|' + ctyp = 'd' + ctyp = 'h' if cell =~ /^_/ + + catts = '' + catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/ + + catts = shelve( catts ) if catts + cells << "\t\t\t#{ cell }" + end + ratts = shelve( ratts ) if ratts + rows << "\t\t\n#{ cells.join( "\n" ) }\n\t\t" + end + "\t\n#{ rows.join( "\n" ) }\n\t\n\n" + end + end + + LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m + LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m + + # Parses Textile lists and generates HTML + def block_textile_lists( text ) + text.gsub!( LISTS_RE ) do |match| + lines = match.split( /\n/ ) + last_line = -1 + depth = [] + lines.each_with_index do |line, line_id| + if line =~ LISTS_CONTENT_RE + tl,atts,content = $~[1..3] + if depth.last + if depth.last.length > tl.length + (depth.length - 1).downto(0) do |i| + break if depth[i].length == tl.length + lines[line_id - 1] << "\n\t\n\t" + depth.pop + end + end + if depth.last and depth.last.length == tl.length + lines[line_id - 1] << '' + end + end + unless depth.last == tl + depth << tl + atts = pba( atts ) + atts = shelve( atts ) if atts + lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t
  • #{ content }" + else + lines[line_id] = "\t\t
  • #{ content }" + end + last_line = line_id + + else + last_line = line_id + end + if line_id - last_line > 1 or line_id == lines.length - 1 + depth.delete_if do |v| + lines[last_line] << "
  • \n\t" + end + end + end + lines.join( "\n" ) + end + end + + QUOTES_RE = /(^>+([^\n]*?)(\n|$))+/m + QUOTES_CONTENT_RE = /^([> ]+)(.*)$/m + + def block_textile_quotes( text ) + text.gsub!( QUOTES_RE ) do |match| + lines = match.split( /\n/ ) + quotes = '' + indent = 0 + lines.each do |line| + line =~ QUOTES_CONTENT_RE + bq,content = $1, $2 + l = bq.count('>') + if l != indent + quotes << ("\n\n" + (l>indent ? '
    ' * (l-indent) : '
    ' * (indent-l)) + "\n\n") + indent = l + end + quotes << (content + "\n") + end + quotes << ("\n" + '' * indent + "\n\n") + quotes + end + end + + CODE_RE = /(\W) + @ + (?:\|(\w+?)\|)? + (.+?) + @ + (?=\W)/x + + def inline_textile_code( text ) + text.gsub!( CODE_RE ) do |m| + before,lang,code,after = $~[1..4] + lang = " lang=\"#{ lang }\"" if lang + rip_offtags( "#{ before }#{ code }
    #{ after }", false ) + end + end + + def lT( text ) + text =~ /\#$/ ? 'o' : 'u' + end + + def hard_break( text ) + text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1
    " ) if hard_breaks + end + + BLOCKS_GROUP_RE = /\n{2,}(?! )/m + + def blocks( text, deep_code = false ) + text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk| + plain = blk !~ /\A[#*> ]/ + + # skip blocks that are complex HTML + if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1 + blk + else + # search for indentation levels + blk.strip! + if blk.empty? + blk + else + code_blk = nil + blk.gsub!( /((?:\n(?:\n^ +[^\n]*)+)+)/m ) do |iblk| + flush_left iblk + blocks iblk, plain + iblk.gsub( /^(\S)/, "\t\\1" ) + if plain + code_blk = iblk; "" + else + iblk + end + end + + block_applied = 0 + @rules.each do |rule_name| + block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) ) + end + if block_applied.zero? + if deep_code + blk = "\t
    #{ blk }
    " + else + blk = "\t

    #{ blk }

    " + end + end + # hard_break blk + blk + "\n#{ code_blk }" + end + end + + end.join( "\n\n" ) ) + end + + def textile_bq( tag, atts, cite, content ) + cite, cite_title = check_refs( cite ) + cite = " cite=\"#{ cite }\"" if cite + atts = shelve( atts ) if atts + "\t\n\t\t#{ content }

    \n\t" + end + + def textile_p( tag, atts, cite, content ) + atts = shelve( atts ) if atts + "\t<#{ tag }#{ atts }>#{ content }" + end + + alias textile_h1 textile_p + alias textile_h2 textile_p + alias textile_h3 textile_p + alias textile_h4 textile_p + alias textile_h5 textile_p + alias textile_h6 textile_p + + def textile_fn_( tag, num, atts, cite, content ) + atts << " id=\"fn#{ num }\" class=\"footnote\"" + content = "#{ num } #{ content }" + atts = shelve( atts ) if atts + "\t#{ content }

    " + end + + BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m + + def block_textile_prefix( text ) + if text =~ BLOCK_RE + tag,tagpre,num,atts,cite,content = $~[1..6] + atts = pba( atts ) + + # pass to prefix handler + replacement = nil + if respond_to? "textile_#{ tag }", true + replacement = method( "textile_#{ tag }" ).call( tag, atts, cite, content ) + elsif respond_to? "textile_#{ tagpre }_", true + replacement = method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) + end + text.gsub!( $& ) { replacement } if replacement + end + end + + SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m + def block_markdown_setext( text ) + if text =~ SETEXT_RE + tag = if $2 == "="; "h1"; else; "h2"; end + blk, cont = "<#{ tag }>#{ $1 }", $' + blocks cont + text.replace( blk + cont ) + end + end + + ATX_RE = /\A(\#{1,6}) # $1 = string of #'s + [ ]* + (.+?) # $2 = Header text + [ ]* + \#* # optional closing #'s (not counted) + $/x + def block_markdown_atx( text ) + if text =~ ATX_RE + tag = "h#{ $1.length }" + blk, cont = "<#{ tag }>#{ $2 }\n\n", $' + blocks cont + text.replace( blk + cont ) + end + end + + MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m + + def block_markdown_bq( text ) + text.gsub!( MARKDOWN_BQ_RE ) do |blk| + blk.gsub!( /^ *> ?/, '' ) + flush_left blk + blocks blk + blk.gsub!( /^(\S)/, "\t\\1" ) + "
    \n#{ blk }\n
    \n\n" + end + end + + MARKDOWN_RULE_RE = /^(#{ + ['*', '-', '_'].collect { |ch| ' ?(' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' ) + })$/ + + def block_markdown_rule( text ) + text.gsub!( MARKDOWN_RULE_RE ) do |blk| + "
    " + end + end + + # XXX TODO XXX + def block_markdown_lists( text ) + end + + def inline_textile_span( text ) + QTAGS.each do |qtag_rc, ht, qtag_re, rtype| + text.gsub!( qtag_re ) do |m| + + case rtype + when :limit + sta,oqs,qtag,content,oqa = $~[1..6] + atts = nil + if content =~ /^(#{C})(.+)$/ + atts, content = $~[1..2] + end + else + qtag,atts,cite,content = $~[1..4] + sta = '' + end + atts = pba( atts ) + atts = shelve( atts ) if atts + + "#{ sta }#{ oqs }<#{ ht }#{ atts }>#{ content }#{ oqa }" + + end + end + end + + LINK_RE = / + ( + ([\s\[{(]|[#{PUNCT}])? # $pre + " # start + (#{C}) # $atts + ([^"\n]+?) # $text + \s? + (?:\(([^)]+?)\)(?="))? # $title + ": + ( # $url + (\/|[a-zA-Z]+:\/\/|www\.|mailto:) # $proto + [\w\/]\S+? + ) + (\/)? # $slash + ([^\w\=\/;\(\)]*?) # $post + ) + (?=<|\s|$) + /x +#" + def inline_textile_link( text ) + text.gsub!( LINK_RE ) do |m| + all,pre,atts,text,title,url,proto,slash,post = $~[1..9] + if text.include?('
    ') + all + else + url, url_title = check_refs( url ) + title ||= url_title + + # Idea below : an URL with unbalanced parethesis and + # ending by ')' is put into external parenthesis + if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) + url=url[0..-2] # discard closing parenth from url + post = ")"+post # add closing parenth to post + end + atts = pba( atts ) + atts = " href=\"#{ htmlesc url }#{ slash }\"#{ atts }" + atts << " title=\"#{ htmlesc title }\"" if title + atts = shelve( atts ) if atts + + external = (url =~ /^https?:\/\//) ? ' class="external"' : '' + + "#{ pre }#{ text }#{ post }" + end + end + end + + MARKDOWN_REFLINK_RE = / + \[([^\[\]]+)\] # $text + [ ]? # opt. space + (?:\n[ ]*)? # one optional newline followed by spaces + \[(.*?)\] # $id + /x + + def inline_markdown_reflink( text ) + text.gsub!( MARKDOWN_REFLINK_RE ) do |m| + text, id = $~[1..2] + + if id.empty? + url, title = check_refs( text ) + else + url, title = check_refs( id ) + end + + atts = " href=\"#{ url }\"" + atts << " title=\"#{ title }\"" if title + atts = shelve( atts ) + + "#{ text }" + end + end + + MARKDOWN_LINK_RE = / + \[([^\[\]]+)\] # $text + \( # open paren + [ \t]* # opt space + ? # $href + [ \t]* # opt space + (?: # whole title + (['"]) # $quote + (.*?) # $title + \3 # matching quote + )? # title is optional + \) + /x + + def inline_markdown_link( text ) + text.gsub!( MARKDOWN_LINK_RE ) do |m| + text, url, quote, title = $~[1..4] + + atts = " href=\"#{ url }\"" + atts << " title=\"#{ title }\"" if title + atts = shelve( atts ) + + "#{ text }" + end + end + + TEXTILE_REFS_RE = /(^ *)\[([^\[\n]+?)\](#{HYPERLINK})(?=\s|$)/ + MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m + + def refs( text ) + @rules.each do |rule_name| + method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/ + end + end + + def refs_textile( text ) + text.gsub!( TEXTILE_REFS_RE ) do |m| + flag, url = $~[2..3] + @urlrefs[flag.downcase] = [url, nil] + nil + end + end + + def refs_markdown( text ) + text.gsub!( MARKDOWN_REFS_RE ) do |m| + flag, url = $~[2..3] + title = $~[6] + @urlrefs[flag.downcase] = [url, title] + nil + end + end + + def check_refs( text ) + ret = @urlrefs[text.downcase] if text + ret || [text, nil] + end + + IMAGE_RE = / + (>|\s|^) # start of line? + \! # opening + (\<|\=|\>)? # optional alignment atts + (#{C}) # optional style,class atts + (?:\. )? # optional dot-space + ([^\s(!]+?) # presume this is the src + \s? # optional space + (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title + \! # closing + (?::#{ HYPERLINK })? # optional href + /x + + def inline_textile_image( text ) + text.gsub!( IMAGE_RE ) do |m| + stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8] + htmlesc title + atts = pba( atts ) + atts = " src=\"#{ htmlesc url.dup }\"#{ atts }" + atts << " title=\"#{ title }\"" if title + atts << " alt=\"#{ title }\"" + # size = @getimagesize($url); + # if($size) $atts.= " $size[3]"; + + href, alt_title = check_refs( href ) if href + url, url_title = check_refs( url ) + + out = '' + out << "" if href + out << "" + out << "#{ href_a1 }#{ href_a2 }" if href + + if algn + algn = h_align( algn ) + if stln == "

    " + out = "

    #{ out }" + else + out = "#{ stln }

    #{ out }
    " + end + else + out = stln + out + end + + out + end + end + + def shelve( val ) + @shelf << val + " :redsh##{ @shelf.length }:" + end + + def retrieve( text ) + @shelf.each_with_index do |r, i| + text.gsub!( " :redsh##{ i + 1 }:", r ) + end + end + + def incoming_entities( text ) + ## turn any incoming ampersands into a dummy character for now. + ## This uses a negative lookahead for alphanumerics followed by a semicolon, + ## implying an incoming html entity, to be skipped + + text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" ) + end + + def no_textile( text ) + text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/, + '\1\2\3' ) + text.gsub!( /^ *==([^=]+.*?)==/m, + '\1\2\3' ) + end + + def clean_white_space( text ) + # normalize line breaks + text.gsub!( /\r\n/, "\n" ) + text.gsub!( /\r/, "\n" ) + text.gsub!( /\t/, ' ' ) + text.gsub!( /^ +$/, '' ) + text.gsub!( /\n{3,}/, "\n\n" ) + text.gsub!( /"$/, "\" " ) + + # if entire document is indented, flush + # to the left side + flush_left text + end + + def flush_left( text ) + indt = 0 + if text =~ /^ / + while text !~ /^ {#{indt}}\S/ + indt += 1 + end unless text.empty? + if indt.nonzero? + text.gsub!( /^ {#{indt}}/, '' ) + end + end + end + + def footnote_ref( text ) + text.gsub!( /\b\[([0-9]+?)\](\s)?/, + '\1\2' ) + end + + OFFTAGS = /(code|pre|kbd|notextile)/ + OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\W|\Z)/mi + OFFTAG_OPEN = /<#{ OFFTAGS }/ + OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/ + HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m + ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m + + def glyphs_textile( text, level = 0 ) + if text !~ HASTAG_MATCH + pgl text + footnote_ref text + else + codepre = 0 + text.gsub!( ALLTAG_MATCH ) do |line| + ## matches are off if we're between ,
     etc.
    +                if $1
    +                    if line =~ OFFTAG_OPEN
    +                        codepre += 1
    +                    elsif line =~ OFFTAG_CLOSE
    +                        codepre -= 1
    +                        codepre = 0 if codepre < 0
    +                    end 
    +                elsif codepre.zero?
    +                    glyphs_textile( line, level + 1 )
    +                else
    +                    htmlesc( line, :NoQuotes )
    +                end
    +                # p [level, codepre, line]
    +
    +                line
    +            end
    +        end
    +    end
    +
    +    def rip_offtags( text, escape_aftertag=true, escape_line=true )
    +        if text =~ /<.*>/
    +            ## strip and encode 
     content
    +            codepre, used_offtags = 0, {}
    +            text.gsub!( OFFTAG_MATCH ) do |line|
    +                if $3
    +                    first, offtag, aftertag = $3, $4, $5
    +                    codepre += 1
    +                    used_offtags[offtag] = true
    +                    if codepre - used_offtags.length > 0
    +                        htmlesc( line, :NoQuotes ) if escape_line
    +                        @pre_list.last << line
    +                        line = ""
    +                    else
    +                        ### htmlesc is disabled between CODE tags which will be parsed with highlighter
    +                        ### Regexp in formatter.rb is : /\s?(.+)/m
    +                        ### NB: some changes were made not to use $N variables, because we use "match"
    +                        ###   and it breaks following lines
    +                        htmlesc( aftertag, :NoQuotes ) if aftertag && escape_aftertag && !first.match(//)
    +                        line = ""
    +                        first.match(/<#{ OFFTAGS }([^>]*)>/)
    +                        tag = $1
    +                        $2.to_s.match(/(class\=("[^"]+"|'[^']+'))/i)
    +                        tag << " #{$1}" if $1
    +                        @pre_list << "<#{ tag }>#{ aftertag }"
    +                    end
    +                elsif $1 and codepre > 0
    +                    if codepre - used_offtags.length > 0
    +                        htmlesc( line, :NoQuotes ) if escape_line
    +                        @pre_list.last << line
    +                        line = ""
    +                    end
    +                    codepre -= 1 unless codepre.zero?
    +                    used_offtags = {} if codepre.zero?
    +                end 
    +                line
    +            end
    +        end
    +        text
    +    end
    +
    +    def smooth_offtags( text )
    +        unless @pre_list.empty?
    +            ## replace 
     content
    +            text.gsub!( // ) { @pre_list[$1.to_i] }
    +        end
    +    end
    +
    +    def inline( text ) 
    +        [/^inline_/, /^glyphs_/].each do |meth_re|
    +            @rules.each do |rule_name|
    +                method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
    +            end
    +        end
    +    end
    +
    +    def h_align( text ) 
    +        H_ALGN_VALS[text]
    +    end
    +
    +    def v_align( text ) 
    +        V_ALGN_VALS[text]
    +    end
    +
    +    def textile_popup_help( name, windowW, windowH )
    +        ' ' + name + '
    ' + end + + # HTML cleansing stuff + BASIC_TAGS = { + 'a' => ['href', 'title'], + 'img' => ['src', 'alt', 'title'], + 'br' => [], + 'i' => nil, + 'u' => nil, + 'b' => nil, + 'pre' => nil, + 'kbd' => nil, + 'code' => ['lang'], + 'cite' => nil, + 'strong' => nil, + 'em' => nil, + 'ins' => nil, + 'sup' => nil, + 'sub' => nil, + 'del' => nil, + 'table' => nil, + 'tr' => nil, + 'td' => ['colspan', 'rowspan'], + 'th' => nil, + 'ol' => nil, + 'ul' => nil, + 'li' => nil, + 'p' => nil, + 'h1' => nil, + 'h2' => nil, + 'h3' => nil, + 'h4' => nil, + 'h5' => nil, + 'h6' => nil, + 'blockquote' => ['cite'] + } + + def clean_html( text, tags = BASIC_TAGS ) + text.gsub!( /]*)>/ ) do + raw = $~ + tag = raw[2].downcase + if tags.has_key? tag + pcs = [tag] + tags[tag].each do |prop| + ['"', "'", ''].each do |q| + q2 = ( q != '' ? q : '\s' ) + if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i + attrv = $1 + next if prop == 'src' and attrv =~ %r{^(?!http)\w+:} + pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\"" + break + end + end + end if tags[tag] + "<#{raw[1]}#{pcs.join " "}>" + else + " " + end + end + end + + ALLOWED_TAGS = %w(redpre pre code notextile) + + def escape_html_tags(text) + text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "<#{$1}#{'>' unless $3.blank?}" } + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/8150bf5b8c067659e615bbcb4f9a5a40975b2bf9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/8150bf5b8c067659e615bbcb4f9a5a40975b2bf9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class Comment < ActiveRecord::Base + generator_for :commented, :method => :generate_news + generator_for :author, :method => :generate_author + generator_for :comments => 'What great news this is.' + + def self.generate_news + News.generate! + end + + def self.generate_author + User.generate_with_protected! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/8152a8429a670810e05571a0d05bddd66f5b7e5e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/8152a8429a670810e05571a0d05bddd66f5b7e5e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class PatchesTest < ActiveSupport::TestCase + include Redmine::I18n + + context "ActiveRecord::Base.human_attribute_name" do + setup do + Setting.default_language = 'en' + end + + should "transform name to field_name" do + assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on') + end + + should "cut extra _id suffix for better validation" do + assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on_id') + end + + should "default to humanized value if no translation has been found (useful for custom fields)" do + assert_equal 'Patch name', ActiveRecord::Base.human_attribute_name('Patch name') + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/81cb96f62c8cc353a52d33b9c57cb4b041ddf07c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/81cb96f62c8cc353a52d33b9c57cb4b041ddf07c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +class AddActivityIndexes < ActiveRecord::Migration + def self.up + add_index :journals, :created_on + add_index :changesets, :committed_on + add_index :wiki_content_versions, :updated_on + add_index :messages, :created_on + add_index :issues, :created_on + add_index :news, :created_on + add_index :attachments, :created_on + add_index :documents, :created_on + add_index :time_entries, :created_on + end + + def self.down + remove_index :journals, :created_on + remove_index :changesets, :committed_on + remove_index :wiki_content_versions, :updated_on + remove_index :messages, :created_on + remove_index :issues, :created_on + remove_index :news, :created_on + remove_index :attachments, :created_on + remove_index :documents, :created_on + remove_index :time_entries, :created_on + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/81cd3726ba1b626ac8fe2e786c213679ee3b4319.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/81/81cd3726ba1b626ac8fe2e786c213679ee3b4319.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +module CodeRay +module Scanners + + map \ + :'c++' => :cpp, + :cplusplus => :cpp, + :ecmascript => :java_script, + :ecma_script => :java_script, + :rhtml => :erb, + :eruby => :erb, + :irb => :ruby, + :javascript => :java_script, + :js => :java_script, + :pascal => :delphi, + :patch => :diff, + :plain => :text, + :plaintext => :text, + :xhtml => :html, + :yml => :yaml + + default :text + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/81/81f83a1cebed98b499cc092f78bbc68f144688da.svn-base Binary file .svn/pristine/81/81f83a1cebed98b499cc092f78bbc68f144688da.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/822b75d0bb3697ed3dee9071dcf61cf8a7528ac2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/822b75d0bb3697ed3dee9071dcf61cf8a7528ac2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,168 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class MessageTest < ActiveSupport::TestCase + fixtures :projects, :roles, :members, :member_roles, :boards, :messages, :users, :watchers + + def setup + @board = Board.find(1) + @user = User.find(1) + end + + def test_create + topics_count = @board.topics_count + messages_count = @board.messages_count + + message = Message.new(:board => @board, :subject => 'Test message', + :content => 'Test message content', + :author => @user) + assert message.save + @board.reload + # topics count incremented + assert_equal topics_count+1, @board[:topics_count] + # messages count incremented + assert_equal messages_count+1, @board[:messages_count] + assert_equal message, @board.last_message + # author should be watching the message + assert message.watched_by?(@user) + end + + def test_reply + topics_count = @board.topics_count + messages_count = @board.messages_count + @message = Message.find(1) + replies_count = @message.replies_count + + reply_author = User.find(2) + reply = Message.new(:board => @board, :subject => 'Test reply', + :content => 'Test reply content', + :parent => @message, :author => reply_author) + assert reply.save + @board.reload + # same topics count + assert_equal topics_count, @board[:topics_count] + # messages count incremented + assert_equal messages_count+1, @board[:messages_count] + assert_equal reply, @board.last_message + @message.reload + # replies count incremented + assert_equal replies_count+1, @message[:replies_count] + assert_equal reply, @message.last_reply + # author should be watching the message + assert @message.watched_by?(reply_author) + end + + def test_cannot_reply_to_locked_topic + topics_count = @board.topics_count + messages_count = @board.messages_count + @message = Message.find(1) + replies_count = @message.replies_count + assert_equal false, @message.locked + @message.locked = true + assert @message.save + assert_equal true, @message.locked + + reply_author = User.find(2) + reply = Message.new(:board => @board, :subject => 'Test reply', + :content => 'Test reply content', + :parent => @message, :author => reply_author) + reply.save + assert_equal 1, reply.errors.count + end + + def test_moving_message_should_update_counters + @message = Message.find(1) + assert_no_difference 'Message.count' do + # Previous board + assert_difference 'Board.find(1).topics_count', -1 do + assert_difference 'Board.find(1).messages_count', -(1 + @message.replies_count) do + # New board + assert_difference 'Board.find(2).topics_count' do + assert_difference 'Board.find(2).messages_count', (1 + @message.replies_count) do + @message.update_attributes(:board_id => 2) + end + end + end + end + end + end + + def test_destroy_topic + message = Message.find(1) + board = message.board + topics_count, messages_count = board.topics_count, board.messages_count + + assert_difference('Watcher.count', -1) do + assert message.destroy + end + board.reload + + # Replies deleted + assert Message.find_all_by_parent_id(1).empty? + # Checks counters + assert_equal topics_count - 1, board.topics_count + assert_equal messages_count - 3, board.messages_count + # Watchers removed + end + + def test_destroy_reply + message = Message.find(5) + board = message.board + topics_count, messages_count = board.topics_count, board.messages_count + assert message.destroy + board.reload + + # Checks counters + assert_equal topics_count, board.topics_count + assert_equal messages_count - 1, board.messages_count + end + + def test_editable_by + message = Message.find(6) + author = message.author + assert message.editable_by?(author) + + author.roles_for_project(message.project).first.remove_permission!(:edit_own_messages) + assert !message.reload.editable_by?(author.reload) + end + + def test_destroyable_by + message = Message.find(6) + author = message.author + assert message.destroyable_by?(author) + + author.roles_for_project(message.project).first.remove_permission!(:delete_own_messages) + assert !message.reload.destroyable_by?(author.reload) + end + + def test_set_sticky + message = Message.new + assert_equal 0, message.sticky + message.sticky = nil + assert_equal 0, message.sticky + message.sticky = false + assert_equal 0, message.sticky + message.sticky = true + assert_equal 1, message.sticky + message.sticky = '0' + assert_equal 0, message.sticky + message.sticky = '1' + assert_equal 1, message.sticky + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/822bd4e2a61e465d85fbdf504efa2d28cd338bc1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/822bd4e2a61e465d85fbdf504efa2d28cd338bc1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+013D Lcaron +!A6 U+015A Sacute +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+015E Scedilla +!AB U+0164 Tcaron +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+013E lcaron +!B6 U+015B sacute +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+015F scedilla +!BB U+0165 tcaron +!BC U+017A zacute +!BD U+02DD hungarumlaut +!BE U+017E zcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/82372cb9f2f842cdf3c8af6fb5cd931421234560.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/82372cb9f2f842cdf3c8af6fb5cd931421234560.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddWikiPagesParentId < ActiveRecord::Migration + def self.up + add_column :wiki_pages, :parent_id, :integer, :default => nil + end + + def self.down + remove_column :wiki_pages, :parent_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/8291420c5b3c01d90eab90ab6db0630cf31b5fe0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/8291420c5b3c01d90eab90ab6db0630cf31b5fe0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1012 @@ +# Update to 1.1 by Michal Gebauer +# Updated by Josef Liška +# CZ translation by Maxim Krušina | Massimo Filippi, s.r.o. | maxim@mxm.cz +# Based on original CZ translation by Jan Kadleček +cs: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Neděle, Pondělí, Úterý, Středa, Čtvrtek, Pátek, Sobota] + abbr_day_names: [Ne, Po, Út, St, Čt, Pá, So] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Leden, Únor, Březen, Duben, Květen, Červen, Červenec, Srpen, Září, Říjen, Listopad, Prosinec] + abbr_month_names: [~, Led, Úno, Bře, Dub, Kvě, Čer, Čec, Srp, Zář, Říj, Lis, Pro] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "dop." + pm: "odp." + + datetime: + distance_in_words: + half_a_minute: "půl minuty" + less_than_x_seconds: + one: "méně než sekunda" + other: "méně než %{count} sekund" + x_seconds: + one: "1 sekunda" + other: "%{count} sekund" + less_than_x_minutes: + one: "méně než minuta" + other: "méně než %{count} minut" + x_minutes: + one: "1 minuta" + other: "%{count} minut" + about_x_hours: + one: "asi 1 hodina" + other: "asi %{count} hodin" + x_days: + one: "1 den" + other: "%{count} dnů" + about_x_months: + one: "asi 1 měsíc" + other: "asi %{count} měsíců" + x_months: + one: "1 měsíc" + other: "%{count} měsíců" + about_x_years: + one: "asi 1 rok" + other: "asi %{count} let" + over_x_years: + one: "více než 1 rok" + other: "více než %{count} roky" + almost_x_years: + one: "témeř 1 rok" + other: "téměř %{count} roky" + + number: + # Výchozí formát pro čísla + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Bajt" + other: "Bajtů" + kb: "kB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "a" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 chyba zabránila uložení %{model}" + other: "%{count} chyb zabránilo uložení %{model}" + messages: + inclusion: "není zahrnuto v seznamu" + exclusion: "je rezervováno" + invalid: "je neplatné" + confirmation: "se neshoduje s potvrzením" + accepted: "musí být akceptováno" + empty: "nemůže být prázdný" + blank: "nemůže být prázdný" + too_long: "je příliš dlouhý" + too_short: "je příliš krátký" + wrong_length: "má chybnou délku" + taken: "je již použito" + not_a_number: "není číslo" + not_a_date: "není platné datum" + greater_than: "musí být větší než %{count}" + greater_than_or_equal_to: "musí být větší nebo rovno %{count}" + equal_to: "musí být přesně %{count}" + less_than: "musí být méně než %{count}" + less_than_or_equal_to: "musí být méně nebo rovno %{count}" + odd: "musí být liché" + even: "musí být sudé" + greater_than_start_date: "musí být větší než počáteční datum" + not_same_project: "nepatří stejnému projektu" + circular_dependency: "Tento vztah by vytvořil cyklickou závislost" + cant_link_an_issue_with_a_descendant: "Úkol nemůže být spojen s jedním z jeho dílčích úkolů" + + actionview_instancetag_blank_option: Prosím vyberte + + general_text_No: 'Ne' + general_text_Yes: 'Ano' + general_text_no: 'ne' + general_text_yes: 'ano' + general_lang_name: 'Čeština' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Účet byl úspěšně změněn. + notice_account_invalid_creditentials: Chybné jméno nebo heslo + notice_account_password_updated: Heslo bylo úspěšně změněno. + notice_account_wrong_password: Chybné heslo + notice_account_register_done: Účet byl úspěšně vytvořen. Pro aktivaci účtu klikněte na odkaz v emailu, který vám byl zaslán. + notice_account_unknown_email: Neznámý uživatel. + notice_can_t_change_password: Tento účet používá externí autentifikaci. Zde heslo změnit nemůžete. + notice_account_lost_email_sent: Byl vám zaslán email s intrukcemi jak si nastavíte nové heslo. + notice_account_activated: Váš účet byl aktivován. Nyní se můžete přihlásit. + notice_successful_create: Úspěšně vytvořeno. + notice_successful_update: Úspěšně aktualizováno. + notice_successful_delete: Úspěšně odstraněno. + notice_successful_connection: Úspěšné připojení. + notice_file_not_found: Stránka na kterou se snažíte zobrazit neexistuje nebo byla smazána. + notice_locking_conflict: Údaje byly změněny jiným uživatelem. + notice_not_authorized: Nemáte dostatečná práva pro zobrazení této stránky. + notice_not_authorized_archived_project: Projekt ke kterému se snažíte přistupovat byl archivován. + notice_email_sent: "Na adresu %{value} byl odeslán email" + notice_email_error: "Při odesílání emailu nastala chyba (%{value})" + notice_feeds_access_key_reseted: Váš klíč pro přístup k RSS byl resetován. + notice_api_access_key_reseted: Váš API přístupový klíč byl resetován. + notice_failed_to_save_issues: "Chyba při uložení %{count} úkolu(ů) z %{total} vybraných: %{ids}." + notice_failed_to_save_members: "Nepodařilo se uložit člena(y): %{errors}." + notice_no_issue_selected: "Nebyl zvolen žádný úkol. Prosím, zvolte úkoly, které chcete editovat" + notice_account_pending: "Váš účet byl vytvořen, nyní čeká na schválení administrátorem." + notice_default_data_loaded: Výchozí konfigurace úspěšně nahrána. + notice_unable_delete_version: Nemohu odstanit verzi + notice_unable_delete_time_entry: Nelze smazat čas ze záznamu. + notice_issue_done_ratios_updated: Koeficienty dokončení úkolu byly aktualizovány. + notice_gantt_chart_truncated: Graf byl oříznut, počet položek přesáhl limit pro zobrazení (%{max}) + + error_can_t_load_default_data: "Výchozí konfigurace nebyla nahrána: %{value}" + error_scm_not_found: "Položka a/nebo revize neexistují v repozitáři." + error_scm_command_failed: "Při pokusu o přístup k repozitáři došlo k chybě: %{value}" + error_scm_annotate: "Položka neexistuje nebo nemůže být komentována." + error_issue_not_found_in_project: 'Úkol nebyl nalezen nebo nepatří k tomuto projektu' + error_no_tracker_in_project: Žádná fronta nebyla přiřazena tomuto projektu. Prosím zkontroluje nastavení projektu. + error_no_default_issue_status: Není nastaven výchozí stav úkolu. Prosím zkontrolujte nastavení ("Administrace -> Stavy úkolů"). + error_can_not_delete_custom_field: Nelze smazat volitelné pole + error_can_not_delete_tracker: Tato fronta obsahuje úkoly a nemůže být smazán. + error_can_not_remove_role: Tato role je právě používaná a nelze ji smazat. + error_can_not_reopen_issue_on_closed_version: Úkol přiřazený k uzavřené verzi nemůže být znovu otevřen + error_can_not_archive_project: Tento projekt nemůže být archivován + error_issue_done_ratios_not_updated: Koeficient dokončení úkolu nebyl aktualizován. + error_workflow_copy_source: Prosím vyberte zdrojovou frontu nebo roly + error_workflow_copy_target: Prosím vyberte cílovou frontu(y) a roly(e) + error_unable_delete_issue_status: Nelze smazat stavy úkolů + error_unable_to_connect: Nelze se připojit (%{value}) + warning_attachments_not_saved: "%{count} soubor(ů) nebylo možné uložit." + + mail_subject_lost_password: "Vaše heslo (%{value})" + mail_body_lost_password: 'Pro změnu vašeho hesla klikněte na následující odkaz:' + mail_subject_register: "Aktivace účtu (%{value})" + mail_body_register: 'Pro aktivaci vašeho účtu klikněte na následující odkaz:' + mail_body_account_information_external: "Pomocí vašeho účtu %{value} se můžete přihlásit." + mail_body_account_information: Informace o vašem účtu + mail_subject_account_activation_request: "Aktivace %{value} účtu" + mail_body_account_activation_request: "Byl zaregistrován nový uživatel %{value}. Aktivace jeho účtu závisí na vašem potvrzení." + mail_subject_reminder: "%{count} úkol(ů) má termín během několik dní (%{days})" + mail_body_reminder: "%{count} úkol(ů), které máte přiřazeny má termín během několik dní (%{days}):" + mail_subject_wiki_content_added: "'%{id}' Wiki stránka byla přidána" + mail_body_wiki_content_added: "'%{id}' Wiki stránka byla přidána od %{author}." + mail_subject_wiki_content_updated: "'%{id}' Wiki stránka byla aktualizována" + mail_body_wiki_content_updated: "'%{id}' Wiki stránka byla aktualizována od %{author}." + + gui_validation_error: 1 chyba + gui_validation_error_plural: "%{count} chyb(y)" + + field_name: Název + field_description: Popis + field_summary: Přehled + field_is_required: Povinné pole + field_firstname: Jméno + field_lastname: Příjmení + field_mail: Email + field_filename: Soubor + field_filesize: Velikost + field_downloads: Staženo + field_author: Autor + field_created_on: Vytvořeno + field_updated_on: Aktualizováno + field_field_format: Formát + field_is_for_all: Pro všechny projekty + field_possible_values: Možné hodnoty + field_regexp: Regulární výraz + field_min_length: Minimální délka + field_max_length: Maximální délka + field_value: Hodnota + field_category: Kategorie + field_title: Název + field_project: Projekt + field_issue: Úkol + field_status: Stav + field_notes: Poznámka + field_is_closed: Úkol uzavřen + field_is_default: Výchozí stav + field_tracker: Fronta + field_subject: Předmět + field_due_date: Uzavřít do + field_assigned_to: Přiřazeno + field_priority: Priorita + field_fixed_version: Cílová verze + field_user: Uživatel + field_principal: Hlavní + field_role: Role + field_homepage: Domovská stránka + field_is_public: Veřejný + field_parent: Nadřazený projekt + field_is_in_roadmap: Úkoly zobrazené v plánu + field_login: Přihlášení + field_mail_notification: Emailová oznámení + field_admin: Administrátor + field_last_login_on: Poslední přihlášení + field_language: Jazyk + field_effective_date: Datum + field_password: Heslo + field_new_password: Nové heslo + field_password_confirmation: Potvrzení + field_version: Verze + field_type: Typ + field_host: Host + field_port: Port + field_account: Účet + field_base_dn: Base DN + field_attr_login: Přihlášení (atribut) + field_attr_firstname: Jméno (atribut) + field_attr_lastname: Příjemní (atribut) + field_attr_mail: Email (atribut) + field_onthefly: Automatické vytváření uživatelů + field_start_date: Začátek + field_done_ratio: "% Hotovo" + field_auth_source: Autentifikační mód + field_hide_mail: Nezobrazovat můj email + field_comments: Komentář + field_url: URL + field_start_page: Výchozí stránka + field_subproject: Podprojekt + field_hours: Hodiny + field_activity: Aktivita + field_spent_on: Datum + field_identifier: Identifikátor + field_is_filter: Použít jako filtr + field_issue_to: Související úkol + field_delay: Zpoždění + field_assignable: Úkoly mohou být přiřazeny této roli + field_redirect_existing_links: Přesměrovat stvávající odkazy + field_estimated_hours: Odhadovaná doba + field_column_names: Sloupce + field_time_entries: Zaznamenaný čas + field_time_zone: Časové pásmo + field_searchable: Umožnit vyhledávání + field_default_value: Výchozí hodnota + field_comments_sorting: Zobrazit komentáře + field_parent_title: Rodičovská stránka + field_editable: Editovatelný + field_watcher: Sleduje + field_identity_url: OpenID URL + field_content: Obsah + field_group_by: Seskupovat výsledky podle + field_sharing: Sdílení + field_parent_issue: Rodičovský úkol + field_member_of_group: Skupina přiřaditele + field_assigned_to_role: Role přiřaditele + field_text: Textové pole + field_visible: Viditelný + + setting_app_title: Název aplikace + setting_app_subtitle: Podtitulek aplikace + setting_welcome_text: Uvítací text + setting_default_language: Výchozí jazyk + setting_login_required: Autentifikace vyžadována + setting_self_registration: Povolena automatická registrace + setting_attachment_max_size: Maximální velikost přílohy + setting_issues_export_limit: Limit pro export úkolů + setting_mail_from: Odesílat emaily z adresy + setting_bcc_recipients: Příjemci skryté kopie (bcc) + setting_plain_text_mail: pouze prostý text (ne HTML) + setting_host_name: Jméno serveru + setting_text_formatting: Formátování textu + setting_wiki_compression: Komprese historie Wiki + setting_feeds_limit: Limit obsahu příspěvků + setting_default_projects_public: Nové projekty nastavovat jako veřejné + setting_autofetch_changesets: Automaticky stahovat commity + setting_sys_api_enabled: Povolit WS pro správu repozitory + setting_commit_ref_keywords: Klíčová slova pro odkazy + setting_commit_fix_keywords: Klíčová slova pro uzavření + setting_autologin: Automatické přihlašování + setting_date_format: Formát data + setting_time_format: Formát času + setting_cross_project_issue_relations: Povolit vazby úkolů napříč projekty + setting_issue_list_default_columns: Výchozí sloupce zobrazené v seznamu úkolů + setting_emails_header: Hlavička emailů + setting_emails_footer: Patička emailů + setting_protocol: Protokol + setting_per_page_options: Povolené počty řádků na stránce + setting_user_format: Formát zobrazení uživatele + setting_activity_days_default: Dny zobrazené v činnosti projektu + setting_display_subprojects_issues: Automaticky zobrazit úkoly podprojektu v hlavním projektu + setting_enabled_scm: Povolené SCM + setting_mail_handler_body_delimiters: Zkrátit e-maily po jednom z těchto řádků + setting_mail_handler_api_enabled: Povolit WS pro příchozí e-maily + setting_mail_handler_api_key: API klíč + setting_sequential_project_identifiers: Generovat sekvenční identifikátory projektů + setting_gravatar_enabled: Použít uživatelské ikony Gravatar + setting_gravatar_default: Výchozí Gravatar + setting_diff_max_lines_displayed: Maximální počet zobrazených řádků rozdílů + setting_file_max_size_displayed: Maximální velikost textových souborů zobrazených přímo na stránce + setting_repository_log_display_limit: Maximální počet revizí zobrazených v logu souboru + setting_openid: Umožnit přihlašování a registrace s OpenID + setting_password_min_length: Minimální délka hesla + setting_new_project_user_role_id: Role přiřazená uživateli bez práv administrátora, který projekt vytvořil + setting_default_projects_modules: Výchozí zapnutné moduly pro nový projekt + setting_issue_done_ratio: Spočítat koeficient dokončení úkolu s + setting_issue_done_ratio_issue_field: Použít pole úkolu + setting_issue_done_ratio_issue_status: Použít stav úkolu + setting_start_of_week: Začínat kalendáře + setting_rest_api_enabled: Zapnout službu REST + setting_cache_formatted_text: Ukládat formátovaný text do vyrovnávací paměti + setting_default_notification_option: Výchozí nastavení oznámení + setting_commit_logtime_enabled: Povolit zapisování času + setting_commit_logtime_activity_id: Aktivita pro zapsaný čas + setting_gantt_items_limit: Maximální počet položek zobrazený na ganttově grafu + + permission_add_project: Vytvořit projekt + permission_add_subprojects: Vytvořit podprojekty + permission_edit_project: Úprava projektů + permission_select_project_modules: Výběr modulů projektu + permission_manage_members: Spravování členství + permission_manage_project_activities: Spravovat aktivity projektu + permission_manage_versions: Spravování verzí + permission_manage_categories: Spravování kategorií úkolů + permission_view_issues: Zobrazit úkoly + permission_add_issues: Přidávání úkolů + permission_edit_issues: Upravování úkolů + permission_manage_issue_relations: Spravování vztahů mezi úkoly + permission_add_issue_notes: Přidávání poznámek + permission_edit_issue_notes: Upravování poznámek + permission_edit_own_issue_notes: Upravování vlastních poznámek + permission_move_issues: Přesouvání úkolů + permission_delete_issues: Mazání úkolů + permission_manage_public_queries: Správa veřejných dotazů + permission_save_queries: Ukládání dotazů + permission_view_gantt: Zobrazené Ganttova diagramu + permission_view_calendar: Prohlížení kalendáře + permission_view_issue_watchers: Zobrazení seznamu sledujícíh uživatelů + permission_add_issue_watchers: Přidání sledujících uživatelů + permission_delete_issue_watchers: Smazat přihlížející + permission_log_time: Zaznamenávání stráveného času + permission_view_time_entries: Zobrazení stráveného času + permission_edit_time_entries: Upravování záznamů o stráveném času + permission_edit_own_time_entries: Upravování vlastních zázamů o stráveném čase + permission_manage_news: Spravování novinek + permission_comment_news: Komentování novinek + permission_manage_documents: Správa dokumentů + permission_view_documents: Prohlížení dokumentů + permission_manage_files: Spravování souborů + permission_view_files: Prohlížení souborů + permission_manage_wiki: Spravování Wiki + permission_rename_wiki_pages: Přejmenovávání Wiki stránek + permission_delete_wiki_pages: Mazání stránek na Wiki + permission_view_wiki_pages: Prohlížení Wiki + permission_view_wiki_edits: Prohlížení historie Wiki + permission_edit_wiki_pages: Upravování stránek Wiki + permission_delete_wiki_pages_attachments: Mazání příloh + permission_protect_wiki_pages: Zabezpečení Wiki stránek + permission_manage_repository: Spravování repozitáře + permission_browse_repository: Procházení repozitáře + permission_view_changesets: Zobrazování sady změn + permission_commit_access: Commit přístup + permission_manage_boards: Správa diskusních fór + permission_view_messages: Prohlížení zpráv + permission_add_messages: Posílání zpráv + permission_edit_messages: Upravování zpráv + permission_edit_own_messages: Upravit vlastní zprávy + permission_delete_messages: Mazání zpráv + permission_delete_own_messages: Smazat vlastní zprávy + permission_export_wiki_pages: Exportovat Wiki stránky + permission_manage_subtasks: Spravovat podúkoly + + project_module_issue_tracking: Sledování úkolů + project_module_time_tracking: Sledování času + project_module_news: Novinky + project_module_documents: Dokumenty + project_module_files: Soubory + project_module_wiki: Wiki + project_module_repository: Repozitář + project_module_boards: Diskuse + project_module_calendar: Kalendář + project_module_gantt: Gantt + + label_user: Uživatel + label_user_plural: Uživatelé + label_user_new: Nový uživatel + label_user_anonymous: Anonymní + label_project: Projekt + label_project_new: Nový projekt + label_project_plural: Projekty + label_x_projects: + zero: žádné projekty + one: 1 projekt + other: "%{count} projekty(ů)" + label_project_all: Všechny projekty + label_project_latest: Poslední projekty + label_issue: Úkol + label_issue_new: Nový úkol + label_issue_plural: Úkoly + label_issue_view_all: Všechny úkoly + label_issues_by: "Úkoly podle %{value}" + label_issue_added: Úkol přidán + label_issue_updated: Úkol aktualizován + label_document: Dokument + label_document_new: Nový dokument + label_document_plural: Dokumenty + label_document_added: Dokument přidán + label_role: Role + label_role_plural: Role + label_role_new: Nová role + label_role_and_permissions: Role a práva + label_member: Člen + label_member_new: Nový člen + label_member_plural: Členové + label_tracker: Fronta + label_tracker_plural: Fronty + label_tracker_new: Nová fronta + label_workflow: Průběh práce + label_issue_status: Stav úkolu + label_issue_status_plural: Stavy úkolů + label_issue_status_new: Nový stav + label_issue_category: Kategorie úkolu + label_issue_category_plural: Kategorie úkolů + label_issue_category_new: Nová kategorie + label_custom_field: Uživatelské pole + label_custom_field_plural: Uživatelská pole + label_custom_field_new: Nové uživatelské pole + label_enumerations: Seznamy + label_enumeration_new: Nová hodnota + label_information: Informace + label_information_plural: Informace + label_please_login: Prosím přihlašte se + label_register: Registrovat + label_login_with_open_id_option: nebo se přihlašte s OpenID + label_password_lost: Zapomenuté heslo + label_home: Úvodní + label_my_page: Moje stránka + label_my_account: Můj účet + label_my_projects: Moje projekty + label_my_page_block: Bloky na mé stránce + label_administration: Administrace + label_login: Přihlášení + label_logout: Odhlášení + label_help: Nápověda + label_reported_issues: Nahlášené úkoly + label_assigned_to_me_issues: Mé úkoly + label_last_login: Poslední přihlášení + label_registered_on: Registrován + label_activity: Aktivita + label_overall_activity: Celková aktivita + label_user_activity: "Aktivita uživatele: %{value}" + label_new: Nový + label_logged_as: Přihlášen jako + label_environment: Prostředí + label_authentication: Autentifikace + label_auth_source: Mód autentifikace + label_auth_source_new: Nový mód autentifikace + label_auth_source_plural: Módy autentifikace + label_subproject_plural: Podprojekty + label_subproject_new: Nový podprojekt + label_and_its_subprojects: "%{value} a jeho podprojekty" + label_min_max_length: Min - Max délka + label_list: Seznam + label_date: Datum + label_integer: Celé číslo + label_float: Desetinné číslo + label_boolean: Ano/Ne + label_string: Text + label_text: Dlouhý text + label_attribute: Atribut + label_attribute_plural: Atributy + label_download: "%{count} stažení" + label_download_plural: "%{count} stažení" + label_no_data: Žádné položky + label_change_status: Změnit stav + label_history: Historie + label_attachment: Soubor + label_attachment_new: Nový soubor + label_attachment_delete: Odstranit soubor + label_attachment_plural: Soubory + label_file_added: Soubor přidán + label_report: Přehled + label_report_plural: Přehledy + label_news: Novinky + label_news_new: Přidat novinku + label_news_plural: Novinky + label_news_latest: Poslední novinky + label_news_view_all: Zobrazit všechny novinky + label_news_added: Novinka přidána + label_settings: Nastavení + label_overview: Přehled + label_version: Verze + label_version_new: Nová verze + label_version_plural: Verze + label_close_versions: Zavřít dokončené verze + label_confirmation: Potvrzení + label_export_to: 'Také k dispozici:' + label_read: Načítá se... + label_public_projects: Veřejné projekty + label_open_issues: otevřený + label_open_issues_plural: otevřené + label_closed_issues: uzavřený + label_closed_issues_plural: uzavřené + label_x_open_issues_abbr_on_total: + zero: 0 otevřených / %{total} + one: 1 otevřený / %{total} + other: "%{count} otevřených / %{total}" + label_x_open_issues_abbr: + zero: 0 otevřených + one: 1 otevřený + other: "%{count} otevřených" + label_x_closed_issues_abbr: + zero: 0 uzavřených + one: 1 uzavřený + other: "%{count} uzavřených" + label_total: Celkem + label_permissions: Práva + label_current_status: Aktuální stav + label_new_statuses_allowed: Nové povolené stavy + label_all: vše + label_none: nic + label_nobody: nikdo + label_next: Další + label_previous: Předchozí + label_used_by: Použito + label_details: Detaily + label_add_note: Přidat poznámku + label_per_page: Na stránku + label_calendar: Kalendář + label_months_from: měsíců od + label_gantt: Ganttův graf + label_internal: Interní + label_last_changes: "posledních %{count} změn" + label_change_view_all: Zobrazit všechny změny + label_personalize_page: Přizpůsobit tuto stránku + label_comment: Komentář + label_comment_plural: Komentáře + label_x_comments: + zero: žádné komentáře + one: 1 komentář + other: "%{count} komentářů" + label_comment_add: Přidat komentáře + label_comment_added: Komentář přidán + label_comment_delete: Odstranit komentář + label_query: Uživatelský dotaz + label_query_plural: Uživatelské dotazy + label_query_new: Nový dotaz + label_filter_add: Přidat filtr + label_filter_plural: Filtry + label_equals: je + label_not_equals: není + label_in_less_than: je měší než + label_in_more_than: je větší než + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: v + label_today: dnes + label_all_time: vše + label_yesterday: včera + label_this_week: tento týden + label_last_week: minulý týden + label_last_n_days: "posledních %{count} dnů" + label_this_month: tento měsíc + label_last_month: minulý měsíc + label_this_year: tento rok + label_date_range: Časový rozsah + label_less_than_ago: před méně jak (dny) + label_more_than_ago: před více jak (dny) + label_ago: před (dny) + label_contains: obsahuje + label_not_contains: neobsahuje + label_day_plural: dny + label_repository: Repozitář + label_repository_plural: Repozitáře + label_browse: Procházet + label_modification: "%{count} změna" + label_modification_plural: "%{count} změn" + label_branch: Větev + label_tag: Tag + label_revision: Revize + label_revision_plural: Revizí + label_revision_id: "Revize %{value}" + label_associated_revisions: Související verze + label_added: přidáno + label_modified: změněno + label_copied: zkopírováno + label_renamed: přejmenováno + label_deleted: odstraněno + label_latest_revision: Poslední revize + label_latest_revision_plural: Poslední revize + label_view_revisions: Zobrazit revize + label_view_all_revisions: Zobrazit všechny revize + label_max_size: Maximální velikost + label_sort_highest: Přesunout na začátek + label_sort_higher: Přesunout nahoru + label_sort_lower: Přesunout dolů + label_sort_lowest: Přesunout na konec + label_roadmap: Plán + label_roadmap_due_in: "Zbývá %{value}" + label_roadmap_overdue: "%{value} pozdě" + label_roadmap_no_issues: Pro tuto verzi nejsou žádné úkoly + label_search: Hledat + label_result_plural: Výsledky + label_all_words: Všechna slova + label_wiki: Wiki + label_wiki_edit: Wiki úprava + label_wiki_edit_plural: Wiki úpravy + label_wiki_page: Wiki stránka + label_wiki_page_plural: Wiki stránky + label_index_by_title: Index dle názvu + label_index_by_date: Index dle data + label_current_version: Aktuální verze + label_preview: Náhled + label_feed_plural: Příspěvky + label_changes_details: Detail všech změn + label_issue_tracking: Sledování úkolů + label_spent_time: Strávený čas + label_overall_spent_time: Celkem strávený čas + label_f_hour: "%{value} hodina" + label_f_hour_plural: "%{value} hodin" + label_time_tracking: Sledování času + label_change_plural: Změny + label_statistics: Statistiky + label_commits_per_month: Commitů za měsíc + label_commits_per_author: Commitů za autora + label_view_diff: Zobrazit rozdíly + label_diff_inline: uvnitř + label_diff_side_by_side: vedle sebe + label_options: Nastavení + label_copy_workflow_from: Kopírovat průběh práce z + label_permissions_report: Přehled práv + label_watched_issues: Sledované úkoly + label_related_issues: Související úkoly + label_applied_status: Použitý stav + label_loading: Nahrávám... + label_relation_new: Nová souvislost + label_relation_delete: Odstranit souvislost + label_relates_to: související s + label_duplicates: duplikuje + label_duplicated_by: zduplikován + label_blocks: blokuje + label_blocked_by: zablokován + label_precedes: předchází + label_follows: následuje + label_end_to_start: od konce do začátku + label_end_to_end: od konce do konce + label_start_to_start: od začátku do začátku + label_start_to_end: od začátku do konce + label_stay_logged_in: Zůstat přihlášený + label_disabled: zakázán + label_show_completed_versions: Ukázat dokončené verze + label_me: já + label_board: Fórum + label_board_new: Nové fórum + label_board_plural: Fóra + label_board_locked: Uzamčeno + label_board_sticky: Nálepka + label_topic_plural: Témata + label_message_plural: Zprávy + label_message_last: Poslední zpráva + label_message_new: Nová zpráva + label_message_posted: Zpráva přidána + label_reply_plural: Odpovědi + label_send_information: Zaslat informace o účtu uživateli + label_year: Rok + label_month: Měsíc + label_week: Týden + label_date_from: Od + label_date_to: Do + label_language_based: Podle výchozího jazyku + label_sort_by: "Seřadit podle %{value}" + label_send_test_email: Poslat testovací email + label_feeds_access_key: Přístupový klíč pro RSS + label_missing_feeds_access_key: Postrádá přístupový klíč pro RSS + label_feeds_access_key_created_on: "Přístupový klíč pro RSS byl vytvořen před %{value}" + label_module_plural: Moduly + label_added_time_by: "Přidáno uživatelem %{author} před %{age}" + label_updated_time_by: "Aktualizováno uživatelem %{author} před %{age}" + label_updated_time: "Aktualizováno před %{value}" + label_jump_to_a_project: Vyberte projekt... + label_file_plural: Soubory + label_changeset_plural: Changesety + label_default_columns: Výchozí sloupce + label_no_change_option: (beze změny) + label_bulk_edit_selected_issues: Hromadná úprava vybraných úkolů + label_theme: Téma + label_default: Výchozí + label_search_titles_only: Vyhledávat pouze v názvech + label_user_mail_option_all: "Pro všechny události všech mých projektů" + label_user_mail_option_selected: "Pro všechny události vybraných projektů..." + label_user_mail_option_none: "Žádné události" + label_user_mail_option_only_my_events: "Jen pro věci co sleduji nebo jsem v nich zapojen" + label_user_mail_option_only_assigned: "Jen pro všeci kterým sem přiřazen" + label_user_mail_option_only_owner: "Jen pro věci které vlastním" + label_user_mail_no_self_notified: "Nezasílat informace o mnou vytvořených změnách" + label_registration_activation_by_email: aktivace účtu emailem + label_registration_manual_activation: manuální aktivace účtu + label_registration_automatic_activation: automatická aktivace účtu + label_display_per_page: "%{value} na stránku" + label_age: Věk + label_change_properties: Změnit vlastnosti + label_general: Obecné + label_more: Více + label_scm: SCM + label_plugins: Doplňky + label_ldap_authentication: Autentifikace LDAP + label_downloads_abbr: Staž. + label_optional_description: Volitelný popis + label_add_another_file: Přidat další soubor + label_preferences: Nastavení + label_chronological_order: V chronologickém pořadí + label_reverse_chronological_order: V obrácaném chronologickém pořadí + label_planning: Plánování + label_incoming_emails: Příchozí e-maily + label_generate_key: Generovat klíč + label_issue_watchers: Sledování + label_example: Příklad + label_display: Zobrazit + label_sort: Řazení + label_ascending: Vzestupně + label_descending: Sestupně + label_date_from_to: Od %{start} do %{end} + label_wiki_content_added: Wiki stránka přidána + label_wiki_content_updated: Wiki stránka aktualizována + label_group: Skupina + label_group_plural: Skupiny + label_group_new: Nová skupina + label_time_entry_plural: Strávený čas + label_version_sharing_none: Nesdíleno + label_version_sharing_descendants: S podprojekty + label_version_sharing_hierarchy: S hierarchií projektu + label_version_sharing_tree: Se stromem projektu + label_version_sharing_system: Se všemi projekty + label_update_issue_done_ratios: Aktualizovat koeficienty dokončení úkolů + label_copy_source: Zdroj + label_copy_target: Cíl + label_copy_same_as_target: Stejný jako cíl + label_display_used_statuses_only: Zobrazit pouze stavy které jsou použité touto frontou + label_api_access_key: API přístupový klíč + label_missing_api_access_key: Chybějící přístupový klíč API + label_api_access_key_created_on: API přístupový klíč vytvořen %{value} + label_profile: Profil + label_subtask_plural: Podúkol + label_project_copy_notifications: Odeslat email oznámení v průběhu kopie projektu + label_principal_search: "Hledat uživatele nebo skupinu:" + label_user_search: "Hledat uživatele:" + + button_login: Přihlásit + button_submit: Potvrdit + button_save: Uložit + button_check_all: Zašrtnout vše + button_uncheck_all: Odšrtnout vše + button_delete: Odstranit + button_create: Vytvořit + button_create_and_continue: Vytvořit a pokračovat + button_test: Testovat + button_edit: Upravit + button_edit_associated_wikipage: "Upravit přiřazenou Wiki stránku: %{page_title}" + button_add: Přidat + button_change: Změnit + button_apply: Použít + button_clear: Smazat + button_lock: Zamknout + button_unlock: Odemknout + button_download: Stáhnout + button_list: Vypsat + button_view: Zobrazit + button_move: Přesunout + button_move_and_follow: Přesunout a následovat + button_back: Zpět + button_cancel: Storno + button_activate: Aktivovat + button_sort: Seřadit + button_log_time: Přidat čas + button_rollback: Zpět k této verzi + button_watch: Sledovat + button_unwatch: Nesledovat + button_reply: Odpovědět + button_archive: Archivovat + button_unarchive: Odarchivovat + button_reset: Resetovat + button_rename: Přejmenovat + button_change_password: Změnit heslo + button_copy: Kopírovat + button_copy_and_follow: Kopírovat a následovat + button_annotate: Komentovat + button_update: Aktualizovat + button_configure: Konfigurovat + button_quote: Citovat + button_duplicate: Duplikovat + button_show: Zobrazit + + status_active: aktivní + status_registered: registrovaný + status_locked: uzamčený + + version_status_open: otevřený + version_status_locked: uzamčený + version_status_closed: zavřený + + field_active: Aktivní + + text_select_mail_notifications: Vyberte akci při které bude zasláno upozornění emailem. + text_regexp_info: např. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znamená bez limitu + text_project_destroy_confirmation: Jste si jisti, že chcete odstranit tento projekt a všechna související data ? + text_subprojects_destroy_warning: "Jeho podprojek(y): %{value} budou také smazány." + text_workflow_edit: Vyberte roli a frontu k editaci průběhu práce + text_are_you_sure: Jste si jisti? + text_are_you_sure_with_children: Smazat úkol včetně všech podúkolů? + text_journal_changed: "%{label} změněn z %{old} na %{new}" + text_journal_set_to: "%{label} nastaven na %{value}" + text_journal_deleted: "%{label} smazán (%{old})" + text_journal_added: "%{label} %{value} přidán" + text_tip_issue_begin_day: úkol začíná v tento den + text_tip_issue_end_day: úkol končí v tento den + text_tip_issue_begin_end_day: úkol začíná a končí v tento den + text_project_identifier_info: 'Jsou povolena malá písmena (a-z), čísla a pomlčky.
    Po uložení již není možné identifikátor změnit.' + text_caracters_maximum: "%{count} znaků maximálně." + text_caracters_minimum: "Musí být alespoň %{count} znaků dlouhé." + text_length_between: "Délka mezi %{min} a %{max} znaky." + text_tracker_no_workflow: Pro tuto frontu není definován žádný průběh práce + text_unallowed_characters: Nepovolené znaky + text_comma_separated: Povoleno více hodnot (oddělěné čárkou). + text_line_separated: Více hodnot povoleno (jeden řádek pro každou hodnotu). + text_issues_ref_in_commit_messages: Odkazování a opravování úkolů ve zprávách commitů + text_issue_added: "Úkol %{id} byl vytvořen uživatelem %{author}." + text_issue_updated: "Úkol %{id} byl aktualizován uživatelem %{author}." + text_wiki_destroy_confirmation: Opravdu si přejete odstranit tuto Wiki a celý její obsah? + text_issue_category_destroy_question: "Některé úkoly (%{count}) jsou přiřazeny k této kategorii. Co s nimi chtete udělat?" + text_issue_category_destroy_assignments: Zrušit přiřazení ke kategorii + text_issue_category_reassign_to: Přiřadit úkoly do této kategorie + text_user_mail_option: "U projektů, které nebyly vybrány, budete dostávat oznámení pouze o vašich či o sledovaných položkách (např. o položkách jejichž jste autor nebo ke kterým jste přiřazen(a))." + text_no_configuration_data: "Role, fronty, stavy úkolů ani průběh práce nebyly zatím nakonfigurovány.\nVelice doporučujeme nahrát výchozí konfiguraci. Po té si můžete vše upravit" + text_load_default_configuration: Nahrát výchozí konfiguraci + text_status_changed_by_changeset: "Použito v changesetu %{value}." + text_time_logged_by_changeset: Aplikováno v changesetu %{value}. + text_issues_destroy_confirmation: 'Opravdu si přejete odstranit všechny zvolené úkoly?' + text_select_project_modules: 'Aktivní moduly v tomto projektu:' + text_default_administrator_account_changed: Výchozí nastavení administrátorského účtu změněno + text_file_repository_writable: Povolen zápis do adresáře ukládání souborů + text_plugin_assets_writable: Možnost zápisu do adresáře plugin assets + text_rmagick_available: RMagick k dispozici (volitelné) + text_destroy_time_entries_question: "U úkolů, které chcete odstranit je evidováno %{hours} práce. Co chete udělat?" + text_destroy_time_entries: Odstranit evidované hodiny. + text_assign_time_entries_to_project: Přiřadit evidované hodiny projektu + text_reassign_time_entries: 'Přeřadit evidované hodiny k tomuto úkolu:' + text_user_wrote: "%{value} napsal:" + text_enumeration_destroy_question: "Několik (%{count}) objektů je přiřazeno k této hodnotě." + text_enumeration_category_reassign_to: 'Přeřadit je do této:' + text_email_delivery_not_configured: "Doručování e-mailů není nastaveno a odesílání notifikací je zakázáno.\nNastavte Váš SMTP server v souboru config/configuration.yml a restartujte aplikaci." + text_repository_usernames_mapping: "Vybrat nebo upravit mapování mezi Redmine uživateli a uživatelskými jmény nalezenými v logu repozitáře.\nUživatelé se shodným Redmine uživatelským jménem a uživatelským jménem v repozitáři jsou mapovaní automaticky." + text_diff_truncated: '... Rozdílový soubor je zkrácen, protože jeho délka přesahuje max. limit.' + text_custom_field_possible_values_info: 'Každá hodnota na novém řádku' + text_wiki_page_destroy_question: Tato stránka má %{descendants} podstránek a potomků. Co chcete udělat? + text_wiki_page_nullify_children: Ponechat podstránky jako kořenové stránky + text_wiki_page_destroy_children: Smazat podstránky a všechny jejich potomky + text_wiki_page_reassign_children: Přiřadit podstránky k tomuto rodiči + text_own_membership_delete_confirmation: "Chystáte se odebrat si některá nebo všechny svá oprávnění a potom již nemusíte být schopni upravit tento projekt.\nOpravdu chcete pokračovat?" + text_zoom_in: Přiblížit + text_zoom_out: Oddálit + + default_role_manager: Manažer + default_role_developer: Vývojář + default_role_reporter: Reportér + default_tracker_bug: Chyba + default_tracker_feature: Požadavek + default_tracker_support: Podpora + default_issue_status_new: Nový + default_issue_status_in_progress: Ve vývoji + default_issue_status_resolved: Vyřešený + default_issue_status_feedback: Čeká se + default_issue_status_closed: Uzavřený + default_issue_status_rejected: Odmítnutý + default_doc_category_user: Uživatelská dokumentace + default_doc_category_tech: Technická dokumentace + default_priority_low: Nízká + default_priority_normal: Normální + default_priority_high: Vysoká + default_priority_urgent: Urgentní + default_priority_immediate: Okamžitá + default_activity_design: Návhr + default_activity_development: Vývoj + + enumeration_issue_priorities: Priority úkolů + enumeration_doc_categories: Kategorie dokumentů + enumeration_activities: Aktivity (sledování času) + enumeration_system_activity: Systémová aktivita + + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kódování zpráv při commitu + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/82b21e972ba488af04b89b832125d370772e13c3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/82b21e972ba488af04b89b832125d370772e13c3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,187 @@ +<% @gantt.view = self %> +

    <%= @query.new_record? ? l(:label_gantt) : h(@query.name) %>

    + +<% form_tag({:controller => 'gantts', :action => 'show', :project_id => @project, :month => params[:month], :year => params[:year], :months => params[:months]}, :method => :get, :id => 'query_form') do %> +<%= hidden_field_tag 'set_filter', '1' %> +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +

    + <%= gantt_zoom_link(@gantt, :in) %> + <%= gantt_zoom_link(@gantt, :out) %> +

    + +

    +<%= text_field_tag 'months', @gantt.months, :size => 2 %> +<%= l(:label_months_from) %> +<%= select_month(@gantt.month_from, :prefix => "month", :discard_type => true) %> +<%= select_year(@gantt.year_from, :prefix => "year", :discard_type => true) %> +<%= hidden_field_tag 'zoom', @gantt.zoom %> + +<%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %> +<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 }, :class => 'icon icon-reload' %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<% zoom = 1 +@gantt.zoom.times { zoom = zoom * 2 } + +subject_width = 330 +header_heigth = 18 + +headers_height = header_heigth +show_weeks = false +show_days = false + +if @gantt.zoom >1 + show_weeks = true + headers_height = 2*header_heigth + if @gantt.zoom > 2 + show_days = true + headers_height = 3*header_heigth + end +end + +# Width of the entire chart +g_width = (@gantt.date_to - @gantt.date_from + 1)*zoom + +@gantt.render(:top => headers_height + 8, :zoom => zoom, :g_width => g_width, :subject_width => subject_width) + +g_height = [(20 * (@gantt.number_of_rows + 6))+150, 206].max +t_height = g_height + headers_height + + +%> + +<% if @gantt.truncated %> +

    <%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %>

    +<% end %> + + + + + + +
    + +
    +
    +
    + +
    +<%= @gantt.subjects.html_safe %> +
    + +
    +
    + +
    +
     
    +<% +# +# Months headers +# +month_f = @gantt.date_from +left = 0 +height = (show_weeks ? header_heigth : header_heigth + g_height) +@gantt.months.times do + width = ((month_f >> 1) - month_f) * zoom - 1 + %> +
    + <%= link_to h("#{month_f.year}-#{month_f.month}"), @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%> +
    + <% + left = left + width + 1 + month_f = month_f >> 1 +end %> + +<% +# +# Weeks headers +# +if show_weeks + left = 0 + height = (show_days ? header_heigth-1 : header_heigth-1 + g_height) + if @gantt.date_from.cwday == 1 + # @date_from is monday + week_f = @gantt.date_from + else + # find next monday after @date_from + week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1) + width = (7 - @gantt.date_from.cwday + 1) * zoom-1 + %> +
     
    + <% + left = left + width+1 + end %> + <% + while week_f <= @gantt.date_to + width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom -1 : (@gantt.date_to - week_f + 1) * zoom-1 + %> +
    + <%= week_f.cweek if width >= 16 %> +
    + <% + left = left + width+1 + week_f = week_f+7 + end +end %> + +<% +# +# Days headers +# +if show_days + left = 0 + height = g_height + header_heigth - 1 + wday = @gantt.date_from.cwday + (@gantt.date_to - @gantt.date_from + 1).to_i.times do + width = zoom - 1 + %> +
    5 %>" class="gantt_hdr"> + <%= day_name(wday).first %> +
    + <% + left = left + width+1 + wday = wday + 1 + wday = 1 if wday > 7 + end +end %> + +<%= @gantt.lines.html_safe %> + +<% +# +# Today red line (excluded from cache) +# +if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %> +
     
    +<% end %> + +
    +
    + + + + + + +
    <%= link_to_content_update("\xc2\xab " + l(:label_previous), params.merge(@gantt.params_previous)) %><%= link_to_content_update(l(:label_next) + " \xc2\xbb", params.merge(@gantt.params_next)) %>
    + +<% other_formats_links do |f| %> + <%= f.link_to 'PDF', :url => params.merge(@gantt.params) %> + <%= f.link_to('PNG', :url => params.merge(@gantt.params)) if @gantt.respond_to?('to_image') %> +<% end %> +<% end # query.valid? %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> +<% end %> + +<% html_title(l(:label_gantt)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/82b5527b2dac372076831682e718c16438363e58.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/82b5527b2dac372076831682e718c16438363e58.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +class Attachment < ActiveRecord::Base + generator_for :container, :method => :generate_project + generator_for :file, :method => :generate_file + generator_for :author, :method => :generate_author + + def self.generate_project + Project.generate! + end + + def self.generate_author + User.generate_with_protected! + end + + def self.generate_file + @file = ActiveSupport::TestCase.mock_file + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/82bbb606607aa23e8d3efe2e04412a3682e044fa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/82bbb606607aa23e8d3efe2e04412a3682e044fa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,64 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class SettingsController < ApplicationController + layout 'admin' + + before_filter :require_admin + + def index + edit + render :action => 'edit' + end + + def edit + @notifiables = Redmine::Notifiable.all + if request.post? && params[:settings] && params[:settings].is_a?(Hash) + settings = (params[:settings] || {}).dup.symbolize_keys + settings.each do |name, value| + # remove blank values in array settings + value.delete_if {|v| v.blank? } if value.is_a?(Array) + Setting[name] = value + end + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'edit', :tab => params[:tab] + else + @options = {} + @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] } + @deliveries = ActionMailer::Base.perform_deliveries + + @guessed_host_and_path = request.host_with_port.dup + @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank? + + Redmine::Themes.rescan + end + end + + def plugin + @plugin = Redmine::Plugin.find(params[:id]) + if request.post? + Setting["plugin_#{@plugin.id}"] = params[:settings] + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'plugin', :id => @plugin.id + else + @partial = @plugin.settings[:partial] + @settings = Setting["plugin_#{@plugin.id}"] + end + rescue Redmine::PluginNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/82/82da6097073fda2bdfe40e34992b6b1ed026f959.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/82/82da6097073fda2bdfe40e34992b6b1ed026f959.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +coverage diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83206370aee2416a0ba8c8a86d39cae59507d756.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83206370aee2416a0ba8c8a86d39cae59507d756.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +

    <%=l(:label_reported_issues)%> (<%= Issue.visible.count(:conditions => { :author_id => User.current.id }) %>)

    + +<% reported_issues = Issue.visible.find(:all, + :conditions => { :author_id => User.current.id }, + :limit => 10, + :include => [ :status, :project, :tracker ], + :order => "#{Issue.table_name}.updated_on DESC") %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> +<% if reported_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :status_id => '*', + :author_id => 'me', + :sort => 'updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :author_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_reported_issues)}) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83443f0d8eb52ec1962ddd94322538ecdebcdcee.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83443f0d8eb52ec1962ddd94322538ecdebcdcee.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do + xml.title truncate_single_line(@title, :length => 100) + xml.link "rel" => "self", "href" => url_for(params.merge(:only_path => false)) + xml.link "rel" => "alternate", "href" => url_for(params.merge(:only_path => false, :format => nil, :key => nil)) + xml.id url_for(:controller => 'welcome', :only_path => false) + xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema) + xml.author { xml.name "#{Setting.app_title}" } + xml.generator(:uri => Redmine::Info.url) { xml.text! Redmine::Info.app_name; } + @items.each do |item| + xml.entry do + url = url_for(item.event_url(:only_path => false)) + if @project + xml.title truncate_single_line(item.event_title, :length => 100) + else + xml.title truncate_single_line("#{item.project} - #{item.event_title}", :length => 100) + end + xml.link "rel" => "alternate", "href" => url + xml.id url + xml.updated item.event_datetime.xmlschema + author = item.event_author if item.respond_to?(:event_author) + xml.author do + xml.name(author) + xml.email(author.mail) if author.is_a?(User) && !author.mail.blank? && !author.pref.hide_mail + end if author + xml.content "type" => "html" do + xml.text! textilizable(item, :event_description, :only_path => false) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/834d9cf4dced150304b5d64254144f6c7a1f3283.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/834d9cf4dced150304b5d64254144f6c7a1f3283.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,107 @@ + + +
    +<% form_tag({:action => "add_block"}, :id => "block-form") do %> +<%= label_tag('block-select', l(:label_my_page_block)) %>: +<%= select_tag 'block', "" + options_for_select(@block_options), :id => "block-select" %> +<%= link_to_remote l(:button_add), + {:url => { :action => "add_block" }, + :with => "Form.serialize('block-form')", + :update => "list-top", + :position => :top, + :complete => "afterAddBlock();" + }, :class => 'icon icon-add' + %> +<% end %> +<%= link_to l(:button_back), {:action => 'page'}, :class => 'icon icon-cancel' %> +
    + +

    <%=l(:label_my_page)%>

    + +
    + <% @blocks['top'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['top'] %> +
    + +
    + <% @blocks['left'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['left'] %> +
    + +
    + <% @blocks['right'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['right'] %> +
    + +<%= sortable_element 'list-top', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :url => { :action => "order_blocks", :group => "top" } + %> + +<%= sortable_element 'list-left', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :url => { :action => "order_blocks", :group => "left" } + %> + +<%= sortable_element 'list-right', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :url => { :action => "order_blocks", :group => "right" } + %> + +<%= javascript_tag "updateSelect()" %> +<% html_title(l(:label_my_page)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/834f64afed6c75bc47b1e5b318e33611720a6e6b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/834f64afed6c75bc47b1e5b318e33611720a6e6b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,57 @@ +SVG::Graph is copyrighted free software by Sean Russell . +You can redistribute it and/or modify it under either the terms of the GPL +(see GPL.txt file), or the conditions below: + + 1. You may make and give away verbatim copies of the source form of the + software without restriction, provided that you duplicate all of the + original copyright notices and associated disclaimers. + + 2. You may modify your copy of the software in any way, provided that + you do at least ONE of the following: + + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. + + b) use the modified software only within your corporation or + organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided. + + d) make other distribution arrangements with the author. + + 3. You may distribute the software in object code or executable + form, provided that you do at least ONE of the following: + + a) distribute the executables and library files of the software, + together with instructions (in the manual page or equivalent) + on where to get the original distribution. + + b) accompany the distribution with the machine-readable source of + the software. + + c) give non-standard executables non-standard names, with + instructions on where to get the original software distribution. + + d) make other distribution arrangements with the author. + + 4. You may modify and include the part of the software into any other + software (possibly commercial). But some files in the distribution + are not written by the author, so that they are not under this terms. + + All files of this sort are located under the contrib/ directory. + See each file for the copying condition. + + 5. The scripts and library files supplied as input to or produced as + output from the software do not automatically fall under the + copyright of the software, but belong to whomever generated them, + and may be sold commercially, and may be aggregated with this + software. + + 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/8360f4a19732e489ca5ff590b12c243a5092c5f6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/8360f4a19732e489ca5ff590b12c243a5092c5f6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 SyntaxHighlighting + + class << self + attr_reader :highlighter + delegate :highlight_by_filename, :highlight_by_language, :to => :highlighter + + def highlighter=(name) + if name.is_a?(Module) + @highlighter = name + else + @highlighter = const_get(name) + end + end + end + + module CodeRay + require 'coderay' + require 'coderay/helpers/file_type' + + class << self + # Highlights +text+ as the content of +filename+ + # Should not return line numbers nor outer pre tag + def highlight_by_filename(text, filename) + language = ::CodeRay::FileType[filename] + language ? ::CodeRay.scan(text, language).html : ERB::Util.h(text) + end + + # Highlights +text+ using +language+ syntax + # Should not return outer pre tag + def highlight_by_language(text, language) + ::CodeRay.scan(text, language).html(:line_numbers => :inline, :line_number_anchors => false, :wrap => :span) + end + end + end + end + + SyntaxHighlighting.highlighter = 'CodeRay' +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83898fbb9cd661a21d3a6cb47b1b7d4f0cfb1030.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83898fbb9cd661a21d3a6cb47b1b7d4f0cfb1030.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +class AddVersionsSharing < ActiveRecord::Migration + def self.up + add_column :versions, :sharing, :string, :default => 'none', :null => false + add_index :versions, :sharing + end + + def self.down + remove_column :versions, :sharing + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83a71fa0994c919b743d5f425de3265db363c4cc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83a71fa0994c919b743d5f425de3265db363c4cc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Views + class ApiTemplateHandler < ActionView::TemplateHandler + include ActionView::TemplateHandlers::Compilable + + def compile(template) + "Redmine::Views::Builders.for(params[:format]) do |api|; #{template.source}; self.output_buffer = api.output; end" + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83b13898f7eab0943573424303e9d171d7a1a13a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83b13898f7eab0943573424303e9d171d7a1a13a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class DocumentTest < ActiveSupport::TestCase + fixtures :projects, :enumerations, :documents, :attachments + + def test_create + doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation')) + assert doc.save + end + + def test_create_should_send_email_notification + ActionMailer::Base.deliveries.clear + Setting.notified_events << 'document_added' + doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation')) + + assert doc.save + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_create_with_default_category + # Sets a default category + e = Enumeration.find_by_name('Technical documentation') + e.update_attributes(:is_default => true) + + doc = Document.new(:project => Project.find(1), :title => 'New document') + assert_equal e, doc.category + assert doc.save + end + + def test_updated_on_with_attachments + d = Document.find(1) + assert d.attachments.any? + assert_equal d.attachments.map(&:created_on).max, d.updated_on + end + + def test_updated_on_without_attachments + d = Document.find(2) + assert d.attachments.empty? + assert_equal d.created_on, d.updated_on + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83c3e4ac7042c55f0008c2a13f02fb3cd6cd5e71.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83c3e4ac7042c55f0008c2a13f02fb3cd6cd5e71.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,140 @@ +# Taken from Rails 2.1 +module CollectiveIdea #:nodoc: + module NamedScope #:nodoc: + # All subclasses of ActiveRecord::Base have two named_scopes: + # * all, which is similar to a find(:all) query, and + # * scoped, which allows for the creation of anonymous scopes, on the fly: + # + # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) + # + # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing + # intermediate values (scopes) around as first-class objects is convenient. + def self.included(base) + base.class_eval do + extend ClassMethods + named_scope :scoped, lambda { |scope| scope } + end + end + + module ClassMethods #:nodoc: + def scopes + read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) + end + + # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query, + # such as :conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions. + # + # class Shirt < ActiveRecord::Base + # named_scope :red, :conditions => {:color => 'red'} + # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] + # end + # + # The above calls to named_scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, + # in effect, represents the query Shirt.find(:all, :conditions => {:color => 'red'}). + # + # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object + # constructed by a has_many declaration. For instance, you can invoke Shirt.red.find(:first), Shirt.red.count, + # Shirt.red.find(:all, :conditions => {:size => 'small'}). Also, just + # as with the association objects, name scopes acts like an Array, implementing Enumerable; Shirt.red.each(&block), + # Shirt.red.first, and Shirt.red.inject(memo, &block) all behave as if Shirt.red really were an Array. + # + # These named scopes are composable. For instance, Shirt.red.dry_clean_only will produce all shirts that are both red and dry clean only. + # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments + # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). + # + # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to + # has_many associations. If, + # + # class Person < ActiveRecord::Base + # has_many :shirts + # end + # + # then elton.shirts.red.dry_clean_only will return all of Elton's red, dry clean + # only shirts. + # + # Named scopes can also be procedural. + # + # class Shirt < ActiveRecord::Base + # named_scope :colored, lambda { |color| + # { :conditions => { :color => color } } + # } + # end + # + # In this example, Shirt.colored('puce') finds all puce shirts. + # + # Named scopes can also have extensions, just as with has_many declarations: + # + # class Shirt < ActiveRecord::Base + # named_scope :red, :conditions => {:color => 'red'} do + # def dom_id + # 'red_shirts' + # end + # end + # end + # + # + # For testing complex named scopes, you can examine the scoping options using the + # proxy_options method on the proxy itself. + # + # class Shirt < ActiveRecord::Base + # named_scope :colored, lambda { |color| + # { :conditions => { :color => color } } + # } + # end + # + # expected_options = { :conditions => { :colored => 'red' } } + # assert_equal expected_options, Shirt.colored('red').proxy_options + def named_scope(name, options = {}, &block) + scopes[name] = lambda do |parent_scope, *args| + Scope.new(parent_scope, case options + when Hash + options + when Proc + options.call(*args) + end, &block) + end + (class << self; self end).instance_eval do + define_method name do |*args| + scopes[name].call(self, *args) + end + end + end + end + + class Scope #:nodoc: + attr_reader :proxy_scope, :proxy_options + [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + delegate :scopes, :with_scope, :to => :proxy_scope + + def initialize(proxy_scope, options, &block) + [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] + extend Module.new(&block) if block_given? + @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) + end + + def reload + load_found; self + end + + protected + def proxy_found + @found || load_found + end + + private + def method_missing(method, *args, &block) + if scopes.include?(method) + scopes[method].call(self, *args) + else + with_scope :find => proxy_options do + proxy_scope.send(method, *args, &block) + end + end + end + + def load_found + @found = find(:all) + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/83/83c73b35099a27db995e5d14735edee2b14aac52.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/83/83c73b35099a27db995e5d14735edee2b14aac52.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,79 @@ +--- +messages_001: + created_on: 2007-05-12 17:15:32 +02:00 + updated_on: 2007-05-12 17:15:32 +02:00 + subject: First post + id: 1 + replies_count: 2 + last_reply_id: 3 + content: "This is the very first post\n\ + in the forum" + author_id: 1 + parent_id: + board_id: 1 +messages_002: + created_on: 2007-05-12 17:18:00 +02:00 + updated_on: 2007-05-12 17:18:00 +02:00 + subject: First reply + id: 2 + replies_count: 0 + last_reply_id: + content: "Reply to the first post" + author_id: 1 + parent_id: 1 + board_id: 1 +messages_003: + created_on: 2007-05-12 17:18:02 +02:00 + updated_on: 2007-05-12 17:18:02 +02:00 + subject: "RE: First post" + id: 3 + replies_count: 0 + last_reply_id: + content: "An other reply" + author_id: 2 + parent_id: 1 + board_id: 1 +messages_004: + created_on: 2007-08-12 17:15:32 +02:00 + updated_on: 2007-08-12 17:15:32 +02:00 + subject: Post 2 + id: 4 + replies_count: 2 + last_reply_id: 6 + content: "This is an other post" + author_id: + parent_id: + board_id: 1 +messages_005: + created_on: <%= 3.days.ago.to_date.to_s(:db) %> + updated_on: <%= 3.days.ago.to_date.to_s(:db) %> + subject: 'RE: post 2' + id: 5 + replies_count: 0 + last_reply_id: + content: "Reply to the second post" + author_id: 1 + parent_id: 4 + board_id: 1 +messages_006: + created_on: <%= 2.days.ago.to_date.to_s(:db) %> + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + subject: 'RE: post 2' + id: 6 + replies_count: 0 + last_reply_id: + content: "Another reply to the second post" + author_id: 3 + parent_id: 4 + board_id: 1 +messages_007: + created_on: <%= 2.days.ago.to_date.to_s(:db) %> + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + subject: 'Message on a private project' + id: 7 + replies_count: 0 + last_reply_id: + content: "This is a private message" + author_id: 1 + parent_id: + board_id: 3 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/84/842d236f9067b05ac81fdd2d952a30deb65e8f8c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/84/842d236f9067b05ac81fdd2d952a30deb65e8f8c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1049 @@ +# Swedish translation for Ruby on Rails +# by Johan Lundström (johanlunds@gmail.com), +# with parts taken from http://github.com/daniel/swe_rails + +sv: + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "," + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "." + # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) + precision: 2 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%n %u" + unit: "kr" + # These three are to override number.format and are optional + # separator: "." + # delimiter: "," + # precision: 2 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "kB" + mb: "MB" + gb: "GB" + tb: "TB" + + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "en halv minut" + less_than_x_seconds: + one: "mindre än en sekund" + other: "mindre än %{count} sekunder" + x_seconds: + one: "en sekund" + other: "%{count} sekunder" + less_than_x_minutes: + one: "mindre än en minut" + other: "mindre än %{count} minuter" + x_minutes: + one: "en minut" + other: "%{count} minuter" + about_x_hours: + one: "ungefär en timme" + other: "ungefär %{count} timmar" + x_days: + one: "en dag" + other: "%{count} dagar" + about_x_months: + one: "ungefär en månad" + other: "ungefär %{count} månader" + x_months: + one: "en månad" + other: "%{count} månader" + about_x_years: + one: "ungefär ett år" + other: "ungefär %{count} år" + over_x_years: + one: "mer än ett år" + other: "mer än %{count} år" + almost_x_years: + one: "nästan 1 år" + other: "nästan %{count} år" + + activerecord: + errors: + template: + header: + one: "Ett fel förhindrade denna %{model} från att sparas" + other: "%{count} fel förhindrade denna %{model} från att sparas" + # The variable :count is also available + body: "Det var problem med följande fält:" + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "finns inte i listan" + exclusion: "är reserverat" + invalid: "är ogiltigt" + confirmation: "stämmer inte överens" + accepted : "måste vara accepterad" + empty: "får ej vara tom" + blank: "måste anges" + too_long: "är för lång (maximum är %{count} tecken)" + too_short: "är för kort (minimum är %{count} tecken)" + wrong_length: "har fel längd (ska vara %{count} tecken)" + taken: "har redan tagits" + not_a_number: "är inte ett nummer" + greater_than: "måste vara större än %{count}" + greater_than_or_equal_to: "måste vara större än eller lika med %{count}" + equal_to: "måste vara samma som" + less_than: "måste vara mindre än %{count}" + less_than_or_equal_to: "måste vara mindre än eller lika med %{count}" + odd: "måste vara udda" + even: "måste vara jämnt" + greater_than_start_date: "måste vara senare än startdatumet" + not_same_project: "tillhör inte samma projekt" + circular_dependency: "Denna relation skulle skapa ett cirkulärt beroende" + cant_link_an_issue_with_a_descendant: "Ett ärende kan inte länkas till ett av dess underärenden" + + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%e %b" + long: "%e %B, %Y" + + day_names: [söndag, måndag, tisdag, onsdag, torsdag, fredag, lördag] + abbr_day_names: [sön, mån, tis, ons, tor, fre, lör] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, januari, februari, mars, april, maj, juni, juli, augusti, september, oktober, november, december] + abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%Y-%m-%d %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "" + pm: "" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "och" + skip_last_comma: true + + actionview_instancetag_blank_option: Var god välj + + general_text_No: 'Nej' + general_text_Yes: 'Ja' + general_text_no: 'nej' + general_text_yes: 'ja' + general_lang_name: 'Svenska' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Kontot har uppdaterats + notice_account_invalid_creditentials: Fel användarnamn eller lösenord + notice_account_password_updated: Lösenordet har uppdaterats + notice_account_wrong_password: Fel lösenord + notice_account_register_done: Kontot har skapats. För att aktivera kontot, klicka på länken i mailet som skickades till dig. + notice_account_unknown_email: Okänd användare. + notice_can_t_change_password: Detta konto använder en extern autentiseringskälla. Det går inte att byta lösenord. + notice_account_lost_email_sent: Ett mail med instruktioner om hur man väljer ett nytt lösenord har skickats till dig. + notice_account_activated: Ditt konto har blivit aktiverat. Du kan nu logga in. + notice_successful_create: Skapades korrekt. + notice_successful_update: Uppdatering lyckades. + notice_successful_delete: Borttagning lyckades. + notice_successful_connection: Uppkoppling lyckades. + notice_file_not_found: Sidan du försökte komma åt existerar inte eller är borttagen. + notice_locking_conflict: Data har uppdaterats av en annan användare. + notice_not_authorized: Du saknar behörighet att komma åt den här sidan. + notice_not_authorized_archived_project: Projektet du försöker komma åt har arkiverats. + notice_email_sent: "Ett mail skickades till %{value}" + notice_email_error: "Ett fel inträffade när mail skickades (%{value})" + notice_feeds_access_key_reseted: Din RSS-nyckel återställdes. + notice_api_access_key_reseted: Din API-nyckel återställdes. + notice_failed_to_save_issues: "Misslyckades med att spara %{count} ärende(n) på %{total} valt: %{ids}." + notice_failed_to_save_members: "Misslyckades med att spara medlem(mar): %{errors}." + notice_no_issue_selected: "Inget ärende är markerat! Var vänlig, markera de ärenden du vill ändra." + notice_account_pending: "Ditt konto skapades och avvaktar nu administratörens godkännande." + notice_default_data_loaded: Standardkonfiguration inläst. + notice_unable_delete_version: Denna version var inte möjlig att ta bort. + notice_unable_delete_time_entry: Tidloggning kunde inte tas bort. + notice_issue_done_ratios_updated: "% klart uppdaterade." + notice_gantt_chart_truncated: "Schemat förminskades eftersom det överskrider det maximala antalet aktiviteter som får visas (%{max})" + notice_issue_successful_create: Ärende %{id} skapades. + + error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %{value}" + error_scm_not_found: "Inlägg och/eller revision finns inte i detta versionsarkiv." + error_scm_command_failed: "Ett fel inträffade vid försök att nå versionsarkivet: %{value}" + error_scm_annotate: "Inlägget existerar inte eller kan inte kommenteras." + error_issue_not_found_in_project: 'Ärendet hittades inte eller så tillhör det inte detta projekt' + error_no_tracker_in_project: 'Ingen ärendetyp är associerad med projektet. Vänligen kontrollera projektinställningarna.' + error_no_default_issue_status: 'Ingen status är definierad som standard för nya ärenden. Vänligen kontrollera din konfiguration (Gå till "Administration -> Ärendestatus").' + error_can_not_delete_custom_field: Kan inte ta bort användardefinerat fält + error_can_not_delete_tracker: "Det finns ärenden av denna typ och den är därför inte möjlig att ta bort." + error_can_not_remove_role: "Denna roll används och den är därför inte möjlig att ta bort." + error_can_not_reopen_issue_on_closed_version: 'Ett ärende tilldelat en stängd version kan inte öppnas på nytt' + error_can_not_archive_project: Detta projekt kan inte arkiveras + error_issue_done_ratios_not_updated: "% klart inte uppdaterade." + error_workflow_copy_source: 'Vänligen välj källans ärendetyp eller roll' + error_workflow_copy_target: 'Vänligen välj ärendetyp(er) och roll(er) för mål' + error_unable_delete_issue_status: 'Ärendestatus kunde inte tas bort' + error_unable_to_connect: "Kan inte ansluta (%{value})" + + warning_attachments_not_saved: "%{count} fil(er) kunde inte sparas." + + mail_subject_lost_password: "Ditt %{value} lösenord" + mail_body_lost_password: 'För att ändra ditt lösenord, klicka på följande länk:' + mail_subject_register: "Din %{value} kontoaktivering" + mail_body_register: 'För att aktivera ditt konto, klicka på följande länk:' + mail_body_account_information_external: "Du kan använda ditt %{value}-konto för att logga in." + mail_body_account_information: Din kontoinformation + mail_subject_account_activation_request: "%{value} begäran om kontoaktivering" + mail_body_account_activation_request: "En ny användare (%{value}) har registrerat sig och avvaktar ditt godkännande:" + mail_subject_reminder: "%{count} ärende(n) har deadline under de kommande %{days} dagarna" + mail_body_reminder: "%{count} ärende(n) som är tilldelat dig har deadline under de %{days} dagarna:" + mail_subject_wiki_content_added: "'%{id}' wikisida has lagts till" + mail_body_wiki_content_added: "The '%{id}' wikisida has lagts till av %{author}." + mail_subject_wiki_content_updated: "'%{id}' wikisida har uppdaterats" + mail_body_wiki_content_updated: "The '%{id}' wikisida har uppdaterats av %{author}." + + gui_validation_error: 1 fel + gui_validation_error_plural: "%{count} fel" + + field_name: Namn + field_description: Beskrivning + field_summary: Sammanfattning + field_is_required: Obligatorisk + field_firstname: Förnamn + field_lastname: Efternamn + field_mail: Mail + field_filename: Fil + field_filesize: Storlek + field_downloads: Nerladdningar + field_author: Författare + field_created_on: Skapad + field_updated_on: Uppdaterad + field_field_format: Format + field_is_for_all: För alla projekt + field_possible_values: Möjliga värden + field_regexp: Reguljärt uttryck + field_min_length: Minimilängd + field_max_length: Maxlängd + field_value: Värde + field_category: Kategori + field_title: Titel + field_project: Projekt + field_issue: Ärende + field_status: Status + field_notes: Anteckningar + field_is_closed: Ärendet är stängt + field_is_default: Standardvärde + field_tracker: Ärendetyp + field_subject: Ämne + field_due_date: Deadline + field_assigned_to: Tilldelad till + field_priority: Prioritet + field_fixed_version: Versionsmål + field_user: Användare + field_principal: Principal + field_role: Roll + field_homepage: Hemsida + field_is_public: Publik + field_parent: Underprojekt till + field_is_in_roadmap: Visa ärenden i roadmap + field_login: Användarnamn + field_mail_notification: Mailnotifieringar + field_admin: Administratör + field_last_login_on: Senaste inloggning + field_language: Språk + field_effective_date: Datum + field_password: Lösenord + field_new_password: Nytt lösenord + field_password_confirmation: Bekräfta lösenord + field_version: Version + field_type: Typ + field_host: Värddator + field_port: Port + field_account: Konto + field_base_dn: Bas-DN + field_attr_login: Inloggningsattribut + field_attr_firstname: Förnamnsattribut + field_attr_lastname: Efternamnsattribut + field_attr_mail: Mailattribut + field_onthefly: Skapa användare on-the-fly + field_start_date: Startdatum + field_done_ratio: "% Klart" + field_auth_source: Autentiseringsläge + field_hide_mail: Dölj min mailadress + field_comments: Kommentar + field_url: URL + field_start_page: Startsida + field_subproject: Underprojekt + field_hours: Timmar + field_activity: Aktivitet + field_spent_on: Datum + field_identifier: Identifierare + field_is_filter: Använd som filter + field_issue_to: Relaterade ärenden + field_delay: Fördröjning + field_assignable: Ärenden kan tilldelas denna roll + field_redirect_existing_links: Omdirigera existerande länkar + field_estimated_hours: Estimerad tid + field_column_names: Kolumner + field_time_entries: Spenderad tid + field_time_zone: Tidszon + field_searchable: Sökbar + field_default_value: Standardvärde + field_comments_sorting: Visa kommentarer + field_parent_title: Föräldersida + field_editable: Redigerbar + field_watcher: Bevakare + field_identity_url: OpenID URL + field_content: Innehåll + field_group_by: Gruppera resultat efter + field_sharing: Delning + field_parent_issue: Förälderaktivitet + field_member_of_group: "Tilldelad användares grupp" + field_assigned_to_role: "Tilldelad användares roll" + field_text: Textfält + field_visible: Synlig + field_warn_on_leaving_unsaved: Varna om jag lämnar en sida med osparad text + field_issues_visibility: Ärendesynlighet + field_is_private: Privat + field_commit_logs_encoding: Teckenuppsättning för commit-meddelanden + field_scm_path_encoding: Sökvägskodning + field_path_to_repository: Sökväg till versionsarkiv + field_root_directory: Rotmapp + field_cvsroot: CVSROOT + field_cvs_module: Modul + + setting_app_title: Applikationsrubrik + setting_app_subtitle: Applikationsunderrubrik + setting_welcome_text: Välkomsttext + setting_default_language: Standardspråk + setting_login_required: Kräver inloggning + setting_self_registration: Självregistrering + setting_attachment_max_size: Maxstorlek på bilaga + setting_issues_export_limit: Exportgräns för ärenden + setting_mail_from: Avsändaradress + setting_bcc_recipients: Hemlig kopia (bcc) till mottagare + setting_plain_text_mail: Oformaterad text i mail (ingen HTML) + setting_host_name: Värddatornamn + setting_text_formatting: Textformatering + setting_wiki_compression: Komprimering av wikihistorik + setting_feeds_limit: Innehållsgräns för Feed + setting_default_projects_public: Nya projekt är publika + setting_autofetch_changesets: Automatisk hämtning av commits + setting_sys_api_enabled: Aktivera WS för versionsarkivhantering + setting_commit_ref_keywords: Referens-nyckelord + setting_commit_fix_keywords: Fix-nyckelord + setting_autologin: Automatisk inloggning + setting_date_format: Datumformat + setting_time_format: Tidsformat + setting_cross_project_issue_relations: Tillåt ärenderelationer mellan projekt + setting_issue_list_default_columns: Standardkolumner i ärendelistan + setting_emails_header: Mail-header + setting_emails_footer: Signatur + setting_protocol: Protokoll + setting_per_page_options: Alternativ, objekt per sida + setting_user_format: Visningsformat för användare + setting_activity_days_default: Dagar som visas på projektaktivitet + setting_display_subprojects_issues: Visa ärenden från underprojekt i huvudprojekt + setting_enabled_scm: Aktivera SCM + setting_mail_handler_body_delimiters: "Trunkera mail efter en av följande rader" + setting_mail_handler_api_enabled: Aktivera WS för inkommande mail + setting_mail_handler_api_key: API-nyckel + setting_sequential_project_identifiers: Generera projektidentifierare sekventiellt + setting_gravatar_enabled: Använd Gravatar-avatarer + setting_gravatar_default: Förvald Gravatar-bild + setting_diff_max_lines_displayed: Maximalt antal synliga rader i diff + setting_file_max_size_displayed: Maxstorlek på textfiler som visas inline + setting_repository_log_display_limit: Maximalt antal revisioner i filloggen + setting_openid: Tillåt inloggning och registrering med OpenID + setting_password_min_length: Minsta tillåtna lösenordslängd + setting_new_project_user_role_id: Tilldelad roll för en icke-administratör som skapar ett projekt + setting_default_projects_modules: Aktiverade moduler för nya projekt + setting_issue_done_ratio: Beräkna % klart med + setting_issue_done_ratio_issue_field: Använd ärendefältet + setting_issue_done_ratio_issue_status: Använd ärendestatus + setting_start_of_week: Första dagen i veckan + setting_rest_api_enabled: Aktivera REST webbtjänst + setting_cache_formatted_text: Cacha formaterad text + setting_default_notification_option: Standard notifieringsalternativ + setting_commit_logtime_enabled: Aktivera tidloggning + setting_commit_logtime_activity_id: Aktivitet för loggad tid + setting_gantt_items_limit: Maximalt antal aktiviteter som visas i gantt-schemat + setting_issue_group_assignment: Tillåt att ärenden tilldelas till grupper + + permission_add_project: Skapa projekt + permission_add_subprojects: Skapa underprojekt + permission_edit_project: Ändra projekt + permission_select_project_modules: Välja projektmoduler + permission_manage_members: Hantera medlemmar + permission_manage_project_activities: Hantera projektaktiviteter + permission_manage_versions: Hantera versioner + permission_manage_categories: Hantera ärendekategorier + permission_add_issues: Lägga till ärenden + permission_edit_issues: Ändra ärenden + permission_view_issues: Visa ärenden + permission_manage_issue_relations: Hantera ärenderelationer + permission_set_issues_private: Sätta ärenden publika eller privata + permission_set_own_issues_private: Sätta egna ärenden publika eller privata + permission_add_issue_notes: Lägga till ärendenotering + permission_edit_issue_notes: Ändra ärendenoteringar + permission_edit_own_issue_notes: Ändra egna ärendenoteringar + permission_move_issues: Flytta ärenden + permission_delete_issues: Ta bort ärenden + permission_manage_public_queries: Hantera publika frågor + permission_save_queries: Spara frågor + permission_view_gantt: Visa Gantt-schema + permission_view_calendar: Visa kalender + permission_view_issue_watchers: Visa bevakarlista + permission_add_issue_watchers: Lägga till bevakare + permission_delete_issue_watchers: Ta bort bevakare + permission_log_time: Logga spenderad tid + permission_view_time_entries: Visa spenderad tid + permission_edit_time_entries: Ändra tidloggningar + permission_edit_own_time_entries: Ändra egna tidloggningar + permission_manage_news: Hantera nyheter + permission_comment_news: Kommentera nyheter + permission_manage_documents: Hantera dokument + permission_view_documents: Visa dokument + permission_manage_files: Hantera filer + permission_view_files: Visa filer + permission_manage_wiki: Hantera wiki + permission_rename_wiki_pages: Byta namn på wikisidor + permission_delete_wiki_pages: Ta bort wikisidor + permission_view_wiki_pages: Visa wiki + permission_view_wiki_edits: Visa wikihistorik + permission_edit_wiki_pages: Ändra wikisidor + permission_delete_wiki_pages_attachments: Ta bort bilagor + permission_protect_wiki_pages: Skydda wikisidor + permission_manage_repository: Hantera versionsarkiv + permission_browse_repository: Bläddra i versionsarkiv + permission_view_changesets: Visa changesets + permission_commit_access: Commit-åtkomst + permission_manage_boards: Hantera forum + permission_view_messages: Visa meddelanden + permission_add_messages: Lägg till meddelanden + permission_edit_messages: Ändra meddelanden + permission_edit_own_messages: Ändra egna meddelanden + permission_delete_messages: Ta bort meddelanden + permission_delete_own_messages: Ta bort egna meddelanden + permission_export_wiki_pages: Exportera wikisidor + permission_manage_subtasks: Hantera underaktiviteter + + project_module_issue_tracking: Ärendeuppföljning + project_module_time_tracking: Tidsuppföljning + project_module_news: Nyheter + project_module_documents: Dokument + project_module_files: Filer + project_module_wiki: Wiki + project_module_repository: Versionsarkiv + project_module_boards: Forum + project_module_calendar: Kalender + project_module_gantt: Gantt + + label_user: Användare + label_user_plural: Användare + label_user_new: Ny användare + label_user_anonymous: Anonym + label_project: Projekt + label_project_new: Nytt projekt + label_project_plural: Projekt + label_x_projects: + zero: inga projekt + one: 1 projekt + other: "%{count} projekt" + label_project_all: Alla projekt + label_project_latest: Senaste projekt + label_issue: Ärende + label_issue_new: Nytt ärende + label_issue_plural: Ärenden + label_issue_view_all: Visa alla ärenden + label_issues_by: "Ärenden %{value}" + label_issue_added: Ärende tillagt + label_issue_updated: Ärende uppdaterat + label_issue_note_added: Anteckning tillagd + label_issue_status_updated: Status uppdaterad + label_issue_priority_updated: Prioritet uppdaterad + label_document: Dokument + label_document_new: Nytt dokument + label_document_plural: Dokument + label_document_added: Dokument tillagt + label_role: Roll + label_role_plural: Roller + label_role_new: Ny roll + label_role_and_permissions: Roller och behörigheter + label_role_anonymous: Anonym + label_role_non_member: Icke-medlem + label_member: Medlem + label_member_new: Ny medlem + label_member_plural: Medlemmar + label_tracker: Ärendetyp + label_tracker_plural: Ärendetyper + label_tracker_new: Ny ärendetyp + label_workflow: Arbetsflöde + label_issue_status: Ärendestatus + label_issue_status_plural: Ärendestatus + label_issue_status_new: Ny status + label_issue_category: Ärendekategori + label_issue_category_plural: Ärendekategorier + label_issue_category_new: Ny kategori + label_custom_field: Användardefinerat fält + label_custom_field_plural: Användardefinerade fält + label_custom_field_new: Nytt användardefinerat fält + label_enumerations: Uppräkningar + label_enumeration_new: Nytt värde + label_information: Information + label_information_plural: Information + label_please_login: Var god logga in + label_register: Registrera + label_login_with_open_id_option: eller logga in med OpenID + label_password_lost: Glömt lösenord + label_home: Hem + label_my_page: Min sida + label_my_account: Mitt konto + label_my_projects: Mina projekt + label_my_page_block: '"Min sida"-block' + label_administration: Administration + label_login: Logga in + label_logout: Logga ut + label_help: Hjälp + label_reported_issues: Rapporterade ärenden + label_assigned_to_me_issues: Ärenden tilldelade till mig + label_last_login: Senaste inloggning + label_registered_on: Registrerad + label_activity: Aktivitet + label_overall_activity: All aktivitet + label_user_activity: "Aktiviteter för %{value}" + label_new: Ny + label_logged_as: Inloggad som + label_environment: Miljö + label_authentication: Autentisering + label_auth_source: Autentiseringsläge + label_auth_source_new: Nytt autentiseringsläge + label_auth_source_plural: Autentiseringslägen + label_subproject_plural: Underprojekt + label_subproject_new: Nytt underprojekt + label_and_its_subprojects: "%{value} och dess underprojekt" + label_min_max_length: Min./Max.-längd + label_list: Lista + label_date: Datum + label_integer: Heltal + label_float: Flyttal + label_boolean: Boolean + label_string: Text + label_text: Lång text + label_attribute: Attribut + label_attribute_plural: Attribut + label_download: "%{count} Nerladdning" + label_download_plural: "%{count} Nerladdningar" + label_no_data: Ingen data att visa + label_change_status: Ändra status + label_history: Historia + label_attachment: Fil + label_attachment_new: Ny fil + label_attachment_delete: Ta bort fil + label_attachment_plural: Filer + label_file_added: Fil tillagd + label_report: Rapport + label_report_plural: Rapporter + label_news: Nyhet + label_news_new: Lägg till nyhet + label_news_plural: Nyheter + label_news_latest: Senaste nyheterna + label_news_view_all: Visa alla nyheter + label_news_added: Nyhet tillagd + label_news_comment_added: Kommentar tillagd till en nyhet + label_settings: Inställningar + label_overview: Översikt + label_version: Version + label_version_new: Ny version + label_version_plural: Versioner + label_close_versions: Stäng klara versioner + label_confirmation: Bekräftelse + label_export_to: 'Finns även som:' + label_read: Läs... + label_public_projects: Publika projekt + label_open_issues: öppen + label_open_issues_plural: öppna + label_closed_issues: stängd + label_closed_issues_plural: stängda + label_x_open_issues_abbr_on_total: + zero: 0 öppna av %{total} + one: 1 öppen av %{total} + other: "%{count} öppna av %{total}" + label_x_open_issues_abbr: + zero: 0 öppna + one: 1 öppen + other: "%{count} öppna" + label_x_closed_issues_abbr: + zero: 0 stängda + one: 1 stängd + other: "%{count} stängda" + label_total: Total + label_permissions: Behörigheter + label_current_status: Nuvarande status + label_new_statuses_allowed: Nya tillåtna statusvärden + label_all: alla + label_none: ingen + label_nobody: ingen + label_next: Nästa + label_previous: Föregående + label_used_by: Använd av + label_details: Detaljer + label_add_note: Lägg till anteckning + label_per_page: Per sida + label_calendar: Kalender + label_months_from: månader från + label_gantt: Gantt + label_internal: Intern + label_last_changes: "senaste %{count} ändringar" + label_change_view_all: Visa alla ändringar + label_personalize_page: Anpassa denna sida + label_comment: Kommentar + label_comment_plural: Kommentarer + label_x_comments: + zero: inga kommentarer + one: 1 kommentar + other: "%{count} kommentarer" + label_comment_add: Lägg till kommentar + label_comment_added: Kommentar tillagd + label_comment_delete: Ta bort kommentar + label_query: Användardefinerad fråga + label_query_plural: Användardefinerade frågor + label_query_new: Ny fråga + label_my_queries: Mina egna frågor + label_filter_add: Lägg till filter + label_filter_plural: Filter + label_equals: är + label_not_equals: är inte + label_in_less_than: om mindre än + label_in_more_than: om mer än + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_between: mellan + label_in: om + label_today: idag + label_all_time: närsom + label_yesterday: igår + label_this_week: denna vecka + label_last_week: senaste veckan + label_last_n_days: "senaste %{count} dagarna" + label_this_month: denna månad + label_last_month: senaste månaden + label_this_year: detta året + label_date_range: Datumintervall + label_less_than_ago: mindre än dagar sedan + label_more_than_ago: mer än dagar sedan + label_ago: dagar sedan + label_contains: innehåller + label_not_contains: innehåller inte + label_day_plural: dagar + label_repository: Versionsarkiv + label_repository_plural: Versionsarkiv + label_browse: Bläddra + label_modification: "%{count} ändring" + label_modification_plural: "%{count} ändringar" + label_branch: Branch + label_tag: Tag + label_revision: Revision + label_revision_plural: Revisioner + label_revision_id: "Revision %{value}" + label_associated_revisions: Associerade revisioner + label_added: tillagd + label_modified: modifierad + label_copied: kopierad + label_renamed: omdöpt + label_deleted: borttagen + label_latest_revision: Senaste revisionen + label_latest_revision_plural: Senaste revisionerna + label_view_revisions: Visa revisioner + label_view_all_revisions: Visa alla revisioner + label_max_size: Maxstorlek + label_sort_highest: Flytta till toppen + label_sort_higher: Flytta upp + label_sort_lower: Flytta ner + label_sort_lowest: Flytta till botten + label_roadmap: Roadmap + label_roadmap_due_in: "Färdig om %{value}" + label_roadmap_overdue: "%{value} sen" + label_roadmap_no_issues: Inga ärenden för denna version + label_search: Sök + label_result_plural: Resultat + label_all_words: Alla ord + label_wiki: Wiki + label_wiki_edit: Wikiändring + label_wiki_edit_plural: Wikiändringar + label_wiki_page: Wikisida + label_wiki_page_plural: Wikisidor + label_index_by_title: Innehåll efter titel + label_index_by_date: Innehåll efter datum + label_current_version: Nuvarande version + label_preview: Förhandsgranska + label_feed_plural: Feeds + label_changes_details: Detaljer om alla ändringar + label_issue_tracking: Ärendeuppföljning + label_spent_time: Spenderad tid + label_overall_spent_time: Total tid spenderad + label_f_hour: "%{value} timme" + label_f_hour_plural: "%{value} timmar" + label_time_tracking: Tidsuppföljning + label_change_plural: Ändringar + label_statistics: Statistik + label_commits_per_month: Commits per månad + label_commits_per_author: Commits per författare + label_view_diff: Visa skillnader + label_diff_inline: i texten + label_diff_side_by_side: sida vid sida + label_options: Inställningar + label_copy_workflow_from: Kopiera arbetsflöde från + label_permissions_report: Behörighetsrapport + label_watched_issues: Bevakade ärenden + label_related_issues: Relaterade ärenden + label_applied_status: Tilldelad status + label_loading: Laddar... + label_relation_new: Ny relation + label_relation_delete: Ta bort relation + label_relates_to: relaterar till + label_duplicates: kopierar + label_duplicated_by: kopierad av + label_blocks: blockerar + label_blocked_by: blockerad av + label_precedes: kommer före + label_follows: följer + label_end_to_start: slut till start + label_end_to_end: slut till slut + label_start_to_start: start till start + label_start_to_end: start till slut + label_stay_logged_in: Förbli inloggad + label_disabled: inaktiverad + label_show_completed_versions: Visa färdiga versioner + label_me: mig + label_board: Forum + label_board_new: Nytt forum + label_board_plural: Forum + label_board_locked: Låst + label_board_sticky: Sticky + label_topic_plural: Ämnen + label_message_plural: Meddelanden + label_message_last: Senaste meddelande + label_message_new: Nytt meddelande + label_message_posted: Meddelande tillagt + label_reply_plural: Svar + label_send_information: Skicka kontoinformation till användaren + label_year: År + label_month: Månad + label_week: Vecka + label_date_from: Från + label_date_to: Till + label_language_based: Språkbaserad + label_sort_by: "Sortera på %{value}" + label_send_test_email: Skicka testmail + label_feeds_access_key: RSS-nyckel + label_missing_feeds_access_key: Saknar en RSS-nyckel + label_feeds_access_key_created_on: "RSS-nyckel skapad för %{value} sedan" + label_module_plural: Moduler + label_added_time_by: "Tillagd av %{author} för %{age} sedan" + label_updated_time_by: "Uppdaterad av %{author} för %{age} sedan" + label_updated_time: "Uppdaterad för %{value} sedan" + label_jump_to_a_project: Gå till projekt... + label_file_plural: Filer + label_changeset_plural: Changesets + label_default_columns: Standardkolumner + label_no_change_option: (Ingen ändring) + label_bulk_edit_selected_issues: Gemensam ändring av markerade ärenden + label_bulk_edit_selected_time_entries: Gruppredigera valda tidloggningar + label_theme: Tema + label_default: Standard + label_search_titles_only: Sök endast i titlar + label_user_mail_option_all: "För alla händelser i mina projekt" + label_user_mail_option_selected: "För alla händelser i markerade projekt..." + label_user_mail_option_none: "Inga händelser" + label_user_mail_option_only_my_events: "Endast för saker jag bevakar eller är inblandad i" + label_user_mail_option_only_assigned: "Endast för saker jag är tilldelad" + label_user_mail_option_only_owner: "Endast för saker jag äger" + label_user_mail_no_self_notified: "Jag vill inte bli underrättad om ändringar som jag har gjort" + label_registration_activation_by_email: kontoaktivering med mail + label_registration_manual_activation: manuell kontoaktivering + label_registration_automatic_activation: automatisk kontoaktivering + label_display_per_page: "Per sida: %{value}" + label_age: Ålder + label_change_properties: Ändra inställningar + label_general: Allmänt + label_more: Mer + label_scm: SCM + label_plugins: Tillägg + label_ldap_authentication: LDAP-autentisering + label_downloads_abbr: Nerl. + label_optional_description: Valfri beskrivning + label_add_another_file: Lägg till ytterligare en fil + label_preferences: Användarinställningar + label_chronological_order: I kronologisk ordning + label_reverse_chronological_order: I omvänd kronologisk ordning + label_planning: Planering + label_incoming_emails: Inkommande mail + label_generate_key: Generera en nyckel + label_issue_watchers: Bevakare + label_example: Exempel + label_display: Visa + label_sort: Sortera + label_descending: Fallande + label_ascending: Stigande + label_date_from_to: Från %{start} till %{end} + label_wiki_content_added: Wikisida tillagd + label_wiki_content_updated: Wikisida uppdaterad + label_group: Grupp + label_group_plural: Grupper + label_group_new: Ny grupp + label_time_entry_plural: Spenderad tid + label_version_sharing_none: Inte delad + label_version_sharing_descendants: Med underprojekt + label_version_sharing_hierarchy: Med projekthierarki + label_version_sharing_tree: Med projektträd + label_version_sharing_system: Med alla projekt + label_update_issue_done_ratios: Uppdatera % klart + label_copy_source: Källa + label_copy_target: Mål + label_copy_same_as_target: Samma som mål + label_display_used_statuses_only: Visa endast status som används av denna ärendetyp + label_api_access_key: API-nyckel + label_missing_api_access_key: Saknar en API-nyckel + label_api_access_key_created_on: "API-nyckel skapad för %{value} sedan" + label_profile: Profil + label_subtask_plural: Underaktiviteter + label_project_copy_notifications: Skicka mailnotifieringar när projektet kopieras + label_principal_search: "Sök efter användare eller grupp:" + label_user_search: "Sök efter användare:" + label_additional_workflow_transitions_for_author: Ytterligare övergångar tillåtna när användaren är den som skapat ärendet + label_additional_workflow_transitions_for_assignee: Ytterligare övergångar tillåtna när användaren är den som tilldelats ärendet + label_issues_visibility_all: Alla ärenden + label_issues_visibility_public: Alla icke-privata ärenden + label_issues_visibility_own: Ärenden skapade av eller tilldelade till användaren + label_git_report_last_commit: Rapportera senaste commit av filer och mappar + + button_login: Logga in + button_submit: Skicka + button_save: Spara + button_check_all: Markera alla + button_uncheck_all: Avmarkera alla + button_collapse_all: Kollapsa alla + button_expand_all: Expandera alla + button_delete: Ta bort + button_create: Skapa + button_create_and_continue: Skapa och fortsätt + button_test: Testa + button_edit: Ändra + button_edit_associated_wikipage: "Ändra associerad Wikisida: %{page_title}" + button_add: Lägg till + button_change: Ändra + button_apply: Verkställ + button_clear: Återställ + button_lock: Lås + button_unlock: Lås upp + button_download: Ladda ner + button_list: Lista + button_view: Visa + button_move: Flytta + button_move_and_follow: Flytta och följ efter + button_back: Tillbaka + button_cancel: Avbryt + button_activate: Aktivera + button_sort: Sortera + button_log_time: Logga tid + button_rollback: Återställ till denna version + button_watch: Bevaka + button_unwatch: Stoppa bevakning + button_reply: Svara + button_archive: Arkivera + button_unarchive: Ta bort från arkiv + button_reset: Återställ + button_rename: Byt namn + button_change_password: Ändra lösenord + button_copy: Kopiera + button_copy_and_follow: Kopiera och följ efter + button_annotate: Kommentera + button_update: Uppdatera + button_configure: Konfigurera + button_quote: Citera + button_duplicate: Duplicera + button_show: Visa + + status_active: aktiv + status_registered: registrerad + status_locked: låst + + version_status_open: öppen + version_status_locked: låst + version_status_closed: stängd + + field_active: Aktiv + + text_select_mail_notifications: Välj för vilka händelser mail ska skickas. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 betyder ingen gräns + text_project_destroy_confirmation: Är du säker på att du vill ta bort detta projekt och all relaterad data? + text_subprojects_destroy_warning: "Alla underprojekt: %{value} kommer också tas bort." + text_workflow_edit: Välj en roll och en ärendetyp för att ändra arbetsflöde + text_are_you_sure: Är du säker ? + text_are_you_sure_with_children: Ta bort ärende och alla underärenden? + text_journal_changed: "%{label} ändrad från %{old} till %{new}" + text_journal_changed_no_detail: "%{label} uppdaterad" + text_journal_set_to: "%{label} satt till %{value}" + text_journal_deleted: "%{label} borttagen (%{old})" + text_journal_added: "%{label} %{value} tillagd" + text_tip_issue_begin_day: ärende som börjar denna dag + text_tip_issue_end_day: ärende som slutar denna dag + text_tip_issue_begin_end_day: ärende som börjar och slutar denna dag + text_project_identifier_info: 'Små bokstäver (a-z), siffror och streck tillåtna.
    När den är sparad kan identifieraren inte ändras.' + text_caracters_maximum: "max %{count} tecken." + text_caracters_minimum: "Måste vara minst %{count} tecken lång." + text_length_between: "Längd mellan %{min} och %{max} tecken." + text_tracker_no_workflow: Inget arbetsflöde definerat för denna ärendetyp + text_unallowed_characters: Otillåtna tecken + text_comma_separated: Flera värden tillåtna (kommaseparerade). + text_line_separated: Flera värden tillåtna (ett värde per rad). + text_issues_ref_in_commit_messages: Referera och fixa ärenden i commit-meddelanden + text_issue_added: "Ärende %{id} har rapporterats (av %{author})." + text_issue_updated: "Ärende %{id} har uppdaterats (av %{author})." + text_wiki_destroy_confirmation: Är du säker på att du vill ta bort denna wiki och allt dess innehåll ? + text_issue_category_destroy_question: "Några ärenden (%{count}) är tilldelade till denna kategori. Vad vill du göra ?" + text_issue_category_destroy_assignments: Ta bort kategoritilldelningar + text_issue_category_reassign_to: Återtilldela ärenden till denna kategori + text_user_mail_option: "För omarkerade projekt kommer du bara bli underrättad om saker du bevakar eller är inblandad i (T.ex. ärenden du skapat eller tilldelats)." + text_no_configuration_data: "Roller, ärendetyper, ärendestatus och arbetsflöden har inte konfigurerats ännu.\nDet rekommenderas att läsa in standardkonfigurationen. Du kommer att kunna göra ändringar efter att den blivit inläst." + text_load_default_configuration: Läs in standardkonfiguration + text_status_changed_by_changeset: "Tilldelad i changeset %{value}." + text_time_logged_by_changeset: "Tilldelad i changeset %{value}." + text_issues_destroy_confirmation: 'Är du säker på att du vill radera markerade ärende(n) ?' + text_issues_destroy_descendants_confirmation: Detta kommer även ta bort %{count} underaktivitet(er). + text_time_entries_destroy_confirmation: Är du säker på att du vill ta bort valda tidloggningar? + text_select_project_modules: 'Välj vilka moduler som ska vara aktiva för projektet:' + text_default_administrator_account_changed: Standardadministratörens konto ändrat + text_file_repository_writable: Arkivet för bifogade filer är skrivbart + text_plugin_assets_writable: Arkivet för plug-ins är skrivbart + text_rmagick_available: RMagick tillgängligt (ej obligatoriskt) + text_destroy_time_entries_question: "%{hours} timmar har rapporterats på ärendena du är på väg att ta bort. Vad vill du göra ?" + text_destroy_time_entries: Ta bort rapporterade timmar + text_assign_time_entries_to_project: Tilldela rapporterade timmar till projektet + text_reassign_time_entries: 'Återtilldela rapporterade timmar till detta ärende:' + text_user_wrote: "%{value} skrev:" + text_enumeration_destroy_question: "%{count} objekt är tilldelade till detta värde." + text_enumeration_category_reassign_to: 'Återtilldela till detta värde:' + text_email_delivery_not_configured: "Mailfunktionen har inte konfigurerats, och notifieringar via mail kan därför inte skickas.\nKonfigurera din SMTP-server i config/configuration.yml och starta om applikationen för att aktivera dem." + text_repository_usernames_mapping: "Välj eller uppdatera den Redmine-användare som är mappad till varje användarnamn i versionarkivloggen.\nAnvändare med samma användarnamn eller mailadress i både Redmine och versionsarkivet mappas automatiskt." + text_diff_truncated: '... Denna diff har förminskats eftersom den överskrider den maximala storlek som kan visas.' + text_custom_field_possible_values_info: 'Ett värde per rad' + text_wiki_page_destroy_question: "Denna sida har %{descendants} underliggande sidor. Vad vill du göra?" + text_wiki_page_nullify_children: "Behåll undersidor som rotsidor" + text_wiki_page_destroy_children: "Ta bort alla underliggande sidor" + text_wiki_page_reassign_children: "Flytta undersidor till denna föräldersida" + text_own_membership_delete_confirmation: "Några av, eller alla, dina behörigheter kommer att tas bort och du kanske inte längre kommer kunna göra ändringar i det här projektet.\nVill du verkligen fortsätta?" + text_zoom_out: Zooma ut + text_zoom_in: Zooma in + text_warn_on_leaving_unsaved: Nuvarande sida innehåller osparad text som kommer försvinna om du lämnar sidan. + text_scm_path_encoding_note: "Standard: UTF-8" + text_mercurial_repository_note: Lokalt versionsarkiv (t.ex. /hgrepo, c:\hgrepo) + text_scm_command: Kommando + text_scm_command_version: Version + text_scm_config: Du kan konfigurera dina scm-kommando i config/configuration.yml. Vänligen starta om applikationen när ändringar gjorts. + text_scm_command_not_available: Scm-kommando är inte tillgängligt. Vänligen kontrollera inställningarna i administratörspanelen. + + default_role_manager: Projektledare + default_role_developer: Utvecklare + default_role_reporter: Rapportör + default_tracker_bug: Bugg + default_tracker_feature: Funktionalitet + default_tracker_support: Support + default_issue_status_new: Ny + default_issue_status_in_progress: Pågår + default_issue_status_resolved: Löst + default_issue_status_feedback: Återkoppling + default_issue_status_closed: Stängd + default_issue_status_rejected: Avslagen + default_doc_category_user: Användardokumentation + default_doc_category_tech: Teknisk dokumentation + default_priority_low: Låg + default_priority_normal: Normal + default_priority_high: Hög + default_priority_urgent: Brådskande + default_priority_immediate: Omedelbar + default_activity_design: Design + default_activity_development: Utveckling + + enumeration_issue_priorities: Ärendeprioriteter + enumeration_doc_categories: Dokumentkategorier + enumeration_activities: Aktiviteter (tidsuppföljning) + enumeration_system_activity: Systemaktivitet + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/84/842d23caf63cf174cbb0a8bccbdb2b32e5fa17e5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/84/842d23caf63cf174cbb0a8bccbdb2b32e5fa17e5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,248 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sat, 21 Jun 2008 15:53:25 +0200 +Message-ID: <002301c8d3a6$2cdf6950$0a00a8c0@osiris> +From: "John Smith" +To: +Subject: Ticket created by email with attachment +Date: Sat, 21 Jun 2008 15:53:25 +0200 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_001F_01C8D3B6.F05C5270" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +This is a multi-part message in MIME format. + +------=_NextPart_000_001F_01C8D3B6.F05C5270 +Content-Type: multipart/alternative; + boundary="----=_NextPart_001_0020_01C8D3B6.F05C5270" + + +------=_NextPart_001_0020_01C8D3B6.F05C5270 +Content-Type: text/plain; + charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable + +This is a new ticket with attachments +------=_NextPart_001_0020_01C8D3B6.F05C5270 +Content-Type: text/html; + charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable + + + + + + + + +
    This is  a new ticket with=20 +attachments
    + +------=_NextPart_001_0020_01C8D3B6.F05C5270-- + +------=_NextPart_000_001F_01C8D3B6.F05C5270 +Content-Type: image/jpeg; + name="Paella.jpg" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="Paella.jpg" + +/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU +FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo +KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCACmAMgDASIA +AhEBAxEB/8QAHQAAAgMBAQEBAQAAAAAAAAAABQYABAcDCAIBCf/EADsQAAEDAwMCBQIDBQcFAQAA +AAECAwQABREGEiExQQcTIlFhcYEUMpEVI0Kh0QhSYrHB4fAWJCUzQ3L/xAAaAQADAQEBAQAAAAAA +AAAAAAADBAUCAQYA/8QAKhEAAgIBBAICAgIDAAMAAAAAAQIAAxEEEiExIkEFE1FhMnFCkaEjwdH/ +2gAMAwEAAhEDEQA/ACTUdSsdhRCNE54GTRaBaXHiBtNOVo0wEpSt8BKfmpWCZRPHcVbdZ3X1J9Jx +Tla9OBpIU8Noo7Gjx4qdrCBkfxGupUSck13GJjeT1ObEdthOG04/zpX8SNXjR1njym46ZMmQ+llp +pStuc9T9hRq/X22afhKl3iazEYHdxWCfgDqT9K83eKfiFG1RfIEi3tuC3W9KlNh0YLqyeuO3QV0D +MznM9O2uai4QI8psYQ8gLA9virY615P034xX+zNNslLDsMKOG1J5HuAa3nQPiBZ9WtpUy4lmcE4U +ypXP2rmMHmcI/EealD7te7ZZ2S7dLhGiN9cvOBP+dIF18btHw3C1DkSbi7nATGZJBPwTitTIyZp9 +SsCun9oJaEFUDTy0oyQFyXSOfoB/rQOL466huE9LIagxW1A48tkuKJxwBlQrm4YzNhGPE9Mmua8Y +JrzsrXPiQ42y7+KtsZt4kpS8ltK0p91J5IzXGFr3xFef8pMqE4vJABZT6se3FDNyEZzNCh89Tfbv +aoV2iKj3GO2+0eyh0+h7VkWq/CqTDUqXpp0uJHPkKOFj6HofvQRzxZ1bbwFTG7c+jO0lKeh+cGi8 +bxrebZZVMtjDqljKgw4Rt9uuea5vEIEceoL09ZnHQoyGy3KaOFhxO0j6g0J8QNPr3tzorHmsJSUv +NgdQeprTIuqbfqdtD7MRxh7HO/H6ZHWlnW0e5tQnv2WgupAyEg8p9xUl7WGowpzKCoDXyJ5nvMdK +Uuho4bSv057CqK2stIWrgEZp2kWtE+O5+MC0OKUchHFCbnaWVNeW1KU3tTtwtAUkj6jkfpXoK7gQ +AZLsqYEmJ0mUBlLeCfeqHKl5PqJopNhriupQWyoqPpKeQfpTXYPDW+3ZlEhTTcVpXI8w+oj6Cmty +qMxTazHAi1ZLG/PXuKClv3Ip7t2n4yI3lKZSsEc7hmicXwfu5ThN22fCUH+tXB4QX1KdzN6WVjth +Q/1oDuG/yjCIV/xgWLouQFfiLK/5LqejbnKT9D1FStX05DRaYrTN8K232wEl1aMJV856VKF9hPc3 +9QPM32HEjxEjykBSh/ERSd4s61uGjLbBnQrcie2t4pfClEFKAM8Y704uvtsMrdfcQ20gZUtZAAHu +SawHxt8V7PKt/wCytPp/aLrToW7JAPlNkAjAPfOfpQ0JY4E42B3Nf09ruwXvTQvjM9lmGkfvvOWE +llXdKvn/ADrONZeNwU28zo2Ml1tHpXc5Y2spP+EHlR/5ivOzYkPPKdjMechRDjrCUHy1Ec9Aa1Lw +l0VF10pcy4XJC0RlbTFTgKbHwnokfSibFXkzAJbiJ0tN81jc1yHXplzkEEqkPA7UjvtR2H1/SrOl +rGu6NvP7Q8yhaWkDruVj/n616Lvl20n4Z2cpeS02tSfRHbAU69/t8nivOGoNXzNQSVRbFAbtsFal +FESEjBOepUR1rBs3D8CFVMHjmXNYW+wWtsMrlMvyyOW4h3FB9irpn70lx7k9AeDttW4w70DgWd3+ +1NmlvDi7XpL0iShcWG0dqllO5SlHsB35NG7l4PSRG823z0YbGFqkDaFK+MZx7d6XOu09Z2M8MKHb +OBM1vBuAkJcuUgyHXRu3KfDp+5ycVTaeU36kKUlYOQQcEVrehvC5l1Mh/VClISHFMttIVgL45VnH +TkEH4rQbjpHTbyGWVQIzL7bYabc2AnaMfYnAxk0K35Smo7e/2IRdC7eXUwfT5m6pfbtC/wARIlLW +VNu7yoN9MlQ9h3NO+n9Cwo8rzZU1Sm2Mlx9YLaUkHjaOv3Nc7zd7FoyY5D07HR56SfMl7961ZGNo +9gKXrtd77dnkssoSwt7K9rZG8jHU44Tkc9q0rvbyvipnNgT9kTRLvqKy2JDgS/8AiH3hjecKXjv2 +/SkG8akmRyhqG+hKSQ4dpyofBxxV2w+Hkuda27pMW5tcSpWxati1HJGQTkYp70xoS2MW1pp+ImXN +koJLi+UtfP1FAt1dFPHcPXQ9nPUy+/3pu4usrYZS16MOKCAkuLJypRxX5aG5ExX4VlfC/Vt98e3z +WvL8M9NsNMtyFyVyGx6h5uPMPyMcV9Q9HQbbdWwzHQGFHKVhStw+uTQTr6tu1IQad85M46baVarV +uVkJ/mDVCVqWUll59t4FxlW0ocOA4k+1P8uLGU35UgAhQ2kgdRWUeIMi2WyKqASFLJJbWchQI7Ul +pWWyw5GSYZ1IXA4Ez7U12mR7q95jCWgTuCQeoPsaGqntylbCpIdxnaSM/wBK56lujtydZS4UkNIw +CBzQO4RURywWnUupcQF7knoT1BHYg5r0lFY2DIwZKvYq5x1DjUo26WzJKEuIQoFSFDIP+9bzaL0x ++HZcZcQpC0ggewIrzYzNJQGpGVt+/cUw2PU8+0vqWEJnW8q/9KzgpHslXb6UV6yw4gBZg8z1NZbj +Ek43LQDjkZFMLbkMcJW3+orKvDq86T1SUssrEef3iPq2rz8f3vtTZrtizaR0pOvD8XephOG2959a +ycJH60HBBxDBhjMB+L9/RY7WpT7jam3kkNNJwSs+/NSss0Bpi4+Jmpfxl7kPOQ2k7iCfyI/hQOwz +/vUroqrUnceZ8LnIG2Cdaa61Dq54i7SVJi5ymGwdjSf/ANe/86s6W0TLvkNySp5pcVjBUy0oAD5x +1P1NbDbPALTQjp/aC5bj+OS27tH+VOmjPDqw6QEv9lNPFcpIQ4p5zeSB0A/WtNYoXCwK1nOWgjwk +sFrg2wuJjtKl5IJUBwPakLxDXbNI6/alaGW6b87uL1vjJCmAogjcvHTrnb8DpVnxj1q1oOS7b9PP +j9qSEErA58gHuf8AF7CsStOurpBjKZioQqS6sqU+vlayepPvQytu3cgz/fEPWaXfFjYEfLlo5+bM +/aurr+X33vW6lIJUD/dyen2p80zboMNG6NBEGOygJLy04cdAGRjjn5NYRD1NcjMMme8XpST6Q4Mp +H0HStstF4kO2lMS5vAlTfq9O04PQZ+KifILaqg3PnPodS5o0S3I0q4x2T3Kr+obzH1HsjuFFpeUU +B5s5Snck4ST0z0p502w5HZW86qW5lXLbpSeMfHFZH4gpFutbDlrmNtujlxvzc705HAHfB5qknVSI +VliuWK7STcHVBL7Ticc8c8f70IaMaipWq4z+oo6jT2sr8ma3qCfBky48be4zvcAOB6gR/CMd6EXF +m9EPKhx3Vx92EJdADmOmQKJ2y5xVpiJlW+OzPSj1LbSBtURyoGjFzWqPbHljClFBLbiBnHHUmpeT +WdqiPISuDM/e0bark4YzkEJkJ9RebGF7u+T/AKVeg6DbVdXHJ6U/hi35KAlRGU44zj/WrtpdfSlt +D7m54jKznr/WnOAVKa9Y7cGtDVWodhaH1WnVlD7cZxPhq3NMobbeBeZQnalKlZ47cUQDSGtvlqwn +GEp7AVQdbddWQHkp2dOea6qWHQlPmJSscEE9aET/AJCK/X+JFxUtuKecHnKxx8VXRKiBSkuKII55 +PSvq4yUQmf3qspxwc8is71fqZMeKtTO0AHn3V8UaitrDgdmcdtoyZ215q1USShq0bZClghTYPqFL +Vr0xH1otbt1XKZkpT6cccfOaF6SZkz7q7dZYWHjz0ykJp2Yvi4YaYVHdUXjs2eSUlR7HPt89KoW5 +p8af5D3OVLldz9GLmsNLR1WZiI+oJlRB5aHgBuKe2cdaxd5tVsuy0OJbdWwvkKGUq+or0PqiyXVy +IJ7za1NlIJbz6m/fgdv61lN000qWJ09EWQ8++6lqM01k8geokY5p/wCK1RXK2Nn/AOz75PS1vStt +Y594iCUnOauWi5SLXMDzIQ4g8ONOp3IcT7KHcVduWn7nbWg5OgSI6SopBcQUjPtzXK1RX1OqkMtb +0xcPO9PSkHrzV0WKRkHM86a2BwZqFm0da9c2pdw0asM3JgBT9qdd2uNH+8y51x7A/rSjrXUmq129 +Om9TuyvKhu70NyUYd4GBlX8QofG1hcLbrBF/tZ/DvtqGEDhJQONpA6gjrXq61f8AS/jDo9mXNhNu +nGxxPR2O5jkBXX+tY3bcFhPtoPAin4H6gsMTQgLEhtM7eoyGioBYI4Tx7Yx+pqUr668ILjZXDOtS +XZsdvlMiGkJlND/GgYDg+Rg1KwUDHIM2r7Bgiei5NwiQo635cllllAypbiwAPvWO678c4UJuRH0y +gSHkDBkrHpz2CR3+prHbXJ1L4o6matwkKaYP7xzkhthsdVEf8NLWrzbo94fh2RKjAjqLSHFnKniO +Cs/X/KuLSAcN3OfYW5HUD3SXJutxfnTnVOyn1lbi1HJJNPnh9otyfbJF5lLabjpJQ0FjlZHUis9C +lDOO9bdHkS4WkbXBlIMdaGUnyhwkjqFfU5pf5K566gqe+I98TpBqb9pnB/Q9wu7kdyOGUNNp3oWp +Owq7+3P1r9uQmqllqS+S+ghClFWR+vtT/Z7goWGOopbjodwEltQOcdR16/WrcrTFmW4tyYZHmuDc +dhwkDHSvNvq2BC2+up6PThdIzDvMypelJN2lI8+M9JKxsZS1/Cfcn2+tF9K6Oh6ZeW5fYS5VwKgl +locpR3Cvk0+zJTdtioi2htDe5OVL/KAPcn3r5j3ZtdmkrKFTFJ3EDG7BAzgH9a+XX2sNi8CJXaZW +c3GIN7u0u931+KwhaGGspKQMKcKepVV5UmU1DZZtzspMVKQXm3F5B+gHIH0zQCBImKuiJMeCuEH1 +YCfVkjv+bqSKr6t1U7a7uxEgurS0yMLBASc/arlenBULiSGtOSSY6WKJKXckJU2tplSt6FA7gfvW +gxA/sUBggDGSayGya5ed8tkNqSlXVYOVVpEZydIablRFF6ORgjGFJPyKga3Tuj5Il2rVC6sKT1L9 +tiuPTnDI3eSfc/lqrqWOuHFK4qlF1HIX7j2NWIkyQ8XEApSUcD/Ea5TmZj2SggqUMKSrp9KUByQM +T45U5mSS9UzJMtMZ93GFcqJ7UL8Q3UOOww24Bx6h3V8/Sqev0sx7u4IqkB5w8tJ4KFfNBXG3Fuo/ +FPqLxA3FXXHtXp9PQiBXXiTGZrmIjTo68qh+Y2ygPhYSAlXIBz1rYHp04RkNRnWDOA5KyEgDrgVh +mmSmPcCfQpWCACnINFdRXOW3GQ4+60GgcJKDgr+R70lqdP8AZaAvuUK3woDY4mqyrjeFWppZZUXW +lnzUlYCVp+K+LLeYEoLLG5lGdxQk4wcfyrOourlyIzbDhcKVNhHB7e9XYlxatbam0dVDOAOT96Rf +TEDBHMMpU9dTQpVxiTWXGUqDy1n0hxCSAPvXnfWVtnWO9TI8lpLHnZOGxhKkE54+K1K1XhLj4S4j +GOnxX5qiNZ7wlpd1Di30ZS0hKtu4kdCaN8fqG0luxhwYtrdOtqZXsTA1dTWh+B+unNG6tbTIWTap +hDUhGeE56L+oP8qSbtBXDnyWSB+7WUnadwH3rgYT6IQmEpS0VbU5WNyj8DrXr/F1/ueXIZT1P6Hh +aVoSpJBSoZBB4IqVjPgP4ii72eHZLsSJrCPKadP8YA4B+cfrUpMgg4jK8jMybw5vUfT/AIXatujD +iRc5S24DX95KVAkn/P8ASstODk9asPSXvwZbUEoQpzhtIwkYHt9z1q3NZiO2uNMhFLbif3chkryc +9lAHsabbAbP5i6DI/qctPSokW9w3p0cvsIcBLY7+2fituuVxYvDbAMZ2VIUkeX5I5x3Tgdqznwz0 +xbb/ADZQuy3w2y2FISycHJz3+MVtWnNLwNMb3G0SZDvlgb3DlWPgf86V5/5e+oOAc7l/9y18WLK/ +IdH/AHB+l23bLPLMl0RkyQS22r1eWQO/tR178NEju3GS8ZahyVIc7ewA4qpKKfxzTMOGHCsBZSob +ueveitut+XGo8tpDacEp2DAP69ahNYHO4yo1rMxJgt22RLy0l5bYQ04jckLWfM+o7frVPUMpdg0a +65EfXvaX5XOArnp9hTtGgRbcyhL6PPbaG1ClnJAPvWeeMl0FogwnWGYkqKHSFxnUkpSojgkD79aJ +pQbblr9ZgNRcAhMzli9zZYfS27NkPBIKAFKVnnkn2pf1PaZbMNm4PpkDzeV+c0UEK+p6/WtX8H5M +GXDm3OS22Jq3P/W2AlIHwOgFVPF+VBfjqKi4sEHBKSAVfFegXWsmo+pV4zJZ0wareTFbw71Y1Ab/ +AAjbcNh1Q/8Ae9yaYU33VESW5KdK1wucuMpwgj3FYq4S456E7VDjimGHqa6wYqIS5HmMq42LOQBT +Wo0AYll5z+YCjV7MA+puVmuDkgh7evZt3bsdK46s1uiNZSY6iHwSj82CPnFC7PcbdbdOxkPTiqaB +5iQlXCf61mV9uC79dn39oDIVztGAajafRK9pPoSrZezKAOzKclyXcLgue8VLUo7sHrUaVIfeCloG +T0Uo9qstKdbcBLZUg9DiuzkbY4VDIBGQkdBVkuBxOrRtAwf7naKlyMoqQ4pRI9RHH2qtc1/i/KS+ +p3yWchtKwcIzX7HnoQv1nbgYUR7+9NESXCmR1xdjexxOXCTg9ODSzO1bBiJvCsCBFu3eahwltCnA +O6ATj6082K2rlltyXGSsIGEhzPP1xQa1QJNngLmMuNPMrPKE5BwKuzrw6Yu6JJVGWkZSkHIXn274 +pe8m0+H+51G2DBlu4J/DzFKbWhICiS2EgH7H2FD3JTMuclt7B2ArBzgJPvQNF1lSUFoON5JyST1P +tmgEu5yY0wgJ2uoUd27nPtRKdEzHk8xezVLUnHudtXsRYc4rt8pxZdKvMSpWcH60M07a03W5JZcW +UtgFSj8Dt96orKnVKUQVK6nv966R5b0dCksLLe4gkp68dOatKjBNgPMiM4Z9xHE1fwCkQx4pqYdC +vJcC1RwT0WkZH8s1KVPDm+Psa208ogAtysqWOqyo4JP2qUtanPM2jDEL+OWn49u8R5UK0MbGClDg +bSOApYyQPvSzM0rKt9qiXCRs8uSSlCeQoHnII+1aJ/aAZWjxImL3FILTSwR/+RX7bhqJ561XC5Jj +O20pSnyFYJWMZypJ6djWLdSa1BzxDUaYWnaOzH/RlmZ0nYWPJab9SQqS5t/eLV2+wzj7UfZmouM8 +MNtlsNoKlFZAV8H4FULPfmrmtyCtwJfQjKggFIVx2orHsbUZ1TzCktFwfvVKJJUB05968jqHaxyz +y3t+sBeiJJTLSXA6hAWscFSTjke561yfkAlte4h88BIJwB3q5Hjx297RUpWfUD+YYqs5Gjx3HJJK +ywRylIGM+/vShBMIrDMtpKiyVKcWtvaP3aRnn3HevOfi9eZM/UEiEv8A7eOHgkhfT0jg4+5r0JJu +ENLad0plpWM9c8dqUtTaMtGoJS37gyXH3UANyEHH6iqXx99entD2CK31m1CqmZZomd+HjORbXte8 +hOVLSk4USeTRm4xrvqbTjseUGmozTmVPLH5fgfNNNhYtWmJardbw3tf59XqIwepNM2poyJVpdKEt ++SRuCR/EfemLdWou3oO/cJXVmsI08z3BiFp7UakMuonR0jk47+31oG7iTM/dkNoWvCdx/KCe9P8A +dIzR1PAZfjtI3gx3QsAJHznFKOqbfbbXKSzbriZrwJ8390UJRjpgnrXpdNeLAM9kSDqKDWT+AYcu +1ivcK2x1KdiyYSejrCgSnPZXehTLqou7cghKRkgd6Px9SWp2xsMT23HF7QgpaOCFDoaCxFee4UKC +gCT14P3oKs5B+xccx+kIpG0wlaJKZLB9KglB5Uo9KsLeDj2GzjI+1AjmPLH4ZzCVEApPAIopGCFR +1rSpW4naaFbWB5DqUabMnaYEuTGyc40le4deO1fMZam17krwAOua7yYjyZCiG8hZ65ya57WW3W2y +lS3FDkFW0CmgdygdydZ4MT1HezzUy4iCwVKLKcFtSuD74r9uVtRJabLZ8obckpTlP60ItSLXOeDT +KlR1spG9W7clw/ejN4mXa0MDYA9FLn7olIxtxyFCprVkWbU7/cY+0FNx6/UU70GYDBQw6FrUcAgH +ke9Lq3FHkkk980xXedHuYWt6D5L4A2rQrCQO4xV+yaaiTrW5JL29GRgflUCOoJ5wPmqaOKUy/cl3 +Zufw6itbriuAJHloSVPNlvJ/hB61RCwVAKPHc1YubQZmvNpSlKUqIACtwH371Tzk/FOKAeR7ibEj +g+o06QWy7riziG2pDf4lsJCjknnrUrv4TtIe1/ZQ50Q+Fk/TkfzxUpW7ggQ1a7xmbF/aGsKEX83N +U4IU8wFJZWMbtvBwf04pOieITadOMxXmWRJR6CsD1HHTH2xWx/2irAu9aJTIjJJkQXgsYHJSrg/6 +V5os1rjsynVXOQY8uMsER1t8r+M9j0pSymu1P/J6j+ktatxtE23QtvmwYar3cX0JjyE+hhQ9ROeC +a0CJJaLTe+Uhfm/l7/YUhWKUxfbKxCztdQkJStWdySf7o/rTHZLC7bW3g5M819Y2pLiPy/TmvLak +AsSeCPUp7i1hB6h+Ytbnl+US2AfVx/nXyWg4kpeOQ4CPT2FVX0JacS6qWpASnC0qIINDLlKKGyGp +QaLmADgYA74xzSY7zDpWW4Eq2e0N2yXMdmKS6twlCUO4IQj3+po86RGWzGjtNgO4AATwlPXNAmPK +dLanH15K04SEE5x7GrsGWLnclJ9SHGuCrOCU+1E2s5zNfSE/7mJniFFciyHJ6XEktoIylWBjPPHv +SnC1HKlFK25Kls7cBpSvy4PtWwXHSsCXIUqUt15Tg2qStfpx7kUIc0JZIqHlpGwqTgFJxgZzx809 +XfWE22DJgwQD49TGr0pN2nlL7i2JKjvC1DCc9qUtRR47sjLQWiYkYdbX0PyDWwax09bZpcZtpdbl +FJO5aztJxkD46Vl83TclMT8SlDjh28lIJwfY/NXdDqK8Ag4iGsosYHK8QVKiRIztv/BqccWUhT6l +jASruBVpEoKkOAYLhJO0D9KGIUoqQ2vucYPaidptb0i6lCMNt8lSlq/N8VRcDblz1J9Tbf4CEGYb +rzbjiEBLqQQAtQAzUs7jrqnGFNJy0fUMcA/WjlutUySrLT0dLGw5C08hQ6fbNCrTBuVlubjjkJ58 +pJwU5Lef72B1pQMLFYZGY0bHQggS7KYUw35ivUlXU9xSfdCp5QWltSUp/iPfNaBLtv4KGiVOkYcf +X5imS2dyE9uM8DvjrQc2hyYsg+WGSfSQKxRatfJMLepvXA7iilxtKmlMJcQ4nlSlKzn7U4wbou7Y +RK9SGeUpzjJPciuLmi5ayDF8t3nsrHFfFx0lcbeSptYWhKUlS0EjBP8ADR2votx5DMSFF1eRjiGF +OWuK4mO+y2lTyFIWpw5SCeivgZpNuCzBU4zEmBbTnUtq4UP+ZoxaNIXG6So5ebX5C3NillXQd/pV +zWlmYtEJmEiARLz6XEerf78jrXy3VK4XO4mDsSzbwMYiQI8iQlx5tpa2kfmWBwK4BKVdDiicpq5t +NGItl1DbbYdUgDgAjO40JZSpxwBA5zVBDnn1EnGD+5rn9n+1pXeZlzcQFIYbCEEjoo9x9galN/hp +BFn06wwQA89+9cPfJ7fpUpG072zHql2Libtf225NukRX+WnWyhX0Iry9drM3ar2i4XN0h6BKS28r +O5TiByleD8Yr0ldJyHWtyOD0UKzHW9taloXM8jzkhBbkN4yVt+4HunqPvQXBxkTqH1E2dck2u5wp +9rUW0yiVPKCdwQgkYJx361pca9NSGG3C5kIR6nkD0g/Ws5uMMT4DJtFyZTCdSlAjlsJKTnHpP+hr +hapk+yxP2fNW7+DeSrAIyN3uP0qJfQtij8/9lPTlkznmPNwdh3FgILzgcK/3bqSfUfZQpW1BMuNr +hKeeQlCyrCWeu0DjdXL9oW2NAadjuLbdj4UFBQIWoe6Scg/NEo5cu81h+5JAQtvcgdE++Tmlvr+o +5YZEbpvstyvRlPSGtFvNJjzox4JKHknHP0pq03c2GlTAp5j8Spw7d5CVEYHANL9xsrTbMibHUCUJ +IKEt8JPvxSey4ZylLX/8yOSMbqIK67stXwIT0NxyZubSDKUX1lbawkAZ9u+KHXeez5ja3HwhpPxy +D2HNZu1rG7W5zeqS0EgbUggHA+nvVaNqOXdr5HVNcQhCV71BKQNx7ZzxQxoW7PUIgGcmNs6SqW+W +2hvdc53qRgkHgc0YsdpVGgluSGygrUdqQClJ+TXVu2sSSu4x3PxD20qDa14yccAe2KruPvNw23Lg +z+HDytqh1Chjoo9utAJ9LC22h0CqMRc15omyXhCnLc0mLc0c7mcBKiBnCk/PuKy646YvkCU0qLuL +iWylQUPyE9cH5/WtkRLs0VhTLzqW22sEqLm5xXPTjtV2bLt88sttrCSpQxsOSCPeqGn191ACnyH7 +k27RI/K8TFdFOOYcTcAWENqIcUpJBz23DvTqvWMRElm3uQiUpIQ08BgJV259qdFWjzorsd8RXQ7k +KJHCh7E9yBWWatszVpmsKRuCRgJTn0g5P9KKt9WrtJYYM+q07IgQGWpsNN/lsTH5W7yF7H22+Nqc +ZJz84r8sMda284IRztBHal19yRbslgltMjKVA01abvCmLamK6AprbtGeoo1ysKwF5Eao0TsxK9xu +03BS6hS9gU4DzkUWj26G4osKbSpRysBQJGaE2W822NHDbyngM7s4wM/avmZqdhrelhorSoEbxknn +5qVtctnEOdLZnkQvKjIhuNojNZyraQMYTx1PtXzeYMZtDS30IS4lQWhWMkH4+tIxvz8GT5iQt1Bz +vSoHBPbNVjPvGo33HWnSEsgqTgcE9NtMJpWyGJwJ9dQVGOxAGt9QruazbYxQGMAOOjBUo9hn4pf0 +vYiu7AvEKQ0rcQOh9hX47bJMW5qjlrCyohKSoEgfOKboflWmIhhsb5S+Sfk16SsCmsLX1PLWoXsz +Z2I6QZ3kBKc5dPGPapSw28qMn1q3PK/Mc9PipQ4YVMwyJt2oHV2uZuGVML/mKoKWlwbkHchQ4qkN +ZaevsQxzcmQsj0byUkH71TgOvRVqbeG6Ks+l5PqSD9RXxBioihqTS8Vm7JlNyHGIqlZWWujDmQQr +H9339q/bihUVLqVvh1ak7S6g8KHwO1OshQIIUAoHg96z7VdpkxIEw2chTDqTmOr/AOZ90Ht9KWv0 +7WkYMf0Oqr075sXIgLTkZl7Uy1zZCQhpsuDOOuQOa05NvYkS0J8h1UUDd5w5UOOAfisK026yJZj3 +YOR3i56XRzkn+EitUsN4uEvEeCpDCGlEOL67ldMikfk6HUg54Ef02pS9i6jEcLpcGUMLSW9iU43J +6EjH+VZ9NuLDmQqCIsdxR7e30rQWNPKaebmOTVrdXysq5C+OhFfcm129Y/7ptghJ3JKU8j6VLqtS +rvmNFNx4mNXGMy6jEQqeUF5V8D2oS63JalpaQdrhxjdyQK2O6Ls8SOGm0hO7ohKeVH2FIl205Pdd +cmMskrICkNg+pIz0IqrptWGGDwP3M3VhFye4w2hmVGYaUmUUsrwcpOSn5xTpcpUJu1vOmQpwObUK +S6njfnjjtzWOu6iu3luRnIhQGTtJHBB/pRq1u3G5hhKFlIVneVdz9+lKXaRgdzkCdRxYMg9S9qB+ +A/MS0tpYIVudaZTgOqwAPtUdjTkORXGmhHbKgltKVBJSMd+9Mtv/ABrcWRFLUdxATl0lGFlWOx7/ +AAaEOJhuLZipYdksr6BokraVnnd7VhbOl7xBfWwctnj8T9m39strVFa9aMggZKlK+lLGpXLhc47d +smsKjlSgpJWg5A65B7dfrWk2vTdus8p+clS1vYyEurB2H+pqs9erVc32zJIbeZXtS2oZO8fH+tap +sVH3VrnHucXftIeZf/0zdZDYbKlPlpJWVnkZ7D704WLRhTbkOzg6XVpxsB2+Wfr3p0hzIylPPtth +KEr2uFQxuI7ChV61IhaTGay24okBST0J6GutrLLPACMJY6DxMze/Ldtdzcik7gnlJ+DVJF2KTlVO +0O2M3WK8mQ0h5/HoIOFdepPalq5aTuapziQhptrPUkHA609VZW3i3cbHyRVfKU03RLishXIpfVqe +Q2lyJC/dZWQpfzmqF5f/AGdcSw08hwJxnb3V7CqcNl5qWp6U2lKRnYnOefeqlOjQDcw4kX5D5g2Y +Wn13GOKsQklxR8yU51UecUSt+5GX3vU8rue1CbeypxfnO/YUWB9jRGIHAiVNZc72lgLJVzzUrmg1 +KFiOjjqIwUpPKSR96KWnUl1tLoXCmOt+4CuD9qFlOe9fm3nrT5wexPN5I6msWHxHjzili+Nhlw4A +faGBn5HSmicCI6X2loeiufkeb5Sf6GvPqknrTJpPVs2wPbMh+EvhxhzlKh9KA1XtYZbM9xj1Laos +/K1ICHv74/1qnbryuwBtCIYQgDatbayQv5wehpnu8NiXaBebK6X7csgOIPK4yj/Cr49jSbJXwQel +BesWLseGrsNTbkjx/wBWQ4FvYfdntLW8NwZC8qT9RQ9Gq3bo8ERlBDajgrJ/KPekB1ltLqZCAlK0 +HcCUgjP0NfIuy1Tg+yw2y4kEL8kYSv52nj9KSPxNQ/jyZRr+UYfyGJt+nm7Kje95pflEAFxR6H/C +DQW+OSocpBjL/EFZOHmzyR7GkzSl9ZLr5uE2LFBOPLWlWSPccYFaxpS8WZlP4aEpDri8OKO4KBP+ +lTL9NZQ/kMxg21agBi3MXo9ulOvB1uC8p0j1LV0PH86JQ7QpiSh94mO3tUFBSeMn2zTsJjKFrde8 +g8DbsIJA78VzbuEd6MVLaSWFZSCUZI985pRnJjCviI2nbncJNzXDUhL7aSU5C8J2/OKcbTaodsU7 +K8hLL6zuUndkA/GaU7tM/ZUlQjBlu3bdzbkdHKTnkE+59qU77q+4zISmGY8lbyVH96hKjlPHHFGG +me0+HAM7bcmMxv1V/wCQkLFvcdxzktd6RbNDC71lDgbS2dy3F9sHmh8PVF5ZQtEdteFDar0eof0o +8q7abXHYNxdDEhgYUUnYpffkdxmqFelspGMZz+Io2qQ+51v9/wDw7KkwZflxlElIKgTnPJNcH7mz +Asjbi1smU8QouE/PBH2pd1DreyOwnojMGPIK8+tLe3HGAfrSE9cVrjtJjFfozwv1bfpnj+VOaf40 +so3DETv+RReF5m53LUNis0Bp9ExK3QkAoQ5nPfisq1druXd3CmMVtsDITlXOPn3pcMGS/HW84VKd +zwF9SKFKCs7T27U/pvjqaju7Mm6jW2uMdCE4tsukyI5cmY77sdtYSt4DICuoBNMFoWiapJcVhY6o +V7138N9XK0/JWw42l+BIT5cmMv8AK6jv9COxpi1XpBtE2LctJvfi7bOBdbAI8xrH5krHYj370zaf +R4gqCQwxzOCMJGE9K6A4rm20ttnDysuJ4OBxmq0uWllv08rNIjyOBPRsCg5GJLnODDZQg+s/yqUs +zJKlqUVHJNSmkqGOZOt1TBvGfZIxkVwWsg1KlaEmT8DhxX7u3dqlStTka/D3Ur2nrylKkfiIEr9z +IjK/K4g9fvR/xBsyLDqF+IwsrjqSl5rd1CFjcAfkZqVKHYIZOonyclpZz0oeygoUpWetSpWVmz1O +c6Ol9o9lDoaBIkPMOZS4obTg4URUqUzWAeDE7SVPEYrXrSZb30ORGwhwDG4rUr/M0SXri+SpYcYu +EiMMcJbVx9alSgtpad27aMw6ai0pjdKFz1nqJuSn/wAtIJIznj+lfQu11VueVdJm9weohwjNSpWj +UigYAmfsck8wPPlPKz5jzyz33LJoOt1SieSB7VKlGQQDk5n2w35qwCaYLbEQEBwgY7CpUrlphaAC +3MIkBKc0DuUUKC5CcJIPI96lSh18GH1AyINiI8x9CM4x3Fat4f6okWOY0qKkFv8AKpCgCFp75qVK +xqfUY+MUENmMmv7bHbDV5tqPJjTFcsK6pVgE4+Kz68xy41vZUEKPvUqUovDyufKjmfrVmYbiHd6n +cbis+/WpUqUcMZKdF44n/9k= + +------=_NextPart_000_001F_01C8D3B6.F05C5270-- + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/84/84aef8daed0663b1abb2c50b1715fa8c859e4a68.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/84/84aef8daed0663b1abb2c50b1715fa8c859e4a68.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,512 @@ +# redMine - project management software +# Copyright (C) 2006-2007 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. + +desc 'Mantis migration script' + +require 'active_record' +require 'iconv' +require 'pp' + +namespace :redmine do +task :migrate_from_mantis => :environment do + + module MantisMigrate + + DEFAULT_STATUS = IssueStatus.default + assigned_status = IssueStatus.find_by_position(2) + resolved_status = IssueStatus.find_by_position(3) + feedback_status = IssueStatus.find_by_position(4) + closed_status = IssueStatus.find :first, :conditions => { :is_closed => true } + STATUS_MAPPING = {10 => DEFAULT_STATUS, # new + 20 => feedback_status, # feedback + 30 => DEFAULT_STATUS, # acknowledged + 40 => DEFAULT_STATUS, # confirmed + 50 => assigned_status, # assigned + 80 => resolved_status, # resolved + 90 => closed_status # closed + } + + priorities = IssuePriority.all + DEFAULT_PRIORITY = priorities[2] + PRIORITY_MAPPING = {10 => priorities[1], # none + 20 => priorities[1], # low + 30 => priorities[2], # normal + 40 => priorities[3], # high + 50 => priorities[4], # urgent + 60 => priorities[5] # immediate + } + + TRACKER_BUG = Tracker.find_by_position(1) + TRACKER_FEATURE = Tracker.find_by_position(2) + + roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC') + manager_role = roles[0] + developer_role = roles[1] + DEFAULT_ROLE = roles.last + ROLE_MAPPING = {10 => DEFAULT_ROLE, # viewer + 25 => DEFAULT_ROLE, # reporter + 40 => DEFAULT_ROLE, # updater + 55 => developer_role, # developer + 70 => manager_role, # manager + 90 => manager_role # administrator + } + + CUSTOM_FIELD_TYPE_MAPPING = {0 => 'string', # String + 1 => 'int', # Numeric + 2 => 'int', # Float + 3 => 'list', # Enumeration + 4 => 'string', # Email + 5 => 'bool', # Checkbox + 6 => 'list', # List + 7 => 'list', # Multiselection list + 8 => 'date', # Date + } + + RELATION_TYPE_MAPPING = {1 => IssueRelation::TYPE_RELATES, # related to + 2 => IssueRelation::TYPE_RELATES, # parent of + 3 => IssueRelation::TYPE_RELATES, # child of + 0 => IssueRelation::TYPE_DUPLICATES, # duplicate of + 4 => IssueRelation::TYPE_DUPLICATES # has duplicate + } + + class MantisUser < ActiveRecord::Base + set_table_name :mantis_user_table + + def firstname + @firstname = realname.blank? ? username : realname.split.first[0..29] + @firstname + end + + def lastname + @lastname = realname.blank? ? '-' : realname.split[1..-1].join(' ')[0..29] + @lastname = '-' if @lastname.blank? + @lastname + end + + def email + if read_attribute(:email).match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i) && + !User.find_by_mail(read_attribute(:email)) + @email = read_attribute(:email) + else + @email = "#{username}@foo.bar" + end + end + + def username + read_attribute(:username)[0..29].gsub(/[^a-zA-Z0-9_\-@\.]/, '-') + end + end + + class MantisProject < ActiveRecord::Base + set_table_name :mantis_project_table + has_many :versions, :class_name => "MantisVersion", :foreign_key => :project_id + has_many :categories, :class_name => "MantisCategory", :foreign_key => :project_id + has_many :news, :class_name => "MantisNews", :foreign_key => :project_id + has_many :members, :class_name => "MantisProjectUser", :foreign_key => :project_id + + def identifier + read_attribute(:name).gsub(/[^a-z0-9\-]+/, '-').slice(0, Project::IDENTIFIER_MAX_LENGTH) + end + end + + class MantisVersion < ActiveRecord::Base + set_table_name :mantis_project_version_table + + def version + read_attribute(:version)[0..29] + end + + def description + read_attribute(:description)[0..254] + end + end + + class MantisCategory < ActiveRecord::Base + set_table_name :mantis_project_category_table + end + + class MantisProjectUser < ActiveRecord::Base + set_table_name :mantis_project_user_list_table + end + + class MantisBug < ActiveRecord::Base + set_table_name :mantis_bug_table + belongs_to :bug_text, :class_name => "MantisBugText", :foreign_key => :bug_text_id + has_many :bug_notes, :class_name => "MantisBugNote", :foreign_key => :bug_id + has_many :bug_files, :class_name => "MantisBugFile", :foreign_key => :bug_id + has_many :bug_monitors, :class_name => "MantisBugMonitor", :foreign_key => :bug_id + end + + class MantisBugText < ActiveRecord::Base + set_table_name :mantis_bug_text_table + + # Adds Mantis steps_to_reproduce and additional_information fields + # to description if any + def full_description + full_description = description + full_description += "\n\n*Steps to reproduce:*\n\n#{steps_to_reproduce}" unless steps_to_reproduce.blank? + full_description += "\n\n*Additional information:*\n\n#{additional_information}" unless additional_information.blank? + full_description + end + end + + class MantisBugNote < ActiveRecord::Base + set_table_name :mantis_bugnote_table + belongs_to :bug, :class_name => "MantisBug", :foreign_key => :bug_id + belongs_to :bug_note_text, :class_name => "MantisBugNoteText", :foreign_key => :bugnote_text_id + end + + class MantisBugNoteText < ActiveRecord::Base + set_table_name :mantis_bugnote_text_table + end + + class MantisBugFile < ActiveRecord::Base + set_table_name :mantis_bug_file_table + + def size + filesize + end + + def original_filename + MantisMigrate.encode(filename) + end + + def content_type + file_type + end + + def read(*args) + if @read_finished + nil + else + @read_finished = true + content + end + end + end + + class MantisBugRelationship < ActiveRecord::Base + set_table_name :mantis_bug_relationship_table + end + + class MantisBugMonitor < ActiveRecord::Base + set_table_name :mantis_bug_monitor_table + end + + class MantisNews < ActiveRecord::Base + set_table_name :mantis_news_table + end + + class MantisCustomField < ActiveRecord::Base + set_table_name :mantis_custom_field_table + set_inheritance_column :none + has_many :values, :class_name => "MantisCustomFieldString", :foreign_key => :field_id + has_many :projects, :class_name => "MantisCustomFieldProject", :foreign_key => :field_id + + def format + read_attribute :type + end + + def name + read_attribute(:name)[0..29] + end + end + + class MantisCustomFieldProject < ActiveRecord::Base + set_table_name :mantis_custom_field_project_table + end + + class MantisCustomFieldString < ActiveRecord::Base + set_table_name :mantis_custom_field_string_table + end + + + def self.migrate + + # Users + print "Migrating users" + User.delete_all "login <> 'admin'" + users_map = {} + users_migrated = 0 + MantisUser.find(:all).each do |user| + u = User.new :firstname => encode(user.firstname), + :lastname => encode(user.lastname), + :mail => user.email, + :last_login_on => user.last_visit + u.login = user.username + u.password = 'mantis' + u.status = User::STATUS_LOCKED if user.enabled != 1 + u.admin = true if user.access_level == 90 + next unless u.save! + users_migrated += 1 + users_map[user.id] = u.id + print '.' + end + puts + + # Projects + print "Migrating projects" + Project.destroy_all + projects_map = {} + versions_map = {} + categories_map = {} + MantisProject.find(:all).each do |project| + p = Project.new :name => encode(project.name), + :description => encode(project.description) + p.identifier = project.identifier + next unless p.save + projects_map[project.id] = p.id + p.enabled_module_names = ['issue_tracking', 'news', 'wiki'] + p.trackers << TRACKER_BUG + p.trackers << TRACKER_FEATURE + print '.' + + # Project members + project.members.each do |member| + m = Member.new :user => User.find_by_id(users_map[member.user_id]), + :roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE] + m.project = p + m.save + end + + # Project versions + project.versions.each do |version| + v = Version.new :name => encode(version.version), + :description => encode(version.description), + :effective_date => (version.date_order ? version.date_order.to_date : nil) + v.project = p + v.save + versions_map[version.id] = v.id + end + + # Project categories + project.categories.each do |category| + g = IssueCategory.new :name => category.category[0,30] + g.project = p + g.save + categories_map[category.category] = g.id + end + end + puts + + # Bugs + print "Migrating bugs" + Issue.destroy_all + issues_map = {} + keep_bug_ids = (Issue.count == 0) + MantisBug.find_each(:batch_size => 200) do |bug| + next unless projects_map[bug.project_id] && users_map[bug.reporter_id] + i = Issue.new :project_id => projects_map[bug.project_id], + :subject => encode(bug.summary), + :description => encode(bug.bug_text.full_description), + :priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY, + :created_on => bug.date_submitted, + :updated_on => bug.last_updated + i.author = User.find_by_id(users_map[bug.reporter_id]) + i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank? + i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank? + i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS + i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG) + i.id = bug.id if keep_bug_ids + next unless i.save + issues_map[bug.id] = i.id + print '.' + STDOUT.flush + + # Assignee + # Redmine checks that the assignee is a project member + if (bug.handler_id && users_map[bug.handler_id]) + i.assigned_to = User.find_by_id(users_map[bug.handler_id]) + i.save_with_validation(false) + end + + # Bug notes + bug.bug_notes.each do |note| + next unless users_map[note.reporter_id] + n = Journal.new :notes => encode(note.bug_note_text.note), + :created_on => note.date_submitted + n.user = User.find_by_id(users_map[note.reporter_id]) + n.journalized = i + n.save + end + + # Bug files + bug.bug_files.each do |file| + a = Attachment.new :created_on => file.date_added + a.file = file + a.author = User.find :first + a.container = i + a.save + end + + # Bug monitors + bug.bug_monitors.each do |monitor| + next unless users_map[monitor.user_id] + i.add_watcher(User.find_by_id(users_map[monitor.user_id])) + end + end + + # update issue id sequence if needed (postgresql) + Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!') + puts + + # Bug relationships + print "Migrating bug relations" + MantisBugRelationship.find(:all).each do |relation| + next unless issues_map[relation.source_bug_id] && issues_map[relation.destination_bug_id] + r = IssueRelation.new :relation_type => RELATION_TYPE_MAPPING[relation.relationship_type] + r.issue_from = Issue.find_by_id(issues_map[relation.source_bug_id]) + r.issue_to = Issue.find_by_id(issues_map[relation.destination_bug_id]) + pp r unless r.save + print '.' + STDOUT.flush + end + puts + + # News + print "Migrating news" + News.destroy_all + MantisNews.find(:all, :conditions => 'project_id > 0').each do |news| + next unless projects_map[news.project_id] + n = News.new :project_id => projects_map[news.project_id], + :title => encode(news.headline[0..59]), + :description => encode(news.body), + :created_on => news.date_posted + n.author = User.find_by_id(users_map[news.poster_id]) + n.save + print '.' + STDOUT.flush + end + puts + + # Custom fields + print "Migrating custom fields" + IssueCustomField.destroy_all + MantisCustomField.find(:all).each do |field| + f = IssueCustomField.new :name => field.name[0..29], + :field_format => CUSTOM_FIELD_TYPE_MAPPING[field.format], + :min_length => field.length_min, + :max_length => field.length_max, + :regexp => field.valid_regexp, + :possible_values => field.possible_values.split('|'), + :is_required => field.require_report? + next unless f.save + print '.' + STDOUT.flush + # Trackers association + f.trackers = Tracker.find :all + + # Projects association + field.projects.each do |project| + f.projects << Project.find_by_id(projects_map[project.project_id]) if projects_map[project.project_id] + end + + # Values + field.values.each do |value| + v = CustomValue.new :custom_field_id => f.id, + :value => value.value + v.customized = Issue.find_by_id(issues_map[value.bug_id]) if issues_map[value.bug_id] + v.save + end unless f.new_record? + end + puts + + puts + puts "Users: #{users_migrated}/#{MantisUser.count}" + puts "Projects: #{Project.count}/#{MantisProject.count}" + puts "Memberships: #{Member.count}/#{MantisProjectUser.count}" + puts "Versions: #{Version.count}/#{MantisVersion.count}" + puts "Categories: #{IssueCategory.count}/#{MantisCategory.count}" + puts "Bugs: #{Issue.count}/#{MantisBug.count}" + puts "Bug notes: #{Journal.count}/#{MantisBugNote.count}" + puts "Bug files: #{Attachment.count}/#{MantisBugFile.count}" + puts "Bug relations: #{IssueRelation.count}/#{MantisBugRelationship.count}" + puts "Bug monitors: #{Watcher.count}/#{MantisBugMonitor.count}" + puts "News: #{News.count}/#{MantisNews.count}" + puts "Custom fields: #{IssueCustomField.count}/#{MantisCustomField.count}" + end + + def self.encoding(charset) + @ic = Iconv.new('UTF-8', charset) + rescue Iconv::InvalidEncoding + return false + end + + def self.establish_connection(params) + constants.each do |const| + klass = const_get(const) + next unless klass.respond_to? 'establish_connection' + klass.establish_connection params + end + end + + def self.encode(text) + @ic.iconv text + rescue + text + end + end + + puts + if Redmine::DefaultData::Loader.no_data? + puts "Redmine configuration need to be loaded before importing data." + puts "Please, run this first:" + puts + puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\"" + exit + end + + puts "WARNING: Your Redmine data will be deleted during this process." + print "Are you sure you want to continue ? [y/N] " + STDOUT.flush + break unless STDIN.gets.match(/^y$/i) + + # Default Mantis database settings + db_params = {:adapter => 'mysql', + :database => 'bugtracker', + :host => 'localhost', + :username => 'root', + :password => '' } + + puts + puts "Please enter settings for your Mantis database" + [:adapter, :host, :database, :username, :password].each do |param| + print "#{param} [#{db_params[param]}]: " + value = STDIN.gets.chomp! + db_params[param] = value unless value.blank? + end + + while true + print "encoding [UTF-8]: " + STDOUT.flush + encoding = STDIN.gets.chomp! + encoding = 'UTF-8' if encoding.blank? + break if MantisMigrate.encoding encoding + puts "Invalid encoding!" + end + puts + + # Make sure bugs can refer bugs in other projects + Setting.cross_project_issue_relations = 1 if Setting.respond_to? 'cross_project_issue_relations' + + # Turn off email notifications + Setting.notified_events = [] + + MantisMigrate.establish_connection db_params + MantisMigrate.migrate +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/84/84bb124f9c56a0e127eefcadf426b28c77093316.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/84/84bb124f9c56a0e127eefcadf426b28c77093316.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%=l(:label_version_new)%>

    + +<% labelled_tabular_form_for @version, :url => project_versions_path(@project) do |f| %> +<%= render :partial => 'versions/form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/84/84cd086f9e2464554982f3173e2d22e96dc00668.svn-base Binary file .svn/pristine/84/84cd086f9e2464554982f3173e2d22e96dc00668.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/85/85316aa62f266023688bb5d8d7b7c31ca5b820f1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/85/85316aa62f266023688bb5d8d7b7c31ca5b820f1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,149 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class MessagesController < ApplicationController + menu_item :boards + default_search_scope :messages + before_filter :find_board, :only => [:new, :preview] + before_filter :find_message, :except => [:new, :preview] + before_filter :authorize, :except => [:preview, :edit, :destroy] + + verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } + verify :xhr => true, :only => :quote + + helper :watchers + helper :attachments + include AttachmentsHelper + + REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE) + + # Show a topic and its replies + def show + page = params[:page] + # Find the page of the requested reply + if params[:r] && page.nil? + offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i]) + page = 1 + offset / REPLIES_PER_PAGE + end + + @reply_count = @topic.children.count + @reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page + @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}], + :order => "#{Message.table_name}.created_on ASC", + :limit => @reply_pages.items_per_page, + :offset => @reply_pages.current.offset) + + @reply = Message.new(:subject => "RE: #{@message.subject}") + render :action => "show", :layout => false if request.xhr? + end + + # Create a new topic + def new + @message = Message.new(params[:message]) + @message.author = User.current + @message.board = @board + if params[:message] && User.current.allowed_to?(:edit_messages, @project) + @message.locked = params[:message]['locked'] + @message.sticky = params[:message]['sticky'] + end + if request.post? && @message.save + call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) + attachments = Attachment.attach_files(@message, params[:attachments]) + render_attachment_warning_if_needed(@message) + redirect_to :action => 'show', :id => @message + end + end + + # Reply to a topic + def reply + @reply = Message.new(params[:reply]) + @reply.author = User.current + @reply.board = @board + @topic.children << @reply + if !@reply.new_record? + call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) + attachments = Attachment.attach_files(@reply, params[:attachments]) + render_attachment_warning_if_needed(@reply) + end + redirect_to :action => 'show', :id => @topic, :r => @reply + end + + # Edit a message + def edit + (render_403; return false) unless @message.editable_by?(User.current) + if params[:message] + @message.locked = params[:message]['locked'] + @message.sticky = params[:message]['sticky'] + end + if request.post? && @message.update_attributes(params[:message]) + attachments = Attachment.attach_files(@message, params[:attachments]) + render_attachment_warning_if_needed(@message) + flash[:notice] = l(:notice_successful_update) + @message.reload + redirect_to :action => 'show', :board_id => @message.board, :id => @message.root, :r => (@message.parent_id && @message.id) + end + end + + # Delete a messages + def destroy + (render_403; return false) unless @message.destroyable_by?(User.current) + @message.destroy + redirect_to @message.parent.nil? ? + { :controller => 'boards', :action => 'show', :project_id => @project, :id => @board } : + { :action => 'show', :id => @message.parent, :r => @message } + end + + def quote + user = @message.author + text = @message.content + subject = @message.subject.gsub('"', '\"') + subject = "RE: #{subject}" unless subject.starts_with?('RE:') + content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> " + content << text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n" + render(:update) { |page| + page << "$('message_subject').value = \"#{subject}\";" + page.<< "$('message_content').value = \"#{content}\";" + page.show 'reply' + page << "Form.Element.focus('message_content');" + page << "Element.scrollTo('reply');" + page << "$('message_content').scrollTop = $('message_content').scrollHeight - $('message_content').clientHeight;" + } + end + + def preview + message = @board.messages.find_by_id(params[:id]) + @attachements = message.attachments if message + @text = (params[:message] || params[:reply])[:content] + render :partial => 'common/preview' + end + +private + def find_message + find_board + @message = @board.messages.find(params[:id], :include => :parent) + @topic = @message.root + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_board + @board = Board.find(params[:board_id], :include => :project) + @project = @board.project + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/85/853c1bb7d443401c4e54746ad2ab51095156b1da.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/85/853c1bb7d443401c4e54746ad2ab51095156b1da.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddIndexOnIssuesNestedSet < ActiveRecord::Migration + def self.up + add_index :issues, [:root_id, :lft, :rgt] + end + + def self.down + remove_index :issues, [:root_id, :lft, :rgt] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/85/85848dd34249f60ad32d28944cb4a9546d489175.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/85/85848dd34249f60ad32d28944cb4a9546d489175.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/string/conversions' +require File.dirname(__FILE__) + '/string/inflections' + +class String #:nodoc: + include Redmine::CoreExtensions::String::Conversions + include Redmine::CoreExtensions::String::Inflections +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/85/85ddd4b590a177f2393d1922fde43631be713d2e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/85/85ddd4b590a177f2393d1922fde43631be713d2e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class SetCustomFieldsEditable < ActiveRecord::Migration + def self.up + UserCustomField.update_all("editable = #{CustomField.connection.quoted_false}") + end + + def self.down + UserCustomField.update_all("editable = #{CustomField.connection.quoted_true}") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/8601448615d28585006a814af01259ba424d7569.svn-base Binary file .svn/pristine/86/8601448615d28585006a814af01259ba424d7569.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/8624ef6adab0da5b4b4384bffa3057ced2706f08.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/8624ef6adab0da5b4b4384bffa3057ced2706f08.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddRepositoryLoginAndPassword < ActiveRecord::Migration + def self.up + add_column :repositories, :login, :string, :limit => 60, :default => "" + add_column :repositories, :password, :string, :limit => 60, :default => "" + end + + def self.down + remove_column :repositories, :login + remove_column :repositories, :password + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/8626420aabc42f1c5c5c9fca490181efb3ed2f66.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/8626420aabc42f1c5c5c9fca490181efb3ed2f66.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +# Settings specified here will take precedence over those in config/environment.rb + +# The production environment is meant for finished, "live" apps. +# Code is not reloaded between requests +config.cache_classes = true + +##### +# Customize the default logger (http://ruby-doc.org/core/classes/Logger.html) +# +# Use a different logger for distributed setups +# config.logger = SyslogLogger.new +# +# Rotate logs bigger than 1MB, keeps no more than 7 rotated logs around. +# When setting a new Logger, make sure to set it's log level too. +# +# config.logger = Logger.new(config.log_path, 7, 1048576) +# config.logger.level = Logger::INFO + +# Full error reports are disabled and caching is turned on +config.action_controller.consider_all_requests_local = false +config.action_controller.perform_caching = true + +# Enable serving of images, stylesheets, and javascripts from an asset server +# config.action_controller.asset_host = "http://assets.example.com" + +# Disable delivery errors if you bad email addresses should just be ignored +config.action_mailer.raise_delivery_errors = false + +# No email in production log +config.action_mailer.logger = nil diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/863064fb5000e258cd2d7b4e4e73c65dd4fbbfc5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/863064fb5000e258cd2d7b4e4e73c65dd4fbbfc5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,190 @@ +# $Id: testldap.rb 65 2006-04-23 01:17:49Z blackhedd $ +# +# + + +$:.unshift "lib" + +require 'test/unit' + +require 'net/ldap' +require 'stringio' + + +class TestLdapClient < Test::Unit::TestCase + + # TODO: these tests crash and burn if the associated + # LDAP testserver isn't up and running. + # We rely on being able to read a file with test data + # in LDIF format. + # TODO, WARNING: for the moment, this data is in a file + # whose name and location are HARDCODED into the + # instance method load_test_data. + + def setup + @host = "127.0.0.1" + @port = 3890 + @auth = { + :method => :simple, + :username => "cn=bigshot,dc=bayshorenetworks,dc=com", + :password => "opensesame" + } + + @ldif = load_test_data + end + + + + # Get some test data which will be used to validate + # the responses from the test LDAP server we will + # connect to. + # TODO, Bogus: we are HARDCODING the location of the file for now. + # + def load_test_data + ary = File.readlines( "tests/testdata.ldif" ) + hash = {} + while line = ary.shift and line.chomp! + if line =~ /^dn:[\s]*/i + dn = $' + hash[dn] = {} + while attr = ary.shift and attr.chomp! and attr =~ /^([\w]+)[\s]*:[\s]*/ + hash[dn][$1.downcase.intern] ||= [] + hash[dn][$1.downcase.intern] << $' + end + end + end + hash + end + + + + # Binding tests. + # Need tests for all kinds of network failures and incorrect auth. + # TODO: Implement a class-level timeout for operations like bind. + # Search has a timeout defined at the protocol level, other ops do not. + # TODO, use constants for the LDAP result codes, rather than hardcoding them. + def test_bind + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth + assert_equal( true, ldap.bind ) + assert_equal( 0, ldap.get_operation_result.code ) + assert_equal( "Success", ldap.get_operation_result.message ) + + bad_username = @auth.merge( {:username => "cn=badguy,dc=imposters,dc=com"} ) + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => bad_username + assert_equal( false, ldap.bind ) + assert_equal( 48, ldap.get_operation_result.code ) + assert_equal( "Inappropriate Authentication", ldap.get_operation_result.message ) + + bad_password = @auth.merge( {:password => "cornhusk"} ) + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => bad_password + assert_equal( false, ldap.bind ) + assert_equal( 49, ldap.get_operation_result.code ) + assert_equal( "Invalid Credentials", ldap.get_operation_result.message ) + end + + + + def test_search + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth + + search = {:base => "dc=smalldomain,dc=com"} + assert_equal( false, ldap.search( search )) + assert_equal( 32, ldap.get_operation_result.code ) + + search = {:base => "dc=bayshorenetworks,dc=com"} + assert_equal( true, ldap.search( search )) + assert_equal( 0, ldap.get_operation_result.code ) + + ldap.search( search ) {|res| + assert_equal( res, @ldif ) + } + end + + + + + # This is a helper routine for test_search_attributes. + def internal_test_search_attributes attrs_to_search + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth + assert( ldap.bind ) + + search = { + :base => "dc=bayshorenetworks,dc=com", + :attributes => attrs_to_search + } + + ldif = @ldif + ldif.each {|dn,entry| + entry.delete_if {|attr,value| + ! attrs_to_search.include?(attr) + } + } + + assert_equal( true, ldap.search( search )) + ldap.search( search ) {|res| + res_keys = res.keys.sort + ldif_keys = ldif.keys.sort + assert( res_keys, ldif_keys ) + res.keys.each {|rk| + assert( res[rk], ldif[rk] ) + } + } + end + + + def test_search_attributes + internal_test_search_attributes [:mail] + internal_test_search_attributes [:cn] + internal_test_search_attributes [:ou] + internal_test_search_attributes [:hasaccessprivilege] + internal_test_search_attributes ["mail"] + internal_test_search_attributes ["cn"] + internal_test_search_attributes ["ou"] + internal_test_search_attributes ["hasaccessrole"] + + internal_test_search_attributes [:mail, :cn, :ou, :hasaccessrole] + internal_test_search_attributes [:mail, "cn", :ou, "hasaccessrole"] + end + + + def test_search_filters + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth + search = { + :base => "dc=bayshorenetworks,dc=com", + :filter => Net::LDAP::Filter.eq( "sn", "Fosse" ) + } + + ldap.search( search ) {|res| + p res + } + end + + + + def test_open + ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth + ldap.open {|ldap| + 10.times { + rc = ldap.search( :base => "dc=bayshorenetworks,dc=com" ) + assert_equal( true, rc ) + } + } + end + + + def test_ldap_open + Net::LDAP.open( :host => @host, :port => @port, :auth => @auth ) {|ldap| + 10.times { + rc = ldap.search( :base => "dc=bayshorenetworks,dc=com" ) + assert_equal( true, rc ) + } + } + end + + + + + +end + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/867eac203b96a63abcb7b1df9206100270f4a496.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/867eac203b96a63abcb7b1df9206100270f4a496.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Бүдүүн'; +jsToolBar.strings['Italic'] = 'Налуу'; +jsToolBar.strings['Underline'] = 'Доогуур зураас'; +jsToolBar.strings['Deleted'] = 'Устгагдсан'; +jsToolBar.strings['Code'] = 'Програмын код'; +jsToolBar.strings['Heading 1'] = 'Гарчиг 1'; +jsToolBar.strings['Heading 2'] = 'Гарчиг 2'; +jsToolBar.strings['Heading 3'] = 'Гарчиг 3'; +jsToolBar.strings['Unordered list'] = 'Эрэмбэгүй жагсаалт'; +jsToolBar.strings['Ordered list'] = 'Эрэмбэтэй жагсаалт'; +jsToolBar.strings['Quote'] = 'Ишлэл'; +jsToolBar.strings['Unquote'] = 'Ишлэлийг устгах'; +jsToolBar.strings['Preformatted text'] = 'Өмнө нь хэлбэржсэн текст'; +jsToolBar.strings['Wiki link'] = 'Вики хуудас руу холбох'; +jsToolBar.strings['Image'] = 'Зураг'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/86909cabd5b535a3543774147c6592927dbdf3f6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/86909cabd5b535a3543774147c6592927dbdf3f6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +<%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>: + +<% @issues.each do |issue| -%> +* <%= "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %> +<% end -%> + +<%= @issues_url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/86cf2abe4f8b8142381e7211a838d3b30b929a54.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/86cf2abe4f8b8142381e7211a838d3b30b929a54.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("일요일", + "월요일", + "화요일", + "수요일", + "목요일", + "금요일", + "토요일", + "일요일"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("일", + "월", + "화", + "수", + "목", + "금", + "토", + "일"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("1월", + "2월", + "3월", + "4월", + "5월", + "6월", + "7월", + "8월", + "9월", + "10월", + "11월", + "12월"); + +// short month names +Calendar._SMN = new Array +("1월", + "2월", + "3월", + "4월", + "5월", + "6월", + "7월", + "8월", + "9월", + "10월", + "11월", + "12월"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "이 달력은 ... & 도움말"; + +Calendar._TT["ABOUT"] = +"DHTML 날짜/시간 선택기\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"최신 버전을 구하려면 여기로: http://www.dynarch.com/projects/calendar/\n" + +"배포라이센스:GNU LGPL. 참조:http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"날짜 선택:\n" + +"- 해를 선택하려면 \xab, \xbb 버튼을 사용하세요.\n" + +"- 달을 선택하려면 " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " 버튼을 사용하세요.\n" + +"- 좀 더 빠르게 선택하려면 위의 버튼을 꾹 눌러주세요."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"시간 선택:\n" + +"- 시, 분을 더하려면 클릭하세요.\n" + +"- 시, 분을 빼려면 쉬프트 누르고 클릭하세요.\n" + +"- 좀 더 빠르게 선택하려면 클릭하고 드래그하세요."; + +Calendar._TT["PREV_YEAR"] = "이전 해"; +Calendar._TT["PREV_MONTH"] = "이전 달"; +Calendar._TT["GO_TODAY"] = "오늘로 이동"; +Calendar._TT["NEXT_MONTH"] = "다음 달"; +Calendar._TT["NEXT_YEAR"] = "다음 해"; +Calendar._TT["SEL_DATE"] = "날짜 선택"; +Calendar._TT["DRAG_TO_MOVE"] = "이동(드래그)"; +Calendar._TT["PART_TODAY"] = " (오늘)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "[%s]을 처음으로"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "닫기"; +Calendar._TT["TODAY"] = "오늘"; +Calendar._TT["TIME_PART"] = "클릭(+),쉬프트+클릭(-),드래그"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "주"; +Calendar._TT["TIME"] = "시간:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/86d46b11f53bf924d634fb6a310d55c059a3a986.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/86d46b11f53bf924d634fb6a310d55c059a3a986.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +
    +<%= link_to l(:label_issue_status_new), new_issue_status_path, :class => 'icon icon-add' %> +<%= link_to(l(:label_update_issue_done_ratios), update_issue_done_ratio_issue_statuses_path, :class => 'icon icon-multiple', :method => 'post', :confirm => l(:text_are_you_sure)) if Issue.use_status_for_done_ratio? %> +
    + +

    <%=l(:label_issue_status_plural)%>

    + + + + + <% if Issue.use_status_for_done_ratio? %> + + <% end %> + + + + + + +<% for status in @issue_statuses %> + "> + + <% if Issue.use_status_for_done_ratio? %> + + <% end %> + + + + + +<% end %> + +
    <%=l(:field_status)%><%=l(:field_done_ratio)%><%=l(:field_is_default)%><%=l(:field_is_closed)%><%=l(:button_sort)%>
    <%= link_to h(status.name), edit_issue_status_path(status) %><%= h status.default_done_ratio %><%= checked_image status.is_default? %><%= checked_image status.is_closed? %><%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %> + <%= link_to(l(:button_delete), issue_status_path(status), + :method => :delete, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + +

    <%= pagination_links_full @issue_status_pages %>

    + +<% html_title(l(:label_issue_status_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/86f993136841831dd0360fe42ff275f20185c30f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/86f993136841831dd0360fe42ff275f20185c30f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%=l(:label_issue_category)%>

    + +<% labelled_tabular_form_for :issue_category, @category, :url => issue_category_path(@category), :html => {:method => :put} do |f| %> +<%= render :partial => 'issue_categories/form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/86/86fc0dc108949dafb75bfcb3403e9b3a41c1387b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/86/86fc0dc108949dafb75bfcb3403e9b3a41c1387b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +# encoding: utf-8 +# +module IssueMovesHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/87/8719788cc5feae1f6d13316748ca22d737c8a820.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/87/8719788cc5feae1f6d13316748ca22d737c8a820.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +
    +<% for attachment in attachments %> +

    <%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> +<%= h(" - #{attachment.description}") unless attachment.description.blank? %> + (<%= number_to_human_size attachment.filesize %>) + <% if options[:deletable] %> + <%= link_to image_tag('delete.png'), attachment_path(attachment), + :confirm => l(:text_are_you_sure), + :method => :delete, + :class => 'delete', + :title => l(:button_delete) %> + <% end %> + <% if options[:author] %> + <%= h(attachment.author) %>, <%= format_time(attachment.created_on) %> + <% end %> +

    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/87/876f7aa5f0d8ab686326dfd20edff23d3549e0ba.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/87/876f7aa5f0d8ab686326dfd20edff23d3549e0ba.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class AddProjectsFeedsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "feeds", :description => "label_feed_plural", :sort => 132, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('projects', 'feeds').destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/87/877a424fbc6e3614aca9bb9dffbdaeacdcc1aeb0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/87/877a424fbc6e3614aca9bb9dffbdaeacdcc1aeb0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class CreateGroupsUsers < ActiveRecord::Migration + def self.up + create_table :groups_users, :id => false do |t| + t.column :group_id, :integer, :null => false + t.column :user_id, :integer, :null => false + end + add_index :groups_users, [:group_id, :user_id], :unique => true, :name => :groups_users_ids + end + + def self.down + drop_table :groups_users + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/87/87b8296b76d4848fd3e88cf880e805a657f96574.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/87/87b8296b76d4848fd3e88cf880e805a657f96574.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,48 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +In-Reply-To: +From: "John Smith" +To: +Subject: Re: update to issue 2 +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +An update to the issue by the sender. + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris --- Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +>> > --- Reply above. Do not remove this line. --- +>> > +>> > Issue #6779 has been updated by Eric Davis. +>> > +>> > Subject changed from Projects with JSON to Project JSON API +>> > Status changed from New to Assigned +>> > Assignee set to Eric Davis +>> > Priority changed from Low to Normal +>> > Estimated time deleted (1.00) +>> > +>> > Looks like the JSON api for projects was missed. I'm going to be +>> > reviewing the existing APIs and trying to clean them up over the next +>> > few weeks. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/87/87cf5e349a5bc29bdc53d5a9546c92b6fc428743.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/87/87cf5e349a5bc29bdc53d5a9546c92b6fc428743.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1031 @@ +pt-BR: + # formatos de data e hora + direction: ltr + date: + formats: + default: "%d/%m/%Y" + short: "%d de %B" + long: "%d de %B de %Y" + only_day: "%d" + + day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] + abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] + month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] + abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %d de %B de %Y, %H:%M hs" + time: "%H:%M hs" + short: "%d/%m, %H:%M hs" + long: "%A, %d de %B de %Y, %H:%M hs" + only_second: "%S" + datetime: + formats: + default: "%Y-%m-%dT%H:%M:%S%Z" + am: '' + pm: '' + + # date helper distancia em palavras + datetime: + distance_in_words: + half_a_minute: 'meio minuto' + less_than_x_seconds: + one: 'menos de 1 segundo' + other: 'menos de %{count} segundos' + + x_seconds: + one: '1 segundo' + other: '%{count} segundos' + + less_than_x_minutes: + one: 'menos de um minuto' + other: 'menos de %{count} minutos' + + x_minutes: + one: '1 minuto' + other: '%{count} minutos' + + about_x_hours: + one: 'aproximadamente 1 hora' + other: 'aproximadamente %{count} horas' + + x_days: + one: '1 dia' + other: '%{count} dias' + + about_x_months: + one: 'aproximadamente 1 mês' + other: 'aproximadamente %{count} meses' + + x_months: + one: '1 mês' + other: '%{count} meses' + + about_x_years: + one: 'aproximadamente 1 ano' + other: 'aproximadamente %{count} anos' + + over_x_years: + one: 'mais de 1 ano' + other: 'mais de %{count} anos' + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + # numeros + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: 'R$' + precision: 2 + format: '%u %n' + separator: ',' + delimiter: '.' + percentage: + format: + delimiter: '.' + precision: + format: + delimiter: '.' + human: + format: + precision: 1 + delimiter: '.' + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + support: + array: + sentence_connector: "e" + skip_last_comma: true + + # Active Record + activerecord: + errors: + template: + header: + one: "model não pode ser salvo: 1 erro" + other: "model não pode ser salvo: %{count} erros." + body: "Por favor, verifique os seguintes campos:" + messages: + inclusion: "não está incluso na lista" + exclusion: "não está disponível" + invalid: "não é válido" + confirmation: "não está de acordo com a confirmação" + accepted: "precisa ser aceito" + empty: "não pode ficar vazio" + blank: "não pode ficar vazio" + too_long: "é muito longo (máximo: %{count} caracteres)" + too_short: "é muito curto (mínimon: %{count} caracteres)" + wrong_length: "deve ter %{count} caracteres" + taken: "não está disponível" + not_a_number: "não é um número" + greater_than: "precisa ser maior do que %{count}" + greater_than_or_equal_to: "precisa ser maior ou igual a %{count}" + equal_to: "precisa ser igual a %{count}" + less_than: "precisa ser menor do que %{count}" + less_than_or_equal_to: "precisa ser menor ou igual a %{count}" + odd: "precisa ser ímpar" + even: "precisa ser par" + greater_than_start_date: "deve ser maior que a data inicial" + not_same_project: "não pertence ao mesmo projeto" + circular_dependency: "Esta relação geraria uma dependência circular" + cant_link_an_issue_with_a_descendant: "Uma tarefa não pode ser relaciona a uma de suas subtarefas" + + actionview_instancetag_blank_option: Selecione + + general_text_No: 'Não' + general_text_Yes: 'Sim' + general_text_no: 'não' + general_text_yes: 'sim' + general_lang_name: 'Português(Brasil)' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Conta atualizada com sucesso. + notice_account_invalid_creditentials: Usuário ou senha inválido. + notice_account_password_updated: Senha alterada com sucesso. + notice_account_wrong_password: Senha inválida. + notice_account_register_done: Conta criada com sucesso. Para ativar sua conta, clique no link que lhe foi enviado por e-mail. + notice_account_unknown_email: Usuário desconhecido. + notice_can_t_change_password: Esta conta utiliza autenticação externa. Não é possível alterar a senha. + notice_account_lost_email_sent: Um e-mail com instruções para escolher uma nova senha foi enviado para você. + notice_account_activated: Sua conta foi ativada. Você pode acessá-la agora. + notice_successful_create: Criado com sucesso. + notice_successful_update: Alterado com sucesso. + notice_successful_delete: Excluído com sucesso. + notice_successful_connection: Conectado com sucesso. + notice_file_not_found: A página que você está tentando acessar não existe ou foi excluída. + notice_locking_conflict: Os dados foram atualizados por outro usuário. + notice_not_authorized: Você não está autorizado a acessar esta página. + notice_email_sent: "Um e-mail foi enviado para %{value}" + notice_email_error: "Ocorreu um erro ao enviar o e-mail (%{value})" + notice_feeds_access_key_reseted: Sua chave RSS foi reconfigurada. + notice_failed_to_save_issues: "Problema ao salvar %{count} tarefa(s) de %{total} selecionadas: %{ids}." + notice_no_issue_selected: "Nenhuma tarefa selecionada! Por favor, marque as tarefas que você deseja editar." + notice_account_pending: "Sua conta foi criada e está aguardando aprovação do administrador." + notice_default_data_loaded: Configuração padrão carregada com sucesso. + + error_can_t_load_default_data: "A configuração padrão não pode ser carregada: %{value}" + error_scm_not_found: "A entrada e/ou a revisão não existe no repositório." + error_scm_command_failed: "Ocorreu um erro ao tentar acessar o repositório: %{value}" + error_scm_annotate: "Esta entrada não existe ou não pode ser anotada." + error_issue_not_found_in_project: 'A tarefa não foi encontrada ou não pertence a este projeto' + error_no_tracker_in_project: 'Não há um tipo de tarefa associado a este projeto. Favor verificar as configurações do projeto.' + error_no_default_issue_status: 'A situação padrão para tarefa não está definida. Favor verificar sua configuração (Vá em "Administração -> Situação da tarefa").' + + mail_subject_lost_password: "Sua senha do %{value}." + mail_body_lost_password: 'Para mudar sua senha, clique no link abaixo:' + mail_subject_register: "Ativação de conta do %{value}." + mail_body_register: 'Para ativar sua conta, clique no link abaixo:' + mail_body_account_information_external: "Você pode usar sua conta do %{value} para entrar." + mail_body_account_information: Informações sobre sua conta + mail_subject_account_activation_request: "%{value} - Requisição de ativação de conta" + mail_body_account_activation_request: "Um novo usuário (%{value}) se registrou. A conta está aguardando sua aprovação:" + mail_subject_reminder: "%{count} tarefa(s) com data prevista para os próximos %{days} dias" + mail_body_reminder: "%{count} tarefa(s) para você com data prevista para os próximos %{days} dias:" + + gui_validation_error: 1 erro + gui_validation_error_plural: "%{count} erros" + + field_name: Nome + field_description: Descrição + field_summary: Resumo + field_is_required: Obrigatório + field_firstname: Nome + field_lastname: Sobrenome + field_mail: E-mail + field_filename: Arquivo + field_filesize: Tamanho + field_downloads: Downloads + field_author: Autor + field_created_on: Criado em + field_updated_on: Alterado em + field_field_format: Formato + field_is_for_all: Para todos os projetos + field_possible_values: Possíveis valores + field_regexp: Expressão regular + field_min_length: Tamanho mínimo + field_max_length: Tamanho máximo + field_value: Valor + field_category: Categoria + field_title: Título + field_project: Projeto + field_issue: Tarefa + field_status: Situação + field_notes: Notas + field_is_closed: Tarefa fechada + field_is_default: Situação padrão + field_tracker: Tipo + field_subject: Título + field_due_date: Data prevista + field_assigned_to: Atribuído para + field_priority: Prioridade + field_fixed_version: Versão + field_user: Usuário + field_role: Cargo + field_homepage: Página do projeto + field_is_public: Público + field_parent: Sub-projeto de + field_is_in_roadmap: Exibir no planejamento + field_login: Usuário + field_mail_notification: Notificações por e-mail + field_admin: Administrador + field_last_login_on: Última conexão + field_language: Idioma + field_effective_date: Data + field_password: Senha + field_new_password: Nova senha + field_password_confirmation: Confirmação + field_version: Versão + field_type: Tipo + field_host: Servidor + field_port: Porta + field_account: Conta + field_base_dn: DN Base + field_attr_login: Atributo para nome de usuário + field_attr_firstname: Atributo para nome + field_attr_lastname: Atributo para sobrenome + field_attr_mail: Atributo para e-mail + field_onthefly: Criar usuários dinamicamente ("on-the-fly") + field_start_date: Início + field_done_ratio: "% Terminado" + field_auth_source: Modo de autenticação + field_hide_mail: Ocultar meu e-mail + field_comments: Comentário + field_url: URL + field_start_page: Página inicial + field_subproject: Sub-projeto + field_hours: Horas + field_activity: Atividade + field_spent_on: Data + field_identifier: Identificador + field_is_filter: É um filtro + field_issue_to: Tarefa relacionada + field_delay: Atraso + field_assignable: Tarefas podem ser atribuídas a este papel + field_redirect_existing_links: Redirecionar links existentes + field_estimated_hours: Tempo estimado + field_column_names: Colunas + field_time_zone: Fuso-horário + field_searchable: Pesquisável + field_default_value: Padrão + field_comments_sorting: Visualizar comentários + field_parent_title: Página pai + + setting_app_title: Título da aplicação + setting_app_subtitle: Sub-título da aplicação + setting_welcome_text: Texto de boas-vindas + setting_default_language: Idioma padrão + setting_login_required: Exigir autenticação + setting_self_registration: Permitido Auto-registro + setting_attachment_max_size: Tamanho máximo do anexo + setting_issues_export_limit: Limite de exportação das tarefas + setting_mail_from: E-mail enviado de + setting_bcc_recipients: Enviar com cópia oculta (cco) + setting_host_name: Nome do Servidor e subdomínio + setting_text_formatting: Formatação do texto + setting_wiki_compression: Compactação de histórico do Wiki + setting_feeds_limit: Número de registros por Feed + setting_default_projects_public: Novos projetos são públicos por padrão + setting_autofetch_changesets: Obter commits automaticamente + setting_sys_api_enabled: Ativa WS para gerenciamento do repositório (SVN) + setting_commit_ref_keywords: Palavras de referência + setting_commit_fix_keywords: Palavras de fechamento + setting_autologin: Auto-login + setting_date_format: Formato da data + setting_time_format: Formato de hora + setting_cross_project_issue_relations: Permitir relacionar tarefas entre projetos + setting_issue_list_default_columns: Colunas padrão visíveis na lista de tarefas + setting_emails_footer: Rodapé do e-mail + setting_protocol: Protocolo + setting_per_page_options: Número de itens exibidos por página + setting_user_format: Formato de exibição de nome de usuário + setting_activity_days_default: Dias visualizados na atividade do projeto + setting_display_subprojects_issues: Visualizar tarefas dos subprojetos nos projetos principais por padrão + setting_enabled_scm: SCM habilitados + setting_mail_handler_api_enabled: Habilitar WS para e-mails de entrada + setting_mail_handler_api_key: Chave de API + setting_sequential_project_identifiers: Gerar identificadores sequenciais de projeto + + project_module_issue_tracking: Gerenciamento de Tarefas + project_module_time_tracking: Gerenciamento de tempo + project_module_news: Notícias + project_module_documents: Documentos + project_module_files: Arquivos + project_module_wiki: Wiki + project_module_repository: Repositório + project_module_boards: Fóruns + + label_user: Usuário + label_user_plural: Usuários + label_user_new: Novo usuário + label_project: Projeto + label_project_new: Novo projeto + label_project_plural: Projetos + label_x_projects: + zero: nenhum projeto + one: 1 projeto + other: "%{count} projetos" + label_project_all: Todos os projetos + label_project_latest: Últimos projetos + label_issue: Tarefa + label_issue_new: Nova tarefa + label_issue_plural: Tarefas + label_issue_view_all: Ver todas as tarefas + label_issues_by: "Tarefas por %{value}" + label_issue_added: Tarefa adicionada + label_issue_updated: Tarefa atualizada + label_issue_note_added: Nota adicionada + label_issue_status_updated: Situação atualizada + label_issue_priority_updated: Prioridade atualizada + label_document: Documento + label_document_new: Novo documento + label_document_plural: Documentos + label_document_added: Documento adicionado + label_role: Papel + label_role_plural: Papéis + label_role_new: Novo papel + label_role_and_permissions: Papéis e permissões + label_member: Membro + label_member_new: Novo membro + label_member_plural: Membros + label_tracker: Tipo de tarefa + label_tracker_plural: Tipos de tarefas + label_tracker_new: Novo tipo + label_workflow: Fluxo de trabalho + label_issue_status: Situação da tarefa + label_issue_status_plural: Situação das tarefas + label_issue_status_new: Nova situação + label_issue_category: Categoria da tarefa + label_issue_category_plural: Categorias das tarefas + label_issue_category_new: Nova categoria + label_custom_field: Campo personalizado + label_custom_field_plural: Campos personalizados + label_custom_field_new: Novo campo personalizado + label_enumerations: 'Tipos & Categorias' + label_enumeration_new: Novo + label_information: Informação + label_information_plural: Informações + label_please_login: Efetue o login + label_register: Cadastre-se + label_password_lost: Perdi minha senha + label_home: Página inicial + label_my_page: Minha página + label_my_account: Minha conta + label_my_projects: Meus projetos + label_administration: Administração + label_login: Entrar + label_logout: Sair + label_help: Ajuda + label_reported_issues: Tarefas reportadas + label_assigned_to_me_issues: Minhas tarefas + label_last_login: Última conexão + label_registered_on: Registrado em + label_activity: Atividade + label_overall_activity: Atividades gerais + label_new: Novo + label_logged_as: "Acessando como:" + label_environment: Ambiente + label_authentication: Autenticação + label_auth_source: Modo de autenticação + label_auth_source_new: Novo modo de autenticação + label_auth_source_plural: Modos de autenticação + label_subproject_plural: Sub-projetos + label_and_its_subprojects: "%{value} e seus sub-projetos" + label_min_max_length: Tamanho mín-máx + label_list: Lista + label_date: Data + label_integer: Inteiro + label_float: Decimal + label_boolean: Boleano + label_string: Texto + label_text: Texto longo + label_attribute: Atributo + label_attribute_plural: Atributos + label_download: "%{count} Download" + label_download_plural: "%{count} Downloads" + label_no_data: Nenhuma informação disponível + label_change_status: Alterar situação + label_history: Histórico + label_attachment: Arquivo + label_attachment_new: Novo arquivo + label_attachment_delete: Excluir arquivo + label_attachment_plural: Arquivos + label_file_added: Arquivo adicionado + label_report: Relatório + label_report_plural: Relatório + label_news: Notícia + label_news_new: Adicionar notícia + label_news_plural: Notícias + label_news_latest: Últimas notícias + label_news_view_all: Ver todas as notícias + label_news_added: Notícia adicionada + label_settings: Configurações + label_overview: Visão geral + label_version: Versão + label_version_new: Nova versão + label_version_plural: Versões + label_confirmation: Confirmação + label_export_to: Exportar para + label_read: Ler... + label_public_projects: Projetos públicos + label_open_issues: Aberta + label_open_issues_plural: Abertas + label_closed_issues: Fechada + label_closed_issues_plural: Fechadas + label_x_open_issues_abbr_on_total: + zero: 0 aberta / %{total} + one: 1 aberta / %{total} + other: "%{count} abertas / %{total}" + label_x_open_issues_abbr: + zero: 0 aberta + one: 1 aberta + other: "%{count} abertas" + label_x_closed_issues_abbr: + zero: 0 fechada + one: 1 fechada + other: "%{count} fechadas" + label_total: Total + label_permissions: Permissões + label_current_status: Situação atual + label_new_statuses_allowed: Nova situação permitida + label_all: todos + label_none: nenhum + label_nobody: ninguém + label_next: Próximo + label_previous: Anterior + label_used_by: Usado por + label_details: Detalhes + label_add_note: Adicionar nota + label_per_page: Por página + label_calendar: Calendário + label_months_from: meses a partir de + label_gantt: Gantt + label_internal: Interno + label_last_changes: "últimas %{count} alterações" + label_change_view_all: Mostrar todas as alterações + label_personalize_page: Personalizar esta página + label_comment: Comentário + label_comment_plural: Comentários + label_x_comments: + zero: nenhum comentário + one: 1 comentário + other: "%{count} comentários" + label_comment_add: Adicionar comentário + label_comment_added: Comentário adicionado + label_comment_delete: Excluir comentário + label_query: Consulta personalizada + label_query_plural: Consultas personalizadas + label_query_new: Nova consulta + label_filter_add: Adicionar filtro + label_filter_plural: Filtros + label_equals: igual a + label_not_equals: diferente de + label_in_less_than: maior que + label_in_more_than: menor que + label_in: em + label_today: hoje + label_all_time: tudo + label_yesterday: ontem + label_this_week: esta semana + label_last_week: última semana + label_last_n_days: "últimos %{count} dias" + label_this_month: este mês + label_last_month: último mês + label_this_year: este ano + label_date_range: Período + label_less_than_ago: menos de + label_more_than_ago: mais de + label_ago: dias atrás + label_contains: contém + label_not_contains: não contém + label_day_plural: dias + label_repository: Repositório + label_repository_plural: Repositórios + label_browse: Procurar + label_modification: "%{count} alteração" + label_modification_plural: "%{count} alterações" + label_revision: Revisão + label_revision_plural: Revisões + label_associated_revisions: Revisões associadas + label_added: adicionada + label_modified: alterada + label_deleted: excluída + label_latest_revision: Última revisão + label_latest_revision_plural: Últimas revisões + label_view_revisions: Ver revisões + label_max_size: Tamanho máximo + label_sort_highest: Mover para o início + label_sort_higher: Mover para cima + label_sort_lower: Mover para baixo + label_sort_lowest: Mover para o fim + label_roadmap: Planejamento + label_roadmap_due_in: "Previsto para %{value}" + label_roadmap_overdue: "%{value} atrasado" + label_roadmap_no_issues: Sem tarefas para esta versão + label_search: Busca + label_result_plural: Resultados + label_all_words: Todas as palavras + label_wiki: Wiki + label_wiki_edit: Editar Wiki + label_wiki_edit_plural: Edições Wiki + label_wiki_page: Página Wiki + label_wiki_page_plural: páginas Wiki + label_index_by_title: Índice por título + label_index_by_date: Índice por data + label_current_version: Versão atual + label_preview: Pré-visualizar + label_feed_plural: Feeds + label_changes_details: Detalhes de todas as alterações + label_issue_tracking: Tarefas + label_spent_time: Tempo gasto + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_time_tracking: Registro de horas + label_change_plural: Alterações + label_statistics: Estatísticas + label_commits_per_month: Commits por mês + label_commits_per_author: Commits por autor + label_view_diff: Ver diferenças + label_diff_inline: inline + label_diff_side_by_side: lado a lado + label_options: Opções + label_copy_workflow_from: Copiar fluxo de trabalho de + label_permissions_report: Relatório de permissões + label_watched_issues: Tarefas observadas + label_related_issues: Tarefas relacionadas + label_applied_status: Situação alterada + label_loading: Carregando... + label_relation_new: Nova relação + label_relation_delete: Excluir relação + label_relates_to: relacionado a + label_duplicates: duplica + label_duplicated_by: duplicado por + label_blocks: bloqueia + label_blocked_by: bloqueado por + label_precedes: precede + label_follows: segue + label_end_to_start: fim para o início + label_end_to_end: fim para fim + label_start_to_start: início para início + label_start_to_end: início para fim + label_stay_logged_in: Permanecer logado + label_disabled: desabilitado + label_show_completed_versions: Exibir versões completas + label_me: mim + label_board: Fórum + label_board_new: Novo fórum + label_board_plural: Fóruns + label_topic_plural: Tópicos + label_message_plural: Mensagens + label_message_last: Última mensagem + label_message_new: Nova mensagem + label_message_posted: Mensagem enviada + label_reply_plural: Respostas + label_send_information: Enviar informação da nova conta para o usuário + label_year: Ano + label_month: Mês + label_week: Semana + label_date_from: De + label_date_to: Para + label_language_based: Com base no idioma do usuário + label_sort_by: "Ordenar por %{value}" + label_send_test_email: Enviar um e-mail de teste + label_feeds_access_key_created_on: "chave de acesso RSS criada %{value} atrás" + label_module_plural: Módulos + label_added_time_by: "Adicionado por %{author} %{age} atrás" + label_updated_time: "Atualizado %{value} atrás" + label_jump_to_a_project: Ir para o projeto... + label_file_plural: Arquivos + label_changeset_plural: Changesets + label_default_columns: Colunas padrão + label_no_change_option: (Sem alteração) + label_bulk_edit_selected_issues: Edição em massa das tarefas selecionados. + label_theme: Tema + label_default: Padrão + label_search_titles_only: Pesquisar somente títulos + label_user_mail_option_all: "Para qualquer evento em todos os meus projetos" + label_user_mail_option_selected: "Para qualquer evento somente no(s) projeto(s) selecionado(s)..." + label_user_mail_no_self_notified: "Eu não quero ser notificado de minhas próprias modificações" + label_registration_activation_by_email: ativação de conta por e-mail + label_registration_manual_activation: ativação manual de conta + label_registration_automatic_activation: ativação automática de conta + label_display_per_page: "Por página: %{value}" + label_age: Idade + label_change_properties: Alterar propriedades + label_general: Geral + label_more: Mais + label_scm: 'Controle de versão:' + label_plugins: Plugins + label_ldap_authentication: Autenticação LDAP + label_downloads_abbr: D/L + label_optional_description: Descrição opcional + label_add_another_file: Adicionar outro arquivo + label_preferences: Preferências + label_chronological_order: Em ordem cronológica + label_reverse_chronological_order: Em ordem cronológica inversa + label_planning: Planejamento + label_incoming_emails: E-mails recebidos + label_generate_key: Gerar uma chave + label_issue_watchers: Observadores + + button_login: Entrar + button_submit: Enviar + button_save: Salvar + button_check_all: Marcar todos + button_uncheck_all: Desmarcar todos + button_delete: Excluir + button_create: Criar + button_test: Testar + button_edit: Editar + button_add: Adicionar + button_change: Alterar + button_apply: Aplicar + button_clear: Limpar + button_lock: Bloquear + button_unlock: Desbloquear + button_download: Baixar + button_list: Listar + button_view: Ver + button_move: Mover + button_back: Voltar + button_cancel: Cancelar + button_activate: Ativar + button_sort: Ordenar + button_log_time: Tempo de trabalho + button_rollback: Voltar para esta versão + button_watch: Observar + button_unwatch: Parar de observar + button_reply: Responder + button_archive: Arquivar + button_unarchive: Desarquivar + button_reset: Redefinir + button_rename: Renomear + button_change_password: Alterar senha + button_copy: Copiar + button_annotate: Anotar + button_update: Atualizar + button_configure: Configurar + button_quote: Responder + + status_active: ativo + status_registered: registrado + status_locked: bloqueado + + text_select_mail_notifications: Ações a serem notificadas por e-mail + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 = sem restrição + text_project_destroy_confirmation: Você tem certeza que deseja excluir este projeto e todos os dados relacionados? + text_subprojects_destroy_warning: "Seu(s) subprojeto(s): %{value} também serão excluídos." + text_workflow_edit: Selecione um papel e um tipo de tarefa para editar o fluxo de trabalho + text_are_you_sure: Você tem certeza? + text_tip_issue_begin_day: tarefa inicia neste dia + text_tip_issue_end_day: tarefa termina neste dia + text_tip_issue_begin_end_day: tarefa inicia e termina neste dia + text_project_identifier_info: 'Letras minúsculas (a-z), números e hífens permitidos.
    Uma vez salvo, o identificador não poderá ser alterado.' + text_caracters_maximum: "máximo %{count} caracteres" + text_caracters_minimum: "deve ter ao menos %{count} caracteres." + text_length_between: "deve ter entre %{min} e %{max} caracteres." + text_tracker_no_workflow: Sem fluxo de trabalho definido para este tipo. + text_unallowed_characters: Caracteres não permitidos + text_comma_separated: Múltiplos valores são permitidos (separados por vírgula). + text_issues_ref_in_commit_messages: Referenciando tarefas nas mensagens de commit + text_issue_added: "Tarefa %{id} incluída (por %{author})." + text_issue_updated: "Tarefa %{id} alterada (por %{author})." + text_wiki_destroy_confirmation: Você tem certeza que deseja excluir este wiki e TODO o seu conteúdo? + text_issue_category_destroy_question: "Algumas tarefas (%{count}) estão atribuídas a esta categoria. O que você deseja fazer?" + text_issue_category_destroy_assignments: Remover atribuições da categoria + text_issue_category_reassign_to: Redefinir tarefas para esta categoria + text_user_mail_option: "Para projetos (não selecionados), você somente receberá notificações sobre o que você está observando ou está envolvido (ex. tarefas das quais você é o autor ou que estão atribuídas a você)" + text_no_configuration_data: "Os Papéis, tipos de tarefas, situação de tarefas e fluxos de trabalho não foram configurados ainda.\nÉ altamente recomendado carregar as configurações padrão. Você poderá modificar estas configurações assim que carregadas." + text_load_default_configuration: Carregar a configuração padrão + text_status_changed_by_changeset: "Aplicado no changeset %{value}." + text_issues_destroy_confirmation: 'Você tem certeza que deseja excluir a(s) tarefa(s) selecionada(s)?' + text_select_project_modules: 'Selecione módulos para habilitar para este projeto:' + text_default_administrator_account_changed: Conta padrão do administrador alterada + text_file_repository_writable: Repositório com permissão de escrita + text_rmagick_available: RMagick disponível (opcional) + text_destroy_time_entries_question: "%{hours} horas de trabalho foram registradas nas tarefas que você está excluindo. O que você deseja fazer?" + text_destroy_time_entries: Excluir horas de trabalho + text_assign_time_entries_to_project: Atribuir estas horas de trabalho para outro projeto + text_reassign_time_entries: 'Atribuir horas reportadas para esta tarefa:' + text_user_wrote: "%{value} escreveu:" + text_enumeration_destroy_question: "%{count} objetos estão atribuídos a este valor." + text_enumeration_category_reassign_to: 'Reatribuí-los ao valor:' + text_email_delivery_not_configured: "O envio de e-mail não está configurado, e as notificações estão inativas.\nConfigure seu servidor SMTP no arquivo config/configuration.yml e reinicie a aplicação para ativá-las." + + default_role_manager: Gerente + default_role_developer: Desenvolvedor + default_role_reporter: Informante + default_tracker_bug: Defeito + default_tracker_feature: Funcionalidade + default_tracker_support: Suporte + default_issue_status_new: Nova + default_issue_status_in_progress: Em andamento + default_issue_status_resolved: Resolvida + default_issue_status_feedback: Feedback + default_issue_status_closed: Fechada + default_issue_status_rejected: Rejeitada + default_doc_category_user: Documentação do usuário + default_doc_category_tech: Documentação técnica + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_high: Alta + default_priority_urgent: Urgente + default_priority_immediate: Imediata + default_activity_design: Design + default_activity_development: Desenvolvimento + + enumeration_issue_priorities: Prioridade das tarefas + enumeration_doc_categories: Categorias de documento + enumeration_activities: Atividades (registro de horas) + notice_unable_delete_version: Não foi possível excluir a versão + label_renamed: renomeado + label_copied: copiado + setting_plain_text_mail: Usar mensagem sem formatação HTML + permission_view_files: Ver arquivos + permission_edit_issues: Editar tarefas + permission_edit_own_time_entries: Editar o próprio tempo de trabalho + permission_manage_public_queries: Gerenciar consultas publicas + permission_add_issues: Adicionar tarefas + permission_log_time: Adicionar tempo gasto + permission_view_changesets: Ver changesets + permission_view_time_entries: Ver tempo gasto + permission_manage_versions: Gerenciar versões + permission_manage_wiki: Gerenciar wiki + permission_manage_categories: Gerenciar categorias de tarefas + permission_protect_wiki_pages: Proteger páginas wiki + permission_comment_news: Comentar notícias + permission_delete_messages: Excluir mensagens + permission_select_project_modules: Selecionar módulos de projeto + permission_manage_documents: Gerenciar documentos + permission_edit_wiki_pages: Editar páginas wiki + permission_add_issue_watchers: Adicionar observadores + permission_view_gantt: Ver gráfico gantt + permission_move_issues: Mover tarefas + permission_manage_issue_relations: Gerenciar relacionamentos de tarefas + permission_delete_wiki_pages: Excluir páginas wiki + permission_manage_boards: Gerenciar fóruns + permission_delete_wiki_pages_attachments: Excluir anexos + permission_view_wiki_edits: Ver histórico do wiki + permission_add_messages: Postar mensagens + permission_view_messages: Ver mensagens + permission_manage_files: Gerenciar arquivos + permission_edit_issue_notes: Editar notas + permission_manage_news: Gerenciar notícias + permission_view_calendar: Ver calendário + permission_manage_members: Gerenciar membros + permission_edit_messages: Editar mensagens + permission_delete_issues: Excluir tarefas + permission_view_issue_watchers: Ver lista de observadores + permission_manage_repository: Gerenciar repositório + permission_commit_access: Acesso de commit + permission_browse_repository: Pesquisar repositório + permission_view_documents: Ver documentos + permission_edit_project: Editar projeto + permission_add_issue_notes: Adicionar notas + permission_save_queries: Salvar consultas + permission_view_wiki_pages: Ver wiki + permission_rename_wiki_pages: Renomear páginas wiki + permission_edit_time_entries: Editar tempo gasto + permission_edit_own_issue_notes: Editar suas próprias notas + setting_gravatar_enabled: Usar ícones do Gravatar + label_example: Exemplo + text_repository_usernames_mapping: "Seleciona ou atualiza os usuários do Redmine mapeando para cada usuário encontrado no log do repositório.\nUsuários com o mesmo login ou e-mail no Redmine e no repositório serão mapeados automaticamente." + permission_edit_own_messages: Editar próprias mensagens + permission_delete_own_messages: Excluir próprias mensagens + label_user_activity: "Atividade de %{value}" + label_updated_time_by: "Atualizado por %{author} há %{age}" + text_diff_truncated: '... Este diff foi truncado porque excede o tamanho máximo que pode ser exibido.' + setting_diff_max_lines_displayed: Número máximo de linhas exibidas no diff + text_plugin_assets_writable: Diretório de plugins gravável + warning_attachments_not_saved: "%{count} arquivo(s) não puderam ser salvo(s)." + button_create_and_continue: Criar e continuar + text_custom_field_possible_values_info: 'Uma linha para cada valor' + label_display: Exibição + field_editable: Editável + setting_repository_log_display_limit: Número máximo de revisões exibidas no arquivo de log + setting_file_max_size_displayed: Tamanho máximo dos arquivos textos exibidos inline + field_identity_urler: Observador + setting_openid: Permitir Login e Registro via OpenID + field_identity_url: OpenID URL + label_login_with_open_id_option: ou use o OpenID + field_content: Conteúdo + label_descending: Descendente + label_sort: Ordenar + label_ascending: Ascendente + label_date_from_to: De %{start} até %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Esta página tem %{descendants} página(s) filha(s) e descendente(s). O que você quer fazer? + text_wiki_page_reassign_children: Reatribuir páginas filhas para esta página pai + text_wiki_page_nullify_children: Manter as páginas filhas como páginas raízes + text_wiki_page_destroy_children: Excluir páginas filhas e todas suas descendentes + setting_password_min_length: Comprimento mínimo para senhas + field_group_by: Agrupar por + mail_subject_wiki_content_updated: "A página wiki '%{id}' foi atualizada" + label_wiki_content_added: Página wiki adicionada + mail_subject_wiki_content_added: "A página wiki '%{id}' foi adicionada" + mail_body_wiki_content_added: A página wiki '%{id}' foi adicionada por %{author}. + label_wiki_content_updated: Página wiki atualizada + mail_body_wiki_content_updated: A página wiki '%{id}' foi atualizada por %{author}. + permission_add_project: Criar projeto + setting_new_project_user_role_id: Papel atribuído a um usuário não-administrador que cria um projeto + label_view_all_revisions: Ver todas as revisões + label_tag: Etiqueta + label_branch: Ramo + text_journal_changed: "%{label} alterado de %{old} para %{new}" + text_journal_set_to: "%{label} ajustado para %{value}" + text_journal_deleted: "%{label} excluído (%{old})" + label_group_plural: Grupos + label_group: Grupo + label_group_new: Novo grupo + label_time_entry_plural: Tempos gastos + text_journal_added: "%{label} %{value} adicionado" + field_active: Ativo + enumeration_system_activity: Atividade do sistema + permission_delete_issue_watchers: Excluir observadores + version_status_closed: fechado + version_status_locked: travado + version_status_open: aberto + error_can_not_reopen_issue_on_closed_version: Uma tarefa atribuída a uma versão fechada não pode ser reaberta + label_user_anonymous: Anônimo + button_move_and_follow: Mover e seguir + setting_default_projects_modules: Módulos habilitados por padrão para novos projetos + setting_gravatar_default: Imagem-padrão de Gravatar + field_sharing: Compartilhamento + label_version_sharing_hierarchy: Com a hierarquia do projeto + label_version_sharing_system: Com todos os projetos + label_version_sharing_descendants: Com sub-projetos + label_version_sharing_tree: Com a árvore do projeto + label_version_sharing_none: Sem compartilhamento + error_can_not_archive_project: Este projeto não pode ser arquivado + button_duplicate: Duplicar + button_copy_and_follow: Copiar e seguir + label_copy_source: Origem + setting_issue_done_ratio: Calcular o percentual de conclusão da tarefa + setting_issue_done_ratio_issue_status: Usar a situação da tarefa + error_issue_done_ratios_not_updated: O pecentual de conclusão das tarefas não foi atualizado. + error_workflow_copy_target: Por favor, selecione os tipos de tarefa e os papéis alvo + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Mesmo alvo + label_copy_target: Alvo + notice_issue_done_ratios_updated: Percentual de conslusão atualizados. + error_workflow_copy_source: Por favor, selecione um tipo de tarefa e papel de origem + label_update_issue_done_ratios: Atualizar percentual de conclusão das tarefas + setting_start_of_week: Início da semana + field_watcher: Observador + permission_view_issues: Ver tarefas + label_display_used_statuses_only: Somente exibir situações que são usadas por este tipo de tarefa + label_revision_id: Revisão %{value} + label_api_access_key: Chave de acesso a API + button_show: Exibir + label_api_access_key_created_on: Chave de acesso a API criado a %{value} atrás + label_feeds_access_key: Chave de acesso ao RSS + notice_api_access_key_reseted: Sua chave de acesso a API foi redefinida. + setting_rest_api_enabled: Habilitar REST web service + label_missing_api_access_key: Chave de acesso a API faltando + label_missing_feeds_access_key: Chave de acesso ao RSS faltando + text_line_separated: Múltiplos valores permitidos (uma linha para cada valor). + setting_mail_handler_body_delimiters: Truncar e-mails após uma destas linhas + permission_add_subprojects: Criar subprojetos + label_subproject_new: Novo subprojeto + text_own_membership_delete_confirmation: |- + Você está para excluir algumas de suas próprias permissões e pode não mais estar apto a editar este projeto após esta operação. + Você tem certeza que deseja continuar? + label_close_versions: Fechar versões concluídas + label_board_sticky: Marcado + label_board_locked: Travado + label_change_log: Registro de alterações + permission_export_wiki_pages: Exportar páginas wiki + setting_cache_formatted_text: Realizar cache de texto formatado + permission_manage_project_activities: Gerenciar atividades do projeto + error_unable_delete_issue_status: Não foi possível excluir situação da tarefa + label_profile: Perfil + permission_manage_subtasks: Gerenciar subtarefas + field_parent_issue: Tarefa pai + label_subtask_plural: Subtarefas + label_project_copy_notifications: Enviar notificações por e-mail ao copiar projeto + error_can_not_delete_custom_field: Não foi possível excluir o campo personalizado + error_unable_to_connect: Não foi possível conectar (%{value}) + error_can_not_remove_role: Este papel está em uso e não pode ser excluído. + error_can_not_delete_tracker: Este tipo de tarefa está atribuído a alguma(s) tarefa(s) e não pode ser excluído. + field_principal: Principal + label_my_page_block: Meu bloco de página + notice_failed_to_save_members: "Falha ao gravar membro(s): %{errors}." + text_zoom_out: Afastar zoom + text_zoom_in: Aproximar zoom + notice_unable_delete_time_entry: Não foi possível excluir a entrada no registro de horas trabalhadas. + label_overall_spent_time: Tempo gasto geral + field_time_entries: Registro de horas + project_module_gantt: Gantt + project_module_calendar: Calendário + button_edit_associated_wikipage: "Editar página wiki relacionada: %{page_title}" + text_are_you_sure_with_children: Excluir a tarefa e suas subtarefas? + field_text: Campo de texto + label_user_mail_option_only_owner: Somente para as coisas que eu criei + setting_default_notification_option: Opção padrão de notificação + label_user_mail_option_only_my_events: Somente para as coisas que eu esteja observando ou esteja envolvido + label_user_mail_option_only_assigned: Somente para as coisas que estejam atribuídas a mim + label_user_mail_option_none: Sem eventos + field_member_of_group: Grupo do responsável + field_assigned_to_role: Papel do responsável + notice_not_authorized_archived_project: O projeto que você está tentando acessar foi arquivado. + label_principal_search: "Pesquisar por usuários ou grupos:" + label_user_search: "Pesquisar por usuário:" + field_visible: Visível + setting_emails_header: Cabeçalho do e-mail + setting_commit_logtime_activity_id: Atividade para registrar horas + text_time_logged_by_changeset: Aplicado no changeset %{value}. + setting_commit_logtime_enabled: Habilitar registro de horas + notice_gantt_chart_truncated: O gráfico foi cortado por exceder o tamanho máximo de linhas que podem ser exibidas (%{max}) + setting_gantt_items_limit: Número máximo de itens exibidos no gráfico gatt + field_warn_on_leaving_unsaved: Alertar-me ao sair de uma página sem salvar o texto + text_warn_on_leaving_unsaved: A página atual contem texto que não foi salvo e será perdido se você sair desta página. + label_my_queries: Minhas consultas personalizadas + text_journal_changed_no_detail: "%{label} atualizado(a)" + label_news_comment_added: Notícia recebeu um comentário + button_expand_all: Expandir tudo + button_collapse_all: Recolher tudo + label_additional_workflow_transitions_for_assignee: Transições adicionais permitidas quando o usuário é o responsável pela tarefa + label_additional_workflow_transitions_for_author: Transições adicionais permitidas quando o usuário é o autor + + label_bulk_edit_selected_time_entries: Alteração em massa do registro de horas + text_time_entries_destroy_confirmation: Tem certeza que quer excluir o(s) registro(s) de horas selecionado(s)? + label_role_anonymous: Anônimo + label_role_non_member: Não Membro + label_issues_visibility_own: Tarefas criadas ou atribuídas ao usuário + field_issues_visibility: Visibilidade das tarefas + label_issues_visibility_all: Todas as tarefas + permission_set_own_issues_private: Alterar as próprias tarefas para públicas ou privadas + field_is_private: Privado + permission_set_issues_private: Alterar tarefas para públicas ou privadas + label_issues_visibility_public: Todas as tarefas não privadas + text_issues_destroy_descendants_confirmation: Isto também irá excluir %{count} subtarefa(s). + field_commit_logs_encoding: Codificação das mensagens de commit + field_scm_path_encoding: Codificação do caminho + text_scm_path_encoding_note: "Padrão: UTF-8" + field_path_to_repository: Caminho para o repositório + field_root_directory: Diretório raiz + field_cvs_module: Módulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: "Repositório local (ex.: /hgrepo, c:\\hgrepo)" + text_scm_command: Comando + text_scm_command_version: Versão + label_git_report_last_commit: Relatar última alteração para arquivos e diretórios + text_scm_config: Você pode configurar seus comandos de versionamento em config/configurations.yml. Por favor reinicie a aplicação após alterá-lo. + text_scm_command_not_available: Comando de versionamento não disponível. Por favor verifique as configurações no painel de administração. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Escopo da pesquisa + description_filter: Filtro + description_user_mail_notification: Configuração de notificações por e-mail + description_date_from: Digita a data inicial + description_message_content: Conteúdo da mensagem + description_available_columns: Colunas disponíveis + description_date_range_interval: Escolha um período selecionando a data de início e fim + description_issue_category_reassign: Escolha uma categoria de tarefas + description_search: Searchfield + description_notes: Notas + description_date_range_list: Escolha um período a partira da lista + description_choose_project: Projetos + description_date_to: Digite a data final + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Escolha uma nova página pai + description_selected_columns: Colunas selecionadas + + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Usar data corrente como data inicial para novas tarefas + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/87/87f2907d35c31e8abc92c6fcec7d6b888afd66cc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/87/87f2907d35c31e8abc92c6fcec7d6b888afd66cc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeAttachmentsContentTypeLimit < ActiveRecord::Migration + def self.up + change_column :attachments, :content_type, :string, :limit => nil + end + + def self.down + change_column :attachments, :content_type, :string, :limit => 60 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/88/881a521bb02c20d53a2e7902239ac48ee09fb6ab.svn-base Binary file .svn/pristine/88/881a521bb02c20d53a2e7902239ac48ee09fb6ab.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/88/88c21d3e94bdee7dc87512ce70ad25e02ec401ea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/88/88c21d3e94bdee7dc87512ce70ad25e02ec401ea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +TCPDFFontDescriptor.define('helvetica') do |font| + font[:cw]={ + 0.chr=>278, 1.chr=>278, 2.chr=>278, 3.chr=>278, 4.chr=>278, 5.chr=>278, 6.chr=>278, 7.chr=>278, 8.chr=>278, 9.chr=>278, 10.chr=>278, 11.chr=>278, 12.chr=>278, 13.chr=>278, 14.chr=>278, 15.chr=>278, 16.chr=>278, 17.chr=>278, 18.chr=>278, 19.chr=>278, 20.chr=>278, 21.chr=>278, 22.chr=>278, 23.chr=>278, 24.chr=>278, 25.chr=>278, 26.chr=>278, 27.chr=>278, 28.chr=>278, 29.chr=>278, 30.chr=>278, 31.chr=>278, ' '=>278, '!'=>278, '"'=>355, '#'=>556, '$'=>556, '%'=>889, '&'=>667, '\''=>191, '('=>333, ')'=>333, '*'=>389, '+'=>584, ','=>278, '-'=>333, '.'=>278, '/'=>278, '0'=>556, '1'=>556, '2'=>556, '3'=>556, '4'=>556, '5'=>556, '6'=>556, '7'=>556, '8'=>556, '9'=>556, ':'=>278, ';'=>278, '<'=>584, '='=>584, '>'=>584, '?'=>556, '@'=>1015, 'A'=>667, 'B'=>667, 'C'=>722, 'D'=>722, 'E'=>667, 'F'=>611, 'G'=>778, 'H'=>722, 'I'=>278, 'J'=>500, 'K'=>667, 'L'=>556, 'M'=>833, 'N'=>722, 'O'=>778, 'P'=>667, 'Q'=>778, 'R'=>722, 'S'=>667, 'T'=>611, 'U'=>722, 'V'=>667, 'W'=>944, 'X'=>667, 'Y'=>667, 'Z'=>611, '['=>278, '\\'=>278, ']'=>278, '^'=>469, '_'=>556, '`'=>333, 'a'=>556, 'b'=>556, 'c'=>500, 'd'=>556, 'e'=>556, 'f'=>278, 'g'=>556, 'h'=>556, 'i'=>222, 'j'=>222, 'k'=>500, 'l'=>222, 'm'=>833, 'n'=>556, 'o'=>556, 'p'=>556, 'q'=>556, 'r'=>333, 's'=>500, 't'=>278, 'u'=>556, 'v'=>500, 'w'=>722, 'x'=>500, 'y'=>500, 'z'=>500, '{'=>334, '|'=>260, '}'=>334, '~'=>584, 127.chr=>350, 128.chr=>556, 129.chr=>350, 130.chr=>222, 131.chr=>556, 132.chr=>333, 133.chr=>1000, 134.chr=>556, 135.chr=>556, 136.chr=>333, 137.chr=>1000, 138.chr=>667, 139.chr=>333, 140.chr=>1000, 141.chr=>350, 142.chr=>611, 143.chr=>350, 144.chr=>350, 145.chr=>222, 146.chr=>222, 147.chr=>333, 148.chr=>333, 149.chr=>350, 150.chr=>556, 151.chr=>1000, 152.chr=>333, 153.chr=>1000, 154.chr=>500, 155.chr=>333, 156.chr=>944, 157.chr=>350, 158.chr=>500, 159.chr=>667, 160.chr=>278, 161.chr=>333, 162.chr=>556, 163.chr=>556, 164.chr=>556, 165.chr=>556, 166.chr=>260, 167.chr=>556, 168.chr=>333, 169.chr=>737, 170.chr=>370, 171.chr=>556, 172.chr=>584, 173.chr=>333, 174.chr=>737, 175.chr=>333, 176.chr=>400, 177.chr=>584, 178.chr=>333, 179.chr=>333, 180.chr=>333, 181.chr=>556, 182.chr=>537, 183.chr=>278, 184.chr=>333, 185.chr=>333, 186.chr=>365, 187.chr=>556, 188.chr=>834, 189.chr=>834, 190.chr=>834, 191.chr=>611, 192.chr=>667, 193.chr=>667, 194.chr=>667, 195.chr=>667, 196.chr=>667, 197.chr=>667, 198.chr=>1000, 199.chr=>722, 200.chr=>667, 201.chr=>667, 202.chr=>667, 203.chr=>667, 204.chr=>278, 205.chr=>278, 206.chr=>278, 207.chr=>278, 208.chr=>722, 209.chr=>722, 210.chr=>778, 211.chr=>778, 212.chr=>778, 213.chr=>778, 214.chr=>778, 215.chr=>584, 216.chr=>778, 217.chr=>722, 218.chr=>722, 219.chr=>722, 220.chr=>722, 221.chr=>667, 222.chr=>667, 223.chr=>611, 224.chr=>556, 225.chr=>556, 226.chr=>556, 227.chr=>556, 228.chr=>556, 229.chr=>556, 230.chr=>889, 231.chr=>500, 232.chr=>556, 233.chr=>556, 234.chr=>556, 235.chr=>556, 236.chr=>278, 237.chr=>278, 238.chr=>278, 239.chr=>278, 240.chr=>556, 241.chr=>556, 242.chr=>556, 243.chr=>556, 244.chr=>556, 245.chr=>556, 246.chr=>556, 247.chr=>584, 248.chr=>611, 249.chr=>556, 250.chr=>556, 251.chr=>556, 252.chr=>556, 253.chr=>500, 254.chr=>556, 255.chr=>500} +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/89021103ecb16e23dc5cc611fa652e5e895e947c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/89021103ecb16e23dc5cc611fa652e5e895e947c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,86 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +module RedmineMenuTestHelper + # Assertions + def assert_number_of_items_in_menu(menu_name, count) + assert Redmine::MenuManager.items(menu_name).size >= count, "Menu has less than #{count} items" + end + + def assert_menu_contains_item_named(menu_name, item_name) + assert Redmine::MenuManager.items(menu_name).collect(&:name).include?(item_name.to_sym), "Menu did not have an item named #{item_name}" + end + + # Helpers + def get_menu_item(menu_name, item_name) + Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym} + end +end + +class RedmineTest < ActiveSupport::TestCase + include RedmineMenuTestHelper + + def test_top_menu + assert_number_of_items_in_menu :top_menu, 5 + assert_menu_contains_item_named :top_menu, :home + assert_menu_contains_item_named :top_menu, :my_page + assert_menu_contains_item_named :top_menu, :projects + assert_menu_contains_item_named :top_menu, :administration + assert_menu_contains_item_named :top_menu, :help + end + + def test_account_menu + assert_number_of_items_in_menu :account_menu, 4 + assert_menu_contains_item_named :account_menu, :login + assert_menu_contains_item_named :account_menu, :register + assert_menu_contains_item_named :account_menu, :my_account + assert_menu_contains_item_named :account_menu, :logout + end + + def test_application_menu + assert_number_of_items_in_menu :application_menu, 0 + end + + def test_admin_menu + assert_number_of_items_in_menu :admin_menu, 0 + end + + def test_project_menu + assert_number_of_items_in_menu :project_menu, 14 + assert_menu_contains_item_named :project_menu, :overview + assert_menu_contains_item_named :project_menu, :activity + assert_menu_contains_item_named :project_menu, :roadmap + assert_menu_contains_item_named :project_menu, :issues + assert_menu_contains_item_named :project_menu, :new_issue + assert_menu_contains_item_named :project_menu, :calendar + assert_menu_contains_item_named :project_menu, :gantt + assert_menu_contains_item_named :project_menu, :news + assert_menu_contains_item_named :project_menu, :documents + assert_menu_contains_item_named :project_menu, :wiki + assert_menu_contains_item_named :project_menu, :boards + assert_menu_contains_item_named :project_menu, :files + assert_menu_contains_item_named :project_menu, :repository + assert_menu_contains_item_named :project_menu, :settings + end + + def test_new_issue_should_have_root_as_a_parent + new_issue = get_menu_item(:project_menu, :new_issue) + assert_equal :root, new_issue.parent.name + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/894f61e1593e5111f70c0b60e768f70d33aa6d50.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/894f61e1593e5111f70c0b60e768f70d33aa6d50.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,221 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class RepositorySubversionTest < ActiveSupport::TestCase + fixtures :projects, :repositories, :enabled_modules, :users, :roles + + NUM_REV = 11 + + def setup + @project = Project.find(3) + @repository = Repository::Subversion.create(:project => @project, + :url => self.class.subversion_repository_url) + assert @repository + end + + if repository_configured?('subversion') + def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + + assert_equal NUM_REV, @repository.changesets.count + assert_equal 20, @repository.changes.count + assert_equal 'Initial import.', @repository.changesets.find_by_revision('1').comments + end + + def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + # Remove changesets with revision > 5 + @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 5} + @project.reload + assert_equal 5, @repository.changesets.count + + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + end + + def test_latest_changesets + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + # with limit + changesets = @repository.latest_changesets('', nil, 2) + assert_equal 2, changesets.size + assert_equal @repository.latest_changesets('', nil).slice(0,2), changesets + + # with path + changesets = @repository.latest_changesets('subversion_test/folder', nil) + assert_equal ["10", "9", "7", "6", "5", "2"], changesets.collect(&:revision) + + # with path and revision + changesets = @repository.latest_changesets('subversion_test/folder', 8) + assert_equal ["7", "6", "5", "2"], changesets.collect(&:revision) + end + + def test_directory_listing_with_square_brackets_in_path + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + entries = @repository.entries('subversion_test/[folder_with_brackets]') + assert_not_nil entries, 'Expect to find entries in folder_with_brackets' + assert_equal 1, entries.size, 'Expect one entry in folder_with_brackets' + assert_equal 'README.txt', entries.first.name + end + + def test_directory_listing_with_square_brackets_in_base + @project = Project.find(3) + @repository = Repository::Subversion.create( + :project => @project, + :url => "file:///#{self.class.repository_path('subversion')}/subversion_test/[folder_with_brackets]") + + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + + assert_equal 1, @repository.changesets.count, 'Expected to see 1 revision' + assert_equal 2, @repository.changes.count, 'Expected to see 2 changes, dir add and file add' + + entries = @repository.entries('') + assert_not_nil entries, 'Expect to find entries' + assert_equal 1, entries.size, 'Expect a single entry' + assert_equal 'README.txt', entries.first.name + end + + def test_identifier + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + c = @repository.changesets.find_by_revision('1') + assert_equal c.revision, c.identifier + end + + def test_find_changeset_by_empty_name + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['', ' ', nil].each do |r| + assert_nil @repository.find_changeset_by_name(r) + end + end + + def test_identifier_nine_digit + c = Changeset.new(:repository => @repository, :committed_on => Time.now, + :revision => '123456789', :comments => 'test') + assert_equal c.identifier, c.revision + end + + def test_format_identifier + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + c = @repository.changesets.find_by_revision('1') + assert_equal c.format_identifier, c.revision + end + + def test_format_identifier_nine_digit + c = Changeset.new(:repository => @repository, :committed_on => Time.now, + :revision => '123456789', :comments => 'test') + assert_equal c.format_identifier, c.revision + end + + def test_activities + c = Changeset.new(:repository => @repository, :committed_on => Time.now, + :revision => '1', :comments => 'test') + assert c.event_title.include?('1:') + assert_equal '1', c.event_url[:rev] + end + + def test_activities_nine_digit + c = Changeset.new(:repository => @repository, :committed_on => Time.now, + :revision => '123456789', :comments => 'test') + assert c.event_title.include?('123456789:') + assert_equal '123456789', c.event_url[:rev] + end + + def test_log_encoding_ignore_setting + with_settings :commit_logs_encoding => 'windows-1252' do + s1 = "\xC2\x80" + s2 = "\xc3\x82\xc2\x80" + if s1.respond_to?(:force_encoding) + s1.force_encoding('ISO-8859-1') + s2.force_encoding('UTF-8') + assert_equal s1.encode('UTF-8'), s2 + end + c = Changeset.new(:repository => @repository, + :comments => s2, + :revision => '123', + :committed_on => Time.now) + assert c.save + assert_equal s2, c.comments + end + end + + def test_previous + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + changeset = @repository.find_changeset_by_name('3') + assert_equal @repository.find_changeset_by_name('2'), changeset.previous + end + + def test_previous_nil + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + changeset = @repository.find_changeset_by_name('1') + assert_nil changeset.previous + end + + def test_next + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + changeset = @repository.find_changeset_by_name('2') + assert_equal @repository.find_changeset_by_name('3'), changeset.next + end + + def test_next_nil + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + changeset = @repository.find_changeset_by_name('11') + assert_nil changeset.next + end + else + puts "Subversion test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/896d2497486a7dfbefa5146aaa83a0fc9dd4aa0c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/896d2497486a7dfbefa5146aaa83a0fc9dd4aa0c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,179 @@ +module CodeRay + module Encoders + + # Outputs code highlighted for a color terminal. + # + # Note: This encoder is in beta. It currently doesn't use the Styles. + # + # Alias: +term+ + # + # == Authors & License + # + # By Rob Aldred (http://robaldred.co.uk) + # + # Based on idea by Nathan Weizenbaum (http://nex-3.com) + # + # MIT License (http://www.opensource.org/licenses/mit-license.php) + class Terminal < Encoder + + register_for :terminal + + TOKEN_COLORS = { + :annotation => '35', + :attribute_name => '33', + :attribute_value => '31', + :binary => '1;35', + :char => { + :self => '36', :delimiter => '34' + }, + :class => '1;35', + :class_variable => '36', + :color => '32', + :comment => '37', + :complex => '34', + :constant => ['34', '4'], + :decoration => '35', + :definition => '1;32', + :directive => ['32', '4'], + :doc => '46', + :doctype => '1;30', + :doc_string => ['31', '4'], + :entity => '33', + :error => ['1;33', '41'], + :exception => '1;31', + :float => '1;35', + :function => '1;34', + :global_variable => '42', + :hex => '1;36', + :include => '33', + :integer => '1;34', + :key => '35', + :label => '1;15', + :local_variable => '33', + :octal => '1;35', + :operator_name => '1;29', + :predefined_constant => '1;36', + :predefined_type => '1;30', + :predefined => ['4', '1;34'], + :preprocessor => '36', + :pseudo_class => '34', + :regexp => { + :self => '31', + :content => '31', + :delimiter => '1;29', + :modifier => '35', + :function => '1;29' + }, + :reserved => '1;31', + :shell => { + :self => '42', + :content => '1;29', + :delimiter => '37', + }, + :string => { + :self => '32', + :modifier => '1;32', + :escape => '1;36', + :delimiter => '1;32', + }, + :symbol => '1;32', + :tag => '34', + :type => '1;34', + :value => '36', + :variable => '34', + + :insert => '42', + :delete => '41', + :change => '44', + :head => '45' + } + TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved] + TOKEN_COLORS[:method] = TOKEN_COLORS[:function] + TOKEN_COLORS[:imaginary] = TOKEN_COLORS[:complex] + TOKEN_COLORS[:begin_group] = TOKEN_COLORS[:end_group] = + TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter] + + protected + + def setup(options) + super + @opened = [] + @subcolors = nil + end + + public + + def text_token text, kind + if color = (@subcolors || TOKEN_COLORS)[kind] + if Hash === color + if color[:self] + color = color[:self] + else + @out << text + return + end + end + + @out << ansi_colorize(color) + @out << text.gsub("\n", ansi_clear + "\n" + ansi_colorize(color)) + @out << ansi_clear + @out << ansi_colorize(@subcolors[:self]) if @subcolors && @subcolors[:self] + else + @out << text + end + end + + def begin_group kind + @opened << kind + @out << open_token(kind) + end + alias begin_line begin_group + + def end_group kind + if @opened.empty? + # nothing to close + else + @opened.pop + @out << ansi_clear + @out << open_token(@opened.last) + end + end + + def end_line kind + if @opened.empty? + # nothing to close + else + @opened.pop + # whole lines to be highlighted, + # eg. added/modified/deleted lines in a diff + @out << "\t" * 100 + ansi_clear + @out << open_token(@opened.last) + end + end + + private + + def open_token kind + if color = TOKEN_COLORS[kind] + if Hash === color + @subcolors = color + ansi_colorize(color[:self]) if color[:self] + else + @subcolors = {} + ansi_colorize(color) + end + else + @subcolors = nil + '' + end + end + + def ansi_colorize(color) + Array(color).map { |c| "\e[#{c}m" }.join + end + def ansi_clear + ansi_colorize(0) + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/897b626212349973674b6ac9d8e1146f917d303b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/897b626212349973674b6ac9d8e1146f917d303b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +--- +members_001: + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 1 + id: 1 + user_id: 2 + mail_notification: true +members_002: + created_on: 2006-07-19 19:35:36 +02:00 + project_id: 1 + id: 2 + user_id: 3 + mail_notification: true +members_003: + created_on: 2006-07-19 19:35:36 +02:00 + project_id: 2 + id: 3 + user_id: 2 + mail_notification: true +members_004: + id: 4 + created_on: 2006-07-19 19:35:36 +02:00 + project_id: 1 + # Locked user + user_id: 5 + mail_notification: true +members_005: + id: 5 + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 5 + user_id: 2 + mail_notification: true +members_006: + id: 6 + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 5 + user_id: 10 + mail_notification: false +members_007: + id: 7 + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 5 + user_id: 8 + mail_notification: false +members_008: + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 5 + id: 8 + user_id: 1 + mail_notification: true +members_009: + id: 9 + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 2 + user_id: 11 + mail_notification: false +members_010: + id: 10 + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 2 + user_id: 8 + mail_notification: false diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/89879d5f63daa96be062efc907c338deadd682c1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/89879d5f63daa96be062efc907c338deadd682c1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +class CreateChangesets < ActiveRecord::Migration + def self.up + create_table :changesets do |t| + t.column :repository_id, :integer, :null => false + t.column :revision, :integer, :null => false + t.column :committer, :string, :limit => 30 + t.column :committed_on, :datetime, :null => false + t.column :comments, :text + end + add_index :changesets, [:repository_id, :revision], :unique => true, :name => :changesets_repos_rev + end + + def self.down + drop_table :changesets + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/899fc5d76ba5b79062018e92150433654216dd83.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/899fc5d76ba5b79062018e92150433654216dd83.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +module CodeRay + VERSION = '1.0.0' +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/89de0a30fbe820a24f361c69ba0c73b295dd67c1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/89de0a30fbe820a24f361c69ba0c73b295dd67c1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class WikiRedirect < ActiveRecord::Base + generator_for :title, :start => 'AWikiPage' + generator_for :redirects_to, :start => '/a/path/000001' + generator_for :wiki, :method => :generate_wiki + + def self.generate_wiki + Wiki.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/89/89f5504f7426bd8b866f9fb941e83b8b3b055e7a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/89/89f5504f7426bd8b866f9fb941e83b8b3b055e7a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,104 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 + class CustomFieldFormat + include Redmine::I18n + + cattr_accessor :available + @@available = {} + + attr_accessor :name, :order, :label, :edit_as, :class_names + + def initialize(name, options={}) + self.name = name + self.label = options[:label] + self.order = options[:order] + self.edit_as = options[:edit_as] || name + self.class_names = options[:only] + end + + def format(value) + send "format_as_#{name}", value + end + + def format_as_date(value) + begin; format_date(value.to_date); rescue; value end + end + + def format_as_bool(value) + l(value == "1" ? :general_text_Yes : :general_text_No) + end + + ['string','text','int','float','list'].each do |name| + define_method("format_as_#{name}") {|value| + return value + } + end + + ['user', 'version'].each do |name| + define_method("format_as_#{name}") {|value| + return value.blank? ? "" : name.classify.constantize.find_by_id(value.to_i).to_s + } + end + + class << self + def map(&block) + yield self + end + + # Registers a custom field format + def register(custom_field_format, options={}) + @@available[custom_field_format.name] = custom_field_format unless @@available.keys.include?(custom_field_format.name) + end + + def available_formats + @@available.keys + end + + def find_by_name(name) + @@available[name.to_s] + end + + def label_for(name) + format = @@available[name.to_s] + format.label if format + end + + # Return an array of custom field formats which can be used in select_tag + def as_select(class_name=nil) + fields = @@available.values + fields = fields.select {|field| field.class_names.nil? || field.class_names.include?(class_name)} + fields.sort {|a,b| + a.order <=> b.order + }.collect {|custom_field_format| + [ l(custom_field_format.label), custom_field_format.name ] + } + end + + def format_value(value, field_format) + return "" unless value && !value.empty? + + if format_type = find_by_name(field_format) + format_type.format(value) + else + value + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8a0afb114464a58c980d1c1fc330e4d0f4da9931.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8a0afb114464a58c980d1c1fc330e4d0f4da9931.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + drop_table :open_id_authentication_settings + drop_table :open_id_authentication_nonces + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_nonces + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :created + t.string :nonce + end + + create_table :open_id_authentication_settings, :force => true do |t| + t.string :setting + t.binary :value + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8a2387840fb935aa8f0a3b22e4246aa11a6a6959.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8a2387840fb935aa8f0a3b22e4246aa11a6a6959.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeChangesFromRevisionToString < ActiveRecord::Migration + def self.up + change_column :changes, :from_revision, :string + end + + def self.down + change_column :changes, :from_revision, :integer + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8a4b8b250e38c9c5c65661973d49cb661d84e614.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8a4b8b250e38c9c5c65661973d49cb661d84e614.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,158 @@ +module CodeRay +module Encoders + + class HTML + + # This module is included in the output String of the HTML Encoder. + # + # It provides methods like wrap, div, page etc. + # + # Remember to use #clone instead of #dup to keep the modules the object was + # extended with. + # + # TODO: Rewrite this without monkey patching. + module Output + + attr_accessor :css + + class << self + + # Raises an exception if an object that doesn't respond to to_str is extended by Output, + # to prevent users from misuse. Use Module#remove_method to disable. + def extended o # :nodoc: + warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str + end + + def make_stylesheet css, in_tag = false # :nodoc: + sheet = css.stylesheet + sheet = <<-'CSS' if in_tag + + CSS + sheet + end + + def page_template_for_css css # :nodoc: + sheet = make_stylesheet css + PAGE.apply 'CSS', sheet + end + + end + + def wrapped_in? element + wrapped_in == element + end + + def wrapped_in + @wrapped_in ||= nil + end + attr_writer :wrapped_in + + def wrap_in! template + Template.wrap! self, template, 'CONTENT' + self + end + + def apply_title! title + self.sub!(/()(<\/title>)/) { $1 + title + $2 } + self + end + + def wrap! element, *args + return self if not element or element == wrapped_in + case element + when :div + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! DIV + when :span + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! SPAN + when :page + wrap! :div if wrapped_in? nil + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div + wrap_in! Output.page_template_for_css(@css) + if args.first.is_a?(Hash) && title = args.first[:title] + apply_title! title + end + self + when nil + return self + else + raise "Unknown value %p for :wrap" % element + end + @wrapped_in = element + self + end + + def stylesheet in_tag = false + Output.make_stylesheet @css, in_tag + end + +#-- don't include the templates in docu + + class Template < String # :nodoc: + + def self.wrap! str, template, target + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if template =~ target + str[0,0] = $` + str << $' + else + raise "Template target <%%%p%%> not found" % target + end + end + + def apply target, replacement + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if self =~ target + Template.new($` + replacement + $') + else + raise "Template target <%%%p%%> not found" % target + end + end + + end + + SPAN = Template.new '<span class="CodeRay"><%CONTENT%></span>' + + DIV = Template.new <<-DIV +<div class="CodeRay"> + <div class="code"><pre><%CONTENT%></pre></div> +</div> + DIV + + TABLE = Template.new <<-TABLE +<table class="CodeRay"><tr> + <td class="line-numbers" title="double click to toggle" ondblclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td> + <td class="code"><pre><%CONTENT%></pre></td> +</tr></table> + TABLE + + PAGE = Template.new <<-PAGE +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title> + + + + +<%CONTENT%> + + + PAGE + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8a5fb0079b7bc3191dfd37b1677f3f459fe6d66e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8a5fb0079b7bc3191dfd37b1677f3f459fe6d66e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,241 @@ +require 'SVG/Graph/Plot' +require 'parsedate' + +module SVG + module Graph + # === For creating SVG plots of scalar temporal data + # + # = Synopsis + # + # require 'SVG/Graph/TimeSeriess' + # + # # Data sets are x,y pairs + # data1 = ["6/17/72", 11, "1/11/72", 7, "4/13/04 17:31", 11, + # "9/11/01", 9, "9/1/85", 2, "9/1/88", 1, "1/15/95", 13] + # data2 = ["8/1/73", 18, "3/1/77", 15, "10/1/98", 4, + # "5/1/02", 14, "3/1/95", 6, "8/1/91", 12, "12/1/87", 6, + # "5/1/84", 17, "10/1/80", 12] + # + # graph = SVG::Graph::TimeSeries.new( { + # :width => 640, + # :height => 480, + # :graph_title => title, + # :show_graph_title => true, + # :no_css => true, + # :key => true, + # :scale_x_integers => true, + # :scale_y_integers => true, + # :min_x_value => 0, + # :min_y_value => 0, + # :show_data_labels => true, + # :show_x_guidelines => true, + # :show_x_title => true, + # :x_title => "Time", + # :show_y_title => true, + # :y_title => "Ice Cream Cones", + # :y_title_text_direction => :bt, + # :stagger_x_labels => true, + # :x_label_format => "%m/%d/%y", + # }) + # + # graph.add_data({ + # :data => projection + # :title => 'Projected', + # }) + # + # graph.add_data({ + # :data => actual, + # :title => 'Actual', + # }) + # + # print graph.burn() + # + # = Description + # + # Produces a graph of temporal scalar data. + # + # = Examples + # + # http://www.germane-software/repositories/public/SVG/test/timeseries.rb + # + # = Notes + # + # The default stylesheet handles upto 10 data sets, if you + # use more you must create your own stylesheet and add the + # additional settings for the extra data sets. You will know + # if you go over 10 data sets as they will have no style and + # be in black. + # + # Unlike the other types of charts, data sets must contain x,y pairs: + # + # [ "12:30", 2 ] # A data set with 1 point: ("12:30",2) + # [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and + # # ("14:20",6) + # + # Note that multiple data sets within the same chart can differ in length, + # and that the data in the datasets needn't be in order; they will be ordered + # by the plot along the X-axis. + # + # The dates must be parseable by ParseDate, but otherwise can be + # any order of magnitude (seconds within the hour, or years) + # + # = See also + # + # * SVG::Graph::Graph + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Bar + # * SVG::Graph::Line + # * SVG::Graph::Pie + # * SVG::Graph::Plot + # + # == Author + # + # Sean E. Russell + # + # Copyright 2004 Sean E. Russell + # This software is available under the Ruby license[LICENSE.txt] + # + class TimeSeries < Plot + # In addition to the defaults set by Graph::initialize and + # Plot::set_defaults, sets: + # [x_label_format] '%Y-%m-%d %H:%M:%S' + # [popup_format] '%Y-%m-%d %H:%M:%S' + def set_defaults + super + init_with( + #:max_time_span => '', + :x_label_format => '%Y-%m-%d %H:%M:%S', + :popup_format => '%Y-%m-%d %H:%M:%S' + ) + end + + # The format string use do format the X axis labels. + # See Time::strformat + attr_accessor :x_label_format + # Use this to set the spacing between dates on the axis. The value + # must be of the form + # "\d+ ?(days|weeks|months|years|hours|minutes|seconds)?" + # + # EG: + # + # graph.timescale_divisions = "2 weeks" + # + # will cause the chart to try to divide the X axis up into segments of + # two week periods. + attr_accessor :timescale_divisions + # The formatting used for the popups. See x_label_format + attr_accessor :popup_format + + # Add data to the plot. + # + # d1 = [ "12:30", 2 ] # A data set with 1 point: ("12:30",2) + # d2 = [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and + # # ("14:20",6) + # graph.add_data( + # :data => d1, + # :title => 'One' + # ) + # graph.add_data( + # :data => d2, + # :title => 'Two' + # ) + # + # Note that the data must be in time,value pairs, and that the date format + # may be any date that is parseable by ParseDate. + def add_data data + @data = [] unless @data + + raise "No data provided by #{@data.inspect}" unless data[:data] and + data[:data].kind_of? Array + raise "Data supplied must be x,y pairs! "+ + "The data provided contained an odd set of "+ + "data points" unless data[:data].length % 2 == 0 + return if data[:data].length == 0 + + + x = [] + y = [] + data[:data].each_index {|i| + if i%2 == 0 + arr = ParseDate.parsedate( data[:data][i] ) + t = Time.local( *arr[0,6].compact ) + x << t.to_i + else + y << data[:data][i] + end + } + sort( x, y ) + data[:data] = [x,y] + @data << data + end + + + protected + + def min_x_value=(value) + arr = ParseDate.parsedate( value ) + @min_x_value = Time.local( *arr[0,6].compact ).to_i + end + + + def format x, y + Time.at( x ).strftime( popup_format ) + end + + def get_x_labels + get_x_values.collect { |v| Time.at(v).strftime( x_label_format ) } + end + + private + def get_x_values + rv = [] + min, max, scale_division = x_range + if timescale_divisions + timescale_divisions =~ /(\d+) ?(day|week|month|year|hour|minute|second)?/ + division_units = $2 ? $2 : "day" + amount = $1.to_i + if amount + step = nil + case division_units + when "month" + cur = min + while cur < max + rv << cur + arr = Time.at( cur ).to_a + arr[4] += amount + if arr[4] > 12 + arr[5] += (arr[4] / 12).to_i + arr[4] = (arr[4] % 12) + end + cur = Time.local(*arr).to_i + end + when "year" + cur = min + while cur < max + rv << cur + arr = Time.at( cur ).to_a + arr[5] += amount + cur = Time.local(*arr).to_i + end + when "week" + step = 7 * 24 * 60 * 60 * amount + when "day" + step = 24 * 60 * 60 * amount + when "hour" + step = 60 * 60 * amount + when "minute" + step = 60 * amount + when "second" + step = amount + end + min.step( max, step ) {|v| rv << v} if step + + return rv + end + end + min.step( max, scale_division ) {|v| rv << v} + return rv + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8a838241ecb1de57abec573d9ab086b1b83f3ab1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8a838241ecb1de57abec573d9ab086b1b83f3ab1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,174 @@ +module CodeRay module Scanners + + # by Josh Goebel + class SQL < Scanner + + register_for :sql + + KEYWORDS = %w( + all and any as before begin between by case check collate + each else end exists + for foreign from full group having if in inner is join + like not of on or order outer over references + then to union using values when where + left right distinct + ) + + OBJECTS = %w( + database databases table tables column columns fields index constraint + constraints transaction function procedure row key view trigger + ) + + COMMANDS = %w( + add alter comment create delete drop grant insert into select update set + show prompt begin commit rollback replace truncate + ) + + PREDEFINED_TYPES = %w( + char varchar varchar2 enum binary text tinytext mediumtext + longtext blob tinyblob mediumblob longblob timestamp + date time datetime year double decimal float int + integer tinyint mediumint bigint smallint unsigned bit + bool boolean hex bin oct + ) + + PREDEFINED_FUNCTIONS = %w( sum cast substring abs pi count min max avg now ) + + DIRECTIVES = %w( + auto_increment unique default charset initially deferred + deferrable cascade immediate read write asc desc after + primary foreign return engine + ) + + PREDEFINED_CONSTANTS = %w( null true false ) + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(OBJECTS, :type). + add(COMMANDS, :class). + add(PREDEFINED_TYPES, :predefined_type). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(PREDEFINED_FUNCTIONS, :predefined). + add(DIRECTIVES, :directive) + + ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x + + STRING_PREFIXES = /[xnb]|_\w+/i + + def scan_tokens encoder, options + + state = :initial + string_type = nil + string_content = '' + name_expected = false + + until eos? + + if state == :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + + elsif match = scan(/(?:--\s?|#).*/) + encoder.text_token match, :comment + + elsif match = scan(%r( /\* (!)? (?: .*? \*/ | .* ) )mx) + encoder.text_token match, self[1] ? :directive : :comment + + elsif match = scan(/ [*\/=<>:;,!&^|()\[\]{}~%] | [-+\.](?!\d) /x) + name_expected = true if match == '.' && check(/[A-Za-z_]/) + encoder.text_token match, :operator + + elsif match = scan(/(#{STRING_PREFIXES})?([`"'])/o) + prefix = self[1] + string_type = self[2] + encoder.begin_group :string + encoder.text_token prefix, :modifier if prefix + match = string_type + state = :string + encoder.text_token match, :delimiter + + elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x) + encoder.text_token match, name_expected ? :ident : (match[0] == ?@ ? :variable : IDENT_KIND[match]) + name_expected = false + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + + elsif match = scan(/0[0-7]+(?![89.eEfF])/) + encoder.text_token match, :octal + + elsif match = scan(/[-+]?(?>\d+)(?![.eEfF])/) + encoder.text_token match, :integer + + elsif match = scan(/[-+]?(?:\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+)/) + encoder.text_token match, :float + + elsif match = scan(/\\N/) + encoder.text_token match, :predefined_constant + + else + encoder.text_token getch, :error + + end + + elsif state == :string + if match = scan(/[^\\"'`]+/) + string_content << match + next + elsif match = scan(/["'`]/) + if string_type == match + if peek(1) == string_type # doubling means escape + string_content << string_type << getch + next + end + unless string_content.empty? + encoder.text_token string_content, :content + string_content = '' + end + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + string_type = nil + else + string_content << match + end + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + unless string_content.empty? + encoder.text_token string_content, :content + string_content = '' + end + encoder.text_token match, :char + elsif match = scan(/ \\ . /mox) + string_content << match + next + elsif match = scan(/ \\ | $ /x) + unless string_content.empty? + encoder.text_token string_content, :content + string_content = '' + end + encoder.text_token match, :error + state = :initial + else + raise "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise 'else-case reached', encoder + + end + + end + + if state == :string + encoder.end_group state + end + + encoder + + end + + end + +end end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8a9427066e2d6e798584d5fb43dde42f7e5a0ae0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8a9427066e2d6e798584d5fb43dde42f7e5a0ae0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +module CodeRay +module Encoders + + # = Null Encoder + # + # Does nothing and returns an empty string. + class Null < Encoder + + register_for :null + + def text_token text, kind + # do nothing + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8ac5c86a4d5f2436afb5894e5073d2a9e8ed85a7.svn-base Binary file .svn/pristine/8a/8ac5c86a4d5f2436afb5894e5073d2a9e8ed85a7.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8acaae9a034e1f7fbae5d32d9a9e7470655334f1.svn-base Binary file .svn/pristine/8a/8acaae9a034e1f7fbae5d32d9a9e7470655334f1.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8a/8adb47a9617850b441bd264fdfaa485feeb05a17.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8a/8adb47a9617850b441bd264fdfaa485feeb05a17.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +class ProjectEnumerationsController < ApplicationController + before_filter :find_project_by_project_id + before_filter :authorize + + def update + if request.put? && params[:enumerations] + Project.transaction do + params[:enumerations].each do |id, activity| + @project.update_or_create_time_entry_activity(id, activity) + end + end + flash[:notice] = l(:notice_successful_update) + end + + redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project + end + + def destroy + @project.time_entry_activities.each do |time_entry_activity| + time_entry_activity.destroy(time_entry_activity.parent) + end + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8b0c72afd0d7787739416aa1510d0e28d12a95ed.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8b0c72afd0d7787739416aa1510d0e28d12a95ed.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'rails_generator' +require 'rails_generator/scripts/generate' + +class MigrationsTest < Test::Unit::TestCase + + @@migration_dir = "#{RAILS_ROOT}/db/migrate" + + def setup + ActiveRecord::Migration.verbose = false + Engines.plugins[:test_migration].migrate(0) + end + + def teardown + FileUtils.rm_r(@@migration_dir) if File.exist?(@@migration_dir) + end + + def test_engine_migrations_can_run_down + assert !table_exists?('tests'), ActiveRecord::Base.connection.tables.inspect + assert !table_exists?('others'), ActiveRecord::Base.connection.tables.inspect + assert !table_exists?('extras'), ActiveRecord::Base.connection.tables.inspect + end + + def test_engine_migrations_can_run_up + Engines.plugins[:test_migration].migrate(3) + assert table_exists?('tests') + assert table_exists?('others') + assert table_exists?('extras') + end + + def test_engine_migrations_can_upgrade_incrementally + Engines.plugins[:test_migration].migrate(1) + assert table_exists?('tests') + assert !table_exists?('others') + assert !table_exists?('extras') + assert_equal 1, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration]) + + + Engines.plugins[:test_migration].migrate(2) + assert table_exists?('others') + assert_equal 2, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration]) + + + Engines.plugins[:test_migration].migrate(3) + assert table_exists?('extras') + assert_equal 3, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration]) + end + + def test_generator_creates_plugin_migration_file + Rails::Generator::Scripts::Generate.new.run(['plugin_migration', 'test_migration'], :quiet => true) + assert migration_file, "migration file is missing" + end + + private + + def table_exists?(table) + ActiveRecord::Base.connection.tables.include?(table) + end + + def migration_file + Dir["#{@@migration_dir}/*test_migration_to_version_3.rb"][0] + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8b136f9015211dea81183c52d1fcc9f2c764bd3e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8b136f9015211dea81183c52d1fcc9f2c764bd3e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +Message-ID: <4974C93E.3070005@somenet.foo> +Date: Mon, 19 Jan 2009 19:41:02 +0100 +From: "John Smith" +User-Agent: Thunderbird 2.0.0.19 (Windows/20081209) +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: Re: [eCookbook - Help board - msg2] Reply to the first post +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: 7bit + +This is a reply to a forum message. + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8b34b320f3a3448ad5019fb625383697dc8a3c95.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8b34b320f3a3448ad5019fb625383697dc8a3c95.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,395 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class IssueNestedSetTest < ActiveSupport::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, + :trackers, :projects_trackers, + :versions, + :issue_statuses, :issue_categories, :issue_relations, :workflows, + :enumerations, + :issues, + :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, + :time_entries + + self.use_transactional_fixtures = false + + def test_create_root_issue + issue1 = create_issue! + issue2 = create_issue! + issue1.reload + issue2.reload + + assert_equal [issue1.id, nil, 1, 2], [issue1.root_id, issue1.parent_id, issue1.lft, issue1.rgt] + assert_equal [issue2.id, nil, 1, 2], [issue2.root_id, issue2.parent_id, issue2.lft, issue2.rgt] + end + + def test_create_child_issue + parent = create_issue! + child = create_issue!(:parent_issue_id => parent.id) + parent.reload + child.reload + + assert_equal [parent.id, nil, 1, 4], [parent.root_id, parent.parent_id, parent.lft, parent.rgt] + assert_equal [parent.id, parent.id, 2, 3], [child.root_id, child.parent_id, child.lft, child.rgt] + end + + def test_creating_a_child_in_different_project_should_not_validate + issue = create_issue! + child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, + :subject => 'child', :parent_issue_id => issue.id) + assert !child.save + assert_not_nil child.errors[:parent_issue_id] + end + + def test_move_a_root_to_child + parent1 = create_issue! + parent2 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + + parent2.parent_issue_id = parent1.id + parent2.save! + child.reload + parent1.reload + parent2.reload + + assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [parent1.id, 4, 5], [parent2.root_id, parent2.lft, parent2.rgt] + assert_equal [parent1.id, 2, 3], [child.root_id, child.lft, child.rgt] + end + + def test_move_a_child_to_root + parent1 = create_issue! + parent2 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + + child.parent_issue_id = nil + child.save! + child.reload + parent1.reload + parent2.reload + + assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt] + assert_equal [child.id, 1, 2], [child.root_id, child.lft, child.rgt] + end + + def test_move_a_child_to_another_issue + parent1 = create_issue! + parent2 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + + child.parent_issue_id = parent2.id + child.save! + child.reload + parent1.reload + parent2.reload + + assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [parent2.id, 1, 4], [parent2.root_id, parent2.lft, parent2.rgt] + assert_equal [parent2.id, 2, 3], [child.root_id, child.lft, child.rgt] + end + + def test_move_a_child_with_descendants_to_another_issue + parent1 = create_issue! + parent2 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + grandchild = create_issue!(:parent_issue_id => child.id) + + parent1.reload + parent2.reload + child.reload + grandchild.reload + + assert_equal [parent1.id, 1, 6], [parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [parent2.id, 1, 2], [parent2.root_id, parent2.lft, parent2.rgt] + assert_equal [parent1.id, 2, 5], [child.root_id, child.lft, child.rgt] + assert_equal [parent1.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt] + + child.reload.parent_issue_id = parent2.id + child.save! + child.reload + grandchild.reload + parent1.reload + parent2.reload + + assert_equal [parent1.id, 1, 2], [parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [parent2.id, 1, 6], [parent2.root_id, parent2.lft, parent2.rgt] + assert_equal [parent2.id, 2, 5], [child.root_id, child.lft, child.rgt] + assert_equal [parent2.id, 3, 4], [grandchild.root_id, grandchild.lft, grandchild.rgt] + end + + def test_move_a_child_with_descendants_to_another_project + parent1 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + grandchild = create_issue!(:parent_issue_id => child.id) + + assert child.reload.move_to_project(Project.find(2)) + child.reload + grandchild.reload + parent1.reload + + assert_equal [1, parent1.id, 1, 2], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [2, child.id, 1, 4], [child.project_id, child.root_id, child.lft, child.rgt] + assert_equal [2, child.id, 2, 3], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt] + end + + def test_invalid_move_to_another_project + parent1 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + grandchild = create_issue!(:parent_issue_id => child.id, :tracker_id => 2) + Project.find(2).tracker_ids = [1] + + parent1.reload + assert_equal [1, parent1.id, 1, 6], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt] + + # child can not be moved to Project 2 because its child is on a disabled tracker + assert_equal false, Issue.find(child.id).move_to_project(Project.find(2)) + child.reload + grandchild.reload + parent1.reload + + # no change + assert_equal [1, parent1.id, 1, 6], [parent1.project_id, parent1.root_id, parent1.lft, parent1.rgt] + assert_equal [1, parent1.id, 2, 5], [child.project_id, child.root_id, child.lft, child.rgt] + assert_equal [1, parent1.id, 3, 4], [grandchild.project_id, grandchild.root_id, grandchild.lft, grandchild.rgt] + end + + def test_moving_an_issue_to_a_descendant_should_not_validate + parent1 = create_issue! + parent2 = create_issue! + child = create_issue!(:parent_issue_id => parent1.id) + grandchild = create_issue!(:parent_issue_id => child.id) + + child.reload + child.parent_issue_id = grandchild.id + assert !child.save + assert_not_nil child.errors[:parent_issue_id] + end + + def test_moving_an_issue_should_keep_valid_relations_only + issue1 = create_issue! + issue2 = create_issue! + issue3 = create_issue!(:parent_issue_id => issue2.id) + issue4 = create_issue! + r1 = IssueRelation.create!(:issue_from => issue1, :issue_to => issue2, :relation_type => IssueRelation::TYPE_PRECEDES) + r2 = IssueRelation.create!(:issue_from => issue1, :issue_to => issue3, :relation_type => IssueRelation::TYPE_PRECEDES) + r3 = IssueRelation.create!(:issue_from => issue2, :issue_to => issue4, :relation_type => IssueRelation::TYPE_PRECEDES) + issue2.reload + issue2.parent_issue_id = issue1.id + issue2.save! + assert !IssueRelation.exists?(r1.id) + assert !IssueRelation.exists?(r2.id) + assert IssueRelation.exists?(r3.id) + end + + def test_destroy_should_destroy_children + issue1 = create_issue! + issue2 = create_issue! + issue3 = create_issue!(:parent_issue_id => issue2.id) + issue4 = create_issue!(:parent_issue_id => issue1.id) + + issue3.init_journal(User.find(2)) + issue3.subject = 'child with journal' + issue3.save! + + assert_difference 'Issue.count', -2 do + assert_difference 'Journal.count', -1 do + assert_difference 'JournalDetail.count', -1 do + Issue.find(issue2.id).destroy + end + end + end + + issue1.reload + issue4.reload + assert !Issue.exists?(issue2.id) + assert !Issue.exists?(issue3.id) + assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt] + assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt] + end + + def test_destroy_child_should_update_parent + issue = create_issue! + child1 = create_issue!(:parent_issue_id => issue.id) + child2 = create_issue!(:parent_issue_id => issue.id) + + issue.reload + assert_equal [issue.id, 1, 6], [issue.root_id, issue.lft, issue.rgt] + + child2.reload.destroy + + issue.reload + assert_equal [issue.id, 1, 4], [issue.root_id, issue.lft, issue.rgt] + end + + def test_destroy_parent_issue_updated_during_children_destroy + parent = create_issue! + create_issue!(:start_date => Date.today, :parent_issue_id => parent.id) + create_issue!(:start_date => 2.days.from_now, :parent_issue_id => parent.id) + + assert_difference 'Issue.count', -3 do + Issue.find(parent.id).destroy + end + end + + def test_destroy_child_issue_with_children + root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root') + child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id) + leaf = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'leaf', :parent_issue_id => child.id) + leaf.init_journal(User.find(2)) + leaf.subject = 'leaf with journal' + leaf.save! + + assert_difference 'Issue.count', -2 do + assert_difference 'Journal.count', -1 do + assert_difference 'JournalDetail.count', -1 do + Issue.find(child.id).destroy + end + end + end + + root = Issue.find(root.id) + assert root.leaf?, "Root issue is not a leaf (lft: #{root.lft}, rgt: #{root.rgt})" + end + + def test_destroy_issue_with_grand_child + parent = create_issue! + issue = create_issue!(:parent_issue_id => parent.id) + child = create_issue!(:parent_issue_id => issue.id) + grandchild1 = create_issue!(:parent_issue_id => child.id) + grandchild2 = create_issue!(:parent_issue_id => child.id) + + assert_difference 'Issue.count', -4 do + Issue.find(issue.id).destroy + parent.reload + assert_equal [1, 2], [parent.lft, parent.rgt] + end + end + + def test_parent_priority_should_be_the_highest_child_priority + parent = create_issue!(:priority => IssuePriority.find_by_name('Normal')) + # Create children + child1 = create_issue!(:priority => IssuePriority.find_by_name('High'), :parent_issue_id => parent.id) + assert_equal 'High', parent.reload.priority.name + child2 = create_issue!(:priority => IssuePriority.find_by_name('Immediate'), :parent_issue_id => child1.id) + assert_equal 'Immediate', child1.reload.priority.name + assert_equal 'Immediate', parent.reload.priority.name + child3 = create_issue!(:priority => IssuePriority.find_by_name('Low'), :parent_issue_id => parent.id) + assert_equal 'Immediate', parent.reload.priority.name + # Destroy a child + child1.destroy + assert_equal 'Low', parent.reload.priority.name + # Update a child + child3.reload.priority = IssuePriority.find_by_name('Normal') + child3.save! + assert_equal 'Normal', parent.reload.priority.name + end + + def test_parent_dates_should_be_lowest_start_and_highest_due_dates + parent = create_issue! + create_issue!(:start_date => '2010-01-25', :due_date => '2010-02-15', :parent_issue_id => parent.id) + create_issue!( :due_date => '2010-02-13', :parent_issue_id => parent.id) + create_issue!(:start_date => '2010-02-01', :due_date => '2010-02-22', :parent_issue_id => parent.id) + parent.reload + assert_equal Date.parse('2010-01-25'), parent.start_date + assert_equal Date.parse('2010-02-22'), parent.due_date + end + + def test_parent_done_ratio_should_be_average_done_ratio_of_leaves + parent = create_issue! + create_issue!(:done_ratio => 20, :parent_issue_id => parent.id) + assert_equal 20, parent.reload.done_ratio + create_issue!(:done_ratio => 70, :parent_issue_id => parent.id) + assert_equal 45, parent.reload.done_ratio + + child = create_issue!(:done_ratio => 0, :parent_issue_id => parent.id) + assert_equal 30, parent.reload.done_ratio + + create_issue!(:done_ratio => 30, :parent_issue_id => child.id) + assert_equal 30, child.reload.done_ratio + assert_equal 40, parent.reload.done_ratio + end + + def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any + parent = create_issue! + create_issue!(:estimated_hours => 10, :done_ratio => 20, :parent_issue_id => parent.id) + assert_equal 20, parent.reload.done_ratio + create_issue!(:estimated_hours => 20, :done_ratio => 50, :parent_issue_id => parent.id) + assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio + end + + def test_parent_estimate_should_be_sum_of_leaves + parent = create_issue! + create_issue!(:estimated_hours => nil, :parent_issue_id => parent.id) + assert_equal nil, parent.reload.estimated_hours + create_issue!(:estimated_hours => 5, :parent_issue_id => parent.id) + assert_equal 5, parent.reload.estimated_hours + create_issue!(:estimated_hours => 7, :parent_issue_id => parent.id) + assert_equal 12, parent.reload.estimated_hours + end + + def test_move_parent_updates_old_parent_attributes + first_parent = create_issue! + second_parent = create_issue! + child = create_issue!(:estimated_hours => 5, :parent_issue_id => first_parent.id) + assert_equal 5, first_parent.reload.estimated_hours + child.update_attributes(:estimated_hours => 7, :parent_issue_id => second_parent.id) + assert_equal 7, second_parent.reload.estimated_hours + assert_nil first_parent.reload.estimated_hours + end + + def test_reschuling_a_parent_should_reschedule_subtasks + parent = create_issue! + c1 = create_issue!(:start_date => '2010-05-12', :due_date => '2010-05-18', :parent_issue_id => parent.id) + c2 = create_issue!(:start_date => '2010-06-03', :due_date => '2010-06-10', :parent_issue_id => parent.id) + parent.reload + parent.reschedule_after(Date.parse('2010-06-02')) + c1.reload + assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-08')], [c1.start_date, c1.due_date] + c2.reload + assert_equal [Date.parse('2010-06-03'), Date.parse('2010-06-10')], [c2.start_date, c2.due_date] # no change + parent.reload + assert_equal [Date.parse('2010-06-02'), Date.parse('2010-06-10')], [parent.start_date, parent.due_date] + end + + def test_project_copy_should_copy_issue_tree + p = Project.create!(:name => 'Tree copy', :identifier => 'tree-copy', :tracker_ids => [1, 2]) + i1 = create_issue!(:project_id => p.id, :subject => 'i1') + i2 = create_issue!(:project_id => p.id, :subject => 'i2', :parent_issue_id => i1.id) + i3 = create_issue!(:project_id => p.id, :subject => 'i3', :parent_issue_id => i1.id) + i4 = create_issue!(:project_id => p.id, :subject => 'i4', :parent_issue_id => i2.id) + i5 = create_issue!(:project_id => p.id, :subject => 'i5') + c = Project.new(:name => 'Copy', :identifier => 'copy', :tracker_ids => [1, 2]) + c.copy(p, :only => 'issues') + c.reload + + assert_equal 5, c.issues.count + ic1, ic2, ic3, ic4, ic5 = c.issues.find(:all, :order => 'subject') + assert ic1.root? + assert_equal ic1, ic2.parent + assert_equal ic1, ic3.parent + assert_equal ic2, ic4.parent + assert ic5.root? + end + + # Helper that creates an issue with default attributes + def create_issue!(attributes={}) + Issue.create!({:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test'}.merge(attributes)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8b4f5e74a10f8a0926d8a97404f0df2441b42b2c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8b4f5e74a10f8a0926d8a97404f0df2441b42b2c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +api.array :trackers do + @trackers.each do |tracker| + api.tracker do + api.id tracker.id + api.name tracker.name + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8bb9ae19f70bfe10707fcbca8e4a7cb4cc52174d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8bb9ae19f70bfe10707fcbca8e4a7cb4cc52174d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +<%= error_messages_for 'auth_source' %> + +
    + +

    +<%= text_field 'auth_source', 'name' %>

    + +

    +<%= text_field 'auth_source', 'host' %>

    + +

    +<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls' %> LDAPS

    + +

    +<%= text_field 'auth_source', 'account' %>

    + +

    +<%= password_field 'auth_source', 'account_password', :name => 'ignore', + :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)), + :onfocus => "this.value=''; this.name='auth_source[account_password]';", + :onchange => "this.name='auth_source[account_password]';" %>

    + +

    +<%= text_field 'auth_source', 'base_dn', :size => 60 %>

    + +

    +<%= check_box 'auth_source', 'onthefly_register' %>

    +
    + +
    <%=l(:label_attribute_plural)%> +

    +<%= text_field 'auth_source', 'attr_login', :size => 20 %>

    + +

    +<%= text_field 'auth_source', 'attr_firstname', :size => 20 %>

    + +

    +<%= text_field 'auth_source', 'attr_lastname', :size => 20 %>

    + +

    +<%= text_field 'auth_source', 'attr_mail', :size => 20 %>

    +
    + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8bbff57766dae3f0b3f76583c36f28f3da4a3883.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8bbff57766dae3f0b3f76583c36f28f3da4a3883.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToWikiContents < ActiveRecord::Migration + def self.up + add_index :wiki_contents, :author_id + end + + def self.down + remove_index :wiki_contents, :author_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8be3417f02fbed94c8f19948d5fc9bbbc391d8ec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8be3417f02fbed94c8f19948d5fc9bbbc391d8ec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,240 @@ +From JSmith@somenet.foo Mon Jun 27 06:55:56 2011 +Return-Path: +X-Original-To: redmine@somenet.foo +Delivered-To: redmine@somenet.foo +From: John Smith +Mime-Version: 1.0 (Apple Message framework v1084) +Content-Type: multipart/alternative; boundary=Apple-Mail-3-163265085 +Subject: Test attaching images to tickets by HTML mail +Date: Mon, 27 Jun 2011 16:55:46 +0300 +To: redmine@somenet.foo +Message-Id: <7ABE3636-07E8-47C9-90A1-FCB1AA894DA1@somenet.foo> +X-Mailer: Apple Mail (2.1084) + + +--Apple-Mail-3-163265085 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; + charset=us-ascii + +Yet another test! + + +--Apple-Mail-3-163265085 +Content-Type: multipart/related; + type="text/html"; + boundary=Apple-Mail-4-163265085 + + +--Apple-Mail-4-163265085 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; + charset=us-ascii + + +
    = + +--Apple-Mail-4-163265085 +Content-Transfer-Encoding: base64 +Content-Disposition: inline; + filename=paella.jpg +Content-Type: image/jpg; + x-unix-mode=0644; + name="paella.jpg" +Content-Id: <1207F0B5-9F9D-4AB4-B547-AF9033E82111> + +/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU +FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo +KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCACmAMgDASIA +AhEBAxEB/8QAHQAAAgMBAQEBAQAAAAAAAAAABQYABAcDCAIBCf/EADsQAAEDAwMCBQIDBQcFAQAA +AAECAwQABREGEiExQQcTIlFhcYEUMpEVI0Kh0QhSYrHB4fAWJCUzQ3L/xAAaAQADAQEBAQAAAAAA +AAAAAAADBAUCAQYA/8QAKhEAAgIBBAICAgIDAAMAAAAAAQIAAxEEEiExIkEFE1FhMnFCkaEjwdH/ +2gAMAwEAAhEDEQA/ACTUdSsdhRCNE54GTRaBaXHiBtNOVo0wEpSt8BKfmpWCZRPHcVbdZ3X1J9Jx +Tla9OBpIU8Noo7Gjx4qdrCBkfxGupUSck13GJjeT1ObEdthOG04/zpX8SNXjR1njym46ZMmQ+llp +pStuc9T9hRq/X22afhKl3iazEYHdxWCfgDqT9K83eKfiFG1RfIEi3tuC3W9KlNh0YLqyeuO3QV0D +MznM9O2uai4QI8psYQ8gLA9virY615P034xX+zNNslLDsMKOG1J5HuAa3nQPiBZ9WtpUy4lmcE4U +ypXP2rmMHmcI/EealD7te7ZZ2S7dLhGiN9cvOBP+dIF18btHw3C1DkSbi7nATGZJBPwTitTIyZp9 +SsCun9oJaEFUDTy0oyQFyXSOfoB/rQOL466huE9LIagxW1A48tkuKJxwBlQrm4YzNhGPE9Mmua8Y +JrzsrXPiQ42y7+KtsZt4kpS8ltK0p91J5IzXGFr3xFef8pMqE4vJABZT6se3FDNyEZzNCh89Tfbv +aoV2iKj3GO2+0eyh0+h7VkWq/CqTDUqXpp0uJHPkKOFj6HofvQRzxZ1bbwFTG7c+jO0lKeh+cGi8 +bxrebZZVMtjDqljKgw4Rt9uuea5vEIEceoL09ZnHQoyGy3KaOFhxO0j6g0J8QNPr3tzorHmsJSUv +NgdQeprTIuqbfqdtD7MRxh7HO/H6ZHWlnW0e5tQnv2WgupAyEg8p9xUl7WGowpzKCoDXyJ5nvMdK +Uuho4bSv057CqK2stIWrgEZp2kWtE+O5+MC0OKUchHFCbnaWVNeW1KU3tTtwtAUkj6jkfpXoK7gQ +AZLsqYEmJ0mUBlLeCfeqHKl5PqJopNhriupQWyoqPpKeQfpTXYPDW+3ZlEhTTcVpXI8w+oj6Cmty +qMxTazHAi1ZLG/PXuKClv3Ip7t2n4yI3lKZSsEc7hmicXwfu5ThN22fCUH+tXB4QX1KdzN6WVjth +Q/1oDuG/yjCIV/xgWLouQFfiLK/5LqejbnKT9D1FStX05DRaYrTN8K232wEl1aMJV856VKF9hPc3 +9QPM32HEjxEjykBSh/ERSd4s61uGjLbBnQrcie2t4pfClEFKAM8Y704uvtsMrdfcQ20gZUtZAAHu +SawHxt8V7PKt/wCytPp/aLrToW7JAPlNkAjAPfOfpQ0JY4E42B3Nf09ruwXvTQvjM9lmGkfvvOWE +llXdKvn/ADrONZeNwU28zo2Ml1tHpXc5Y2spP+EHlR/5ivOzYkPPKdjMechRDjrCUHy1Ec9Aa1Lw +l0VF10pcy4XJC0RlbTFTgKbHwnokfSibFXkzAJbiJ0tN81jc1yHXplzkEEqkPA7UjvtR2H1/SrOl +rGu6NvP7Q8yhaWkDruVj/n616Lvl20n4Z2cpeS02tSfRHbAU69/t8nivOGoNXzNQSVRbFAbtsFal +FESEjBOepUR1rBs3D8CFVMHjmXNYW+wWtsMrlMvyyOW4h3FB9irpn70lx7k9AeDttW4w70DgWd3+ +1NmlvDi7XpL0iShcWG0dqllO5SlHsB35NG7l4PSRG823z0YbGFqkDaFK+MZx7d6XOu09Z2M8MKHb +OBM1vBuAkJcuUgyHXRu3KfDp+5ycVTaeU36kKUlYOQQcEVrehvC5l1Mh/VClISHFMttIVgL45VnH +TkEH4rQbjpHTbyGWVQIzL7bYabc2AnaMfYnAxk0K35Smo7e/2IRdC7eXUwfT5m6pfbtC/wARIlLW +VNu7yoN9MlQ9h3NO+n9Cwo8rzZU1Sm2Mlx9YLaUkHjaOv3Nc7zd7FoyY5D07HR56SfMl7961ZGNo +9gKXrtd77dnkssoSwt7K9rZG8jHU44Tkc9q0rvbyvipnNgT9kTRLvqKy2JDgS/8AiH3hjecKXjv2 +/SkG8akmRyhqG+hKSQ4dpyofBxxV2w+Hkuda27pMW5tcSpWxati1HJGQTkYp70xoS2MW1pp+ImXN +koJLi+UtfP1FAt1dFPHcPXQ9nPUy+/3pu4usrYZS16MOKCAkuLJypRxX5aG5ExX4VlfC/Vt98e3z +WvL8M9NsNMtyFyVyGx6h5uPMPyMcV9Q9HQbbdWwzHQGFHKVhStw+uTQTr6tu1IQad85M46baVarV +uVkJ/mDVCVqWUll59t4FxlW0ocOA4k+1P8uLGU35UgAhQ2kgdRWUeIMi2WyKqASFLJJbWchQI7Ul +pWWyw5GSYZ1IXA4Ez7U12mR7q95jCWgTuCQeoPsaGqntylbCpIdxnaSM/wBK56lujtydZS4UkNIw +CBzQO4RURywWnUupcQF7knoT1BHYg5r0lFY2DIwZKvYq5x1DjUo26WzJKEuIQoFSFDIP+9bzaL0x ++HZcZcQpC0ggewIrzYzNJQGpGVt+/cUw2PU8+0vqWEJnW8q/9KzgpHslXb6UV6yw4gBZg8z1NZbj +Ek43LQDjkZFMLbkMcJW3+orKvDq86T1SUssrEef3iPq2rz8f3vtTZrtizaR0pOvD8XephOG2959a +ycJH60HBBxDBhjMB+L9/RY7WpT7jam3kkNNJwSs+/NSss0Bpi4+Jmpfxl7kPOQ2k7iCfyI/hQOwz +/vUroqrUnceZ8LnIG2Cdaa61Dq54i7SVJi5ymGwdjSf/ANe/86s6W0TLvkNySp5pcVjBUy0oAD5x +1P1NbDbPALTQjp/aC5bj+OS27tH+VOmjPDqw6QEv9lNPFcpIQ4p5zeSB0A/WtNYoXCwK1nOWgjwk +sFrg2wuJjtKl5IJUBwPakLxDXbNI6/alaGW6b87uL1vjJCmAogjcvHTrnb8DpVnxj1q1oOS7b9PP +j9qSEErA58gHuf8AF7CsStOurpBjKZioQqS6sqU+vlayepPvQytu3cgz/fEPWaXfFjYEfLlo5+bM +/aurr+X33vW6lIJUD/dyen2p80zboMNG6NBEGOygJLy04cdAGRjjn5NYRD1NcjMMme8XpST6Q4Mp +H0HStstF4kO2lMS5vAlTfq9O04PQZ+KifILaqg3PnPodS5o0S3I0q4x2T3Kr+obzH1HsjuFFpeUU +B5s5Snck4ST0z0p502w5HZW86qW5lXLbpSeMfHFZH4gpFutbDlrmNtujlxvzc705HAHfB5qknVSI +VliuWK7STcHVBL7Ticc8c8f70IaMaipWq4z+oo6jT2sr8ma3qCfBky48be4zvcAOB6gR/CMd6EXF +m9EPKhx3Vx92EJdADmOmQKJ2y5xVpiJlW+OzPSj1LbSBtURyoGjFzWqPbHljClFBLbiBnHHUmpeT +WdqiPISuDM/e0bark4YzkEJkJ9RebGF7u+T/AKVeg6DbVdXHJ6U/hi35KAlRGU44zj/WrtpdfSlt +D7m54jKznr/WnOAVKa9Y7cGtDVWodhaH1WnVlD7cZxPhq3NMobbeBeZQnalKlZ47cUQDSGtvlqwn +GEp7AVQdbddWQHkp2dOea6qWHQlPmJSscEE9aET/AJCK/X+JFxUtuKecHnKxx8VXRKiBSkuKII55 +PSvq4yUQmf3qspxwc8is71fqZMeKtTO0AHn3V8UaitrDgdmcdtoyZ215q1USShq0bZClghTYPqFL +Vr0xH1otbt1XKZkpT6cccfOaF6SZkz7q7dZYWHjz0ykJp2Yvi4YaYVHdUXjs2eSUlR7HPt89KoW5 +p8af5D3OVLldz9GLmsNLR1WZiI+oJlRB5aHgBuKe2cdaxd5tVsuy0OJbdWwvkKGUq+or0PqiyXVy +IJ7za1NlIJbz6m/fgdv61lN000qWJ09EWQ8++6lqM01k8geokY5p/wCK1RXK2Nn/AOz75PS1vStt +Y594iCUnOauWi5SLXMDzIQ4g8ONOp3IcT7KHcVduWn7nbWg5OgSI6SopBcQUjPtzXK1RX1OqkMtb +0xcPO9PSkHrzV0WKRkHM86a2BwZqFm0da9c2pdw0asM3JgBT9qdd2uNH+8y51x7A/rSjrXUmq129 +Om9TuyvKhu70NyUYd4GBlX8QofG1hcLbrBF/tZ/DvtqGEDhJQONpA6gjrXq61f8AS/jDo9mXNhNu +nGxxPR2O5jkBXX+tY3bcFhPtoPAin4H6gsMTQgLEhtM7eoyGioBYI4Tx7Yx+pqUr668ILjZXDOtS +XZsdvlMiGkJlND/GgYDg+Rg1KwUDHIM2r7Bgiei5NwiQo635cllllAypbiwAPvWO678c4UJuRH0y +gSHkDBkrHpz2CR3+prHbXJ1L4o6matwkKaYP7xzkhthsdVEf8NLWrzbo94fh2RKjAjqLSHFnKniO +Cs/X/KuLSAcN3OfYW5HUD3SXJutxfnTnVOyn1lbi1HJJNPnh9otyfbJF5lLabjpJQ0FjlZHUis9C +lDOO9bdHkS4WkbXBlIMdaGUnyhwkjqFfU5pf5K566gqe+I98TpBqb9pnB/Q9wu7kdyOGUNNp3oWp +Owq7+3P1r9uQmqllqS+S+ghClFWR+vtT/Z7goWGOopbjodwEltQOcdR16/WrcrTFmW4tyYZHmuDc +dhwkDHSvNvq2BC2+up6PThdIzDvMypelJN2lI8+M9JKxsZS1/Cfcn2+tF9K6Oh6ZeW5fYS5VwKgl +locpR3Cvk0+zJTdtioi2htDe5OVL/KAPcn3r5j3ZtdmkrKFTFJ3EDG7BAzgH9a+XX2sNi8CJXaZW +c3GIN7u0u931+KwhaGGspKQMKcKepVV5UmU1DZZtzspMVKQXm3F5B+gHIH0zQCBImKuiJMeCuEH1 +YCfVkjv+bqSKr6t1U7a7uxEgurS0yMLBASc/arlenBULiSGtOSSY6WKJKXckJU2tplSt6FA7gfvW +gxA/sUBggDGSayGya5ed8tkNqSlXVYOVVpEZydIablRFF6ORgjGFJPyKga3Tuj5Il2rVC6sKT1L9 +tiuPTnDI3eSfc/lqrqWOuHFK4qlF1HIX7j2NWIkyQ8XEApSUcD/Ea5TmZj2SggqUMKSrp9KUByQM +T45U5mSS9UzJMtMZ93GFcqJ7UL8Q3UOOww24Bx6h3V8/Sqev0sx7u4IqkB5w8tJ4KFfNBXG3Fuo/ +FPqLxA3FXXHtXp9PQiBXXiTGZrmIjTo68qh+Y2ygPhYSAlXIBz1rYHp04RkNRnWDOA5KyEgDrgVh +mmSmPcCfQpWCACnINFdRXOW3GQ4+60GgcJKDgr+R70lqdP8AZaAvuUK3woDY4mqyrjeFWppZZUXW +lnzUlYCVp+K+LLeYEoLLG5lGdxQk4wcfyrOourlyIzbDhcKVNhHB7e9XYlxatbam0dVDOAOT96Rf +TEDBHMMpU9dTQpVxiTWXGUqDy1n0hxCSAPvXnfWVtnWO9TI8lpLHnZOGxhKkE54+K1K1XhLj4S4j +GOnxX5qiNZ7wlpd1Di30ZS0hKtu4kdCaN8fqG0luxhwYtrdOtqZXsTA1dTWh+B+unNG6tbTIWTap +hDUhGeE56L+oP8qSbtBXDnyWSB+7WUnadwH3rgYT6IQmEpS0VbU5WNyj8DrXr/F1/ueXIZT1P6Hh +aVoSpJBSoZBB4IqVjPgP4ii72eHZLsSJrCPKadP8YA4B+cfrUpMgg4jK8jMybw5vUfT/AIXatujD +iRc5S24DX95KVAkn/P8ASstODk9asPSXvwZbUEoQpzhtIwkYHt9z1q3NZiO2uNMhFLbif3chkryc +9lAHsabbAbP5i6DI/qctPSokW9w3p0cvsIcBLY7+2fituuVxYvDbAMZ2VIUkeX5I5x3Tgdqznwz0 +xbb/ADZQuy3w2y2FISycHJz3+MVtWnNLwNMb3G0SZDvlgb3DlWPgf86V5/5e+oOAc7l/9y18WLK/ +IdH/AHB+l23bLPLMl0RkyQS22r1eWQO/tR178NEju3GS8ZahyVIc7ewA4qpKKfxzTMOGHCsBZSob +ueveitut+XGo8tpDacEp2DAP69ahNYHO4yo1rMxJgt22RLy0l5bYQ04jckLWfM+o7frVPUMpdg0a +65EfXvaX5XOArnp9hTtGgRbcyhL6PPbaG1ClnJAPvWeeMl0FogwnWGYkqKHSFxnUkpSojgkD79aJ +pQbblr9ZgNRcAhMzli9zZYfS27NkPBIKAFKVnnkn2pf1PaZbMNm4PpkDzeV+c0UEK+p6/WtX8H5M +GXDm3OS22Jq3P/W2AlIHwOgFVPF+VBfjqKi4sEHBKSAVfFegXWsmo+pV4zJZ0wareTFbw71Y1Ab/ +AAjbcNh1Q/8Ae9yaYU33VESW5KdK1wucuMpwgj3FYq4S456E7VDjimGHqa6wYqIS5HmMq42LOQBT +Wo0AYll5z+YCjV7MA+puVmuDkgh7evZt3bsdK46s1uiNZSY6iHwSj82CPnFC7PcbdbdOxkPTiqaB +5iQlXCf61mV9uC79dn39oDIVztGAajafRK9pPoSrZezKAOzKclyXcLgue8VLUo7sHrUaVIfeCloG +T0Uo9qstKdbcBLZUg9DiuzkbY4VDIBGQkdBVkuBxOrRtAwf7naKlyMoqQ4pRI9RHH2qtc1/i/KS+ +p3yWchtKwcIzX7HnoQv1nbgYUR7+9NESXCmR1xdjexxOXCTg9ODSzO1bBiJvCsCBFu3eahwltCnA +O6ATj6082K2rlltyXGSsIGEhzPP1xQa1QJNngLmMuNPMrPKE5BwKuzrw6Yu6JJVGWkZSkHIXn274 +pe8m0+H+51G2DBlu4J/DzFKbWhICiS2EgH7H2FD3JTMuclt7B2ArBzgJPvQNF1lSUFoON5JyST1P +tmgEu5yY0wgJ2uoUd27nPtRKdEzHk8xezVLUnHudtXsRYc4rt8pxZdKvMSpWcH60M07a03W5JZcW +UtgFSj8Dt96orKnVKUQVK6nv966R5b0dCksLLe4gkp68dOatKjBNgPMiM4Z9xHE1fwCkQx4pqYdC +vJcC1RwT0WkZH8s1KVPDm+Psa208ogAtysqWOqyo4JP2qUtanPM2jDEL+OWn49u8R5UK0MbGClDg +bSOApYyQPvSzM0rKt9qiXCRs8uSSlCeQoHnII+1aJ/aAZWjxImL3FILTSwR/+RX7bhqJ561XC5Jj +O20pSnyFYJWMZypJ6djWLdSa1BzxDUaYWnaOzH/RlmZ0nYWPJab9SQqS5t/eLV2+wzj7UfZmouM8 +MNtlsNoKlFZAV8H4FULPfmrmtyCtwJfQjKggFIVx2orHsbUZ1TzCktFwfvVKJJUB05968jqHaxyz +y3t+sBeiJJTLSXA6hAWscFSTjke561yfkAlte4h88BIJwB3q5Hjx297RUpWfUD+YYqs5Gjx3HJJK +ywRylIGM+/vShBMIrDMtpKiyVKcWtvaP3aRnn3HevOfi9eZM/UEiEv8A7eOHgkhfT0jg4+5r0JJu +ENLad0plpWM9c8dqUtTaMtGoJS37gyXH3UANyEHH6iqXx99entD2CK31m1CqmZZomd+HjORbXte8 +hOVLSk4USeTRm4xrvqbTjseUGmozTmVPLH5fgfNNNhYtWmJardbw3tf59XqIwepNM2poyJVpdKEt ++SRuCR/EfemLdWou3oO/cJXVmsI08z3BiFp7UakMuonR0jk47+31oG7iTM/dkNoWvCdx/KCe9P8A +dIzR1PAZfjtI3gx3QsAJHznFKOqbfbbXKSzbriZrwJ8390UJRjpgnrXpdNeLAM9kSDqKDWT+AYcu +1ivcK2x1KdiyYSejrCgSnPZXehTLqou7cghKRkgd6Px9SWp2xsMT23HF7QgpaOCFDoaCxFee4UKC +gCT14P3oKs5B+xccx+kIpG0wlaJKZLB9KglB5Uo9KsLeDj2GzjI+1AjmPLH4ZzCVEApPAIopGCFR +1rSpW4naaFbWB5DqUabMnaYEuTGyc40le4deO1fMZam17krwAOua7yYjyZCiG8hZ65ya57WW3W2y +lS3FDkFW0CmgdygdydZ4MT1HezzUy4iCwVKLKcFtSuD74r9uVtRJabLZ8obckpTlP60ItSLXOeDT +KlR1spG9W7clw/ejN4mXa0MDYA9FLn7olIxtxyFCprVkWbU7/cY+0FNx6/UU70GYDBQw6FrUcAgH +ke9Lq3FHkkk980xXedHuYWt6D5L4A2rQrCQO4xV+yaaiTrW5JL29GRgflUCOoJ5wPmqaOKUy/cl3 +Zufw6itbriuAJHloSVPNlvJ/hB61RCwVAKPHc1YubQZmvNpSlKUqIACtwH371Tzk/FOKAeR7ibEj +g+o06QWy7riziG2pDf4lsJCjknnrUrv4TtIe1/ZQ50Q+Fk/TkfzxUpW7ggQ1a7xmbF/aGsKEX83N +U4IU8wFJZWMbtvBwf04pOieITadOMxXmWRJR6CsD1HHTH2xWx/2irAu9aJTIjJJkQXgsYHJSrg/6 +V5os1rjsynVXOQY8uMsER1t8r+M9j0pSymu1P/J6j+ktatxtE23QtvmwYar3cX0JjyE+hhQ9ROeC +a0CJJaLTe+Uhfm/l7/YUhWKUxfbKxCztdQkJStWdySf7o/rTHZLC7bW3g5M819Y2pLiPy/TmvLak +AsSeCPUp7i1hB6h+Ytbnl+US2AfVx/nXyWg4kpeOQ4CPT2FVX0JacS6qWpASnC0qIINDLlKKGyGp +QaLmADgYA74xzSY7zDpWW4Eq2e0N2yXMdmKS6twlCUO4IQj3+po86RGWzGjtNgO4AATwlPXNAmPK +dLanH15K04SEE5x7GrsGWLnclJ9SHGuCrOCU+1E2s5zNfSE/7mJniFFciyHJ6XEktoIylWBjPPHv +SnC1HKlFK25Kls7cBpSvy4PtWwXHSsCXIUqUt15Tg2qStfpx7kUIc0JZIqHlpGwqTgFJxgZzx809 +XfWE22DJgwQD49TGr0pN2nlL7i2JKjvC1DCc9qUtRR47sjLQWiYkYdbX0PyDWwax09bZpcZtpdbl +FJO5aztJxkD46Vl83TclMT8SlDjh28lIJwfY/NXdDqK8Ag4iGsosYHK8QVKiRIztv/BqccWUhT6l +jASruBVpEoKkOAYLhJO0D9KGIUoqQ2vucYPaidptb0i6lCMNt8lSlq/N8VRcDblz1J9Tbf4CEGYb +rzbjiEBLqQQAtQAzUs7jrqnGFNJy0fUMcA/WjlutUySrLT0dLGw5C08hQ6fbNCrTBuVlubjjkJ58 +pJwU5Lef72B1pQMLFYZGY0bHQggS7KYUw35ivUlXU9xSfdCp5QWltSUp/iPfNaBLtv4KGiVOkYcf +X5imS2dyE9uM8DvjrQc2hyYsg+WGSfSQKxRatfJMLepvXA7iilxtKmlMJcQ4nlSlKzn7U4wbou7Y +RK9SGeUpzjJPciuLmi5ayDF8t3nsrHFfFx0lcbeSptYWhKUlS0EjBP8ADR2votx5DMSFF1eRjiGF +OWuK4mO+y2lTyFIWpw5SCeivgZpNuCzBU4zEmBbTnUtq4UP+ZoxaNIXG6So5ebX5C3NillXQd/pV +zWlmYtEJmEiARLz6XEerf78jrXy3VK4XO4mDsSzbwMYiQI8iQlx5tpa2kfmWBwK4BKVdDiicpq5t +NGItl1DbbYdUgDgAjO40JZSpxwBA5zVBDnn1EnGD+5rn9n+1pXeZlzcQFIYbCEEjoo9x9galN/hp +BFn06wwQA89+9cPfJ7fpUpG072zHql2Libtf225NukRX+WnWyhX0Iry9drM3ar2i4XN0h6BKS28r +O5TiByleD8Yr0ldJyHWtyOD0UKzHW9taloXM8jzkhBbkN4yVt+4HunqPvQXBxkTqH1E2dck2u5wp +9rUW0yiVPKCdwQgkYJx361pca9NSGG3C5kIR6nkD0g/Ws5uMMT4DJtFyZTCdSlAjlsJKTnHpP+hr +hapk+yxP2fNW7+DeSrAIyN3uP0qJfQtij8/9lPTlkznmPNwdh3FgILzgcK/3bqSfUfZQpW1BMuNr +hKeeQlCyrCWeu0DjdXL9oW2NAadjuLbdj4UFBQIWoe6Scg/NEo5cu81h+5JAQtvcgdE++Tmlvr+o +5YZEbpvstyvRlPSGtFvNJjzox4JKHknHP0pq03c2GlTAp5j8Spw7d5CVEYHANL9xsrTbMibHUCUJ +IKEt8JPvxSey4ZylLX/8yOSMbqIK67stXwIT0NxyZubSDKUX1lbawkAZ9u+KHXeez5ja3HwhpPxy +D2HNZu1rG7W5zeqS0EgbUggHA+nvVaNqOXdr5HVNcQhCV71BKQNx7ZzxQxoW7PUIgGcmNs6SqW+W +2hvdc53qRgkHgc0YsdpVGgluSGygrUdqQClJ+TXVu2sSSu4x3PxD20qDa14yccAe2KruPvNw23Lg +z+HDytqh1Chjoo9utAJ9LC22h0CqMRc15omyXhCnLc0mLc0c7mcBKiBnCk/PuKy646YvkCU0qLuL +iWylQUPyE9cH5/WtkRLs0VhTLzqW22sEqLm5xXPTjtV2bLt88sttrCSpQxsOSCPeqGn191ACnyH7 +k27RI/K8TFdFOOYcTcAWENqIcUpJBz23DvTqvWMRElm3uQiUpIQ08BgJV259qdFWjzorsd8RXQ7k +KJHCh7E9yBWWatszVpmsKRuCRgJTn0g5P9KKt9WrtJYYM+q07IgQGWpsNN/lsTH5W7yF7H22+Nqc +ZJz84r8sMda284IRztBHal19yRbslgltMjKVA01abvCmLamK6AprbtGeoo1ysKwF5Eao0TsxK9xu +03BS6hS9gU4DzkUWj26G4osKbSpRysBQJGaE2W822NHDbyngM7s4wM/avmZqdhrelhorSoEbxknn +5qVtctnEOdLZnkQvKjIhuNojNZyraQMYTx1PtXzeYMZtDS30IS4lQWhWMkH4+tIxvz8GT5iQt1Bz +vSoHBPbNVjPvGo33HWnSEsgqTgcE9NtMJpWyGJwJ9dQVGOxAGt9QruazbYxQGMAOOjBUo9hn4pf0 +vYiu7AvEKQ0rcQOh9hX47bJMW5qjlrCyohKSoEgfOKboflWmIhhsb5S+Sfk16SsCmsLX1PLWoXsz +Z2I6QZ3kBKc5dPGPapSw28qMn1q3PK/Mc9PipQ4YVMwyJt2oHV2uZuGVML/mKoKWlwbkHchQ4qkN +ZaevsQxzcmQsj0byUkH71TgOvRVqbeG6Ks+l5PqSD9RXxBioihqTS8Vm7JlNyHGIqlZWWujDmQQr +H9339q/bihUVLqVvh1ak7S6g8KHwO1OshQIIUAoHg96z7VdpkxIEw2chTDqTmOr/AOZ90Ht9KWv0 +7WkYMf0Oqr075sXIgLTkZl7Uy1zZCQhpsuDOOuQOa05NvYkS0J8h1UUDd5w5UOOAfisK026yJZj3 +YOR3i56XRzkn+EitUsN4uEvEeCpDCGlEOL67ldMikfk6HUg54Ef02pS9i6jEcLpcGUMLSW9iU43J +6EjH+VZ9NuLDmQqCIsdxR7e30rQWNPKaebmOTVrdXysq5C+OhFfcm129Y/7ptghJ3JKU8j6VLqtS +rvmNFNx4mNXGMy6jEQqeUF5V8D2oS63JalpaQdrhxjdyQK2O6Ls8SOGm0hO7ohKeVH2FIl205Pdd +cmMskrICkNg+pIz0IqrptWGGDwP3M3VhFye4w2hmVGYaUmUUsrwcpOSn5xTpcpUJu1vOmQpwObUK +S6njfnjjtzWOu6iu3luRnIhQGTtJHBB/pRq1u3G5hhKFlIVneVdz9+lKXaRgdzkCdRxYMg9S9qB+ +A/MS0tpYIVudaZTgOqwAPtUdjTkORXGmhHbKgltKVBJSMd+9Mtv/ABrcWRFLUdxATl0lGFlWOx7/ +AAaEOJhuLZipYdksr6BokraVnnd7VhbOl7xBfWwctnj8T9m39strVFa9aMggZKlK+lLGpXLhc47d +smsKjlSgpJWg5A65B7dfrWk2vTdus8p+clS1vYyEurB2H+pqs9erVc32zJIbeZXtS2oZO8fH+tap +sVH3VrnHucXftIeZf/0zdZDYbKlPlpJWVnkZ7D704WLRhTbkOzg6XVpxsB2+Wfr3p0hzIylPPtth +KEr2uFQxuI7ChV61IhaTGay24okBST0J6GutrLLPACMJY6DxMze/Ldtdzcik7gnlJ+DVJF2KTlVO +0O2M3WK8mQ0h5/HoIOFdepPalq5aTuapziQhptrPUkHA609VZW3i3cbHyRVfKU03RLishXIpfVqe +Q2lyJC/dZWQpfzmqF5f/AGdcSw08hwJxnb3V7CqcNl5qWp6U2lKRnYnOefeqlOjQDcw4kX5D5g2Y +Wn13GOKsQklxR8yU51UecUSt+5GX3vU8rue1CbeypxfnO/YUWB9jRGIHAiVNZc72lgLJVzzUrmg1 +KFiOjjqIwUpPKSR96KWnUl1tLoXCmOt+4CuD9qFlOe9fm3nrT5wexPN5I6msWHxHjzili+Nhlw4A +faGBn5HSmicCI6X2loeiufkeb5Sf6GvPqknrTJpPVs2wPbMh+EvhxhzlKh9KA1XtYZbM9xj1Laos +/K1ICHv74/1qnbryuwBtCIYQgDatbayQv5wehpnu8NiXaBebK6X7csgOIPK4yj/Cr49jSbJXwQel +BesWLseGrsNTbkjx/wBWQ4FvYfdntLW8NwZC8qT9RQ9Gq3bo8ERlBDajgrJ/KPekB1ltLqZCAlK0 +HcCUgjP0NfIuy1Tg+yw2y4kEL8kYSv52nj9KSPxNQ/jyZRr+UYfyGJt+nm7Kje95pflEAFxR6H/C +DQW+OSocpBjL/EFZOHmzyR7GkzSl9ZLr5uE2LFBOPLWlWSPccYFaxpS8WZlP4aEpDri8OKO4KBP+ +lTL9NZQ/kMxg21agBi3MXo9ulOvB1uC8p0j1LV0PH86JQ7QpiSh94mO3tUFBSeMn2zTsJjKFrde8 +g8DbsIJA78VzbuEd6MVLaSWFZSCUZI985pRnJjCviI2nbncJNzXDUhL7aSU5C8J2/OKcbTaodsU7 +K8hLL6zuUndkA/GaU7tM/ZUlQjBlu3bdzbkdHKTnkE+59qU77q+4zISmGY8lbyVH96hKjlPHHFGG +me0+HAM7bcmMxv1V/wCQkLFvcdxzktd6RbNDC71lDgbS2dy3F9sHmh8PVF5ZQtEdteFDar0eof0o +8q7abXHYNxdDEhgYUUnYpffkdxmqFelspGMZz+Io2qQ+51v9/wDw7KkwZflxlElIKgTnPJNcH7mz +Asjbi1smU8QouE/PBH2pd1DreyOwnojMGPIK8+tLe3HGAfrSE9cVrjtJjFfozwv1bfpnj+VOaf40 +so3DETv+RReF5m53LUNis0Bp9ExK3QkAoQ5nPfisq1druXd3CmMVtsDITlXOPn3pcMGS/HW84VKd +zwF9SKFKCs7T27U/pvjqaju7Mm6jW2uMdCE4tsukyI5cmY77sdtYSt4DICuoBNMFoWiapJcVhY6o +V7138N9XK0/JWw42l+BIT5cmMv8AK6jv9COxpi1XpBtE2LctJvfi7bOBdbAI8xrH5krHYj370zaf +R4gqCQwxzOCMJGE9K6A4rm20ttnDysuJ4OBxmq0uWllv08rNIjyOBPRsCg5GJLnODDZQg+s/yqUs +zJKlqUVHJNSmkqGOZOt1TBvGfZIxkVwWsg1KlaEmT8DhxX7u3dqlStTka/D3Ur2nrylKkfiIEr9z +IjK/K4g9fvR/xBsyLDqF+IwsrjqSl5rd1CFjcAfkZqVKHYIZOonyclpZz0oeygoUpWetSpWVmz1O +c6Ol9o9lDoaBIkPMOZS4obTg4URUqUzWAeDE7SVPEYrXrSZb30ORGwhwDG4rUr/M0SXri+SpYcYu +EiMMcJbVx9alSgtpad27aMw6ai0pjdKFz1nqJuSn/wAtIJIznj+lfQu11VueVdJm9weohwjNSpWj +UigYAmfsck8wPPlPKz5jzyz33LJoOt1SieSB7VKlGQQDk5n2w35qwCaYLbEQEBwgY7CpUrlphaAC +3MIkBKc0DuUUKC5CcJIPI96lSh18GH1AyINiI8x9CM4x3Fat4f6okWOY0qKkFv8AKpCgCFp75qVK +xqfUY+MUENmMmv7bHbDV5tqPJjTFcsK6pVgE4+Kz68xy41vZUEKPvUqUovDyufKjmfrVmYbiHd6n +cbis+/WpUqUcMZKdF44n/9k= + +--Apple-Mail-4-163265085-- + +--Apple-Mail-3-163265085-- diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8b/8be5515353af5348184307d5162405a9424a7697.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8b/8be5515353af5348184307d5162405a9424a7697.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class FixMessagesStickyNull < ActiveRecord::Migration + def self.up + Message.update_all('sticky = 0', 'sticky IS NULL') + end + + def self.down + # nothing to do + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8c/8c1df4d73d6e3117c24c3c76b9007e79ab4c6eb2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8c/8c1df4d73d6e3117c24c3c76b9007e79ab4c6eb2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +class SetTopicAuthorsAsWatchers < ActiveRecord::Migration + def self.up + # Sets active users who created/replied a topic as watchers of the topic + # so that the new watch functionality at topic level doesn't affect notifications behaviour + Message.connection.execute("INSERT INTO #{Watcher.table_name} (watchable_type, watchable_id, user_id)" + + " SELECT DISTINCT 'Message', COALESCE(m.parent_id, m.id), m.author_id" + + " FROM #{Message.table_name} m, #{User.table_name} u" + + " WHERE m.author_id = u.id AND u.status = 1") + end + + def self.down + # Removes all message watchers + Watcher.delete_all("watchable_type = 'Message'") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8c/8c4fab1287b72e3f74cffb8a1dd8ba6c360dd802.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8c/8c4fab1287b72e3f74cffb8a1dd8ba6c360dd802.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,110 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class QueriesController < ApplicationController + menu_item :issues + before_filter :find_query, :except => [:new, :create, :index] + before_filter :find_optional_project, :only => [:new, :create] + + accept_api_auth :index + + include QueriesHelper + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @query_count = Query.visible.count + @query_pages = Paginator.new self, @query_count, @limit, params['page'] + @queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name") + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + def new + @query = Query.new + @query.user = User.current + @query.project = @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + build_query_from_params + end + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create + @query = Query.new(params[:query]) + @query.user = User.current + @query.project = params[:query_is_for_all] ? nil : @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + build_query_from_params + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query + else + render :action => 'new', :layout => !request.xhr? + end + end + + def edit + end + + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + def update + @query.attributes = params[:query] + @query.project = nil if params[:query_is_for_all] + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + build_query_from_params + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query + else + render :action => 'edit' + end + end + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } + def destroy + @query.destroy + redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 + end + +private + def find_query + @query = Query.find(params[:id]) + @project = @query.project + render_403 unless @query.editable_by?(User.current) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_optional_project + @project = Project.find(params[:project_id]) if params[:project_id] + render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8c/8c8f1143f138ce617f21f89790a7e1f8a60e4e92.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8c/8c8f1143f138ce617f21f89790a7e1f8a60e4e92.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 AuthSourcesHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8c/8c9985bb9b23719d27561e0988a8665ae9ec3fc9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8c/8c9985bb9b23719d27561e0988a8665ae9ec3fc9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=h @enumeration %>

    + +<% form_tag({:action => 'update', :id => @enumeration}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8c/8cc3b49fb336589b0c77ad88bf1cb1e4d4cc2b4b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8c/8cc3b49fb336589b0c77ad88bf1cb1e4d4cc2b4b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,215 @@ +#!/usr/bin/env ruby +require 'coderay' + +$options, args = ARGV.partition { |arg| arg[/^-[hv]$|--\w+/] } +subcommand = args.first if /^\w/ === args.first +subcommand = nil if subcommand && File.exist?(subcommand) +args.delete subcommand + +def option? *options + !($options & options).empty? +end + +def tty? + $stdout.tty? || option?('--tty') +end + +def version + puts <<-USAGE +CodeRay #{CodeRay::VERSION} + USAGE +end + +def help + puts <<-HELP +This is CodeRay #{CodeRay::VERSION}, a syntax highlighting tool for selected languages. + +usage: + coderay [-language] [input] [-format] [output] + +defaults: + language detect from input file name or shebang; fall back to plain text + input STDIN + format detect from output file name or use terminal; fall back to HTML + output STDOUT + +common: + coderay file.rb # highlight file to terminal + coderay file.rb > file.html # highlight file to HTML page + coderay file.rb -div > file.html # highlight file to HTML snippet + +configure output: + coderay file.py output.json # output tokens as JSON + coderay file.py -loc # count lines of code in Python file + +configure input: + coderay -python file # specify the input language + coderay -ruby # take input from STDIN + +more: + coderay stylesheet [style] # print CSS stylesheet + HELP +end + +def commands + puts <<-COMMANDS + general: + highlight code highlighting (default command, optional) + stylesheet print the CSS stylesheet with the given name (aliases: style, css) + + about: + list [of] list all available plugins (or just the scanners|encoders|styles|filetypes) + commands print this list + help show some help + version print CodeRay version + COMMANDS +end + +def print_list_of plugin_host + plugins = plugin_host.all_plugins.map do |plugin| + info = " #{plugin.plugin_id}: #{plugin.title}" + + aliases = (plugin.aliases - [:default]).map { |key| "-#{key}" }.sort_by { |key| key.size } + if plugin.respond_to?(:file_extension) || !aliases.empty? + additional_info = [] + additional_info << aliases.join(', ') unless aliases.empty? + info << " (#{additional_info.join('; ')})" + end + + info << ' <-- default' if plugin.aliases.include? :default + + info + end + puts plugins.sort +end + +if option? '-v', '--version' + version +end + +if option? '-h', '--help' + help +end + +case subcommand +when 'highlight', nil + if ARGV.empty? + version + help + else + signature = args.map { |arg| arg[/^-/] ? '-' : 'f' }.join + names = args.map { |arg| arg.sub(/^-/, '') } + case signature + when /^$/ + exit + when /^ff?$/ + input_file, output_file, = *names + when /^f-f?$/ + input_file, output_format, output_file, = *names + when /^-ff?$/ + input_lang, input_file, output_file, = *names + when /^-f-f?$/ + input_lang, input_file, output_format, output_file, = *names + when /^--?f?$/ + input_lang, output_format, output_file, = *names + else + $stdout = $stderr + help + puts + puts "Unknown parameter order: #{args.join ' '}, expected: [-language] [input] [-format] [output]" + exit 1 + end + + if input_file + input_lang ||= CodeRay::FileType.fetch input_file, :text, true + end + + if output_file + output_format ||= CodeRay::FileType[output_file] + else + output_format ||= :terminal + end + + output_format = :page if output_format.to_s == 'html' + + if input_file + input = File.read input_file + else + input = $stdin.read + end + + begin + file = + if output_file + File.open output_file, 'w' + else + $stdout.sync = true + $stdout + end + CodeRay.encode(input, input_lang, output_format, :out => file) + file.puts + rescue CodeRay::PluginHost::PluginNotFound => boom + $stdout = $stderr + if boom.message[/CodeRay::(\w+)s could not load plugin :?(.*?): /] + puts "I don't know the #$1 \"#$2\"." + else + puts boom.message + end + # puts "I don't know this plugin: #{boom.message[/Could not load plugin (.*?): /, 1]}." + rescue CodeRay::Scanners::Scanner::ScanError # FIXME: rescue Errno::EPIPE + # this is sometimes raised by pagers; ignore [TODO: wtf?] + ensure + file.close if output_file + end + end +when 'li', 'list' + arg = args.first && args.first.downcase + if [nil, 's', 'sc', 'scanner', 'scanners'].include? arg + puts 'input languages (Scanners):' + print_list_of CodeRay::Scanners + end + + if [nil, 'e', 'en', 'enc', 'encoder', 'encoders'].include? arg + puts 'output formats (Encoders):' + print_list_of CodeRay::Encoders + end + + if [nil, 'st', 'style', 'styles'].include? arg + puts 'CSS themes for HTML output (Styles):' + print_list_of CodeRay::Styles + end + + if [nil, 'f', 'ft', 'file', 'filetype', 'filetypes'].include? arg + puts 'recognized file types:' + + filetypes = Hash.new { |h, k| h[k] = [] } + CodeRay::FileType::TypeFromExt.inject filetypes do |types, (ext, type)| + types[type.to_s] << ".#{ext}" + types + end + CodeRay::FileType::TypeFromName.inject filetypes do |types, (name, type)| + types[type.to_s] << name + types + end + + filetypes.sort.each do |type, exts| + puts " #{type}: #{exts.sort_by { |ext| ext.size }.join(', ')}" + end + end +when 'stylesheet', 'style', 'css' + puts CodeRay::Encoders[:html]::CSS.new(args.first).stylesheet +when 'commands' + commands +when 'help' + help +else + $stdout = $stderr + help + puts + if subcommand[/\A\w+\z/] + puts "Unknown command: #{subcommand}" + else + puts "File not found: #{subcommand}" + end + exit 1 +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8c/8cc5de5e640ab07aad0e53b894b271a11458548a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8c/8cc5de5e640ab07aad0e53b894b271a11458548a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class FixUsersCustomValues < ActiveRecord::Migration + def self.up + CustomValue.update_all("customized_type = 'Principal'", "customized_type = 'User'") + end + + def self.down + CustomValue.update_all("customized_type = 'User'", "customized_type = 'Principal'") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8d/8d137ddbd4cf6f8f24fe80f23c9c81f3f5e0f6a8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8d/8d137ddbd4cf6f8f24fe80f23c9c81f3f5e0f6a8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Themes + + # Return an array of installed themes + def self.themes + @@installed_themes ||= scan_themes + end + + # Rescan themes directory + def self.rescan + @@installed_themes = scan_themes + end + + # Return theme for given id, or nil if it's not found + def self.theme(id, options={}) + return nil if id.blank? + + found = themes.find {|t| t.id == id} + if found.nil? && options[:rescan] != false + rescan + found = theme(id, :rescan => false) + end + found + end + + # Class used to represent a theme + class Theme + attr_reader :path, :name, :dir + + def initialize(path) + @path = path + @dir = File.basename(path) + @name = @dir.humanize + @stylesheets = nil + @javascripts = nil + end + + # Directory name used as the theme id + def id; dir end + + def ==(theme) + theme.is_a?(Theme) && theme.dir == dir + end + + def <=>(theme) + name <=> theme.name + end + + def stylesheets + @stylesheets ||= assets("stylesheets", "css") + end + + def javascripts + @javascripts ||= assets("javascripts", "js") + end + + def stylesheet_path(source) + "/themes/#{dir}/stylesheets/#{source}" + end + + def javascript_path(source) + "/themes/#{dir}/javascripts/#{source}" + end + + private + + def assets(dir, ext) + Dir.glob("#{path}/#{dir}/*.#{ext}").collect {|f| File.basename(f).gsub(/\.#{ext}$/, '')} + end + end + + private + + def self.scan_themes + dirs = Dir.glob("#{Rails.public_path}/themes/*").select do |f| + # A theme should at least override application.css + File.directory?(f) && File.exist?("#{f}/stylesheets/application.css") + end + dirs.collect {|dir| Theme.new(dir)}.sort + end + end +end + +module ApplicationHelper + def current_theme + unless instance_variable_defined?(:@current_theme) + @current_theme = Redmine::Themes.theme(Setting.ui_theme) + end + @current_theme + end + + def stylesheet_path(source) + if current_theme && current_theme.stylesheets.include?(source) + super current_theme.stylesheet_path(source) + else + super + end + end + + def path_to_stylesheet(source) + stylesheet_path source + end + + # Returns the header tags for the current theme + def heads_for_theme + if current_theme && current_theme.javascripts.include?('theme') + javascript_include_tag current_theme.javascript_path('theme') + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8d/8d16ae55d2f1c008a010086c27548d8733c4f49f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8d/8d16ae55d2f1c008a010086c27548d8733c4f49f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,82 @@ +var NS4 = (navigator.appName == "Netscape" && parseInt(navigator.appVersion) < 5); + +function addOption(theSel, theText, theValue) +{ + var newOpt = new Option(theText, theValue); + var selLength = theSel.length; + theSel.options[selLength] = newOpt; +} + +function swapOptions(theSel, index1, index2) +{ + var text, value; + text = theSel.options[index1].text; + value = theSel.options[index1].value; + theSel.options[index1].text = theSel.options[index2].text; + theSel.options[index1].value = theSel.options[index2].value; + theSel.options[index2].text = text; + theSel.options[index2].value = value; +} + +function deleteOption(theSel, theIndex) +{ + var selLength = theSel.length; + if(selLength>0) + { + theSel.options[theIndex] = null; + } +} + +function moveOptions(theSelFrom, theSelTo) +{ + + var selLength = theSelFrom.length; + var selectedText = new Array(); + var selectedValues = new Array(); + var selectedCount = 0; + + var i; + + for(i=selLength-1; i>=0; i--) + { + if(theSelFrom.options[i].selected) + { + selectedText[selectedCount] = theSelFrom.options[i].text; + selectedValues[selectedCount] = theSelFrom.options[i].value; + deleteOption(theSelFrom, i); + selectedCount++; + } + } + + for(i=selectedCount-1; i>=0; i--) + { + addOption(theSelTo, selectedText[i], selectedValues[i]); + } + + if(NS4) history.go(0); +} + +function moveOptionUp(theSel) { + var index = theSel.selectedIndex; + if (index > 0) { + swapOptions(theSel, index-1, index); + theSel.selectedIndex = index-1; + } +} + +function moveOptionDown(theSel) { + var index = theSel.selectedIndex; + if (index < theSel.length - 1) { + swapOptions(theSel, index, index+1); + theSel.selectedIndex = index+1; + } +} + +function selectAllOptions(id) +{ + var select = $(id); + for (var i=0; iIdentifikatoren kan ikke endres etter den er lagret.' + text_caracters_maximum: "%{count} tegn maksimum." + text_caracters_minimum: "Må være minst %{count} tegn langt." + text_length_between: "Lengde mellom %{min} og %{max} tegn." + text_tracker_no_workflow: Ingen arbeidsflyt definert for denne sakstypen + text_unallowed_characters: Ugyldige tegn + text_comma_separated: Flere verdier tillat (kommaseparert). + text_issues_ref_in_commit_messages: Referering og retting av saker i innsendingsmelding + text_issue_added: "Sak %{id} er innrapportert av %{author}." + text_issue_updated: "Sak %{id} er oppdatert av %{author}." + text_wiki_destroy_confirmation: Er du sikker på at du vil slette denne wikien og alt innholdet ? + text_issue_category_destroy_question: "Noen saker (%{count}) er lagt til i denne kategorien. Hva vil du gjøre ?" + text_issue_category_destroy_assignments: Fjern bruk av kategorier + text_issue_category_reassign_to: Overfør sakene til denne kategorien + text_user_mail_option: "For ikke-valgte prosjekter vil du bare motta varsling om ting du overvåker eller er involveret i (eks. saker du er forfatter av eller er tildelt)." + text_no_configuration_data: "Roller, arbeidsflyt, sakstyper og -statuser er ikke konfigurert enda.\nDet anbefales sterkt å laste inn standardkonfigurasjonen. Du vil kunne endre denne etter den er innlastet." + text_load_default_configuration: Last inn standardkonfigurasjonen + text_status_changed_by_changeset: "Brukt i endringssett %{value}." + text_issues_destroy_confirmation: 'Er du sikker på at du vil slette valgte sak(er) ?' + text_select_project_modules: 'Velg moduler du vil aktivere for dette prosjektet:' + text_default_administrator_account_changed: Standard administrator-konto er endret + text_file_repository_writable: Fil-arkivet er skrivbart + text_rmagick_available: RMagick er tilgjengelig (valgfritt) + text_destroy_time_entries_question: "%{hours} timer er ført på sakene du er i ferd med å slette. Hva vil du gjøre ?" + text_destroy_time_entries: Slett førte timer + text_assign_time_entries_to_project: Overfør førte timer til prosjektet + text_reassign_time_entries: 'Overfør førte timer til denne saken:' + text_user_wrote: "%{value} skrev:" + + default_role_manager: Leder + default_role_developer: Utvikler + default_role_reporter: Rapportør + default_tracker_bug: Feil + default_tracker_feature: Funksjon + default_tracker_support: Support + default_issue_status_new: Ny + default_issue_status_in_progress: Pågår + default_issue_status_resolved: Avklart + default_issue_status_feedback: Tilbakemelding + default_issue_status_closed: Lukket + default_issue_status_rejected: Avvist + default_doc_category_user: Brukerdokumentasjon + default_doc_category_tech: Teknisk dokumentasjon + default_priority_low: Lav + default_priority_normal: Normal + default_priority_high: Høy + default_priority_urgent: Haster + default_priority_immediate: Omgående + default_activity_design: Design + default_activity_development: Utvikling + + enumeration_issue_priorities: Sakssprioriteringer + enumeration_doc_categories: Dokumentkategorier + enumeration_activities: Aktiviteter (tidsregistrering) + text_enumeration_category_reassign_to: 'Endre dem til denne verdien:' + text_enumeration_destroy_question: "%{count} objekter er endret til denne verdien." + label_incoming_emails: Innkommende e-post + label_generate_key: Generer en nøkkel + setting_mail_handler_api_enabled: Skru på WS for innkommende epost + setting_mail_handler_api_key: API-nøkkel + text_email_delivery_not_configured: "Levering av epost er ikke satt opp, og varsler er skrudd av.\nStill inn din SMTP-tjener i config/configuration.yml og start programmet på nytt for å skru det på." + field_parent_title: Overordnet side + label_issue_watchers: Overvåkere + button_quote: Sitat + setting_sequential_project_identifiers: Generer sekvensielle prosjekt-IDer + notice_unable_delete_version: Kan ikke slette versjonen + label_renamed: gitt nytt navn + label_copied: kopiert + setting_plain_text_mail: kun ren tekst (ikke HTML) + permission_view_files: Vise filer + permission_edit_issues: Redigere saker + permission_edit_own_time_entries: Redigere egne timelister + permission_manage_public_queries: Administrere delte søk + permission_add_issues: Legge inn saker + permission_log_time: Loggføre timer + permission_view_changesets: Vise endringssett + permission_view_time_entries: Vise brukte timer + permission_manage_versions: Administrere versjoner + permission_manage_wiki: Administrere wiki + permission_manage_categories: Administrere kategorier for saker + permission_protect_wiki_pages: Beskytte wiki-sider + permission_comment_news: Kommentere nyheter + permission_delete_messages: Slette meldinger + permission_select_project_modules: Velge prosjektmoduler + permission_manage_documents: Administrere dokumenter + permission_edit_wiki_pages: Redigere wiki-sider + permission_add_issue_watchers: Legge til overvåkere + permission_view_gantt: Vise gantt-diagram + permission_move_issues: Flytte saker + permission_manage_issue_relations: Administrere saksrelasjoner + permission_delete_wiki_pages: Slette wiki-sider + permission_manage_boards: Administrere forum + permission_delete_wiki_pages_attachments: Slette vedlegg + permission_view_wiki_edits: Vise wiki-historie + permission_add_messages: Sende meldinger + permission_view_messages: Vise meldinger + permission_manage_files: Administrere filer + permission_edit_issue_notes: Redigere notater + permission_manage_news: Administrere nyheter + permission_view_calendar: Vise kalender + permission_manage_members: Administrere medlemmer + permission_edit_messages: Redigere meldinger + permission_delete_issues: Slette saker + permission_view_issue_watchers: Vise liste over overvåkere + permission_manage_repository: Administrere depot + permission_commit_access: Tilgang til innsending + permission_browse_repository: Bla gjennom depot + permission_view_documents: Vise dokumenter + permission_edit_project: Redigere prosjekt + permission_add_issue_notes: Legge til notater + permission_save_queries: Lagre søk + permission_view_wiki_pages: Vise wiki + permission_rename_wiki_pages: Gi wiki-sider nytt navn + permission_edit_time_entries: Redigere timelister + permission_edit_own_issue_notes: Redigere egne notater + setting_gravatar_enabled: Bruk Gravatar-brukerikoner + label_example: Eksempel + text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + permission_edit_own_messages: Rediger egne meldinger + permission_delete_own_messages: Slett egne meldinger + label_user_activity: "%{value}s aktivitet" + label_updated_time_by: "Oppdatert av %{author} for %{age} siden" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} fil(er) kunne ikke lagres." + button_create_and_continue: Opprett og fortsett + text_custom_field_possible_values_info: 'En linje for hver verdi' + label_display: Visning + field_editable: Redigerbar + setting_repository_log_display_limit: Maks antall revisjoner vist i fil-loggen + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Overvåker + setting_openid: Tillat OpenID innlogging og registrering + field_identity_url: OpenID URL + label_login_with_open_id_option: eller logg inn med OpenID + field_content: Innhold + label_descending: Synkende + label_sort: Sorter + label_ascending: Stigende + label_date_from_to: Fra %{start} til %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Denne siden har %{descendants} underside(r). Hva ønsker du å gjøre? + text_wiki_page_reassign_children: Tilknytt undersider til denne overordnede siden + text_wiki_page_nullify_children: Behold undersider som rotsider + text_wiki_page_destroy_children: Slett undersider og alle deres underliggende sider + setting_password_min_length: Minimum passordlengde + field_group_by: Grupper resultater etter + mail_subject_wiki_content_updated: "Wiki-side '%{id}' er oppdatert" + label_wiki_content_added: Wiki-side opprettet + mail_subject_wiki_content_added: "Wiki-side '%{id}' er opprettet" + mail_body_wiki_content_added: Wiki-siden '%{id}' ble opprettet av %{author}. + label_wiki_content_updated: Wiki-side oppdatert + mail_body_wiki_content_updated: Wiki-siden '%{id}' ble oppdatert av %{author}. + permission_add_project: Opprett prosjekt + setting_new_project_user_role_id: Rolle gitt en ikke-administratorbruker som oppretter et prosjekt + label_view_all_revisions: Se alle revisjoner + label_tag: Tag + label_branch: Gren + error_no_tracker_in_project: Ingen sakstyper er tilknyttet dette prosjektet. Vennligst kontroller prosjektets innstillinger. + error_no_default_issue_status: Ingen standard saksstatus er angitt. Vennligst kontroller konfigurasjonen (Gå til "Administrasjon -> Saksstatuser"). + text_journal_changed: "%{label} endret fra %{old} til %{new}" + text_journal_set_to: "%{label} satt til %{value}" + text_journal_deleted: "%{label} slettet (%{old})" + label_group_plural: Grupper + label_group: Gruppe + label_group_new: Ny gruppe + label_time_entry_plural: Brukt tid + text_journal_added: "%{label} %{value} lagt til" + field_active: Aktiv + enumeration_system_activity: Systemaktivitet + permission_delete_issue_watchers: Slett overvåkere + version_status_closed: stengt + version_status_locked: låst + version_status_open: åpen + error_can_not_reopen_issue_on_closed_version: En sak tilknyttet en stengt versjon kan ikke gjenåpnes. + label_user_anonymous: Anonym + button_move_and_follow: Flytt og følg etter + setting_default_projects_modules: Standard aktiverte moduler for nye prosjekter + setting_gravatar_default: Standard Gravatar-bilde + field_sharing: Deling + label_version_sharing_hierarchy: Med prosjekt-hierarki + label_version_sharing_system: Med alle prosjekter + label_version_sharing_descendants: Med underprosjekter + label_version_sharing_tree: Med prosjekt-tre + label_version_sharing_none: Ikke delt + error_can_not_archive_project: Dette prosjektet kan ikke arkiveres + button_duplicate: Duplikat + button_copy_and_follow: Kopier og følg etter + label_copy_source: Kilde + setting_issue_done_ratio: Kalkuler ferdigstillingsprosent ut i fra + setting_issue_done_ratio_issue_status: Bruk saksstatuser + error_issue_done_ratios_not_updated: Ferdigstillingsprosent oppdateres ikke. + error_workflow_copy_target: Vennligst velg sakstype(r) og rolle(r) + setting_issue_done_ratio_issue_field: Bruk felt fra saker + label_copy_same_as_target: Samme som mål + label_copy_target: Mål + notice_issue_done_ratios_updated: Ferdigstillingsprosent oppdatert. + error_workflow_copy_source: Vennligst velg en kilde-sakstype eller rolle. + label_update_issue_done_ratios: Oppdatert ferdigstillingsprosent + setting_start_of_week: Start kalender på + permission_view_issues: Se på saker + label_display_used_statuses_only: Vis kun statuser som brukes av denne sakstypen + label_revision_id: Revision %{value} + label_api_access_key: API tilgangsnøkkel + label_api_access_key_created_on: API tilgangsnøkkel opprettet for %{value} siden + label_feeds_access_key: RSS tilgangsnøkkel + notice_api_access_key_reseted: Din API tilgangsnøkkel ble resatt. + setting_rest_api_enabled: Aktiver REST webservice + label_missing_api_access_key: Mangler en API tilgangsnøkkel + label_missing_feeds_access_key: Mangler en RSS tilgangsnøkkel + button_show: Vis + text_line_separated: Flere verdier er tillatt (en linje per verdi). + setting_mail_handler_body_delimiters: Avkort epost etter en av disse linjene + permission_add_subprojects: Opprett underprosjekt + label_subproject_new: Nytt underprosjekt + text_own_membership_delete_confirmation: |- + Du er i ferd med å fjerne noen eller alle rettigheter og vil kanskje ikke være i stand til å redigere dette prosjektet etterpå. + Er du sikker på at du vil fortsette? + label_close_versions: Steng fullførte versjoner + label_board_sticky: Fast + label_board_locked: Låst + permission_export_wiki_pages: Eksporter wiki-sider + setting_cache_formatted_text: Mellomlagre formattert tekst + permission_manage_project_activities: Administrere prosjektaktiviteter + error_unable_delete_issue_status: Kan ikke slette saksstatus + label_profile: Profil + permission_manage_subtasks: Administrere undersaker + field_parent_issue: Overordnet sak + label_subtask_plural: Undersaker + label_project_copy_notifications: Send epost-varslinger under prosjektkopiering + error_can_not_delete_custom_field: Kan ikke slette eget felt + error_unable_to_connect: Kunne ikke koble til (%{value}) + error_can_not_remove_role: Denne rollen er i bruk og kan ikke slettes. + error_can_not_delete_tracker: Denne sakstypen inneholder saker og kan ikke slettes. + field_principal: Principal + label_my_page_block: Min side felt + notice_failed_to_save_members: "Feil ved lagring av medlem(mer): %{errors}." + text_zoom_out: Zoom ut + text_zoom_in: Zoom inn + notice_unable_delete_time_entry: Kan ikke slette oppføring fra timeliste. + label_overall_spent_time: All tidsbruk + field_time_entries: Loggfør tid + project_module_gantt: Gantt + project_module_calendar: Kalender + button_edit_associated_wikipage: "Rediger tilhørende Wiki-side: %{page_title}" + text_are_you_sure_with_children: Slett sak og alle undersaker? + field_text: Tekstfelt + label_user_mail_option_only_owner: Kun for ting jeg eier + setting_default_notification_option: Standardvalg for varslinger + label_user_mail_option_only_my_events: Kun for ting jeg overvåker eller er involvert i + label_user_mail_option_only_assigned: Kun for ting jeg er tildelt + label_user_mail_option_none: Ingen hendelser + field_member_of_group: Den tildeltes gruppe + field_assigned_to_role: Den tildeltes rolle + notice_not_authorized_archived_project: Prosjektet du forsøker å åpne er blitt arkivert. + label_principal_search: "Søk etter bruker eller gruppe:" + label_user_search: "Søk etter bruker:" + field_visible: Synlig + setting_emails_header: Eposthode + setting_commit_logtime_activity_id: Aktivitet for logget tid. + text_time_logged_by_changeset: Lagt til i endringssett %{value}. + setting_commit_logtime_enabled: Muliggjør loggføring av tid + notice_gantt_chart_truncated: Diagrammet ble avkortet fordi det overstiger det maksimale antall elementer som kan vises (%{max}) + setting_gantt_items_limit: Maksimalt antall elementer vist på gantt-diagrammet + field_warn_on_leaving_unsaved: Vis meg en advarsel når jeg forlater en side med ikke lagret tekst + text_warn_on_leaving_unsaved: Den gjeldende siden inneholder tekst som ikke er lagret, som vil bli tapt hvis du forlater denne siden. + label_my_queries: Mine egne spørringer + text_journal_changed_no_detail: "%{label} oppdatert" + label_news_comment_added: Kommentar lagt til en nyhet + button_expand_all: Utvid alle + button_collapse_all: Kollaps alle + label_additional_workflow_transitions_for_assignee: Ytterligere overganger tillatt når brukeren er sakens tildelte + label_additional_workflow_transitions_for_author: Ytterligere overganger tillatt når brukeren er den som har opprettet saken + label_bulk_edit_selected_time_entries: Masserediger valgte timeliste-oppføringer + text_time_entries_destroy_confirmation: Er du sikker på du vil slette de(n) valgte timeliste-oppføringen(e)? + label_role_anonymous: Anonym + label_role_non_member: Ikke medlem + label_issue_note_added: Notat lagt til + label_issue_status_updated: Status oppdatert + label_issue_priority_updated: Prioritet oppdatert + label_issues_visibility_own: Saker opprettet av eller tildelt brukeren + field_issues_visibility: Synlighet på saker + label_issues_visibility_all: Alle saker + permission_set_own_issues_private: Gjør egne saker offentlige eller private + field_is_private: Privat + permission_set_issues_private: Gjør saker offentlige eller private + label_issues_visibility_public: Alle ikke-private saker + text_issues_destroy_descendants_confirmation: Dette vil også slette %{count} undersak(er). + field_commit_logs_encoding: Tegnkoding for innsendingsmeldinger + field_scm_path_encoding: Koding av sti + text_scm_path_encoding_note: "Standard: UTF-8" + field_path_to_repository: Sti til depot + field_root_directory: Rotkatalog + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokalt depot (f.eks. /hgrepo, c:\hgrepo) + text_scm_command: Kommando + text_scm_command_version: Versjon + label_git_report_last_commit: Rapporter siste innsending for filer og kataloger + text_scm_config: Du kan konfigurere scm kommandoer i config/configuration.yml. Vennligst restart applikasjonen etter å ha redigert filen. + text_scm_command_not_available: Scm kommando er ikke tilgjengelig. Vennligst kontroller innstillingene i administrasjonspanelet. + + text_git_repository_note: Depot er bart og lokalt (f.eks. /gitrepo, c:\gitrepo) + + notice_issue_successful_create: Sak %{id} opprettet. + label_between: mellom + setting_issue_group_assignment: Tillat tildeling av saker til grupper + label_diff: diff + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8d/8d70a80330e873b5c23fc9008335a0057853807a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8d/8d70a80330e873b5c23fc9008335a0057853807a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeProjectsIdentifierLimit < ActiveRecord::Migration + def self.up + change_column :projects, :identifier, :string, :limit => nil + end + + def self.down + change_column :projects, :identifier, :string, :limit => 20 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8d/8d7fae9b6295abcc91d872594ff664db1efabeb4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8d/8d7fae9b6295abcc91d872594ff664db1efabeb4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +Pagination +========== + +To install: + + script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination + +This code was extracted from Rails trunk after the release 1.2.3. +WARNING: this code is dead. It is unmaintained, untested and full of cruft. + +There is a much better pagination plugin called will_paginate. +Install it like this and glance through the README: + + script/plugin install svn://errtheblog.com/svn/plugins/will_paginate + +It doesn't have the same API, but is in fact much nicer. You can +have both plugins installed until you change your controller/view code that +handles pagination. Then, simply uninstall classic_pagination. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8d/8dc228786073bdd226ed8ffeeb72abeba31ad9e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8d/8dc228786073bdd226ed8ffeeb72abeba31ad9e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,57 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class UserPreference < ActiveRecord::Base + belongs_to :user + serialize :others + + attr_protected :others + + def initialize(attributes = nil) + super + self.others ||= {} + end + + def before_save + self.others ||= {} + end + + def [](attr_name) + if attribute_present? attr_name + super + else + others ? others[attr_name] : nil + end + end + + def []=(attr_name, value) + if attribute_present? attr_name + super + else + h = read_attribute(:others).dup || {} + h.update(attr_name => value) + write_attribute(:others, h) + value + end + end + + def comments_sorting; self[:comments_sorting] end + def comments_sorting=(order); self[:comments_sorting]=order end + + def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end + def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8e/8e3a1cce1761039cfaa74854eab700c58025e356.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8e/8e3a1cce1761039cfaa74854eab700c58025e356.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<%= f.error_messages %> + +
    +

    <%= f.text_field :lastname, :label => :field_name %>

    + <% @group.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :group, value %>

    + <% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/8e/8e4c7afc7109386dd42e0a86c04a6247a9bd537e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/8e/8e4c7afc7109386dd42e0a86c04a6247a9bd537e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,343 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) +require 'digest/md5' + +class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase + + def setup + @formatter = Redmine::WikiFormatting::Textile::Formatter + end + + MODIFIERS = { + "*" => 'strong', # bold + "_" => 'em', # italic + "+" => 'ins', # underline + "-" => 'del', # deleted + "^" => 'sup', # superscript + "~" => 'sub' # subscript + } + + def test_modifiers + assert_html_output( + '*bold*' => 'bold', + 'before *bold*' => 'before bold', + '*bold* after' => 'bold after', + '*two words*' => 'two words', + '*two*words*' => 'two*words', + '*two * words*' => 'two * words', + '*two* *words*' => 'two words', + '*(two)* *(words)*' => '(two) (words)', + # with class + '*(foo)two words*' => 'two words' + ) + end + + def test_modifiers_combination + MODIFIERS.each do |m1, tag1| + MODIFIERS.each do |m2, tag2| + next if m1 == m2 + text = "#{m2}#{m1}Phrase modifiers#{m1}#{m2}" + html = "<#{tag2}><#{tag1}>Phrase modifiers" + assert_html_output text => html + end + end + end + + def test_inline_code + assert_html_output( + 'this is @some code@' => 'this is some code', + '@@' => '<Location /redmine>' + ) + end + + def test_escaping + assert_html_output( + 'this is a " => "

    <script>some script;</script>

    ", + # do not escape pre/code tags + "
    \nline 1\nline2
    " => "
    \nline 1\nline2
    ", + "
    \nline 1\nline2
    " => "
    \nline 1\nline2
    ", + "
    content
    " => "
    <div>content</div>
    ", + "HTML comment: " => "

    HTML comment: <!-- no comments -->

    ", + "|.*)/m) + encoder.text_token match, :comment + elsif match = scan(/|.*)/m) + encoder.text_token match, :doctype + elsif match = scan(/<\?xml(?:.*?\?>|.*)/m) + encoder.text_token match, :preprocessor + elsif match = scan(/<\?(?:.*?\?>|.*)/m) + encoder.text_token match, :comment + elsif match = scan(/<\/[-\w.:]*>?/m) + in_tag = nil + encoder.text_token match, :tag + elsif match = scan(/<(?:(script)|[-\w.:]+)(>)?/m) + encoder.text_token match, :tag + in_tag = self[1] + if self[2] + state = :in_special_tag if in_tag + else + state = :attribute + end + elsif match = scan(/[^<>&]+/) + encoder.text_token match, :plain + elsif match = scan(/#{ENTITY}/ox) + encoder.text_token match, :entity + elsif match = scan(/[<>&]/) + in_tag = nil + encoder.text_token match, :error + else + raise_inspect '[BUG] else-case reached with state %p' % [state], encoder + end + + when :attribute + if match = scan(/#{TAG_END}/o) + encoder.text_token match, :tag + in_attribute = nil + if in_tag + state = :in_special_tag + else + state = :initial + end + elsif match = scan(/#{ATTR_NAME}/o) + in_attribute = IN_ATTRIBUTE[match] + encoder.text_token match, :attribute_name + state = :attribute_equal + else + in_tag = nil + encoder.text_token getch, :error + end + + when :attribute_equal + if match = scan(/=/) #/ + encoder.text_token match, :operator + state = :attribute_value + elsif scan(/#{ATTR_NAME}/o) || scan(/#{TAG_END}/o) + state = :attribute + next + else + encoder.text_token getch, :error + state = :attribute + end + + when :attribute_value + if match = scan(/#{ATTR_NAME}/o) + encoder.text_token match, :attribute_value + state = :attribute + elsif match = scan(/["']/) + if in_attribute == :script + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + if scan(/javascript:[ \t]*/) + encoder.text_token matched, :comment + end + code = scan_until(match == '"' ? /(?="|\z)/ : /(?='|\z)/) + scan_java_script encoder, code + match = scan(/["']/) + encoder.text_token match, :inline_delimiter if match + encoder.end_group :inline + state = :attribute + in_attribute = nil + else + encoder.begin_group :string + state = :attribute_value_string + plain_string_content = PLAIN_STRING_CONTENT[match] + encoder.text_token match, :delimiter + end + elsif match = scan(/#{TAG_END}/o) + encoder.text_token match, :tag + state = :initial + else + encoder.text_token getch, :error + end + + when :attribute_value_string + if match = scan(plain_string_content) + encoder.text_token match, :content + elsif match = scan(/['"]/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :attribute + elsif match = scan(/#{ENTITY}/ox) + encoder.text_token match, :entity + elsif match = scan(/&/) + encoder.text_token match, :content + elsif match = scan(/[\n>]/) + encoder.end_group :string + state = :initial + encoder.text_token match, :error + end + + when :in_special_tag + case in_tag + when 'script' + encoder.text_token match, :space if match = scan(/[ \t]*\n/) + if scan(/(\s*)|(.*))/m) + code = self[2] || self[4] + closing = self[3] + encoder.text_token self[1], :comment + else + code = scan_until(/(?=(?:\n\s*)?<\/script>)|\z/) + closing = false + end + unless code.empty? + encoder.begin_group :inline + scan_java_script encoder, code + encoder.end_group :inline + end + encoder.text_token closing, :comment if closing + state = :initial + else + raise 'unknown special tag: %p' % [in_tag] + end + + else + raise_inspect 'Unknown state: %p' % [state], encoder + + end + + end + + end + + if options[:keep_state] + @state = state + @plain_string_content = plain_string_content + end + + encoder.end_group :string if state == :attribute_value_string + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c4/c44c388b41c813b95c15c47903c713fd3c24bb0e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c4/c44c388b41c813b95c15c47903c713fd3c24bb0e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,102 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) +require 'pp' +class ApiTest::NewsTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :news + + def setup + Setting.rest_api_enabled = '1' + end + + context "GET /news" do + context ".xml" do + should "return news" do + get '/news.xml' + + assert_tag :tag => 'news', + :attributes => {:type => 'array'}, + :child => { + :tag => 'news', + :child => { + :tag => 'id', + :content => '2' + } + } + end + end + + context ".json" do + should "return news" do + get '/news.json' + + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert_kind_of Array, json['news'] + assert_kind_of Hash, json['news'].first + assert_equal 2, json['news'].first['id'] + end + end + end + + context "GET /projects/:project_id/news" do + context ".xml" do + should_allow_api_authentication(:get, "/projects/onlinestore/news.xml") + + should "return news" do + get '/projects/ecookbook/news.xml' + + assert_tag :tag => 'news', + :attributes => {:type => 'array'}, + :child => { + :tag => 'news', + :child => { + :tag => 'id', + :content => '2' + } + } + end + end + + context ".json" do + should_allow_api_authentication(:get, "/projects/onlinestore/news.json") + + should "return news" do + get '/projects/ecookbook/news.json' + + json = ActiveSupport::JSON.decode(response.body) + assert_kind_of Hash, json + assert_kind_of Array, json['news'] + assert_kind_of Hash, json['news'].first + assert_equal 2, json['news'].first['id'] + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c4/c47ea70159d60a5c0573c2a0aac115d020f1fa5a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c4/c47ea70159d60a5c0573c2a0aac115d020f1fa5a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +welcome: + id: 1 + title: Welcome to the weblog + lock_version: 24 + type: LockedPage +thinking: + id: 2 + title: So I was thinking + lock_version: 24 + type: SpecialLockedPage diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c4/c4ac74e610c2462a31209e180df1fe8ab03e924c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c4/c4ac74e610c2462a31209e180df1fe8ab03e924c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c4/c4b62ae1f4f01307776331aad68b547e24878c12.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c4/c4b62ae1f4f01307776331aad68b547e24878c12.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ModelAndLibTest < Test::Unit::TestCase + + def test_WITH_a_model_defined_only_in_a_plugin_IT_should_load_the_model + assert_equal 'AlphaPluginModel (from alpha_plugin)', AlphaPluginModel.report_location + end + + def test_WITH_a_model_defined_only_in_a_plugin_lib_dir_IT_should_load_the_model + assert_equal 'AlphaPluginLibModel (from alpha_plugin)', AlphaPluginLibModel.report_location + end + + # app takes precedence over plugins + + def test_WITH_a_model_defined_in_both_app_and_plugin_IT_should_load_the_one_in_app + assert_equal 'AppAndPluginModel (from app)', AppAndPluginModel.report_location + assert_raises(NoMethodError) { AppAndPluginLibModel.defined_only_in_alpha_engine_version } + end + + def test_WITH_a_model_defined_in_both_app_and_plugin_lib_dirs_IT_should_load_the_one_in_app + assert_equal 'AppAndPluginLibModel (from lib)', AppAndPluginLibModel.report_location + assert_raises(NoMethodError) { AppAndPluginLibModel.defined_only_in_alpha_engine_version } + end + + # subsequently loaded plugins take precendence over previously loaded plugins + + # TODO + # + # this does work when we rely on $LOAD_PATH while it won't work when we use + # Dependency constant autoloading. This somewhat confusing difference has + # been there since at least Rails 1.2.x. See http://www.ruby-forum.com/topic/134529 + + def test_WITH_a_model_defined_in_two_plugins_IT_should_load_the_latter_of_both + require 'shared_plugin_model' + assert_equal SharedPluginModel.report_location, 'SharedPluginModel (from beta_plugin)' + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c4/c4b7e166da06347732efe23afdfc246d0e8be00e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c4/c4b7e166da06347732efe23afdfc246d0e8be00e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,101 @@ +# Contains the enhancements to assist in testing plugins. See Engines::Testing +# for more details. + +require 'test/unit' + +require 'tmpdir' +require 'fileutils' + +# In most cases, Rails' own plugin testing mechanisms are sufficient. However, there +# are cases where plugins can be given a helping hand in the testing arena. This module +# contains some methods to assist when testing plugins that contain fixtures. +# +# == Fixtures and plugins +# +# Since Rails' own fixtures method is fairly strict about where files can be loaded from, +# the simplest approach when running plugin tests with fixtures is to simply copy all +# fixtures into a single temporary location and inform the standard Rails mechanism to +# use this directory, rather than RAILS_ROOT/test/fixtures. +# +# The Engines::Testing#setup_plugin_fixtures method does this, copying all plugin fixtures +# into the temporary location before and tests are performed. This behaviour is invoked +# the the rake tasks provided by the Engines plugin, in the "test:plugins" namespace. If +# necessary, you can invoke the task manually. +# +# If you wish to take advantage of this, add a call to the Engines::Testing.set_fixture_path +# method somewhere before your tests (in a test_helper file, or above the TestCase itself). +# +# = Testing plugins +# +# Normally testing a plugin will require that Rails is loaded, unless you are including +# a skeleton Rails environment or set of mocks within your plugin tests. If you require +# the Rails environment to be started, you must ensure that this actually happens; while +# it's not obvious, your tests do not automatically run with Rails loaded. +# +# The simplest way to setup plugin tests is to include a test helper with the following +# contents: +# +# # Load the normal Rails helper. This ensures the environment is loaded +# require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper') +# # Ensure that we are using the temporary fixture path +# Engines::Testing.set_fixture_path +# +# Then run tests using the provided tasks (test:plugins, or the tasks that the engines +# plugin provides - test:plugins:units, etc.). +# +# Alternatively, you can explicitly load the environment by adpating the contents of the +# default test_helper: +# +# ENV["RAILS_ENV"] = "test" +# # Note that we are requiring config/environment from the root of the enclosing application. +# require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment") +# require 'test_help' +# +module Engines::Testing + mattr_accessor :temporary_fixtures_directory + self.temporary_fixtures_directory = FileUtils.mkdir_p(File.join(Dir.tmpdir, "rails_fixtures")) + + # Copies fixtures from plugins and the application into a temporary directory + # (Engines::Testing.temporary_fixtures_directory). + # + # If a set of plugins is not given, fixtures are copied from all plugins in order + # of precedence, meaning that plugins can 'overwrite' the fixtures of others if they are + # loaded later; the application's fixtures are copied last, allowing any custom fixtures + # to override those in the plugins. If no argument is given, plugins are loaded via + # PluginList#by_precedence. + # + # This method is called by the engines-supplied plugin testing rake tasks + def self.setup_plugin_fixtures(plugins = Engines.plugins.by_precedence) + + # First, clear the directory + Dir.glob("#{self.temporary_fixtures_directory}/*.yml").each{|fixture| File.delete(fixture)} + + # Copy all plugin fixtures, and then the application fixtures, into this directory + plugins.each do |plugin| + plugin_fixtures_directory = File.join(plugin.directory, "test", "fixtures") + plugin_app_directory = File.join(plugin.directory, "app") + if File.directory?(plugin_app_directory) && File.directory?(plugin_fixtures_directory) + Engines.mirror_files_from(plugin_fixtures_directory, self.temporary_fixtures_directory) + end + end + Engines.mirror_files_from(File.join(RAILS_ROOT, "test", "fixtures"), + self.temporary_fixtures_directory) + end + + # Sets the fixture path used by Test::Unit::TestCase to the temporary + # directory which contains all plugin fixtures. + def self.set_fixture_path + ActiveSupport::TestCase.fixture_path = self.temporary_fixtures_directory + $LOAD_PATH.unshift self.temporary_fixtures_directory + end + + # overridden test should be in test/{unit,functional,integration}/{plugin_name}/{test_name} + def self.override_tests_from_app + filename = caller.first.split(":").first + plugin_name = filename.split("/")[-4] + test_kind = filename.split("/")[-2] + override_file = File.expand_path(File.join(File.dirname(filename), "..", "..", "..", "..", "..", "test", + test_kind, plugin_name, File.basename(filename))) + load(override_file) if File.exist?(override_file) + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c4/c4ee80c89b51195f1785a06677f274a4ebb1c20c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c4/c4ee80c89b51195f1785a06677f274a4ebb1c20c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class Thing + def self.from_app; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c52de5352fd6a63c50f835f73d19c6ea098b9072.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c52de5352fd6a63c50f835f73d19c6ea098b9072.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class SharedPluginModel < ActiveRecord::Base + def self.report_location; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c5503b3ee9ba7623ae8cf8fbea689e4b99399e2c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c5503b3ee9ba7623ae8cf8fbea689e4b99399e2c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,154 @@ +require File.expand_path('../../../../../../test_helper', __FILE__) +begin + require 'mocha' + + class BazaarAdapterTest < ActiveSupport::TestCase + REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s + REPOSITORY_PATH.gsub!(/\/+/, '/') + + if File.directory?(REPOSITORY_PATH) + def setup + @adapter = Redmine::Scm::Adapters::BazaarAdapter.new( + File.join(REPOSITORY_PATH, "trunk") + ) + end + + def test_scm_version + to_test = { "Bazaar (bzr) 2.1.2\n" => [2,1,2], + "2.1.1\n1.7\n1.8" => [2,1,1], + "2.0.1\r\n1.8.1\r\n1.9.1" => [2,0,1]} + to_test.each do |s, v| + test_scm_version_for(s, v) + end + end + + def test_cat + cat = @adapter.cat('directory/document.txt') + assert cat =~ /Write the contents of a file as of a given revision to standard output/ + end + + def test_cat_path_invalid + assert_nil @adapter.cat('invalid') + end + + def test_cat_revision_invalid + assert_nil @adapter.cat('doc-mkdir.txt', '12345678') + end + + def test_diff_path_invalid + assert_equal [], @adapter.diff('invalid', 1) + end + + def test_diff_revision_invalid + assert_equal [], @adapter.diff(nil, 12345678) + assert_equal [], @adapter.diff(nil, 12345678, 87654321) + end + + def test_annotate + annotate = @adapter.annotate('doc-mkdir.txt') + assert_equal 17, annotate.lines.size + assert_equal '1', annotate.revisions[0].identifier + assert_equal 'jsmith@', annotate.revisions[0].author + assert_equal 'mkdir', annotate.lines[0] + end + + def test_annotate_path_invalid + assert_nil @adapter.annotate('invalid') + end + + def test_annotate_revision_invalid + assert_nil @adapter.annotate('doc-mkdir.txt', '12345678') + end + + def test_branch_conf_path + p = "c:\\test\\test\\" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "c:\\test\\test\\.bzr" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "c:\\test\\test\\.bzr\\" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "c:\\test\\test" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "\\\\server\\test\\test\\" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("\\\\server\\test\\test", ".bzr", "branch", "branch.conf"), bcp + end + + def test_append_revisions_only_true + assert_equal true, @adapter.append_revisions_only + end + + def test_append_revisions_only_false + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + File.join(REPOSITORY_PATH, "empty-branch") + ) + assert_equal false, adpt.append_revisions_only + end + + def test_append_revisions_only_shared_repo + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + REPOSITORY_PATH + ) + assert_equal false, adpt.append_revisions_only + end + + def test_info_not_nil + assert_not_nil @adapter.info + end + + def test_info_nil + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + "/invalid/invalid/" + ) + assert_nil adpt.info + end + + def test_info + info = @adapter.info + assert_equal 4, info.lastrev.identifier.to_i + end + + def test_info_emtpy + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + File.join(REPOSITORY_PATH, "empty-branch") + ) + assert_equal 0, adpt.info.lastrev.identifier.to_i + end + + def test_entries_path_invalid + assert_equal [], @adapter.entries('invalid') + end + + def test_entries_revision_invalid + assert_nil @adapter.entries(nil, 12345678) + end + + def test_revisions_path_invalid + assert_nil @adapter.revisions('invalid') + end + + def test_revisions_revision_invalid + assert_nil @adapter.revisions(nil, 12345678) + assert_nil @adapter.revisions(nil, 12345678, 87654321) + end + + private + + def test_scm_version_for(scm_command_version, version) + @adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version) + assert_equal version, @adapter.class.scm_command_version + end + else + puts "Bazaar test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end + end +rescue LoadError + class BazaarMochaFake < ActiveSupport::TestCase + def test_fake; assert(false, "Requires mocha to run those tests") end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c554ca3d3ef536612169417c578edf843b001721.svn-base Binary file .svn/pristine/c5/c554ca3d3ef536612169417c578edf843b001721.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c5649a1bf27c5e95ae3ea1070e4c95186fc163f0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c5649a1bf27c5e95ae3ea1070e4c95186fc163f0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,80 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'issues_controller' + +class IssuesControllerTransactionTest < ActionController::TestCase + fixtures :projects, + :users, + :roles, + :members, + :member_roles, + :issues, + :issue_statuses, + :versions, + :trackers, + :projects_trackers, + :issue_categories, + :enabled_modules, + :enumerations, + :attachments, + :workflows, + :custom_fields, + :custom_values, + :custom_fields_projects, + :custom_fields_trackers, + :time_entries, + :journals, + :journal_details, + :queries + + self.use_transactional_fixtures = false + + def setup + @controller = IssuesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_put_update_stale_issue + issue = Issue.find(2) + @request.session[:user_id] = 2 + + assert_no_difference 'Journal.count' do + assert_no_difference 'TimeEntry.count' do + assert_no_difference 'Attachment.count' do + put :update, + :id => issue.id, + :issue => { + :fixed_version_id => 4, + :lock_version => (issue.lock_version - 1) + }, + :notes => '', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}, + :time_entry => { :hours => '2.5', :comments => '', :activity_id => TimeEntryActivity.first.id } + end + end + end + + assert_response :success + assert_template 'edit' + assert_tag :tag => 'div', :attributes => { :id => 'errorExplanation' }, + :content => /Data has been updated by another user/ + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c5707570ea0196ea9f935f667e3dcd5ff44e5925.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c5707570ea0196ea9f935f667e3dcd5ff44e5925.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,74 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sat, 21 Jun 2008 18:41:39 +0200 +Message-ID: <006a01c8d3bd$ad9baec0$0a00a8c0@osiris> +In-Reply-To: +From: "John Smith" +To: +References: <485d0ad366c88_d7014663a025f@osiris.tmail> +Subject: Re: Add ingredients categories +Date: Sat, 21 Jun 2008 18:41:39 +0200 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_NextPart_000_0067_01C8D3CE.711F9CC0" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +This is a multi-part message in MIME format. + +------=_NextPart_000_0067_01C8D3CE.711F9CC0 +Content-Type: text/plain; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +This is reply +------=_NextPart_000_0067_01C8D3CE.711F9CC0 +Content-Type: text/html; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +=EF=BB=BF + + + + + + +
    This is=20 +reply
    + +------=_NextPart_000_0067_01C8D3CE.711F9CC0-- + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c59e038abb96e6c9aa4d8af1853de23ece566c1b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c59e038abb96e6c9aa4d8af1853de23ece566c1b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +# Test case that checks that the testing infrastructure is setup correctly. +class TestingTest < ActiveSupport::TestCase + def test_working + assert true + end + + test "Rails 'test' case syntax" do + assert true + end + + test "Generating with object_daddy" do + assert_difference "IssueStatus.count" do + IssueStatus.generate! + end + end + + should "work with shoulda" do + assert true + end + + context "works with a context" do + should "work" do + assert true + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c59fb753030308d56248ba6e72defcd65036218f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c59fb753030308d56248ba6e72defcd65036218f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +

    <%= text_field_tag 'settings[sample_setting]', @settings['sample_setting'] %>

    + +

    <%= text_field_tag 'settings[foo]', @settings['foo'] %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c5caa31d1ab1ccf81fe14cfaca2195b9d5a737f4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c5caa31d1ab1ccf81fe14cfaca2195b9d5a737f4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,73 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class CustomValue < ActiveRecord::Base + belongs_to :custom_field + belongs_to :customized, :polymorphic => true + + validate :validate_custom_value + + def after_initialize + if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?)) + self.value ||= custom_field.default_value + end + end + + # Returns true if the boolean custom value is true + def true? + self.value == '1' + end + + def editable? + custom_field.editable? + end + + def visible? + custom_field.visible? + end + + def required? + custom_field.is_required? + end + + def to_s + value.to_s + end + +protected + def validate_custom_value + if value.blank? + errors.add(:value, :blank) if custom_field.is_required? and value.blank? + else + errors.add(:value, :invalid) unless custom_field.regexp.blank? or value =~ Regexp.new(custom_field.regexp) + errors.add(:value, :too_short, :count => custom_field.min_length) if custom_field.min_length > 0 and value.length < custom_field.min_length + errors.add(:value, :too_long, :count => custom_field.max_length) if custom_field.max_length > 0 and value.length > custom_field.max_length + + # Format specific validations + case custom_field.field_format + when 'int' + errors.add(:value, :not_a_number) unless value =~ /^[+-]?\d+$/ + when 'float' + begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end + when 'date' + errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end + when 'list' + errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c5d4573c549212fe6b7f9e01b91e10403d97db88.svn-base Binary file .svn/pristine/c5/c5d4573c549212fe6b7f9e01b91e10403d97db88.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c5/c5eef695c607c92e30f00026dd7c86eab2c87b3e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c5/c5eef695c607c92e30f00026dd7c86eab2c87b3e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,76 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class CustomFieldVersionFormatTest < ActiveSupport::TestCase + fixtures :custom_fields, :projects, :members, :users, :member_roles, :trackers, :issues, :versions + + def setup + @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'version') + end + + def test_possible_values_with_no_arguments + assert_equal [], @field.possible_values + assert_equal [], @field.possible_values(nil) + end + + def test_possible_values_with_project_resource + project = Project.find(1) + possible_values = @field.possible_values(project.issues.first) + assert possible_values.any? + assert_equal project.shared_versions.sort.collect(&:id).map(&:to_s), possible_values + end + + def test_possible_values_with_nil_project_resource + assert_equal [], @field.possible_values(Issue.new) + end + + def test_possible_values_options_with_no_arguments + assert_equal [], @field.possible_values_options + assert_equal [], @field.possible_values_options(nil) + end + + def test_possible_values_options_with_project_resource + project = Project.find(1) + possible_values_options = @field.possible_values_options(project.issues.first) + assert possible_values_options.any? + assert_equal project.shared_versions.sort.map {|u| [u.name, u.id.to_s]}, possible_values_options + end + + def test_possible_values_options_with_array + projects = Project.find([1, 2]) + possible_values_options = @field.possible_values_options(projects) + assert possible_values_options.any? + assert_equal (projects.first.shared_versions & projects.last.shared_versions).sort.map {|u| [u.name, u.id.to_s]}, possible_values_options + end + + def test_cast_blank_value + assert_equal nil, @field.cast_value(nil) + assert_equal nil, @field.cast_value("") + end + + def test_cast_valid_value + version = @field.cast_value("2") + assert_kind_of Version, version + assert_equal Version.find(2), version + end + + def test_cast_invalid_value + assert_equal nil, @field.cast_value("187") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c610bbe51dc33caa866a178c5e1ee0ffff498fe5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c610bbe51dc33caa866a178c5e1ee0ffff498fe5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,80 @@ +--- !ruby/object:Gem::Specification +name: rubytree +version: !ruby/object:Gem::Version + version: 0.5.2 +platform: ruby +authors: +- Anupam Sengupta +autorequire: tree +bindir: bin +cert_chain: [] + +date: 2007-12-20 00:00:00 -08:00 +default_executable: +dependencies: +- !ruby/object:Gem::Dependency + name: hoe + type: :runtime + version_requirement: + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.3.0 + version: +description: "Provides a generic tree data-structure with ability to store keyed node-elements in the tree. The implementation mixes in the Enumerable module. Website: http://rubytree.rubyforge.org/" +email: anupamsg@gmail.com +executables: [] + +extensions: [] + +extra_rdoc_files: +- README +- COPYING +- ChangeLog +- History.txt +files: +- COPYING +- ChangeLog +- History.txt +- Manifest.txt +- README +- Rakefile +- TODO +- lib/tree.rb +- lib/tree/binarytree.rb +- setup.rb +- test/test_binarytree.rb +- test/test_tree.rb +has_rdoc: true +homepage: http://rubytree.rubyforge.org/ +licenses: [] + +post_install_message: +rdoc_options: +- --main +- README +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] + +rubyforge_project: rubytree +rubygems_version: 1.3.5 +signing_key: +specification_version: 2 +summary: Ruby implementation of the Tree data structure. +test_files: +- test/test_binarytree.rb +- test/test_tree.rb diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c6573918f956a594f222ea673138e51654a28125.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c6573918f956a594f222ea673138e51654a28125.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +$:.unshift "#{File.dirname(__FILE__)}/lib" +require 'active_record/acts/list' +ActiveRecord::Base.class_eval { include ActiveRecord::Acts::List } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c65bfd6780a9f0fa4b112d559eaf34468d9f02bc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c65bfd6780a9f0fa4b112d559eaf34468d9f02bc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1011 @@ +en-GB: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d/%m/%Y" + short: "%d %b" + long: "%d %B, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%d/%m/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: " " + precision: 3 + + currency: + format: + format: "%u%n" + unit: "£" + + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "kB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "is not included in the list" + exclusion: "is reserved" + invalid: "is invalid" + confirmation: "doesn't match confirmation" + accepted: "must be accepted" + empty: "can't be empty" + blank: "can't be blank" + too_long: "is too long (maximum is %{count} characters)" + too_short: "is too short (minimum is %{count} characters)" + wrong_length: "is the wrong length (should be %{count} characters)" + taken: "has already been taken" + not_a_number: "is not a number" + not_a_date: "is not a valid date" + greater_than: "must be greater than %{count}" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "must be greater than start date" + not_same_project: "doesn't belong to the same project" + circular_dependency: "This relation would create a circular dependency" + cant_link_an_issue_with_a_descendant: "An issue cannot be linked to one of its subtasks" + + actionview_instancetag_blank_option: Please select + + general_text_No: 'No' + general_text_Yes: 'Yes' + general_text_no: 'no' + general_text_yes: 'yes' + general_lang_name: 'English (British)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Account was successfully updated. + notice_account_invalid_creditentials: Invalid user or password + notice_account_password_updated: Password was successfully updated. + notice_account_wrong_password: Wrong password + notice_account_register_done: Account was successfully created. To activate your account, click on the link that was emailed to you. + notice_account_unknown_email: Unknown user. + notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. + notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. + notice_account_activated: Your account has been activated. You can now log in. + notice_successful_create: Successful creation. + notice_successful_update: Successful update. + notice_successful_delete: Successful deletion. + notice_successful_connection: Successful connection. + notice_file_not_found: The page you were trying to access doesn't exist or has been removed. + notice_locking_conflict: Data has been updated by another user. + notice_not_authorized: You are not authorised to access this page. + notice_not_authorized_archived_project: The project you're trying to access has been archived. + notice_email_sent: "An email was sent to %{value}" + notice_email_error: "An error occurred while sending mail (%{value})" + notice_feeds_access_key_reseted: Your RSS access key was reset. + notice_api_access_key_reseted: Your API access key was reset. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." + notice_account_pending: "Your account was created and is now pending administrator approval." + notice_default_data_loaded: Default configuration successfully loaded. + notice_unable_delete_version: Unable to delete version. + notice_unable_delete_time_entry: Unable to delete time log entry. + notice_issue_done_ratios_updated: Issue done ratios updated. + notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" + + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + error_scm_annotate: "The entry does not exist or cannot be annotated." + error_scm_annotate_big_text_file: "The entry cannot be annotated, as it exceeds the maximum text file size." + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_delete_custom_field: Unable to delete custom field + error_can_not_delete_tracker: "This tracker contains issues and cannot be deleted." + error_can_not_remove_role: "This role is in use and cannot be deleted." + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version cannot be reopened' + error_can_not_archive_project: This project cannot be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + error_unable_delete_issue_status: 'Unable to delete issue status' + error_unable_to_connect: "Unable to connect (%{value})" + warning_attachments_not_saved: "%{count} file(s) could not be saved." + + mail_subject_lost_password: "Your %{value} password" + mail_body_lost_password: 'To change your password, click on the following link:' + mail_subject_register: "Your %{value} account activation" + mail_body_register: 'To activate your account, click on the following link:' + mail_body_account_information_external: "You can use your %{value} account to log in." + mail_body_account_information: Your account information + mail_subject_account_activation_request: "%{value} account activation request" + mail_body_account_activation_request: "A new user (%{value}) has registered. The account is pending your approval:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + gui_validation_error: 1 error + gui_validation_error_plural: "%{count} errors" + + field_name: Name + field_description: Description + field_summary: Summary + field_is_required: Required + field_firstname: First name + field_lastname: Last name + field_mail: Email + field_filename: File + field_filesize: Size + field_downloads: Downloads + field_author: Author + field_created_on: Created + field_updated_on: Updated + field_field_format: Format + field_is_for_all: For all projects + field_possible_values: Possible values + field_regexp: Regular expression + field_min_length: Minimum length + field_max_length: Maximum length + field_value: Value + field_category: Category + field_title: Title + field_project: Project + field_issue: Issue + field_status: Status + field_notes: Notes + field_is_closed: Issue closed + field_is_default: Default value + field_tracker: Tracker + field_subject: Subject + field_due_date: Due date + field_assigned_to: Assignee + field_priority: Priority + field_fixed_version: Target version + field_user: User + field_principal: Principal + field_role: Role + field_homepage: Homepage + field_is_public: Public + field_parent: Subproject of + field_is_in_roadmap: Issues displayed in roadmap + field_login: Login + field_mail_notification: Email notifications + field_admin: Administrator + field_last_login_on: Last connection + field_language: Language + field_effective_date: Date + field_password: Password + field_new_password: New password + field_password_confirmation: Confirmation + field_version: Version + field_type: Type + field_host: Host + field_port: Port + field_account: Account + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: On-the-fly user creation + field_start_date: Start date + field_done_ratio: "% Done" + field_auth_source: Authentication mode + field_hide_mail: Hide my email address + field_comments: Comment + field_url: URL + field_start_page: Start page + field_subproject: Subproject + field_hours: Hours + field_activity: Activity + field_spent_on: Date + field_identifier: Identifier + field_is_filter: Used as a filter + field_issue_to: Related issue + field_delay: Delay + field_assignable: Issues can be assigned to this role + field_redirect_existing_links: Redirect existing links + field_estimated_hours: Estimated time + field_column_names: Columns + field_time_entries: Log time + field_time_zone: Time zone + field_searchable: Searchable + field_default_value: Default value + field_comments_sorting: Display comments + field_parent_title: Parent page + field_editable: Editable + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Content + field_group_by: Group results by + field_sharing: Sharing + field_parent_issue: Parent task + field_member_of_group: "Assignee's group" + field_assigned_to_role: "Assignee's role" + field_text: Text field + field_visible: Visible + field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" + + setting_app_title: Application title + setting_app_subtitle: Application subtitle + setting_welcome_text: Welcome text + setting_default_language: Default language + setting_login_required: Authentication required + setting_self_registration: Self-registration + setting_attachment_max_size: Attachment max. size + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Plain text mail (no HTML) + setting_host_name: Host name and path + setting_text_formatting: Text formatting + setting_wiki_compression: Wiki history compression + setting_feeds_limit: Feed content limit + setting_default_projects_public: New projects are public by default + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Referencing keywords + setting_commit_fix_keywords: Fixing keywords + setting_autologin: Autologin + setting_date_format: Date format + setting_time_format: Time format + setting_cross_project_issue_relations: Allow cross-project issue relations + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_emails_header: Emails header + setting_emails_footer: Emails footer + setting_protocol: Protocol + setting_per_page_options: Objects per page options + setting_user_format: Users display format + setting_activity_days_default: Days displayed on project activity + setting_display_subprojects_issues: Display subprojects issues on main projects by default + setting_enabled_scm: Enabled SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + setting_sequential_project_identifiers: Generate sequential project identifiers + setting_gravatar_enabled: Use Gravatar user icons + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Max number of diff lines displayed + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + setting_default_notification_option: Default notification option + setting_commit_logtime_enabled: Enable time logging + setting_commit_logtime_activity_id: Activity for logged time + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + setting_issue_group_assignment: Allow issue assignment to groups + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + + permission_add_project: Create project + permission_add_subprojects: Create subprojects + permission_edit_project: Edit project + permission_select_project_modules: Select project modules + permission_manage_members: Manage members + permission_manage_project_activities: Manage project activities + permission_manage_versions: Manage versions + permission_manage_categories: Manage issue categories + permission_view_issues: View Issues + permission_add_issues: Add issues + permission_edit_issues: Edit issues + permission_manage_issue_relations: Manage issue relations + permission_add_issue_notes: Add notes + permission_edit_issue_notes: Edit notes + permission_edit_own_issue_notes: Edit own notes + permission_move_issues: Move issues + permission_delete_issues: Delete issues + permission_manage_public_queries: Manage public queries + permission_save_queries: Save queries + permission_view_gantt: View gantt chart + permission_view_calendar: View calendar + permission_view_issue_watchers: View watchers list + permission_add_issue_watchers: Add watchers + permission_delete_issue_watchers: Delete watchers + permission_log_time: Log spent time + permission_view_time_entries: View spent time + permission_edit_time_entries: Edit time logs + permission_edit_own_time_entries: Edit own time logs + permission_manage_news: Manage news + permission_comment_news: Comment news + permission_manage_documents: Manage documents + permission_view_documents: View documents + permission_manage_files: Manage files + permission_view_files: View files + permission_manage_wiki: Manage wiki + permission_rename_wiki_pages: Rename wiki pages + permission_delete_wiki_pages: Delete wiki pages + permission_view_wiki_pages: View wiki + permission_view_wiki_edits: View wiki history + permission_edit_wiki_pages: Edit wiki pages + permission_delete_wiki_pages_attachments: Delete attachments + permission_protect_wiki_pages: Protect wiki pages + permission_manage_repository: Manage repository + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Commit access + permission_manage_boards: Manage forums + permission_view_messages: View messages + permission_add_messages: Post messages + permission_edit_messages: Edit messages + permission_edit_own_messages: Edit own messages + permission_delete_messages: Delete messages + permission_delete_own_messages: Delete own messages + permission_export_wiki_pages: Export wiki pages + permission_manage_subtasks: Manage subtasks + + project_module_issue_tracking: Issue tracking + project_module_time_tracking: Time tracking + project_module_news: News + project_module_documents: Documents + project_module_files: Files + project_module_wiki: Wiki + project_module_repository: Repository + project_module_boards: Forums + project_module_calendar: Calendar + project_module_gantt: Gantt + + label_user: User + label_user_plural: Users + label_user_new: New user + label_user_anonymous: Anonymous + label_project: Project + label_project_new: New project + label_project_plural: Projects + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: All Projects + label_project_latest: Latest projects + label_issue: Issue + label_issue_new: New issue + label_issue_plural: Issues + label_issue_view_all: View all issues + label_issues_by: "Issues by %{value}" + label_issue_added: Issue added + label_issue_updated: Issue updated + label_document: Document + label_document_new: New document + label_document_plural: Documents + label_document_added: Document added + label_role: Role + label_role_plural: Roles + label_role_new: New role + label_role_and_permissions: Roles and permissions + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_member: Member + label_member_new: New member + label_member_plural: Members + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: New tracker + label_workflow: Workflow + label_issue_status: Issue status + label_issue_status_plural: Issue statuses + label_issue_status_new: New status + label_issue_category: Issue category + label_issue_category_plural: Issue categories + label_issue_category_new: New category + label_custom_field: Custom field + label_custom_field_plural: Custom fields + label_custom_field_new: New custom field + label_enumerations: Enumerations + label_enumeration_new: New value + label_information: Information + label_information_plural: Information + label_please_login: Please log in + label_register: Register + label_login_with_open_id_option: or login with OpenID + label_password_lost: Lost password + label_home: Home + label_my_page: My page + label_my_account: My account + label_my_projects: My projects + label_my_page_block: My page block + label_administration: Administration + label_login: Sign in + label_logout: Sign out + label_help: Help + label_reported_issues: Reported issues + label_assigned_to_me_issues: Issues assigned to me + label_last_login: Last connection + label_registered_on: Registered on + label_activity: Activity + label_overall_activity: Overall activity + label_user_activity: "%{value}'s activity" + label_new: New + label_logged_as: Logged in as + label_environment: Environment + label_authentication: Authentication + label_auth_source: Authentication mode + label_auth_source_new: New authentication mode + label_auth_source_plural: Authentication modes + label_subproject_plural: Subprojects + label_subproject_new: New subproject + label_and_its_subprojects: "%{value} and its subprojects" + label_min_max_length: Min - Max length + label_list: List + label_date: Date + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Attribute + label_attribute_plural: Attributes + label_download: "%{count} Download" + label_download_plural: "%{count} Downloads" + label_no_data: No data to display + label_change_status: Change status + label_history: History + label_attachment: File + label_attachment_new: New file + label_attachment_delete: Delete file + label_attachment_plural: Files + label_file_added: File added + label_report: Report + label_report_plural: Reports + label_news: News + label_news_new: Add news + label_news_plural: News + label_news_latest: Latest news + label_news_view_all: View all news + label_news_added: News added + label_news_comment_added: Comment added to a news + label_settings: Settings + label_overview: Overview + label_version: Version + label_version_new: New version + label_version_plural: Versions + label_close_versions: Close completed versions + label_confirmation: Confirmation + label_export_to: 'Also available in:' + label_read: Read... + label_public_projects: Public projects + label_open_issues: open + label_open_issues_plural: open + label_closed_issues: closed + label_closed_issues_plural: closed + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Total + label_permissions: Permissions + label_current_status: Current status + label_new_statuses_allowed: New statuses allowed + label_all: all + label_none: none + label_nobody: nobody + label_next: Next + label_previous: Previous + label_used_by: Used by + label_details: Details + label_add_note: Add a note + label_per_page: Per page + label_calendar: Calendar + label_months_from: months from + label_gantt: Gantt + label_internal: Internal + label_last_changes: "last %{count} changes" + label_change_view_all: View all changes + label_personalize_page: Personalise this page + label_comment: Comment + label_comment_plural: Comments + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Add a comment + label_comment_added: Comment added + label_comment_delete: Delete comments + label_query: Custom query + label_query_plural: Custom queries + label_query_new: New query + label_my_queries: My custom queries + label_filter_add: Add filter + label_filter_plural: Filters + label_equals: is + label_not_equals: is not + label_in_less_than: in less than + label_in_more_than: in more than + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: in + label_today: today + label_all_time: all time + label_yesterday: yesterday + label_this_week: this week + label_last_week: last week + label_last_n_days: "last %{count} days" + label_this_month: this month + label_last_month: last month + label_this_year: this year + label_date_range: Date range + label_less_than_ago: less than days ago + label_more_than_ago: more than days ago + label_ago: days ago + label_contains: contains + label_not_contains: doesn't contain + label_day_plural: days + label_repository: Repository + label_repository_plural: Repositories + label_browse: Browse + label_modification: "%{count} change" + label_modification_plural: "%{count} changes" + label_branch: Branch + label_tag: Tag + label_revision: Revision + label_revision_plural: Revisions + label_revision_id: "Revision %{value}" + label_associated_revisions: Associated revisions + label_added: added + label_modified: modified + label_copied: copied + label_renamed: renamed + label_deleted: deleted + label_latest_revision: Latest revision + label_latest_revision_plural: Latest revisions + label_view_revisions: View revisions + label_view_all_revisions: View all revisions + label_max_size: Maximum size + label_sort_highest: Move to top + label_sort_higher: Move up + label_sort_lower: Move down + label_sort_lowest: Move to bottom + label_roadmap: Roadmap + label_roadmap_due_in: "Due in %{value}" + label_roadmap_overdue: "%{value} late" + label_roadmap_no_issues: No issues for this version + label_search: Search + label_result_plural: Results + label_all_words: All words + label_wiki: Wiki + label_wiki_edit: Wiki edit + label_wiki_edit_plural: Wiki edits + label_wiki_page: Wiki page + label_wiki_page_plural: Wiki pages + label_index_by_title: Index by title + label_index_by_date: Index by date + label_current_version: Current version + label_preview: Preview + label_feed_plural: Feeds + label_changes_details: Details of all changes + label_issue_tracking: Issue tracking + label_spent_time: Spent time + label_overall_spent_time: Overall spent time + label_f_hour: "%{value} hour" + label_f_hour_plural: "%{value} hours" + label_time_tracking: Time tracking + label_change_plural: Changes + label_statistics: Statistics + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_view_diff: View differences + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Options + label_copy_workflow_from: Copy workflow from + label_permissions_report: Permissions report + label_watched_issues: Watched issues + label_related_issues: Related issues + label_applied_status: Applied status + label_loading: Loading... + label_relation_new: New relation + label_relation_delete: Delete relation + label_relates_to: related to + label_duplicates: duplicates + label_duplicated_by: duplicated by + label_blocks: blocks + label_blocked_by: blocked by + label_precedes: precedes + label_follows: follows + label_end_to_start: end to start + label_end_to_end: end to end + label_start_to_start: start to start + label_start_to_end: start to end + label_stay_logged_in: Stay logged in + label_disabled: disabled + label_show_completed_versions: Show completed versions + label_me: me + label_board: Forum + label_board_new: New forum + label_board_plural: Forums + label_board_locked: Locked + label_board_sticky: Sticky + label_topic_plural: Topics + label_message_plural: Messages + label_message_last: Last message + label_message_new: New message + label_message_posted: Message added + label_reply_plural: Replies + label_send_information: Send account information to the user + label_year: Year + label_month: Month + label_week: Week + label_date_from: From + label_date_to: To + label_language_based: Based on user's language + label_sort_by: "Sort by %{value}" + label_send_test_email: Send a test email + label_feeds_access_key: RSS access key + label_missing_feeds_access_key: Missing a RSS access key + label_feeds_access_key_created_on: "RSS access key created %{value} ago" + label_module_plural: Modules + label_added_time_by: "Added by %{author} %{age} ago" + label_updated_time_by: "Updated by %{author} %{age} ago" + label_updated_time: "Updated %{value} ago" + label_jump_to_a_project: Jump to a project... + label_file_plural: Files + label_changeset_plural: Changesets + label_default_columns: Default columns + label_no_change_option: (No change) + label_bulk_edit_selected_issues: Bulk edit selected issues + label_theme: Theme + label_default: Default + label_search_titles_only: Search titles only + label_user_mail_option_all: "For any event on all my projects" + label_user_mail_option_selected: "For any event on the selected projects only..." + label_user_mail_option_none: "No events" + label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" + label_user_mail_option_only_assigned: "Only for things I am assigned to" + label_user_mail_option_only_owner: "Only for things I am the owner of" + label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself" + label_registration_activation_by_email: account activation by email + label_registration_manual_activation: manual account activation + label_registration_automatic_activation: automatic account activation + label_display_per_page: "Per page: %{value}" + label_age: Age + label_change_properties: Change properties + label_general: General + label_more: More + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP authentication + label_downloads_abbr: D/L + label_optional_description: Optional description + label_add_another_file: Add another file + label_preferences: Preferences + label_chronological_order: In chronological order + label_reverse_chronological_order: In reverse chronological order + label_planning: Planning + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + label_issue_watchers: Watchers + label_example: Example + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Groups + label_group_new: New group + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + label_profile: Profile + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + + button_login: Login + button_submit: Submit + button_save: Save + button_check_all: Check all + button_uncheck_all: Uncheck all + button_collapse_all: Collapse all + button_expand_all: Expand all + button_delete: Delete + button_create: Create + button_create_and_continue: Create and continue + button_test: Test + button_edit: Edit + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + button_add: Add + button_change: Change + button_apply: Apply + button_clear: Clear + button_lock: Lock + button_unlock: Unlock + button_download: Download + button_list: List + button_view: View + button_move: Move + button_move_and_follow: Move and follow + button_back: Back + button_cancel: Cancel + button_activate: Activate + button_sort: Sort + button_log_time: Log time + button_rollback: Rollback to this version + button_watch: Watch + button_unwatch: Unwatch + button_reply: Reply + button_archive: Archive + button_unarchive: Unarchive + button_reset: Reset + button_rename: Rename + button_change_password: Change password + button_copy: Copy + button_copy_and_follow: Copy and follow + button_annotate: Annotate + button_update: Update + button_configure: Configure + button_quote: Quote + button_duplicate: Duplicate + button_show: Show + + status_active: active + status_registered: registered + status_locked: locked + + version_status_open: open + version_status_locked: locked + version_status_closed: closed + + field_active: Active + + text_select_mail_notifications: Select actions for which email notifications should be sent. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 means no restriction + text_project_destroy_confirmation: Are you sure you want to delete this project and related data? + text_subprojects_destroy_warning: "Its subproject(s): %{value} will be also deleted." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Are you sure? + text_are_you_sure_with_children: "Delete issue and all child issues?" + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_changed_no_detail: "%{label} updated" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + text_journal_added: "%{label} %{value} added" + text_tip_issue_begin_day: task beginning this day + text_tip_issue_end_day: task ending this day + text_tip_issue_begin_end_day: task beginning and ending this day + text_project_identifier_info: 'Only lower case letters (a-z), numbers and dashes are allowed.
    Once saved, the identifier cannot be changed.' + text_caracters_maximum: "%{count} characters maximum." + text_caracters_minimum: "Must be at least %{count} characters long." + text_length_between: "Length between %{min} and %{max} characters." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Unallowed characters + text_comma_separated: Multiple values allowed (comma separated). + text_line_separated: Multiple values allowed (one line for each value). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content? + text_issue_category_destroy_question: "Some issues (%{count}) are assigned to this category. What do you want to do?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Reassign issues to this category + text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_time_logged_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s)?' + text_select_project_modules: 'Select modules to enable for this project:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Attachments directory writable + text_plugin_assets_writable: Plugin assets directory writable + text_rmagick_available: RMagick available (optional) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Assign reported hours to the project + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} wrote:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page." + + default_role_manager: Manager + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Bug + default_tracker_feature: Feature + default_tracker_support: Support + default_issue_status_new: New + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Resolved + default_issue_status_feedback: Feedback + default_issue_status_closed: Closed + default_issue_status_rejected: Rejected + default_doc_category_user: User documentation + default_doc_category_tech: Technical documentation + default_priority_low: Low + default_priority_normal: Normal + default_priority_high: High + default_priority_urgent: Urgent + default_priority_immediate: Immediate + default_activity_design: Design + default_activity_development: Development + + enumeration_issue_priorities: Issue priorities + enumeration_doc_categories: Document categories + enumeration_activities: Activities (time tracking) + enumeration_system_activity: System Activity + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c66377d22fe47ecd09af051b19c6f64432a147d3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c66377d22fe47ecd09af051b19c6f64432a147d3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1011 @@ +# Redmine catalan translation: +# by Joan Duran + +ca: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%e de %b" + long: "%a, %e de %b de %Y" + + day_names: [Diumenge, Dilluns, Dimarts, Dimecres, Dijous, Divendres, Dissabte] + abbr_day_names: [dg, dl, dt, dc, dj, dv, ds] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Gener, Febrer, Març, Abril, Maig, Juny, Juliol, Agost, Setembre, Octubre, Novembre, Desembre] + abbr_month_names: [~, Gen, Feb, Mar, Abr, Mai, Jun, Jul, Ago, Set, Oct, Nov, Des] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%d-%m-%Y %H:%M" + time: "%H:%M" + short: "%e de %b, %H:%M" + long: "%a, %e de %b de %Y, %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "mig minut" + less_than_x_seconds: + one: "menys d'un segon" + other: "menys de %{count} segons" + x_seconds: + one: "1 segons" + other: "%{count} segons" + less_than_x_minutes: + one: "menys d'un minut" + other: "menys de %{count} minuts" + x_minutes: + one: "1 minut" + other: "%{count} minuts" + about_x_hours: + one: "aproximadament 1 hora" + other: "aproximadament %{count} hores" + x_days: + one: "1 dia" + other: "%{count} dies" + about_x_months: + one: "aproximadament 1 mes" + other: "aproximadament %{count} mesos" + x_months: + one: "1 mes" + other: "%{count} mesos" + about_x_years: + one: "aproximadament 1 any" + other: "aproximadament %{count} anys" + over_x_years: + one: "més d'un any" + other: "més de %{count} anys" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + # Default format for numbers + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "no està inclòs a la llista" + exclusion: "està reservat" + invalid: "no és vàlid" + confirmation: "la confirmació no coincideix" + accepted: "s'ha d'acceptar" + empty: "no pot estar buit" + blank: "no pot estar en blanc" + too_long: "és massa llarg" + too_short: "és massa curt" + wrong_length: "la longitud és incorrecta" + taken: "ja s'està utilitzant" + not_a_number: "no és un número" + not_a_date: "no és una data vàlida" + greater_than: "ha de ser més gran que %{count}" + greater_than_or_equal_to: "ha de ser més gran o igual a %{count}" + equal_to: "ha de ser igual a %{count}" + less_than: "ha de ser menys que %{count}" + less_than_or_equal_to: "ha de ser menys o igual a %{count}" + odd: "ha de ser senar" + even: "ha de ser parell" + greater_than_start_date: "ha de ser superior que la data inicial" + not_same_project: "no pertany al mateix projecte" + circular_dependency: "Aquesta relació crearia una dependència circular" + cant_link_an_issue_with_a_descendant: "Un assumpte no es pot enllaçar a una de les seves subtasques" + + actionview_instancetag_blank_option: Seleccioneu + + general_text_No: 'No' + general_text_Yes: 'Si' + general_text_no: 'no' + general_text_yes: 'si' + general_lang_name: 'Català' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: "El compte s'ha actualitzat correctament." + notice_account_invalid_creditentials: Usuari o contrasenya invàlid + notice_account_password_updated: "La contrasenya s'ha modificat correctament." + notice_account_wrong_password: Contrasenya incorrecta + notice_account_register_done: "El compte s'ha creat correctament. Per a activar el compte, feu clic en l'enllaç que us han enviat per correu electrònic." + notice_account_unknown_email: Usuari desconegut. + notice_can_t_change_password: "Aquest compte utilitza una font d'autenticació externa. No és possible canviar la contrasenya." + notice_account_lost_email_sent: "S'ha enviat un correu electrònic amb instruccions per a seleccionar una contrasenya nova." + notice_account_activated: "El compte s'ha activat. Ara podeu entrar." + notice_successful_create: "S'ha creat correctament." + notice_successful_update: "S'ha modificat correctament." + notice_successful_delete: "S'ha suprimit correctament." + notice_successful_connection: "S'ha connectat correctament." + notice_file_not_found: "La pàgina a la que intenteu accedir no existeix o s'ha suprimit." + notice_locking_conflict: Un altre usuari ha actualitzat les dades. + notice_not_authorized: No teniu permís per a accedir a aquesta pàgina. + notice_email_sent: "S'ha enviat un correu electrònic a %{value}" + notice_email_error: "S'ha produït un error en enviar el correu (%{value})" + notice_feeds_access_key_reseted: "S'ha reiniciat la clau d'accés del RSS." + notice_api_access_key_reseted: "S'ha reiniciat la clau d'accés a l'API." + notice_failed_to_save_issues: "No s'han pogut desar %{count} assumptes de %{total} seleccionats: %{ids}." + notice_failed_to_save_members: "No s'han pogut desar els membres: %{errors}." + notice_no_issue_selected: "No s'ha seleccionat cap assumpte. Activeu els assumptes que voleu editar." + notice_account_pending: "S'ha creat el compte i ara està pendent de l'aprovació de l'administrador." + notice_default_data_loaded: "S'ha carregat correctament la configuració predeterminada." + notice_unable_delete_version: "No s'ha pogut suprimir la versió." + notice_unable_delete_time_entry: "No s'ha pogut suprimir l'entrada del registre de temps." + notice_issue_done_ratios_updated: "S'ha actualitzat el tant per cent dels assumptes." + + error_can_t_load_default_data: "No s'ha pogut carregar la configuració predeterminada: %{value} " + error_scm_not_found: "No s'ha trobat l'entrada o la revisió en el dipòsit." + error_scm_command_failed: "S'ha produït un error en intentar accedir al dipòsit: %{value}" + error_scm_annotate: "L'entrada no existeix o no s'ha pogut anotar." + error_issue_not_found_in_project: "No s'ha trobat l'assumpte o no pertany a aquest projecte" + error_no_tracker_in_project: "Aquest projecte no té seguidor associat. Comproveu els paràmetres del projecte." + error_no_default_issue_status: "No s'ha definit cap estat d'assumpte predeterminat. Comproveu la configuració (aneu a «Administració -> Estats de l'assumpte»)." + error_can_not_delete_custom_field: "No s'ha pogut suprimir el camp personalitat" + error_can_not_delete_tracker: "Aquest seguidor conté assumptes i no es pot suprimir." + error_can_not_remove_role: "Aquest rol s'està utilitzant i no es pot suprimir." + error_can_not_reopen_issue_on_closed_version: "Un assumpte assignat a una versió tancada no es pot tornar a obrir" + error_can_not_archive_project: "Aquest projecte no es pot arxivar" + error_issue_done_ratios_not_updated: "No s'ha actualitza el tant per cent dels assumptes." + error_workflow_copy_source: "Seleccioneu un seguidor o rol font" + error_workflow_copy_target: "Seleccioneu seguidors i rols objectiu" + error_unable_delete_issue_status: "No s'ha pogut suprimir l'estat de l'assumpte" + error_unable_to_connect: "No s'ha pogut connectar (%{value})" + warning_attachments_not_saved: "No s'han pogut desar %{count} fitxers." + + mail_subject_lost_password: "Contrasenya de %{value}" + mail_body_lost_password: "Per a canviar la contrasenya, feu clic en l'enllaç següent:" + mail_subject_register: "Activació del compte de %{value}" + mail_body_register: "Per a activar el compte, feu clic en l'enllaç següent:" + mail_body_account_information_external: "Podeu utilitzar el compte «%{value}» per a entrar." + mail_body_account_information: Informació del compte + mail_subject_account_activation_request: "Sol·licitud d'activació del compte de %{value}" + mail_body_account_activation_request: "S'ha registrat un usuari nou (%{value}). El seu compte està pendent d'aprovació:" + mail_subject_reminder: "%{count} assumptes venceran els següents %{days} dies" + mail_body_reminder: "%{count} assumptes que teniu assignades venceran els següents %{days} dies:" + mail_subject_wiki_content_added: "S'ha afegit la pàgina wiki «%{id}»" + mail_body_wiki_content_added: "En %{author} ha afegit la pàgina wiki «%{id}»." + mail_subject_wiki_content_updated: "S'ha actualitzat la pàgina wiki «%{id}»" + mail_body_wiki_content_updated: "En %{author} ha actualitzat la pàgina wiki «%{id}»." + + gui_validation_error: 1 error + gui_validation_error_plural: "%{count} errors" + + field_name: Nom + field_description: Descripció + field_summary: Resum + field_is_required: Necessari + field_firstname: Nom + field_lastname: Cognom + field_mail: Correu electrònic + field_filename: Fitxer + field_filesize: Mida + field_downloads: Baixades + field_author: Autor + field_created_on: Creat + field_updated_on: Actualitzat + field_field_format: Format + field_is_for_all: Per a tots els projectes + field_possible_values: Valores possibles + field_regexp: Expressió regular + field_min_length: Longitud mínima + field_max_length: Longitud màxima + field_value: Valor + field_category: Categoria + field_title: Títol + field_project: Projecte + field_issue: Assumpte + field_status: Estat + field_notes: Notes + field_is_closed: Assumpte tancat + field_is_default: Estat predeterminat + field_tracker: Seguidor + field_subject: Tema + field_due_date: Data de venciment + field_assigned_to: Assignat a + field_priority: Prioritat + field_fixed_version: Versió objectiu + field_user: Usuari + field_principal: Principal + field_role: Rol + field_homepage: Pàgina web + field_is_public: Públic + field_parent: Subprojecte de + field_is_in_roadmap: Assumptes mostrats en la planificació + field_login: Entrada + field_mail_notification: Notificacions per correu electrònic + field_admin: Administrador + field_last_login_on: Última connexió + field_language: Idioma + field_effective_date: Data + field_password: Contrasenya + field_new_password: Contrasenya nova + field_password_confirmation: Confirmació + field_version: Versió + field_type: Tipus + field_host: Ordinador + field_port: Port + field_account: Compte + field_base_dn: Base DN + field_attr_login: "Atribut d'entrada" + field_attr_firstname: Atribut del nom + field_attr_lastname: Atribut del cognom + field_attr_mail: Atribut del correu electrònic + field_onthefly: "Creació de l'usuari «al vol»" + field_start_date: Inici + field_done_ratio: "% realitzat" + field_auth_source: "Mode d'autenticació" + field_hide_mail: "Oculta l'adreça de correu electrònic" + field_comments: Comentari + field_url: URL + field_start_page: Pàgina inicial + field_subproject: Subprojecte + field_hours: Hores + field_activity: Activitat + field_spent_on: Data + field_identifier: Identificador + field_is_filter: "S'ha utilitzat com a filtre" + field_issue_to: Assumpte relacionat + field_delay: Retard + field_assignable: Es poden assignar assumptes a aquest rol + field_redirect_existing_links: Redirigeix els enllaços existents + field_estimated_hours: Temps previst + field_column_names: Columnes + field_time_entries: "Registre de temps" + field_time_zone: Zona horària + field_searchable: Es pot cercar + field_default_value: Valor predeterminat + field_comments_sorting: Mostra els comentaris + field_parent_title: Pàgina pare + field_editable: Es pot editar + field_watcher: Vigilància + field_identity_url: URL OpenID + field_content: Contingut + field_group_by: "Agrupa els resultats per" + field_sharing: Compartició + field_parent_issue: "Tasca pare" + + setting_app_title: "Títol de l'aplicació" + setting_app_subtitle: "Subtítol de l'aplicació" + setting_welcome_text: Text de benvinguda + setting_default_language: Idioma predeterminat + setting_login_required: Es necessita autenticació + setting_self_registration: Registre automàtic + setting_attachment_max_size: Mida màxima dels adjunts + setting_issues_export_limit: "Límit d'exportació d'assumptes" + setting_mail_from: "Adreça de correu electrònic d'emissió" + setting_bcc_recipients: Vincula els destinataris de les còpies amb carbó (bcc) + setting_plain_text_mail: només text pla (no HTML) + setting_host_name: "Nom de l'ordinador" + setting_text_formatting: Format del text + setting_wiki_compression: "Comprimeix l'historial del wiki" + setting_feeds_limit: Límit de contingut del canal + setting_default_projects_public: Els projectes nous són públics per defecte + setting_autofetch_changesets: Omple automàticament les publicacions + setting_sys_api_enabled: Habilita el WS per a la gestió del dipòsit + setting_commit_ref_keywords: Paraules claus per a la referència + setting_commit_fix_keywords: Paraules claus per a la correcció + setting_autologin: Entrada automàtica + setting_date_format: Format de la data + setting_time_format: Format de hora + setting_cross_project_issue_relations: "Permet les relacions d'assumptes entre projectes" + setting_issue_list_default_columns: "Columnes mostrades per defecte en la llista d'assumptes" + setting_emails_footer: Peu dels correus electrònics + setting_protocol: Protocol + setting_per_page_options: Opcions dels objectes per pàgina + setting_user_format: "Format de com mostrar l'usuari" + setting_activity_days_default: "Dies a mostrar l'activitat del projecte" + setting_display_subprojects_issues: "Mostra els assumptes d'un subprojecte en el projecte pare per defecte" + setting_enabled_scm: "Habilita l'SCM" + setting_mail_handler_body_delimiters: "Trunca els correus electrònics després d'una d'aquestes línies" + setting_mail_handler_api_enabled: "Habilita el WS per correus electrònics d'entrada" + setting_mail_handler_api_key: Clau API + setting_sequential_project_identifiers: Genera identificadors de projecte seqüencials + setting_gravatar_enabled: "Utilitza les icones d'usuari Gravatar" + setting_gravatar_default: "Imatge Gravatar predeterminada" + setting_diff_max_lines_displayed: Número màxim de línies amb diferències mostrades + setting_file_max_size_displayed: Mida màxima dels fitxers de text mostrats en línia + setting_repository_log_display_limit: Número màxim de revisions que es mostren al registre de fitxers + setting_openid: "Permet entrar i registrar-se amb l'OpenID" + setting_password_min_length: "Longitud mínima de la contrasenya" + setting_new_project_user_role_id: "Aquest rol es dóna a un usuari no administrador per a crear projectes" + setting_default_projects_modules: "Mòduls activats per defecte en els projectes nous" + setting_issue_done_ratio: "Calcula tant per cent realitzat de l'assumpte amb" + setting_issue_done_ratio_issue_status: "Utilitza l'estat de l'assumpte" + setting_issue_done_ratio_issue_field: "Utilitza el camp de l'assumpte" + setting_start_of_week: "Inicia les setmanes en" + setting_rest_api_enabled: "Habilita el servei web REST" + setting_cache_formatted_text: Cache formatted text + + permission_add_project: "Crea projectes" + permission_add_subprojects: "Crea subprojectes" + permission_edit_project: Edita el projecte + permission_select_project_modules: Selecciona els mòduls del projecte + permission_manage_members: Gestiona els membres + permission_manage_project_activities: "Gestiona les activitats del projecte" + permission_manage_versions: Gestiona les versions + permission_manage_categories: Gestiona les categories dels assumptes + permission_view_issues: "Visualitza els assumptes" + permission_add_issues: Afegeix assumptes + permission_edit_issues: Edita els assumptes + permission_manage_issue_relations: Gestiona les relacions dels assumptes + permission_add_issue_notes: Afegeix notes + permission_edit_issue_notes: Edita les notes + permission_edit_own_issue_notes: Edita les notes pròpies + permission_move_issues: Mou els assumptes + permission_delete_issues: Suprimeix els assumptes + permission_manage_public_queries: Gestiona les consultes públiques + permission_save_queries: Desa les consultes + permission_view_gantt: Visualitza la gràfica de Gantt + permission_view_calendar: Visualitza el calendari + permission_view_issue_watchers: Visualitza la llista de vigilàncies + permission_add_issue_watchers: Afegeix vigilàncies + permission_delete_issue_watchers: Suprimeix els vigilants + permission_log_time: Registra el temps invertit + permission_view_time_entries: Visualitza el temps invertit + permission_edit_time_entries: Edita els registres de temps + permission_edit_own_time_entries: Edita els registres de temps propis + permission_manage_news: Gestiona les noticies + permission_comment_news: Comenta les noticies + permission_manage_documents: Gestiona els documents + permission_view_documents: Visualitza els documents + permission_manage_files: Gestiona els fitxers + permission_view_files: Visualitza els fitxers + permission_manage_wiki: Gestiona el wiki + permission_rename_wiki_pages: Canvia el nom de les pàgines wiki + permission_delete_wiki_pages: Suprimeix les pàgines wiki + permission_view_wiki_pages: Visualitza el wiki + permission_view_wiki_edits: "Visualitza l'historial del wiki" + permission_edit_wiki_pages: Edita les pàgines wiki + permission_delete_wiki_pages_attachments: Suprimeix adjunts + permission_protect_wiki_pages: Protegeix les pàgines wiki + permission_manage_repository: Gestiona el dipòsit + permission_browse_repository: Navega pel dipòsit + permission_view_changesets: Visualitza els canvis realitzats + permission_commit_access: Accés a les publicacions + permission_manage_boards: Gestiona els taulers + permission_view_messages: Visualitza els missatges + permission_add_messages: Envia missatges + permission_edit_messages: Edita els missatges + permission_edit_own_messages: Edita els missatges propis + permission_delete_messages: Suprimeix els missatges + permission_delete_own_messages: Suprimeix els missatges propis + permission_export_wiki_pages: "Exporta les pàgines wiki" + permission_manage_subtasks: "Gestiona subtasques" + + project_module_issue_tracking: "Seguidor d'assumptes" + project_module_time_tracking: Seguidor de temps + project_module_news: Noticies + project_module_documents: Documents + project_module_files: Fitxers + project_module_wiki: Wiki + project_module_repository: Dipòsit + project_module_boards: Taulers + project_module_calendar: Calendari + project_module_gantt: Gantt + + label_user: Usuari + label_user_plural: Usuaris + label_user_new: Usuari nou + label_user_anonymous: Anònim + label_project: Projecte + label_project_new: Projecte nou + label_project_plural: Projectes + label_x_projects: + zero: cap projecte + one: 1 projecte + other: "%{count} projectes" + label_project_all: Tots els projectes + label_project_latest: Els últims projectes + label_issue: Assumpte + label_issue_new: Assumpte nou + label_issue_plural: Assumptes + label_issue_view_all: Visualitza tots els assumptes + label_issues_by: "Assumptes per %{value}" + label_issue_added: Assumpte afegit + label_issue_updated: Assumpte actualitzat + label_document: Document + label_document_new: Document nou + label_document_plural: Documents + label_document_added: Document afegit + label_role: Rol + label_role_plural: Rols + label_role_new: Rol nou + label_role_and_permissions: Rols i permisos + label_member: Membre + label_member_new: Membre nou + label_member_plural: Membres + label_tracker: Seguidor + label_tracker_plural: Seguidors + label_tracker_new: Seguidor nou + label_workflow: Flux de treball + label_issue_status: "Estat de l'assumpte" + label_issue_status_plural: "Estats de l'assumpte" + label_issue_status_new: Estat nou + label_issue_category: "Categoria de l'assumpte" + label_issue_category_plural: "Categories de l'assumpte" + label_issue_category_new: Categoria nova + label_custom_field: Camp personalitzat + label_custom_field_plural: Camps personalitzats + label_custom_field_new: Camp personalitzat nou + label_enumerations: Enumeracions + label_enumeration_new: Valor nou + label_information: Informació + label_information_plural: Informació + label_please_login: Entreu + label_register: Registre + label_login_with_open_id_option: "o entra amb l'OpenID" + label_password_lost: Contrasenya perduda + label_home: Inici + label_my_page: La meva pàgina + label_my_account: El meu compte + label_my_projects: Els meus projectes + label_my_page_block: "Els meus blocs de pàgina" + label_administration: Administració + label_login: Entra + label_logout: Surt + label_help: Ajuda + label_reported_issues: Assumptes informats + label_assigned_to_me_issues: Assumptes assignats a mi + label_last_login: Última connexió + label_registered_on: Informat el + label_activity: Activitat + label_overall_activity: Activitat global + label_user_activity: "Activitat de %{value}" + label_new: Nou + label_logged_as: Heu entrat com a + label_environment: Entorn + label_authentication: Autenticació + label_auth_source: "Mode d'autenticació" + label_auth_source_new: "Mode d'autenticació nou" + label_auth_source_plural: "Modes d'autenticació" + label_subproject_plural: Subprojectes + label_subproject_new: "Subprojecte nou" + label_and_its_subprojects: "%{value} i els seus subprojectes" + label_min_max_length: Longitud mín - max + label_list: Llist + label_date: Data + label_integer: Enter + label_float: Flotant + label_boolean: Booleà + label_string: Text + label_text: Text llarg + label_attribute: Atribut + label_attribute_plural: Atributs + label_download: "%{count} baixada" + label_download_plural: "%{count} baixades" + label_no_data: Sense dades a mostrar + label_change_status: "Canvia l'estat" + label_history: Historial + label_attachment: Fitxer + label_attachment_new: Fitxer nou + label_attachment_delete: Suprimeix el fitxer + label_attachment_plural: Fitxers + label_file_added: Fitxer afegit + label_report: Informe + label_report_plural: Informes + label_news: Noticies + label_news_new: Afegeix noticies + label_news_plural: Noticies + label_news_latest: Últimes noticies + label_news_view_all: Visualitza totes les noticies + label_news_added: Noticies afegides + label_settings: Paràmetres + label_overview: Resum + label_version: Versió + label_version_new: Versió nova + label_version_plural: Versions + label_close_versions: "Tanca les versions completades" + label_confirmation: Confirmació + label_export_to: "També disponible a:" + label_read: Llegeix... + label_public_projects: Projectes públics + label_open_issues: obert + label_open_issues_plural: oberts + label_closed_issues: tancat + label_closed_issues_plural: tancats + label_x_open_issues_abbr_on_total: + zero: 0 oberts / %{total} + one: 1 obert / %{total} + other: "%{count} oberts / %{total}" + label_x_open_issues_abbr: + zero: 0 oberts + one: 1 obert + other: "%{count} oberts" + label_x_closed_issues_abbr: + zero: 0 tancats + one: 1 tancat + other: "%{count} tancats" + label_total: Total + label_permissions: Permisos + label_current_status: Estat actual + label_new_statuses_allowed: Nous estats autoritzats + label_all: tots + label_none: cap + label_nobody: ningú + label_next: Següent + label_previous: Anterior + label_used_by: Utilitzat per + label_details: Detalls + label_add_note: Afegeix una nota + label_per_page: Per pàgina + label_calendar: Calendari + label_months_from: mesos des de + label_gantt: Gantt + label_internal: Intern + label_last_changes: "últims %{count} canvis" + label_change_view_all: Visualitza tots els canvis + label_personalize_page: Personalitza aquesta pàgina + label_comment: Comentari + label_comment_plural: Comentaris + label_x_comments: + zero: sense comentaris + one: 1 comentari + other: "%{count} comentaris" + label_comment_add: Afegeix un comentari + label_comment_added: Comentari afegit + label_comment_delete: Suprimeix comentaris + label_query: Consulta personalitzada + label_query_plural: Consultes personalitzades + label_query_new: Consulta nova + label_filter_add: Afegeix un filtre + label_filter_plural: Filtres + label_equals: és + label_not_equals: no és + label_in_less_than: en menys de + label_in_more_than: en més de + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_in: en + label_today: avui + label_all_time: tot el temps + label_yesterday: ahir + label_this_week: aquesta setmana + label_last_week: "l'última setmana" + label_last_n_days: "els últims %{count} dies" + label_this_month: aquest més + label_last_month: "l'últim més" + label_this_year: aquest any + label_date_range: Abast de les dates + label_less_than_ago: fa menys de + label_more_than_ago: fa més de + label_ago: fa + label_contains: conté + label_not_contains: no conté + label_day_plural: dies + label_repository: Dipòsit + label_repository_plural: Dipòsits + label_browse: Navega + label_modification: "%{count} canvi" + label_modification_plural: "%{count} canvis" + label_branch: Branca + label_tag: Etiqueta + label_revision: Revisió + label_revision_plural: Revisions + label_revision_id: "Revisió %{value}" + label_associated_revisions: Revisions associades + label_added: afegit + label_modified: modificat + label_copied: copiat + label_renamed: reanomenat + label_deleted: suprimit + label_latest_revision: Última revisió + label_latest_revision_plural: Últimes revisions + label_view_revisions: Visualitza les revisions + label_view_all_revisions: "Visualitza totes les revisions" + label_max_size: Mida màxima + label_sort_highest: Mou a la part superior + label_sort_higher: Mou cap amunt + label_sort_lower: Mou cap avall + label_sort_lowest: Mou a la part inferior + label_roadmap: Planificació + label_roadmap_due_in: "Venç en %{value}" + label_roadmap_overdue: "%{value} tard" + label_roadmap_no_issues: No hi ha assumptes per a aquesta versió + label_search: Cerca + label_result_plural: Resultats + label_all_words: Totes les paraules + label_wiki: Wiki + label_wiki_edit: Edició wiki + label_wiki_edit_plural: Edicions wiki + label_wiki_page: Pàgina wiki + label_wiki_page_plural: Pàgines wiki + label_index_by_title: Índex per títol + label_index_by_date: Índex per data + label_current_version: Versió actual + label_preview: Previsualització + label_feed_plural: Canals + label_changes_details: Detalls de tots els canvis + label_issue_tracking: "Seguiment d'assumptes" + label_spent_time: Temps invertit + label_overall_spent_time: "Temps total invertit" + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} hores" + label_time_tracking: Temps de seguiment + label_change_plural: Canvis + label_statistics: Estadístiques + label_commits_per_month: Publicacions per mes + label_commits_per_author: Publicacions per autor + label_view_diff: Visualitza les diferències + label_diff_inline: en línia + label_diff_side_by_side: costat per costat + label_options: Opcions + label_copy_workflow_from: Copia el flux de treball des de + label_permissions_report: Informe de permisos + label_watched_issues: Assumptes vigilats + label_related_issues: Assumptes relacionats + label_applied_status: Estat aplicat + label_loading: "S'està carregant..." + label_relation_new: Relació nova + label_relation_delete: Suprimeix la relació + label_relates_to: relacionat amb + label_duplicates: duplicats + label_duplicated_by: duplicat per + label_blocks: bloqueja + label_blocked_by: bloquejats per + label_precedes: anterior a + label_follows: posterior a + label_end_to_start: final al començament + label_end_to_end: final al final + label_start_to_start: començament al començament + label_start_to_end: començament al final + label_stay_logged_in: "Manté l'entrada" + label_disabled: inhabilitat + label_show_completed_versions: Mostra les versions completes + label_me: jo mateix + label_board: Fòrum + label_board_new: Fòrum nou + label_board_plural: Fòrums + label_board_locked: Bloquejat + label_board_sticky: Sticky + label_topic_plural: Temes + label_message_plural: Missatges + label_message_last: Últim missatge + label_message_new: Missatge nou + label_message_posted: Missatge afegit + label_reply_plural: Respostes + label_send_information: "Envia la informació del compte a l'usuari" + label_year: Any + label_month: Mes + label_week: Setmana + label_date_from: Des de + label_date_to: A + label_language_based: "Basat en l'idioma de l'usuari" + label_sort_by: "Ordena per %{value}" + label_send_test_email: Envia un correu electrònic de prova + label_feeds_access_key: "Clau d'accés del RSS" + label_missing_feeds_access_key: "Falta una clau d'accés del RSS" + label_feeds_access_key_created_on: "Clau d'accés del RSS creada fa %{value}" + label_module_plural: Mòduls + label_added_time_by: "Afegit per %{author} fa %{age}" + label_updated_time_by: "Actualitzat per %{author} fa %{age}" + label_updated_time: "Actualitzat fa %{value}" + label_jump_to_a_project: Salta al projecte... + label_file_plural: Fitxers + label_changeset_plural: Conjunt de canvis + label_default_columns: Columnes predeterminades + label_no_change_option: (sense canvis) + label_bulk_edit_selected_issues: Edita en bloc els assumptes seleccionats + label_theme: Tema + label_default: Predeterminat + label_search_titles_only: Cerca només en els títols + label_user_mail_option_all: "Per qualsevol esdeveniment en tots els meus projectes" + label_user_mail_option_selected: "Per qualsevol esdeveniment en els projectes seleccionats..." + label_user_mail_no_self_notified: "No vull ser notificat pels canvis que faig jo mateix" + label_registration_activation_by_email: activació del compte per correu electrònic + label_registration_manual_activation: activació del compte manual + label_registration_automatic_activation: activació del compte automàtica + label_display_per_page: "Per pàgina: %{value}" + label_age: Edat + label_change_properties: Canvia les propietats + label_general: General + label_more: Més + label_scm: SCM + label_plugins: Connectors + label_ldap_authentication: Autenticació LDAP + label_downloads_abbr: Baixades + label_optional_description: Descripció opcional + label_add_another_file: Afegeix un altre fitxer + label_preferences: Preferències + label_chronological_order: En ordre cronològic + label_reverse_chronological_order: En ordre cronològic invers + label_planning: Planificació + label_incoming_emails: "Correu electrònics d'entrada" + label_generate_key: Genera una clau + label_issue_watchers: Vigilàncies + label_example: Exemple + label_display: Mostra + label_sort: Ordena + label_ascending: Ascendent + label_descending: Descendent + label_date_from_to: Des de %{start} a %{end} + label_wiki_content_added: "S'ha afegit la pàgina wiki" + label_wiki_content_updated: "S'ha actualitzat la pàgina wiki" + label_group: Grup + label_group_plural: Grups + label_group_new: Grup nou + label_time_entry_plural: Temps invertit + label_version_sharing_hierarchy: "Amb la jerarquia del projecte" + label_version_sharing_system: "Amb tots els projectes" + label_version_sharing_descendants: "Amb tots els subprojectes" + label_version_sharing_tree: "Amb l'arbre del projecte" + label_version_sharing_none: "Sense compartir" + label_update_issue_done_ratios: "Actualitza el tant per cent dels assumptes realitzats" + label_copy_source: Font + label_copy_target: Objectiu + label_copy_same_as_target: "El mateix que l'objectiu" + label_display_used_statuses_only: "Mostra només els estats que utilitza aquest seguidor" + label_api_access_key: "Clau d'accés a l'API" + label_missing_api_access_key: "Falta una clau d'accés de l'API" + label_api_access_key_created_on: "Clau d'accés de l'API creada fa %{value}" + label_profile: Perfil + label_subtask_plural: Subtasques + label_project_copy_notifications: "Envia notificacions de correu electrònic durant la còpia del projecte" + + button_login: Entra + button_submit: Tramet + button_save: Desa + button_check_all: Activa-ho tot + button_uncheck_all: Desactiva-ho tot + button_delete: Suprimeix + button_create: Crea + button_create_and_continue: Crea i continua + button_test: Test + button_edit: Edit + button_add: Afegeix + button_change: Canvia + button_apply: Aplica + button_clear: Neteja + button_lock: Bloca + button_unlock: Desbloca + button_download: Baixa + button_list: Llista + button_view: Visualitza + button_move: Mou + button_move_and_follow: "Mou i segueix" + button_back: Enrere + button_cancel: Cancel·la + button_activate: Activa + button_sort: Ordena + button_log_time: "Registre de temps" + button_rollback: Torna a aquesta versió + button_watch: Vigila + button_unwatch: No vigilis + button_reply: Resposta + button_archive: Arxiva + button_unarchive: Desarxiva + button_reset: Reinicia + button_rename: Reanomena + button_change_password: Canvia la contrasenya + button_copy: Copia + button_copy_and_follow: "Copia i segueix" + button_annotate: Anota + button_update: Actualitza + button_configure: Configura + button_quote: Cita + button_duplicate: Duplica + button_show: Mostra + + status_active: actiu + status_registered: informat + status_locked: bloquejat + + version_status_open: oberta + version_status_locked: bloquejada + version_status_closed: tancada + + field_active: Actiu + + text_select_mail_notifications: "Seleccioneu les accions per les quals s'hauria d'enviar una notificació per correu electrònic." + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 significa sense restricció + text_project_destroy_confirmation: Segur que voleu suprimir aquest projecte i les dades relacionades? + text_subprojects_destroy_warning: "També seran suprimits els seus subprojectes: %{value}." + text_workflow_edit: Seleccioneu un rol i un seguidor per a editar el flux de treball + text_are_you_sure: Segur? + text_journal_changed: "%{label} ha canviat de %{old} a %{new}" + text_journal_set_to: "%{label} s'ha establert a %{value}" + text_journal_deleted: "%{label} s'ha suprimit (%{old})" + text_journal_added: "S'ha afegit %{label} %{value}" + text_tip_issue_begin_day: "tasca que s'inicia aquest dia" + text_tip_issue_end_day: tasca que finalitza aquest dia + text_tip_issue_begin_end_day: "tasca que s'inicia i finalitza aquest dia" + text_project_identifier_info: "Es permeten lletres en minúscules (a-z), números i guions.
    Un cop desat, l'identificador no es pot modificar." + text_caracters_maximum: "%{count} caràcters com a màxim." + text_caracters_minimum: "Com a mínim ha de tenir %{count} caràcters." + text_length_between: "Longitud entre %{min} i %{max} caràcters." + text_tracker_no_workflow: "No s'ha definit cap flux de treball per a aquest seguidor" + text_unallowed_characters: Caràcters no permesos + text_comma_separated: Es permeten valors múltiples (separats per una coma). + text_line_separated: "Es permeten diversos valors (una línia per cada valor)." + text_issues_ref_in_commit_messages: Referència i soluciona els assumptes en els missatges publicats + text_issue_added: "L'assumpte %{id} ha sigut informat per %{author}." + text_issue_updated: "L'assumpte %{id} ha sigut actualitzat per %{author}." + text_wiki_destroy_confirmation: Segur que voleu suprimir aquest wiki i tots els seus continguts? + text_issue_category_destroy_question: "Alguns assumptes (%{count}) estan assignats a aquesta categoria. Què voleu fer?" + text_issue_category_destroy_assignments: Suprimeix les assignacions de la categoria + text_issue_category_reassign_to: Torna a assignar els assumptes a aquesta categoria + text_user_mail_option: "Per als projectes no seleccionats, només rebreu notificacions sobre les coses que vigileu o que hi esteu implicat (ex. assumptes que en sou l'autor o hi esteu assignat)." + text_no_configuration_data: "Encara no s'han configurat els rols, seguidors, estats de l'assumpte i flux de treball.\nÉs altament recomanable que carregueu la configuració predeterminada. Podreu modificar-la un cop carregada." + text_load_default_configuration: Carrega la configuració predeterminada + text_status_changed_by_changeset: "Aplicat en el conjunt de canvis %{value}." + text_issues_destroy_confirmation: "Segur que voleu suprimir els assumptes seleccionats?" + text_select_project_modules: "Seleccioneu els mòduls a habilitar per a aquest projecte:" + text_default_administrator_account_changed: "S'ha canviat el compte d'administrador predeterminat" + text_file_repository_writable: Es pot escriure en el dipòsit de fitxers + text_plugin_assets_writable: Es pot escriure als connectors actius + text_rmagick_available: RMagick disponible (opcional) + text_destroy_time_entries_question: "S'han informat %{hours} hores en els assumptes que aneu a suprimir. Què voleu fer?" + text_destroy_time_entries: Suprimeix les hores informades + text_assign_time_entries_to_project: Assigna les hores informades al projecte + text_reassign_time_entries: "Torna a assignar les hores informades a aquest assumpte:" + text_user_wrote: "%{value} va escriure:" + text_enumeration_destroy_question: "%{count} objectes estan assignats a aquest valor." + text_enumeration_category_reassign_to: "Torna a assignar-los a aquest valor:" + text_email_delivery_not_configured: "El lliurament per correu electrònic no està configurat i les notificacions estan inhabilitades.\nConfigureu el servidor SMTP a config/configuration.yml i reinicieu l'aplicació per habilitar-lo." + text_repository_usernames_mapping: "Seleccioneu l'assignació entre els usuaris del Redmine i cada nom d'usuari trobat al dipòsit.\nEls usuaris amb el mateix nom d'usuari o correu del Redmine i del dipòsit s'assignaran automàticament." + text_diff_truncated: "... Aquestes diferències s'han trucat perquè excedeixen la mida màxima que es pot mostrar." + text_custom_field_possible_values_info: "Una línia per a cada valor" + text_wiki_page_destroy_question: "Aquesta pàgina té %{descendants} pàgines fill i descendents. Què voleu fer?" + text_wiki_page_nullify_children: "Deixa les pàgines fill com a pàgines arrel" + text_wiki_page_destroy_children: "Suprimeix les pàgines fill i tots els seus descendents" + text_wiki_page_reassign_children: "Reasigna les pàgines fill a aquesta pàgina pare" + text_own_membership_delete_confirmation: "Esteu a punt de suprimir algun o tots els vostres permisos i potser no podreu editar més aquest projecte.\nSegur que voleu continuar?" + text_zoom_in: Redueix + text_zoom_out: Amplia + + default_role_manager: Gestor + default_role_developer: Desenvolupador + default_role_reporter: Informador + default_tracker_bug: Error + default_tracker_feature: Característica + default_tracker_support: Suport + default_issue_status_new: Nou + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Resolt + default_issue_status_feedback: Comentaris + default_issue_status_closed: Tancat + default_issue_status_rejected: Rebutjat + default_doc_category_user: "Documentació d'usuari" + default_doc_category_tech: Documentació tècnica + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_high: Alta + default_priority_urgent: Urgent + default_priority_immediate: Immediata + default_activity_design: Disseny + default_activity_development: Desenvolupament + + enumeration_issue_priorities: Prioritat dels assumptes + enumeration_doc_categories: Categories del document + enumeration_activities: Activitats (seguidor de temps) + enumeration_system_activity: Activitat del sistema + + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Codificació dels missatges publicats + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c66d3b3ac719b98649d62296e3f91aca262abec6.svn-base Binary file .svn/pristine/c6/c66d3b3ac719b98649d62296e3f91aca262abec6.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c67df8f4061dcb392af7b61e6af1469235ed0229.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c67df8f4061dcb392af7b61e6af1469235ed0229.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1038 @@ +# Japanese translations for Ruby on Rails +# by Akira Matsuda (ronnie@dio.jp) +# AR error messages are basically taken from Ruby-GetText-Package. Thanks to Masao Mutoh. + +ja: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%m/%d" + long: "%Y年%m月%d日(%a)" + + day_names: [日曜日, 月曜日, 火曜日, 水曜日, 木曜日, 金曜日, 土曜日] + abbr_day_names: [日, 月, 火, 水, 木, 金, 土] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d %H:%M:%S" + time: "%H:%M" + short: "%y/%m/%d %H:%M" + long: "%Y年%m月%d日(%a) %H時%M分%S秒 %Z" + am: "午前" + pm: "午後" + + datetime: + distance_in_words: + half_a_minute: "30秒前後" + less_than_x_seconds: + one: "1秒以内" + other: "%{count}秒以内" + x_seconds: + one: "1秒" + other: "%{count}秒" + less_than_x_minutes: + one: "1分以内" + other: "%{count}分以内" + x_minutes: + one: "1分" + other: "%{count}分" + about_x_hours: + one: "約1時間" + other: "約%{count}時間" + x_days: + one: "1日" + other: "%{count}日" + about_x_months: + one: "約1ヶ月" + other: "約%{count}ヶ月" + x_months: + one: "1ヶ月" + other: "%{count}ヶ月" + about_x_years: + one: "約1年" + other: "約%{count}年" + over_x_years: + one: "1年以上" + other: "%{count}年以上" + almost_x_years: + one: "ほぼ1年" + other: "ほぼ%{count}年" + + number: + format: + separator: "." + delimiter: "," + precision: 3 + + currency: + format: + format: "%n%u" + unit: "円" + separator: "." + delimiter: "," + precision: 0 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "及び" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "%{model} にエラーが発生しました。" + other: "%{model} に %{count} つのエラーが発生しました。" + body: "次の項目を確認してください。" + + messages: + inclusion: "は一覧にありません。" + exclusion: "は予約されています。" + invalid: "は不正な値です。" + confirmation: "が一致しません。" + accepted: "を受諾してください。" + empty: "を入力してください。" + blank: "を入力してください。" + too_long: "は%{count}文字以内で入力してください。" + too_short: "は%{count}文字以上で入力してください。" + wrong_length: "は%{count}文字で入力してください。" + taken: "はすでに存在します。" + not_a_number: "は数値で入力してください。" + not_a_date: "は日付を入力してください。" + greater_than: "は%{count}より大きい値にしてください。" + greater_than_or_equal_to: "は%{count}以上の値にしてください。" + equal_to: "は%{count}にしてください。" + less_than: "は%{count}より小さい値にしてください。" + less_than_or_equal_to: "は%{count}以下の値にしてください。" + odd: "は奇数にしてください。" + even: "は偶数にしてください。" + greater_than_start_date: "を開始日より後にしてください" + not_same_project: "同じプロジェクトに属していません" + circular_dependency: "この関係では、循環依存になります" + cant_link_an_issue_with_a_descendant: "指定したチケットとは親子関係になっているため関連づけられません" + + actionview_instancetag_blank_option: 選んでください + + general_text_No: 'いいえ' + general_text_Yes: 'はい' + general_text_no: 'いいえ' + general_text_yes: 'はい' + general_lang_name: 'Japanese (日本語)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: CP932 + ## Redmine 1.2.0 現在、この値によって、pdfの出力のフォントを切り替えています。 + ## CRuby では CP932 にしてください。 + ## JRuby 1.6.2 (ruby-1.8.7-p330) では、CP932 ですと + ## Iconv::InvalidEncoding例外が発生します。 + ## JRuby では、SJIS か Shift_JIS にしてください。 + ## ご存知の通り、CP932 と SJIS は別物ですが、 + ## そこまでの検証はしていません。 + # general_pdf_encoding: SJIS + general_pdf_encoding: CP932 + general_first_day_of_week: '7' + + notice_account_updated: アカウントが更新されました。 + notice_account_invalid_creditentials: ユーザ名もしくはパスワードが無効 + notice_account_password_updated: パスワードが更新されました。 + notice_account_wrong_password: パスワードが違います + notice_account_register_done: アカウントが作成されました。 + notice_account_unknown_email: ユーザが存在しません。 + notice_can_t_change_password: このアカウントでは外部認証を使っています。パスワードは変更できません。 + notice_account_lost_email_sent: 新しいパスワードのメールを送信しました。 + notice_account_activated: アカウントが有効になりました。ログインできます。 + notice_successful_create: 作成しました。 + notice_successful_update: 更新しました。 + notice_successful_delete: 削除しました。 + notice_successful_connection: 接続しました。 + notice_file_not_found: アクセスしようとしたページは存在しないか削除されています。 + notice_locking_conflict: 別のユーザがデータを更新しています。 + notice_not_authorized: このページにアクセスするには認証が必要です。 + notice_not_authorized_archived_project: プロジェクトは書庫に保存されています。 + notice_email_sent: "%{value} 宛にメールを送信しました。" + notice_email_error: "メール送信中にエラーが発生しました (%{value})" + notice_feeds_access_key_reseted: RSSアクセスキーを初期化しました。 + notice_api_access_key_reseted: APIアクセスキーを初期化しました。 + notice_failed_to_save_issues: "%{total}件のうち%{count}件のチケットが保存できませんでした: %{ids}." + notice_failed_to_save_members: "メンバーの保存に失敗しました: %{errors}." + notice_no_issue_selected: "チケットが選択されていません! 更新対象のチケットを選択してください。" + notice_account_pending: アカウントは作成済みで、管理者の承認待ちです。 + notice_default_data_loaded: デフォルト設定をロードしました。 + notice_unable_delete_version: バージョンを削除できません + notice_unable_delete_time_entry: 作業時間を削除できません + notice_issue_done_ratios_updated: チケットの進捗が更新されました。 + notice_gantt_chart_truncated: ガントチャートは、最大表示項目数(%{max})を超えたたため切り捨てられました。 + + error_can_t_load_default_data: "デフォルト設定がロードできませんでした: %{value}" + error_scm_not_found: リポジトリに、エントリ/リビジョンが存在しません。 + error_scm_command_failed: "リポジトリへアクセスしようとしてエラーになりました: %{value}" + error_scm_annotate: "エントリが存在しない、もしくはアノテートできません。" + error_issue_not_found_in_project: 'チケットが見つかりません、もしくはこのプロジェクトに属していません' + error_unable_delete_issue_status: "チケットのステータスを削除できませんでした。" + error_no_tracker_in_project: 'このプロジェクトにはトラッカーが登録されていません。プロジェクト設定を確認してください。' + error_no_default_issue_status: 'デフォルトのチケットステータスが定義されていません。設定を確認してください(管理→チケットのステータス)。' + error_can_not_delete_custom_field: 'カスタムフィールドを削除できません。' + error_unable_to_connect: "接続できません。 (%{value})" + error_can_not_remove_role: 'このロールは使用されています。削除できません。' + error_can_not_reopen_issue_on_closed_version: '終了したバージョンにひも付けされたチケットの再オープンはできません。' + error_can_not_archive_project: このプロジェクトは書庫に保存できません + error_issue_done_ratios_not_updated: "チケットの進捗が更新できません。" + error_workflow_copy_source: 'コピー元となるトラッカーまたはロールを選択してください' + error_workflow_copy_target: 'コピー先となるトラッカーとロールを選択してください' + error_can_not_delete_tracker: 'このトラッカーは使用されています。削除できません。' + + warning_attachments_not_saved: "%{count}個の添付ファイルが保存できませんでした。" + + mail_subject_lost_password: "%{value} パスワード再発行" + mail_body_lost_password: 'パスワードを変更するには、以下のリンクをクリックしてください:' + mail_subject_register: "%{value} アカウント登録の確認" + mail_body_register: 'アカウント登録を完了するには、以下のアドレスをクリックしてください:' + mail_body_account_information_external: "%{value} アカウントを使ってにログインできます。" + mail_body_account_information: アカウント情報 + mail_subject_account_activation_request: "%{value} アカウントの承認要求" + mail_body_account_activation_request: "新しいユーザ %{value} が登録されました。このアカウントはあなたの承認待ちです:" + mail_subject_reminder: "%{count}件のチケットの期日が%{days}日以内に到来します" + mail_body_reminder: "%{count}件の担当チケットの期日が%{days}日以内に到来します:" + mail_subject_wiki_content_added: "Wikiページ %{id} が追加されました" + mail_body_wiki_content_added: "%{author} によってWikiページ %{id} が追加されました。" + mail_subject_wiki_content_updated: "Wikiページ %{id} が更新されました" + mail_body_wiki_content_updated: "%{author} によってWikiページ %{id} が更新されました。" + + gui_validation_error: 1件のエラー + gui_validation_error_plural: "%{count}件のエラー" + + field_name: 名称 + field_description: 説明 + field_summary: サマリー + field_is_required: 必須 + field_firstname: 名前 + field_lastname: 苗字 + field_mail: メールアドレス + field_filename: ファイル + field_filesize: サイズ + field_downloads: ダウンロード + field_author: 作成者 + field_created_on: 作成日 + field_updated_on: 更新日 + field_field_format: 書式 + field_is_for_all: 全プロジェクト向け + field_possible_values: 選択肢 + field_regexp: 正規表現 + field_min_length: 最小値 + field_max_length: 最大値 + field_value: 値 + field_category: カテゴリ + field_title: タイトル + field_project: プロジェクト + field_issue: チケット + field_status: ステータス + field_notes: 注記 + field_is_closed: 終了したチケット + field_is_default: デフォルト値 + field_tracker: トラッカー + field_subject: 題名 + field_due_date: 期日 + field_assigned_to: 担当者 + field_priority: 優先度 + field_fixed_version: 対象バージョン + field_user: ユーザ + field_principal: 主体 + field_role: ロール + field_homepage: ホームページ + field_is_public: 公開 + field_parent: 親プロジェクト名 + field_is_in_roadmap: チケットをロードマップに表示する + field_login: ログイン + field_mail_notification: メール通知 + field_admin: 管理者 + field_last_login_on: 最終接続日 + field_language: 言語 + field_effective_date: 期日 + field_password: パスワード + field_new_password: 新しいパスワード + field_password_confirmation: パスワードの確認 + field_version: バージョン + field_type: タイプ + field_host: ホスト + field_port: ポート + field_account: アカウント + field_base_dn: 検索範囲 + field_attr_login: ログイン名属性 + field_attr_firstname: 名前属性 + field_attr_lastname: 苗字属性 + field_attr_mail: メール属性 + field_onthefly: あわせてユーザを作成 + field_start_date: 開始日 + field_done_ratio: 進捗 % + field_auth_source: 認証方式 + field_hide_mail: メールアドレスを隠す + field_comments: コメント + field_url: URL + field_start_page: メインページ + field_subproject: サブプロジェクト + field_hours: 時間 + field_activity: 活動 + field_spent_on: 日付 + field_identifier: 識別子 + field_is_filter: フィルタとして使う + field_issue_to: 関連するチケット + field_delay: 遅延 + field_assignable: このロールにチケットを割り当て可能 + field_redirect_existing_links: 既存のリンクをリダイレクトする + field_estimated_hours: 予定工数 + field_column_names: 項目 + field_time_entries: 時間を記録 + field_time_zone: タイムゾーン + field_searchable: 検索条件に設定可能とする + field_default_value: デフォルト値 + field_comments_sorting: コメントの表示順 + field_parent_title: 親ページ + field_editable: 編集可能 + field_watcher: ウォッチャー + field_identity_url: OpenID URL + field_content: 内容 + field_group_by: グループ条件 + field_sharing: 共有 + field_parent_issue: 親チケット + field_member_of_group: 担当者のグループ + field_assigned_to_role: 担当者のロール + field_text: テキスト + field_visible: 表示 + field_warn_on_leaving_unsaved: データを保存せずにページから移動するときに警告 + field_commit_logs_encoding: コミットメッセージのエンコーディング + field_scm_path_encoding: パスのエンコーディング + field_path_to_repository: リポジトリのパス + field_root_directory: ルートディレクトリ + field_cvsroot: CVSROOT + field_cvs_module: モジュール + + setting_app_title: アプリケーションのタイトル + setting_app_subtitle: アプリケーションのサブタイトル + setting_welcome_text: ウェルカムメッセージ + setting_default_language: 既定の言語 + setting_login_required: 認証が必要 + setting_self_registration: ユーザは自分で登録できる + setting_attachment_max_size: 添付ファイルサイズの上限 + setting_issues_export_limit: エクスポートするチケット数の上限 + setting_mail_from: 送信元メールアドレス + setting_bcc_recipients: ブラインドカーボンコピーで受信(bcc) + setting_plain_text_mail: プレインテキストのみ(HTMLなし) + setting_host_name: ホスト名 + setting_text_formatting: テキストの書式 + setting_cache_formatted_text: 書式化されたテキストをキャッシュする + setting_wiki_compression: Wiki履歴を圧縮する + setting_feeds_limit: フィード内容の上限 + setting_default_projects_public: デフォルトで新しいプロジェクトは公開にする + setting_autofetch_changesets: コミットを自動取得する + setting_sys_api_enabled: リポジトリ管理用のWebサービスを有効にする + setting_commit_ref_keywords: 参照用キーワード + setting_commit_fix_keywords: 修正用キーワード + setting_autologin: 自動ログイン + setting_date_format: 日付の形式 + setting_time_format: 時刻の形式 + setting_cross_project_issue_relations: 異なるプロジェクトのチケット間で関係の設定を許可 + setting_issue_list_default_columns: チケットの一覧で表示する項目 + setting_repositories_encodings: 添付ファイルとリポジトリのエンコーディング + setting_emails_header: メールのヘッダ + setting_emails_footer: メールのフッタ + setting_protocol: プロトコル + setting_per_page_options: ページ毎の表示件数 + setting_user_format: ユーザ名の表示書式 + setting_activity_days_default: プロジェクトの活動ページに表示される日数 + setting_display_subprojects_issues: サブプロジェクトのチケットをメインプロジェクトに表示する + setting_enabled_scm: 使用するバージョン管理システム + setting_mail_handler_body_delimiters: "メール本文から一致する行以降を切り取る" + setting_mail_handler_api_enabled: 受信メール用のWebサービスを有効にする + setting_mail_handler_api_key: APIキー + setting_sequential_project_identifiers: プロジェクト識別子を連番で生成する + setting_gravatar_enabled: Gravatarのアイコンを使用する + setting_gravatar_default: デフォルトのGravatarアイコン + setting_diff_max_lines_displayed: 差分の表示行数の上限 + setting_file_max_size_displayed: 画面表示するテキストファイルサイズの上限 + setting_repository_log_display_limit: ファイルのリビジョン表示数の上限 + setting_openid: OpenIDによるログインと登録 + setting_password_min_length: パスワードの最低必要文字数 + setting_new_project_user_role_id: 管理者以外のユーザが作成したプロジェクトに設定するロール + setting_default_projects_modules: 新規プロジェクトにおいてデフォルトで有効になるモジュール + setting_issue_done_ratio: 進捗の算出方法 + setting_issue_done_ratio_issue_field: 各チケットにフィールドを用意する + setting_issue_done_ratio_issue_status: チケットのステータスを使用する + setting_start_of_week: 週の開始曜日 + setting_rest_api_enabled: RESTによるWebサービスを有効にする + setting_default_notification_option: デフォルトのメール通知オプション + setting_commit_logtime_enabled: コミット時に作業時間を記録する + setting_commit_logtime_activity_id: 作業時間の作業分類 + setting_gantt_items_limit: ガントチャート最大表示項目数 + + permission_add_project: プロジェクトの追加 + permission_add_subprojects: サブプロジェクトの追加 + permission_edit_project: プロジェクトの編集 + permission_select_project_modules: モジュールの選択 + permission_manage_members: メンバーの管理 + permission_manage_versions: バージョンの管理 + permission_manage_categories: チケットのカテゴリの管理 + permission_view_issues: チケットの閲覧 + permission_add_issues: チケットの追加 + permission_edit_issues: チケットの編集 + permission_manage_issue_relations: チケットの管理 + permission_add_issue_notes: 注記の追加 + permission_edit_issue_notes: 注記の編集 + permission_edit_own_issue_notes: 自身が記入した注記の編集 + permission_move_issues: チケットの移動 + permission_delete_issues: チケットの削除 + permission_manage_public_queries: 公開クエリの管理 + permission_save_queries: クエリの保存 + permission_view_gantt: ガントチャートの閲覧 + permission_view_calendar: カレンダーの閲覧 + permission_view_issue_watchers: ウォッチ一覧の閲覧 + permission_add_issue_watchers: ウォッチの追加 + permission_delete_issue_watchers: ウォッチの削除 + permission_log_time: 変更履歴の記入 + permission_view_time_entries: 変更履歴の閲覧 + permission_edit_time_entries: 変更履歴の編集 + permission_edit_own_time_entries: 自身が記入した変更履歴の編集 + permission_manage_project_activities: 作業分類 (時間トラッキング) の管理 + permission_manage_news: ニュースの管理 + permission_comment_news: ニュースへのコメント + permission_manage_documents: 文書の管理 + permission_view_documents: 文書の閲覧 + permission_manage_files: ファイルの管理 + permission_view_files: ファイルの閲覧 + permission_manage_wiki: Wikiの管理 + permission_rename_wiki_pages: Wikiページ名の変更 + permission_delete_wiki_pages: Wikiページの削除 + permission_view_wiki_pages: Wikiの閲覧 + permission_export_wiki_pages: Wikiページを他の形式にエクスポート + permission_view_wiki_edits: Wiki履歴の閲覧 + permission_edit_wiki_pages: Wikiページの編集 + permission_delete_wiki_pages_attachments: 添付ファイルの削除 + permission_protect_wiki_pages: Wikiページの凍結 + permission_manage_repository: リポジトリの管理 + permission_browse_repository: リポジトリの閲覧 + permission_view_changesets: 更新履歴の閲覧 + permission_commit_access: コミットの閲覧 + permission_manage_boards: フォーラムの管理 + permission_view_messages: メッセージの閲覧 + permission_add_messages: メッセージの追加 + permission_edit_messages: メッセージの編集 + permission_edit_own_messages: 自身が記入したメッセージの編集 + permission_delete_messages: メッセージの削除 + permission_delete_own_messages: 自身が記入したメッセージの削除 + permission_manage_subtasks: 子チケットの管理 + + project_module_issue_tracking: チケットトラッキング + project_module_time_tracking: 時間トラッキング + project_module_news: ニュース + project_module_documents: 文書 + project_module_files: ファイル + project_module_wiki: Wiki + project_module_repository: リポジトリ + project_module_boards: フォーラム + project_module_gantt: ガントチャート + project_module_calendar: カレンダー + + label_user: ユーザ + label_user_plural: ユーザ + label_user_new: 新しいユーザ + label_user_anonymous: 匿名ユーザ + label_profile: プロフィール + label_project: プロジェクト + label_project_new: 新しいプロジェクト + label_project_plural: プロジェクト + label_x_projects: + zero: プロジェクトはありません + one: 1プロジェクト + other: "%{count}プロジェクト" + label_project_all: 全プロジェクト + label_project_latest: 最近のプロジェクト + label_issue: チケット + label_issue_new: 新しいチケット + label_issue_plural: チケット + label_issue_view_all: すべてのチケットを見る + label_issues_by: "%{value} 別のチケット" + label_issue_added: チケットが追加されました + label_issue_updated: チケットが更新されました + label_document: 文書 + label_document_new: 新しい文書 + label_document_plural: 文書 + label_document_added: 文書が追加されました + label_role: ロール + label_role_plural: ロール + label_role_new: 新しいロール + label_role_and_permissions: ロールと権限 + label_member: メンバー + label_member_new: 新しいメンバー + label_member_plural: メンバー + label_tracker: トラッカー + label_tracker_plural: トラッカー + label_tracker_new: 新しいトラッカーを作成 + label_workflow: ワークフロー + label_issue_status: チケットのステータス + label_issue_status_plural: チケットのステータス + label_issue_status_new: 新しいステータス + label_issue_category: チケットのカテゴリ + label_issue_category_plural: チケットのカテゴリ + label_issue_category_new: 新しいカテゴリ + label_custom_field: カスタムフィールド + label_custom_field_plural: カスタムフィールド + label_custom_field_new: 新しいカスタムフィールドを作成 + label_enumerations: 列挙項目 + label_enumeration_new: 新しい値 + label_information: 情報 + label_information_plural: 情報 + label_please_login: ログインしてください + label_register: 登録する + label_login_with_open_id_option: またはOpenIDでログインする + label_password_lost: パスワードの再発行 + label_home: ホーム + label_my_page: マイページ + label_my_account: 個人設定 + label_my_projects: マイプロジェクト + label_my_page_block: マイページパーツ + label_administration: 管理 + label_login: ログイン + label_logout: ログアウト + label_help: ヘルプ + label_reported_issues: 報告したチケット + label_assigned_to_me_issues: 担当しているチケット + label_last_login: 最近の接続 + label_registered_on: 登録日 + label_activity: 活動 + label_overall_activity: すべての活動 + label_user_activity: "%{value} の活動" + label_new: 新しく作成 + label_logged_as: ログイン中: + label_environment: 環境 + label_authentication: 認証 + label_auth_source: 認証方式 + label_auth_source_new: 新しい認証方式 + label_auth_source_plural: 認証方式 + label_subproject_plural: サブプロジェクト + label_subproject_new: 新しいサブプロジェクト + label_and_its_subprojects: "%{value} とサブプロジェクト" + label_min_max_length: 最小値 - 最大値の長さ + label_list: リストから選択 + label_date: 日付 + label_integer: 整数 + label_float: 小数 + label_boolean: 真偽値 + label_string: テキスト + label_text: 長いテキスト + label_attribute: 属性 + label_attribute_plural: 属性 + label_download: "%{count}ダウンロード" + label_download_plural: "%{count}ダウンロード" + label_no_data: 表示するデータがありません + label_change_status: ステータスの変更 + label_history: 履歴 + label_attachment: 添付ファイル + label_attachment_new: 新しい添付ファイル + label_attachment_delete: 添付ファイルを削除 + label_attachment_plural: 添付ファイル + label_file_added: ファイルが追加されました + label_report: レポート + label_report_plural: レポート + label_news: ニュース + label_news_new: ニュースを追加 + label_news_plural: ニュース + label_news_latest: 最新ニュース + label_news_view_all: すべてのニュースを見る + label_news_added: ニュースが追加されました + label_news_comment_added: ニュースにコメントが追加されました + label_settings: 設定 + label_overview: 概要 + label_version: バージョン + label_version_new: 新しいバージョン + label_version_plural: バージョン + label_confirmation: 確認 + label_close_versions: 完了したバージョンを終了にする + label_export_to: '他の形式にエクスポート:' + label_read: 読む... + label_public_projects: 公開プロジェクト + label_open_issues: 未完了 + label_open_issues_plural: 未完了 + label_closed_issues: 完了 + label_closed_issues_plural: 完了 + label_x_open_issues_abbr_on_total: + zero: 0件未完了 / 全%{total}件 + one: 1件未完了 / 全%{total}件 + other: "%{count}件未完了 / 全%{total}件" + label_x_open_issues_abbr: + zero: 0件未完了 + one: 1件未完了 + other: "%{count}件未完了" + label_x_closed_issues_abbr: + zero: 0件完了 + one: 1件完了 + other: "%{count}件完了" + label_total: 合計 + label_permissions: 権限 + label_current_status: 現在のステータス + label_new_statuses_allowed: ステータスの移行先 + label_all: すべて + label_none: なし + label_nobody: 無記名 + label_next: 次 + label_previous: 前 + label_used_by: 使用中 + label_details: 詳細 + label_add_note: 注記を追加 + label_per_page: ページ毎 + label_calendar: カレンダー + label_months_from: ヶ月分 + label_gantt: ガントチャート + label_internal: 内部 + label_last_changes: "最新の変更 %{count}件" + label_change_view_all: すべての変更を見る + label_personalize_page: このページをパーソナライズする + label_comment: コメント + label_comment_plural: コメント + label_x_comments: + zero: コメントがありません + one: 1コメント + other: "%{count}コメント" + label_comment_add: コメント追加 + label_comment_added: 追加されたコメント + label_comment_delete: コメント削除 + label_query: カスタムクエリ + label_query_plural: カスタムクエリ + label_query_new: 新しいクエリ + label_my_queries: マイカスタムクエリ + label_filter_add: フィルタ追加 + label_filter_plural: フィルタ + label_equals: 等しい + label_not_equals: 等しくない + label_in_less_than: が今日から○日後以前 + label_in_more_than: が今日から○日後以降 + label_greater_or_equal: 以上 + label_less_or_equal: 以下 + label_in: が今日から○日後 + label_today: 今日 + label_all_time: 全期間 + label_yesterday: 昨日 + label_this_week: 今週 + label_last_week: 先週 + label_last_n_days: "直近%{count}日間" + label_this_month: 今月 + label_last_month: 先月 + label_this_year: 今年 + label_date_range: 期間 + label_less_than_ago: が今日より○日前以降 + label_more_than_ago: が今日より○日前以前 + label_ago: 日前 + label_contains: 含む + label_not_contains: 含まない + label_day_plural: 日 + label_repository: リポジトリ + label_repository_plural: リポジトリ + label_browse: ブラウズ + label_modification: "%{count}点の変更" + label_modification_plural: "%{count}点の変更" + label_branch: ブランチ + label_tag: タグ + label_revision: リビジョン + label_revision_plural: リビジョン + label_revision_id: リビジョン %{value} + label_associated_revisions: 関係しているリビジョン + label_added: 追加 + label_modified: 変更 + label_copied: コピー + label_renamed: 名称変更 + label_deleted: 削除 + label_latest_revision: 最新リビジョン + label_latest_revision_plural: 最新リビジョン + label_view_revisions: リビジョンを見る + label_view_all_revisions: すべてのリビジョンを見る + label_max_size: サイズの上限 + label_sort_highest: 一番上へ + label_sort_higher: 上へ + label_sort_lower: 下へ + label_sort_lowest: 一番下へ + label_roadmap: ロードマップ + label_roadmap_due_in: "期日まで %{value}" + label_roadmap_overdue: "%{value} 遅れ" + label_roadmap_no_issues: このバージョンに関するチケットはありません + label_search: 検索 + label_result_plural: 結果 + label_all_words: すべての単語 + label_wiki: Wiki + label_wiki_edit: Wiki編集 + label_wiki_edit_plural: Wiki編集 + label_wiki_page: Wikiページ + label_wiki_page_plural: Wikiページ + label_index_by_title: 索引(名前順) + label_index_by_date: 索引(日付順) + label_current_version: 最新版 + label_preview: プレビュー + label_feed_plural: フィード + label_changes_details: 全変更の詳細 + label_issue_tracking: チケットトラッキング + label_spent_time: 作業時間の記録 + label_overall_spent_time: すべての作業時間の記録 + label_f_hour: "%{value}時間" + label_f_hour_plural: "%{value}時間" + label_time_tracking: 時間トラッキング + label_change_plural: 変更 + label_statistics: 統計 + label_commits_per_month: 月別のコミット + label_commits_per_author: 起票者別のコミット + label_diff: 差分 + label_view_diff: 差分を見る + label_diff_inline: インライン + label_diff_side_by_side: 横に並べる + label_options: オプション + label_copy_workflow_from: ワークフローをここからコピー + label_permissions_report: 権限レポート + label_watched_issues: ウォッチしているチケット + label_related_issues: 関連するチケット + label_applied_status: 適用されるステータス + label_loading: ロード中... + label_relation_new: 新しい関連 + label_relation_delete: 関連の削除 + label_relates_to: 関係している + label_duplicates: 重複している + label_duplicated_by: 重複されている + label_blocks: ブロックしている + label_blocked_by: ブロックされている + label_precedes: 先行する + label_follows: 後続する + label_end_to_start: 最後-最初 + label_end_to_end: 最後-最後 + label_start_to_start: 最初-最初 + label_start_to_end: 最初-最後 + label_stay_logged_in: ログインを維持 + label_disabled: 無効 + label_show_completed_versions: 完了したバージョンを表示 + label_me: 自分 + label_board: フォーラム + label_board_new: 新しいフォーラム + label_board_plural: フォーラム + label_board_sticky: スティッキー + label_board_locked: ロック + label_topic_plural: トピック + label_message_plural: メッセージ + label_message_last: 最新のメッセージ + label_message_new: 新しいメッセージ + label_message_posted: メッセージが追加されました + label_reply_plural: 返答 + label_send_information: アカウント情報をユーザに送信 + label_year: 年 + label_month: 月 + label_week: 週 + label_date_from: "日付指定: " + label_date_to: から + label_language_based: 既定の言語の設定に従う + label_sort_by: "並び替え %{value}" + label_send_test_email: テストメールを送信 + label_feeds_access_key: RSSアクセスキー + label_missing_feeds_access_key: RSSアクセスキーが見つかりません + label_feeds_access_key_created_on: "RSSアクセスキーは%{value}前に作成されました" + label_module_plural: モジュール + label_added_time_by: "%{author} が%{age}前に追加" + label_updated_time_by: "%{author} が%{age}前に更新" + label_updated_time: "%{value}前に更新" + label_jump_to_a_project: プロジェクトへ移動... + label_file_plural: ファイル + label_changeset_plural: 更新履歴 + label_default_columns: 既定の項目 + label_no_change_option: (変更無し) + label_bulk_edit_selected_issues: チケットの一括編集 + label_theme: テーマ + label_default: 既定 + label_search_titles_only: タイトルのみ + label_user_mail_option_all: "参加しているプロジェクトのすべての通知" + label_user_mail_option_selected: "選択したプロジェクトのすべての通知..." + label_user_mail_option_none: "通知しない" + label_user_mail_option_only_my_events: "ウォッチまたは関係している事柄のみ" + label_user_mail_option_only_assigned: "自分が担当している事柄のみ" + label_user_mail_option_only_owner: "自分が作成した事柄のみ" + label_user_mail_no_self_notified: 自分自身による変更の通知は不要 + label_registration_activation_by_email: メールでアカウントを有効化 + label_registration_manual_activation: 手動でアカウントを有効化 + label_registration_automatic_activation: 自動でアカウントを有効化 + label_display_per_page: "1ページに: %{value}" + label_age: 年齢 + label_change_properties: プロパティの変更 + label_general: 全般 + label_more: 続き + label_scm: バージョン管理システム + label_plugins: プラグイン + label_ldap_authentication: LDAP認証 + label_downloads_abbr: DL + label_optional_description: 任意のコメント + label_add_another_file: 別のファイルを追加 + label_preferences: 設定 + label_chronological_order: 古い順 + label_reverse_chronological_order: 新しい順 + label_planning: 計画 + label_incoming_emails: 受信メール + label_generate_key: キーの生成 + label_issue_watchers: チケットのウォッチャー + label_example: 例 + label_display: 表示 + label_sort: ソート条件 + label_ascending: 昇順 + label_descending: 降順 + label_date_from_to: "%{start}から%{end}まで" + label_wiki_content_added: Wikiページが追加されました + label_wiki_content_updated: Wikiページが更新されました + label_group: グループ + label_group_plural: グループ + label_group_new: 新しいグループ + label_time_entry_plural: 作業時間の記録 + label_version_sharing_none: 共有しない + label_version_sharing_descendants: サブプロジェクト単位 + label_version_sharing_hierarchy: プロジェクト階層単位 + label_version_sharing_tree: プロジェクトツリー単位 + label_version_sharing_system: すべてのプロジェクト + label_update_issue_done_ratios: 進捗の更新 + label_copy_source: コピー元 + label_copy_target: コピー先 + label_copy_same_as_target: 同じコピー先 + label_display_used_statuses_only: このトラッカーで使われているステータスのみ表示する + label_api_access_key: APIアクセスキー + label_missing_api_access_key: APIアクセスキーが見つかりません + label_api_access_key_created_on: "APIアクセスキーは%{value}前に作成されました" + label_subtask_plural: 子チケット + label_project_copy_notifications: コピーしたチケットのメール通知を送信する + label_principal_search: "ユーザまたはグループの検索:" + label_user_search: "ユーザの検索:" + label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する + label_parent_revision: 親 + label_child_revision: 子 + + button_login: ログイン + button_submit: 変更 + button_save: 保存 + button_check_all: すべてにチェックをつける + button_uncheck_all: すべてのチェックを外す + button_expand_all: 展開 + button_collapse_all: 折りたたみ + button_delete: 削除 + button_create: 作成 + button_create_and_continue: 連続作成 + button_test: テスト + button_edit: 編集 + button_edit_associated_wikipage: "関連するWikiページを編集: %{page_title}" + button_add: 追加 + button_change: 変更 + button_apply: 適用 + button_clear: クリア + button_lock: ロック + button_unlock: アンロック + button_download: ダウンロード + button_list: 一覧 + button_view: 見る + button_move: 移動 + button_move_and_follow: 移動後表示 + button_back: 戻る + button_cancel: キャンセル + button_activate: 有効にする + button_sort: ソート + button_log_time: 時間を記録 + button_rollback: このバージョンにロールバック + button_watch: ウォッチ + button_unwatch: ウォッチをやめる + button_reply: 返答 + button_archive: 書庫に保存 + button_unarchive: 書庫から戻す + button_reset: リセット + button_rename: 名前変更 + button_change_password: パスワード変更 + button_copy: コピー + button_copy_and_follow: コピー後表示 + button_annotate: アノテート + button_update: 更新 + button_configure: 設定 + button_quote: 引用 + button_duplicate: 複製 + button_show: 表示 + + status_active: 有効 + status_registered: 登録 + status_locked: ロック + + version_status_open: 進行中 + version_status_locked: ロック中 + version_status_closed: 終了 + + field_active: 有効 + + text_select_mail_notifications: どのメール通知を送信するか、アクションを選択してください。 + text_regexp_info: 例) ^[A-Z0-9]+$ + text_min_max_length_info: 0だと無制限になります + text_project_destroy_confirmation: 本当にこのプロジェクトと関連データを削除しますか? + text_subprojects_destroy_warning: "サブプロジェクト %{value} も削除されます。" + text_workflow_edit: ワークフローを編集するロールとトラッカーを選んでください + text_are_you_sure: よろしいですか? + text_are_you_sure_with_children: チケットとその子チケットすべてを削除しますか? + text_journal_changed: "%{label} を %{old} から %{new} に変更" + text_journal_changed_no_detail: "%{label} を更新" + text_journal_set_to: "%{label} を %{value} にセット" + text_journal_deleted: "%{label} を削除 (%{old})" + text_journal_added: "%{label} %{value} を追加" + text_tip_issue_begin_day: この日に開始するタスク + text_tip_issue_end_day: この日に終了するタスク + text_tip_issue_begin_end_day: この日のうちに開始して終了するタスク + text_project_identifier_info: '英小文字(a-z)と数字とダッシュ(-)が使えます。
    一度保存すると、識別子は変更できません。' + text_caracters_maximum: "最大%{count}文字です。" + text_caracters_minimum: "最低%{count}文字の長さが必要です" + text_length_between: "長さは%{min}から%{max}文字までです。" + text_tracker_no_workflow: このトラッカーにワークフローが定義されていません + text_unallowed_characters: 次の文字は使用できません + text_comma_separated: (カンマで区切ることで)複数の値を設定できます。 + text_line_separated: (1行ごとに書くことで)複数の値を設定できます。 + text_issues_ref_in_commit_messages: コミットメッセージ内でチケットの参照/修正 + text_issue_added: "チケット %{id} が %{author} によって報告されました。" + text_issue_updated: "チケット %{id} が %{author} によって更新されました。" + text_wiki_destroy_confirmation: 本当にこのwikiとその内容のすべてを削除しますか? + text_issue_category_destroy_question: "%{count}件のチケットがこのカテゴリに割り当てられています。" + text_issue_category_destroy_assignments: カテゴリの割り当てを削除する + text_issue_category_reassign_to: チケットをこのカテゴリに再割り当てする + text_user_mail_option: "未選択のプロジェクトでは、ウォッチまたは関係している事柄(例: 自分が報告者もしくは担当者であるチケット)のみメールが送信されます。" + text_no_configuration_data: "ロール、トラッカー、チケットのステータス、ワークフローがまだ設定されていません。\nデフォルト設定のロードを強くお勧めします。ロードした後、それを修正することができます。" + text_load_default_configuration: デフォルト設定をロード + text_status_changed_by_changeset: "更新履歴 %{value} で適用されました。" + text_time_logged_by_changeset: "更新履歴 %{value} で適用されました。" + text_issues_destroy_confirmation: '本当に選択したチケットを削除しますか?' + text_select_project_modules: 'このプロジェクトで使用するモジュールを選択してください:' + text_default_administrator_account_changed: デフォルト管理アカウントが変更済 + text_file_repository_writable: ファイルリポジトリに書き込み可能 + text_plugin_assets_writable: Plugin assetsディレクトリに書き込み可能 + text_rmagick_available: RMagickが使用可能 (オプション) + text_destroy_time_entries_question: このチケットの%{hours}時間分の作業記録の扱いを選択してください。 + text_destroy_time_entries: 記録された作業時間を含めて削除 + text_assign_time_entries_to_project: 記録された作業時間をプロジェクト自体に割り当て + text_reassign_time_entries: '記録された作業時間をこのチケットに再割り当て:' + text_user_wrote: "%{value} は書きました:" + text_enumeration_destroy_question: "%{count}個のオブジェクトがこの値に割り当てられています。" + text_enumeration_category_reassign_to: '次の値に割り当て直す:' + text_email_delivery_not_configured: "メールを送信するために必要な設定が行われていないため、メール通知は利用できません。\nconfig/configuration.ymlでSMTPサーバの設定を行い、アプリケーションを再起動してください。" + text_repository_usernames_mapping: "リポジトリのログから検出されたユーザー名をどのRedmineユーザーに関連づけるのか選択してください。\nログ上のユーザー名またはメールアドレスがRedmineのユーザーと一致する場合は自動的に関連づけられます。" + text_diff_truncated: '... 差分の行数が表示可能な上限を超えました。超過分は表示しません。' + text_custom_field_possible_values_info: '選択肢の値は1行に1個ずつ記述してください。' + text_wiki_page_destroy_question: "この親ページの配下に%{descendants}ページの子孫ページがあります。" + text_wiki_page_nullify_children: "子ページをメインページ配下に移動する" + text_wiki_page_destroy_children: "配下の子孫ページも削除する" + text_wiki_page_reassign_children: "子ページを次の親ページの配下に移動する" + text_own_membership_delete_confirmation: "一部またはすべての権限を自分自身から剥奪しようとしているため、このプロジェクトを編集できなくなる可能性があります。\n本当に続けますか?" + text_zoom_in: 拡大 + text_zoom_out: 縮小 + text_warn_on_leaving_unsaved: このページから移動すると、保存されていないデータが失われます。 + text_scm_path_encoding_note: "デフォルト: UTF-8" + text_mercurial_repository_note: "ローカルリポジトリ (例: /hgrepo, c:\\hgrepo)" + text_git_repository_note: "Bare、かつ、ローカルリポジトリ (例: /gitrepo, c:\\gitrepo)" + text_scm_command: コマンド + text_scm_command_version: バージョン + text_scm_config: バージョン管理システムのコマンドをconfig/configuration.ymlで設定できます。設定後、Redmineを再起動してください。 + text_scm_command_not_available: バージョン管理システムのコマンドが利用できません。管理画面にて設定を確認してください。 + + default_role_manager: 管理者 + default_role_developer: 開発者 + default_role_reporter: 報告者 + default_tracker_bug: バグ + default_tracker_feature: 機能 + default_tracker_support: サポート + default_issue_status_new: 新規 + default_issue_status_in_progress: 進行中 + default_issue_status_resolved: 解決 + default_issue_status_feedback: フィードバック + default_issue_status_closed: 終了 + default_issue_status_rejected: 却下 + default_doc_category_user: ユーザ文書 + default_doc_category_tech: 技術文書 + default_priority_low: 低め + default_priority_normal: 通常 + default_priority_high: 高め + default_priority_urgent: 急いで + default_priority_immediate: 今すぐ + default_activity_design: 設計作業 + default_activity_development: 開発作業 + + enumeration_issue_priorities: チケットの優先度 + enumeration_doc_categories: 文書カテゴリ + enumeration_activities: 作業分類 (時間トラッキング) + enumeration_system_activity: システム作業分類 + label_additional_workflow_transitions_for_assignee: チケット担当者に追加で許可する遷移 + label_additional_workflow_transitions_for_author: チケット作成者に追加で許可する遷移 + label_bulk_edit_selected_time_entries: 作業時間の一括編集 + text_time_entries_destroy_confirmation: 本当に選択した作業時間を削除しますか? + + label_role_anonymous: Anonymous + label_role_non_member: Non member + + label_issue_note_added: 注記が追加されました + label_issue_status_updated: ステータスが更新されました + label_issue_priority_updated: 優先度が更新されました + label_issues_visibility_own: 作成者か担当者であるチケット + field_issues_visibility: 表示できるチケット + label_issues_visibility_all: すべてのチケット + permission_set_own_issues_private: 自分のチケットをプライベートに設定 + field_is_private: プライベート + permission_set_issues_private: チケットをプライベートに設定 + label_issues_visibility_public: プライベートチケット以外 + text_issues_destroy_descendants_confirmation: "%{count}個の子チケットも削除されます。" + notice_issue_successful_create: チケット %{id} が作成されました。 + label_between: 次の範囲内 + setting_issue_group_assignment: グループへのチケット割り当てを許可 + description_query_sort_criteria_direction: 順序 + description_project_scope: 検索範囲 + description_filter: Filter + description_user_mail_notification: メール通知の設定 + description_date_from: 開始日 + description_message_content: 内容 + description_available_columns: 利用できる項目 + description_date_range_interval: 日付で指定 + description_issue_category_reassign: 新しいカテゴリを選択してください + description_search: 検索キーワード + description_notes: 注記 + description_date_range_list: 一覧から選択 + description_choose_project: プロジェクト + description_date_to: 終了日 + description_query_sort_criteria_attribute: 項目 + description_wiki_subpages_reassign: 新しい親ページを選択してください + description_selected_columns: 選択された項目 + error_scm_annotate_big_text_file: テキストファイルサイズの上限を超えているためアノテートできません。 + setting_default_issue_start_date_to_creation_date: 現在の日付を新しいチケットの開始日とする + button_edit_section: このセクションを編集 + description_all_columns: すべての項目 + button_export: エクスポート + label_export_options: "%{export_format} エクスポート設定" + error_attachment_too_big: このファイルはアップロードできません。添付ファイルサイズの上限(%{max_size})を超えています。 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c6b86dc69f620a96ac6d188516e2403c6f257c84.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c6b86dc69f620a96ac6d188516e2403c6f257c84.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,182 @@ +require 'rubygems' + +Gem::manage_gems + +require 'rake/rdoctask' +require 'rake/packagetask' +require 'rake/gempackagetask' +require 'rake/testtask' +require 'rake/contrib/rubyforgepublisher' + +PKG_NAME = 'acts_as_versioned' +PKG_VERSION = '0.3.1' +PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" +PROD_HOST = "technoweenie@bidwell.textdrive.com" +RUBY_FORGE_PROJECT = 'ar-versioned' +RUBY_FORGE_USER = 'technoweenie' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the calculations plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the calculations plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models" + rdoc.options << '--line-numbers --inline-source' + rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +spec = Gem::Specification.new do |s| + s.name = PKG_NAME + s.version = PKG_VERSION + s.platform = Gem::Platform::RUBY + s.summary = "Simple versioning with active record models" + s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS) + s.files.delete "acts_as_versioned_plugin.sqlite.db" + s.files.delete "acts_as_versioned_plugin.sqlite3.db" + s.files.delete "test/debug.log" + s.require_path = 'lib' + s.autorequire = 'acts_as_versioned' + s.has_rdoc = true + s.test_files = Dir['test/**/*_test.rb'] + s.add_dependency 'activerecord', '>= 1.10.1' + s.add_dependency 'activesupport', '>= 1.1.1' + s.author = "Rick Olson" + s.email = "technoweenie@gmail.com" + s.homepage = "http://techno-weenie.net" +end + +Rake::GemPackageTask.new(spec) do |pkg| + pkg.need_tar = true +end + +desc "Publish the API documentation" +task :pdoc => [:rdoc] do + Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload +end + +desc 'Publish the gem and API docs' +task :publish => [:pdoc, :rubyforge_upload] + +desc "Publish the release files to RubyForge." +task :rubyforge_upload => :package do + files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" } + + if RUBY_FORGE_PROJECT then + require 'net/http' + require 'open-uri' + + project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/" + project_data = open(project_uri) { |data| data.read } + group_id = project_data[/[?&]group_id=(\d+)/, 1] + raise "Couldn't get group id" unless group_id + + # This echos password to shell which is a bit sucky + if ENV["RUBY_FORGE_PASSWORD"] + password = ENV["RUBY_FORGE_PASSWORD"] + else + print "#{RUBY_FORGE_USER}@rubyforge.org's password: " + password = STDIN.gets.chomp + end + + login_response = Net::HTTP.start("rubyforge.org", 80) do |http| + data = [ + "login=1", + "form_loginname=#{RUBY_FORGE_USER}", + "form_pw=#{password}" + ].join("&") + http.post("/account/login.php", data) + end + + cookie = login_response["set-cookie"] + raise "Login failed" unless cookie + headers = { "Cookie" => cookie } + + release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}" + release_data = open(release_uri, headers) { |data| data.read } + package_id = release_data[/[?&]package_id=(\d+)/, 1] + raise "Couldn't get package id" unless package_id + + first_file = true + release_id = "" + + files.each do |filename| + basename = File.basename(filename) + file_ext = File.extname(filename) + file_data = File.open(filename, "rb") { |file| file.read } + + puts "Releasing #{basename}..." + + release_response = Net::HTTP.start("rubyforge.org", 80) do |http| + release_date = Time.now.strftime("%Y-%m-%d %H:%M") + type_map = { + ".zip" => "3000", + ".tgz" => "3110", + ".gz" => "3110", + ".gem" => "1400" + }; type_map.default = "9999" + type = type_map[file_ext] + boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor" + + query_hash = if first_file then + { + "group_id" => group_id, + "package_id" => package_id, + "release_name" => PKG_FILE_NAME, + "release_date" => release_date, + "type_id" => type, + "processor_id" => "8000", # Any + "release_notes" => "", + "release_changes" => "", + "preformatted" => "1", + "submit" => "1" + } + else + { + "group_id" => group_id, + "release_id" => release_id, + "package_id" => package_id, + "step2" => "1", + "type_id" => type, + "processor_id" => "8000", # Any + "submit" => "Add This File" + } + end + + query = "?" + query_hash.map do |(name, value)| + [name, URI.encode(value)].join("=") + end.join("&") + + data = [ + "--" + boundary, + "Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"", + "Content-Type: application/octet-stream", + "Content-Transfer-Encoding: binary", + "", file_data, "" + ].join("\x0D\x0A") + + release_headers = headers.merge( + "Content-Type" => "multipart/form-data; boundary=#{boundary}" + ) + + target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php" + http.post(target + query, data, release_headers) + end + + if first_file then + release_id = release_response.body[/release_id=(\d+)/, 1] + raise("Couldn't get release id") unless release_id + end + + first_file = false + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c6/c6ff1374312284d6c1b8200e5a3e6f1fba439441.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c6/c6ff1374312284d6c1b8200e5a3e6f1fba439441.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,112 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 WikiFormatting + class StaleSectionError < Exception; end + + @@formatters = {} + + class << self + def map + yield self + end + + def register(name, formatter, helper) + raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_s] + @@formatters[name.to_s] = {:formatter => formatter, :helper => helper} + end + + def formatter + formatter_for(Setting.text_formatting) + end + + def formatter_for(name) + entry = @@formatters[name.to_s] + (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter + end + + def helper_for(name) + entry = @@formatters[name.to_s] + (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper + end + + def format_names + @@formatters.keys.map + end + + def to_html(format, text, options = {}) + text = if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, options[:object], options[:attribute]) + # Text retrieved from the cache store may be frozen + # We need to dup it so we can do in-place substitutions with gsub! + cache_store.fetch cache_key do + formatter_for(format).new(text).to_html + end.dup + else + formatter_for(format).new(text).to_html + end + text + end + + # Returns true if the text formatter supports single section edit + def supports_section_edit? + (formatter.instance_methods & ['update_section', :update_section]).any? + end + + # Returns a cache key for the given text +format+, +object+ and +attribute+ or nil if no caching should be done + def cache_key_for(format, object, attribute) + if object && attribute && !object.new_record? && object.respond_to?(:updated_on) && !format.blank? + "formatted_text/#{format}/#{object.class.model_name.cache_key}/#{object.id}-#{attribute}-#{object.updated_on.to_s(:number)}" + end + end + + # Returns the cache store used to cache HTML output + def cache_store + ActionController::Base.cache_store + end + end + + # Default formatter module + module NullFormatter + class Formatter + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TextHelper + include ActionView::Helpers::UrlHelper + + def initialize(text) + @text = text + end + + def to_html(*args) + simple_format(auto_link(CGI::escapeHTML(@text))) + end + end + + module Helper + def wikitoolbar_for(field_id) + end + + def heads_for_wiki_formatter + end + + def initial_page_content(page) + page.pretty_title.to_s + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c71482bf089794bd794cdd7fd0ac71e100b04b51.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c71482bf089794bd794cdd7fd0ac71e100b04b51.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +<%= l(:mail_body_register) %> +<%= @url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c7478ec9fe0088baa4bd4e0b03aab480956ab36b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c7478ec9fe0088baa4bd4e0b03aab480956ab36b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +class CreateChanges < ActiveRecord::Migration + def self.up + create_table :changes do |t| + t.column :changeset_id, :integer, :null => false + t.column :action, :string, :limit => 1, :default => "", :null => false + t.column :path, :string, :default => "", :null => false + t.column :from_path, :string + t.column :from_revision, :integer + end + add_index :changes, [:changeset_id], :name => :changesets_changeset_id + end + + def self.down + drop_table :changes + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c74e11d7cd6b9dd238099928581d6b72f92ee155.svn-base Binary file .svn/pristine/c7/c74e11d7cd6b9dd238099928581d6b72f92ee155.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c767e59ba9a302d7263fb3fbb0ffcd078888d13a.svn-base Binary file .svn/pristine/c7/c767e59ba9a302d7263fb3fbb0ffcd078888d13a.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c77ac5664a51030570530480da86c95e1084dfb0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c77ac5664a51030570530480da86c95e1084dfb0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 CalendarsHelper + def link_to_previous_month(year, month, options={}) + target_year, target_month = if month == 1 + [year - 1, 12] + else + [year, month - 1] + end + + name = if target_month == 12 + "#{month_name(target_month)} #{target_year}" + else + "#{month_name(target_month)}" + end + + # \xc2\xab(utf-8) = « + link_to_month(("\xc2\xab " + name), target_year, target_month, options) + end + + def link_to_next_month(year, month, options={}) + target_year, target_month = if month == 12 + [year + 1, 1] + else + [year, month + 1] + end + + name = if target_month == 1 + "#{month_name(target_month)} #{target_year}" + else + "#{month_name(target_month)}" + end + + # \xc2\xbb(utf-8) = » + link_to_month((name + " \xc2\xbb"), target_year, target_month, options) + end + + def link_to_month(link_name, year, month, options={}) + link_to_content_update(h(link_name), params.merge(:year => year, :month => month)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c7847076c2df1da6c67e052fc800303ce438f4c9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c7847076c2df1da6c67e052fc800303ce438f4c9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1003 @@ +sk: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Nedeľa, Pondelok, Utorok, Streda, Štvrtok, Piatok, Sobota] + abbr_day_names: [Ne, Po, Ut, St, Št, Pi, So] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Január, Február, Marec, Apríl, Máj, Jún, Júl, August, September, Október, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Máj, Jún, Júl, Aug, Sep, Okt, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pol minúty" + less_than_x_seconds: + one: "menej ako 1 sekunda" + other: "menej ako %{count} sekúnd" + x_seconds: + one: "1 sekunda" + other: "%{count} sekúnd" + less_than_x_minutes: + one: "menej ako minúta" + other: "menej ako %{count} minút" + x_minutes: + one: "1 minuta" + other: "%{count} minút" + about_x_hours: + one: "okolo 1 hodiny" + other: "okolo %{count} hodín" + x_days: + one: "1 deň" + other: "%{count} dní" + about_x_months: + one: "okolo 1 mesiaca" + other: "okolo %{count} mesiace/ov" + x_months: + one: "1 mesiac" + other: "%{count} mesiace/ov" + about_x_years: + one: "okolo 1 roka" + other: "okolo %{count} roky/ov" + over_x_years: + one: "cez 1 rok" + other: "cez %{count} roky/ov" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + human: + format: + precision: 1 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "a" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nieje zahrnuté v zozname" + exclusion: "je rezervované" + invalid: "je neplatné" + confirmation: "sa nezhoduje s potvrdením" + accepted: "musí byť akceptované" + empty: "nemôže byť prázdne" + blank: "nemôže byť prázdne" + too_long: "je príliš dlhé" + too_short: "je príliš krátke" + wrong_length: "má chybnú dĺžku" + taken: "je už použité" + not_a_number: "nieje číslo" + not_a_date: "nieje platný dátum" + greater_than: "musí byť väčšíe ako %{count}" + greater_than_or_equal_to: "musí byť väčšie alebo rovné %{count}" + equal_to: "musí byť rovné %{count}" + less_than: "musí byť menej ako %{count}" + less_than_or_equal_to: "musí byť menej alebo rovné %{count}" + odd: "musí byť nepárne" + even: "musí byť párne" + greater_than_start_date: "musí byť neskôr ako počiatočný dátum" + not_same_project: "nepatrí rovnakému projektu" + circular_dependency: "Tento vzťah by vytvoril cyklickú závislosť" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + # SK translation by Stanislav Pach | stano.pach@seznam.cz + + actionview_instancetag_blank_option: Prosím vyberte + + general_text_No: 'Nie' + general_text_Yes: 'Áno' + general_text_no: 'nie' + general_text_yes: 'áno' + general_lang_name: 'Slovenčina' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Účet bol úspešne zmenený. + notice_account_invalid_creditentials: Chybné meno alebo heslo + notice_account_password_updated: Heslo bolo úspešne zmenené. + notice_account_wrong_password: Chybné heslo + notice_account_register_done: Účet bol úspešne vytvorený. Pre aktiváciu účtu kliknite na odkaz v emailu, ktorý vam bol zaslaný. + notice_account_unknown_email: Neznámy užívateľ. + notice_can_t_change_password: Tento účet používa externú autentifikáciu. Tu heslo zmeniť nemôžete. + notice_account_lost_email_sent: Bol vám zaslaný email s inštrukciami ako si nastavite nové heslo. + notice_account_activated: Váš účet bol aktivovaný. Teraz se môžete prihlásiť. + notice_successful_create: Úspešne vytvorené. + notice_successful_update: Úspešne aktualizované. + notice_successful_delete: Úspešne odstránené. + notice_successful_connection: Úspešne pripojené. + notice_file_not_found: Stránka, ktorú se snažíte zobraziť, neexistuje alebo bola zmazaná. + notice_locking_conflict: Údaje boli zmenené iným užívateľom. + notice_scm_error: Položka a/alebo revízia neexistuje v repozitári. + notice_not_authorized: Nemáte dostatočné práva pre zobrazenie tejto stránky. + notice_email_sent: "Na adresu %{value} bol odeslaný email" + notice_email_error: "Pri odosielaní emailu nastala chyba (%{value})" + notice_feeds_access_key_reseted: Váš klúč pre prístup k Atomu bol resetovaný. + notice_failed_to_save_issues: "Nastala chyba pri ukládaní %{count} úloh na %{total} zvolený: %{ids}." + notice_no_issue_selected: "Nebola zvolená žiadná úloha. Prosím, zvoľte úlohy, ktoré chcete upraviť" + notice_account_pending: "Váš účet bol vytvorený, teraz čaká na schválenie administrátorom." + notice_default_data_loaded: Výchozia konfigurácia úspešne nahraná. + + error_can_t_load_default_data: "Výchozia konfigurácia nebola nahraná: %{value}" + error_scm_not_found: "Položka a/alebo revízia neexistuje v repozitári." + error_scm_command_failed: "Pri pokuse o prístup k repozitári došlo k chybe: %{value}" + error_issue_not_found_in_project: 'Úloha nebola nájdená alebo nepatrí k tomuto projektu' + + mail_subject_lost_password: "Vaše heslo (%{value})" + mail_body_lost_password: 'Pre zmenu vašeho hesla kliknite na následujúci odkaz:' + mail_subject_register: "Aktivácia účtu (%{value})" + mail_body_register: 'Pre aktiváciu vašeho účtu kliknite na následujúci odkaz:' + mail_body_account_information_external: "Pomocou vašeho účtu %{value} se môžete prihlásiť." + mail_body_account_information: Informácie o vašom účte + mail_subject_account_activation_request: "Aktivácia %{value} účtu" + mail_body_account_activation_request: "Bol zaregistrovaný nový uživateľ %{value}. Aktivácia jeho účtu závisí na vašom potvrdení." + + gui_validation_error: 1 chyba + gui_validation_error_plural: "%{count} chyb(y)" + + field_name: Názov + field_description: Popis + field_summary: Prehľad + field_is_required: Povinné pole + field_firstname: Meno + field_lastname: Priezvisko + field_mail: Email + field_filename: Súbor + field_filesize: Veľkosť + field_downloads: Stiahnuté + field_author: Autor + field_created_on: Vytvorené + field_updated_on: Aktualizované + field_field_format: Formát + field_is_for_all: Pre všetky projekty + field_possible_values: Možné hodnoty + field_regexp: Regulérny výraz + field_min_length: Minimálna dĺžka + field_max_length: Maximálna dĺžka + field_value: Hodnota + field_category: Kategória + field_title: Názov + field_project: Projekt + field_issue: Úloha + field_status: Stav + field_notes: Poznámka + field_is_closed: Úloha uzavretá + field_is_default: Východzí stav + field_tracker: Fronta + field_subject: Predmet + field_due_date: Uzavrieť do + field_assigned_to: Priradené + field_priority: Priorita + field_fixed_version: Priradené k verzii + field_user: Užívateľ + field_role: Rola + field_homepage: Domovská stránka + field_is_public: Verejný + field_parent: Nadradený projekt + field_is_in_roadmap: Úlohy zobrazené v pláne + field_login: Login + field_mail_notification: Emailové oznámenie + field_admin: Administrátor + field_last_login_on: Posledné prihlásenie + field_language: Jazyk + field_effective_date: Dátum + field_password: Heslo + field_new_password: Nové heslo + field_password_confirmation: Potvrdenie + field_version: Verzia + field_type: Typ + field_host: Host + field_port: Port + field_account: Účet + field_base_dn: Base DN + field_attr_login: Prihlásenie (atribut) + field_attr_firstname: Meno (atribut) + field_attr_lastname: Priezvisko (atribut) + field_attr_mail: Email (atribut) + field_onthefly: Automatické vytváranie užívateľov + field_start_date: Začiatok + field_done_ratio: "% hotovo" + field_auth_source: Autentifikačný mód + field_hide_mail: Nezobrazovať môj email + field_comments: Komentár + field_url: URL + field_start_page: Výchozia stránka + field_subproject: Podprojekt + field_hours: Hodiny + field_activity: Aktivita + field_spent_on: Dátum + field_identifier: Identifikátor + field_is_filter: Použiť ako filter + field_issue_to: Súvisiaca úloha + field_delay: Oneskorenie + field_assignable: Úlohy môžu byť priradené tejto roli + field_redirect_existing_links: Presmerovať existujúce odkazy + field_estimated_hours: Odhadovaná doba + field_column_names: Stĺpce + field_time_zone: Časové pásmo + field_searchable: Umožniť vyhľadávanie + field_default_value: Východzia hodnota + field_comments_sorting: Zobraziť komentáre + + setting_app_title: Názov aplikácie + setting_app_subtitle: Podtitulok aplikácie + setting_welcome_text: Uvítací text + setting_default_language: Východzí jazyk + setting_login_required: Auten. vyžadovaná + setting_self_registration: Povolenie registrácie + setting_attachment_max_size: Maximálna veľkosť prílohy + setting_issues_export_limit: Limit pre export úloh + setting_mail_from: Odosielať emaily z adresy + setting_bcc_recipients: Príjemcovia skrytej kópie (bcc) + setting_host_name: Hostname + setting_text_formatting: Formátovanie textu + setting_wiki_compression: Kompresia histórie Wiki + setting_feeds_limit: Limit zobrazených položiek (Atom feed) + setting_default_projects_public: Nové projekty nastavovať ako verejné + setting_autofetch_changesets: Automatický prenos zmien + setting_sys_api_enabled: Povolit Webovú Službu (WS) pre správu repozitára + setting_commit_ref_keywords: Klúčové slová pre odkazy + setting_commit_fix_keywords: Klúčové slová pre uzavretie + setting_autologin: Automatické prihlasovanie + setting_date_format: Formát dátumu + setting_time_format: Formát času + setting_cross_project_issue_relations: Povoliť väzby úloh skrz projekty + setting_issue_list_default_columns: Východzie stĺpce zobrazené v zozname úloh + setting_ itories_encodings: Kódovanie + setting_emails_footer: Zapätie emailov + setting_protocol: Protokol + setting_per_page_options: Povolené množstvo riadkov na stránke + setting_user_format: Formát zobrazenia užívateľa + setting_activity_days_default: "Zobrazené dni aktivity projektu:" + setting_display_subprojects_issues: Prednastavenie zobrazenia úloh podporojektov v hlavnom projekte + + project_module_issue_tracking: Sledovanie úloh + project_module_time_tracking: Sledovanie času + project_module_news: Novinky + project_module_documents: Dokumenty + project_module_files: Súbory + project_module_wiki: Wiki + project_module_repository: Repozitár + project_module_boards: Diskusie + + label_user: Užívateľ + label_user_plural: Užívatelia + label_user_new: Nový užívateľ + label_project: Projekt + label_project_new: Nový projekt + label_project_plural: Projekty + label_x_projects: + zero: žiadne projekty + one: 1 projekt + other: "%{count} projekty/ov" + label_project_all: Všetky projekty + label_project_latest: Posledné projekty + label_issue: Úloha + label_issue_new: Nová úloha + label_issue_plural: Úlohy + label_issue_view_all: Všetky úlohy + label_issues_by: "Úlohy od užívateľa %{value}" + label_issue_added: Úloha pridaná + label_issue_updated: Úloha aktualizovaná + label_document: Dokument + label_document_new: Nový dokument + label_document_plural: Dokumenty + label_document_added: Dokument pridaný + label_role: Rola + label_role_plural: Role + label_role_new: Nová rola + label_role_and_permissions: Role a práva + label_member: Člen + label_member_new: Nový člen + label_member_plural: Členovia + label_tracker: Fronta + label_tracker_plural: Fronty + label_tracker_new: Nová fronta + label_workflow: Workflow + label_issue_status: Stav úloh + label_issue_status_plural: Stavy úloh + label_issue_status_new: Nový stav + label_issue_category: Kategória úloh + label_issue_category_plural: Kategórie úloh + label_issue_category_new: Nová kategória + label_custom_field: Užívateľské pole + label_custom_field_plural: Užívateľské polia + label_custom_field_new: Nové užívateľské pole + label_enumerations: Zoznamy + label_enumeration_new: Nová hodnota + label_information: Informácia + label_information_plural: Informácie + label_please_login: Prosím prihláste sa + label_register: Registrovať + label_password_lost: Zabudnuté heslo + label_home: Domovská stránka + label_my_page: Moja stránka + label_my_account: Môj účet + label_my_projects: Moje projekty + label_administration: Administrácia + label_login: Prihlásenie + label_logout: Odhlásenie + label_help: Nápoveda + label_reported_issues: Nahlásené úlohy + label_assigned_to_me_issues: Moje úlohy + label_last_login: Posledné prihlásenie + label_registered_on: Registrovaný + label_activity: Aktivita + label_overall_activity: Celková aktivita + label_new: Nový + label_logged_as: Prihlásený ako + label_environment: Prostredie + label_authentication: Autentifikácia + label_auth_source: Mód autentifikácie + label_auth_source_new: Nový mód autentifikácie + label_auth_source_plural: Módy autentifikácie + label_subproject_plural: Podprojekty + label_min_max_length: Min - Max dĺžka + label_list: Zoznam + label_date: Dátum + label_integer: Celé číslo + label_float: Desatinné číslo + label_boolean: Áno/Nie + label_string: Text + label_text: Dlhý text + label_attribute: Atribut + label_attribute_plural: Atributy + label_download: "%{count} Download" + label_download_plural: "%{count} Downloady" + label_no_data: Žiadné položky + label_change_status: Zmeniť stav + label_history: História + label_attachment: Súbor + label_attachment_new: Nový súbor + label_attachment_delete: Odstrániť súbor + label_attachment_plural: Súbory + label_file_added: Súbor pridaný + label_report: Prehľad + label_report_plural: Prehľady + label_news: Novinky + label_news_new: Pridať novinku + label_news_plural: Novinky + label_news_latest: Posledné novinky + label_news_view_all: Zobrazit všetky novinky + label_news_added: Novinka pridaná + label_settings: Nastavenie + label_overview: Prehľad + label_version: Verzia + label_version_new: Nová verzia + label_version_plural: Verzie + label_confirmation: Potvrdenie + label_export_to: 'Tiež k dispozícií:' + label_read: Načíta sa... + label_public_projects: Verejné projekty + label_open_issues: Otvorený + label_open_issues_plural: Otvorené + label_closed_issues: Uzavrený + label_closed_issues_plural: Uzavrené + label_x_open_issues_abbr_on_total: + zero: 0 otvorených z celkovo %{total} + one: 1 otvorený z celkovo %{total} + other: "%{count} otvorené/ých z celkovo %{total}" + label_x_open_issues_abbr: + zero: 0 otvorených + one: 1 otvorený + other: "%{count} otvorené/ých" + label_x_closed_issues_abbr: + zero: 0 zavretých + one: 1 zavretý + other: "%{count} zavreté/ých" + label_total: Celkovo + label_permissions: Práva + label_current_status: Aktuálny stav + label_new_statuses_allowed: Nové povolené stavy + label_all: všetko + label_none: nič + label_nobody: nikto + label_next: Ďalší + label_previous: Predchádzajúci + label_used_by: Použité + label_details: Detaily + label_add_note: Pridať poznámku + label_per_page: Na stránku + label_calendar: Kalendár + label_months_from: mesiacov od + label_gantt: Ganttov graf + label_internal: Interný + label_last_changes: "posledných %{count} zmien" + label_change_view_all: Zobraziť všetky zmeny + label_personalize_page: Prispôsobiť túto stránku + label_comment: Komentár + label_comment_plural: Komentáre + label_x_comments: + zero: žiaden komentár + one: 1 komentár + other: "%{count} komentáre/ov" + label_comment_add: Pridať komentár + label_comment_added: Komentár pridaný + label_comment_delete: Odstrániť komentár + label_query: Užívateľský dotaz + label_query_plural: Užívateľské dotazy + label_query_new: Nový dotaz + label_filter_add: Pridať filter + label_filter_plural: Filtre + label_equals: je + label_not_equals: nieje + label_in_less_than: je menší ako + label_in_more_than: je väčší ako + label_in: v + label_today: dnes + label_all_time: vždy + label_yesterday: včera + label_this_week: tento týždeň + label_last_week: minulý týždeň + label_last_n_days: "posledných %{count} dní" + label_this_month: tento mesiac + label_last_month: minulý mesiac + label_this_year: tento rok + label_date_range: Časový rozsah + label_less_than_ago: pred menej ako (dňami) + label_more_than_ago: pred viac ako (dňami) + label_ago: pred (dňami) + label_contains: obsahuje + label_not_contains: neobsahuje + label_day_plural: dní + label_repository: Repozitár + label_repository_plural: Repozitáre + label_browse: Prechádzať + label_modification: "%{count} zmena" + label_modification_plural: "%{count} zmien" + label_revision: Revízia + label_revision_plural: Revízií + label_associated_revisions: Súvisiace verzie + label_added: pridané + label_modified: zmenené + label_deleted: odstránené + label_latest_revision: Posledná revízia + label_latest_revision_plural: Posledné revízie + label_view_revisions: Zobraziť revízie + label_max_size: Maximálna veľkosť + label_sort_highest: Presunúť na začiatok + label_sort_higher: Presunúť navrch + label_sort_lower: Presunúť dole + label_sort_lowest: Presunúť na koniec + label_roadmap: Plán + label_roadmap_due_in: "Zostáva %{value}" + label_roadmap_overdue: "%{value} neskoro" + label_roadmap_no_issues: Pre túto verziu niesú žiadne úlohy + label_search: Hľadať + label_result_plural: Výsledky + label_all_words: Všetky slova + label_wiki: Wiki + label_wiki_edit: Wiki úprava + label_wiki_edit_plural: Wiki úpravy + label_wiki_page: Wiki stránka + label_wiki_page_plural: Wiki stránky + label_index_by_title: Index podľa názvu + label_index_by_date: Index podľa dátumu + label_current_version: Aktuálna verzia + label_preview: Náhľad + label_feed_plural: Príspevky + label_changes_details: Detail všetkých zmien + label_issue_tracking: Sledovanie úloh + label_spent_time: Strávený čas + label_f_hour: "%{value} hodina" + label_f_hour_plural: "%{value} hodín" + label_time_tracking: Sledovánie času + label_change_plural: Zmeny + label_statistics: Štatistiky + label_commits_per_month: Úkony za mesiac + label_commits_per_author: Úkony podľa autora + label_view_diff: Zobrazit rozdiely + label_diff_inline: vo vnútri + label_diff_side_by_side: vedľa seba + label_options: Nastavenie + label_copy_workflow_from: Kopírovať workflow z + label_permissions_report: Prehľad práv + label_watched_issues: Sledované úlohy + label_related_issues: Súvisiace úlohy + label_applied_status: Použitý stav + label_loading: Nahrávam ... + label_relation_new: Nová súvislosť + label_relation_delete: Odstrániť súvislosť + label_relates_to: súvisiací s + label_duplicates: duplicity + label_blocks: blokovaný + label_blocked_by: zablokovaný + label_precedes: predcháza + label_follows: následuje + label_end_to_start: od konca na začiatok + label_end_to_end: od konca do konca + label_start_to_start: od začiatku do začiatku + label_start_to_end: od začiatku do konca + label_stay_logged_in: Zostať prihlásený + label_disabled: zakazané + label_show_completed_versions: Ukázať dokončené verzie + label_me: ja + label_board: Fórum + label_board_new: Nové fórum + label_board_plural: Fóra + label_topic_plural: Témy + label_message_plural: Správy + label_message_last: Posledná správa + label_message_new: Nová správa + label_message_posted: Správa pridaná + label_reply_plural: Odpovede + label_send_information: Zaslať informácie o účte užívateľa + label_year: Rok + label_month: Mesiac + label_week: Týžden + label_date_from: Od + label_date_to: Do + label_language_based: Podľa výchozieho jazyka + label_sort_by: "Zoradenie podľa %{value}" + label_send_test_email: Poslať testovací email + label_feeds_access_key_created_on: "Prístupový klúč pre RSS bol vytvorený pred %{value}" + label_module_plural: Moduly + label_added_time_by: "Pridané užívateľom %{author} pred %{age}" + label_updated_time: "Aktualizované pred %{value}" + label_jump_to_a_project: Zvoliť projekt... + label_file_plural: Súbory + label_changeset_plural: Sady zmien + label_default_columns: Východzie stĺpce + label_no_change_option: (bez zmeny) + label_bulk_edit_selected_issues: Skupinová úprava vybraných úloh + label_theme: Téma + label_default: Východzí + label_search_titles_only: Vyhľadávať iba v názvoch + label_user_mail_option_all: "Pre všetky události všetkých mojích projektov" + label_user_mail_option_selected: "Pre všetky události vybraných projektov" + label_user_mail_no_self_notified: "Nezasielať informácie o mnou vytvorených zmenách" + label_registration_activation_by_email: aktivácia účtu emailom + label_registration_manual_activation: manuálna aktivácia účtu + label_registration_automatic_activation: automatická aktivácia účtu + label_display_per_page: "%{value} na stránku" + label_age: Vek + label_change_properties: Zmeniť vlastnosti + label_general: Všeobecné + label_more: Viac + label_scm: SCM + label_plugins: Pluginy + label_ldap_authentication: Autentifikácia LDAP + label_downloads_abbr: D/L + label_optional_description: Voliteľný popis + label_add_another_file: Pridať ďaľší súbor + label_preferences: Nastavenia + label_chronological_order: V chronologickom poradí + label_reverse_chronological_order: V obrátenom chronologickom poradí + + button_login: Prihlásiť + button_submit: Potvrdiť + button_save: Uložiť + button_check_all: Označiť všetko + button_uncheck_all: Odznačiť všetko + button_delete: Odstrániť + button_create: Vytvoriť + button_test: Test + button_edit: Upraviť + button_add: Pridať + button_change: Zmeniť + button_apply: Použiť + button_clear: Zmazať + button_lock: Zamknúť + button_unlock: Odomknúť + button_download: Stiahnúť + button_list: Vypísať + button_view: Zobraziť + button_move: Presunúť + button_back: Naspäť + button_cancel: Storno + button_activate: Aktivovať + button_sort: Zoradenie + button_log_time: Pridať čas + button_rollback: Naspäť k tejto verzii + button_watch: Sledovať + button_unwatch: Nesledovať + button_reply: Odpovedať + button_archive: Archivovať + button_unarchive: Odarchivovať + button_reset: Reset + button_rename: Premenovať + button_change_password: Zmeniť heslo + button_copy: Kopírovať + button_annotate: Komentovať + button_update: Aktualizovať + button_configure: Konfigurovať + + status_active: aktívny + status_registered: registrovaný + status_locked: uzamknutý + + text_select_mail_notifications: Vyberte akciu, pri ktorej bude zaslané upozornenie emailom + text_regexp_info: napr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znamená bez limitu + text_project_destroy_confirmation: Ste si istý, že chcete odstránit tento projekt a všetky súvisiace dáta ? + text_workflow_edit: Vyberte rolu a frontu k úprave workflow + text_are_you_sure: Ste si istý? + text_tip_issue_begin_day: úloha začína v tento deň + text_tip_issue_end_day: úloha končí v tento deň + text_tip_issue_begin_end_day: úloha začína a končí v tento deň + text_project_identifier_info: 'Povolené znaky sú malé písmena (a-z), čísla a pomlčka.
    Po uložení už nieje možné identifikátor zmeniť.' + text_caracters_maximum: "%{count} znakov maximálne." + text_caracters_minimum: "Musí byť aspoň %{count} znaky/ov dlhé." + text_length_between: "Dĺžka medzi %{min} až %{max} znakmi." + text_tracker_no_workflow: Pre tuto frontu nieje definovaný žiadný workflow + text_unallowed_characters: Nepovolené znaky + text_comma_separated: Je povolené viacero hodnôt (oddelené navzájom čiarkou). + text_issues_ref_in_commit_messages: Odkazovať a upravovať úlohy v správach s následovnym obsahom + text_issue_added: "úloha %{id} bola vytvorená užívateľom %{author}." + text_issue_updated: "Úloha %{id} byla aktualizovaná užívateľom %{author}." + text_wiki_destroy_confirmation: Naozaj si prajete odstrániť túto Wiki a celý jej obsah? + text_issue_category_destroy_question: "Niektoré úlohy (%{count}) sú priradené k tejto kategórii. Čo chtete s nimi spraviť?" + text_issue_category_destroy_assignments: Zrušiť priradenie ku kategórii + text_issue_category_reassign_to: Priradiť úlohy do tejto kategórie + text_user_mail_option: "U projektov, které neboli vybrané, budete dostávať oznamenie iba o vašich či o sledovaných položkách (napr. o položkách, ktorých ste autor, alebo ku ktorým ste priradený/á)." + text_no_configuration_data: "Role, fronty, stavy úloh ani workflow neboli zatiaľ nakonfigurované.\nVelmi doporučujeme nahrať východziu konfiguráciu. Potom si môžete všetko upraviť" + text_load_default_configuration: Nahrať východziu konfiguráciu + text_status_changed_by_changeset: "Aktualizované v sade zmien %{value}." + text_issues_destroy_confirmation: 'Naozaj si prajete odstrániť všetky zvolené úlohy?' + text_select_project_modules: 'Aktivne moduly v tomto projekte:' + text_default_administrator_account_changed: Zmenené výchozie nastavenie administrátorského účtu + text_file_repository_writable: Povolený zápis do repozitára + text_rmagick_available: RMagick k dispozícií (voliteľné) + text_destroy_time_entries_question: U úloh, které chcete odstraniť, je evidované %.02f práce. Čo chcete vykonať? + text_destroy_time_entries: Odstrániť evidované hodiny. + text_assign_time_entries_to_project: Priradiť evidované hodiny projektu + text_reassign_time_entries: 'Preradiť evidované hodiny k tejto úlohe:' + + default_role_manager: Manažér + default_role_developer: Vývojár + default_role_reporter: Reportér + default_tracker_bug: Chyba + default_tracker_feature: Rozšírenie + default_tracker_support: Podpora + default_issue_status_new: Nový + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Vyriešený + default_issue_status_feedback: Čaká sa + default_issue_status_closed: Uzavrený + default_issue_status_rejected: Odmietnutý + default_doc_category_user: Užívateľská dokumentácia + default_doc_category_tech: Technická dokumentácia + default_priority_low: Nízká + default_priority_normal: Normálna + default_priority_high: Vysoká + default_priority_urgent: Urgentná + default_priority_immediate: Okamžitá + default_activity_design: Design + default_activity_development: Vývoj + + enumeration_issue_priorities: Priority úloh + enumeration_doc_categories: Kategorie dokumentov + enumeration_activities: Aktivity (sledovanie času) + error_scm_annotate: "Položka neexistuje alebo nemôže byť komentovaná." + label_planning: Plánovanie + text_subprojects_destroy_warning: "Jeho podprojekt(y): %{value} budú takisto vymazané." + label_and_its_subprojects: "%{value} a jeho podprojekty" + mail_body_reminder: "%{count} úloha(y), ktorá(é) je(sú) vám priradený(é), ma(jú) byť hotova(é) za %{days} dní:" + mail_subject_reminder: "%{count} úloha(y) ma(jú) byť hotova(é) za pár %{days} dní" + text_user_wrote: "%{value} napísal:" + label_duplicated_by: duplikovaný + setting_enabled_scm: Zapnúť SCM + text_enumeration_category_reassign_to: 'Prenastaviť na túto hodnotu:' + text_enumeration_destroy_question: "%{count} objekty sú nastavené na túto hodnotu." + label_incoming_emails: Príchádzajúce emaily + label_generate_key: Vygenerovať kľúč + setting_mail_handler_api_enabled: Zapnúť Webovú Službu (WS) pre príchodzie emaily + setting_mail_handler_api_key: API kľúč + text_email_delivery_not_configured: "Doručenie emailov nieje nastavené, notifikácie sú vypnuté.\nNastavte váš SMTP server v config/configuration.yml a reštartnite aplikáciu pre aktiváciu funkcie." + field_parent_title: Nadradená stránka + label_issue_watchers: Pozorovatelia + button_quote: Citácia + setting_sequential_project_identifiers: Generovať sekvenčné identifikátory projektov + notice_unable_delete_version: Verzia nemôže byť zmazaná + label_renamed: premenované + label_copied: kopírované + setting_plain_text_mail: Len jednoduchý text (bez HTML) + permission_view_files: Zobrazenie súborov + permission_edit_issues: Úprava úloh + permission_edit_own_time_entries: Úprava vlastných zaznamov o strávenom čase + permission_manage_public_queries: Správa verejných otáziek + permission_add_issues: Pridanie úlohy + permission_log_time: Zaznamenávanie stráveného času + permission_view_changesets: Zobrazenie sád zmien + permission_view_time_entries: Zobrazenie stráveného času + permission_manage_versions: Správa verzií + permission_manage_wiki: Správa Wiki + permission_manage_categories: Správa kategórií úloh + permission_protect_wiki_pages: Ochrana Wiki strániek + permission_comment_news: Komentovanie noviniek + permission_delete_messages: Mazanie správ + permission_select_project_modules: Voľba projektových modulov + permission_manage_documents: Správa dokumentov + permission_edit_wiki_pages: Úprava Wiki strániek + permission_add_issue_watchers: Pridanie pozorovateľov + permission_view_gantt: Zobrazenie Ganttovho diagramu + permission_move_issues: Presun úloh + permission_manage_issue_relations: Správa vzťahov medzi úlohami + permission_delete_wiki_pages: Mazanie Wiki strániek + permission_manage_boards: Správa diskusií + permission_delete_wiki_pages_attachments: Mazanie Wiki príloh + permission_view_wiki_edits: Zobrazenie Wiki úprav + permission_add_messages: Pridanie správ + permission_view_messages: Zobrazenie správ + permission_manage_files: Správa súborov + permission_edit_issue_notes: Úprava poznámok úlohy + permission_manage_news: Správa noviniek + permission_view_calendar: Zobrazenie kalendára + permission_manage_members: Správa členov + permission_edit_messages: Úprava správ + permission_delete_issues: Mazanie správ + permission_view_issue_watchers: Zobrazenie zoznamu pozorovateľov + permission_manage_repository: Správa repozitára + permission_commit_access: Povoliť prístup + permission_browse_repository: Prechádzanie repozitára + permission_view_documents: Zobrazenie dokumentov + permission_edit_project: Úprava projektu + permission_add_issue_notes: Pridanie poznámky úlohy + permission_save_queries: Uloženie otáziek + permission_view_wiki_pages: Zobrazenie Wiki strániek + permission_rename_wiki_pages: Premenovanie Wiki strániek + permission_edit_time_entries: Úprava záznamov o strávenom čase + permission_edit_own_issue_notes: Úprava vlastných poznámok úlohy + setting_gravatar_enabled: Použitie užívateľských Gravatar ikon + permission_edit_own_messages: Úprava vlastných správ + permission_delete_own_messages: Mazanie vlastných správ + text_repository_usernames_mapping: "Vyberte alebo upravte mapovanie medzi užívateľmi systému Redmine a užívateľskými menami nájdenými v logu repozitára.\nUžívatelia s rovnakým prihlasovacím menom alebo emailom v systéme Redmine a repozitára sú mapovaní automaticky." + label_example: Príklad + label_user_activity: "Aktivita užívateľa %{value}" + label_updated_time_by: "Aktualizované užívateľom %{author} pred %{age}" + text_diff_truncated: '... Tento rozdielový výpis bol skratený, pretože prekračuje maximálnu veľkosť, ktorá môže byť zobrazená.' + setting_diff_max_lines_displayed: Maximálne množstvo zobrazených riadkov rozdielového výpisu + text_plugin_assets_writable: Adresár pre pluginy s možnosťou zápisu + warning_attachments_not_saved: "%{count} súbor(y) nemohol(li) byť uložené." + field_editable: Editovateľné + label_display: Zobrazenie + button_create_and_continue: Vytvoriť a pokračovať + text_custom_field_possible_values_info: 'Jeden riadok pre každú hodnotu' + setting_repository_log_display_limit: Maximálne množstvo revizií zobrazené v logu + setting_file_max_size_displayed: Maximálna veľkosť textových súborov zobrazených priamo na stránke + field_watcher: Pozorovateľ + setting_openid: Povoliť OpenID prihlasovanie a registráciu + field_identity_url: OpenID URL + label_login_with_open_id_option: alebo sa prihlásiť pomocou OpenID + field_content: Obsah + label_descending: Zostupné + label_sort: Zoradenie + label_ascending: Rastúce + label_date_from_to: Od %{start} do %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Táto stránka má %{descendants} podstránku/y a potomka/ov. Čo chcete vykonať? + text_wiki_page_reassign_children: Preradiť podstránky k tejto hlavnej stránke + text_wiki_page_nullify_children: Zachovať podstránky ako hlavné stránky + text_wiki_page_destroy_children: Vymazať podstránky a všetkých ich potomkov + setting_password_min_length: Minimálna dĺžka hesla + field_group_by: Skupinové výsledky podľa + mail_subject_wiki_content_updated: "'%{id}' Wiki stránka bola aktualizovaná" + label_wiki_content_added: Wiki stránka pridaná + mail_subject_wiki_content_added: "'%{id}' Wiki stránka bola pridaná" + mail_body_wiki_content_added: The '%{id}' Wiki stránka bola pridaná užívateľom %{author}. + permission_add_project: Vytvorenie projektu + label_wiki_content_updated: Wiki stránka aktualizovaná + mail_body_wiki_content_updated: Wiki stránka '%{id}' bola aktualizovaná užívateľom %{author}. + setting_new_project_user_role_id: Rola dána non-admin užívateľovi, ktorý vytvorí projekt + label_view_all_revisions: Zobraziť všetkz revízie + label_tag: Tag + label_branch: Vetva + error_no_tracker_in_project: K tomuto projektu nieje priradená žiadna fronta. Prosím skontrolujte nastavenie projektu. + error_no_default_issue_status: Nieje definovaný východzí stav úlohy. Prosím skontrolujte vase nastavenie (Choďte na "Administrácia -> Stavz úloh"). + text_journal_changed: "%{label} zmenené z %{old} na %{new}" + text_journal_set_to: "%{label} nastavené na %{value}" + text_journal_deleted: "%{label} zmazané (%{old})" + label_group_plural: Skupiny + label_group: Skupina + label_group_new: Nová skupina + label_time_entry_plural: Strávený čas + text_journal_added: "%{label} %{value} pridané" + field_active: Aktívne + enumeration_system_activity: Aktivita systému + permission_delete_issue_watchers: Odstrániť pozorovateľov + version_status_closed: zavreté + version_status_locked: uzavreté + version_status_open: otvorené + error_can_not_reopen_issue_on_closed_version: Úloha priradená uzavretej verzií nemôže byť znovu-otvorená + label_user_anonymous: Anonym + button_move_and_follow: Presunúť a následovať + setting_default_projects_modules: Prednastavené aktívne moduly pre nové projekty + setting_gravatar_default: Východzí Gravatar obrázok + field_sharing: Zdieľanie + label_version_sharing_hierarchy: S hierarchiou projektu + label_version_sharing_system: So všetkými projektami + label_version_sharing_descendants: S podprojektami + label_version_sharing_tree: S projektovým stromom + label_version_sharing_none: Nezdielané + error_can_not_archive_project: Tento projekt nemôže byť archivovaný + button_duplicate: Duplikovať + button_copy_and_follow: Kopírovať a následovať + label_copy_source: Zdroj + setting_issue_done_ratio: Vyrátať pomer vypracovania úlohy s + setting_issue_done_ratio_issue_status: Použiť stav úlohy + error_issue_done_ratios_not_updated: Stav vypracovania úlohy neaktualizovaný. + error_workflow_copy_target: Prosím zvoľte cieľovú frontu(y) a rolu(e) + setting_issue_done_ratio_issue_field: Použiť pole úlohy + label_copy_same_as_target: Rovnaké ako cieľ + label_copy_target: Cieľ + notice_issue_done_ratios_updated: Stav vypracovania úlohy aktualizovaný. + error_workflow_copy_source: Prosím zvoľte zdrojovú frontu alebo rolu + label_update_issue_done_ratios: Aktualizácia stavu úloh + setting_start_of_week: Štart pracovného týždňa v + permission_view_issues: Zobraziť úlohy + label_display_used_statuses_only: Zobraziť len stavy, ktoré sú priradené k tejto fronte + label_revision_id: Revízia %{value} + label_api_access_key: API prístupový kľúč + label_api_access_key_created_on: API prístupový kľúč vytvorený pred %{value} + label_feeds_access_key: RSS prístupový kľúč + notice_api_access_key_reseted: Váš API prístupový kľúč bol resetovaný. + setting_rest_api_enabled: Zapnúť REST web službu + label_missing_api_access_key: API prístupový kľuč nenájdený + label_missing_feeds_access_key: RSS prístupový kľúč nenájdený + button_show: Zobraziť + text_line_separated: Možnosť viacerých hodnôt (jeden riadok pre každú hodnotu). + setting_mail_handler_body_delimiters: Orezať emaily po následujúcich riadkoch + permission_add_subprojects: Vytváranie podprojektov + label_subproject_new: Nový podprojekt + text_own_membership_delete_confirmation: |- + Práve sa pokúšate o odstránenie niektorých alebo všetkých prístupových práv a možno nebudete mať možnost naďalej upravovať tento projekt. + Ste si istý(á), že chcete pokračovat? + label_close_versions: Uzavrieť ukončené verzie + label_board_sticky: Sticky + label_board_locked: Uzamknuté + permission_export_wiki_pages: Exportovať WiKi stránky + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Nastavovať aktivity projektu + error_unable_delete_issue_status: Nieje možné zmeniť stav úlohy + label_profile: Profil + permission_manage_subtasks: Nastavovať podúlohy + field_parent_issue: Nadradená úloha + label_subtask_plural: Podúlohy + label_project_copy_notifications: Zaslať emailové upozornenie behom kopírovania projektu + error_can_not_delete_custom_field: Nieje možné vymazať užívateľské pole + error_unable_to_connect: Nieje možné vymazať (%{value}) + error_can_not_remove_role: Táto roľa sa používa a nemôže byť vymazaná. + error_can_not_delete_tracker: Táto fronta obsahuje úlohy a nemôže byť vymazaná. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kódovanie prenášaných správ + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c7bb69004035c6ba51de1c4b9e2df0f70c675d27.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c7bb69004035c6ba51de1c4b9e2df0f70c675d27.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,84 @@ +// ** I18N + +// full day names +Calendar._DN = new Array +("Söndag", + "Måndag", + "Tisdag", + "Onsdag", + "Torsdag", + "Fredag", + "Lördag", + "Söndag"); + +Calendar._SDN_len = 3; // short day name length +Calendar._SMN_len = 3; // short month name length + + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Januari", + "Februari", + "Mars", + "April", + "Maj", + "Juni", + "Juli", + "Augusti", + "September", + "Oktober", + "November", + "December"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Om kalendern"; + +Calendar._TT["ABOUT"] = +"DHTML Datum/Tid-väljare\n" + +"(c) dynarch.com 2002-2005 / Upphovsman: Mihai Bazon\n" + // don't translate this this ;-) +"För senaste version besök: http://www.dynarch.com/projects/calendar/\n" + +"Distribueras under GNU LGPL. Se http://gnu.org/licenses/lgpl.html för detaljer." + +"\n\n" + +"Välja datum:\n" + +"- Använd \xab, \xbb knapparna för att välja år\n" + +"- Använd " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " knapparna för att välja månad\n" + +"- Håll nere musknappen på någon av ovanstående knappar för att se snabbval."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Välja tid:\n" + +"- Klicka på något av tidsfälten för att öka\n" + +"- eller Skift-klicka för att minska\n" + +"- eller klicka och dra för att välja snabbare."; + +Calendar._TT["PREV_YEAR"] = "Föreg. år (håll nere för lista)"; +Calendar._TT["PREV_MONTH"] = "Föreg. månad (håll nere för lista)"; +Calendar._TT["GO_TODAY"] = "Gå till Idag"; +Calendar._TT["NEXT_MONTH"] = "Nästa månad (håll nere för lista)"; +Calendar._TT["NEXT_YEAR"] = "Nästa år (håll nere för lista)"; +Calendar._TT["SEL_DATE"] = "Välj datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Dra för att flytta"; +Calendar._TT["PART_TODAY"] = " (idag)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Visa %s först"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Stäng"; +Calendar._TT["TODAY"] = "Idag"; +Calendar._TT["TIME_PART"] = "(Skift-)klicka eller dra för att ändra värde"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "v."; +Calendar._TT["TIME"] = "Tid:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c7d5fcf60428c25b64f2230a47dd713a94818cae.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c7d5fcf60428c25b64f2230a47dd713a94818cae.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Namespace::AlphaPluginController < ApplicationController + def an_action + render_class_and_action + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c7/c7dbabe98ae3e574a637d9bbb8d3b6e27e263f8a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c7/c7dbabe98ae3e574a637d9bbb8d3b6e27e263f8a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,75 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class ActivitiesController < ApplicationController + menu_item :activity + before_filter :find_optional_project + accept_rss_auth :index + + def index + @days = Setting.activity_days_default.to_i + + if params[:from] + begin; @date_to = params[:from].to_date + 1; rescue; end + end + + @date_to ||= Date.today + 1 + @date_from = @date_to - @days + @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) + + @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, + :with_subprojects => @with_subprojects, + :author => @author) + @activity.scope_select {|t| !params["show_#{t}"].nil?} + @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? + + events = @activity.events(@date_from, @date_to) + + if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, User.current, current_language]) + respond_to do |format| + format.html { + @events_by_day = events.group_by(&:event_date) + render :layout => false if request.xhr? + } + format.atom { + title = l(:label_activity) + if @author + title = @author.name + elsif @activity.scope.size == 1 + title = l("label_#{@activity.scope.first.singularize}_plural") + end + render_feed(events, :title => "#{@project || Setting.app_title}: #{title}") + } + end + end + + rescue ActiveRecord::RecordNotFound + render_404 + end + + private + + # TODO: refactor, duplicated in projects_controller + def find_optional_project + return true unless params[:id] + @project = Project.find(params[:id]) + authorize + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c8/c84c8feb09c74f4066537c3dc5805060fec4acf5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c8/c84c8feb09c74f4066537c3dc5805060fec4acf5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1787 @@ +#!/usr/bin/env ruby +# +# Utility to generate font definition files +# Version: 1.1 +# Date: 2006-07-19 +# +# Changelog: +# Version 1.1 - Brian Ollenberger +# - Fixed a very small bug in MakeFont for generating FontDef.diff. + +Charencodings = { +# Central Europe + 'cp1250' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', '.notdef', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + '.notdef', 'perthousand', 'Scaron', 'guilsinglleft', + 'Sacute', 'Tcaron', 'Zcaron', 'Zacute', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', 'scaron', 'guilsinglright', + 'sacute', 'tcaron', 'zcaron', 'zacute', + 'space', 'caron', 'breve', 'Lslash', + 'currency', 'Aogonek', 'brokenbar', 'section', + 'dieresis', 'copyright', 'Scedilla', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'Zdotaccent', + 'degree', 'plusminus', 'ogonek', 'lslash', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'aogonek', 'scedilla', 'guillemotright', + 'Lcaron', 'hungarumlaut', 'lcaron', 'zdotaccent', + 'Racute', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Lacute', 'Cacute', 'Ccedilla', + 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', + 'Ecaron', 'Iacute', 'Icircumflex', 'Dcaron', + 'Dcroat', 'Nacute', 'Ncaron', 'Oacute', + 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'multiply', + 'Rcaron', 'Uring', 'Uacute', 'Uhungarumlaut', + 'Udieresis', 'Yacute', 'Tcommaaccent', 'germandbls', + 'racute', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'lacute', 'cacute', 'ccedilla', + 'ccaron', 'eacute', 'eogonek', 'edieresis', + 'ecaron', 'iacute', 'icircumflex', 'dcaron', + 'dcroat', 'nacute', 'ncaron', 'oacute', + 'ocircumflex', 'ohungarumlaut', 'odieresis', 'divide', + 'rcaron', 'uring', 'uacute', 'uhungarumlaut', + 'udieresis', 'yacute', 'tcommaaccent', 'dotaccent' + ], +# Cyrillic + 'cp1251' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'afii10051', 'afii10052', 'quotesinglbase', 'afii10100', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'Euro', 'perthousand', 'afii10058', 'guilsinglleft', + 'afii10059', 'afii10061', 'afii10060', 'afii10145', + 'afii10099', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', 'afii10106', 'guilsinglright', + 'afii10107', 'afii10109', 'afii10108', 'afii10193', + 'space', 'afii10062', 'afii10110', 'afii10057', + 'currency', 'afii10050', 'brokenbar', 'section', + 'afii10023', 'copyright', 'afii10053', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'afii10056', + 'degree', 'plusminus', 'afii10055', 'afii10103', + 'afii10098', 'mu', 'paragraph', 'periodcentered', + 'afii10071', 'afii61352', 'afii10101', 'guillemotright', + 'afii10105', 'afii10054', 'afii10102', 'afii10104', + 'afii10017', 'afii10018', 'afii10019', 'afii10020', + 'afii10021', 'afii10022', 'afii10024', 'afii10025', + 'afii10026', 'afii10027', 'afii10028', 'afii10029', + 'afii10030', 'afii10031', 'afii10032', 'afii10033', + 'afii10034', 'afii10035', 'afii10036', 'afii10037', + 'afii10038', 'afii10039', 'afii10040', 'afii10041', + 'afii10042', 'afii10043', 'afii10044', 'afii10045', + 'afii10046', 'afii10047', 'afii10048', 'afii10049', + 'afii10065', 'afii10066', 'afii10067', 'afii10068', + 'afii10069', 'afii10070', 'afii10072', 'afii10073', + 'afii10074', 'afii10075', 'afii10076', 'afii10077', + 'afii10078', 'afii10079', 'afii10080', 'afii10081', + 'afii10082', 'afii10083', 'afii10084', 'afii10085', + 'afii10086', 'afii10087', 'afii10088', 'afii10089', + 'afii10090', 'afii10091', 'afii10092', 'afii10093', + 'afii10094', 'afii10095', 'afii10096', 'afii10097' + ], +# Western Europe + 'cp1252' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', + 'OE', '.notdef', 'Zcaron', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', 'scaron', 'guilsinglright', + 'oe', '.notdef', 'zcaron', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'yacute', 'thorn', 'ydieresis' + ], +# Greek + 'cp1253' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + '.notdef', 'perthousand', '.notdef', 'guilsinglleft', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', '.notdef', 'guilsinglright', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'dieresistonos', 'Alphatonos', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', '.notdef', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'afii00208', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'tonos', 'mu', 'paragraph', 'periodcentered', + 'Epsilontonos', 'Etatonos', 'Iotatonos', 'guillemotright', + 'Omicrontonos', 'onehalf', 'Upsilontonos', 'Omegatonos', + 'iotadieresistonos','Alpha', 'Beta', 'Gamma', + 'Delta', 'Epsilon', 'Zeta', 'Eta', + 'Theta', 'Iota', 'Kappa', 'Lambda', + 'Mu', 'Nu', 'Xi', 'Omicron', + 'Pi', 'Rho', '.notdef', 'Sigma', + 'Tau', 'Upsilon', 'Phi', 'Chi', + 'Psi', 'Omega', 'Iotadieresis', 'Upsilondieresis', + 'alphatonos', 'epsilontonos', 'etatonos', 'iotatonos', + 'upsilondieresistonos','alpha', 'beta', 'gamma', + 'delta', 'epsilon', 'zeta', 'eta', + 'theta', 'iota', 'kappa', 'lambda', + 'mu', 'nu', 'xi', 'omicron', + 'pi', 'rho', 'sigma1', 'sigma', + 'tau', 'upsilon', 'phi', 'chi', + 'psi', 'omega', 'iotadieresis', 'upsilondieresis', + 'omicrontonos', 'upsilontonos', 'omegatonos', '.notdef' + ], +# Turkish + 'cp1254' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', 'Scaron', 'guilsinglleft', + 'OE', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', 'scaron', 'guilsinglright', + 'oe', '.notdef', '.notdef', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Gbreve', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Idotaccent', 'Scedilla', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'gbreve', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'dotlessi', 'scedilla', 'ydieresis' + ], +# Hebrew + 'cp1255' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', '.notdef', 'guilsinglleft', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', '.notdef', 'guilsinglright', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'afii57636', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'multiply', 'guillemotleft', + 'logicalnot', 'sfthyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'middot', + 'cedilla', 'onesuperior', 'divide', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'afii57799', 'afii57801', 'afii57800', 'afii57802', + 'afii57793', 'afii57794', 'afii57795', 'afii57798', + 'afii57797', 'afii57806', '.notdef', 'afii57796', + 'afii57807', 'afii57839', 'afii57645', 'afii57841', + 'afii57842', 'afii57804', 'afii57803', 'afii57658', + 'afii57716', 'afii57717', 'afii57718', 'gereshhebrew', + 'gershayimhebrew','.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'afii57664', 'afii57665', 'afii57666', 'afii57667', + 'afii57668', 'afii57669', 'afii57670', 'afii57671', + 'afii57672', 'afii57673', 'afii57674', 'afii57675', + 'afii57676', 'afii57677', 'afii57678', 'afii57679', + 'afii57680', 'afii57681', 'afii57682', 'afii57683', + 'afii57684', 'afii57685', 'afii57686', 'afii57687', + 'afii57688', 'afii57689', 'afii57690', '.notdef', + '.notdef', 'afii299', 'afii300', '.notdef' + ], +# Baltic + 'cp1257' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', '.notdef', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + '.notdef', 'perthousand', '.notdef', 'guilsinglleft', + '.notdef', 'dieresis', 'caron', 'cedilla', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', 'trademark', '.notdef', 'guilsinglright', + '.notdef', 'macron', 'ogonek', '.notdef', + 'space', '.notdef', 'cent', 'sterling', + 'currency', '.notdef', 'brokenbar', 'section', + 'Oslash', 'copyright', 'Rcommaaccent', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'AE', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'oslash', 'onesuperior', 'rcommaaccent', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'ae', + 'Aogonek', 'Iogonek', 'Amacron', 'Cacute', + 'Adieresis', 'Aring', 'Eogonek', 'Emacron', + 'Ccaron', 'Eacute', 'Zacute', 'Edotaccent', + 'Gcommaaccent', 'Kcommaaccent', 'Imacron', 'Lcommaaccent', + 'Scaron', 'Nacute', 'Ncommaaccent', 'Oacute', + 'Omacron', 'Otilde', 'Odieresis', 'multiply', + 'Uogonek', 'Lslash', 'Sacute', 'Umacron', + 'Udieresis', 'Zdotaccent', 'Zcaron', 'germandbls', + 'aogonek', 'iogonek', 'amacron', 'cacute', + 'adieresis', 'aring', 'eogonek', 'emacron', + 'ccaron', 'eacute', 'zacute', 'edotaccent', + 'gcommaaccent', 'kcommaaccent', 'imacron', 'lcommaaccent', + 'scaron', 'nacute', 'ncommaaccent', 'oacute', + 'omacron', 'otilde', 'odieresis', 'divide', + 'uogonek', 'lslash', 'sacute', 'umacron', + 'udieresis', 'zdotaccent', 'zcaron', 'dotaccent' + ], +# Vietnamese + 'cp1258' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', + 'circumflex', 'perthousand', '.notdef', 'guilsinglleft', + 'OE', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + 'tilde', 'trademark', '.notdef', 'guilsinglright', + 'oe', '.notdef', '.notdef', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'gravecomb', 'Iacute', 'Icircumflex', 'Idieresis', + 'Dcroat', 'Ntilde', 'hookabovecomb', 'Oacute', + 'Ocircumflex', 'Ohorn', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Uhorn', 'tildecomb', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'acutecomb', 'iacute', 'icircumflex', 'idieresis', + 'dcroat', 'ntilde', 'dotbelowcomb', 'oacute', + 'ocircumflex', 'ohorn', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'uhorn', 'dong', 'ydieresis' + ], +# Thai + 'cp874' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'Euro', '.notdef', '.notdef', '.notdef', + '.notdef', 'ellipsis', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'kokaithai', 'khokhaithai', 'khokhuatthai', + 'khokhwaithai', 'khokhonthai', 'khorakhangthai', 'ngonguthai', + 'chochanthai', 'chochingthai', 'chochangthai', 'sosothai', + 'chochoethai', 'yoyingthai', 'dochadathai', 'topatakthai', + 'thothanthai', 'thonangmonthothai', 'thophuthaothai', 'nonenthai', + 'dodekthai', 'totaothai', 'thothungthai', 'thothahanthai', + 'thothongthai', 'nonuthai', 'bobaimaithai', 'poplathai', + 'phophungthai', 'fofathai', 'phophanthai', 'fofanthai', + 'phosamphaothai', 'momathai', 'yoyakthai', 'roruathai', + 'ruthai', 'lolingthai', 'luthai', 'wowaenthai', + 'sosalathai', 'sorusithai', 'sosuathai', 'hohipthai', + 'lochulathai', 'oangthai', 'honokhukthai', 'paiyannoithai', + 'saraathai', 'maihanakatthai', 'saraaathai', 'saraamthai', + 'saraithai', 'saraiithai', 'sarauethai', 'saraueethai', + 'sarauthai', 'sarauuthai', 'phinthuthai', '.notdef', + '.notdef', '.notdef', '.notdef', 'bahtthai', + 'saraethai', 'saraaethai', 'saraothai', 'saraaimaimuanthai', + 'saraaimaimalaithai', 'lakkhangyaothai', 'maiyamokthai', 'maitaikhuthai', + 'maiekthai', 'maithothai', 'maitrithai', 'maichattawathai', + 'thanthakhatthai', 'nikhahitthai', 'yamakkanthai', 'fongmanthai', + 'zerothai', 'onethai', 'twothai', 'threethai', + 'fourthai', 'fivethai', 'sixthai', 'seventhai', + 'eightthai', 'ninethai', 'angkhankhuthai', 'khomutthai', + '.notdef', '.notdef', '.notdef', '.notdef' + ], +# Western Europe + 'ISO-8859-1' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'yacute', 'thorn', 'ydieresis' + ], +# Central Europe + 'ISO-8859-2' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'Aogonek', 'breve', 'Lslash', + 'currency', 'Lcaron', 'Sacute', 'section', + 'dieresis', 'Scaron', 'Scedilla', 'Tcaron', + 'Zacute', 'hyphen', 'Zcaron', 'Zdotaccent', + 'degree', 'aogonek', 'ogonek', 'lslash', + 'acute', 'lcaron', 'sacute', 'caron', + 'cedilla', 'scaron', 'scedilla', 'tcaron', + 'zacute', 'hungarumlaut', 'zcaron', 'zdotaccent', + 'Racute', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Lacute', 'Cacute', 'Ccedilla', + 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', + 'Ecaron', 'Iacute', 'Icircumflex', 'Dcaron', + 'Dcroat', 'Nacute', 'Ncaron', 'Oacute', + 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'multiply', + 'Rcaron', 'Uring', 'Uacute', 'Uhungarumlaut', + 'Udieresis', 'Yacute', 'Tcommaaccent', 'germandbls', + 'racute', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'lacute', 'cacute', 'ccedilla', + 'ccaron', 'eacute', 'eogonek', 'edieresis', + 'ecaron', 'iacute', 'icircumflex', 'dcaron', + 'dcroat', 'nacute', 'ncaron', 'oacute', + 'ocircumflex', 'ohungarumlaut', 'odieresis', 'divide', + 'rcaron', 'uring', 'uacute', 'uhungarumlaut', + 'udieresis', 'yacute', 'tcommaaccent', 'dotaccent' + ], +# Baltic + 'ISO-8859-4' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'Aogonek', 'kgreenlandic', 'Rcommaaccent', + 'currency', 'Itilde', 'Lcommaaccent', 'section', + 'dieresis', 'Scaron', 'Emacron', 'Gcommaaccent', + 'Tbar', 'hyphen', 'Zcaron', 'macron', + 'degree', 'aogonek', 'ogonek', 'rcommaaccent', + 'acute', 'itilde', 'lcommaaccent', 'caron', + 'cedilla', 'scaron', 'emacron', 'gcommaaccent', + 'tbar', 'Eng', 'zcaron', 'eng', + 'Amacron', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Iogonek', + 'Ccaron', 'Eacute', 'Eogonek', 'Edieresis', + 'Edotaccent', 'Iacute', 'Icircumflex', 'Imacron', + 'Dcroat', 'Ncommaaccent', 'Omacron', 'Kcommaaccent', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Uogonek', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Utilde', 'Umacron', 'germandbls', + 'amacron', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'iogonek', + 'ccaron', 'eacute', 'eogonek', 'edieresis', + 'edotaccent', 'iacute', 'icircumflex', 'imacron', + 'dcroat', 'ncommaaccent', 'omacron', 'kcommaaccent', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'uogonek', 'uacute', 'ucircumflex', + 'udieresis', 'utilde', 'umacron', 'dotaccent' + ], +# Cyrillic + 'ISO-8859-5' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'afii10023', 'afii10051', 'afii10052', + 'afii10053', 'afii10054', 'afii10055', 'afii10056', + 'afii10057', 'afii10058', 'afii10059', 'afii10060', + 'afii10061', 'hyphen', 'afii10062', 'afii10145', + 'afii10017', 'afii10018', 'afii10019', 'afii10020', + 'afii10021', 'afii10022', 'afii10024', 'afii10025', + 'afii10026', 'afii10027', 'afii10028', 'afii10029', + 'afii10030', 'afii10031', 'afii10032', 'afii10033', + 'afii10034', 'afii10035', 'afii10036', 'afii10037', + 'afii10038', 'afii10039', 'afii10040', 'afii10041', + 'afii10042', 'afii10043', 'afii10044', 'afii10045', + 'afii10046', 'afii10047', 'afii10048', 'afii10049', + 'afii10065', 'afii10066', 'afii10067', 'afii10068', + 'afii10069', 'afii10070', 'afii10072', 'afii10073', + 'afii10074', 'afii10075', 'afii10076', 'afii10077', + 'afii10078', 'afii10079', 'afii10080', 'afii10081', + 'afii10082', 'afii10083', 'afii10084', 'afii10085', + 'afii10086', 'afii10087', 'afii10088', 'afii10089', + 'afii10090', 'afii10091', 'afii10092', 'afii10093', + 'afii10094', 'afii10095', 'afii10096', 'afii10097', + 'afii61352', 'afii10071', 'afii10099', 'afii10100', + 'afii10101', 'afii10102', 'afii10103', 'afii10104', + 'afii10105', 'afii10106', 'afii10107', 'afii10108', + 'afii10109', 'section', 'afii10110', 'afii10193' + ], +# Greek + 'ISO-8859-7' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'quoteleft', 'quoteright', 'sterling', + '.notdef', '.notdef', 'brokenbar', 'section', + 'dieresis', 'copyright', '.notdef', 'guillemotleft', + 'logicalnot', 'hyphen', '.notdef', 'afii00208', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'tonos', 'dieresistonos', 'Alphatonos', 'periodcentered', + 'Epsilontonos', 'Etatonos', 'Iotatonos', 'guillemotright', + 'Omicrontonos', 'onehalf', 'Upsilontonos', 'Omegatonos', + 'iotadieresistonos','Alpha', 'Beta', 'Gamma', + 'Delta', 'Epsilon', 'Zeta', 'Eta', + 'Theta', 'Iota', 'Kappa', 'Lambda', + 'Mu', 'Nu', 'Xi', 'Omicron', + 'Pi', 'Rho', '.notdef', 'Sigma', + 'Tau', 'Upsilon', 'Phi', 'Chi', + 'Psi', 'Omega', 'Iotadieresis', 'Upsilondieresis', + 'alphatonos', 'epsilontonos', 'etatonos', 'iotatonos', + 'upsilondieresistonos','alpha', 'beta', 'gamma', + 'delta', 'epsilon', 'zeta', 'eta', + 'theta', 'iota', 'kappa', 'lambda', + 'mu', 'nu', 'xi', 'omicron', + 'pi', 'rho', 'sigma1', 'sigma', + 'tau', 'upsilon', 'phi', 'chi', + 'psi', 'omega', 'iotadieresis', 'upsilondieresis', + 'omicrontonos', 'upsilontonos', 'omegatonos', '.notdef' + ], +# Turkish + 'ISO-8859-9' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'currency', 'yen', 'brokenbar', 'section', + 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', + 'onequarter', 'onehalf', 'threequarters', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Gbreve', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Idotaccent', 'Scedilla', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'gbreve', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'dotlessi', 'scedilla', 'ydieresis' + ], +# Thai + 'ISO-8859-11' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'kokaithai', 'khokhaithai', 'khokhuatthai', + 'khokhwaithai', 'khokhonthai', 'khorakhangthai', 'ngonguthai', + 'chochanthai', 'chochingthai', 'chochangthai', 'sosothai', + 'chochoethai', 'yoyingthai', 'dochadathai', 'topatakthai', + 'thothanthai', 'thonangmonthothai','thophuthaothai', 'nonenthai', + 'dodekthai', 'totaothai', 'thothungthai', 'thothahanthai', + 'thothongthai', 'nonuthai', 'bobaimaithai', 'poplathai', + 'phophungthai', 'fofathai', 'phophanthai', 'fofanthai', + 'phosamphaothai', 'momathai', 'yoyakthai', 'roruathai', + 'ruthai', 'lolingthai', 'luthai', 'wowaenthai', + 'sosalathai', 'sorusithai', 'sosuathai', 'hohipthai', + 'lochulathai', 'oangthai', 'honokhukthai', 'paiyannoithai', + 'saraathai', 'maihanakatthai', 'saraaathai', 'saraamthai', + 'saraithai', 'saraiithai', 'sarauethai', 'saraueethai', + 'sarauthai', 'sarauuthai', 'phinthuthai', '.notdef', + '.notdef', '.notdef', '.notdef', 'bahtthai', + 'saraethai', 'saraaethai', 'saraothai', 'saraaimaimuanthai', + 'saraaimaimalaithai','lakkhangyaothai','maiyamokthai', 'maitaikhuthai', + 'maiekthai', 'maithothai', 'maitrithai', 'maichattawathai', + 'thanthakhatthai','nikhahitthai', 'yamakkanthai', 'fongmanthai', + 'zerothai', 'onethai', 'twothai', 'threethai', + 'fourthai', 'fivethai', 'sixthai', 'seventhai', + 'eightthai', 'ninethai', 'angkhankhuthai', 'khomutthai', + '.notdef', '.notdef', '.notdef', '.notdef' + ], +# Western Europe + 'ISO-8859-15' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclamdown', 'cent', 'sterling', + 'Euro', 'yen', 'Scaron', 'section', + 'scaron', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', + 'degree', 'plusminus', 'twosuperior', 'threesuperior', + 'Zcaron', 'mu', 'paragraph', 'periodcentered', + 'zcaron', 'onesuperior', 'ordmasculine', 'guillemotright', + 'OE', 'oe', 'Ydieresis', 'questiondown', + 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', + 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', + 'Oslash', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', + 'adieresis', 'aring', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', + 'oslash', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'yacute', 'thorn', 'ydieresis' + ], +# Central Europe + 'ISO-8859-16' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'Aogonek', 'aogonek', 'Lslash', + 'Euro', 'quotedblbase', 'Scaron', 'section', + 'scaron', 'copyright', 'Scommaaccent', 'guillemotleft', + 'Zacute', 'hyphen', 'zacute', 'Zdotaccent', + 'degree', 'plusminus', 'Ccaron', 'lslash', + 'Zcaron', 'quotedblright', 'paragraph', 'periodcentered', + 'zcaron', 'ccaron', 'scommaaccent', 'guillemotright', + 'OE', 'oe', 'Ydieresis', 'zdotaccent', + 'Agrave', 'Aacute', 'Acircumflex', 'Abreve', + 'Adieresis', 'Cacute', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', + 'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', + 'Dcroat', 'Nacute', 'Ograve', 'Oacute', + 'Ocircumflex', 'Ohungarumlaut', 'Odieresis', 'Sacute', + 'Uhungarumlaut', 'Ugrave', 'Uacute', 'Ucircumflex', + 'Udieresis', 'Eogonek', 'Tcommaaccent', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'abreve', + 'adieresis', 'cacute', 'ae', 'ccedilla', + 'egrave', 'eacute', 'ecircumflex', 'edieresis', + 'igrave', 'iacute', 'icircumflex', 'idieresis', + 'dcroat', 'nacute', 'ograve', 'oacute', + 'ocircumflex', 'ohungarumlaut', 'odieresis', 'sacute', + 'uhungarumlaut', 'ugrave', 'uacute', 'ucircumflex', + 'udieresis', 'eogonek', 'tcommaaccent', 'ydieresis' + ], +# Russian + 'KOI8-R' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'SF100000', 'SF110000', 'SF010000', 'SF030000', + 'SF020000', 'SF040000', 'SF080000', 'SF090000', + 'SF060000', 'SF070000', 'SF050000', 'upblock', + 'dnblock', 'block', 'lfblock', 'rtblock', + 'ltshade', 'shade', 'dkshade', 'integraltp', + 'filledbox', 'periodcentered', 'radical', 'approxequal', + 'lessequal', 'greaterequal', 'space', 'integralbt', + 'degree', 'twosuperior', 'periodcentered', 'divide', + 'SF430000', 'SF240000', 'SF510000', 'afii10071', + 'SF520000', 'SF390000', 'SF220000', 'SF210000', + 'SF250000', 'SF500000', 'SF490000', 'SF380000', + 'SF280000', 'SF270000', 'SF260000', 'SF360000', + 'SF370000', 'SF420000', 'SF190000', 'afii10023', + 'SF200000', 'SF230000', 'SF470000', 'SF480000', + 'SF410000', 'SF450000', 'SF460000', 'SF400000', + 'SF540000', 'SF530000', 'SF440000', 'copyright', + 'afii10096', 'afii10065', 'afii10066', 'afii10088', + 'afii10069', 'afii10070', 'afii10086', 'afii10068', + 'afii10087', 'afii10074', 'afii10075', 'afii10076', + 'afii10077', 'afii10078', 'afii10079', 'afii10080', + 'afii10081', 'afii10097', 'afii10082', 'afii10083', + 'afii10084', 'afii10085', 'afii10072', 'afii10067', + 'afii10094', 'afii10093', 'afii10073', 'afii10090', + 'afii10095', 'afii10091', 'afii10089', 'afii10092', + 'afii10048', 'afii10017', 'afii10018', 'afii10040', + 'afii10021', 'afii10022', 'afii10038', 'afii10020', + 'afii10039', 'afii10026', 'afii10027', 'afii10028', + 'afii10029', 'afii10030', 'afii10031', 'afii10032', + 'afii10033', 'afii10049', 'afii10034', 'afii10035', + 'afii10036', 'afii10037', 'afii10024', 'afii10019', + 'afii10046', 'afii10045', 'afii10025', 'afii10042', + 'afii10047', 'afii10043', 'afii10041', 'afii10044' + ], +# Ukrainian + 'KOI8-U' => [ + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + '.notdef', '.notdef', '.notdef', '.notdef', + 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quotesingle', + 'parenleft', 'parenright', 'asterisk', 'plus', + 'comma', 'hyphen', 'period', 'slash', + 'zero', 'one', 'two', 'three', + 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', + 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 'bracketleft', + 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', + 'x', 'y', 'z', 'braceleft', + 'bar', 'braceright', 'asciitilde', '.notdef', + 'SF100000', 'SF110000', 'SF010000', 'SF030000', + 'SF020000', 'SF040000', 'SF080000', 'SF090000', + 'SF060000', 'SF070000', 'SF050000', 'upblock', + 'dnblock', 'block', 'lfblock', 'rtblock', + 'ltshade', 'shade', 'dkshade', 'integraltp', + 'filledbox', 'bullet', 'radical', 'approxequal', + 'lessequal', 'greaterequal', 'space', 'integralbt', + 'degree', 'twosuperior', 'periodcentered', 'divide', + 'SF430000', 'SF240000', 'SF510000', 'afii10071', + 'afii10101', 'SF390000', 'afii10103', 'afii10104', + 'SF250000', 'SF500000', 'SF490000', 'SF380000', + 'SF280000', 'afii10098', 'SF260000', 'SF360000', + 'SF370000', 'SF420000', 'SF190000', 'afii10023', + 'afii10053', 'SF230000', 'afii10055', 'afii10056', + 'SF410000', 'SF450000', 'SF460000', 'SF400000', + 'SF540000', 'afii10050', 'SF440000', 'copyright', + 'afii10096', 'afii10065', 'afii10066', 'afii10088', + 'afii10069', 'afii10070', 'afii10086', 'afii10068', + 'afii10087', 'afii10074', 'afii10075', 'afii10076', + 'afii10077', 'afii10078', 'afii10079', 'afii10080', + 'afii10081', 'afii10097', 'afii10082', 'afii10083', + 'afii10084', 'afii10085', 'afii10072', 'afii10067', + 'afii10094', 'afii10093', 'afii10073', 'afii10090', + 'afii10095', 'afii10091', 'afii10089', 'afii10092', + 'afii10048', 'afii10017', 'afii10018', 'afii10040', + 'afii10021', 'afii10022', 'afii10038', 'afii10020', + 'afii10039', 'afii10026', 'afii10027', 'afii10028', + 'afii10029', 'afii10030', 'afii10031', 'afii10032', + 'afii10033', 'afii10049', 'afii10034', 'afii10035', + 'afii10036', 'afii10037', 'afii10024', 'afii10019', + 'afii10046', 'afii10045', 'afii10025', 'afii10042', + 'afii10047', 'afii10043', 'afii10041', 'afii10044' + ] +} + +def ReadAFM(file, map) + + # Read a font metric file + a = IO.readlines(file) + + raise "File no found: #{file}" if a.size == 0 + + widths = {} + fm = {} + fix = { 'Edot' => 'Edotaccent', 'edot' => 'edotaccent', + 'Idot' => 'Idotaccent', + 'Zdot' => 'Zdotaccent', 'zdot' => 'zdotaccent', + 'Odblacute' => 'Ohungarumlaut', 'odblacute' => 'ohungarumlaut', + 'Udblacute' => 'Uhungarumlaut', 'udblacute' => 'uhungarumlaut', + 'Gcedilla' => 'Gcommaaccent', 'gcedilla' => 'gcommaaccent', + 'Kcedilla' => 'Kcommaaccent', 'kcedilla' => 'kcommaaccent', + 'Lcedilla' => 'Lcommaaccent', 'lcedilla' => 'lcommaaccent', + 'Ncedilla' => 'Ncommaaccent', 'ncedilla' => 'ncommaaccent', + 'Rcedilla' => 'Rcommaaccent', 'rcedilla' => 'rcommaaccent', + 'Scedilla' => 'Scommaaccent',' scedilla' => 'scommaaccent', + 'Tcedilla' => 'Tcommaaccent',' tcedilla' => 'tcommaaccent', + 'Dslash' => 'Dcroat', 'dslash' => 'dcroat', + 'Dmacron' => 'Dcroat', 'dmacron' => 'dcroat', + 'combininggraveaccent' => 'gravecomb', + 'combininghookabove' => 'hookabovecomb', + 'combiningtildeaccent' => 'tildecomb', + 'combiningacuteaccent' => 'acutecomb', + 'combiningdotbelow' => 'dotbelowcomb', + 'dongsign' => 'dong' + } + + a.each do |line| + + e = line.rstrip.split(' ') + next if e.size < 2 + + code = e[0] + param = e[1] + + if code == 'C' then + + # Character metrics + cc = e[1].to_i + w = e[4] + gn = e[7] + + gn = 'Euro' if gn[-4, 4] == '20AC' + + if fix[gn] then + + # Fix incorrect glyph name + 0.upto(map.size - 1) do |i| + if map[i] == fix[gn] then + map[i] = gn + end + end + end + + if map.size == 0 then + # Symbolic font: use built-in encoding + widths[cc] = w + else + widths[gn] = w + fm['CapXHeight'] = e[13].to_i if gn == 'X' + end + + fm['MissingWidth'] = w if gn == '.notdef' + + elsif code == 'FontName' then + fm['FontName'] = param + elsif code == 'Weight' then + fm['Weight'] = param + elsif code == 'ItalicAngle' then + fm['ItalicAngle'] = param.to_f + elsif code == 'Ascender' then + fm['Ascender'] = param.to_i + elsif code == 'Descender' then + fm['Descender'] = param.to_i + elsif code == 'UnderlineThickness' then + fm['UnderlineThickness'] = param.to_i + elsif code == 'UnderlinePosition' then + fm['UnderlinePosition'] = param.to_i + elsif code == 'IsFixedPitch' then + fm['IsFixedPitch'] = (param == 'true') + elsif code == 'FontBBox' then + fm['FontBBox'] = "[#{e[1]},#{e[2]},#{e[3]},#{e[4]}]" + elsif code == 'CapHeight' then + fm['CapHeight'] = param.to_i + elsif code == 'StdVW' then + fm['StdVW'] = param.to_i + end + end + + raise 'FontName not found' unless fm['FontName'] + + if map.size > 0 then + widths['.notdef'] = 600 unless widths['.notdef'] + + if (widths['Delta'] == nil) && widths['increment'] then + widths['Delta'] = widths['increment'] + end + + # Order widths according to map + 0.upto(255) do |i| + if widths[map[i]] == nil + puts "Warning: character #{map[i]} is missing" + widths[i] = widths['.notdef'] + else + widths[i] = widths[map[i]] + end + end + end + + fm['Widths'] = widths + + return fm +end + +def MakeFontDescriptor(fm, symbolic) + + # Ascent + asc = fm['Ascender'] ? fm['Ascender'] : 1000 + fd = "{\n 'Ascent' => '#{asc}'" + + # Descent + desc = fm['Descender'] ? fm['Descender'] : -200 + fd += ", 'Descent' => '#{desc}'" + + # CapHeight + if fm['CapHeight'] then + ch = fm['CapHeight'] + elsif fm['CapXHeight'] + ch = fm['CapXHeight'] + else + ch = asc + end + fd += ", 'CapHeight' => '#{ch}'" + + # Flags + flags = 0 + + if fm['IsFixedPitch'] then + flags += 1 << 0 + end + + if symbolic then + flags += 1 << 2 + else + flags += 1 << 5 + end + + if fm['ItalicAngle'] && (fm['ItalicAngle'] != 0) then + flags += 1 << 6 + end + + fd += ",\n 'Flags' => '#{flags}'" + + # FontBBox + if fm['FontBBox'] then + fbb = fm['FontBBox'].gsub(/,/, ' ') + else + fbb = "[0 #{desc - 100} 1000 #{asc + 100}]" + end + + fd += ", 'FontBBox' => '#{fbb}'" + + # ItalicAngle + ia = fm['ItalicAngle'] ? fm['ItalicAngle'] : 0 + fd += ",\n 'ItalicAngle' => '#{ia}'" + + # StemV + if fm['StdVW'] then + stemv = fm['StdVW'] + elsif fm['Weight'] && (/bold|black/i =~ fm['Weight']) + stemv = 120 + else + stemv = 70 + end + + fd += ", 'StemV' => '#{stemv}'" + + # MissingWidth + if fm['MissingWidth'] then + fd += ", 'MissingWidth' => '#{fm['MissingWidth']}'" + end + + fd += "\n }" + return fd +end + +def MakeWidthArray(fm) + + # Make character width array + s = " [\n " + + cw = fm['Widths'] + + 0.upto(255) do |i| + s += "%5d" % cw[i] + s += "," if i != 255 + s += "\n " if (i % 8) == 7 + end + + s += ']' + + return s +end + +def MakeFontEncoding(map) + + # Build differences from reference encoding + ref = Charencodings['cp1252'] + s = '' + last = 0 + 32.upto(255) do |i| + if map[i] != ref[i] then + if i != last + 1 then + s += i.to_s + ' ' + end + last = i + s += '/' + map[i] + ' ' + end + end + return s.rstrip +end + +def ReadShort(f) + a = f.read(2).unpack('n') + return a[0] +end + +def ReadLong(f) + a = f.read(4).unpack('N') + return a[0] +end + +def CheckTTF(file) + + rl = false + pp = false + e = false + + # Check if font license allows embedding + File.open(file, 'rb') do |f| + + # Extract number of tables + f.seek(4, IO::SEEK_CUR) + nb = ReadShort(f) + f.seek(6, IO::SEEK_CUR) + + # Seek OS/2 table + found = false + 0.upto(nb - 1) do |i| + if f.read(4) == 'OS/2' then + found = true + break + end + + f.seek(12, IO::SEEK_CUR) + end + + if ! found then + return + end + + f.seek(4, IO::SEEK_CUR) + offset = ReadLong(f) + f.seek(offset, IO::SEEK_SET) + + # Extract fsType flags + f.seek(8, IO::SEEK_CUR) + fsType = ReadShort(f) + + rl = (fsType & 0x02) != 0 + pp = (fsType & 0x04) != 0 + e = (fsType & 0x08) != 0 + end + + if rl && ( ! pp) && ( ! e) then + puts 'Warning: font license does not allow embedding' + end +end + +# +# fontfile: path to TTF file (or empty string if not to be embedded) +# afmfile: path to AFM file +# enc: font encoding (or empty string for symbolic fonts) +# patch: optional patch for encoding +# type : font type if $fontfile is empty +# +def MakeFont(fontfile, afmfile, enc = 'cp1252', patch = {}, type = 'TrueType') + # Generate a font definition file + if (enc != nil) && (enc != '') then + map = Charencodings[enc] + patch.each { |cc, gn| map[cc] = gn } + else + map = [] + end + + raise "Error: AFM file not found: #{afmfile}" unless File.exists?(afmfile) + + fm = ReadAFM(afmfile, map) + + if (enc != nil) && (enc != '') then + diff = MakeFontEncoding(map) + else + diff = '' + end + + fd = MakeFontDescriptor(fm, (map.size == 0)) + + # Find font type + if fontfile then + ext = File.extname(fontfile).downcase.sub(/^\./, '') + + if ext == 'ttf' then + type = 'TrueType' + elsif ext == 'pfb' + type = 'Type1' + else + raise "Error: unrecognized font file extension: #{ext}" + end + else + raise "Error: incorrect font type: #{type}" if (type != 'TrueType') && (type != 'Type1') + end + printf "type = #{type}\n" + # Start generation + s = "# #{fm['FontName']} font definition\n\n" + s += "module FontDef\n" + s += " def FontDef.type\n '#{type}'\n end\n" + s += " def FontDef.name\n '#{fm['FontName']}'\n end\n" + s += " def FontDef.desc\n #{fd}\n end\n" + + if fm['UnderlinePosition'] == nil then + fm['UnderlinePosition'] = -100 + end + + if fm['UnderlineThickness'] == nil then + fm['UnderlineThickness'] = 50 + end + + s += " def FontDef.up\n #{fm['UnderlinePosition']}\n end\n" + s += " def FontDef.ut\n #{fm['UnderlineThickness']}\n end\n" + + w = MakeWidthArray(fm) + s += " def FontDef.cw\n#{w}\n end\n" + + s += " def FontDef.enc\n '#{enc}'\n end\n" + s += " def FontDef.diff\n #{(diff == nil) || (diff == '') ? 'nil' : '\'' + diff '\''}\n end\n" + + basename = File.basename(afmfile, '.*') + + if fontfile then + # Embedded font + if ! File.exist?(fontfile) then + raise "Error: font file not found: #{fontfile}" + end + + if type == 'TrueType' then + CheckTTF(fontfile) + end + + file = '' + File.open(fontfile, 'rb') do |f| + file = f.read() + end + + if type == 'Type1' then + # Find first two sections and discard third one + header = file[0] == 128 + file = file[6, file.length - 6] if header + + pos = file.index('eexec') + raise 'Error: font file does not seem to be valid Type1' if pos == nil + + size1 = pos + 6 + + file = file[0, size1] + file[size1 + 6, file.length - (size1 + 6)] if header && file[size1] == 128 + + pos = file.index('00000000') + raise 'Error: font file does not seem to be valid Type1' if pos == nil + + size2 = pos - size1 + file = file[0, size1 + size2] + end + + if require 'zlib' then + File.open(basename + '.z', 'wb') { |f| f.write(Zlib::Deflate.deflate(file)) } + s += " def FontDef.file\n '#{basename}.z'\n end\n" + puts "Font file compressed ('#{basename}.z')" + else + s += " def FontDef.file\n '#{File.basename(fontfile)}'\n end\n" + puts 'Notice: font file could not be compressed (zlib not available)' + end + + if type == 'Type1' then + s += " def FontDef.size1\n '#{size1}'\n end\n" + s += " def FontDef.size2\n '#{size2}'\n end\n" + else + s += " def FontDef.originalsize\n '#{File.size(fontfile)}'\n end\n" + end + + else + # Not embedded font + s += " def FontDef.file\n ''\n end\n" + end + + s += "end\n" + File.open(basename + '.rb', 'w') { |file| file.write(s)} + puts "Font definition file generated (#{basename}.rb)" +end + + +if $0 == __FILE__ then + if ARGV.length >= 3 then + enc = ARGV[2] + else + enc = 'cp1252' + end + + if ARGV.length >= 4 then + patch = ARGV[3] + else + patch = {} + end + + if ARGV.length >= 5 then + type = ARGV[4] + else + type = 'TrueType' + end + + MakeFont(ARGV[0], ARGV[1], enc, patch, type) +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c8/c84d690d9bd0576dfc0e1af20e017bb13ff2e71d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c8/c84d690d9bd0576dfc0e1af20e017bb13ff2e71d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1311 @@ +# $Id: ldap.rb 154 2006-08-15 09:35:43Z blackhedd $ +# +# Net::LDAP for Ruby +# +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Written and maintained by Francis Cianfrocca, gmail: garbagecat10. +# +# This program is free software. +# You may re-distribute and/or modify this program under the same terms +# as Ruby itself: Ruby Distribution License or GNU General Public License. +# +# +# See Net::LDAP for documentation and usage samples. +# + + +require 'socket' +require 'ostruct' + +begin + require 'openssl' + $net_ldap_openssl_available = true +rescue LoadError +end + +require 'net/ber' +require 'net/ldap/pdu' +require 'net/ldap/filter' +require 'net/ldap/dataset' +require 'net/ldap/psw' +require 'net/ldap/entry' + + +module Net + + + # == Net::LDAP + # + # This library provides a pure-Ruby implementation of the + # LDAP client protocol, per RFC-2251. + # It can be used to access any server which implements the + # LDAP protocol. + # + # Net::LDAP is intended to provide full LDAP functionality + # while hiding the more arcane aspects + # the LDAP protocol itself, and thus presenting as Ruby-like + # a programming interface as possible. + # + # == Quick-start for the Impatient + # === Quick Example of a user-authentication against an LDAP directory: + # + # require 'rubygems' + # require 'net/ldap' + # + # ldap = Net::LDAP.new + # ldap.host = your_server_ip_address + # ldap.port = 389 + # ldap.auth "joe_user", "opensesame" + # if ldap.bind + # # authentication succeeded + # else + # # authentication failed + # end + # + # + # === Quick Example of a search against an LDAP directory: + # + # require 'rubygems' + # require 'net/ldap' + # + # ldap = Net::LDAP.new :host => server_ip_address, + # :port => 389, + # :auth => { + # :method => :simple, + # :username => "cn=manager,dc=example,dc=com", + # :password => "opensesame" + # } + # + # filter = Net::LDAP::Filter.eq( "cn", "George*" ) + # treebase = "dc=example,dc=com" + # + # ldap.search( :base => treebase, :filter => filter ) do |entry| + # puts "DN: #{entry.dn}" + # entry.each do |attribute, values| + # puts " #{attribute}:" + # values.each do |value| + # puts " --->#{value}" + # end + # end + # end + # + # p ldap.get_operation_result + # + # + # == A Brief Introduction to LDAP + # + # We're going to provide a quick, informal introduction to LDAP + # terminology and + # typical operations. If you're comfortable with this material, skip + # ahead to "How to use Net::LDAP." If you want a more rigorous treatment + # of this material, we recommend you start with the various IETF and ITU + # standards that relate to LDAP. + # + # === Entities + # LDAP is an Internet-standard protocol used to access directory servers. + # The basic search unit is the entity, which corresponds to + # a person or other domain-specific object. + # A directory service which supports the LDAP protocol typically + # stores information about a number of entities. + # + # === Principals + # LDAP servers are typically used to access information about people, + # but also very often about such items as printers, computers, and other + # resources. To reflect this, LDAP uses the term entity, or less + # commonly, principal, to denote its basic data-storage unit. + # + # + # === Distinguished Names + # In LDAP's view of the world, + # an entity is uniquely identified by a globally-unique text string + # called a Distinguished Name, originally defined in the X.400 + # standards from which LDAP is ultimately derived. + # Much like a DNS hostname, a DN is a "flattened" text representation + # of a string of tree nodes. Also like DNS (and unlike Java package + # names), a DN expresses a chain of tree-nodes written from left to right + # in order from the most-resolved node to the most-general one. + # + # If you know the DN of a person or other entity, then you can query + # an LDAP-enabled directory for information (attributes) about the entity. + # Alternatively, you can query the directory for a list of DNs matching + # a set of criteria that you supply. + # + # === Attributes + # + # In the LDAP view of the world, a DN uniquely identifies an entity. + # Information about the entity is stored as a set of Attributes. + # An attribute is a text string which is associated with zero or more + # values. Most LDAP-enabled directories store a well-standardized + # range of attributes, and constrain their values according to standard + # rules. + # + # A good example of an attribute is sn, which stands for "Surname." + # This attribute is generally used to store a person's surname, or last name. + # Most directories enforce the standard convention that + # an entity's sn attribute have exactly one value. In LDAP + # jargon, that means that sn must be present and + # single-valued. + # + # Another attribute is mail, which is used to store email addresses. + # (No, there is no attribute called "email," perhaps because X.400 terminology + # predates the invention of the term email.) mail differs + # from sn in that most directories permit any number of values for the + # mail attribute, including zero. + # + # + # === Tree-Base + # We said above that X.400 Distinguished Names are globally unique. + # In a manner reminiscent of DNS, LDAP supposes that each directory server + # contains authoritative attribute data for a set of DNs corresponding + # to a specific sub-tree of the (notional) global directory tree. + # This subtree is generally configured into a directory server when it is + # created. It matters for this discussion because most servers will not + # allow you to query them unless you specify a correct tree-base. + # + # Let's say you work for the engineering department of Big Company, Inc., + # whose internet domain is bigcompany.com. You may find that your departmental + # directory is stored in a server with a defined tree-base of + # ou=engineering,dc=bigcompany,dc=com + # You will need to supply this string as the tree-base when querying this + # directory. (Ou is a very old X.400 term meaning "organizational unit." + # Dc is a more recent term meaning "domain component.") + # + # === LDAP Versions + # (stub, discuss v2 and v3) + # + # === LDAP Operations + # The essential operations are: #bind, #search, #add, #modify, #delete, and #rename. + # ==== Bind + # #bind supplies a user's authentication credentials to a server, which in turn verifies + # or rejects them. There is a range of possibilities for credentials, but most directories + # support a simple username and password authentication. + # + # Taken by itself, #bind can be used to authenticate a user against information + # stored in a directory, for example to permit or deny access to some other resource. + # In terms of the other LDAP operations, most directories require a successful #bind to + # be performed before the other operations will be permitted. Some servers permit certain + # operations to be performed with an "anonymous" binding, meaning that no credentials are + # presented by the user. (We're glossing over a lot of platform-specific detail here.) + # + # ==== Search + # Calling #search against the directory involves specifying a treebase, a set of search filters, + # and a list of attribute values. + # The filters specify ranges of possible values for particular attributes. Multiple + # filters can be joined together with AND, OR, and NOT operators. + # A server will respond to a #search by returning a list of matching DNs together with a + # set of attribute values for each entity, depending on what attributes the search requested. + # + # ==== Add + # #add specifies a new DN and an initial set of attribute values. If the operation + # succeeds, a new entity with the corresponding DN and attributes is added to the directory. + # + # ==== Modify + # #modify specifies an entity DN, and a list of attribute operations. #modify is used to change + # the attribute values stored in the directory for a particular entity. + # #modify may add or delete attributes (which are lists of values) or it change attributes by + # adding to or deleting from their values. + # Net::LDAP provides three easier methods to modify an entry's attribute values: + # #add_attribute, #replace_attribute, and #delete_attribute. + # + # ==== Delete + # #delete specifies an entity DN. If it succeeds, the entity and all its attributes + # is removed from the directory. + # + # ==== Rename (or Modify RDN) + # #rename (or #modify_rdn) is an operation added to version 3 of the LDAP protocol. It responds to + # the often-arising need to change the DN of an entity without discarding its attribute values. + # In earlier LDAP versions, the only way to do this was to delete the whole entity and add it + # again with a different DN. + # + # #rename works by taking an "old" DN (the one to change) and a "new RDN," which is the left-most + # part of the DN string. If successful, #rename changes the entity DN so that its left-most + # node corresponds to the new RDN given in the request. (RDN, or "relative distinguished name," + # denotes a single tree-node as expressed in a DN, which is a chain of tree nodes.) + # + # == How to use Net::LDAP + # + # To access Net::LDAP functionality in your Ruby programs, start by requiring + # the library: + # + # require 'net/ldap' + # + # If you installed the Gem version of Net::LDAP, and depending on your version of + # Ruby and rubygems, you _may_ also need to require rubygems explicitly: + # + # require 'rubygems' + # require 'net/ldap' + # + # Most operations with Net::LDAP start by instantiating a Net::LDAP object. + # The constructor for this object takes arguments specifying the network location + # (address and port) of the LDAP server, and also the binding (authentication) + # credentials, typically a username and password. + # Given an object of class Net:LDAP, you can then perform LDAP operations by calling + # instance methods on the object. These are documented with usage examples below. + # + # The Net::LDAP library is designed to be very disciplined about how it makes network + # connections to servers. This is different from many of the standard native-code + # libraries that are provided on most platforms, which share bloodlines with the + # original Netscape/Michigan LDAP client implementations. These libraries sought to + # insulate user code from the workings of the network. This is a good idea of course, + # but the practical effect has been confusing and many difficult bugs have been caused + # by the opacity of the native libraries, and their variable behavior across platforms. + # + # In general, Net::LDAP instance methods which invoke server operations make a connection + # to the server when the method is called. They execute the operation (typically binding first) + # and then disconnect from the server. The exception is Net::LDAP#open, which makes a connection + # to the server and then keeps it open while it executes a user-supplied block. Net::LDAP#open + # closes the connection on completion of the block. + # + + class LDAP + + class LdapError < Exception; end + + VERSION = "0.0.4" + + + SearchScope_BaseObject = 0 + SearchScope_SingleLevel = 1 + SearchScope_WholeSubtree = 2 + SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel, SearchScope_WholeSubtree] + + AsnSyntax = { + :application => { + :constructed => { + 0 => :array, # BindRequest + 1 => :array, # BindResponse + 2 => :array, # UnbindRequest + 3 => :array, # SearchRequest + 4 => :array, # SearchData + 5 => :array, # SearchResult + 6 => :array, # ModifyRequest + 7 => :array, # ModifyResponse + 8 => :array, # AddRequest + 9 => :array, # AddResponse + 10 => :array, # DelRequest + 11 => :array, # DelResponse + 12 => :array, # ModifyRdnRequest + 13 => :array, # ModifyRdnResponse + 14 => :array, # CompareRequest + 15 => :array, # CompareResponse + 16 => :array, # AbandonRequest + 19 => :array, # SearchResultReferral + 24 => :array, # Unsolicited Notification + } + }, + :context_specific => { + :primitive => { + 0 => :string, # password + 1 => :string, # Kerberos v4 + 2 => :string, # Kerberos v5 + }, + :constructed => { + 0 => :array, # RFC-2251 Control + 3 => :array, # Seach referral + } + } + } + + DefaultHost = "127.0.0.1" + DefaultPort = 389 + DefaultAuth = {:method => :anonymous} + DefaultTreebase = "dc=com" + + + ResultStrings = { + 0 => "Success", + 1 => "Operations Error", + 2 => "Protocol Error", + 3 => "Time Limit Exceeded", + 4 => "Size Limit Exceeded", + 12 => "Unavailable crtical extension", + 16 => "No Such Attribute", + 17 => "Undefined Attribute Type", + 20 => "Attribute or Value Exists", + 32 => "No Such Object", + 34 => "Invalid DN Syntax", + 48 => "Invalid DN Syntax", + 48 => "Inappropriate Authentication", + 49 => "Invalid Credentials", + 50 => "Insufficient Access Rights", + 51 => "Busy", + 52 => "Unavailable", + 53 => "Unwilling to perform", + 65 => "Object Class Violation", + 68 => "Entry Already Exists" + } + + + module LdapControls + PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696 + end + + + # + # LDAP::result2string + # + def LDAP::result2string code # :nodoc: + ResultStrings[code] || "unknown result (#{code})" + end + + + attr_accessor :host, :port, :base + + + # Instantiate an object of type Net::LDAP to perform directory operations. + # This constructor takes a Hash containing arguments, all of which are either optional or may be specified later with other methods as described below. The following arguments + # are supported: + # * :host => the LDAP server's IP-address (default 127.0.0.1) + # * :port => the LDAP server's TCP port (default 389) + # * :auth => a Hash containing authorization parameters. Currently supported values include: + # {:method => :anonymous} and + # {:method => :simple, :username => your_user_name, :password => your_password } + # The password parameter may be a Proc that returns a String. + # * :base => a default treebase parameter for searches performed against the LDAP server. If you don't give this value, then each call to #search must specify a treebase parameter. If you do give this value, then it will be used in subsequent calls to #search that do not specify a treebase. If you give a treebase value in any particular call to #search, that value will override any treebase value you give here. + # * :encryption => specifies the encryption to be used in communicating with the LDAP server. The value is either a Hash containing additional parameters, or the Symbol :simple_tls, which is equivalent to specifying the Hash {:method => :simple_tls}. There is a fairly large range of potential values that may be given for this parameter. See #encryption for details. + # + # Instantiating a Net::LDAP object does not result in network traffic to + # the LDAP server. It simply stores the connection and binding parameters in the + # object. + # + def initialize args = {} + @host = args[:host] || DefaultHost + @port = args[:port] || DefaultPort + @verbose = false # Make this configurable with a switch on the class. + @auth = args[:auth] || DefaultAuth + @base = args[:base] || DefaultTreebase + encryption args[:encryption] # may be nil + + if pr = @auth[:password] and pr.respond_to?(:call) + @auth[:password] = pr.call + end + + # This variable is only set when we are created with LDAP::open. + # All of our internal methods will connect using it, or else + # they will create their own. + @open_connection = nil + end + + # Convenience method to specify authentication credentials to the LDAP + # server. Currently supports simple authentication requiring + # a username and password. + # + # Observe that on most LDAP servers, + # the username is a complete DN. However, with A/D, it's often possible + # to give only a user-name rather than a complete DN. In the latter + # case, beware that many A/D servers are configured to permit anonymous + # (uncredentialled) binding, and will silently accept your binding + # as anonymous if you give an unrecognized username. This is not usually + # what you want. (See #get_operation_result.) + # + # Important: The password argument may be a Proc that returns a string. + # This makes it possible for you to write client programs that solicit + # passwords from users or from other data sources without showing them + # in your code or on command lines. + # + # require 'net/ldap' + # + # ldap = Net::LDAP.new + # ldap.host = server_ip_address + # ldap.authenticate "cn=Your Username,cn=Users,dc=example,dc=com", "your_psw" + # + # Alternatively (with a password block): + # + # require 'net/ldap' + # + # ldap = Net::LDAP.new + # ldap.host = server_ip_address + # psw = proc { your_psw_function } + # ldap.authenticate "cn=Your Username,cn=Users,dc=example,dc=com", psw + # + def authenticate username, password + password = password.call if password.respond_to?(:call) + @auth = {:method => :simple, :username => username, :password => password} + end + + alias_method :auth, :authenticate + + # Convenience method to specify encryption characteristics for connections + # to LDAP servers. Called implicitly by #new and #open, but may also be called + # by user code if desired. + # The single argument is generally a Hash (but see below for convenience alternatives). + # This implementation is currently a stub, supporting only a few encryption + # alternatives. As additional capabilities are added, more configuration values + # will be added here. + # + # Currently, the only supported argument is {:method => :simple_tls}. + # (Equivalently, you may pass the symbol :simple_tls all by itself, without + # enclosing it in a Hash.) + # + # The :simple_tls encryption method encrypts all communications with the LDAP + # server. + # It completely establishes SSL/TLS encryption with the LDAP server + # before any LDAP-protocol data is exchanged. + # There is no plaintext negotiation and no special encryption-request controls + # are sent to the server. + # The :simple_tls option is the simplest, easiest way to encrypt communications + # between Net::LDAP and LDAP servers. + # It's intended for cases where you have an implicit level of trust in the authenticity + # of the LDAP server. No validation of the LDAP server's SSL certificate is + # performed. This means that :simple_tls will not produce errors if the LDAP + # server's encryption certificate is not signed by a well-known Certification + # Authority. + # If you get communications or protocol errors when using this option, check + # with your LDAP server administrator. Pay particular attention to the TCP port + # you are connecting to. It's impossible for an LDAP server to support plaintext + # LDAP communications and simple TLS connections on the same port. + # The standard TCP port for unencrypted LDAP connections is 389, but the standard + # port for simple-TLS encrypted connections is 636. Be sure you are using the + # correct port. + # + # [Note: a future version of Net::LDAP will support the STARTTLS LDAP control, + # which will enable encrypted communications on the same TCP port used for + # unencrypted connections.] + # + def encryption args + if args == :simple_tls + args = {:method => :simple_tls} + end + @encryption = args + end + + + # #open takes the same parameters as #new. #open makes a network connection to the + # LDAP server and then passes a newly-created Net::LDAP object to the caller-supplied block. + # Within the block, you can call any of the instance methods of Net::LDAP to + # perform operations against the LDAP directory. #open will perform all the + # operations in the user-supplied block on the same network connection, which + # will be closed automatically when the block finishes. + # + # # (PSEUDOCODE) + # auth = {:method => :simple, :username => username, :password => password} + # Net::LDAP.open( :host => ipaddress, :port => 389, :auth => auth ) do |ldap| + # ldap.search( ... ) + # ldap.add( ... ) + # ldap.modify( ... ) + # end + # + def LDAP::open args + ldap1 = LDAP.new args + ldap1.open {|ldap| yield ldap } + end + + # Returns a meaningful result any time after + # a protocol operation (#bind, #search, #add, #modify, #rename, #delete) + # has completed. + # It returns an #OpenStruct containing an LDAP result code (0 means success), + # and a human-readable string. + # unless ldap.bind + # puts "Result: #{ldap.get_operation_result.code}" + # puts "Message: #{ldap.get_operation_result.message}" + # end + # + def get_operation_result + os = OpenStruct.new + if @result + os.code = @result + else + os.code = 0 + end + os.message = LDAP.result2string( os.code ) + os + end + + + # Opens a network connection to the server and then + # passes self to the caller-supplied block. The connection is + # closed when the block completes. Used for executing multiple + # LDAP operations without requiring a separate network connection + # (and authentication) for each one. + # Note: You do not need to log-in or "bind" to the server. This will + # be done for you automatically. + # For an even simpler approach, see the class method Net::LDAP#open. + # + # # (PSEUDOCODE) + # auth = {:method => :simple, :username => username, :password => password} + # ldap = Net::LDAP.new( :host => ipaddress, :port => 389, :auth => auth ) + # ldap.open do |ldap| + # ldap.search( ... ) + # ldap.add( ... ) + # ldap.modify( ... ) + # end + #-- + # First we make a connection and then a binding, but we don't + # do anything with the bind results. + # We then pass self to the caller's block, where he will execute + # his LDAP operations. Of course they will all generate auth failures + # if the bind was unsuccessful. + def open + raise LdapError.new( "open already in progress" ) if @open_connection + @open_connection = Connection.new( :host => @host, :port => @port, :encryption => @encryption ) + @open_connection.bind @auth + yield self + @open_connection.close + @open_connection = nil + end + + + # Searches the LDAP directory for directory entries. + # Takes a hash argument with parameters. Supported parameters include: + # * :base (a string specifying the tree-base for the search); + # * :filter (an object of type Net::LDAP::Filter, defaults to objectclass=*); + # * :attributes (a string or array of strings specifying the LDAP attributes to return from the server); + # * :return_result (a boolean specifying whether to return a result set). + # * :attributes_only (a boolean flag, defaults false) + # * :scope (one of: Net::LDAP::SearchScope_BaseObject, Net::LDAP::SearchScope_SingleLevel, Net::LDAP::SearchScope_WholeSubtree. Default is WholeSubtree.) + # + # #search queries the LDAP server and passes each entry to the + # caller-supplied block, as an object of type Net::LDAP::Entry. + # If the search returns 1000 entries, the block will + # be called 1000 times. If the search returns no entries, the block will + # not be called. + # + #-- + # ORIGINAL TEXT, replaced 04May06. + # #search returns either a result-set or a boolean, depending on the + # value of the :return_result argument. The default behavior is to return + # a result set, which is a hash. Each key in the hash is a string specifying + # the DN of an entry. The corresponding value for each key is a Net::LDAP::Entry object. + # If you request a result set and #search fails with an error, it will return nil. + # Call #get_operation_result to get the error information returned by + # the LDAP server. + #++ + # #search returns either a result-set or a boolean, depending on the + # value of the :return_result argument. The default behavior is to return + # a result set, which is an Array of objects of class Net::LDAP::Entry. + # If you request a result set and #search fails with an error, it will return nil. + # Call #get_operation_result to get the error information returned by + # the LDAP server. + # + # When :return_result => false, #search will + # return only a Boolean, to indicate whether the operation succeeded. This can improve performance + # with very large result sets, because the library can discard each entry from memory after + # your block processes it. + # + # + # treebase = "dc=example,dc=com" + # filter = Net::LDAP::Filter.eq( "mail", "a*.com" ) + # attrs = ["mail", "cn", "sn", "objectclass"] + # ldap.search( :base => treebase, :filter => filter, :attributes => attrs, :return_result => false ) do |entry| + # puts "DN: #{entry.dn}" + # entry.each do |attr, values| + # puts ".......#{attr}:" + # values.each do |value| + # puts " #{value}" + # end + # end + # end + # + #-- + # This is a re-implementation of search that replaces the + # original one (now renamed searchx and possibly destined to go away). + # The difference is that we return a dataset (or nil) from the + # call, and pass _each entry_ as it is received from the server + # to the caller-supplied block. This will probably make things + # far faster as we can do useful work during the network latency + # of the search. The downside is that we have no access to the + # whole set while processing the blocks, so we can't do stuff + # like sort the DNs until after the call completes. + # It's also possible that this interacts badly with server timeouts. + # We'll have to ensure that something reasonable happens if + # the caller has processed half a result set when we throw a timeout + # error. + # Another important difference is that we return a result set from + # this method rather than a T/F indication. + # Since this can be very heavy-weight, we define an argument flag + # that the caller can set to suppress the return of a result set, + # if he's planning to process every entry as it comes from the server. + # + # REINTERPRETED the result set, 04May06. Originally this was a hash + # of entries keyed by DNs. But let's get away from making users + # handle DNs. Change it to a plain array. Eventually we may + # want to return a Dataset object that delegates to an internal + # array, so we can provide sort methods and what-not. + # + def search args = {} + args[:base] ||= @base + result_set = (args and args[:return_result] == false) ? nil : [] + + if @open_connection + @result = @open_connection.search( args ) {|entry| + result_set << entry if result_set + yield( entry ) if block_given? + } + else + @result = 0 + conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption ) + if (@result = conn.bind( args[:auth] || @auth )) == 0 + @result = conn.search( args ) {|entry| + result_set << entry if result_set + yield( entry ) if block_given? + } + end + conn.close + end + + @result == 0 and result_set + end + + # #bind connects to an LDAP server and requests authentication + # based on the :auth parameter passed to #open or #new. + # It takes no parameters. + # + # User code does not need to call #bind directly. It will be called + # implicitly by the library whenever you invoke an LDAP operation, + # such as #search or #add. + # + # It is useful, however, to call #bind in your own code when the + # only operation you intend to perform against the directory is + # to validate a login credential. #bind returns true or false + # to indicate whether the binding was successful. Reasons for + # failure include malformed or unrecognized usernames and + # incorrect passwords. Use #get_operation_result to find out + # what happened in case of failure. + # + # Here's a typical example using #bind to authenticate a + # credential which was (perhaps) solicited from the user of a + # web site: + # + # require 'net/ldap' + # ldap = Net::LDAP.new + # ldap.host = your_server_ip_address + # ldap.port = 389 + # ldap.auth your_user_name, your_user_password + # if ldap.bind + # # authentication succeeded + # else + # # authentication failed + # p ldap.get_operation_result + # end + # + # You don't have to create a new instance of Net::LDAP every time + # you perform a binding in this way. If you prefer, you can cache the Net::LDAP object + # and re-use it to perform subsequent bindings, provided you call + # #auth to specify a new credential before calling #bind. Otherwise, you'll + # just re-authenticate the previous user! (You don't need to re-set + # the values of #host and #port.) As noted in the documentation for #auth, + # the password parameter can be a Ruby Proc instead of a String. + # + #-- + # If there is an @open_connection, then perform the bind + # on it. Otherwise, connect, bind, and disconnect. + # The latter operation is obviously useful only as an auth check. + # + def bind auth=@auth + if @open_connection + @result = @open_connection.bind auth + else + conn = Connection.new( :host => @host, :port => @port , :encryption => @encryption) + @result = conn.bind @auth + conn.close + end + + @result == 0 + end + + # + # #bind_as is for testing authentication credentials. + # + # As described under #bind, most LDAP servers require that you supply a complete DN + # as a binding-credential, along with an authenticator such as a password. + # But for many applications (such as authenticating users to a Rails application), + # you often don't have a full DN to identify the user. You usually get a simple + # identifier like a username or an email address, along with a password. + # #bind_as allows you to authenticate these user-identifiers. + # + # #bind_as is a combination of a search and an LDAP binding. First, it connects and + # binds to the directory as normal. Then it searches the directory for an entry + # corresponding to the email address, username, or other string that you supply. + # If the entry exists, then #bind_as will re-bind as that user with the + # password (or other authenticator) that you supply. + # + # #bind_as takes the same parameters as #search, with the addition of an + # authenticator. Currently, this authenticator must be :password. + # Its value may be either a String, or a +proc+ that returns a String. + # #bind_as returns +false+ on failure. On success, it returns a result set, + # just as #search does. This result set is an Array of objects of + # type Net::LDAP::Entry. It contains the directory attributes corresponding to + # the user. (Just test whether the return value is logically true, if you don't + # need this additional information.) + # + # Here's how you would use #bind_as to authenticate an email address and password: + # + # require 'net/ldap' + # + # user,psw = "joe_user@yourcompany.com", "joes_psw" + # + # ldap = Net::LDAP.new + # ldap.host = "192.168.0.100" + # ldap.port = 389 + # ldap.auth "cn=manager,dc=yourcompany,dc=com", "topsecret" + # + # result = ldap.bind_as( + # :base => "dc=yourcompany,dc=com", + # :filter => "(mail=#{user})", + # :password => psw + # ) + # if result + # puts "Authenticated #{result.first.dn}" + # else + # puts "Authentication FAILED." + # end + def bind_as args={} + result = false + open {|me| + rs = search args + if rs and rs.first and dn = rs.first.dn + password = args[:password] + password = password.call if password.respond_to?(:call) + result = rs if bind :method => :simple, :username => dn, :password => password + end + } + result + end + + + # Adds a new entry to the remote LDAP server. + # Supported arguments: + # :dn :: Full DN of the new entry + # :attributes :: Attributes of the new entry. + # + # The attributes argument is supplied as a Hash keyed by Strings or Symbols + # giving the attribute name, and mapping to Strings or Arrays of Strings + # giving the actual attribute values. Observe that most LDAP directories + # enforce schema constraints on the attributes contained in entries. + # #add will fail with a server-generated error if your attributes violate + # the server-specific constraints. + # Here's an example: + # + # dn = "cn=George Smith,ou=people,dc=example,dc=com" + # attr = { + # :cn => "George Smith", + # :objectclass => ["top", "inetorgperson"], + # :sn => "Smith", + # :mail => "gsmith@example.com" + # } + # Net::LDAP.open (:host => host) do |ldap| + # ldap.add( :dn => dn, :attributes => attr ) + # end + # + def add args + if @open_connection + @result = @open_connection.add( args ) + else + @result = 0 + conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption) + if (@result = conn.bind( args[:auth] || @auth )) == 0 + @result = conn.add( args ) + end + conn.close + end + @result == 0 + end + + + # Modifies the attribute values of a particular entry on the LDAP directory. + # Takes a hash with arguments. Supported arguments are: + # :dn :: (the full DN of the entry whose attributes are to be modified) + # :operations :: (the modifications to be performed, detailed next) + # + # This method returns True or False to indicate whether the operation + # succeeded or failed, with extended information available by calling + # #get_operation_result. + # + # Also see #add_attribute, #replace_attribute, or #delete_attribute, which + # provide simpler interfaces to this functionality. + # + # The LDAP protocol provides a full and well thought-out set of operations + # for changing the values of attributes, but they are necessarily somewhat complex + # and not always intuitive. If these instructions are confusing or incomplete, + # please send us email or create a bug report on rubyforge. + # + # The :operations parameter to #modify takes an array of operation-descriptors. + # Each individual operation is specified in one element of the array, and + # most LDAP servers will attempt to perform the operations in order. + # + # Each of the operations appearing in the Array must itself be an Array + # with exactly three elements: + # an operator:: must be :add, :replace, or :delete + # an attribute name:: the attribute name (string or symbol) to modify + # a value:: either a string or an array of strings. + # + # The :add operator will, unsurprisingly, add the specified values to + # the specified attribute. If the attribute does not already exist, + # :add will create it. Most LDAP servers will generate an error if you + # try to add a value that already exists. + # + # :replace will erase the current value(s) for the specified attribute, + # if there are any, and replace them with the specified value(s). + # + # :delete will remove the specified value(s) from the specified attribute. + # If you pass nil, an empty string, or an empty array as the value parameter + # to a :delete operation, the _entire_ _attribute_ will be deleted, along + # with all of its values. + # + # For example: + # + # dn = "mail=modifyme@example.com,ou=people,dc=example,dc=com" + # ops = [ + # [:add, :mail, "aliasaddress@example.com"], + # [:replace, :mail, ["newaddress@example.com", "newalias@example.com"]], + # [:delete, :sn, nil] + # ] + # ldap.modify :dn => dn, :operations => ops + # + # (This example is contrived since you probably wouldn't add a mail + # value right before replacing the whole attribute, but it shows that order + # of execution matters. Also, many LDAP servers won't let you delete SN + # because that would be a schema violation.) + # + # It's essential to keep in mind that if you specify more than one operation in + # a call to #modify, most LDAP servers will attempt to perform all of the operations + # in the order you gave them. + # This matters because you may specify operations on the + # same attribute which must be performed in a certain order. + # + # Most LDAP servers will _stop_ processing your modifications if one of them + # causes an error on the server (such as a schema-constraint violation). + # If this happens, you will probably get a result code from the server that + # reflects only the operation that failed, and you may or may not get extended + # information that will tell you which one failed. #modify has no notion + # of an atomic transaction. If you specify a chain of modifications in one + # call to #modify, and one of them fails, the preceding ones will usually + # not be "rolled back," resulting in a partial update. This is a limitation + # of the LDAP protocol, not of Net::LDAP. + # + # The lack of transactional atomicity in LDAP means that you're usually + # better off using the convenience methods #add_attribute, #replace_attribute, + # and #delete_attribute, which are are wrappers over #modify. However, certain + # LDAP servers may provide concurrency semantics, in which the several operations + # contained in a single #modify call are not interleaved with other + # modification-requests received simultaneously by the server. + # It bears repeating that this concurrency does _not_ imply transactional + # atomicity, which LDAP does not provide. + # + def modify args + if @open_connection + @result = @open_connection.modify( args ) + else + @result = 0 + conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption ) + if (@result = conn.bind( args[:auth] || @auth )) == 0 + @result = conn.modify( args ) + end + conn.close + end + @result == 0 + end + + + # Add a value to an attribute. + # Takes the full DN of the entry to modify, + # the name (Symbol or String) of the attribute, and the value (String or + # Array). If the attribute does not exist (and there are no schema violations), + # #add_attribute will create it with the caller-specified values. + # If the attribute already exists (and there are no schema violations), the + # caller-specified values will be _added_ to the values already present. + # + # Returns True or False to indicate whether the operation + # succeeded or failed, with extended information available by calling + # #get_operation_result. See also #replace_attribute and #delete_attribute. + # + # dn = "cn=modifyme,dc=example,dc=com" + # ldap.add_attribute dn, :mail, "newmailaddress@example.com" + # + def add_attribute dn, attribute, value + modify :dn => dn, :operations => [[:add, attribute, value]] + end + + # Replace the value of an attribute. + # #replace_attribute can be thought of as equivalent to calling #delete_attribute + # followed by #add_attribute. It takes the full DN of the entry to modify, + # the name (Symbol or String) of the attribute, and the value (String or + # Array). If the attribute does not exist, it will be created with the + # caller-specified value(s). If the attribute does exist, its values will be + # _discarded_ and replaced with the caller-specified values. + # + # Returns True or False to indicate whether the operation + # succeeded or failed, with extended information available by calling + # #get_operation_result. See also #add_attribute and #delete_attribute. + # + # dn = "cn=modifyme,dc=example,dc=com" + # ldap.replace_attribute dn, :mail, "newmailaddress@example.com" + # + def replace_attribute dn, attribute, value + modify :dn => dn, :operations => [[:replace, attribute, value]] + end + + # Delete an attribute and all its values. + # Takes the full DN of the entry to modify, and the + # name (Symbol or String) of the attribute to delete. + # + # Returns True or False to indicate whether the operation + # succeeded or failed, with extended information available by calling + # #get_operation_result. See also #add_attribute and #replace_attribute. + # + # dn = "cn=modifyme,dc=example,dc=com" + # ldap.delete_attribute dn, :mail + # + def delete_attribute dn, attribute + modify :dn => dn, :operations => [[:delete, attribute, nil]] + end + + + # Rename an entry on the remote DIS by changing the last RDN of its DN. + # _Documentation_ _stub_ + # + def rename args + if @open_connection + @result = @open_connection.rename( args ) + else + @result = 0 + conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption ) + if (@result = conn.bind( args[:auth] || @auth )) == 0 + @result = conn.rename( args ) + end + conn.close + end + @result == 0 + end + + # modify_rdn is an alias for #rename. + def modify_rdn args + rename args + end + + # Delete an entry from the LDAP directory. + # Takes a hash of arguments. + # The only supported argument is :dn, which must + # give the complete DN of the entry to be deleted. + # Returns True or False to indicate whether the delete + # succeeded. Extended status information is available by + # calling #get_operation_result. + # + # dn = "mail=deleteme@example.com,ou=people,dc=example,dc=com" + # ldap.delete :dn => dn + # + def delete args + if @open_connection + @result = @open_connection.delete( args ) + else + @result = 0 + conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption ) + if (@result = conn.bind( args[:auth] || @auth )) == 0 + @result = conn.delete( args ) + end + conn.close + end + @result == 0 + end + + end # class LDAP + + + + class LDAP + # This is a private class used internally by the library. It should not be called by user code. + class Connection # :nodoc: + + LdapVersion = 3 + + + #-- + # initialize + # + def initialize server + begin + @conn = TCPsocket.new( server[:host], server[:port] ) + rescue + raise LdapError.new( "no connection to server" ) + end + + if server[:encryption] + setup_encryption server[:encryption] + end + + yield self if block_given? + end + + + #-- + # Helper method called only from new, and only after we have a successfully-opened + # @conn instance variable, which is a TCP connection. + # Depending on the received arguments, we establish SSL, potentially replacing + # the value of @conn accordingly. + # Don't generate any errors here if no encryption is requested. + # DO raise LdapError objects if encryption is requested and we have trouble setting + # it up. That includes if OpenSSL is not set up on the machine. (Question: + # how does the Ruby OpenSSL wrapper react in that case?) + # DO NOT filter exceptions raised by the OpenSSL library. Let them pass back + # to the user. That should make it easier for us to debug the problem reports. + # Presumably (hopefully?) that will also produce recognizable errors if someone + # tries to use this on a machine without OpenSSL. + # + # The simple_tls method is intended as the simplest, stupidest, easiest solution + # for people who want nothing more than encrypted comms with the LDAP server. + # It doesn't do any server-cert validation and requires nothing in the way + # of key files and root-cert files, etc etc. + # OBSERVE: WE REPLACE the value of @conn, which is presumed to be a connected + # TCPsocket object. + # + def setup_encryption args + case args[:method] + when :simple_tls + raise LdapError.new("openssl unavailable") unless $net_ldap_openssl_available + ctx = OpenSSL::SSL::SSLContext.new + @conn = OpenSSL::SSL::SSLSocket.new(@conn, ctx) + @conn.connect + @conn.sync_close = true + # additional branches requiring server validation and peer certs, etc. go here. + else + raise LdapError.new( "unsupported encryption method #{args[:method]}" ) + end + end + + #-- + # close + # This is provided as a convenience method to make + # sure a connection object gets closed without waiting + # for a GC to happen. Clients shouldn't have to call it, + # but perhaps it will come in handy someday. + def close + @conn.close + @conn = nil + end + + #-- + # next_msgid + # + def next_msgid + @msgid ||= 0 + @msgid += 1 + end + + + #-- + # bind + # + def bind auth + user,psw = case auth[:method] + when :anonymous + ["",""] + when :simple + [auth[:username] || auth[:dn], auth[:password]] + end + raise LdapError.new( "invalid binding information" ) unless (user && psw) + + msgid = next_msgid.to_ber + request = [LdapVersion.to_ber, user.to_ber, psw.to_ber_contextspecific(0)].to_ber_appsequence(0) + request_pkt = [msgid, request].to_ber_sequence + @conn.write request_pkt + + (be = @conn.read_ber(AsnSyntax) and pdu = Net::LdapPdu.new( be )) or raise LdapError.new( "no bind result" ) + pdu.result_code + end + + #-- + # search + # Alternate implementation, this yields each search entry to the caller + # as it are received. + # TODO, certain search parameters are hardcoded. + # TODO, if we mis-parse the server results or the results are wrong, we can block + # forever. That's because we keep reading results until we get a type-5 packet, + # which might never come. We need to support the time-limit in the protocol. + #-- + # WARNING: this code substantially recapitulates the searchx method. + # + # 02May06: Well, I added support for RFC-2696-style paged searches. + # This is used on all queries because the extension is marked non-critical. + # As far as I know, only A/D uses this, but it's required for A/D. Otherwise + # you won't get more than 1000 results back from a query. + # This implementation is kindof clunky and should probably be refactored. + # Also, is it my imagination, or are A/Ds the slowest directory servers ever??? + # + def search args = {} + search_filter = (args && args[:filter]) || Filter.eq( "objectclass", "*" ) + search_filter = Filter.construct(search_filter) if search_filter.is_a?(String) + search_base = (args && args[:base]) || "dc=example,dc=com" + search_attributes = ((args && args[:attributes]) || []).map {|attr| attr.to_s.to_ber} + return_referrals = args && args[:return_referrals] == true + + attributes_only = (args and args[:attributes_only] == true) + scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree + raise LdapError.new( "invalid search scope" ) unless SearchScopes.include?(scope) + + # An interesting value for the size limit would be close to A/D's built-in + # page limit of 1000 records, but openLDAP newer than version 2.2.0 chokes + # on anything bigger than 126. You get a silent error that is easily visible + # by running slapd in debug mode. Go figure. + rfc2696_cookie = [126, ""] + result_code = 0 + + loop { + # should collect this into a private helper to clarify the structure + + request = [ + search_base.to_ber, + scope.to_ber_enumerated, + 0.to_ber_enumerated, + 0.to_ber, + 0.to_ber, + attributes_only.to_ber, + search_filter.to_ber, + search_attributes.to_ber_sequence + ].to_ber_appsequence(3) + + controls = [ + [ + LdapControls::PagedResults.to_ber, + false.to_ber, # criticality MUST be false to interoperate with normal LDAPs. + rfc2696_cookie.map{|v| v.to_ber}.to_ber_sequence.to_s.to_ber + ].to_ber_sequence + ].to_ber_contextspecific(0) + + pkt = [next_msgid.to_ber, request, controls].to_ber_sequence + @conn.write pkt + + result_code = 0 + controls = [] + + while (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) + case pdu.app_tag + when 4 # search-data + yield( pdu.search_entry ) if block_given? + when 19 # search-referral + if return_referrals + if block_given? + se = Net::LDAP::Entry.new + se[:search_referrals] = (pdu.search_referrals || []) + yield se + end + end + #p pdu.referrals + when 5 # search-result + result_code = pdu.result_code + controls = pdu.result_controls + break + else + raise LdapError.new( "invalid response-type in search: #{pdu.app_tag}" ) + end + end + + # When we get here, we have seen a type-5 response. + # If there is no error AND there is an RFC-2696 cookie, + # then query again for the next page of results. + # If not, we're done. + # Don't screw this up or we'll break every search we do. + more_pages = false + if result_code == 0 and controls + controls.each do |c| + if c.oid == LdapControls::PagedResults + more_pages = false # just in case some bogus server sends us >1 of these. + if c.value and c.value.length > 0 + cookie = c.value.read_ber[1] + if cookie and cookie.length > 0 + rfc2696_cookie[1] = cookie + more_pages = true + end + end + end + end + end + + break unless more_pages + } # loop + + result_code + end + + + + + #-- + # modify + # TODO, need to support a time limit, in case the server fails to respond. + # TODO!!! We're throwing an exception here on empty DN. + # Should return a proper error instead, probaby from farther up the chain. + # TODO!!! If the user specifies a bogus opcode, we'll throw a + # confusing error here ("to_ber_enumerated is not defined on nil"). + # + def modify args + modify_dn = args[:dn] or raise "Unable to modify empty DN" + modify_ops = [] + a = args[:operations] and a.each {|op, attr, values| + # TODO, fix the following line, which gives a bogus error + # if the opcode is invalid. + op_1 = {:add => 0, :delete => 1, :replace => 2} [op.to_sym].to_ber_enumerated + modify_ops << [op_1, [attr.to_s.to_ber, values.to_a.map {|v| v.to_ber}.to_ber_set].to_ber_sequence].to_ber_sequence + } + + request = [modify_dn.to_ber, modify_ops.to_ber_sequence].to_ber_appsequence(6) + pkt = [next_msgid.to_ber, request].to_ber_sequence + @conn.write pkt + + (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 7) or raise LdapError.new( "response missing or invalid" ) + pdu.result_code + end + + + #-- + # add + # TODO, need to support a time limit, in case the server fails to respond. + # + def add args + add_dn = args[:dn] or raise LdapError.new("Unable to add empty DN") + add_attrs = [] + a = args[:attributes] and a.each {|k,v| + add_attrs << [ k.to_s.to_ber, v.to_a.map {|m| m.to_ber}.to_ber_set ].to_ber_sequence + } + + request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(8) + pkt = [next_msgid.to_ber, request].to_ber_sequence + @conn.write pkt + + (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 9) or raise LdapError.new( "response missing or invalid" ) + pdu.result_code + end + + + #-- + # rename + # TODO, need to support a time limit, in case the server fails to respond. + # + def rename args + old_dn = args[:olddn] or raise "Unable to rename empty DN" + new_rdn = args[:newrdn] or raise "Unable to rename to empty RDN" + delete_attrs = args[:delete_attributes] ? true : false + + request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber].to_ber_appsequence(12) + pkt = [next_msgid.to_ber, request].to_ber_sequence + @conn.write pkt + + (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 13) or raise LdapError.new( "response missing or invalid" ) + pdu.result_code + end + + + #-- + # delete + # TODO, need to support a time limit, in case the server fails to respond. + # + def delete args + dn = args[:dn] or raise "Unable to delete empty DN" + + request = dn.to_s.to_ber_application_string(10) + pkt = [next_msgid.to_ber, request].to_ber_sequence + @conn.write pkt + + (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 11) or raise LdapError.new( "response missing or invalid" ) + pdu.result_code + end + + + end # class Connection + end # class LDAP + + +end # module Net + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c8/c8702ef29ff3c16a1b898e52dd1bebfb9737ece6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c8/c8702ef29ff3c16a1b898e52dd1bebfb9737ece6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,96 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Member < ActiveRecord::Base + belongs_to :user + belongs_to :principal, :foreign_key => 'user_id' + has_many :member_roles, :dependent => :destroy + has_many :roles, :through => :member_roles + belongs_to :project + + validates_presence_of :principal, :project + validates_uniqueness_of :user_id, :scope => :project_id + + after_destroy :unwatch_from_permission_change + + def name + self.user.name + end + + alias :base_role_ids= :role_ids= + def role_ids=(arg) + ids = (arg || []).collect(&:to_i) - [0] + # Keep inherited roles + ids += member_roles.select {|mr| !mr.inherited_from.nil?}.collect(&:role_id) + + new_role_ids = ids - role_ids + # Add new roles + new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id) } + # Remove roles (Rails' #role_ids= will not trigger MemberRole#on_destroy) + member_roles_to_destroy = member_roles.select {|mr| !ids.include?(mr.role_id)} + if member_roles_to_destroy.any? + member_roles_to_destroy.each(&:destroy) + unwatch_from_permission_change + end + end + + def <=>(member) + a, b = roles.sort.first, member.roles.sort.first + a == b ? (principal <=> member.principal) : (a <=> b) + end + + def deletable? + member_roles.detect {|mr| mr.inherited_from}.nil? + end + + def include?(user) + if principal.is_a?(Group) + !user.nil? && user.groups.include?(principal) + else + self.user == user + end + end + + def before_destroy + if user + # remove category based auto assignments for this member + IssueCategory.update_all "assigned_to_id = NULL", ["project_id = ? AND assigned_to_id = ?", project.id, user.id] + end + end + + # Find or initilize a Member with an id, attributes, and for a Principal + def self.edit_membership(id, new_attributes, principal=nil) + @membership = id.present? ? Member.find(id) : Member.new(:principal => principal) + @membership.attributes = new_attributes + @membership + end + + protected + + def validate + errors.add_on_empty :role if member_roles.empty? && roles.empty? + end + + private + + # Unwatch things that the user is no longer allowed to view inside project + def unwatch_from_permission_change + if user + Watcher.prune(:user => user, :project => project) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c8/c8bf21d1404b2daaac7abe315bbaa50d1e93dc11.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c8/c8bf21d1404b2daaac7abe315bbaa50d1e93dc11.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +begin + require 'openid' +rescue LoadError + begin + gem 'ruby-openid', '>=2.1.4' + rescue Gem::LoadError + # no openid support + end +end + +if Object.const_defined?(:OpenID) + config.to_prepare do + OpenID::Util.logger = Rails.logger + ActionController::Base.send :include, OpenIdAuthentication + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c8/c8da3c273fd9abb66682c7cb71fc3a6abac15623.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c8/c8da3c273fd9abb66682c7cb71fc3a6abac15623.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +x-sender: +x-receiver: +Received: from [127.0.0.1] ([127.0.0.1]) by somenet.foo with Quick 'n Easy Mail Server SMTP (1.0.0.0); + Sun, 14 Dec 2008 16:18:06 GMT +Message-ID: <494531B9.1070709@somenet.foo> +Date: Sun, 14 Dec 2008 17:18:01 +0100 +From: "John Smith" +User-Agent: Thunderbird 2.0.0.18 (Windows/20081105) +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: HTML email +Content-Type: text/html; charset=ISO-8859-1 +Content-Transfer-Encoding: 7bit + + + + + + +This is a html-only email.
    + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c8/c8e7b69b6d4edbb8f6c91d1e8dfed1d65edbf72f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c8/c8e7b69b6d4edbb8f6c91d1e8dfed1d65edbf72f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Gras'; +jsToolBar.strings['Italic'] = 'Italique'; +jsToolBar.strings['Underline'] = 'Souligné'; +jsToolBar.strings['Deleted'] = 'Rayé'; +jsToolBar.strings['Code'] = 'Code en ligne'; +jsToolBar.strings['Heading 1'] = 'Titre niveau 1'; +jsToolBar.strings['Heading 2'] = 'Titre niveau 2'; +jsToolBar.strings['Heading 3'] = 'Titre niveau 3'; +jsToolBar.strings['Unordered list'] = 'Liste à puces'; +jsToolBar.strings['Ordered list'] = 'Liste numérotée'; +jsToolBar.strings['Quote'] = 'Citer'; +jsToolBar.strings['Unquote'] = 'Supprimer citation'; +jsToolBar.strings['Preformatted text'] = 'Texte préformaté'; +jsToolBar.strings['Wiki link'] = 'Lien vers une page Wiki'; +jsToolBar.strings['Image'] = 'Image'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c9/c931f2d34cca31d2bb57a53ae8694c7f520ff6e5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c9/c931f2d34cca31d2bb57a53ae8694c7f520ff6e5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,54 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class News < ActiveRecord::Base + belongs_to :project + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on" + + validates_presence_of :title, :description + validates_length_of :title, :maximum => 60 + validates_length_of :summary, :maximum => 255 + + acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project + acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}} + acts_as_activity_provider :find_options => {:include => [:project, :author]}, + :author_key => :author_id + acts_as_watchable + + after_create :add_author_as_watcher + + named_scope :visible, lambda {|*args| { + :include => :project, + :conditions => Project.allowed_to_condition(args.shift || User.current, :view_news, *args) + }} + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_news, project) + end + + # returns latest news for projects visible by user + def self.latest(user = User.current, count = 5) + find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") + end + + private + + def add_author_as_watcher + Watcher.create(:watchable => self, :user => author) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c9/c98b53052b91d2ade4ab264e541402cfff642b4a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c9/c98b53052b91d2ade4ab264e541402cfff642b4a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,92 @@ +<% form_tag({:action => 'edit', :tab => 'repositories'}) do %> + +
    +<%= hidden_field_tag 'settings[enabled_scm][]', '' %> +<%= l(:setting_enabled_scm) %> + + + + + + + <% Redmine::Scm::Base.all.collect do |choice| %> + <% scm_class = "Repository::#{choice}".constantize %> + <% text, value = (choice.is_a?(Array) ? choice : [choice, choice]) %> + <% setting = :enabled_scm %> + + + + + + <% end %> +
    <%= l(:text_scm_command) %><%= l(:text_scm_command_version) %>
    + <%= + check_box_tag( + "settings[#{setting}][]", + value, + Setting.send(setting).include?(value)) + %> + <%= text.to_s %> + + <%= + image_tag( + (scm_class.scm_available ? 'true.png' : 'exclamation.png'), + :style => "vertical-align:bottom;" + ) + %> + <%= scm_class.scm_command %> + + <%= scm_class.scm_version_string %> +
    +

    <%= l(:text_scm_config) %>

    +
    + +
    +

    <%= setting_check_box :autofetch_changesets %>

    + +

    <%= setting_check_box :sys_api_enabled, + :onclick => + "if (this.checked) { Form.Element.enable('settings_sys_api_key'); } else { Form.Element.disable('settings_sys_api_key'); }" %>

    + +

    <%= setting_text_field :sys_api_key, + :size => 30, + :id => 'settings_sys_api_key', + :disabled => !Setting.sys_api_enabled?, + :label => :setting_mail_handler_api_key %> + <%= link_to_function l(:label_generate_key), + "if ($('settings_sys_api_key').disabled == false) { $('settings_sys_api_key').value = randomKey(20) }" %> +

    + +

    <%= setting_text_field :repository_log_display_limit, :size => 6 %>

    +
    + +
    +<%= l(:text_issues_ref_in_commit_messages) %> +

    <%= setting_text_field :commit_ref_keywords, :size => 30 %>
    +<%= l(:text_comma_separated) %>

    + +

    <%= setting_text_field :commit_fix_keywords, :size => 30 %> + <%= l(:label_applied_status) %>: <%= setting_select :commit_fix_status_id, + [["", 0]] + + IssueStatus.find(:all).collect{ + |status| [status.name, status.id.to_s] + }, + :label => false %> + <%= l(:field_done_ratio) %>: <%= setting_select :commit_fix_done_ratio, + (0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] }, + :blank => :label_no_change_option, + :label => false %> +
    <%= l(:text_comma_separated) %>

    + +

    <%= setting_check_box :commit_logtime_enabled, + :onclick => + "if (this.checked) { Form.Element.enable('settings_commit_logtime_activity_id'); } else { Form.Element.disable('settings_commit_logtime_activity_id'); }"%>

    + +

    <%= setting_select :commit_logtime_activity_id, + [[l(:label_default), 0]] + + TimeEntryActivity.shared.active.collect{|activity| [activity.name, activity.id.to_s]}, + :disabled => !Setting.commit_logtime_enabled?%>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c9/c9d9d8fe02aa83f34233bc2bdafa5296924279e1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c9/c9d9d8fe02aa83f34233bc2bdafa5296924279e1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +default directory for uploaded files \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/c9/c9ed1c5ecdb956b01f130ded5e7336f5878cd4a2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/c9/c9ed1c5ecdb956b01f130ded5e7336f5878cd4a2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +module CodeRay + + # This module holds the Style class and its subclasses. + # + # See Plugin. + module Styles + extend PluginHost + plugin_path File.dirname(__FILE__), 'styles' + + # Base class for styles. + # + # Styles are used by Encoders::HTML to colorize tokens. + class Style + extend Plugin + plugin_host Styles + + DEFAULT_OPTIONS = { } # :nodoc: + + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/ca0155b87af1f6afa9052425d12b486a3be81421.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/ca0155b87af1f6afa9052425d12b486a3be81421.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,462 @@ +# redMine - project management software +# Copyright (C) 2006-2007 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 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class CvsAdapter < AbstractAdapter + + # CVS executable name + CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" + + class << self + def client_command + @@bin ||= CVS_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + client_version_above?([1, 12]) + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}m) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + # Guidelines for the input: + # url -> the project-path, relative to the cvsroot (eg. module name) + # root_url -> the good old, sometimes damned, CVSROOT + # login -> unnecessary + # password -> unnecessary too + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + @url = url + # TODO: better Exception here (IllegalArgumentException) + raise CommandFailed if root_url.blank? + @root_url = root_url + + # These are unused. + @login = login if login && !login.empty? + @password = (password || "") if @login + end + + def path_encoding + @path_encoding + end + + def info + logger.debug " info" + Info.new({:root_url => @root_url, :lastrev => nil}) + end + + def get_previous_revision(revision) + CvsRevisionHelper.new(revision).prevRev + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + # this method is used by the repository-browser (aka LIST) + def entries(path=nil, identifier=nil, options={}) + logger.debug " entries '#{path}' with identifier '#{identifier}'" + path_locale = scm_iconv(@path_encoding, 'UTF-8', path) + path_locale.force_encoding("ASCII-8BIT") if path_locale.respond_to?(:force_encoding) + entries = Entries.new + cmd_args = %w|-q rls -e| + cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier + cmd_args << path_with_proj(path) + scm_cmd(*cmd_args) do |io| + io.each_line() do |line| + fields = line.chop.split('/',-1) + logger.debug(">>InspectLine #{fields.inspect}") + if fields[0]!="D" + time = nil + # Thu Dec 13 16:27:22 2007 + time_l = fields[-3].split(' ') + if time_l.size == 5 && time_l[4].length == 4 + begin + time = Time.parse( + "#{time_l[1]} #{time_l[2]} #{time_l[3]} GMT #{time_l[4]}") + rescue + end + end + entries << Entry.new( + { + :name => scm_iconv('UTF-8', @path_encoding, fields[-5]), + #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]), + :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[-5]}"), + :kind => 'file', + :size => nil, + :lastrev => Revision.new( + { + :revision => fields[-4], + :name => scm_iconv('UTF-8', @path_encoding, fields[-4]), + :time => time, + :author => '' + }) + }) + else + entries << Entry.new( + { + :name => scm_iconv('UTF-8', @path_encoding, fields[1]), + :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[1]}"), + :kind => 'dir', + :size => nil, + :lastrev => nil + }) + end + end + end + entries.sort_by_name + rescue ScmCommandAborted + nil + end + + STARTLOG="----------------------------" + ENDLOG ="=============================================================================" + + # Returns all revisions found between identifier_from and identifier_to + # in the repository. both identifier have to be dates or nil. + # these method returns nothing but yield every result in block + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block) + path_with_project_utf8 = path_with_proj(path) + path_with_project_locale = scm_iconv(@path_encoding, 'UTF-8', path_with_project_utf8) + logger.debug " revisions path:" + + "'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" + cmd_args = %w|-q rlog| + cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from + cmd_args << path_with_project_utf8 + scm_cmd(*cmd_args) do |io| + state = "entry_start" + commit_log = String.new + revision = nil + date = nil + author = nil + entry_path = nil + entry_name = nil + file_state = nil + branch_map = nil + io.each_line() do |line| + if state != "revision" && /^#{ENDLOG}/ =~ line + commit_log = String.new + revision = nil + state = "entry_start" + end + if state == "entry_start" + branch_map = Hash.new + if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project_locale)}(.+),v$/ =~ line + entry_path = normalize_cvs_path($1) + entry_name = normalize_path(File.basename($1)) + logger.debug("Path #{entry_path} <=> Name #{entry_name}") + elsif /^head: (.+)$/ =~ line + entry_headRev = $1 #unless entry.nil? + elsif /^symbolic names:/ =~ line + state = "symbolic" #unless entry.nil? + elsif /^#{STARTLOG}/ =~ line + commit_log = String.new + state = "revision" + end + next + elsif state == "symbolic" + if /^(.*):\s(.*)/ =~ (line.strip) + branch_map[$1] = $2 + else + state = "tags" + next + end + elsif state == "tags" + if /^#{STARTLOG}/ =~ line + commit_log = "" + state = "revision" + elsif /^#{ENDLOG}/ =~ line + state = "head" + end + next + elsif state == "revision" + if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line + if revision + revHelper = CvsRevisionHelper.new(revision) + revBranch = "HEAD" + branch_map.each() do |branch_name, branch_point| + if revHelper.is_in_branch_with_symbol(branch_point) + revBranch = branch_name + end + end + logger.debug("********** YIELD Revision #{revision}::#{revBranch}") + yield Revision.new({ + :time => date, + :author => author, + :message => commit_log.chomp, + :paths => [{ + :revision => revision, + :branch => revBranch, + :path => scm_iconv('UTF-8', @path_encoding, entry_path), + :name => scm_iconv('UTF-8', @path_encoding, entry_name), + :kind => 'file', + :action => file_state + }] + }) + end + commit_log = String.new + revision = nil + if /^#{ENDLOG}/ =~ line + state = "entry_start" + end + next + end + + if /^branches: (.+)$/ =~ line + # TODO: version.branch = $1 + elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line + revision = $1 + elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line + date = Time.parse($1) + line_utf8 = scm_iconv('UTF-8', options[:log_encoding], line) + author_utf8 = /author: ([^;]+)/.match(line_utf8)[1] + author = scm_iconv(options[:log_encoding], 'UTF-8', author_utf8) + file_state = /state: ([^;]+)/.match(line)[1] + # TODO: + # linechanges only available in CVS.... + # maybe a feature our SVN implementation. + # I'm sure, they are useful for stats or something else + # linechanges =/lines: \+(\d+) -(\d+)/.match(line) + # unless linechanges.nil? + # version.line_plus = linechanges[1] + # version.line_minus = linechanges[2] + # else + # version.line_plus = 0 + # version.line_minus = 0 + # end + else + commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/ + end + end + end + end + rescue ScmCommandAborted + Revisions.new + end + + def diff(path, identifier_from, identifier_to=nil) + logger.debug " diff path:'#{path}'" + + ",identifier_from #{identifier_from}, identifier_to #{identifier_to}" + cmd_args = %w|rdiff -u| + cmd_args << "-r#{identifier_to}" + cmd_args << "-r#{identifier_from}" + cmd_args << path_with_proj(path) + diff = [] + scm_cmd(*cmd_args) do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue ScmCommandAborted + nil + end + + def cat(path, identifier=nil) + identifier = (identifier) ? identifier : "HEAD" + logger.debug " cat path:'#{path}',identifier #{identifier}" + cmd_args = %w|-q co| + cmd_args << "-D" << time_to_cvstime(identifier) if identifier + cmd_args << "-p" << path_with_proj(path) + cat = nil + scm_cmd(*cmd_args) do |io| + io.binmode + cat = io.read + end + cat + rescue ScmCommandAborted + nil + end + + def annotate(path, identifier=nil) + identifier = (identifier) ? identifier : "HEAD" + logger.debug " annotate path:'#{path}',identifier #{identifier}" + cmd_args = %w|rannotate| + cmd_args << "-D" << time_to_cvstime(identifier) if identifier + cmd_args << path_with_proj(path) + blame = Annotate.new + scm_cmd(*cmd_args) do |io| + io.each_line do |line| + next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$} + blame.add_line( + $3.rstrip, + Revision.new( + :revision => $1, + :identifier => nil, + :author => $2.strip + )) + end + end + blame + rescue ScmCommandAborted + Annotate.new + end + + private + + # Returns the root url without the connexion string + # :pserver:anonymous@foo.bar:/path => /path + # :ext:cvsservername:/path => /path + def root_url_path + root_url.to_s.gsub(/^:.+:\d*/, '') + end + + # convert a date/time into the CVS-format + def time_to_cvstime(time) + return nil if time.nil? + time = Time.now if time == 'HEAD' + + unless time.kind_of? Time + time = Time.parse(time) + end + return time_to_cvstime_rlog(time) + end + + def time_to_cvstime_rlog(time) + return nil if time.nil? + t1 = time.clone.localtime + return t1.strftime("%Y-%m-%d %H:%M:%S") + end + + def normalize_cvs_path(path) + normalize_path(path.gsub(/Attic\//,'')) + end + + def normalize_path(path) + path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1') + end + + def path_with_proj(path) + "#{url}#{with_leading_slash(path)}" + end + private :path_with_proj + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + revision.to_s + end + end + + def scm_cmd(*args, &block) + full_args = ['-d', root_url] + full_args += args + full_args_locale = [] + full_args.map do |e| + full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) + end + ret = shellout( + self.class.sq_bin + ' ' + full_args_locale.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd + end + + class CvsRevisionHelper + attr_accessor :complete_rev, :revision, :base, :branchid + + def initialize(complete_rev) + @complete_rev = complete_rev + parseRevision() + end + + def branchPoint + return @base + end + + def branchVersion + if isBranchRevision + return @base+"."+@branchid + end + return @base + end + + def isBranchRevision + !@branchid.nil? + end + + def prevRev + unless @revision == 0 + return buildRevision( @revision - 1 ) + end + return buildRevision( @revision ) + end + + def is_in_branch_with_symbol(branch_symbol) + bpieces = branch_symbol.split(".") + branch_start = "#{bpieces[0..-3].join(".")}.#{bpieces[-1]}" + return ( branchVersion == branch_start ) + end + + private + def buildRevision(rev) + if rev == 0 + if @branchid.nil? + @base + ".0" + else + @base + end + elsif @branchid.nil? + @base + "." + rev.to_s + else + @base + "." + @branchid + "." + rev.to_s + end + end + + # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15 + def parseRevision() + pieces = @complete_rev.split(".") + @revision = pieces.last.to_i + baseSize = 1 + baseSize += (pieces.size / 2) + @base = pieces[0..-baseSize].join(".") + if baseSize > 2 + @branchid = pieces[-2] + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/ca0795b70306f0c036dcfe85786cda89b037c6f0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/ca0795b70306f0c036dcfe85786cda89b037c6f0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,97 @@ +# An instance of Plugin is created for each plugin loaded by Rails, and +# stored in the Engines.plugins PluginList +# (see Engines::RailsExtensions::RailsInitializer for more details). +# +# Engines.plugins[:plugin_name] +# +# Other properties of the Plugin instance can also be set. +module Engines + class Plugin < Rails::Plugin + # Plugins can add paths to this attribute in init.rb if they need + # controllers loaded from additional locations. + attr_accessor :controller_paths + + # The directory in this plugin to mirror into the shared directory + # under +public+. + # + # Defaults to "assets" (see default_public_directory). + attr_accessor :public_directory + + protected + # The default set of code paths which will be added to the routing system + def default_controller_paths + %w(app/controllers components) + end + + # Attempts to detect the directory to use for public files. + # If +assets+ exists in the plugin, this will be used. If +assets+ is missing + # but +public+ is found, +public+ will be used. + def default_public_directory + Engines.select_existing_paths(%w(assets public).map { |p| File.join(directory, p) }).first + end + + public + + def initialize(directory) + super directory + @controller_paths = default_controller_paths + @public_directory = default_public_directory + end + + # Extends the superclass' load method to additionally mirror public assets + def load(initializer) + return if loaded? + super initializer + add_plugin_locale_paths + Assets.mirror_files_for(self) + end + + # select those paths that actually exist in the plugin's directory + def select_existing_paths(name) + Engines.select_existing_paths(self.send(name).map { |p| File.join(directory, p) }) + end + + def add_plugin_locale_paths + locale_path = File.join(directory, 'locales') + return unless File.exists?(locale_path) + + locale_files = Dir[File.join(locale_path, '*.{rb,yml}')] + return if locale_files.blank? + + first_app_element = + I18n.load_path.select{ |e| e =~ /^#{ RAILS_ROOT }/ }.reject{ |e| e =~ /^#{ RAILS_ROOT }\/vendor\/plugins/ }.first + app_index = I18n.load_path.index(first_app_element) || - 1 + + I18n.load_path.insert(app_index, *locale_files) + end + + # The path to this plugin's public files + def public_asset_directory + "#{File.basename(Engines.public_directory)}/#{name}" + end + + # The directory containing this plugin's migrations (plugin/db/migrate) + def migration_directory + File.join(self.directory, 'db', 'migrate') + end + + # Returns the version number of the latest migration for this plugin. Returns + # nil if this plugin has no migrations. + def latest_migration + migrations.last + end + + # Returns the version numbers of all migrations for this plugin. + def migrations + migrations = Dir[migration_directory+"/*.rb"] + migrations.map { |p| File.basename(p).match(/0*(\d+)\_/)[1].to_i }.sort + end + + # Migrate this plugin to the given version. See Engines::Plugin::Migrator for more + # information. + def migrate(version = nil) + Engines::Plugin::Migrator.migrate_plugin(self, version) + end + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/ca32a6fd6107d91e2ec44b600a99b4e48d32d15b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/ca32a6fd6107d91e2ec44b600a99b4e48d32d15b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +changeset = 'This template must be used with --debug option\n' +changeset_quiet = 'This template must be used with --debug option\n' +changeset_verbose = 'This template must be used with --debug option\n' +changeset_debug = '\n{author|escape}\n{date|isodatesec}\n\n{file_mods}{file_adds}{file_dels}{file_copies}\n{desc|escape}\n\n{parents}\n\n\n' + +file_mod = '{file_mod|urlescape}\n' +file_add = '{file_add|urlescape}\n' +file_del = '{file_del|urlescape}\n' +file_copy = '{name|urlescape}\n' +parent = '{node|short}\n' +header='\n\n\n' +# footer="" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/caa1ddd4c159daa3892ce812a7b8945e9e584642.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/caa1ddd4c159daa3892ce812a7b8945e9e584642.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,90 @@ +
    +<% if !@query.new_record? && @query.editable_by?(User.current) %> + <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), query_path(@query), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> +<% end %> +
    + +

    <%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %>

    +<% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %> + +<% form_tag({ :controller => 'issues', :action => 'index', :project_id => @project }, :method => :get, :id => 'query_form') do %> + <%= hidden_field_tag 'set_filter', '1' %> +
    +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +
    +

    + + <%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %> + <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %> + <%= link_to_function l(:button_save), "$('query_form').action='#{ @project ? new_project_query_path : new_query_path }'; submit_query_form('query_form')", :class => 'icon icon-save' %> + <% end %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<% if @issues.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> +

    <%= pagination_links_full @issue_pages, @issue_count %>

    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %> + <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '330px'); return false;" %> + <%= f.link_to 'PDF', :url => params %> +<% end %> + + + +<% end %> +<%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %> + <%= auto_discovery_link_tag(:atom, {:controller => 'journals', :action => 'index', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %> +<% end %> + +<%= context_menu issues_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/caa790576a7a41ad0997dc10006135ba339b93a8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/caa790576a7a41ad0997dc10006135ba339b93a8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +<% if @project.issue_categories.any? %> + + + + + + + +<% for category in @project.issue_categories %> + <% unless category.new_record? %> + + + + + + <% end %> +<% end %> + +
    <%= l(:label_issue_category) %><%= l(:field_assigned_to) %>
    <%=h(category.name) %><%=h(category.assigned_to.name) if category.assigned_to %> + <% if User.current.allowed_to?(:manage_categories, @project) %> + <%= link_to l(:button_edit), edit_issue_category_path(category), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), issue_category_path(category), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +

    <%= link_to l(:label_issue_category_new), new_project_issue_category_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_categories, @project) %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/caaf4adc236fed5cfdedcad59181499afa1fb97d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/caaf4adc236fed5cfdedcad59181499afa1fb97d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,205 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/cvs_adapter' +require 'digest/sha1' + +class Repository::Cvs < Repository + validates_presence_of :url, :root_url, :log_encoding + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == "root_url" + attr_name = "cvsroot" + elsif attr_name == "url" + attr_name = "cvs_module" + end + super(attr_name) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::CvsAdapter + end + + def self.scm_name + 'CVS' + end + + def entry(path=nil, identifier=nil) + rev = identifier.nil? ? nil : changesets.find_by_revision(identifier) + scm.entry(path, rev.nil? ? nil : rev.committed_on) + end + + def entries(path=nil, identifier=nil) + rev = nil + if ! identifier.nil? + rev = changesets.find_by_revision(identifier) + return nil if rev.nil? + end + entries = scm.entries(path, rev.nil? ? nil : rev.committed_on) + if entries + entries.each() do |entry| + if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? ) + change=changes.find_by_revision_and_path( + entry.lastrev.revision, + scm.with_leading_slash(entry.path) ) + if change + entry.lastrev.identifier = change.changeset.revision + entry.lastrev.revision = change.changeset.revision + entry.lastrev.author = change.changeset.committer + # entry.lastrev.branch = change.branch + end + end + end + end + entries + end + + def cat(path, identifier=nil) + rev = nil + if ! identifier.nil? + rev = changesets.find_by_revision(identifier) + return nil if rev.nil? + end + scm.cat(path, rev.nil? ? nil : rev.committed_on) + end + + def annotate(path, identifier=nil) + rev = nil + if ! identifier.nil? + rev = changesets.find_by_revision(identifier) + return nil if rev.nil? + end + scm.annotate(path, rev.nil? ? nil : rev.committed_on) + end + + def diff(path, rev, rev_to) + # convert rev to revision. CVS can't handle changesets here + diff=[] + changeset_from = changesets.find_by_revision(rev) + if rev_to.to_i > 0 + changeset_to = changesets.find_by_revision(rev_to) + end + changeset_from.changes.each() do |change_from| + revision_from = nil + revision_to = nil + if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path)) + revision_from = change_from.revision + end + if revision_from + if changeset_to + changeset_to.changes.each() do |change_to| + revision_to = change_to.revision if change_to.path == change_from.path + end + end + unless revision_to + revision_to = scm.get_previous_revision(revision_from) + end + file_diff = scm.diff(change_from.path, revision_from, revision_to) + diff = diff + file_diff unless file_diff.nil? + end + end + return diff + end + + def fetch_changesets + # some nifty bits to introduce a commit-id with cvs + # natively cvs doesn't provide any kind of changesets, + # there is only a revision per file. + # we now take a guess using the author, the commitlog and the commit-date. + + # last one is the next step to take. the commit-date is not equal for all + # commits in one changeset. cvs update the commit-date when the *,v file was touched. so + # we use a small delta here, to merge all changes belonging to _one_ changeset + time_delta = 10.seconds + fetch_since = latest_changeset ? latest_changeset.committed_on : nil + transaction do + tmp_rev_num = 1 + scm.revisions('', fetch_since, nil, :log_encoding => repo_log_encoding) do |revision| + # only add the change to the database, if it doen't exists. the cvs log + # is not exclusive at all. + tmp_time = revision.time.clone + unless changes.find_by_path_and_revision( + scm.with_leading_slash(revision.paths[0][:path]), + revision.paths[0][:revision] + ) + cmt = Changeset.normalize_comments(revision.message, repo_log_encoding) + author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding) + cs = changesets.find( + :first, + :conditions => { + :committed_on => tmp_time - time_delta .. tmp_time + time_delta, + :committer => author_utf8, + :comments => cmt + } + ) + # create a new changeset.... + unless cs + # we use a temporaray revision number here (just for inserting) + # later on, we calculate a continous positive number + tmp_time2 = tmp_time.clone.gmtime + branch = revision.paths[0][:branch] + scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S") + cs = Changeset.create(:repository => self, + :revision => "tmp#{tmp_rev_num}", + :scmid => scmid, + :committer => revision.author, + :committed_on => tmp_time, + :comments => revision.message) + tmp_rev_num += 1 + end + # convert CVS-File-States to internal Action-abbrevations + # default action is (M)odified + action = "M" + if revision.paths[0][:action] == "Exp" && revision.paths[0][:revision] == "1.1" + action = "A" # add-action always at first revision (= 1.1) + elsif revision.paths[0][:action] == "dead" + action = "D" # dead-state is similar to Delete + end + Change.create( + :changeset => cs, + :action => action, + :path => scm.with_leading_slash(revision.paths[0][:path]), + :revision => revision.paths[0][:revision], + :branch => revision.paths[0][:branch] + ) + end + end + + # Renumber new changesets in chronological order + changesets.find( + :all, + :order => 'committed_on ASC, id ASC', + :conditions => "revision LIKE 'tmp%'" + ).each do |changeset| + changeset.update_attribute :revision, next_revision_number + end + end # transaction + @current_revision_number = nil + end + + private + + # Returns the next revision number to assign to a CVS changeset + def next_revision_number + # Need to retrieve existing revision numbers to sort them as integers + sql = "SELECT revision FROM #{Changeset.table_name} " + sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'" + @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0) + @current_revision_number += 1 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/cadd13f5c17692bf3bd94786e8022d3458924f05.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/cadd13f5c17692bf3bd94786e8022d3458924f05.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +User-agent: * +<% @projects.each do |p| -%> +Disallow: /projects/<%= p.to_param %>/repository +Disallow: /projects/<%= p.to_param %>/issues +Disallow: /projects/<%= p.to_param %>/activity +<% end -%> +Disallow: /issues/gantt +Disallow: /issues/calendar +Disallow: /activity diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ca/cade6eedd6319cb3e2496764528bb0106de2f7c9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ca/cade6eedd6319cb3e2496764528bb0106de2f7c9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ + + + <%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil, :class => 'file', + :onchange => "checkFileSize(this, #{Setting.attachment_max_size.to_i.kilobytes}, '#{escape_javascript(l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)))}');" -%> + + <%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %> + + +<%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %> +(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cb0276a6b1828c54ac9135df3c312c39f935b7fa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cb0276a6b1828c54ac9135df3c312c39f935b7fa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,54 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ActionMailerWithinApplicationTest < Test::Unit::TestCase + + def test_normal_implicit_template + m = NotifyMail.create_signup("hello") + assert m.body =~ /^Signup template from application/ + end + + def test_action_mailer_can_get_helper + m = NotifyMail.create_signup('James') + assert m.body =~ /James/ + assert m.body =~ /semaJ/ # from the helper + end + + def test_multipart_mails_with_explicit_templates + m = NotifyMail.create_multipart + assert_equal 2, m.parts.length + assert_equal 'the html part of the email james', m.parts[0].body + assert_equal 'the plaintext part of the email', m.parts[1].body + end + + def test_multipart_mails_with_implicit_templates + m = NotifyMail.create_implicit_multipart + assert_equal 2, m.parts.length + assert_equal 'the implicit plaintext part of the email', m.parts[0].body + assert_equal 'the implicit html part of the email james', m.parts[1].body + end +end + + +class ActionMailerWithinPluginsTest < Test::Unit::TestCase + def test_should_be_able_to_create_mails_from_plugin + m = PluginMail.create_mail_from_plugin("from_plugin") + assert_equal "from_plugin", m.body + end + + def test_should_be_able_to_overload_views_within_the_application + m = PluginMail.create_mail_from_plugin_with_application_template("from_plugin") + assert_equal "from_plugin (from application)", m.body + end + + def test_should_be_able_to_create_a_multipart_mail_from_within_plugin + m = PluginMail.create_multipart_from_plugin + assert_equal 2, m.parts.length + assert_equal 'html template', m.parts[0].body + assert_equal 'plain template', m.parts[1].body + end + + def test_plugin_mailer_template_overriding + m = PluginMail.create_multipart_from_plugin_with_application_template + assert_equal 'plugin mail template loaded from application', m.parts[1].body + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cb0e71af9d9855ebc68f242e545c17bcb9905dc1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cb0e71af9d9855ebc68f242e545c17bcb9905dc1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,271 @@ + + + +RedmineWikiFormatting + + + + + +

    Wiki formatting

    + +

    Links

    + +

    Redmine links

    + +

    Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.

    +
      +
    • Link to an issue: #124 (displays #124, link is striked-through if the issue is closed)
    • +
    • Link to a changeset: r758 (displays r758)
    • +
    • Link to a changeset with a non-numeric hash: commit:c6f4d0fd (displays c6f4d0fd).
    • +
    • Link to a changeset of another project: sandbox:r758 (displays sandbox:r758)
    • +
    • Link to a changeset with a non-numeric hash: sandbox:c6f4d0fd (displays sandbox:c6f4d0fd).
    • +
    + +

    Wiki links:

    + +
      +
    • [[Guide]] displays a link to the page named 'Guide': Guide
    • +
    • [[Guide#further-reading]] takes you to the anchor "further-reading". Headings get automatically assigned anchors so that you can refer to them: Guide
    • +
    • [[Guide|User manual]] displays a link to the same page but with a different text: User manual
    • +
    + +

    You can also link to pages of an other project wiki:

    + +
      +
    • [[sandbox:some page]] displays a link to the page named 'Some page' of the Sandbox wiki
    • +
    • [[sandbox:]] displays a link to the Sandbox wiki main page
    • +
    + +

    Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

    + +

    Links to other resources:

    + +
      +
    • Documents: +
        +
      • document#17 (link to document with id 17)
      • +
      • document:Greetings (link to the document with title "Greetings")
      • +
      • document:"Some document" (double quotes can be used when document title contains spaces)
      • +
      • sandbox:document:"Some document" (link to a document with title "Some document" in other project "sandbox")
      • +
    • +
    + +
      +
    • Versions: +
        +
      • version#3 (link to version with id 3)
      • +
      • version:1.0.0 (link to version named "1.0.0")
      • +
      • version:"1.0 beta 2"
      • +
      • sandbox:version:1.0.0 (link to version "1.0.0" in the project "sandbox")
      • +
    • +
    + +
      +
    • Attachments: +
        +
      • attachment:file.zip (link to the attachment of the current object named file.zip)
      • +
      • For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)
      • +
    • +
    + +
      +
    • Repository files: +
        +
      • source:some/file (link to the file located at /some/file in the project's repository)
      • +
      • source:some/file@52 (link to the file's revision 52)
      • +
      • source:some/file#L120 (link to line 120 of the file)
      • +
      • source:some/file@52#L120 (link to line 120 of the file's revision 52)
      • +
      • source:"some file@52#L120" (use double quotes when the URL contains spaces
      • +
      • export:some/file (force the download of the file)
      • +
      • sandbox:source:some/file (link to the file located at /some/file in the repository of the project "sandbox")
      • +
      • sandbox:export:some/file (force the download of the file)
      • +
    • +
    + +
      +
    • Forum messages: +
        +
      • message#1218 (link to message with id 1218)
      • +
    • +
    + +
      +
    • Projects: +
        +
      • project#3 (link to project with id 3)
      • +
      • project:someproject (link to project named "someproject")
      • +
    • +
    + + +

    Escaping:

    + +
      +
    • You can prevent Redmine links from being parsed by preceding them with an exclamation mark: !
    • +
    + + +

    External links

    + +

    HTTP URLs and email addresses are automatically turned into clickable links:

    + +
    +http://www.redmine.org, someone@foo.bar
    +
    + +

    displays: http://www.redmine.org,

    + +

    If you want to display a specific text instead of the URL, you can use the standard textile syntax:

    + +
    +"Redmine web site":http://www.redmine.org
    +
    + +

    displays: Redmine web site

    + + +

    Text formatting

    + + +

    For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See http://www.textism.com/tools/textile/ for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

    + +

    Font style

    + +
    +* *bold*
    +* _italic_
    +* _*bold italic*_
    +* +underline+
    +* -strike-through-
    +
    + +

    Display:

    + +
      +
    • bold
    • +
    • italic
    • +
    • *bold italic*
    • +
    • underline
    • +
    • strike-through
    • +
    + +

    Inline images

    + +
      +
    • !image_url! displays an image located at image_url (textile syntax)
    • +
    • !>image_url! right floating image
    • +
    • If you have an image attached to your wiki page, it can be displayed inline using its filename: !attached_image.png!
    • +
    + +

    Headings

    + +
    +h1. Heading
    +h2. Subheading
    +h3. Subsubheading
    +
    + +

    Redmine assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.

    + + +

    Paragraphs

    + +
    +p>. right aligned
    +p=. centered
    +
    + +

    This is a centered paragraph.

    + + +

    Blockquotes

    + +

    Start the paragraph with bq.

    + +
    +bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    +To go live, all you need to add is a database and a web server.
    +
    + +

    Display:

    + +
    +

    Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    To go live, all you need to add is a database and a web server.

    +
    + + +

    Table of content

    + +
    +{{toc}} => left aligned toc
    +{{>toc}} => right aligned toc
    +
    + +

    Macros

    + +

    Redmine has the following builtin macros:

    + +

    hello_world

    Sample macro.

    include

    Include a wiki page. Example:

    + +
    {{include(Foo)}}
    macro_list

    Displays a list of all available macros, including description if available.

    + + +

    Code highlighting

    + +

    Default code highlightment relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.

    + +

    You can highlight code in your wiki page using this syntax:

    + +
    +<pre><code class="ruby">
    +  Place you code here.
    +</code></pre>
    +
    + +

    Example:

    + +
     1 # The Greeter class
    + 2 class Greeter
    + 3   def initialize(name)
    + 4     @name = name.capitalize
    + 5   end
    + 6 
    + 7   def salute
    + 8     puts "Hello #{@name}!" 
    + 9   end
    +10 end
    +
    + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cb3e674951a781432401762d4179a55c378e4a30.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cb3e674951a781432401762d4179a55c378e4a30.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +

    Sample block

    + +You are <%= h(User.current) %> and this is a sample block for My Page added from a plugin. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cb77c35e0f5d712e80f322b3491b400888bdeef9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cb77c35e0f5d712e80f322b3491b400888bdeef9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb')) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cb8860bc881def0adbb33f2d3107b033de5fdd84.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cb8860bc881def0adbb33f2d3107b033de5fdd84.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,69 @@ +
    +<% if @editable %> +<%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.current_version? %> +<%= watcher_tag(@page, User.current) %> +<%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %> +<%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %> +<%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') if @content.current_version? %> +<%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %> +<%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page.title, :version => @content.version }, :class => 'icon icon-cancel') unless @content.current_version? %> +<% end %> +<%= link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +<% unless @content.current_version? %> +

    + <%= link_to(("\xc2\xab " + l(:label_previous)), + :action => 'show', :id => @page.title, :project_id => @page.project, + :version => (@content.version - 1)) + " - " if @content.version > 1 %> + <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> + <%= '(' + link_to(l(:label_diff), :controller => 'wiki', :action => 'diff', + :id => @page.title, :project_id => @page.project, + :version => @content.version) + ')' if @content.version > 1 %> - + <%= link_to((l(:label_next) + " \xc2\xbb"), :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %> + <%= link_to(l(:label_current_version), :action => 'show', :id => @page.title, :project_id => @page.project) %> +
    + <%= @content.author ? link_to_user(@content.author) : l(:label_user_anonymous) + %>, <%= format_time(@content.updated_on) %>
    + <%=h @content.comments %> +

    +
    +<% end %> + +<%= render(:partial => "wiki/content", :locals => {:content => @content}) %> + +<%= link_to_attachments @page %> + +<% if @editable && authorize_for('wiki', 'add_attachment') %> +
    +

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", + :id => 'attach_files_link' %>

    +<% form_tag({ :controller => 'wiki', :action => 'add_attachment', :project_id => @project, :id => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> +
    +

    <%= render :partial => 'attachments/form' %>

    +
    +<%= submit_tag l(:button_add) %> +<%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %> +<% end %> +
    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'PDF', :url => {:id => @page.title, :version => params[:version]} %> + <%= f.link_to 'HTML', :url => {:id => @page.title, :version => params[:version]} %> + <%= f.link_to 'TXT', :url => {:id => @page.title, :version => params[:version]} %> +<% end if User.current.allowed_to?(:export_wiki_pages, @project) %> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% html_title @page.pretty_title %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cb9498d4606605e6e97dd345a7fb3ba9d914a73a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cb9498d4606605e6e97dd345a7fb3ba9d914a73a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::QueriesTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :queries + + def setup + Setting.rest_api_enabled = '1' + end + + context "/queries" do + context "GET" do + + should "return queries" do + get '/queries.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'queries', + :attributes => {:type => 'array'}, + :child => { + :tag => 'query', + :child => { + :tag => 'id', + :content => '4', + :sibling => { + :tag => 'name', + :content => 'Public query for all projects' + } + } + } + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cb/cbc9695a147fcc463edc9725d0fd463106ff0284.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cb/cbc9695a147fcc463edc9725d0fd463106ff0284.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +# MySQL (default setup). + +production: + adapter: mysql + database: redmine + host: localhost + username: root + password: + encoding: utf8 + +development: + adapter: mysql + database: redmine_development + host: localhost + username: root + password: + encoding: utf8 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: mysql + database: redmine_test + host: localhost + username: root + password: + encoding: utf8 + +test_pgsql: + adapter: postgresql + database: redmine_test + host: localhost + username: postgres + password: "postgres" + +test_sqlite3: + adapter: sqlite3 + database: db/test.sqlite3 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cc/cc6020dd7fb43016d05c4e77058b762d643cb4c2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cc/cc6020dd7fb43016d05c4e77058b762d643cb4c2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1025 @@ +# Polish translations for Ruby on Rails +# by Jacek Becela (jacek.becela@gmail.com, http://github.com/ncr) +# by Krzysztof Podejma (kpodejma@customprojects.pl, http://www.customprojects.pl) + +pl: + number: + format: + separator: "," + delimiter: " " + precision: 2 + currency: + format: + format: "%n %u" + unit: "PLN" + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "B" + other: "B" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + direction: ltr + date: + formats: + default: "%Y-%m-%d" + short: "%d %b" + long: "%d %B %Y" + + day_names: [Niedziela, Poniedziałek, Wtorek, Środa, Czwartek, Piątek, Sobota] + abbr_day_names: [nie, pon, wto, śro, czw, pia, sob] + + month_names: [~, Styczeń, Luty, Marzec, Kwiecień, Maj, Czerwiec, Lipiec, Sierpień, Wrzesień, Październik, Listopad, Grudzień] + abbr_month_names: [~, sty, lut, mar, kwi, maj, cze, lip, sie, wrz, paź, lis, gru] + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%d %B %Y, %H:%M" + am: "przed południem" + pm: "po południu" + + datetime: + distance_in_words: + half_a_minute: "pół minuty" + less_than_x_seconds: + one: "mniej niż sekundę" + few: "mniej niż %{count} sekundy" + other: "mniej niż %{count} sekund" + x_seconds: + one: "sekundę" + few: "%{count} sekundy" + other: "%{count} sekund" + less_than_x_minutes: + one: "mniej niż minutę" + few: "mniej niż %{count} minuty" + other: "mniej niż %{count} minut" + x_minutes: + one: "minutę" + few: "%{count} minuty" + other: "%{count} minut" + about_x_hours: + one: "około godziny" + other: "około %{count} godzin" + x_days: + one: "1 dzień" + other: "%{count} dni" + about_x_months: + one: "około miesiąca" + other: "około %{count} miesięcy" + x_months: + one: "1 miesiąc" + few: "%{count} miesiące" + other: "%{count} miesięcy" + about_x_years: + one: "około roku" + other: "około %{count} lat" + over_x_years: + one: "ponad rok" + few: "ponad %{count} lata" + other: "ponad %{count} lat" + almost_x_years: + one: "prawie rok" + other: "prawie %{count} lata" + + activerecord: + errors: + template: + header: + one: "%{model} nie został zachowany z powodu jednego błędu" + other: "%{model} nie został zachowany z powodu %{count} błędów" + body: "Błędy dotyczą następujących pól:" + messages: + inclusion: "nie znajduje się na liście dopuszczalnych wartości" + exclusion: "znajduje się na liście zabronionych wartości" + invalid: "jest nieprawidłowe" + confirmation: "nie zgadza się z potwierdzeniem" + accepted: "musi być zaakceptowane" + empty: "nie może być puste" + blank: "nie może być puste" + too_long: "jest za długie (maksymalnie %{count} znaków)" + too_short: "jest za krótkie (minimalnie %{count} znaków)" + wrong_length: "jest nieprawidłowej długości (powinna wynosić %{count} znaków)" + taken: "jest już zajęte" + not_a_number: "nie jest liczbą" + greater_than: "musi być większe niż %{count}" + greater_than_or_equal_to: "musi być większe lub równe %{count}" + equal_to: "musi być równe %{count}" + less_than: "musi być mniejsze niż %{count}" + less_than_or_equal_to: "musi być mniejsze lub równe %{count}" + odd: "musi być nieparzyste" + even: "musi być parzyste" + greater_than_start_date: "musi być większe niż początkowa data" + not_same_project: "nie należy do tego samego projektu" + circular_dependency: "Ta relacja może wytworzyć kołową zależność" + cant_link_an_issue_with_a_descendant: "Zagadnienie nie może zostać powiązane z jednym z własnych podzagadnień" + + support: + array: + sentence_connector: "i" + skip_last_comma: true + + # Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BFidea... + # Best regards from Lublin@Poland :-) + # PL translation by Mariusz@Olejnik.net, + actionview_instancetag_blank_option: Proszę wybierz + + button_activate: Aktywuj + button_add: Dodaj + button_annotate: Adnotuj + button_apply: Ustaw + button_archive: Archiwizuj + button_back: Wstecz + button_cancel: Anuluj + button_change: Zmień + button_change_password: Zmień hasło + button_check_all: Zaznacz wszystko + button_clear: Wyczyść + button_configure: Konfiguruj + button_copy: Kopia + button_create: Stwórz + button_delete: Usuń + button_download: Pobierz + button_edit: Edytuj + button_list: Lista + button_lock: Zablokuj + button_log_time: Dziennik + button_login: Login + button_move: Przenieś + button_quote: Cytuj + button_rename: Zmień nazwę + button_reply: Odpowiedz + button_reset: Resetuj + button_rollback: Przywróć do tej wersji + button_save: Zapisz + button_sort: Sortuj + button_submit: Wyślij + button_test: Testuj + button_unarchive: Przywróć z archiwum + button_uncheck_all: Odznacz wszystko + button_unlock: Odblokuj + button_unwatch: Nie obserwuj + button_update: Uaktualnij + button_view: Pokaż + button_watch: Obserwuj + default_activity_design: Projektowanie + default_activity_development: Rozwój + default_doc_category_tech: Dokumentacja techniczna + default_doc_category_user: Dokumentacja użytkownika + default_issue_status_in_progress: W Toku + default_issue_status_closed: Zamknięty + default_issue_status_feedback: Odpowiedź + default_issue_status_new: Nowy + default_issue_status_rejected: Odrzucony + default_issue_status_resolved: Rozwiązany + default_priority_high: Wysoki + default_priority_immediate: Natychmiastowy + default_priority_low: Niski + default_priority_normal: Normalny + default_priority_urgent: Pilny + default_role_developer: Programista + default_role_manager: Kierownik + default_role_reporter: Wprowadzajacy + default_tracker_bug: Błąd + default_tracker_feature: Zadanie + default_tracker_support: Wsparcie + enumeration_activities: Działania (śledzenie czasu) + enumeration_doc_categories: Kategorie dokumentów + enumeration_issue_priorities: Priorytety zagadnień + error_can_t_load_default_data: "Domyślna konfiguracja nie może być załadowana: %{value}" + error_issue_not_found_in_project: 'Zaganienie nie zostało znalezione lub nie należy do tego projektu' + error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacji." + error_scm_command_failed: "Wystąpił błąd przy próbie dostępu do repozytorium: %{value}" + error_scm_not_found: "Obiekt lub wersja nie zostały znalezione w repozytorium." + field_account: Konto + field_activity: Aktywność + field_admin: Administrator + field_assignable: Zagadnienia mogą być przypisane do tej roli + field_assigned_to: Przydzielony do + field_attr_firstname: Imię atrybut + field_attr_lastname: Nazwisko atrybut + field_attr_login: Login atrybut + field_attr_mail: Email atrybut + field_auth_source: Tryb identyfikacji + field_author: Autor + field_base_dn: Base DN + field_category: Kategoria + field_column_names: Nazwy kolumn + field_comments: Komentarz + field_comments_sorting: Pokazuj komentarze + field_created_on: Stworzone + field_default_value: Domyślny + field_delay: Opóźnienie + field_description: Opis + field_done_ratio: "% Wykonane" + field_downloads: Pobrań + field_due_date: Data oddania + field_effective_date: Data + field_estimated_hours: Szacowany czas + field_field_format: Format + field_filename: Plik + field_filesize: Rozmiar + field_firstname: Imię + field_fixed_version: Wersja docelowa + field_hide_mail: Ukryj mój adres email + field_homepage: Strona www + field_host: Host + field_hours: Godzin + field_identifier: Identifikator + field_is_closed: Zagadnienie zamknięte + field_is_default: Domyślny status + field_is_filter: Atrybut filtrowania + field_is_for_all: Dla wszystkich projektów + field_is_in_roadmap: Zagadnienie pokazywane na mapie + field_is_public: Publiczny + field_is_required: Wymagane + field_issue: Zagadnienie + field_issue_to: Powiązania zagadnienia + field_language: Język + field_last_login_on: Ostatnie połączenie + field_lastname: Nazwisko + field_login: Login + field_mail: Email + field_mail_notification: Powiadomienia Email + field_max_length: Maksymalna długość + field_min_length: Minimalna długość + field_name: Nazwa + field_new_password: Nowe hasło + field_notes: Notatki + field_onthefly: Tworzenie użytkownika w locie + field_parent: Nadprojekt + field_parent_title: Strona rodzica + field_password: Hasło + field_password_confirmation: Potwierdzenie + field_port: Port + field_possible_values: Możliwe wartości + field_priority: Priorytet + field_project: Projekt + field_redirect_existing_links: Przekierowanie istniejących odnośników + field_regexp: Wyrażenie regularne + field_role: Rola + field_searchable: Przeszukiwalne + field_spent_on: Data + field_start_date: Start + field_start_page: Strona startowa + field_status: Status + field_subject: Temat + field_subproject: Podprojekt + field_summary: Podsumowanie + field_time_zone: Strefa czasowa + field_title: Tytuł + field_tracker: Typ zagadnienia + field_type: Typ + field_updated_on: Zmienione + field_url: URL + field_user: Użytkownik + field_value: Wartość + field_version: Wersja + field_vf_personnel: Personel + field_vf_watcher: Obserwator + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Polski' + general_pdf_encoding: UTF-8 + general_text_No: 'Nie' + general_text_Yes: 'Tak' + general_text_no: 'nie' + general_text_yes: 'tak' + gui_validation_error: 1 błąd + gui_validation_error_plural234: "%{count} błędy" + gui_validation_error_plural5: "%{count} błędów" + gui_validation_error_plural: "%{count} błędów" + label_activity: Aktywność + label_add_another_file: Dodaj kolejny plik + label_add_note: Dodaj notatkę + label_added: dodane + label_added_time_by: "Dodane przez %{author} %{age} temu" + label_administration: Administracja + label_age: Wiek + label_ago: dni temu + label_all: wszystko + label_all_time: cały czas + label_all_words: Wszystkie słowa + label_and_its_subprojects: "%{value} i podprojekty" + label_applied_status: Stosowany status + label_assigned_to_me_issues: Zagadnienia przypisane do mnie + label_associated_revisions: Skojarzone rewizje + label_attachment: Plik + label_attachment_delete: Usuń plik + label_attachment_new: Nowy plik + label_attachment_plural: Pliki + label_attribute: Atrybut + label_attribute_plural: Atrybuty + label_auth_source: Tryb identyfikacji + label_auth_source_new: Nowy tryb identyfikacji + label_auth_source_plural: Tryby identyfikacji + label_authentication: Identyfikacja + label_blocked_by: zablokowane przez + label_blocks: blokuje + label_board: Forum + label_board_new: Nowe forum + label_board_plural: Fora + label_boolean: Wartość logiczna + label_browse: Przegląd + label_bulk_edit_selected_issues: Zbiorowa edycja zagadnień + label_calendar: Kalendarz + label_change_plural: Zmiany + label_change_properties: Zmień właściwości + label_change_status: Status zmian + label_change_view_all: Pokaż wszystkie zmiany + label_changes_details: Szczegóły wszystkich zmian + label_changeset_plural: Zestawienia zmian + label_chronological_order: W kolejności chronologicznej + label_closed_issues: zamknięte + label_closed_issues_plural234: zamknięte + label_closed_issues_plural5: zamknięte + label_closed_issues_plural: zamknięte + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_comment: Komentarz + label_comment_add: Dodaj komentarz + label_comment_added: Komentarz dodany + label_comment_delete: Usuń komentarze + label_comment_plural234: Komentarze + label_comment_plural5: Komentarze + label_comment_plural: Komentarze + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_commits_per_author: Zatwierdzenia według autorów + label_commits_per_month: Zatwierdzenia według miesięcy + label_confirmation: Potwierdzenie + label_contains: zawiera + label_copied: skopiowano + label_copy_workflow_from: Kopiuj przepływ z + label_current_status: Obecny status + label_current_version: Obecna wersja + label_custom_field: Dowolne pole + label_custom_field_new: Nowe dowolne pole + label_custom_field_plural: Dowolne pola + label_date: Data + label_date_from: Z + label_date_range: Zakres datowy + label_date_to: Do + label_day_plural: dni + label_default: Domyślne + label_default_columns: Domyślne kolumny + label_deleted: usunięte + label_details: Szczegóły + label_diff_inline: w linii + label_diff_side_by_side: obok siebie + label_disabled: zablokowany + label_display_per_page: "Na stronę: %{value}" + label_document: Dokument + label_document_added: Dodano dokument + label_document_new: Nowy dokument + label_document_plural: Dokumenty + label_download: "%{count} Pobranie" + label_download_plural234: "%{count} Pobrania" + label_download_plural5: "%{count} Pobrań" + label_download_plural: "%{count} Pobrania" + label_downloads_abbr: Pobieranie + label_duplicated_by: zduplikowane przez + label_duplicates: duplikuje + label_end_to_end: koniec do końca + label_end_to_start: koniec do początku + label_enumeration_new: Nowa wartość + label_enumerations: Wyliczenia + label_environment: Środowisko + label_equals: równa się + label_example: Przykład + label_export_to: Eksportuj do + label_f_hour: "%{value} godzina" + label_f_hour_plural: "%{value} godzin" + label_feed_plural: Ilość RSS + label_feeds_access_key_created_on: "Klucz dostępu RSS stworzony %{value} dni temu" + label_file_added: Dodano plik + label_file_plural: Pliki + label_filter_add: Dodaj filtr + label_filter_plural: Filtry + label_float: Liczba rzeczywista + label_follows: następuje po + label_gantt: Gantt + label_general: Ogólne + label_generate_key: Wygeneruj klucz + label_help: Pomoc + label_history: Historia + label_home: Główna + label_in: w + label_in_less_than: mniejsze niż + label_in_more_than: większe niż + label_incoming_emails: Przychodząca poczta elektroniczna + label_index_by_date: Indeks wg daty + label_index_by_title: Indeks + label_information: Informacja + label_information_plural: Informacje + label_integer: Liczba całkowita + label_internal: Wewnętrzny + label_issue: Zagadnienie + label_issue_added: Dodano zagadnienie + label_issue_category: Kategoria zagadnienia + label_issue_category_new: Nowa kategoria + label_issue_category_plural: Kategorie zagadnień + label_issue_new: Nowe zagadnienie + label_issue_plural: Zagadnienia + label_issue_status: Status zagadnienia + label_issue_status_new: Nowy status + label_issue_status_plural: Statusy zagadnień + label_issue_tracking: Śledzenie zagadnień + label_issue_updated: Uaktualniono zagadnienie + label_issue_view_all: Zobacz wszystkie zagadnienia + label_issue_watchers: Obserwatorzy + label_issues_by: "Zagadnienia wprowadzone przez %{value}" + label_jump_to_a_project: Skocz do projektu... + label_language_based: Na podstawie języka + label_last_changes: "ostatnie %{count} zmian" + label_last_login: Ostatnie połączenie + label_last_month: ostatni miesiąc + label_last_n_days: "ostatnie %{count} dni" + label_last_week: ostatni tydzień + label_latest_revision: Najnowsza rewizja + label_latest_revision_plural: Najnowsze rewizje + label_ldap_authentication: Autoryzacja LDAP + label_less_than_ago: dni mniej + label_list: Lista + label_loading: Ładowanie... + label_logged_as: Zalogowany jako + label_login: Login + label_logout: Wylogowanie + label_max_size: Maksymalny rozmiar + label_me: ja + label_member: Uczestnik + label_member_new: Nowy uczestnik + label_member_plural: Uczestnicy + label_message_last: Ostatnia wiadomość + label_message_new: Nowa wiadomość + label_message_plural: Wiadomości + label_message_posted: Dodano wiadomość + label_min_max_length: Min - Maks długość + label_modification: "%{count} modyfikacja" + label_modification_plural234: "%{count} modyfikacje" + label_modification_plural5: "%{count} modyfikacji" + label_modification_plural: "%{count} modyfikacje" + label_modified: zmodyfikowane + label_module_plural: Moduły + label_month: Miesiąc + label_months_from: miesiące od + label_more: Więcej + label_more_than_ago: dni więcej + label_my_account: Moje konto + label_my_page: Moja strona + label_my_projects: Moje projekty + label_new: Nowy + label_new_statuses_allowed: Uprawnione nowe statusy + label_news: Komunikat + label_news_added: Dodano komunikat + label_news_latest: Ostatnie komunikaty + label_news_new: Dodaj komunikat + label_news_plural: Komunikaty + label_news_view_all: Pokaż wszystkie komunikaty + label_next: Następne + label_no_change_option: (Bez zmian) + label_no_data: Brak danych do pokazania + label_nobody: nikt + label_none: brak + label_not_contains: nie zawiera + label_not_equals: różni się + label_open_issues: otwarte + label_open_issues_plural234: otwarte + label_open_issues_plural5: otwarte + label_open_issues_plural: otwarte + label_optional_description: Opcjonalny opis + label_options: Opcje + label_overall_activity: Ogólna aktywność + label_overview: Przegląd + label_password_lost: Zapomniane hasło + label_per_page: Na stronę + label_permissions: Uprawnienia + label_permissions_report: Raport uprawnień + label_personalize_page: Personalizuj tą stronę + label_planning: Planowanie + label_please_login: Zaloguj się + label_plugins: Wtyczki + label_precedes: poprzedza + label_preferences: Preferencje + label_preview: Podgląd + label_previous: Poprzednie + label_project: Projekt + label_project_all: Wszystkie projekty + label_project_latest: Ostatnie projekty + label_project_new: Nowy projekt + label_project_plural234: Projekty + label_project_plural5: Projektów + label_project_plural: Projekty + label_x_projects: + zero: brak projektów + one: jeden projekt + other: "%{count} projektów" + label_public_projects: Projekty publiczne + label_query: Kwerenda + label_query_new: Nowa kwerenda + label_query_plural: Kwerendy + label_read: Czytanie... + label_register: Rejestracja + label_registered_on: Zarejestrowany + label_registration_activation_by_email: aktywacja konta przez e-mail + label_registration_automatic_activation: automatyczna aktywacja kont + label_registration_manual_activation: manualna aktywacja kont + label_related_issues: Powiązane zagadnienia + label_relates_to: powiązane z + label_relation_delete: Usuń powiązanie + label_relation_new: Nowe powiązanie + label_renamed: przemianowano + label_reply_plural: Odpowiedzi + label_report: Raport + label_report_plural: Raporty + label_reported_issues: Wprowadzone zagadnienia + label_repository: Repozytorium + label_repository_plural: Repozytoria + label_result_plural: Rezultatów + label_reverse_chronological_order: W kolejności odwrotnej do chronologicznej + label_revision: Rewizja + label_revision_plural: Rewizje + label_roadmap: Mapa + label_roadmap_due_in: W czasie + label_roadmap_no_issues: Brak zagadnień do tej wersji + label_roadmap_overdue: "%{value} spóźnienia" + label_role: Rola + label_role_and_permissions: Role i Uprawnienia + label_role_new: Nowa rola + label_role_plural: Role + label_scm: SCM + label_search: Szukaj + label_search_titles_only: Przeszukuj tylko tytuły + label_send_information: Wyślij informację użytkownikowi + label_send_test_email: Wyślij próbny email + label_settings: Ustawienia + label_show_completed_versions: Pokaż kompletne wersje + label_sort_by: "Sortuj po %{value}" + label_sort_higher: Do góry + label_sort_highest: Przesuń na górę + label_sort_lower: Do dołu + label_sort_lowest: Przesuń na dół + label_spent_time: Przepracowany czas + label_start_to_end: początek do końca + label_start_to_start: początek do początku + label_statistics: Statystyki + label_stay_logged_in: Pozostań zalogowany + label_string: Tekst + label_subproject_plural: Podprojekty + label_text: Długi tekst + label_theme: Temat + label_this_month: ten miesiąc + label_this_week: ten tydzień + label_this_year: ten rok + label_time_tracking: Śledzenie czasu pracy + label_today: dzisiaj + label_topic_plural: Tematy + label_total: Ogółem + label_tracker: Typ zagadnienia + label_tracker_new: Nowy typ zagadnienia + label_tracker_plural: Typy zagadnień + label_updated_time: "Zaktualizowane %{value} temu" + label_used_by: Używane przez + label_user: Użytkownik + label_user_mail_no_self_notified: "Nie chcę powiadomień o zmianach, które sam wprowadzam." + label_user_mail_option_all: "Dla każdego zdarzenia w każdym moim projekcie" + label_user_mail_option_selected: "Tylko dla każdego zdarzenia w wybranych projektach..." + label_user_new: Nowy użytkownik + label_user_plural: Użytkownicy + label_version: Wersja + label_version_new: Nowa wersja + label_version_plural: Wersje + label_view_diff: Pokaż różnice + label_view_revisions: Pokaż rewizje + label_watched_issues: Obserwowane zagadnienia + label_week: Tydzień + label_wiki: Wiki + label_wiki_edit: Edycja wiki + label_wiki_edit_plural: Edycje wiki + label_wiki_page: Strona wiki + label_wiki_page_plural: Strony wiki + label_workflow: Przepływ + label_year: Rok + label_yesterday: wczoraj + mail_body_account_activation_request: "Zarejestrowano nowego użytkownika: (%{value}). Konto oczekuje na twoje zatwierdzenie:" + mail_body_account_information: Twoje konto + mail_body_account_information_external: "Możesz użyć twojego %{value} konta do zalogowania." + mail_body_lost_password: 'W celu zmiany swojego hasła użyj poniższego odnośnika:' + mail_body_register: 'W celu aktywacji Twojego konta, użyj poniższego odnośnika:' + mail_body_reminder: "Wykaz przypisanych do Ciebie zagadnień, których termin wypada w ciągu następnych %{count} dni" + mail_subject_account_activation_request: "Zapytanie aktywacyjne konta %{value}" + mail_subject_lost_password: "Twoje hasło do %{value}" + mail_subject_register: "Aktywacja konta w %{value}" + mail_subject_reminder: "Uwaga na terminy, masz zagadnienia do obsłużenia w ciągu następnych %{count} dni! (%{days})" + notice_account_activated: Twoje konto zostało aktywowane. Możesz się zalogować. + notice_account_invalid_creditentials: Zły użytkownik lub hasło + notice_account_lost_email_sent: Email z instrukcjami zmiany hasła został wysłany do Ciebie. + notice_account_password_updated: Hasło prawidłowo zmienione. + notice_account_pending: "Twoje konto zostało utworzone i oczekuje na zatwierdzenie administratora." + notice_account_register_done: Konto prawidłowo stworzone. + notice_account_unknown_email: Nieznany użytkownik. + notice_account_updated: Konto prawidłowo zaktualizowane. + notice_account_wrong_password: Złe hasło + notice_can_t_change_password: To konto ma zewnętrzne źródło identyfikacji. Nie możesz zmienić hasła. + notice_default_data_loaded: Domyślna konfiguracja została pomyślnie załadowana. + notice_email_error: "Wystąpił błąd w trakcie wysyłania maila (%{value})" + notice_email_sent: "Email został wysłany do %{value}" + notice_failed_to_save_issues: "Błąd podczas zapisu zagadnień %{count} z %{total} zaznaczonych: %{ids}." + notice_feeds_access_key_reseted: Twój klucz dostępu RSS został zrestetowany. + notice_file_not_found: Strona do której próbujesz się dostać nie istnieje lub została usunięta. + notice_locking_conflict: Dane poprawione przez innego użytkownika. + notice_no_issue_selected: "Nie wybrano zagadnienia! Zaznacz zagadnienie, które chcesz edytować." + notice_not_authorized: Nie jesteś autoryzowany by zobaczyć stronę. + notice_successful_connection: Udane nawiązanie połączenia. + notice_successful_create: Utworzenie zakończone sukcesem. + notice_successful_delete: Usunięcie zakończone sukcesem. + notice_successful_update: Uaktualnienie zakończone sukcesem. + notice_unable_delete_version: Nie można usunąć wersji + permission_add_issue_notes: Dodawanie notatek + permission_add_issue_watchers: Dodawanie obserwatorów + permission_add_issues: Dodawanie zagadnień + permission_add_messages: Dodawanie wiadomości + permission_browse_repository: Przeglądanie repozytorium + permission_comment_news: Komentowanie komunikatów + permission_commit_access: Wykonywanie zatwierdzeń + permission_delete_issues: Usuwanie zagadnień + permission_delete_messages: Usuwanie wiadomości + permission_delete_wiki_pages: Usuwanie stron wiki + permission_delete_wiki_pages_attachments: Usuwanie załączników + permission_delete_own_messages: Usuwanie własnych wiadomości + permission_edit_issue_notes: Edycja notatek + permission_edit_issues: Edycja zagadnień + permission_edit_messages: Edycja wiadomości + permission_edit_own_issue_notes: Edycja własnych notatek + permission_edit_own_messages: Edycja własnych wiadomości + permission_edit_own_time_entries: Edycja własnego dziennika + permission_edit_project: Edycja projektów + permission_edit_time_entries: Edycja wpisów dziennika + permission_edit_wiki_pages: Edycja stron wiki + permission_log_time: Zapisywanie przepracowanego czasu + permission_manage_boards: Zarządzanie forami + permission_manage_categories: Zarządzanie kategoriami zaganień + permission_manage_documents: Zarządzanie dokumentami + permission_manage_files: Zarządzanie plikami + permission_manage_issue_relations: Zarządzanie powiązaniami zagadnień + permission_manage_members: Zarządzanie uczestnikami + permission_manage_news: Zarządzanie komunikatami + permission_manage_public_queries: Zarządzanie publicznymi kwerendami + permission_manage_repository: Zarządzanie repozytorium + permission_manage_versions: Zarządzanie wersjami + permission_manage_wiki: Zarządzanie wiki + permission_move_issues: Przenoszenie zagadnień + permission_protect_wiki_pages: Blokowanie stron wiki + permission_rename_wiki_pages: Zmiana nazw stron wiki + permission_save_queries: Zapisywanie kwerend + permission_select_project_modules: Wybieranie modułów projektu + permission_view_calendar: Podgląd kalendarza + permission_view_changesets: Podgląd zmian + permission_view_documents: Podgląd dokumentów + permission_view_files: Podgląd plików + permission_view_gantt: Podgląd diagramu Gantta + permission_view_issue_watchers: Podgląd listy obserwatorów + permission_view_messages: Podgląd wiadomości + permission_view_time_entries: Podgląd przepracowanego czasu + permission_view_wiki_edits: Podgląd historii wiki + permission_view_wiki_pages: Podgląd wiki + project_module_boards: Fora + project_module_documents: Dokumenty + project_module_files: Pliki + project_module_issue_tracking: Śledzenie zagadnień + project_module_news: Komunikaty + project_module_repository: Repozytorium + project_module_time_tracking: Śledzenie czasu pracy + project_module_wiki: Wiki + setting_activity_days_default: Dni wyświetlane w aktywności projektu + setting_app_subtitle: Podtytuł aplikacji + setting_app_title: Tytuł aplikacji + setting_attachment_max_size: Maks. rozm. załącznika + setting_autofetch_changesets: Automatyczne pobieranie zmian + setting_autologin: Auto logowanie + setting_bcc_recipients: Odbiorcy kopii tajnej (kt/bcc) + setting_commit_fix_keywords: Słowa zmieniające status + setting_commit_ref_keywords: Słowa tworzące powiązania + setting_cross_project_issue_relations: Zezwól na powiązania zagadnień między projektami + setting_date_format: Format daty + setting_default_language: Domyślny język + setting_default_projects_public: Nowe projekty są domyślnie publiczne + setting_display_subprojects_issues: Domyślnie pokazuj zagadnienia podprojektów w głównym projekcie + setting_emails_footer: Stopka e-mail + setting_enabled_scm: Dostępny SCM + setting_feeds_limit: Limit danych RSS + setting_gravatar_enabled: Używaj ikon użytkowników Gravatar + setting_host_name: Nazwa hosta i ścieżka + setting_issue_list_default_columns: Domyślne kolumny wyświetlane na liście zagadnień + setting_issues_export_limit: Limit eksportu zagadnień + setting_login_required: Identyfikacja wymagana + setting_mail_from: Adres email wysyłki + setting_mail_handler_api_enabled: Uaktywnij usługi sieciowe (WebServices) dla poczty przychodzącej + setting_mail_handler_api_key: Klucz API + setting_per_page_options: Opcje ilości obiektów na stronie + setting_plain_text_mail: tylko tekst (bez HTML) + setting_protocol: Protokoł + setting_self_registration: Samodzielna rejestracja użytkowników + setting_sequential_project_identifiers: Generuj sekwencyjne identyfikatory projektów + setting_sys_api_enabled: Włączenie WS do zarządzania repozytorium + setting_text_formatting: Formatowanie tekstu + setting_time_format: Format czasu + setting_user_format: Personalny format wyświetlania + setting_welcome_text: Tekst powitalny + setting_wiki_compression: Kompresja historii Wiki + status_active: aktywny + status_locked: zablokowany + status_registered: zarejestrowany + text_are_you_sure: Jesteś pewien ? + text_assign_time_entries_to_project: Przypisz wpisy dziennika do projektu + text_caracters_maximum: "%{count} znaków maksymalnie." + text_caracters_minimum: "Musi być nie krótsze niż %{count} znaków." + text_comma_separated: Wielokrotne wartości dozwolone (rozdzielone przecinkami). + text_default_administrator_account_changed: Zmieniono domyślne hasło administratora + text_destroy_time_entries: Usuń wpisy dziennika + text_destroy_time_entries_question: Przepracowano %{hours} godzin przy zagadnieniu, które chcesz usunąć. Co chcesz zrobić? + text_email_delivery_not_configured: "Dostarczanie poczty elektronicznej nie zostało skonfigurowane, więc powiadamianie jest nieaktywne.\nSkonfiguruj serwer SMTP w config/configuration.yml a następnie zrestartuj aplikację i uaktywnij to." + text_enumeration_category_reassign_to: 'Zmień przypisanie na tą wartość:' + text_enumeration_destroy_question: "%{count} obiektów jest przypisana do tej wartości." + text_file_repository_writable: Zapisywalne repozytorium plików + text_issue_added: "Zagadnienie %{id} zostało wprowadzone (by %{author})." + text_issue_category_destroy_assignments: Usuń przydziały kategorii + text_issue_category_destroy_question: "Zagadnienia (%{count}) są przypisane do tej kategorii. Co chcesz zrobić?" + text_issue_category_reassign_to: Przydziel zagadnienie do tej kategorii + text_issue_updated: "Zagadnienie %{id} zostało zaktualizowane (by %{author})." + text_issues_destroy_confirmation: 'Czy jestes pewien, że chcesz usunąć wskazane zagadnienia?' + text_issues_ref_in_commit_messages: Odwołania do zagadnień w komentarzach zatwierdzeń + text_length_between: "Długość pomiędzy %{min} i %{max} znaków." + text_load_default_configuration: Załaduj domyślną konfigurację + text_min_max_length_info: 0 oznacza brak restrykcji + text_no_configuration_data: "Role użytkowników, typy zagadnień, statusy zagadnień oraz przepływ pracy nie zostały jeszcze skonfigurowane.\nJest wysoce rekomendowane by załadować domyślną konfigurację. Po załadowaniu będzie możliwość edycji tych danych." + text_project_destroy_confirmation: Jesteś pewien, że chcesz usunąć ten projekt i wszystkie powiązane dane? + text_project_identifier_info: 'Małe litery (a-z), liczby i myślniki dozwolone.
    Raz zapisany, identyfikator nie może być zmieniony.' + text_reassign_time_entries: 'Przepnij przepracowany czas do tego zagadnienia:' + text_regexp_info: np. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Wybierz lub uaktualnij przyporządkowanie użytkowników Redmine do użytkowników repozytorium.\nUżytkownicy z taką samą nazwą lub adresem email są przyporządkowani automatycznie." + text_rmagick_available: RMagick dostępne (opcjonalnie) + text_select_mail_notifications: Zaznacz czynności przy których użytkownik powinien być powiadomiony mailem. + text_select_project_modules: 'Wybierz moduły do aktywacji w tym projekcie:' + text_status_changed_by_changeset: "Zastosowane w zmianach %{value}." + text_subprojects_destroy_warning: "Podprojekt(y): %{value} zostaną także usunięte." + text_tip_issue_begin_day: zadanie zaczynające się dzisiaj + text_tip_issue_begin_end_day: zadanie zaczynające i kończące się dzisiaj + text_tip_issue_end_day: zadanie kończące się dzisiaj + text_tracker_no_workflow: Brak przepływu zdefiniowanego dla tego typu zagadnienia + text_unallowed_characters: Niedozwolone znaki + text_user_mail_option: "W przypadku niezaznaczonych projektów, będziesz otrzymywał powiadomienia tylko na temat zagadnień, które obserwujesz, lub w których bierzesz udział (np. jesteś autorem lub adresatem)." + text_user_wrote: "%{value} napisał:" + text_wiki_destroy_confirmation: Jesteś pewien, że chcesz usunąć to wiki i całą jego zawartość ? + text_workflow_edit: Zaznacz rolę i typ zagadnienia do edycji przepływu + + label_user_activity: "Aktywność: %{value}" + label_updated_time_by: "Uaktualnione przez %{author} %{age} temu" + text_diff_truncated: '... Ten plik różnic został przycięty ponieważ jest zbyt długi.' + setting_diff_max_lines_displayed: Maksymalna liczba linii różnicy do pokazania + text_plugin_assets_writable: Zapisywalny katalog zasobów wtyczek + warning_attachments_not_saved: "%{count} załącznik(ów) nie zostało zapisanych." + field_editable: Edytowalne + label_display: Wygląd + button_create_and_continue: Stwórz i dodaj kolejne + text_custom_field_possible_values_info: 'Każda wartość w osobnej linii' + setting_repository_log_display_limit: Maksymalna liczba rewizji pokazywanych w logu pliku + setting_file_max_size_displayed: Maksymalny rozmiar plików tekstowych osadzanych w stronie + field_watcher: Obserwator + setting_openid: Logowanie i rejestracja przy użyciu OpenID + field_identity_url: Identyfikator OpenID (URL) + label_login_with_open_id_option: albo użyj OpenID + field_content: Treść + label_descending: Malejąco + label_sort: Sortuj + label_ascending: Rosnąco + label_date_from_to: Od %{start} do %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Ta strona posiada podstrony (%{descendants}). Co chcesz zrobić? + text_wiki_page_reassign_children: Podepnij je do strony nadrzędnej względem usuwanej + text_wiki_page_nullify_children: Przesuń je na szczyt hierarchii + text_wiki_page_destroy_children: Usuń wszystkie podstrony + setting_password_min_length: Minimalna długość hasła + field_group_by: Grupuj wyniki wg + mail_subject_wiki_content_updated: "Strona wiki '%{id}' została uaktualniona" + label_wiki_content_added: Dodano stronę wiki + mail_subject_wiki_content_added: "Strona wiki '%{id}' została dodana" + mail_body_wiki_content_added: Strona wiki '%{id}' została dodana przez %{author}. + label_wiki_content_updated: Uaktualniono stronę wiki + mail_body_wiki_content_updated: Strona wiki '%{id}' została uaktualniona przez %{author}. + permission_add_project: Tworzenie projektu + setting_new_project_user_role_id: Rola nadawana twórcom projektów, którzy nie posiadają uprawnień administatora + label_view_all_revisions: Pokaż wszystkie rewizje + label_tag: Słowo kluczowe + label_branch: Gałąź + error_no_tracker_in_project: Projekt nie posiada powiązanych typów zagadnień. Sprawdź ustawienia projektu. + error_no_default_issue_status: Nie zdefiniowano domyślnego statusu zagadnień. Sprawdź konfigurację (Przejdź do "Administracja -> Statusy zagadnień). + text_journal_changed: "Zmieniono %{label} z %{old} na %{new}" + text_journal_set_to: "Ustawiono %{label} na %{value}" + text_journal_deleted: "Usunięto %{label} (%{old})" + label_group_plural: Grupy + label_group: Grupa + label_group_new: Nowa grupa + label_time_entry_plural: Przepracowany czas + text_journal_added: "Dodano %{label} %{value}" + field_active: Aktywne + enumeration_system_activity: Aktywność Systemowa + button_copy_and_follow: Kopiuj i przejdź do kopii zagadnienia + button_duplicate: Duplikuj + button_move_and_follow: Przenieś i przejdź do zagadnienia + button_show: Pokaż + error_can_not_archive_project: Ten projekt nie może zostać zarchiwizowany + error_can_not_reopen_issue_on_closed_version: Zagadnienie przydzielone do zakończonej wersji nie może zostać ponownie otwarte + error_issue_done_ratios_not_updated: "% wykonania zagadnienia nie został uaktualniony." + error_workflow_copy_source: Proszę wybrać źródłowy typ zagadnienia lub rolę + error_workflow_copy_target: Proszę wybrać docelowe typ(y) zagadnień i rolę(e) + field_sharing: Współdzielenie + label_api_access_key: Klucz dostępu do API + label_api_access_key_created_on: Klucz dostępu do API został utworzony %{value} temu + label_close_versions: Zamknij ukończone wersje + label_copy_same_as_target: Jak cel + label_copy_source: Źródło + label_copy_target: Cel + label_display_used_statuses_only: Wyświetlaj tylko statusy używane przez ten typ zagadnienia + label_feeds_access_key: Klucz dostępu do RSS + label_missing_api_access_key: Brakuje klucza dostępu do API + label_missing_feeds_access_key: Brakuje klucza dostępu do RSS + label_revision_id: Rewizja %{value} + label_subproject_new: Nowy podprojekt + label_update_issue_done_ratios: Uaktualnij % wykonania + label_user_anonymous: Anonimowy + label_version_sharing_descendants: Z podprojektami + label_version_sharing_hierarchy: Z hierarchią projektów + label_version_sharing_none: Brak współdzielenia + label_version_sharing_system: Ze wszystkimi projektami + label_version_sharing_tree: Z drzewem projektów + notice_api_access_key_reseted: Twój klucz dostępu do API został zresetowany. + notice_issue_done_ratios_updated: Uaktualnienie % wykonania zakończone sukcesem. + permission_add_subprojects: Tworzenie podprojektów + permission_delete_issue_watchers: Usuń obserwatorów + permission_view_issues: Przeglądanie zagadnień + setting_default_projects_modules: Domyślnie włączone moduły dla nowo tworzonych projektów + setting_gravatar_default: Domyślny obraz Gravatar + setting_issue_done_ratio: Obliczaj postęp realizacji zagadnień za pomocą + setting_issue_done_ratio_issue_field: "% Wykonania zagadnienia" + setting_issue_done_ratio_issue_status: Statusu zagadnienia + setting_mail_handler_body_delimiters: Przycinaj e-maile po jednej z tych linii + setting_rest_api_enabled: Uaktywnij usługę sieciową REST + setting_start_of_week: Pierwszy dzień tygodnia + text_line_separated: Dozwolone jest wiele wartości (każda wartość w osobnej linii). + text_own_membership_delete_confirmation: |- + Masz zamiar usunąć niektóre lub wszystkie swoje uprawnienia. Po wykonaniu tej czynności możesz utracić możliwości edycji tego projektu. + Czy na pewno chcesz kontynuować? + version_status_closed: zamknięta + version_status_locked: zablokowana + version_status_open: otwarta + + label_board_sticky: Przyklejona + label_board_locked: Zamknięta + permission_export_wiki_pages: Eksport stron wiki + permission_manage_project_activities: Zarządzanie aktywnościami projektu + setting_cache_formatted_text: Buforuj sformatowany tekst + error_unable_delete_issue_status: Nie można usunąć statusu zagadnienia + label_profile: Profil + permission_manage_subtasks: Zarządzanie podzagadnieniami + field_parent_issue: Zagadnienie nadrzędne + label_subtask_plural: Podzagadnienia + label_project_copy_notifications: Wyślij powiadomienia mailowe przy kopiowaniu projektu + error_can_not_delete_custom_field: Nie można usunąć tego pola + error_unable_to_connect: Nie można połączyć (%{value}) + error_can_not_remove_role: Ta rola przypisana jest niektórym użytkownikom i nie może zostać usunięta. + error_can_not_delete_tracker: Ten typ przypisany jest do części zagadnień i nie może zostać usunięty. + field_principal: Przełożony + label_my_page_block: Elementy + notice_failed_to_save_members: "Nie można zapisać uczestników: %{errors}." + text_zoom_out: Zmniejsz czcionkę + text_zoom_in: Powiększ czcionkę + notice_unable_delete_time_entry: Nie można usunąć wpisu z dziennika. + label_overall_spent_time: Przepracowany czas + field_time_entries: Dziennik + project_module_gantt: Diagram Gantta + project_module_calendar: Kalendarz + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kodowanie komentarzy zatwierdzeń + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cc/cc7238196dd96da8ce92c86fd54dd11d367ca04a.svn-base Binary file .svn/pristine/cc/cc7238196dd96da8ce92c86fd54dd11d367ca04a.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cc/cc7e24029845835ceefcf0f89b3be2506a1df963.svn-base Binary file .svn/pristine/cc/cc7e24029845835ceefcf0f89b3be2506a1df963.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cc/ccad1072a6b0c20c818238d015e69db735382ae9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cc/ccad1072a6b0c20c818238d015e69db735382ae9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +module CollectiveIdea #:nodoc: + module Acts #:nodoc: + module NestedSet #:nodoc: + # This module provides some helpers for the model classes using acts_as_nested_set. + # It is included by default in all views. + # + module Helper + # Returns options for select. + # You can exclude some items from the tree. + # You can pass a block receiving an item and returning the string displayed in the select. + # + # == Params + # * +class_or_item+ - Class name or top level times + # * +mover+ - The item that is being move, used to exlude impossible moves + # * +&block+ - a block that will be used to display: { |item| ... item.name } + # + # == Usage + # + # <%= f.select :parent_id, nested_set_options(Category, @category) {|i| + # "#{'–' * i.level} #{i.name}" + # }) %> + # + def nested_set_options(class_or_item, mover = nil) + class_or_item = class_or_item.roots if class_or_item.is_a?(Class) + items = Array(class_or_item) + result = [] + items.each do |root| + result += root.self_and_descendants.map do |i| + if mover.nil? || mover.new_record? || mover.move_possible?(i) + [yield(i), i.id] + end + end.compact + end + result + end + + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cd0cd3d509a8a2e2326a5695c336ef169a2d874f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cd0cd3d509a8a2e2326a5695c336ef169a2d874f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,201 @@ +module CodeRay +module Scanners + + # Scanner for output of the diff command. + # + # Alias: +patch+ + class Diff < Scanner + + register_for :diff + title 'diff output' + + DEFAULT_OPTIONS = { + :highlight_code => true, + :inline_diff => true, + } + + protected + + require 'coderay/helpers/file_type' + + def scan_tokens encoder, options + + line_kind = nil + state = :initial + deleted_lines = 0 + scanners = Hash.new do |h, lang| + h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true + end + content_scanner = scanners[:plain] + content_scanner_entry_state = nil + + until eos? + + if match = scan(/\n/) + deleted_lines = 0 unless line_kind == :delete + if line_kind + encoder.end_line line_kind + line_kind = nil + end + encoder.text_token match, :space + next + end + + case state + + when :initial + if match = scan(/--- |\+\+\+ |=+|_+/) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + if match = scan(/.*?(?=$|[\t\n\x00]| \(revision)/) + encoder.text_token match, :filename + if options[:highlight_code] + file_type = FileType.fetch(match, :text) + file_type = :text if file_type == :diff + content_scanner = scanners[file_type] + content_scanner_entry_state = nil + end + end + next unless match = scan(/.+/) + encoder.text_token match, :plain + elsif match = scan(/Index: |Property changes on: /) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + next unless match = scan(/.+/) + encoder.text_token match, :plain + elsif match = scan(/Added: /) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + next unless match = scan(/.+/) + encoder.text_token match, :plain + state = :added + elsif match = scan(/\\ .*/) + encoder.text_token match, :comment + elsif match = scan(/@@(?>[^@\n]*)@@/) + content_scanner.state = :initial unless match?(/\n\+/) + content_scanner_entry_state = nil + if check(/\n|$/) + encoder.begin_line line_kind = :change + else + encoder.begin_group :change + end + encoder.text_token match[0,2], :change + encoder.text_token match[2...-2], :plain + encoder.text_token match[-2,2], :change + encoder.end_group :change unless line_kind + next unless match = scan(/.+/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/\+/) + encoder.begin_line line_kind = :insert + encoder.text_token match, :insert + next unless match = scan(/.+/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/-/) + deleted_lines += 1 + encoder.begin_line line_kind = :delete + encoder.text_token match, :delete + if options[:inline_diff] && deleted_lines == 1 && check(/(?>.*)\n\+(?>.*)$(?!\n\+)/) + content_scanner_entry_state = content_scanner.state + skip(/(.*)\n\+(.*)$/) + head, deletion, insertion, tail = diff self[1], self[2] + pre, deleted, post = content_scanner.tokenize [head, deletion, tail], :tokens => Tokens.new + encoder.tokens pre + unless deleted.empty? + encoder.begin_group :eyecatcher + encoder.tokens deleted + encoder.end_group :eyecatcher + end + encoder.tokens post + encoder.end_line line_kind + encoder.text_token "\n", :space + encoder.begin_line line_kind = :insert + encoder.text_token '+', :insert + content_scanner.state = content_scanner_entry_state || :initial + pre, inserted, post = content_scanner.tokenize [head, insertion, tail], :tokens => Tokens.new + encoder.tokens pre + unless inserted.empty? + encoder.begin_group :eyecatcher + encoder.tokens inserted + encoder.end_group :eyecatcher + end + encoder.tokens post + elsif match = scan(/.*/) + if options[:highlight_code] + if deleted_lines == 1 + content_scanner_entry_state = content_scanner.state + end + content_scanner.tokenize match, :tokens => encoder unless match.empty? + if !match?(/\n-/) + if match?(/\n\+/) + content_scanner.state = content_scanner_entry_state || :initial + end + content_scanner_entry_state = nil + end + else + encoder.text_token match, :plain + end + end + next + elsif match = scan(/ .*/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/.+/) + encoder.begin_line line_kind = :comment + encoder.text_token match, :plain + else + raise_inspect 'else case rached' + end + + when :added + if match = scan(/ \+/) + encoder.begin_line line_kind = :insert + encoder.text_token match, :insert + next unless match = scan(/.+/) + encoder.text_token match, :plain + else + state = :initial + next + end + end + + end + + encoder.end_line line_kind if line_kind + + encoder + end + + private + + def diff a, b + # i will be the index of the leftmost difference from the left. + i_max = [a.size, b.size].min + i = 0 + i += 1 while i < i_max && a[i] == b[i] + # j_min will be the index of the leftmost difference from the right. + j_min = i - i_max + # j will be the index of the rightmost difference from the right which + # does not precede the leftmost one from the left. + j = -1 + j -= 1 while j >= j_min && a[j] == b[j] + return a[0...i], a[i..j], b[i..j], (j < -1) ? a[j+1..-1] : '' + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cd412581b9626dbf7e98af61ce1dd6cc17d027b2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cd412581b9626dbf7e98af61ce1dd6cc17d027b2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,104 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/bazaar_adapter' + +class Repository::Bazaar < Repository + attr_protected :root_url + validates_presence_of :url, :log_encoding + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::BazaarAdapter + end + + def self.scm_name + 'Bazaar' + end + + def entries(path=nil, identifier=nil) + entries = scm.entries(path, identifier) + if entries + entries.each do |e| + next if e.lastrev.revision.blank? + # Set the filesize unless browsing a specific revision + if identifier.nil? && e.is_file? + full_path = File.join(root_url, e.path) + e.size = File.stat(full_path).size if File.file?(full_path) + end + c = Change.find( + :first, + :include => :changeset, + :conditions => [ + "#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?", + e.lastrev.revision, + id + ], + :order => "#{Changeset.table_name}.revision DESC") + if c + e.lastrev.identifier = c.changeset.revision + e.lastrev.name = c.changeset.revision + e.lastrev.author = c.changeset.committer + end + end + end + end + + def fetch_changesets + scm_info = scm.info + if scm_info + # latest revision found in database + db_revision = latest_changeset ? latest_changeset.revision.to_i : 0 + # latest revision in the repository + scm_revision = scm_info.lastrev.identifier.to_i + if db_revision < scm_revision + logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? + identifier_from = db_revision + 1 + while (identifier_from <= scm_revision) + # loads changesets by batches of 200 + identifier_to = [identifier_from + 199, scm_revision].min + revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true) + transaction do + revisions.reverse_each do |revision| + changeset = Changeset.create(:repository => self, + :revision => revision.identifier, + :committer => revision.author, + :committed_on => revision.time, + :scmid => revision.scmid, + :comments => revision.message) + + revision.paths.each do |change| + Change.create(:changeset => changeset, + :action => change[:action], + :path => change[:path], + :revision => change[:revision]) + end + end + end unless revisions.nil? + identifier_from = identifier_to + 1 + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cd592887335d21aca272fd319f91c63379f5d086.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cd592887335d21aca272fd319f91c63379f5d086.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,74 @@ +--- +projects_001: + created_on: 2006-07-19 19:13:59 +02:00 + name: eCookbook + updated_on: 2006-07-19 22:53:01 +02:00 + id: 1 + description: Recipes management application + homepage: http://ecookbook.somenet.foo/ + is_public: true + identifier: ecookbook + parent_id: + lft: 1 + rgt: 10 +projects_002: + created_on: 2006-07-19 19:14:19 +02:00 + name: OnlineStore + updated_on: 2006-07-19 19:14:19 +02:00 + id: 2 + description: E-commerce web site + homepage: "" + is_public: false + identifier: onlinestore + parent_id: + lft: 11 + rgt: 12 +projects_003: + created_on: 2006-07-19 19:15:21 +02:00 + name: eCookbook Subproject 1 + updated_on: 2006-07-19 19:18:12 +02:00 + id: 3 + description: eCookBook Subproject 1 + homepage: "" + is_public: true + identifier: subproject1 + parent_id: 1 + lft: 6 + rgt: 7 +projects_004: + created_on: 2006-07-19 19:15:51 +02:00 + name: eCookbook Subproject 2 + updated_on: 2006-07-19 19:17:07 +02:00 + id: 4 + description: eCookbook Subproject 2 + homepage: "" + is_public: true + identifier: subproject2 + parent_id: 1 + lft: 8 + rgt: 9 +projects_005: + created_on: 2006-07-19 19:15:51 +02:00 + name: Private child of eCookbook + updated_on: 2006-07-19 19:17:07 +02:00 + id: 5 + description: This is a private subproject of a public project + homepage: "" + is_public: false + identifier: private-child + parent_id: 1 + lft: 2 + rgt: 5 +projects_006: + created_on: 2006-07-19 19:15:51 +02:00 + name: Child of private child + updated_on: 2006-07-19 19:17:07 +02:00 + id: 6 + description: This is a public subproject of a private project + homepage: "" + is_public: true + identifier: project6 + parent_id: 5 + lft: 3 + rgt: 4 + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cd6717c1e1864b31f8cb026ceaadc6f4b357d700.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cd6717c1e1864b31f8cb026ceaadc6f4b357d700.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +This is a test email sent by Redmine. +Redmine URL: <%= @url %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cd674353ec11ce3e47c106792aeb680957571d71.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cd674353ec11ce3e47c106792aeb680957571d71.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +<% content_for :header_tags do %> + <%= javascript_include_tag 'repository_navigation' %> +<% end %> + +<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> + +<% form_tag({:action => controller.action_name, :id => @project, :path => to_path_param(@path), :rev => ''}, {:method => :get, :id => 'revision_selector'}) do -%> + + <% if !@repository.branches.nil? && @repository.branches.length > 0 -%> + | <%= l(:label_branch) %>: + <%= select_tag :branch, options_for_select([''] + @repository.branches,@rev), :id => 'branch' %> + <% end -%> + + <% if !@repository.tags.nil? && @repository.tags.length > 0 -%> + | <%= l(:label_tag) %>: + <%= select_tag :tag, options_for_select([''] + @repository.tags,@rev), :id => 'tag' %> + <% end -%> + + | <%= l(:label_revision) %>: + <%= text_field_tag 'rev', @rev, :size => 8 %> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cd82575e9a77e51c0f726bf6149523455798899e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cd82575e9a77e51c0f726bf6149523455798899e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ + + + + + +<% if @repository.report_last_commit %> + + + + +<% end %> + + + +<%= render :partial => 'dir_list_content' %> + +
    <%= l(:field_name) %><%= l(:field_filesize) %><%= l(:label_revision) %><%= l(:label_age) %><%= l(:field_author) %><%= l(:field_comments) %>
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cde0e9e2f86f3f2daa1bb290f329ede0eed7e74f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cde0e9e2f86f3f2daa1bb290f329ede0eed7e74f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +

    <%=l(:label_enumerations)%>

    + +<% Enumeration.get_subclasses.each do |klass| %> +

    <%= l(klass::OptionName) %>

    + +<% enumerations = klass.shared %> +<% if enumerations.any? %> + + + + + + + + +<% enumerations.each do |enumeration| %> + + + + + + + +<% end %> +
    <%= l(:field_name) %><%= l(:field_is_default) %><%= l(:field_active) %>
    <%= link_to h(enumeration), :action => 'edit', :id => enumeration %><%= checked_image enumeration.is_default? %><%= checked_image enumeration.active? %><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}) %> + <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration }, + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del' %> +
    +<% reset_cycle %> +<% end %> + +

    <%= link_to l(:label_enumeration_new), { :action => 'new', :type => klass.name } %>

    +<% end %> + +<% html_title(l(:label_enumerations)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cd/cde9f06f97fdd301b66d1d21b5f974e9b5aa95e4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cd/cde9f06f97fdd301b66d1d21b5f974e9b5aa95e4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/dbconsole' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ce0ddfb0e373d214b7494e9b42aebe1b7d26bc67.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ce0ddfb0e373d214b7494e9b42aebe1b7d26bc67.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +module CodeRay + + # A simplified interface to the gzip library +zlib+ (from the Ruby Standard Library.) + module GZip + + require 'zlib' + + # The default zipping level. 7 zips good and fast. + DEFAULT_GZIP_LEVEL = 7 + + # Unzips the given string +s+. + # + # Example: + # require 'gzip_simple' + # print GZip.gunzip(File.read('adresses.gz')) + def GZip.gunzip s + Zlib::Inflate.inflate s + end + + # Zips the given string +s+. + # + # Example: + # require 'gzip_simple' + # File.open('adresses.gz', 'w') do |file + # file.write GZip.gzip('Mum: 0123 456 789', 9) + # end + # + # If you provide a +level+, you can control how strong + # the string is compressed: + # - 0: no compression, only convert to gzip format + # - 1: compress fast + # - 7: compress more, but still fast (default) + # - 8: compress more, slower + # - 9: compress best, very slow + def GZip.gzip s, level = DEFAULT_GZIP_LEVEL + Zlib::Deflate.new(level).deflate s, Zlib::FINISH + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ce0fa91ce6538119a32d18dfd025c34cf1ec7c43.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ce0fa91ce6538119a32d18dfd025c34cf1ec7c43.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,54 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../../../test_helper', __FILE__) + +class Redmine::Views::Builders::XmlTest < ActiveSupport::TestCase + + def test_hash + assert_xml_output('Ryan32') do |b| + b.person do + b.name 'Ryan' + b.age 32 + end + end + end + + def test_array + assert_xml_output('') do |b| + b.array :books do |b| + b.book :title => 'Book 1' + b.book :title => 'Book 2' + end + end + end + + def test_array_with_content_tags + assert_xml_output('Book 1Book 2') do |b| + b.array :books do |b| + b.book 'Book 1', :author => 'B. Smith' + b.book 'Book 2', :author => 'G. Cooper' + end + end + end + + def assert_xml_output(expected, &block) + builder = Redmine::Views::Builders::Xml.new + block.call(builder) + assert_equal('' + expected, builder.output) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ce3436e583ff12a4824d53281463f89ddea0a5e7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ce3436e583ff12a4824d53281463f89ddea0a5e7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,189 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class IssuesHelperTest < HelperTestCase + include ApplicationHelper + include IssuesHelper + + include ActionController::Assertions::SelectorAssertions + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + # Used by assert_select + def html_document + HTML::Document.new(@response.body) + end + + def setup + super + set_language_if_valid('en') + User.current = nil + @response = ActionController::TestResponse.new + end + + def controller + @controller ||= IssuesController.new + end + + def request + @request ||= ActionController::TestRequest.new + end + + def test_issue_heading + assert_equal "Bug #1", issue_heading(Issue.find(1)) + end + + def test_issues_destroy_confirmation_message_with_one_root_issue + assert_equal l(:text_issues_destroy_confirmation), issues_destroy_confirmation_message(Issue.find(1)) + end + + def test_issues_destroy_confirmation_message_with_an_arrayt_of_root_issues + assert_equal l(:text_issues_destroy_confirmation), issues_destroy_confirmation_message(Issue.find([1, 2])) + end + + def test_issues_destroy_confirmation_message_with_one_parent_issue + Issue.find(2).update_attribute :parent_issue_id, 1 + assert_equal l(:text_issues_destroy_confirmation) + "\n" + l(:text_issues_destroy_descendants_confirmation, :count => 1), + issues_destroy_confirmation_message(Issue.find(1)) + end + + def test_issues_destroy_confirmation_message_with_one_parent_issue_and_its_child + Issue.find(2).update_attribute :parent_issue_id, 1 + assert_equal l(:text_issues_destroy_confirmation), issues_destroy_confirmation_message(Issue.find([1, 2])) + end + + context "IssuesHelper#show_detail" do + context "with no_html" do + should 'show a changing attribute' do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '40', :value => '100', :prop_key => 'done_ratio') + assert_equal "% Done changed from 40 to 100", show_detail(@detail, true) + end + + should 'show a new attribute' do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => nil, :value => '100', :prop_key => 'done_ratio') + assert_equal "% Done set to 100", show_detail(@detail, true) + end + + should 'show a deleted attribute' do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '50', :value => nil, :prop_key => 'done_ratio') + assert_equal "% Done deleted (50)", show_detail(@detail, true) + end + end + + context "with html" do + should 'show a changing attribute with HTML highlights' do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '40', :value => '100', :prop_key => 'done_ratio') + @response.body = show_detail(@detail, false) + + assert_select 'strong', :text => '% Done' + assert_select 'i', :text => '40' + assert_select 'i', :text => '100' + end + + should 'show a new attribute with HTML highlights' do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => nil, :value => '100', :prop_key => 'done_ratio') + @response.body = show_detail(@detail, false) + + assert_select 'strong', :text => '% Done' + assert_select 'i', :text => '100' + end + + should 'show a deleted attribute with HTML highlights' do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '50', :value => nil, :prop_key => 'done_ratio') + @response.body = show_detail(@detail, false) + + assert_select 'strong', :text => '% Done' + assert_select 'strike' do + assert_select 'i', :text => '50' + end + end + end + + context "with a start_date attribute" do + should "format the current date" do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '2010-01-01', :value => '2010-01-31', :prop_key => 'start_date') + assert_match "01/31/2010", show_detail(@detail, true) + end + + should "format the old date" do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '2010-01-01', :value => '2010-01-31', :prop_key => 'start_date') + assert_match "01/01/2010", show_detail(@detail, true) + end + end + + context "with a due_date attribute" do + should "format the current date" do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '2010-01-01', :value => '2010-01-31', :prop_key => 'due_date') + assert_match "01/31/2010", show_detail(@detail, true) + end + + should "format the old date" do + @detail = JournalDetail.generate!(:property => 'attr', :old_value => '2010-01-01', :value => '2010-01-31', :prop_key => 'due_date') + assert_match "01/01/2010", show_detail(@detail, true) + end + end + + context "with a project attribute" do + should_show_the_old_and_new_values_for('project_id', Project) + end + + context "with a issue status attribute" do + should_show_the_old_and_new_values_for('status_id', IssueStatus) + end + + context "with a tracker attribute" do + should_show_the_old_and_new_values_for('tracker_id', Tracker) + end + + context "with a assigned to attribute" do + should_show_the_old_and_new_values_for('assigned_to_id', User) + end + + context "with a priority attribute" do + should_show_the_old_and_new_values_for('priority_id', IssuePriority) do + @old_value = IssuePriority.generate!(:type => 'IssuePriority') + @new_value = IssuePriority.generate!(:type => 'IssuePriority') + end + end + + context "with a category attribute" do + should_show_the_old_and_new_values_for('category_id', IssueCategory) + end + + context "with a fixed version attribute" do + should_show_the_old_and_new_values_for('fixed_version_id', Version) + end + + context "with a estimated hours attribute" do + should "format the time into two decimal places" + should "format the old time into two decimal places" + end + + should "test custom fields" + should "test attachments" + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ce47c7361e1efd01e41b63643992673c2a65f3bf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ce47c7361e1efd01e41b63643992673c2a65f3bf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +<% form_for(:user, :url => { :action => 'update' }, :html => {:method => :put}) do %> +
    +<% Group.all.sort.each do |group| %> +
    +<% end %> +<%= hidden_field_tag 'user[group_ids][]', '' %> +
    +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ce65482399f7db1011fefe68c8bc250f9288d056.svn-base Binary file .svn/pristine/ce/ce65482399f7db1011fefe68c8bc250f9288d056.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ceb298f4f21b49e5ec797a7957cfba79299fa10a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ceb298f4f21b49e5ec797a7957cfba79299fa10a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 JournalsHelper + def render_notes(issue, journal, options={}) + content = '' + editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project))) + links = [] + if !journal.notes.blank? + links << link_to_remote(image_tag('comment.png'), + { :url => {:controller => 'journals', :action => 'new', :id => issue, :journal_id => journal} }, + :title => l(:button_quote)) if options[:reply_links] + links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", + { :controller => 'journals', :action => 'edit', :id => journal }, + :title => l(:button_edit)) if editable + end + content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty? + content << textilizable(journal, :notes) + css_classes = "wiki" + css_classes << " editable" if editable + content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes) + end + + def link_to_in_place_notes_editor(text, field_id, url, options={}) + onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;" + link_to text, '#', options.merge(:onclick => onclick) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ced93bd48305a49cb820a66f40d4cb9957e328e7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ced93bd48305a49cb820a66f40d4cb9957e328e7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class AuthSource < ActiveRecord::Base + generator_for :name, :start => 'Auth0' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ce/ceeec812f6673a5b491920c0b24b5c1bc35d610b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ce/ceeec812f6673a5b491920c0b24b5c1bc35d610b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +# Sample plugin migration +# Use rake db:migrate_plugins to migrate installed plugins +class CreateMeetings < ActiveRecord::Migration + def self.up + create_table :meetings do |t| + t.column :project_id, :integer, :null => false + t.column :description, :string + t.column :scheduled_on, :datetime + end + end + + def self.down + drop_table :meetings + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf0bca266fbc21a03db30e949b23e76b71b26da6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cf0bca266fbc21a03db30e949b23e76b71b26da6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +require File.expand_path('../../../test_helper', __FILE__) + +class ApiTest::TokenAuthenticationTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def setup + Setting.rest_api_enabled = '1' + Setting.login_required = '1' + end + + def teardown + Setting.rest_api_enabled = '0' + Setting.login_required = '0' + end + + # Using the NewsController because it's a simple API. + context "get /news" do + context "in :xml format" do + should_allow_key_based_auth(:get, "/news.xml") + end + + context "in :json format" do + should_allow_key_based_auth(:get, "/news.json") + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf164880642b001e32b75655aabc9764c7865713.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cf164880642b001e32b75655aabc9764c7865713.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,117 @@ +require 'test/unit' + +unless defined?(ActiveRecord) + plugin_root = File.join(File.dirname(__FILE__), '..') + + # first look for a symlink to a copy of the framework + if framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].find { |p| File.directory? p } + puts "found framework root: #{framework_root}" + # this allows for a plugin to be tested outside an app + $:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib" + else + # is the plugin installed in an application? + app_root = plugin_root + '/../../..' + + if File.directory? app_root + '/config' + puts 'using config/boot.rb' + ENV['RAILS_ENV'] = 'test' + require File.expand_path(app_root + '/config/boot') + else + # simply use installed gems if available + puts 'using rubygems' + require 'rubygems' + gem 'actionpack'; gem 'activerecord' + end + end + + %w(action_pack active_record action_controller active_record/fixtures action_controller/test_process).each {|f| require f} + + Dependencies.load_paths.unshift "#{plugin_root}/lib" +end + +# Define the connector +class ActiveRecordTestConnector + cattr_accessor :able_to_connect + cattr_accessor :connected + + # Set our defaults + self.connected = false + self.able_to_connect = true + + class << self + def setup + unless self.connected || !self.able_to_connect + setup_connection + load_schema + require_fixture_models + self.connected = true + end + rescue Exception => e # errors from ActiveRecord setup + $stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}" + #$stderr.puts " #{e.backtrace.join("\n ")}\n" + self.able_to_connect = false + end + + private + + def setup_connection + if Object.const_defined?(:ActiveRecord) + defaults = { :database => ':memory:' } + begin + options = defaults.merge :adapter => 'sqlite3', :timeout => 500 + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } + ActiveRecord::Base.connection + rescue Exception # errors from establishing a connection + $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.' + options = defaults.merge :adapter => 'sqlite' + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options } + ActiveRecord::Base.connection + end + + Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE) + else + raise "Can't setup connection since ActiveRecord isn't loaded." + end + end + + # Load actionpack sqlite tables + def load_schema + File.read(File.dirname(__FILE__) + "/fixtures/schema.sql").split(';').each do |sql| + ActiveRecord::Base.connection.execute(sql) unless sql.blank? + end + end + + def require_fixture_models + Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f} + end + end +end + +# Test case for inheritance +class ActiveRecordTestCase < Test::Unit::TestCase + # Set our fixture path + if ActiveRecordTestConnector.able_to_connect + self.fixture_path = "#{File.dirname(__FILE__)}/fixtures/" + self.use_transactional_fixtures = false + end + + def self.fixtures(*args) + super if ActiveRecordTestConnector.connected + end + + def run(*args) + super if ActiveRecordTestConnector.connected + end + + # Default so Test::Unit::TestCase doesn't complain + def test_truth + end +end + +ActiveRecordTestConnector.setup +ActionController::Routing::Routes.reload rescue nil +ActionController::Routing::Routes.draw do |map| + map.connect ':controller/:action/:id' +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf19ffcda60f22eb99d03994d0032804b48ae172.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cf19ffcda60f22eb99d03994d0032804b48ae172.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class Role < ActiveRecord::Base + generator_for :name, :start => 'Role0' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf1a848896acb56eab1a3d8174b0732f774a9b99.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cf1a848896acb56eab1a3d8174b0732f774a9b99.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +

    <%=l(:label_confirmation)%>

    + +
    +

    <%= h(@project.name) %>
    <%=l(:text_wiki_destroy_confirmation)%>

    + +<% form_tag({:controller => 'wikis', :action => 'destroy', :id => @project}) do %> +<%= hidden_field_tag "confirm", 1 %> +<%= submit_tag l(:button_delete) %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf1bff102ee3ca48f043ca35863f1b9c5fcd0807.svn-base Binary file .svn/pristine/cf/cf1bff102ee3ca48f043ca35863f1b9c5fcd0807.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf4982b297720063bae01c150cffe2934335b63a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cf4982b297720063bae01c150cffe2934335b63a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class RemoveIssueStatusesHtmlColor < ActiveRecord::Migration + def self.up + remove_column :issue_statuses, :html_color + end + + def self.down + raise IrreversibleMigration + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cf6b4f3e9cb0379c963e7ded050370ef24206ad4.svn-base Binary file .svn/pristine/cf/cf6b4f3e9cb0379c963e7ded050370ef24206ad4.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cfa3b42a480e62d585b5ac3b60b5eaa7a3df4427.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cfa3b42a480e62d585b5ac3b60b5eaa7a3df4427.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class Member < ActiveRecord::Base + generator_for :roles, :method => :generate_roles + generator_for :principal, :method => :generate_user + + def self.generate_roles + [Role.generate!] + end + + def self.generate_user + User.generate_with_protected! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cfc60690251a0006237e1c8a62505c246f4de941.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cfc60690251a0006237e1c8a62505c246f4de941.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +api.array :queries, api_meta(:total_count => @query_count, :offset => @offset, :limit => @limit) do + @queries.each do |query| + api.query do + api.id query.id + api.name query.name + api.is_public query.is_public + api.project_id query.project_id + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cfcd7c9b97a7c386801c8595e27a26562b98c813.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cfcd7c9b97a7c386801c8595e27a26562b98c813.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +# $Id: testfilter.rb 122 2006-05-15 20:03:56Z blackhedd $ +# +# + +require 'test/unit' + +$:.unshift "lib" + +require 'net/ldap' + + +class TestFilter < Test::Unit::TestCase + + def setup + end + + + def teardown + end + + def test_rfc_2254 + p Net::LDAP::Filter.from_rfc2254( " ( uid=george* ) " ) + p Net::LDAP::Filter.from_rfc2254( "uid!=george*" ) + p Net::LDAP::Filter.from_rfc2254( "uidgeorge*" ) + p Net::LDAP::Filter.from_rfc2254( "uid>=george*" ) + p Net::LDAP::Filter.from_rfc2254( "uid!=george*" ) + + p Net::LDAP::Filter.from_rfc2254( "(& (uid!=george* ) (mail=*))" ) + p Net::LDAP::Filter.from_rfc2254( "(| (uid!=george* ) (mail=*))" ) + p Net::LDAP::Filter.from_rfc2254( "(! (mail=*))" ) + end + + +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cfec8983ac77198ee4afcea197f856dd17d091ca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cfec8983ac77198ee4afcea197f856dd17d091ca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,113 @@ +-*-text-*- +$Id: README,v 1.1 2002/11/28 10:10:30 peterlin Exp $ + +Summary: This project aims to privide a set of free scalable +(PostScript Type0, TrueType, OpenType...) fonts covering the ISO +10646/Unicode UCS (Universal Character Set). + + +Why do we need free scalable UCS fonts? + +A large number of free software users switched from free X11 +bitmapped fonts to proprietary Microsoft Truetype fonts, as a) they +used to be freely downloaded from Microsoft Typography page +, b) they contain a more +or less decent subsed of the ISO 10646 UCS (Universal Character Set), +c) they are high-quality, well hinted scalable Truetype fonts, and d) +Freetype , a free high-quality Truetype font +renderer exists and has been integrated into the latest release of +XFree86, the free X11 server. + +Building a dependence on non-free software, even a niche one like +fonts, is dangerous. Microsoft Truetype core fonts are not free, they +are just costless. For now, at least. Citing the TrueType core fonts +for the Web FAQ : +"You may only redistribute the fonts in their original form (.exe or +.sit.hqx) and with their original file name from your Web site or +intranet site. You must not supply the fonts, or any derivative fonts +based on them, in any form that adds value to commercial products, +such as CD-ROM or disk based multimedia programs, application software +or utilities." As of August 2002, however, the fonts are not +anymore available on the Web, which makes the situation clearer. + +Aren't there any free high-quality scalable fonts? Yes, there are. +URW++, a German digital typefoundry, released their own version of the +35 Postscript Type 1 core fonts under GPL as their donation to the +Ghostscript project . The Wadalab +Kanji comittee has produced Type 1 font files with thousands of +filigree Japanese glyphs . +Yannis Haralambous has drawn beautiful glyphs for the Omega +typesetting system . And so +on. Scattered around the internet there are numerous other free +resources for other national scripts, many of them aiming to be a +suitable match for Latin fonts like Times or Helvetica. + + +What do we plan to achieve, and how? + +Our aim is to collect available resources, fill in the missing pieces, +and provide a set of free high-quality scalable (Type 1 and Truetype) +UCS fonts, released under GPL. + +Free UCS scalable fonts will cover the following character sets + +# ISO 8859 parts 1-15 +# CEN MES-3 European Unicode Subset + http://www.evertype.com/standards/iso10646/pdf/cwa13873.pdf +# IBM/Microsoft code pages 437, 850, 852, 1250, 1252 and more +# Microsoft/Adobe Windows Glyph List 4 (WGL4) + http://partners.adobe.com/asn/developer/opentype/appendices/wgl4.html +# KOI8-R and KOI8-RU +# DEC VT100 graphics symbols +# International Phonetic Alphabet +# Arabic, Hebrew, Armenian, Georgian, Ethiopian, Thai and Lao alphabets, + including Arabic presentation forms A/B +# Japanese Katakana and Hiragana +# mathematical symbols, including the whole TeX repertoire of symbols +# APL symbols + etc. + +A free Postscript font editor, George Williams's Pfaedit + will be used for creating new +glyphs. + +Which font shapes should be made? As historical style terms like +Renaissance or Baroque letterforms cannot be applied beyond +Latin/Cyrillic/Greek scripts to any greater extent than Kufi or Nashki +can be applied beyond Arabic script, a smaller subset of styles will +be made: one monospaced and two proportional (one with uniform stroke +and one with modulated) will be made at the start. + +In the beginning, however, we don't believe that Truetype hinting will +be good enough to compete with neither the hand-crafted bitmapped +fonts at small sizes, nor with commercial TrueType fonts. A companion +program for modifying the TrueType font tables, TtfMod, is in the +works, though: . For +applications like xterm, users are referred to the existing UCS bitmap +fonts, . + + +What do the file suffices mean? + +The files with .sfd (Spline Font Database) are in PfaEdit's native +format. Please use these if you plan to modify the font files. PfaEdit +can export these to mostly any existing font file format. + +TrueType fonts for immediate consumption are the files with the .ttf +(TrueType Font) suffix. You can use them directly, e.g. with the X +font server. + +The files with .ps (PostScript) suffix are not font files at all - +they are merely PostScript files with glyph tables, which can be used +for overview, which glyphs are contained in which font file. + +You may have noticed the lacking of PostScript Type 1 (.pfa/.pfb) font +files. Type 1 format does not support large (> 256) encoding vectors, +so they can not be used with ISO 10646 encoding. If your printer +supports it, you can use Type 0 format, though. Please use PfaEdit for +conversion to Type 0. + + +Primoz Peterlin, + +Free UCS scalable fonts: ftp:#biofiz.mf.uni-lj.si/pub/fonts/elbrus/ diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cff70e9e53fe19a0d4f34ba76842be87f910b4d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/cf/cff70e9e53fe19a0d4f34ba76842be87f910b4d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ + + + +<%=h @page.pretty_title %> + + + + +<%= textilizable @content, :text, :wiki_links => :local %> + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/cf/cffbd65abc17acb98b484ef29f7d919a9e59b7c6.svn-base Binary file .svn/pristine/cf/cffbd65abc17acb98b484ef29f7d919a9e59b7c6.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d0/d039eff47c882ca8fdcaa341586c99c94f946614.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d0/d039eff47c882ca8fdcaa341586c99c94f946614.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Views + module MyPage + module Block + def self.additional_blocks + @@additional_blocks ||= Dir.glob("#{Rails.root}/vendor/plugins/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file| + name = File.basename(file).split('.').first.gsub(/^_/, '') + h[name] = name.to_sym + h + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d0/d06b6083b66969c3f352b413de031bfbb21d7aa5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d0/d06b6083b66969c3f352b413de031bfbb21d7aa5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

    <%= l(:mail_body_register) %>
    +<%= auto_link(@url) %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d0/d0a217e11ee239305cbc0be7652fdb60b88c5c93.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d0/d0a217e11ee239305cbc0be7652fdb60b88c5c93.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +.icon-example-works { background-image: url(../images/it_works.png); } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d0/d0cb7ff899061c806d3cee6fe597edd800fee259.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d0/d0cb7ff899061c806d3cee6fe597edd800fee259.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,149 @@ +require 'iconv' + +module Redmine + module CodesetUtil + + def self.replace_invalid_utf8(str) + return str if str.nil? + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + if ! str.valid_encoding? + str = str.encode("US-ASCII", :invalid => :replace, + :undef => :replace, :replace => '?').encode("UTF-8") + end + elsif RUBY_PLATFORM == 'java' + begin + ic = Iconv.new('UTF-8', 'UTF-8') + str = ic.iconv(str) + rescue + str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?') + end + else + ic = Iconv.new('UTF-8', 'UTF-8') + txtar = "" + begin + txtar += ic.iconv(str) + rescue Iconv::IllegalSequence + txtar += $!.success + str = '?' + $!.failed[1,$!.failed.length] + retry + rescue + txtar += $!.success + end + str = txtar + end + str + end + + def self.to_utf8(str, encoding) + return str if str.nil? + str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding) + if str.empty? + str.force_encoding("UTF-8") if str.respond_to?(:force_encoding) + return str + end + enc = encoding.blank? ? "UTF-8" : encoding + if str.respond_to?(:force_encoding) + if enc.upcase != "UTF-8" + str.force_encoding(enc) + str = str.encode("UTF-8", :invalid => :replace, + :undef => :replace, :replace => '?') + else + str.force_encoding("UTF-8") + if ! str.valid_encoding? + str = str.encode("US-ASCII", :invalid => :replace, + :undef => :replace, :replace => '?').encode("UTF-8") + end + end + elsif RUBY_PLATFORM == 'java' + begin + ic = Iconv.new('UTF-8', enc) + str = ic.iconv(str) + rescue + str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?') + end + else + ic = Iconv.new('UTF-8', enc) + txtar = "" + begin + txtar += ic.iconv(str) + rescue Iconv::IllegalSequence + txtar += $!.success + str = '?' + $!.failed[1,$!.failed.length] + retry + rescue + txtar += $!.success + end + str = txtar + end + str + end + + def self.to_utf8_by_setting(str) + return str if str.nil? + str = self.to_utf8_by_setting_internal(str) + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + end + str + end + + def self.to_utf8_by_setting_internal(str) + return str if str.nil? + if str.respond_to?(:force_encoding) + str.force_encoding('ASCII-8BIT') + end + return str if str.empty? + return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + end + encodings = Setting.repositories_encodings.split(',').collect(&:strip) + encodings.each do |encoding| + begin + return Iconv.conv('UTF-8', encoding, str) + rescue Iconv::Failure + # do nothing here and try the next encoding + end + end + str = self.replace_invalid_utf8(str) + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + end + str + end + + def self.from_utf8(str, encoding) + str ||= '' + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + if encoding.upcase != 'UTF-8' + str = str.encode(encoding, :invalid => :replace, + :undef => :replace, :replace => '?') + else + str = self.replace_invalid_utf8(str) + end + elsif RUBY_PLATFORM == 'java' + begin + ic = Iconv.new(encoding, 'UTF-8') + str = ic.iconv(str) + rescue + str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?') + end + else + ic = Iconv.new(encoding, 'UTF-8') + txtar = "" + begin + txtar += ic.iconv(str) + rescue Iconv::IllegalSequence + txtar += $!.success + str = '?' + $!.failed[1, $!.failed.length] + retry + rescue + txtar += $!.success + end + str = txtar + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d0/d0da4895684ef4cb299c5edf6622c92dd56d9cc9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d0/d0da4895684ef4cb299c5edf6622c92dd56d9cc9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +
    +<%= link_to l(:label_role_new), {:action => 'new'}, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_role_plural)%>

    + + + + + + + + +<% for role in @roles %> + "> + + + + +<% end %> + +
    <%=l(:label_role)%><%=l(:button_sort)%>
    <%= content_tag(role.builtin? ? 'em' : 'span', link_to(h(role.name), :action => 'edit', :id => role)) %> + <% unless role.builtin? %> + <%= reorder_links('role', {:action => 'edit', :id => role}) %> + <% end %> + + <%= link_to(l(:button_delete), { :action => 'destroy', :id => role }, + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') unless role.builtin? %> +
    + +

    <%= pagination_links_full @role_pages %>

    + +

    <%= link_to l(:label_permissions_report), :action => 'report' %>

    + +<% html_title(l(:label_role_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d0/d0f8878bdc56439db6ee9330f7bfbb77c7251f27.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d0/d0f8878bdc56439db6ee9330f7bfbb77c7251f27.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,200 @@ +/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/ + * --------------------------------------------------------------------------- + * + * The DHTML Calendar + * + * Details and latest version at: + * http://dynarch.com/mishoo/calendar.epl + * + * This script is distributed under the GNU Lesser General Public License. + * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html + * + * This file defines helper functions for setting up the calendar. They are + * intended to help non-programmers get a working calendar on their site + * quickly. This script should not be seen as part of the calendar. It just + * shows you what one can do with the calendar, while in the same time + * providing a quick and simple method for setting it up. If you need + * exhaustive customization of the calendar creation process feel free to + * modify this code to suit your needs (this is recommended and much better + * than modifying calendar.js itself). + */ + +// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $ + +/** + * This function "patches" an input field (or other element) to use a calendar + * widget for date selection. + * + * The "params" is a single object that can have the following properties: + * + * prop. name | description + * ------------------------------------------------------------------------------------------------- + * inputField | the ID of an input field to store the date + * displayArea | the ID of a DIV or other element to show the date + * button | ID of a button or other element that will trigger the calendar + * eventName | event that will trigger the calendar, without the "on" prefix (default: "click") + * ifFormat | date format that will be stored in the input field + * daFormat | the date format that will be used to display the date in displayArea + * singleClick | (true/false) wether the calendar is in single click mode or not (default: true) + * firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc. + * align | alignment (default: "Br"); if you don't know what's this see the calendar documentation + * range | array with 2 elements. Default: [1900, 2999] -- the range of years available + * weekNumbers | (true/false) if it's true (default) the calendar will display week numbers + * flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID + * flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar) + * disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar + * onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay) + * onClose | function that gets called when the calendar is closed. [default] + * onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar. + * date | the date that the calendar will be initially displayed to + * showsTime | default: false; if true the calendar will include a time selector + * timeFormat | the time format; can be "12" or "24", default is "12" + * electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close + * step | configures the step of the years in drop-down boxes; default: 2 + * position | configures the calendar absolute position; default: null + * cache | if "true" (but default: "false") it will reuse the same calendar object, where possible + * showOthers | if "true" (but default: "false") it will show days from other months too + * + * None of them is required, they all have default values. However, if you + * pass none of "inputField", "displayArea" or "button" you'll get a warning + * saying "nothing to setup". + */ +Calendar.setup = function (params) { + function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } }; + + param_default("inputField", null); + param_default("displayArea", null); + param_default("button", null); + param_default("eventName", "click"); + param_default("ifFormat", "%Y/%m/%d"); + param_default("daFormat", "%Y/%m/%d"); + param_default("singleClick", true); + param_default("disableFunc", null); + param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined + param_default("dateText", null); + param_default("firstDay", null); + param_default("align", "Br"); + param_default("range", [1900, 2999]); + param_default("weekNumbers", true); + param_default("flat", null); + param_default("flatCallback", null); + param_default("onSelect", null); + param_default("onClose", null); + param_default("onUpdate", null); + param_default("date", null); + param_default("showsTime", false); + param_default("timeFormat", "24"); + param_default("electric", true); + param_default("step", 2); + param_default("position", null); + param_default("cache", false); + param_default("showOthers", false); + param_default("multiple", null); + + var tmp = ["inputField", "displayArea", "button"]; + for (var i in tmp) { + if (typeof params[tmp[i]] == "string") { + params[tmp[i]] = document.getElementById(params[tmp[i]]); + } + } + if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) { + alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code"); + return false; + } + + function onSelect(cal) { + var p = cal.params; + var update = (cal.dateClicked || p.electric); + if (update && p.inputField) { + p.inputField.value = cal.date.print(p.ifFormat); + if (typeof p.inputField.onchange == "function") + p.inputField.onchange(); + } + if (update && p.displayArea) + p.displayArea.innerHTML = cal.date.print(p.daFormat); + if (update && typeof p.onUpdate == "function") + p.onUpdate(cal); + if (update && p.flat) { + if (typeof p.flatCallback == "function") + p.flatCallback(cal); + } + if (update && p.singleClick && cal.dateClicked) + cal.callCloseHandler(); + }; + + if (params.flat != null) { + if (typeof params.flat == "string") + params.flat = document.getElementById(params.flat); + if (!params.flat) { + alert("Calendar.setup:\n Flat specified but can't find parent."); + return false; + } + var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect); + cal.showsOtherMonths = params.showOthers; + cal.showsTime = params.showsTime; + cal.time24 = (params.timeFormat == "24"); + cal.params = params; + cal.weekNumbers = params.weekNumbers; + cal.setRange(params.range[0], params.range[1]); + cal.setDateStatusHandler(params.dateStatusFunc); + cal.getDateText = params.dateText; + if (params.ifFormat) { + cal.setDateFormat(params.ifFormat); + } + if (params.inputField && typeof params.inputField.value == "string") { + cal.parseDate(params.inputField.value); + } + cal.create(params.flat); + cal.show(); + return false; + } + + var triggerEl = params.button || params.displayArea || params.inputField; + triggerEl["on" + params.eventName] = function() { + var dateEl = params.inputField || params.displayArea; + var dateFmt = params.inputField ? params.ifFormat : params.daFormat; + var mustCreate = false; + var cal = window.calendar; + if (dateEl) + params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt); + if (!(cal && params.cache)) { + window.calendar = cal = new Calendar(params.firstDay, + params.date, + params.onSelect || onSelect, + params.onClose || function(cal) { cal.hide(); }); + cal.showsTime = params.showsTime; + cal.time24 = (params.timeFormat == "24"); + cal.weekNumbers = params.weekNumbers; + mustCreate = true; + } else { + if (params.date) + cal.setDate(params.date); + cal.hide(); + } + if (params.multiple) { + cal.multiple = {}; + for (var i = params.multiple.length; --i >= 0;) { + var d = params.multiple[i]; + var ds = d.print("%Y%m%d"); + cal.multiple[ds] = d; + } + } + cal.showsOtherMonths = params.showOthers; + cal.yearStep = params.step; + cal.setRange(params.range[0], params.range[1]); + cal.params = params; + cal.setDateStatusHandler(params.dateStatusFunc); + cal.getDateText = params.dateText; + cal.setDateFormat(dateFmt); + if (mustCreate) + cal.create(); + cal.refresh(); + if (!params.position) + cal.showAtElement(params.button || params.displayArea || params.inputField); + else + cal.showAt(params.position[0], params.position[1]); + return false; + }; + + return cal; +}; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d1/d12fedcbe9f8547cfa6f4a11afa8ce1f7c83ddcf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d1/d12fedcbe9f8547cfa6f4a11afa8ce1f7c83ddcf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +

    <%= link_to l(:label_user_plural), users_path %> » <%=l(:label_user_new)%>

    + +<% form_for @user, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + <% if email_delivery_enabled? %> +

    + <% end %> +

    + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> +

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d1/d17414b1dfdce0231596e6df806c393321b9c1d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d1/d17414b1dfdce0231596e6df806c393321b9c1d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,200 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class IssuesTest < ActionController::IntegrationTest + fixtures :projects, + :users, + :roles, + :members, + :trackers, + :projects_trackers, + :enabled_modules, + :issue_statuses, + :issues, + :enumerations, + :custom_fields, + :custom_values, + :custom_fields_trackers + + # create an issue + def test_add_issue + log_user('jsmith', 'jsmith') + get 'projects/1/issues/new', :tracker_id => '1' + assert_response :success + assert_template 'issues/new' + + post 'projects/1/issues', :tracker_id => "1", + :issue => { :start_date => "2006-12-26", + :priority_id => "4", + :subject => "new test issue", + :category_id => "", + :description => "new issue", + :done_ratio => "0", + :due_date => "", + :assigned_to_id => "" }, + :custom_fields => {'2' => 'Value for field 2'} + # find created issue + issue = Issue.find_by_subject("new test issue") + assert_kind_of Issue, issue + + # check redirection + assert_redirected_to :controller => 'issues', :action => 'show', :id => issue + follow_redirect! + assert_equal issue, assigns(:issue) + + # check issue attributes + assert_equal 'jsmith', issue.author.login + assert_equal 1, issue.project.id + assert_equal 1, issue.status.id + end + + # add then remove 2 attachments to an issue + def test_issue_attachments + log_user('jsmith', 'jsmith') + set_tmp_attachments_directory + + put 'issues/1', + :notes => 'Some notes', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}} + assert_redirected_to "/issues/1" + + # make sure attachment was saved + attachment = Issue.find(1).attachments.find_by_filename("testfile.txt") + assert_kind_of Attachment, attachment + assert_equal Issue.find(1), attachment.container + assert_equal 'This is an attachment', attachment.description + # verify the size of the attachment stored in db + #assert_equal file_data_1.length, attachment.filesize + # verify that the attachment was written to disk + assert File.exist?(attachment.diskfile) + + # remove the attachments + Issue.find(1).attachments.each(&:destroy) + assert_equal 0, Issue.find(1).attachments.length + end + + def test_other_formats_links_on_get_index + get '/projects/ecookbook/issues' + + %w(Atom PDF CSV).each do |format| + assert_tag :a, :content => format, + :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}", + :rel => 'nofollow' } + end + end + + def test_other_formats_links_on_post_index_without_project_id_in_url + post '/issues', :project_id => 'ecookbook' + + %w(Atom PDF CSV).each do |format| + assert_tag :a, :content => format, + :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}", + :rel => 'nofollow' } + end + end + + def test_pagination_links_on_get_index + Setting.per_page_options = '2' + get '/projects/ecookbook/issues' + + assert_tag :a, :content => '2', + :attributes => { :href => '/projects/ecookbook/issues?page=2' } + + end + + def test_pagination_links_on_post_index_without_project_id_in_url + Setting.per_page_options = '2' + post '/issues', :project_id => 'ecookbook' + + assert_tag :a, :content => '2', + :attributes => { :href => '/projects/ecookbook/issues?page=2' } + + end + + def test_issue_with_user_custom_field + @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all) + Role.anonymous.add_permission! :add_issues, :edit_issues + users = Project.find(1).users + tester = users.first + + # Issue form + get '/projects/ecookbook/issues/new' + assert_response :success + assert_tag :select, + :attributes => {:name => "issue[custom_field_values][#{@field.id}]"}, + :children => {:count => (users.size + 1)}, # +1 for blank value + :child => { + :tag => 'option', + :attributes => {:value => tester.id.to_s}, + :content => tester.name + } + + # Create issue + assert_difference 'Issue.count' do + post '/projects/ecookbook/issues', + :issue => { + :tracker_id => '1', + :priority_id => '4', + :subject => 'Issue with user custom field', + :custom_field_values => {@field.id.to_s => users.first.id.to_s} + } + end + issue = Issue.first(:order => 'id DESC') + assert_response 302 + + # Issue view + follow_redirect! + assert_tag :th, + :content => /Tester/, + :sibling => { + :tag => 'td', + :content => tester.name + } + assert_tag :select, + :attributes => {:name => "issue[custom_field_values][#{@field.id}]"}, + :children => {:count => (users.size + 1)}, # +1 for blank value + :child => { + :tag => 'option', + :attributes => {:value => tester.id.to_s, :selected => 'selected'}, + :content => tester.name + } + + # Update issue + new_tester = users[1] + assert_difference 'Journal.count' do + put "/issues/#{issue.id}", + :notes => 'Updating custom field', + :issue => { + :custom_field_values => {@field.id.to_s => new_tester.id.to_s} + } + end + assert_response 302 + + # Issue view + follow_redirect! + assert_tag :content => 'Tester', + :ancestor => {:tag => 'ul', :attributes => {:class => /details/}}, + :sibling => { + :content => tester.name, + :sibling => { + :content => new_tester.name + } + } + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d1/d17ed0048a8732d627b6e8e9b53ae2903c41d045.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d1/d17ed0048a8732d627b6e8e9b53ae2903c41d045.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,85 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Helpers + + # Simple class to compute the start and end dates of a calendar + class Calendar + include Redmine::I18n + attr_reader :startdt, :enddt + + def initialize(date, lang = current_language, period = :month) + @date = date + @events = [] + @ending_events_by_days = {} + @starting_events_by_days = {} + set_language_if_valid lang + case period + when :month + @startdt = Date.civil(date.year, date.month, 1) + @enddt = (@startdt >> 1)-1 + # starts from the first day of the week + @startdt = @startdt - (@startdt.cwday - first_wday)%7 + # ends on the last day of the week + @enddt = @enddt + (last_wday - @enddt.cwday)%7 + when :week + @startdt = date - (date.cwday - first_wday)%7 + @enddt = date + (last_wday - date.cwday)%7 + else + raise 'Invalid period' + end + end + + # Sets calendar events + def events=(events) + @events = events + @ending_events_by_days = @events.group_by {|event| event.due_date} + @starting_events_by_days = @events.group_by {|event| event.start_date} + end + + # Returns events for the given day + def events_on(day) + ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq + end + + # Calendar current month + def month + @date.month + end + + # Return the first day of week + # 1 = Monday ... 7 = Sunday + def first_wday + case Setting.start_of_week.to_i + when 1 + @first_dow ||= (1 - 1)%7 + 1 + when 6 + @first_dow ||= (6 - 1)%7 + 1 + when 7 + @first_dow ||= (7 - 1)%7 + 1 + else + @first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1 + end + end + + def last_wday + @last_dow ||= (first_wday + 5)%7 + 1 + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d1/d1a19395b15d6e38fe259f8023ce7a4ffd30768e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d1/d1a19395b15d6e38fe259f8023ce7a4ffd30768e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ExtendSettingsName < ActiveRecord::Migration + def self.up + change_column :settings, :name, :string, :limit => 255, :default => '', :null => false + end + + def self.down + raise ActiveRecord::IrreversibleMigration + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d1/d1cb23e4b2849d91c4eed462a543696732f1999f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d1/d1cb23e4b2849d91c4eed462a543696732f1999f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class AddViewIssuesPermission < ActiveRecord::Migration + def self.up + Role.find(:all).each do |r| + r.add_permission!(:view_issues) + end + end + + def self.down + Role.find(:all).each do |r| + r.remove_permission!(:view_issues) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d1/d1f808fff3001eb66af368407709979594e75713.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d1/d1f808fff3001eb66af368407709979594e75713.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +# Tests in this file ensure that: +# +# * Routes from plugins can be routed to +# * Named routes can be defined within a plugin + +require File.dirname(__FILE__) + '/../test_helper' + +class RoutesTest < ActionController::TestCase + tests TestRoutingController + + def test_WITH_a_route_defined_in_a_plugin_IT_should_route_it + path = '/routes/an_action' + opts = {:controller => 'test_routing', :action => 'an_action'} + assert_routing path, opts + assert_recognizes opts, path # not sure what exactly the difference is, but it won't hurt either + end + + def test_WITH_a_route_for_a_namespaced_controller_defined_in_a_plugin_IT_should_route_it + path = 'somespace/routes/an_action' + opts = {:controller => 'namespace/test_routing', :action => 'an_action'} + assert_routing path, opts + assert_recognizes opts, path + end + + def test_should_properly_generate_named_routes + get :test_named_routes_from_plugin + assert_response_body '/somespace/routes' + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d229908205785bb3d05ed246eb92f48aebe96ceb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d229908205785bb3d05ed246eb92f48aebe96ceb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +# $Id: testpsw.rb 72 2006-04-24 21:58:14Z blackhedd $ +# +# + + +$:.unshift "lib" + +require 'net/ldap' +require 'stringio' + + +class TestPassword < Test::Unit::TestCase + + def setup + end + + + def test_psw + assert_equal( "{MD5}xq8jwrcfibi0sZdZYNkSng==", Net::LDAP::Password.generate( :md5, "cashflow" )) + assert_equal( "{SHA}YE4eGkN4BvwNN1f5R7CZz0kFn14=", Net::LDAP::Password.generate( :sha, "cashflow" )) + end + + + + +end + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d235886576ad0af00741b82cf28f624324ebe1c5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d235886576ad0af00741b82cf28f624324ebe1c5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class AlphaPluginModel < ActiveRecord::Base + def self.report_location; TestHelper::report_location(__FILE__); end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d24962e05eefa8c4a95f4bd86c0954dda018dde6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d24962e05eefa8c4a95f4bd86c0954dda018dde6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +# Sample plugin controller +class ExampleController < ApplicationController + unloadable + + layout 'base' + before_filter :find_project, :authorize + menu_item :sample_plugin + + def say_hello + @value = Setting.plugin_sample_plugin['sample_setting'] + end + + def say_goodbye + end + +private + def find_project + @project=Project.find(params[:id]) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d24f4899353e6be2fcd4f22d01a7b5ad69fcd0bd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d24f4899353e6be2fcd4f22d01a7b5ad69fcd0bd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::IssueStatusesTest < ActionController::IntegrationTest + fixtures :issue_statuses + + def setup + Setting.rest_api_enabled = '1' + end + + context "/issue_statuses" do + context "GET" do + + should "return issue statuses" do + get '/issue_statuses.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'issue_statuses', + :attributes => {:type => 'array'}, + :child => { + :tag => 'issue_status', + :child => { + :tag => 'id', + :content => '2', + :sibling => { + :tag => 'name', + :content => 'Assigned' + } + } + } + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d276e4452e3d3844bd9ce46cbf0d95284ffa7454.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d276e4452e3d3844bd9ce46cbf0d95284ffa7454.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddUserPreferencesTimeZone < ActiveRecord::Migration + def self.up + add_column :user_preferences, :time_zone, :string + end + + def self.down + remove_column :user_preferences, :time_zone + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d27acaba5e51d3baf547fd1e551a5deb117304a0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d27acaba5e51d3baf547fd1e551a5deb117304a0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,461 @@ +module CodeRay +module Scanners + + # This scanner is really complex, since Ruby _is_ a complex language! + # + # It tries to highlight 100% of all common code, + # and 90% of strange codes. + # + # It is optimized for HTML highlighting, and is not very useful for + # parsing or pretty printing. + class Ruby < Scanner + + register_for :ruby + file_extension 'rb' + + autoload :Patterns, 'coderay/scanners/ruby/patterns' + autoload :StringState, 'coderay/scanners/ruby/string_state' + + def interpreted_string_state + StringState.new :string, true, '"' + end + + protected + + def setup + @state = :initial + end + + def scan_tokens encoder, options + state, heredocs = options[:state] || @state + heredocs = heredocs.dup if heredocs.is_a?(Array) + + if state && state.instance_of?(StringState) + encoder.begin_group state.type + end + + last_state = nil + + method_call_expected = false + value_expected = true + + inline_block_stack = nil + inline_block_curly_depth = 0 + + if heredocs + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + end + + # def_object_stack = nil + # def_object_paren_depth = 0 + + patterns = Patterns # avoid constant lookup + + unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' + + until eos? + + if state.instance_of? ::Symbol + + if match = scan(/[ \t\f\v]+/) + encoder.text_token match, :space + + elsif match = scan(/\n/) + if heredocs + unscan # heredoc scanning needs \n at start + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + else + state = :initial if state == :undef_comma_expected + encoder.text_token match, :space + value_expected = true + end + + elsif match = scan(bol? ? / \#(!)?.* | #{patterns::RUBYDOC_OR_DATA} /ox : /\#.*/) + encoder.text_token match, self[1] ? :doctype : :comment + + elsif match = scan(/\\\n/) + if heredocs + unscan # heredoc scanning needs \n at start + encoder.text_token scan(/\\/), :space + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + else + encoder.text_token match, :space + end + + elsif state == :initial + + # IDENTS # + if !method_call_expected && + match = scan(unicode ? /#{patterns::METHOD_NAME}/uo : + /#{patterns::METHOD_NAME}/o) + value_expected = false + kind = patterns::IDENT_KIND[match] + if kind == :ident + if match[/\A[A-Z]/] && !(match[/[!?]$/] || match?(/\(/)) + kind = :constant + end + elsif kind == :keyword + state = patterns::KEYWORD_NEW_STATE[match] + value_expected = true if patterns::KEYWORDS_EXPECTING_VALUE[match] + end + value_expected = true if !value_expected && check(/#{patterns::VALUE_FOLLOWS}/o) + encoder.text_token match, kind + + elsif method_call_expected && + match = scan(unicode ? /#{patterns::METHOD_AFTER_DOT}/uo : + /#{patterns::METHOD_AFTER_DOT}/o) + if method_call_expected == '::' && match[/\A[A-Z]/] && !match?(/\(/) + encoder.text_token match, :constant + else + encoder.text_token match, :ident + end + method_call_expected = false + value_expected = check(/#{patterns::VALUE_FOLLOWS}/o) + + # OPERATORS # + elsif !method_call_expected && match = scan(/ (\.(?!\.)|::) | (?: \.\.\.? | ==?=? | [,\(\[\{] )() | [\)\]\}] /x) + method_call_expected = self[1] + value_expected = !method_call_expected && self[2] + if inline_block_stack + case match + when '{' + inline_block_curly_depth += 1 + when '}' + inline_block_curly_depth -= 1 + if inline_block_curly_depth == 0 # closing brace of inline block reached + state, inline_block_curly_depth, heredocs = inline_block_stack.pop + inline_block_stack = nil if inline_block_stack.empty? + heredocs = nil if heredocs && heredocs.empty? + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + next + end + end + end + encoder.text_token match, :operator + + elsif match = scan(unicode ? /#{patterns::SYMBOL}/uo : + /#{patterns::SYMBOL}/o) + case delim = match[1] + when ?', ?" + encoder.begin_group :symbol + encoder.text_token ':', :symbol + match = delim.chr + encoder.text_token match, :delimiter + state = self.class::StringState.new :symbol, delim == ?", match + else + encoder.text_token match, :symbol + value_expected = false + end + + elsif match = scan(/ ' (?:(?>[^'\\]*) ')? | " (?:(?>[^"\\\#]*) ")? /mx) + encoder.begin_group :string + if match.size == 1 + encoder.text_token match, :delimiter + state = self.class::StringState.new :string, match == '"', match # important for streaming + else + encoder.text_token match[0,1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1,1], :delimiter + encoder.end_group :string + value_expected = false + end + + elsif match = scan(unicode ? /#{patterns::INSTANCE_VARIABLE}/uo : + /#{patterns::INSTANCE_VARIABLE}/o) + value_expected = false + encoder.text_token match, :instance_variable + + elsif value_expected && match = scan(/\//) + encoder.begin_group :regexp + encoder.text_token match, :delimiter + state = self.class::StringState.new :regexp, true, '/' + + elsif match = scan(value_expected ? /[-+]?#{patterns::NUMERIC}/o : /#{patterns::NUMERIC}/o) + if method_call_expected + encoder.text_token match, :error + method_call_expected = false + else + encoder.text_token match, self[1] ? :float : :integer # TODO: send :hex/:octal/:binary + end + value_expected = false + + elsif match = scan(/ [-+!~^\/]=? | [:;] | [*|&]{1,2}=? | >>? /x) + value_expected = true + encoder.text_token match, :operator + + elsif value_expected && match = scan(/#{patterns::HEREDOC_OPEN}/o) + quote = self[3] + delim = self[quote ? 4 : 2] + kind = patterns::QUOTE_TO_TYPE[quote] + encoder.begin_group kind + encoder.text_token match, :delimiter + encoder.end_group kind + heredocs ||= [] # create heredocs if empty + heredocs << self.class::StringState.new(kind, quote != "'", delim, + self[1] == '-' ? :indented : :linestart) + value_expected = false + + elsif value_expected && match = scan(/#{patterns::FANCY_STRING_START}/o) + kind = patterns::FANCY_STRING_KIND[self[1]] + encoder.begin_group kind + state = self.class::StringState.new kind, patterns::FANCY_STRING_INTERPRETED[self[1]], self[2] + encoder.text_token match, :delimiter + + elsif value_expected && match = scan(/#{patterns::CHARACTER}/o) + value_expected = false + encoder.text_token match, :integer + + elsif match = scan(/ %=? | <(?:<|=>?)? | \? /x) + value_expected = true + encoder.text_token match, :operator + + elsif match = scan(/`/) + encoder.begin_group :shell + encoder.text_token match, :delimiter + state = self.class::StringState.new :shell, true, match + + elsif match = scan(unicode ? /#{patterns::GLOBAL_VARIABLE}/uo : + /#{patterns::GLOBAL_VARIABLE}/o) + encoder.text_token match, :global_variable + value_expected = false + + elsif match = scan(unicode ? /#{patterns::CLASS_VARIABLE}/uo : + /#{patterns::CLASS_VARIABLE}/o) + encoder.text_token match, :class_variable + value_expected = false + + elsif match = scan(/\\\z/) + encoder.text_token match, :space + + else + if method_call_expected + method_call_expected = false + next + end + unless unicode + # check for unicode + $DEBUG_BEFORE, $DEBUG = $DEBUG, false + begin + if check(/./mu).size > 1 + # seems like we should try again with unicode + unicode = true + end + rescue + # bad unicode char; use getch + ensure + $DEBUG = $DEBUG_BEFORE + end + next if unicode + end + + encoder.text_token getch, :error + + end + + if last_state + state = last_state + last_state = nil + end + + elsif state == :def_expected + if match = scan(unicode ? /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : + /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) + encoder.text_token match, :method + state = :initial + else + last_state = :dot_expected + state = :initial + end + + elsif state == :dot_expected + if match = scan(/\.|::/) + # invalid definition + state = :def_expected + encoder.text_token match, :operator + else + state = :initial + end + + elsif state == :module_expected + if match = scan(/<#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : + /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) + encoder.text_token match, :method + elsif match = scan(/#{patterns::SYMBOL}/o) + case delim = match[1] + when ?', ?" + encoder.begin_group :symbol + encoder.text_token ':', :symbol + match = delim.chr + encoder.text_token match, :delimiter + state = self.class::StringState.new :symbol, delim == ?", match + state.next_state = :undef_comma_expected + else + encoder.text_token match, :symbol + end + else + state = :initial + end + + elsif state == :undef_comma_expected + if match = scan(/,/) + encoder.text_token match, :operator + state = :undef_expected + else + state = :initial + end + + elsif state == :alias_expected + match = scan(unicode ? /(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/uo : + /(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/o) + + if match + encoder.text_token self[1], (self[1][0] == ?: ? :symbol : :method) + encoder.text_token self[2], :space + encoder.text_token self[3], (self[3][0] == ?: ? :symbol : :method) + end + state = :initial + + else + #:nocov: + raise_inspect 'Unknown state: %p' % [state], encoder + #:nocov: + end + + else # StringState + + match = scan_until(state.pattern) || scan_rest + unless match.empty? + encoder.text_token match, :content + break if eos? + end + + if state.heredoc && self[1] # end of heredoc + match = getch + match << scan_until(/$/) unless eos? + encoder.text_token match, :delimiter unless match.empty? + encoder.end_group state.type + state = state.next_state + next + end + + case match = getch + + when state.delim + if state.paren_depth + state.paren_depth -= 1 + if state.paren_depth > 0 + encoder.text_token match, :content + next + end + end + encoder.text_token match, :delimiter + if state.type == :regexp && !eos? + match = scan(/#{patterns::REGEXP_MODIFIERS}/o) + encoder.text_token match, :modifier unless match.empty? + end + encoder.end_group state.type + value_expected = false + state = state.next_state + + when '\\' + if state.interpreted + if esc = scan(/#{patterns::ESCAPE}/o) + encoder.text_token match + esc, :char + else + encoder.text_token match, :error + end + else + case esc = getch + when nil + encoder.text_token match, :content + when state.delim, '\\' + encoder.text_token match + esc, :char + else + encoder.text_token match + esc, :content + end + end + + when '#' + case peek(1) + when '{' + inline_block_stack ||= [] + inline_block_stack << [state, inline_block_curly_depth, heredocs] + value_expected = true + state = :initial + inline_block_curly_depth = 1 + encoder.begin_group :inline + encoder.text_token match + getch, :inline_delimiter + when '$', '@' + encoder.text_token match, :escape + last_state = state + state = :initial + else + #:nocov: + raise_inspect 'else-case # reached; #%p not handled' % [peek(1)], encoder + #:nocov: + end + + when state.opening_paren + state.paren_depth += 1 + encoder.text_token match, :content + + else + #:nocov + raise_inspect 'else-case " reached; %p not handled, state = %p' % [match, state], encoder + #:nocov: + + end + + end + + end + + # cleaning up + if state.is_a? StringState + encoder.end_group state.type + end + + if options[:keep_state] + if state.is_a?(StringState) && state.heredoc + (heredocs ||= []).unshift state + state = :initial + elsif heredocs && heredocs.empty? + heredocs = nil + end + @state = state, heredocs + end + + if inline_block_stack + until inline_block_stack.empty? + state, = *inline_block_stack.pop + encoder.end_group :inline + encoder.end_group state.type + end + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d2ab451eb617526d561093c390e63e0839289e3b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d2ab451eb617526d561093c390e63e0839289e3b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,84 @@ +require 'test/unit' +require File.expand_path('../../lib/assert_warning', __FILE__) + +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +begin + require 'rubygems' unless defined? Gem + gem 'RedCloth', '>= 4.0.3' rescue nil + require 'redcloth' +rescue LoadError + warn 'RedCloth not found - skipping for_redcloth tests.' + undef RedCloth if defined? RedCloth +end + +class BasicTest < Test::Unit::TestCase + + def test_for_redcloth + require 'coderay/for_redcloth' + assert_equal "

    puts "Hello, World!"

    ", + RedCloth.new('@[ruby]puts "Hello, World!"@').to_html + assert_equal <<-BLOCKCODE.chomp, +
    +
    puts "Hello, World!"
    +
    + BLOCKCODE + RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html + end + + def test_for_redcloth_no_lang + require 'coderay/for_redcloth' + assert_equal "

    puts \"Hello, World!\"

    ", + RedCloth.new('@puts "Hello, World!"@').to_html + assert_equal <<-BLOCKCODE.chomp, +
    puts \"Hello, World!\"
    + BLOCKCODE + RedCloth.new('bc. puts "Hello, World!"').to_html + end + + def test_for_redcloth_style + require 'coderay/for_redcloth' + assert_equal <<-BLOCKCODE.chomp, +
    puts \"Hello, World!\"
    + BLOCKCODE + RedCloth.new('bc{color: red}. puts "Hello, World!"').to_html + end + + def test_for_redcloth_escapes + require 'coderay/for_redcloth' + assert_equal '

    >

    ', + RedCloth.new('@[ruby]>@').to_html + assert_equal <<-BLOCKCODE.chomp, +
    +
    &
    +
    + BLOCKCODE + RedCloth.new('bc[ruby]. &').to_html + end + + def test_for_redcloth_escapes2 + require 'coderay/for_redcloth' + assert_equal "

    #include <test.h>

    ", + RedCloth.new('@[c]#include @').to_html + end + + # See http://jgarber.lighthouseapp.com/projects/13054/tickets/124-code-markup-does-not-allow-brackets. + def test_for_redcloth_false_positive + require 'coderay/for_redcloth' + assert_warning 'CodeRay::Scanners could not load plugin :project; falling back to :text' do + assert_equal '

    [project]_dff.skjd

    ', + RedCloth.new('@[project]_dff.skjd@').to_html + end + # false positive, but expected behavior / known issue + assert_equal "

    _dff.skjd

    ", + RedCloth.new('@[ruby]_dff.skjd@').to_html + assert_warning 'CodeRay::Scanners could not load plugin :project; falling back to :text' do + assert_equal <<-BLOCKCODE.chomp, +
    [project]_dff.skjd
    + BLOCKCODE + RedCloth.new('bc. [project]_dff.skjd').to_html + end + end + +end if defined? RedCloth \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d2b7e4e31fe8e1c6b720e33448674102879e4246.svn-base Binary file .svn/pristine/d2/d2b7e4e31fe8e1c6b720e33448674102879e4246.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d2bd0bf95ab05008a71c2b2b37ad8bf69fcda9be.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d2bd0bf95ab05008a71c2b2b37ad8bf69fcda9be.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,77 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class MenuManagerTest < ActionController::IntegrationTest + include Redmine::I18n + + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def test_project_menu_with_specific_locale + get 'projects/ecookbook/issues', { }, 'Accept-Language' => 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' + + assert_tag :div, :attributes => { :id => 'main-menu' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => ll('fr', :label_activity), + :attributes => { :href => '/projects/ecookbook/activity', + :class => 'activity' } } } + assert_tag :div, :attributes => { :id => 'main-menu' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => ll('fr', :label_issue_plural), + :attributes => { :href => '/projects/ecookbook/issues', + :class => 'issues selected' } } } + end + + def test_project_menu_with_additional_menu_items + Setting.default_language = 'en' + assert_no_difference 'Redmine::MenuManager.items(:project_menu).size' do + Redmine::MenuManager.map :project_menu do |menu| + menu.push :foo, { :controller => 'projects', :action => 'show' }, :caption => 'Foo' + menu.push :bar, { :controller => 'projects', :action => 'show' }, :before => :activity + menu.push :hello, { :controller => 'projects', :action => 'show' }, :caption => Proc.new {|p| p.name.upcase }, :after => :bar + end + + get 'projects/ecookbook' + assert_tag :div, :attributes => { :id => 'main-menu' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo', + :attributes => { :class => 'foo' } } } + + assert_tag :div, :attributes => { :id => 'main-menu' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar', + :attributes => { :class => 'bar' } }, + :before => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK' } } } + + assert_tag :div, :attributes => { :id => 'main-menu' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK', + :attributes => { :class => 'hello' } }, + :before => { :tag => 'li', :child => { :tag => 'a', :content => 'Activity' } } } + + # Remove the menu items + Redmine::MenuManager.map :project_menu do |menu| + menu.delete :foo + menu.delete :bar + menu.delete :hello + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d2/d2f1b8e2151a17fc86ef289127a063bc9d150c8c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d2/d2f1b8e2151a17fc86ef289127a063bc9d150c8c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,408 @@ +require File.expand_path('../../../../../../test_helper', __FILE__) +begin + require 'mocha' + + class MercurialAdapterTest < ActiveSupport::TestCase + HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR + TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME + TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION + + REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s + CHAR_1_HEX = "\xc3\x9c" + + if File.directory?(REPOSITORY_PATH) + def setup + adapter_class = Redmine::Scm::Adapters::MercurialAdapter + assert adapter_class + assert adapter_class.client_command + assert_equal true, adapter_class.client_available + assert_equal true, adapter_class.client_version_above?([0, 9, 5]) + + @adapter = Redmine::Scm::Adapters::MercurialAdapter.new( + REPOSITORY_PATH, + nil, + nil, + nil, + 'ISO-8859-1') + @diff_c_support = true + @char_1 = CHAR_1_HEX.dup + @tag_char_1 = "tag-#{CHAR_1_HEX}-00" + @branch_char_0 = "branch-#{CHAR_1_HEX}-00" + @branch_char_1 = "branch-#{CHAR_1_HEX}-01" + if @tag_char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + @tag_char_1.force_encoding('UTF-8') + @branch_char_0.force_encoding('UTF-8') + @branch_char_1.force_encoding('UTF-8') + end + end + + def test_hgversion + to_test = { "Mercurial Distributed SCM (version 0.9.5)\n" => [0,9,5], + "Mercurial Distributed SCM (1.0)\n" => [1,0], + "Mercurial Distributed SCM (1e4ddc9ac9f7+20080325)\n" => nil, + "Mercurial Distributed SCM (1.0.1+20080525)\n" => [1,0,1], + "Mercurial Distributed SCM (1916e629a29d)\n" => nil, + "Mercurial SCM Distribuito (versione 0.9.5)\n" => [0,9,5], + "(1.6)\n(1.7)\n(1.8)" => [1,6], + "(1.7.1)\r\n(1.8.1)\r\n(1.9.1)" => [1,7,1]} + + to_test.each do |s, v| + test_hgversion_for(s, v) + end + end + + def test_template_path + to_test = { + [1,2] => "1.0", + [] => "1.0", + [1,2,1] => "1.0", + [1,7] => "1.0", + [1,7,1] => "1.0", + [2,0] => "1.0", + } + to_test.each do |v, template| + test_template_path_for(v, template) + end + end + + def test_info + [REPOSITORY_PATH, REPOSITORY_PATH + "/", + REPOSITORY_PATH + "//"].each do |repo| + adp = Redmine::Scm::Adapters::MercurialAdapter.new(repo) + repo_path = adp.info.root_url.gsub(/\\/, "/") + assert_equal REPOSITORY_PATH, repo_path + assert_equal '31', adp.info.lastrev.revision + assert_equal '31eeee7395c8',adp.info.lastrev.scmid + end + end + + def test_revisions + revisions = @adapter.revisions(nil, 2, 4) + assert_equal 3, revisions.size + assert_equal '2', revisions[0].revision + assert_equal '400bb8672109', revisions[0].scmid + assert_equal '4', revisions[2].revision + assert_equal 'def6d2f1254a', revisions[2].scmid + + revisions = @adapter.revisions(nil, 2, 4, {:limit => 2}) + assert_equal 2, revisions.size + assert_equal '2', revisions[0].revision + assert_equal '400bb8672109', revisions[0].scmid + end + + def test_parents + revs1 = @adapter.revisions(nil, 0, 0) + assert_equal 1, revs1.size + assert_equal [], revs1[0].parents + revs2 = @adapter.revisions(nil, 1, 1) + assert_equal 1, revs2.size + assert_equal 1, revs2[0].parents.size + assert_equal "0885933ad4f6", revs2[0].parents[0] + revs3 = @adapter.revisions(nil, 30, 30) + assert_equal 1, revs3.size + assert_equal 2, revs3[0].parents.size + assert_equal "a94b0528f24f", revs3[0].parents[0] + assert_equal "3a330eb32958", revs3[0].parents[1] + end + + def test_diff + if @adapter.class.client_version_above?([1, 2]) + assert_nil @adapter.diff(nil, '100000') + end + assert_nil @adapter.diff(nil, '100000', '200000') + [2, '400bb8672109', '400', 400].each do |r1| + diff1 = @adapter.diff(nil, r1) + if @diff_c_support + assert_equal 28, diff1.size + buf = diff1[24].gsub(/\r\n|\r|\n/, "") + assert_equal "+ return true unless klass.respond_to?('watched_by')", buf + else + assert_equal 0, diff1.size + end + [4, 'def6d2f1254a'].each do |r2| + diff2 = @adapter.diff(nil,r1,r2) + assert_equal 49, diff2.size + buf = diff2[41].gsub(/\r\n|\r|\n/, "") + assert_equal "+class WelcomeController < ApplicationController", buf + diff3 = @adapter.diff('sources/watchers_controller.rb', r1, r2) + assert_equal 20, diff3.size + buf = diff3[12].gsub(/\r\n|\r|\n/, "") + assert_equal "+ @watched.remove_watcher(user)", buf + end + end + end + + def test_diff_made_by_revision + if @diff_c_support + [24, '24', '4cddb4e45f52'].each do |r1| + diff1 = @adapter.diff(nil, r1) + assert_equal 5, diff1.size + buf = diff1[4].gsub(/\r\n|\r|\n/, "") + assert_equal '+0885933ad4f68d77c2649cd11f8311276e7ef7ce tag-init-revision', buf + end + end + end + + def test_cat + [2, '400bb8672109', '400', 400].each do |r| + buf = @adapter.cat('sources/welcome_controller.rb', r) + assert buf + lines = buf.split("\r\n") + assert_equal 25, lines.length + assert_equal 'class WelcomeController < ApplicationController', lines[17] + end + assert_nil @adapter.cat('sources/welcome_controller.rb') + end + + def test_annotate + assert_equal [], @adapter.annotate("sources/welcome_controller.rb").lines + [2, '400bb8672109', '400', 400].each do |r| + ann = @adapter.annotate('sources/welcome_controller.rb', r) + assert ann + assert_equal '1', ann.revisions[17].revision + assert_equal '9d5b5b004199', ann.revisions[17].identifier + assert_equal 'jsmith', ann.revisions[0].author + assert_equal 25, ann.lines.length + assert_equal 'class WelcomeController < ApplicationController', ann.lines[17] + end + end + + def test_entries + assert_nil @adapter.entries(nil, '100000') + + assert_equal 1, @adapter.entries("sources", 3).size + assert_equal 1, @adapter.entries("sources", 'b3a615152df8').size + + [2, '400bb8672109', '400', 400].each do |r| + entries1 = @adapter.entries(nil, r) + assert entries1 + assert_equal 3, entries1.size + assert_equal 'sources', entries1[1].name + assert_equal 'sources', entries1[1].path + assert_equal 'dir', entries1[1].kind + readme = entries1[2] + assert_equal 'README', readme.name + assert_equal 'README', readme.path + assert_equal 'file', readme.kind + assert_equal 27, readme.size + assert_equal '1', readme.lastrev.revision + assert_equal '9d5b5b004199', readme.lastrev.identifier + # 2007-12-14 10:24:01 +0100 + assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time + + entries2 = @adapter.entries('sources', r) + assert entries2 + assert_equal 2, entries2.size + assert_equal 'watchers_controller.rb', entries2[0].name + assert_equal 'sources/watchers_controller.rb', entries2[0].path + assert_equal 'file', entries2[0].kind + assert_equal 'welcome_controller.rb', entries2[1].name + assert_equal 'sources/welcome_controller.rb', entries2[1].path + assert_equal 'file', entries2[1].kind + end + end + + def test_entries_tag + entries1 = @adapter.entries(nil, 'tag_test.00') + assert entries1 + assert_equal 3, entries1.size + assert_equal 'sources', entries1[1].name + assert_equal 'sources', entries1[1].path + assert_equal 'dir', entries1[1].kind + readme = entries1[2] + assert_equal 'README', readme.name + assert_equal 'README', readme.path + assert_equal 'file', readme.kind + assert_equal 21, readme.size + assert_equal '0', readme.lastrev.revision + assert_equal '0885933ad4f6', readme.lastrev.identifier + # 2007-12-14 10:22:52 +0100 + assert_equal Time.gm(2007, 12, 14, 9, 22, 52), readme.lastrev.time + end + + def test_entries_branch + entries1 = @adapter.entries(nil, 'test-branch-00') + assert entries1 + assert_equal 5, entries1.size + assert_equal 'sql_escape', entries1[2].name + assert_equal 'sql_escape', entries1[2].path + assert_equal 'dir', entries1[2].kind + readme = entries1[4] + assert_equal 'README', readme.name + assert_equal 'README', readme.path + assert_equal 'file', readme.kind + assert_equal 365, readme.size + assert_equal '8', readme.lastrev.revision + assert_equal 'c51f5bb613cd', readme.lastrev.identifier + # 2001-02-01 00:00:00 -0900 + assert_equal Time.gm(2001, 2, 1, 9, 0, 0), readme.lastrev.time + end + + def test_locate_on_outdated_repository + assert_equal 1, @adapter.entries("images", 0).size + assert_equal 2, @adapter.entries("images").size + assert_equal 2, @adapter.entries("images", 2).size + end + + def test_access_by_nodeid + path = 'sources/welcome_controller.rb' + assert_equal @adapter.cat(path, 2), @adapter.cat(path, '400bb8672109') + end + + def test_access_by_fuzzy_nodeid + path = 'sources/welcome_controller.rb' + # falls back to nodeid + assert_equal @adapter.cat(path, 2), @adapter.cat(path, '400') + end + + def test_tags + assert_equal [@tag_char_1, 'tag_test.00', 'tag-init-revision'], @adapter.tags + end + + def test_tagmap + tm = { + @tag_char_1 => 'adf805632193', + 'tag_test.00' => '6987191f453a', + 'tag-init-revision' => '0885933ad4f6', + } + assert_equal tm, @adapter.tagmap + end + + def test_branches + brs = [] + @adapter.branches.each do |b| + brs << b + end + assert_equal 7, brs.length + assert_equal 'default', brs[0].to_s + assert_equal '31', brs[0].revision + assert_equal '31eeee7395c8', brs[0].scmid + assert_equal 'test-branch-01', brs[1].to_s + assert_equal '30', brs[1].revision + assert_equal 'ad4dc4f80284', brs[1].scmid + assert_equal @branch_char_1, brs[2].to_s + assert_equal '27', brs[2].revision + assert_equal '7bbf4c738e71', brs[2].scmid + assert_equal 'branch (1)[2]&,%.-3_4', brs[3].to_s + assert_equal '25', brs[3].revision + assert_equal 'afc61e85bde7', brs[3].scmid + assert_equal @branch_char_0, brs[4].to_s + assert_equal '23', brs[4].revision + assert_equal 'c8d3e4887474', brs[4].scmid + assert_equal 'test_branch.latin-1', brs[5].to_s + assert_equal '22', brs[5].revision + assert_equal 'c2ffe7da686a', brs[5].scmid + assert_equal 'test-branch-00', brs[6].to_s + assert_equal '13', brs[6].revision + assert_equal '3a330eb32958', brs[6].scmid + end + + def test_branchmap + bm = { + 'default' => '31eeee7395c8', + 'test_branch.latin-1' => 'c2ffe7da686a', + 'branch (1)[2]&,%.-3_4' => 'afc61e85bde7', + 'test-branch-00' => '3a330eb32958', + "test-branch-01" => 'ad4dc4f80284', + @branch_char_0 => 'c8d3e4887474', + @branch_char_1 => '7bbf4c738e71', + } + assert_equal bm, @adapter.branchmap + end + + def test_path_space + p = 'README (1)[2]&,%.-3_4' + [15, '933ca60293d7'].each do |r1| + assert @adapter.diff(p, r1) + assert @adapter.cat(p, r1) + assert_equal 1, @adapter.annotate(p, r1).lines.length + [25, 'afc61e85bde7'].each do |r2| + assert @adapter.diff(p, r1, r2) + end + end + end + + def test_tag_non_ascii + p = "latin-1-dir/test-#{@char_1}-1.txt" + assert @adapter.cat(p, @tag_char_1) + assert_equal 1, @adapter.annotate(p, @tag_char_1).lines.length + end + + def test_branch_non_ascii + p = "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-1.txt" + assert @adapter.cat(p, @branch_char_1) + assert_equal 1, @adapter.annotate(p, @branch_char_1).lines.length + end + + def test_nodes_in_branch + [ + 'default', + @branch_char_1, + 'branch (1)[2]&,%.-3_4', + @branch_char_0, + 'test_branch.latin-1', + 'test-branch-00', + ].each do |bra| + nib0 = @adapter.nodes_in_branch(bra) + assert nib0 + nib1 = @adapter.nodes_in_branch(bra, :limit => 1) + assert_equal 1, nib1.size + case bra + when 'branch (1)[2]&,%.-3_4' + if @adapter.class.client_version_above?([1, 6]) + assert_equal 3, nib0.size + assert_equal nib0[0], 'afc61e85bde7' + nib2 = @adapter.nodes_in_branch(bra, :limit => 2) + assert_equal 2, nib2.size + assert_equal nib2[1], '933ca60293d7' + end + when @branch_char_1 + if @adapter.class.client_version_above?([1, 6]) + assert_equal 2, nib0.size + assert_equal nib0[1], '08ff3227303e' + nib2 = @adapter.nodes_in_branch(bra, :limit => 1) + assert_equal 1, nib2.size + assert_equal nib2[0], '7bbf4c738e71' + end + end + end + end + + def test_path_encoding_default_utf8 + adpt1 = Redmine::Scm::Adapters::MercurialAdapter.new( + REPOSITORY_PATH + ) + assert_equal "UTF-8", adpt1.path_encoding + adpt2 = Redmine::Scm::Adapters::MercurialAdapter.new( + REPOSITORY_PATH, + nil, + nil, + nil, + "" + ) + assert_equal "UTF-8", adpt2.path_encoding + end + + private + + def test_hgversion_for(hgversion, version) + @adapter.class.expects(:hgversion_from_command_line).returns(hgversion) + assert_equal version, @adapter.class.hgversion + end + + def test_template_path_for(version, template) + assert_equal "#{HELPERS_DIR}/#{TEMPLATE_NAME}-#{template}.#{TEMPLATE_EXTENSION}", + @adapter.class.template_path_for(version) + assert File.exist?(@adapter.class.template_path_for(version)) + end + else + puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end + end +rescue LoadError + class MercurialMochaFake < ActiveSupport::TestCase + def test_fake; assert(false, "Requires mocha to run those tests") end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d3/d3139a5cfc4007abb2ed50b55b9ba87ef94495bd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d3/d3139a5cfc4007abb2ed50b55b9ba87ef94495bd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +api.array :relations do + @relations.each do |relation| + api.relation do + api.id relation.id + api.issue_id relation.issue_from_id + api.issue_to_id relation.issue_to_id + api.relation_type relation.relation_type + api.delay relation.delay + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d3/d32d21249396868773353a3cd0ae8adc825c08bb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d3/d32d21249396868773353a3cd0ae8adc825c08bb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Жирный'; +jsToolBar.strings['Italic'] = 'Курсив'; +jsToolBar.strings['Underline'] = 'Подчеркнутый'; +jsToolBar.strings['Deleted'] = 'Зачеркнутый'; +jsToolBar.strings['Code'] = 'Вставка кода'; +jsToolBar.strings['Heading 1'] = 'Заголовок 1'; +jsToolBar.strings['Heading 2'] = 'Заголовок 2'; +jsToolBar.strings['Heading 3'] = 'Заголовок 3'; +jsToolBar.strings['Unordered list'] = 'Маркированный список'; +jsToolBar.strings['Ordered list'] = 'Нумерованный список'; +jsToolBar.strings['Quote'] = 'Цитата'; +jsToolBar.strings['Unquote'] = 'Удалить цитату'; +jsToolBar.strings['Preformatted text'] = 'Заранее форматированный текст'; +jsToolBar.strings['Wiki link'] = 'Ссылка на страницу в Wiki'; +jsToolBar.strings['Image'] = 'Вставка изображения'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d3/d3987661375bfbc88642c98052463ea82f5344e4.svn-base Binary file .svn/pristine/d3/d3987661375bfbc88642c98052463ea82f5344e4.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d3/d3d2f31a14fe74bbd0e9f83346a5f38a3ee8b9ad.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d3/d3d2f31a14fe74bbd0e9f83346a5f38a3ee8b9ad.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 WelcomeHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d3/d3f415dece34a1117d042ed2dfb14252d8d7eeec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d3/d3f415dece34a1117d042ed2dfb14252d8d7eeec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 AdminHelper + def project_status_options_for_select(selected) + options_for_select([[l(:label_all), ''], + [l(:status_active), 1]], selected) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d4053288db720e7328efde6be5005ae9fef364cf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d4053288db720e7328efde6be5005ae9fef364cf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,131 @@ +# binarytree.rb +# +# $Revision: 1.5 $ by $Author: anupamsg $ +# $Name: $ +# +# = binarytree.rb - Binary Tree implementation +# +# Provides a generic tree data structure with ability to +# store keyed node elements in the tree. The implementation +# mixes in the Enumerable module. +# +# Author:: Anupam Sengupta (anupamsg@gmail.com) +# + +# Copyright (c) 2007 Anupam Sengupta +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# - Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# - Neither the name of the organization nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +require 'tree' + +module Tree + + # Provides a Binary tree implementation. This tree node allows only two child + # nodes (left and right childs). It also provides direct access to the left + # and right children, including assignment to the same. + class BinaryTreeNode < TreeNode + + # Adds the specified child node to the receiver node. The child node's + # parent is set to be the receiver. The child nodes are added in the order + # of addition, i.e., the first child added becomes the left node, and the + # second child will be the second node. + # If only one child is present, then this will be the left child. + def add(child) + raise "Already has two child nodes" if @children.size == 2 + + super(child) + end + + # Returns the left child node. Note that + # left Child == first Child + def leftChild + children.first + end + + # Returns the right child node. Note that + # right child == last child unless there is only one child. + # Returns nil if the right child does not exist. + def rightChild + children[1] + end + + # Sets the left child. If a previous child existed, it is replaced. + def leftChild=(child) + @children[0] = child + @childrenHash[child.name] = child if child # Assign the name mapping + end + + # Sets the right child. If a previous child existed, it is replaced. + def rightChild=(child) + @children[1] = child + @childrenHash[child.name] = child if child # Assign the name mapping + end + + # Returns true if this is the left child of its parent. Always returns false + # if this is the root node. + def isLeftChild? + return nil if isRoot? + self == parent.leftChild + end + + # Returns true if this is the right child of its parent. Always returns false + # if this is the root node. + def isRightChild? + return nil if isRoot? + self == parent.rightChild + end + + # Swaps the left and right children with each other + def swap_children + tempChild = leftChild + self.leftChild= rightChild + self.rightChild= tempChild + end + end + +end + +# $Log: binarytree.rb,v $ +# Revision 1.5 2007/12/18 23:11:29 anupamsg +# Minor documentation changes in the binarytree class. +# +# Revision 1.4 2007/08/30 22:08:58 anupamsg +# Added a new swap_children method for Binary Tree. Also added minor +# documentation and test updates. +# +# Revision 1.3 2007/07/21 03:24:25 anupamsg +# Minor edits to parameter names. User visible functionality does not change. +# +# Revision 1.2 2007/07/18 20:15:06 anupamsg +# Added two predicate methods in BinaryTreeNode to determine whether a node +# is a left or a right node. +# +# Revision 1.1 2007/07/18 19:33:27 anupamsg +# Added a new binary tree implementation. +# diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d41121fcebce5326907fe3372125f263e4e35c3c.svn-base Binary file .svn/pristine/d4/d41121fcebce5326907fe3372125f263e4e35c3c.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d43f96e1d5c57768eacc3fbf283865d4bf12992f.svn-base Binary file .svn/pristine/d4/d43f96e1d5c57768eacc3fbf283865d4bf12992f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d4482ad7b7f59be62f8bc68fbfaf937393743402.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d4482ad7b7f59be62f8bc68fbfaf937393743402.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,172 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::Hook::ManagerTest < ActiveSupport::TestCase + + fixtures :issues + + # Some hooks that are manually registered in these tests + class TestHook < Redmine::Hook::ViewListener; end + + class TestHook1 < TestHook + def view_layouts_base_html_head(context) + 'Test hook 1 listener.' + end + end + + class TestHook2 < TestHook + def view_layouts_base_html_head(context) + 'Test hook 2 listener.' + end + end + + class TestHook3 < TestHook + def view_layouts_base_html_head(context) + "Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}." + end + end + + class TestLinkToHook < TestHook + def view_layouts_base_html_head(context) + link_to('Issues', :controller => 'issues') + end + end + + class TestHookHelperController < ActionController::Base + include Redmine::Hook::Helper + end + + class TestHookHelperView < ActionView::Base + include Redmine::Hook::Helper + end + + Redmine::Hook.clear_listeners + + def setup + @hook_module = Redmine::Hook + end + + def teardown + @hook_module.clear_listeners + end + + def test_clear_listeners + assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size + @hook_module.add_listener(TestHook1) + @hook_module.add_listener(TestHook2) + assert_equal 2, @hook_module.hook_listeners(:view_layouts_base_html_head).size + + @hook_module.clear_listeners + assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size + end + + def test_add_listener + assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size + @hook_module.add_listener(TestHook1) + assert_equal 1, @hook_module.hook_listeners(:view_layouts_base_html_head).size + end + + def test_call_hook + @hook_module.add_listener(TestHook1) + assert_equal ['Test hook 1 listener.'], hook_helper.call_hook(:view_layouts_base_html_head) + end + + def test_call_hook_with_context + @hook_module.add_listener(TestHook3) + assert_equal ['Context keys: bar, controller, foo, project, request.'], + hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a') + end + + def test_call_hook_with_multiple_listeners + @hook_module.add_listener(TestHook1) + @hook_module.add_listener(TestHook2) + assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], hook_helper.call_hook(:view_layouts_base_html_head) + end + + # Context: Redmine::Hook::Helper.call_hook default_url + def test_call_hook_default_url_options + @hook_module.add_listener(TestLinkToHook) + + assert_equal ['Issues'], hook_helper.call_hook(:view_layouts_base_html_head) + end + + # Context: Redmine::Hook::Helper.call_hook + def test_call_hook_with_project_added_to_context + @hook_module.add_listener(TestHook3) + assert_match /project/i, hook_helper.call_hook(:view_layouts_base_html_head)[0] + end + + def test_call_hook_from_controller_with_controller_added_to_context + @hook_module.add_listener(TestHook3) + assert_match /controller/i, hook_helper.call_hook(:view_layouts_base_html_head)[0] + end + + def test_call_hook_from_controller_with_request_added_to_context + @hook_module.add_listener(TestHook3) + assert_match /request/i, hook_helper.call_hook(:view_layouts_base_html_head)[0] + end + + def test_call_hook_from_view_with_project_added_to_context + @hook_module.add_listener(TestHook3) + assert_match /project/i, view_hook_helper.call_hook(:view_layouts_base_html_head) + end + + def test_call_hook_from_view_with_controller_added_to_context + @hook_module.add_listener(TestHook3) + assert_match /controller/i, view_hook_helper.call_hook(:view_layouts_base_html_head) + end + + def test_call_hook_from_view_with_request_added_to_context + @hook_module.add_listener(TestHook3) + assert_match /request/i, view_hook_helper.call_hook(:view_layouts_base_html_head) + end + + def test_call_hook_from_view_should_join_responses_with_a_space + @hook_module.add_listener(TestHook1) + @hook_module.add_listener(TestHook2) + assert_equal 'Test hook 1 listener. Test hook 2 listener.', + view_hook_helper.call_hook(:view_layouts_base_html_head) + end + + def test_call_hook_should_not_change_the_default_url_for_email_notifications + issue = Issue.find(1) + + ActionMailer::Base.deliveries.clear + Mailer.deliver_issue_add(issue) + mail = ActionMailer::Base.deliveries.last + + @hook_module.add_listener(TestLinkToHook) + hook_helper.call_hook(:view_layouts_base_html_head) + + ActionMailer::Base.deliveries.clear + Mailer.deliver_issue_add(issue) + mail2 = ActionMailer::Base.deliveries.last + + assert_equal mail.body, mail2.body + end + + def hook_helper + @hook_helper ||= TestHookHelperController.new + end + + def view_hook_helper + @view_hook_helper ||= TestHookHelperView.new(Rails.root.to_s + '/app/views') + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d45b2dee9e6069640c900ea2aa339df5c894b306.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d45b2dee9e6069640c900ea2aa339df5c894b306.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddQueriesSortCriteria < ActiveRecord::Migration + def self.up + add_column :queries, :sort_criteria, :text + end + + def self.down + remove_column :queries, :sort_criteria + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d4784b674172654e5a4164cf7f526c3360280dc5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d4784b674172654e5a4164cf7f526c3360280dc5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%=l(:label_password_lost)%>

    + +<%= error_messages_for 'user' %> + +<% form_tag({:token => @token.value}) do %> +
    +

    +<%= password_field_tag 'new_password', nil, :size => 25 %>
    +<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    + +

    +<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    +
    +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d4926106ef44c5f951d961f9eb5f2af78dbe9754.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d4926106ef44c5f951d961f9eb5f2af78dbe9754.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/process/spawner' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d4da4a559fadb71236d2e8c75903152ca38b8d80.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d4da4a559fadb71236d2e8c75903152ca38b8d80.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class NewsObserver < ActiveRecord::Observer + def after_create(news) + Mailer.deliver_news_added(news) if Setting.notified_events.include?('news_added') + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d4/d4dcf9a5e7b6ef2ec5289c5f08ea6b3b53a0b6cf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d4/d4dcf9a5e7b6ef2ec5289c5f08ea6b3b53a0b6cf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class PopulateMemberRoles < ActiveRecord::Migration + def self.up + MemberRole.delete_all + Member.find(:all).each do |member| + MemberRole.create!(:member_id => member.id, :role_id => member.role_id) + end + end + + def self.down + MemberRole.delete_all + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d5050114448f68b3daa8ff218c27426ce16d4bf7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d5050114448f68b3daa8ff218c27426ce16d4bf7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,143 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class WatcherTest < ActiveSupport::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, :enabled_modules, + :issues, + :boards, :messages, + :wikis, :wiki_pages, + :watchers + + def setup + @user = User.find(1) + @issue = Issue.find(1) + end + + def test_watch + assert @issue.add_watcher(@user) + @issue.reload + assert @issue.watchers.detect { |w| w.user == @user } + end + + def test_cant_watch_twice + assert @issue.add_watcher(@user) + assert !@issue.add_watcher(@user) + end + + def test_watched_by + assert @issue.add_watcher(@user) + @issue.reload + assert @issue.watched_by?(@user) + assert Issue.watched_by(@user).include?(@issue) + end + + def test_watcher_users + watcher_users = Issue.find(2).watcher_users + assert_kind_of Array, watcher_users + assert_kind_of User, watcher_users.first + end + + def test_watcher_users_should_not_validate_user + User.update_all("firstname = ''", "id=1") + @user.reload + assert !@user.valid? + + issue = Issue.new(:project => Project.find(1), :tracker_id => 1, :subject => "test", :author => User.find(2)) + issue.watcher_users << @user + issue.save! + assert issue.watched_by?(@user) + end + + def test_watcher_user_ids + assert_equal [1, 3], Issue.find(2).watcher_user_ids.sort + end + + def test_watcher_user_ids= + issue = Issue.new + issue.watcher_user_ids = ['1', '3'] + assert issue.watched_by?(User.find(1)) + end + + def test_addable_watcher_users + addable_watcher_users = @issue.addable_watcher_users + assert_kind_of Array, addable_watcher_users + assert_kind_of User, addable_watcher_users.first + end + + def test_addable_watcher_users_should_not_include_user_that_cannot_view_the_object + issue = Issue.new(:project => Project.find(1), :is_private => true) + assert_nil issue.addable_watcher_users.detect {|user| !issue.visible?(user)} + end + + def test_recipients + @issue.watchers.delete_all + @issue.reload + + assert @issue.watcher_recipients.empty? + assert @issue.add_watcher(@user) + + @user.mail_notification = 'all' + @user.save! + @issue.reload + assert @issue.watcher_recipients.include?(@user.mail) + + @user.mail_notification = 'none' + @user.save! + @issue.reload + assert !@issue.watcher_recipients.include?(@user.mail) + end + + def test_unwatch + assert @issue.add_watcher(@user) + @issue.reload + assert_equal 1, @issue.remove_watcher(@user) + end + + def test_prune + Watcher.delete_all("user_id = 9") + user = User.find(9) + + # public + Watcher.create!(:watchable => Issue.find(1), :user => user) + Watcher.create!(:watchable => Issue.find(2), :user => user) + Watcher.create!(:watchable => Message.find(1), :user => user) + Watcher.create!(:watchable => Wiki.find(1), :user => user) + Watcher.create!(:watchable => WikiPage.find(2), :user => user) + + # private project (id: 2) + Member.create!(:project => Project.find(2), :principal => user, :role_ids => [1]) + Watcher.create!(:watchable => Issue.find(4), :user => user) + Watcher.create!(:watchable => Message.find(7), :user => user) + Watcher.create!(:watchable => Wiki.find(2), :user => user) + Watcher.create!(:watchable => WikiPage.find(3), :user => user) + + assert_no_difference 'Watcher.count' do + Watcher.prune(:user => User.find(9)) + end + + Member.delete_all + + assert_difference 'Watcher.count', -4 do + Watcher.prune(:user => User.find(9)) + end + + assert Issue.find(1).watched_by?(user) + assert !Issue.find(4).watched_by?(user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d52cd894471c60da0fd08878344d5bd7680a2e5a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d52cd894471c60da0fd08878344d5bd7680a2e5a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,65 @@ +# Be sure to restart your web server when you modify this file. + +# Uncomment below to force Rails into production mode when +# you don't control web/app server and can't set it the proper way +# ENV['RAILS_ENV'] ||= 'production' + +# Specifies gem version of Rails to use when vendor/rails is not present +RAILS_GEM_VERSION = '2.3.14' unless defined? RAILS_GEM_VERSION + +if RUBY_VERSION >= '1.9' + Encoding.default_external = 'UTF-8' +end + +# Bootstrap the Rails environment, frameworks, and default configuration +require File.join(File.dirname(__FILE__), 'boot') + +# Load Engine plugin if available +begin + require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot') +rescue LoadError + # Not available +end + +Rails::Initializer.run do |config| + # Settings in config/environments/* take precedence those specified here + + # Skip frameworks you're not going to use + # config.frameworks -= [ :action_web_service, :action_mailer ] + + # Add additional load paths for sweepers + config.autoload_paths += %W( #{RAILS_ROOT}/app/sweepers ) + + # Force all environments to use the same logger level + # (by default production uses :info, the others :debug) + # config.log_level = :debug + + # Enable page/fragment caching by setting a file-based store + # (remember to create the caching directory and make it readable to the application) + # config.action_controller.cache_store = :file_store, "#{RAILS_ROOT}/tmp/cache" + + # Activate observers that should always be running + # config.active_record.observers = :cacher, :garbage_collector + config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer, :comment_observer + + # Make Active Record use UTC-base instead of local time + # config.active_record.default_timezone = :utc + + # Use Active Record's schema dumper instead of SQL when creating the test database + # (enables use of different database adapters for development and test environments) + # config.active_record.schema_format = :ruby + + # Deliveries are disabled by default. Do NOT modify this section. + # Define your email configuration in configuration.yml instead. + # It will automatically turn deliveries on + config.action_mailer.perform_deliveries = false + + config.gem 'rubytree', :lib => 'tree' + config.gem 'coderay', :version => '~>1.0.0' + + # Load any local configuration that is kept out of source control + # (e.g. gems, patches). + if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) + instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb')) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d548c36e80e4a89327441816bcb3b1c0d9351684.svn-base Binary file .svn/pristine/d5/d548c36e80e4a89327441816bcb3b1c0d9351684.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d562875108cecc41042a4d0be1488884f1e06a95.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d562875108cecc41042a4d0be1488884f1e06a95.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,68 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class AuthSource < ActiveRecord::Base + include Redmine::Ciphering + + has_many :users + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 60 + + def authenticate(login, password) + end + + def test_connection + end + + def auth_method_name + "Abstract" + end + + def account_password + read_ciphered_attribute(:account_password) + end + + def account_password=(arg) + write_ciphered_attribute(:account_password, arg) + end + + def allow_password_changes? + self.class.allow_password_changes? + end + + # Does this auth source backend allow password changes? + def self.allow_password_changes? + false + end + + # Try to authenticate a user not yet registered against available sources + def self.authenticate(login, password) + AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source| + begin + logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? + attrs = source.authenticate(login, password) + rescue => e + logger.error "Error during authentication: #{e.message}" + attrs = nil + end + return attrs if attrs + end + return nil + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d5702bcdc6e61efeb5c6de92cb904d7e57f2c46b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d5702bcdc6e61efeb5c6de92cb904d7e57f2c46b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +module RenderInformation + def render_class_and_action(note = nil, options={}) + text = "rendered in #{self.class.name}##{params[:action]}" + text += " (#{note})" unless note.nil? + render options.update(:text => text) + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d588ced6d5efcbe60b58d36d380d9f3530582ca9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d588ced6d5efcbe60b58d36d380d9f3530582ca9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Token < ActiveRecord::Base + belongs_to :user + validates_uniqueness_of :value + + before_create :delete_previous_tokens, :generate_new_token + + @@validity_time = 1.day + + def generate_new_token + self.value = Token.generate_token_value + end + + # Return true if token has expired + def expired? + return Time.now > self.created_on + @@validity_time + end + + # Delete all expired tokens + def self.destroy_expired + Token.delete_all ["action <> 'feeds' AND created_on < ?", Time.now - @@validity_time] + end + +private + def self.generate_token_value + ActiveSupport::SecureRandom.hex(20) + end + + # Removes obsolete tokens (same user and action) + def delete_previous_tokens + if user + Token.delete_all(['user_id = ? AND action = ?', user.id, action]) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d5c42a8cf284c9057072604f567dd5624a3806d3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d5c42a8cf284c9057072604f567dd5624a3806d3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,313 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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' +require 'redmine/codeset_util' + +module RepositoriesHelper + def format_revision(revision) + if revision.respond_to? :format_identifier + revision.format_identifier + else + revision.to_s + end + end + + def truncate_at_line_break(text, length = 255) + if text + text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...') + end + end + + def render_properties(properties) + unless properties.nil? || properties.empty? + content = '' + properties.keys.sort.each do |property| + content << content_tag('li', "#{h property}: #{h properties[property]}".html_safe) + end + content_tag('ul', content.html_safe, :class => 'properties') + end + end + + def render_changeset_changes + changes = @changeset.changes.find(:all, :limit => 1000, :order => 'path').collect do |change| + case change.action + when 'A' + # Detects moved/copied files + if !change.from_path.blank? + change.action = + @changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C' + end + change + when 'D' + @changeset.changes.detect {|c| c.from_path == change.path} ? nil : change + else + change + end + end.compact + + tree = { } + changes.each do |change| + p = tree + dirs = change.path.to_s.split('/').select {|d| !d.blank?} + path = '' + dirs.each do |dir| + path += '/' + dir + p[:s] ||= {} + p = p[:s] + p[path] ||= {} + p = p[path] + end + p[:c] = change + end + render_changes_tree(tree[:s]) + end + + def render_changes_tree(tree) + return '' if tree.nil? + output = '' + output << '
      ' + tree.keys.sort.each do |file| + style = 'change' + text = File.basename(h(file)) + if s = tree[file][:s] + style << ' folder' + path_param = to_path_param(@repository.relative_path(file)) + text = link_to(h(text), :controller => 'repositories', + :action => 'show', + :id => @project, + :path => path_param, + :rev => @changeset.identifier) + output << "
    • #{text}
    • " + output << render_changes_tree(s) + elsif c = tree[file][:c] + style << " change-#{c.action}" + path_param = to_path_param(@repository.relative_path(c.path)) + text = link_to(h(text), :controller => 'repositories', + :action => 'entry', + :id => @project, + :path => path_param, + :rev => @changeset.identifier) unless c.action == 'D' + text << " - #{h(c.revision)}" unless c.revision.blank? + text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories', + :action => 'diff', + :id => @project, + :path => path_param, + :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M' + text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank? + output << "
    • #{text}
    • " + end + end + output << '
    ' + output.html_safe + end + + def repository_field_tags(form, repository) + method = repository.class.name.demodulize.underscore + "_field_tags" + if repository.is_a?(Repository) && + respond_to?(method) && method != 'repository_field_tags' + send(method, form, repository) + end + end + + def scm_select_tag(repository) + scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']] + Redmine::Scm::Base.all.each do |scm| + if Setting.enabled_scm.include?(scm) || + (repository && repository.class.name.demodulize == scm) + scm_options << ["Repository::#{scm}".constantize.scm_name, scm] + end + end + select_tag('repository_scm', + options_for_select(scm_options, repository.class.name.demodulize), + :disabled => (repository && !repository.new_record?), + :onchange => remote_function( + :url => { + :controller => 'repositories', + :action => 'edit', + :id => @project + }, + :method => :get, + :with => "Form.serialize(this.form)") + ) + end + + def with_leading_slash(path) + path.to_s.starts_with?('/') ? path : "/#{path}" + end + + def without_leading_slash(path) + path.gsub(%r{^/+}, '') + end + + def subversion_field_tags(form, repository) + content_tag('p', form.text_field(:url, :size => 60, :required => true, + :disabled => (repository && !repository.root_url.blank?)) + + '
    '.html_safe + + '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') + + content_tag('p', form.text_field(:login, :size => 30)) + + content_tag('p', form.password_field( + :password, :size => 30, :name => 'ignore', + :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)), + :onfocus => "this.value=''; this.name='repository[password]';", + :onchange => "this.name='repository[password]';")) + end + + def darcs_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => (repository && !repository.new_record?))) + + content_tag('p', form.select( + :log_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_commit_logs_encoding), :required => true)) + end + + def mercurial_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => (repository && !repository.root_url.blank?) + ) + + '
    '.html_safe + l(:text_mercurial_repository_note)) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
    '.html_safe + l(:text_scm_path_encoding_note)) + end + + def git_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => (repository && !repository.root_url.blank?) + ) + + '
    '.html_safe + + l(:text_git_repository_note)) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
    '.html_safe + l(:text_scm_path_encoding_note)) + + content_tag('p', form.check_box( + :extra_report_last_commit, + :label => l(:label_git_report_last_commit) + )) + end + + def cvs_field_tags(form, repository) + content_tag('p', form.text_field( + :root_url, + :label => l(:field_cvsroot), + :size => 60, :required => true, + :disabled => !repository.new_record?)) + + content_tag('p', form.text_field( + :url, + :label => l(:field_cvs_module), + :size => 30, :required => true, + :disabled => !repository.new_record?)) + + content_tag('p', form.select( + :log_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_commit_logs_encoding), :required => true)) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
    '.html_safe + l(:text_scm_path_encoding_note)) + end + + def bazaar_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => (repository && !repository.new_record?))) + + content_tag('p', form.select( + :log_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_commit_logs_encoding), :required => true)) + end + + def filesystem_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_root_directory), + :size => 60, :required => true, + :disabled => (repository && !repository.root_url.blank?))) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
    '.html_safe + l(:text_scm_path_encoding_note)) + end + + def index_commits(commits, heads, href_proc = nil) + return nil if commits.nil? or commits.first.parents.nil? + map = {} + commit_hashes = [] + refs_map = {} + href_proc ||= Proc.new {|x|x} + heads.each{|r| refs_map[r.scmid] ||= []; refs_map[r.scmid] << r} + commits.reverse.each_with_index do |c, i| + h = {} + h[:parents] = c.parents.collect do |p| + [p.scmid, 0, 0] + end + h[:rdmid] = i + h[:space] = 0 + h[:refs] = refs_map[c.scmid].join(" ") if refs_map.include? c.scmid + h[:scmid] = c.scmid + h[:href] = href_proc.call(c.scmid) + commit_hashes << h + map[c.scmid] = h + end + heads.sort! do |a,b| + a.to_s <=> b.to_s + end + j = 0 + heads.each do |h| + if map.include? h.scmid then + j = mark_chain(j += 1, map[h.scmid], map) + end + end + # when no head matched anything use first commit + if j == 0 then + mark_chain(j += 1, map.values.first, map) + end + map + end + + def mark_chain(mark, commit, map) + stack = [[mark, commit]] + markmax = mark + until stack.empty? + current = stack.pop + m, commit = current + commit[:space] = m if commit[:space] == 0 + m1 = m - 1 + commit[:parents].each_with_index do |p, i| + psha = p[0] + if map.include? psha and map[psha][:space] == 0 then + stack << [m1 += 1, map[psha]] if i == 0 + stack = [[m1 += 1, map[psha]]] + stack if i > 0 + end + end + markmax = m1 if markmax < m1 + end + markmax + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d5d37bb7dbfb0bad38a53c5b63ab300f544aea42.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d5d37bb7dbfb0bad38a53c5b63ab300f544aea42.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'net/pop' + +module Redmine + module POP3 + class << self + def check(pop_options={}, options={}) + host = pop_options[:host] || '127.0.0.1' + port = pop_options[:port] || '110' + apop = (pop_options[:apop].to_s == '1') + delete_unprocessed = (pop_options[:delete_unprocessed].to_s == '1') + + pop = Net::POP3.APOP(apop).new(host,port) + logger.debug "Connecting to #{host}..." if logger && logger.debug? + pop.start(pop_options[:username], pop_options[:password]) do |pop_session| + if pop_session.mails.empty? + logger.debug "No email to process" if logger && logger.debug? + else + logger.debug "#{pop_session.mails.size} email(s) to process..." if logger && logger.debug? + pop_session.each_mail do |msg| + message = msg.pop + message_id = (message =~ /^Message-ID: (.*)/ ? $1 : '').strip + if MailHandler.receive(message, options) + msg.delete + logger.debug "--> Message #{message_id} processed and deleted from the server" if logger && logger.debug? + else + if delete_unprocessed + msg.delete + logger.debug "--> Message #{message_id} NOT processed and deleted from the server" if logger && logger.debug? + else + logger.debug "--> Message #{message_id} NOT processed and left on the server" if logger && logger.debug? + end + end + end + end + end + end + + private + + def logger + RAILS_DEFAULT_LOGGER + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d5/d5f12b9435fe0efa5be5065b1768cd4f3672f5e4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d5/d5f12b9435fe0efa5be5065b1768cd4f3672f5e4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +Description: + Generates a plugin model. + +Examples: + ./script/generate redmine_plugin_model MyPlugin pool title:string question:text diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d629345df56e3e889eaaef3db666cce1ae6753ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d629345df56e3e889eaaef3db666cce1ae6753ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/server' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d6359025a5eb4f10b9cc606f83ccdea5749d7ce4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d6359025a5eb4f10b9cc606f83ccdea5749d7ce4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +<% if @wiki && @wiki.sidebar -%> + <%= textilizable @wiki.sidebar.content, :text %> +<% end -%> + +

    <%= l(:label_wiki) %>

    + +<%= link_to l(:field_start_page), {:action => 'show', :id => nil} %>
    +<%= link_to l(:label_index_by_title), {:action => 'index'} %>
    +<%= link_to l(:label_index_by_date), {:action => 'date_index'} %>
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d6596be6722d5d3017f7578d7146052fd2188b57.svn-base Binary file .svn/pristine/d6/d6596be6722d5d3017f7578d7146052fd2188b57.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d6698fbb3d7ced7c091f2c64deb47e313e9b1ff9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d6698fbb3d7ced7c091f2c64deb47e313e9b1ff9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Félkövér'; +jsToolBar.strings['Italic'] = 'Dőlt'; +jsToolBar.strings['Underline'] = 'Aláhúzott'; +jsToolBar.strings['Deleted'] = 'Törölt'; +jsToolBar.strings['Code'] = 'Kód sorok'; +jsToolBar.strings['Heading 1'] = 'Fejléc 1'; +jsToolBar.strings['Heading 2'] = 'Fejléc 2'; +jsToolBar.strings['Heading 3'] = 'Fejléc 3'; +jsToolBar.strings['Unordered list'] = 'Felsorolás'; +jsToolBar.strings['Ordered list'] = 'Számozott lista'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Előreformázott szöveg'; +jsToolBar.strings['Wiki link'] = 'Link egy Wiki oldalra'; +jsToolBar.strings['Image'] = 'Kép'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d686576cc5313c6c5ff9ec468ab9b2b763d728a1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d686576cc5313c6c5ff9ec468ab9b2b763d728a1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,139 @@ +# Information +# +# PDF_EPS class from Valentin Schmidt ported to ruby by Thiago Jackiw (tjackiw@gmail.com) +# working for Mingle LLC (www.mingle.com) +# Release Date: July 13th, 2006 +# +# Description +# +# This script allows to embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files. +# Only vector drawing is supported, not text or bitmap. Although the script was successfully +# tested with various AI format versions, best results are probably achieved with files that +# were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2). +# +# ImageEps(string file, float x, float y [, float w [, float h [, string link [, boolean useBoundingBox]]]]) +# +# Same parameters as for regular FPDF::Image() method, with an additional one: +# +# useBoundingBox: specifies whether to position the bounding box (true) or the complete canvas (false) +# at location (x,y). Default value is true. +# +# First added to the Ruby FPDF distribution in 1.53c +# +# Usage is as follows: +# +# require 'fpdf' +# require 'fpdf_eps' +# pdf = FPDF.new +# pdf.extend(PDF_EPS) +# pdf.ImageEps(...) +# +# This allows it to be combined with other extensions, such as the bookmark +# module. + +module PDF_EPS + def ImageEps(file, x, y, w=0, h=0, link='', use_bounding_box=true) + data = nil + if File.exists?(file) + File.open(file, 'rb') do |f| + data = f.read() + end + else + Error('EPS file not found: '+file) + end + + # Find BoundingBox param + regs = data.scan(/%%BoundingBox: [^\r\n]*/m) + regs << regs[0].gsub(/%%BoundingBox: /, '') + if regs.size > 1 + tmp = regs[1].to_s.split(' ') + @x1 = tmp[0].to_i + @y1 = tmp[1].to_i + @x2 = tmp[2].to_i + @y2 = tmp[3].to_i + else + Error('No BoundingBox found in EPS file: '+file) + end + f_start = data.index('%%EndSetup') + f_start = data.index('%%EndProlog') if f_start === false + f_start = data.index('%%BoundingBox') if f_start === false + + data = data.slice(f_start, data.length) + + f_end = data.index('%%PageTrailer') + f_end = data.index('showpage') if f_end === false + data = data.slice(0, f_end) if f_end + + # save the current graphic state + out('q') + + k = @k + + # Translate + if use_bounding_box + dx = x*k-@x1 + dy = @hPt-@y2-y*k + else + dx = x*k + dy = -y*k + end + tm = [1,0,0,1,dx,dy] + out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', + tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])) + + if w > 0 + scale_x = w/((@x2-@x1)/k) + if h > 0 + scale_y = h/((@y2-@y1)/k) + else + scale_y = scale_x + h = (@y2-@y1)/k * scale_y + end + else + if h > 0 + scale_y = $h/((@y2-@y1)/$k) + scale_x = scale_y + w = (@x2-@x1)/k * scale_x + else + w = (@x2-@x1)/k + h = (@y2-@y1)/k + end + end + + if !scale_x.nil? + # Scale + tm = [scale_x,0,0,scale_y,0,@hPt*(1-scale_y)] + out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', + tm[0], tm[1], tm[2], tm[3], tm[4], tm[5])) + end + + data.split(/\r\n|[\r\n]/).each do |line| + next if line == '' || line[0,1] == '%' + len = line.length + # next if (len > 2 && line[len-2,len] != ' ') + cmd = line[len-2,len].strip + case cmd + when 'm', 'l', 'v', 'y', 'c', 'k', 'K', 'g', 'G', 's', 'S', 'J', 'j', 'w', 'M', 'd': + out(line) + + when 'L': + line[len-1,len]='l' + out(line) + + when 'C': + line[len-1,len]='c' + out(line) + + when 'f', 'F': + out('f*') + + when 'b', 'B': + out(cmd + '*') + end + end + + # restore previous graphic state + out('Q') + Link(x,y,w,h,link) if link + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d68d2d2b45f16a8ea41410cc06486a1fab804216.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d68d2d2b45f16a8ea41410cc06486a1fab804216.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToBoards < ActiveRecord::Migration + def self.up + add_index :boards, :last_message_id + end + + def self.down + remove_index :boards, :last_message_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d69bb5e326921662068639ad253bdc842f1583e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d69bb5e326921662068639ad253bdc842f1583e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +this is a text file for upload tests +with multiple lines diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d6d2d7c49f7779d8e6b7df27e7cb7703684fb6de.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d6d2d7c49f7779d8e6b7df27e7cb7703684fb6de.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +class CreateProjectsTrackers < ActiveRecord::Migration + def self.up + create_table :projects_trackers, :id => false do |t| + t.column :project_id, :integer, :default => 0, :null => false + t.column :tracker_id, :integer, :default => 0, :null => false + end + add_index :projects_trackers, :project_id, :name => :projects_trackers_project_id + + # Associates all trackers to all projects (as it was before) + tracker_ids = Tracker.find(:all).collect(&:id) + Project.find(:all).each do |project| + project.tracker_ids = tracker_ids + end + end + + def self.down + drop_table :projects_trackers + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d6ec7da458d1a6039ba94f943e025c4cbc9d1f92.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d6ec7da458d1a6039ba94f943e025c4cbc9d1f92.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +
    +<%= l(:label_date_range) %> +
    +

    +<%= label_tag "period_type_list", l(:description_date_range_list), :class => "hidden-for-sighted" %> +<%= radio_button_tag 'period_type', '1', !@free_period, :onclick => 'Form.Element.disable("from");Form.Element.disable("to");Form.Element.enable("period");', :id => "period_type_list"%> +<%= select_tag 'period', options_for_period_select(params[:period]), + :onchange => 'this.form.submit();', + :onfocus => '$("period_type_1").checked = true;', + :disabled => @free_period %> +

    +

    +<%= label_tag "period_type_interval", l(:description_date_range_interval), :class => "hidden-for-sighted" %> +<%= radio_button_tag 'period_type', '2', @free_period, :onclick => 'Form.Element.enable("from");Form.Element.enable("to");Form.Element.disable("period");', :id => "period_type_interval" %> + +<%= l(:label_date_from_to, + :start => ((label_tag "from", l(:description_date_from), :class => "hidden-for-sighted") + + text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), + :end => ((label_tag "to", l(:description_date_to), :class => "hidden-for-sighted") + + text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))) %> + +

    +
    +
    +

    + <%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), {:controller => controller_name, :action => action_name, :project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %> +

    + +
    +<% url_params = @free_period ? { :from => @from, :to => @to } : { :period => params[:period] } %> +
      +
    • <%= link_to(l(:label_details), url_params.merge({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue }), + :class => (@controller.action_name == 'index' ? 'selected' : nil)) %>
    • +
    • <%= link_to(l(:label_report), url_params.merge({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}), + :class => (@controller.action_name == 'report' ? 'selected' : nil)) %>
    • +
    +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d6/d6fb15df1769f8d322c674910838ec3cca56e211.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d6/d6fb15df1769f8d322c674910838ec3cca56e211.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +acts_as_tree +============ + +Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children +association. This requires that you have a foreign key column, which by default is called +parent_id+. + + class Category < ActiveRecord::Base + acts_as_tree :order => "name" + end + + Example: + root + \_ child1 + \_ subchild1 + \_ subchild2 + + root = Category.create("name" => "root") + child1 = root.children.create("name" => "child1") + subchild1 = child1.children.create("name" => "subchild1") + + root.parent # => nil + child1.parent # => root + root.children # => [child1] + root.children.first.children.first # => subchild1 + +Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d70cd74c0ebc78d926978f72403660b2b7a42fad.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d70cd74c0ebc78d926978f72403660b2b7a42fad.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +class CreateBoards < ActiveRecord::Migration + def self.up + create_table :boards do |t| + t.column :project_id, :integer, :null => false + t.column :name, :string, :default => "", :null => false + t.column :description, :string + t.column :position, :integer, :default => 1 + t.column :topics_count, :integer, :default => 0, :null => false + t.column :messages_count, :integer, :default => 0, :null => false + t.column :last_message_id, :integer + end + add_index :boards, [:project_id], :name => :boards_project_id + end + + def self.down + drop_table :boards + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d71db2ac4105263a352d2e280dedafe26d5196e1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d71db2ac4105263a352d2e280dedafe26d5196e1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class CreateTests < ActiveRecord::Migration + def self.up + create_table 'tests' do |t| + t.column 'name', :string + end + end + + def self.down + drop_table 'tests' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d73cc4282b0675ac6625b48691a08efc047fa105.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d73cc4282b0675ac6625b48691a08efc047fa105.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/helper' +require File.dirname(__FILE__) + '/../init' + +class PaginationHelperTest < Test::Unit::TestCase + include ActionController::Pagination + include ActionView::Helpers::PaginationHelper + include ActionView::Helpers::UrlHelper + include ActionView::Helpers::TagHelper + + def setup + @controller = Class.new do + attr_accessor :url, :request + def url_for(options, *parameters_for_method_reference) + url + end + end + @controller = @controller.new + @controller.url = "http://www.example.com" + end + + def test_pagination_links + total, per_page, page = 30, 10, 1 + output = pagination_links Paginator.new(@controller, total, per_page, page) + assert_equal "1 2 3 ", output + end + + def test_pagination_links_with_prefix + total, per_page, page = 30, 10, 1 + output = pagination_links Paginator.new(@controller, total, per_page, page), :prefix => 'Newer ' + assert_equal "Newer 1 2 3 ", output + end + + def test_pagination_links_with_suffix + total, per_page, page = 30, 10, 1 + output = pagination_links Paginator.new(@controller, total, per_page, page), :suffix => 'Older' + assert_equal "1 2 3 Older", output + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d748c91ccd41e8268da967dfd983a0fea41803f6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d748c91ccd41e8268da967dfd983a0fea41803f6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar SR language +// Author: Dragan Matic, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("недеља", + "понедељак", + "уторак", + "среда", + "четвртак", + "петак", + "субота", + "недеља"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("нед", + "пон", + "уто", + "сре", + "чет", + "пет", + "суб", + "нед"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("јануар", + "фебруар", + "март", + "април", + "мај", + "јун", + "јул", + "август", + "септембар", + "октобар", + "новембар", + "децембар"); + +// short month names +Calendar._SMN = new Array +("јан", + "феб", + "мар", + "апр", + "мај", + "јун", + "јул", + "авг", + "сеп", + "окт", + "нов", + "дец"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "О календару"; + +Calendar._TT["ABOUT"] = +"DHTML бирач датума/времена\n" + +"(c) dynarch.com 2002-2005 / Аутор: Mihai Bazon\n" + // don't translate this this ;-) +"За новију верзију посетите: http://www.dynarch.com/projects/calendar/\n" + +"Дистрибуира се под GNU LGPL. Погледајте http://gnu.org/licenses/lgpl.html за детаљe." + +"\n\n" + +"Избор датума:\n" + +"- Користите \xab, \xbb тастере за избор године\n" + +"- Користите " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " тастере за избор месеца\n" + +"- Задржите тастер миша на било ком тастеру изнад за бржи избор."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Избор времена:\n" + +"- Кликните на било који део времена за повећање\n" + +"- или Shift-клик за умањење\n" + +"- или кликните и превуците за бржи одабир."; + +Calendar._TT["PREV_YEAR"] = "Претходна година (задржати за мени)"; +Calendar._TT["PREV_MONTH"] = "Претходни месец (задржати за мени)"; +Calendar._TT["GO_TODAY"] = "На данашњи дан"; +Calendar._TT["NEXT_MONTH"] = "Наредни месец (задржати за мени)"; +Calendar._TT["NEXT_YEAR"] = "Наредна година (задржати за мени)"; +Calendar._TT["SEL_DATE"] = "Избор датума"; +Calendar._TT["DRAG_TO_MOVE"] = "Превуците за премештање"; +Calendar._TT["PART_TODAY"] = " (данас)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s као први дан у седмици"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "6,7"; + +Calendar._TT["CLOSE"] = "Затвори"; +Calendar._TT["TODAY"] = "Данас"; +Calendar._TT["TIME_PART"] = "(Shift-) клик или превлачење за измену вредности"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y."; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e. %b"; + +Calendar._TT["WK"] = "сед."; +Calendar._TT["TIME"] = "Време:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d75e9d9a3eafcbb243ad41e212cf5cdb308eeb31.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d75e9d9a3eafcbb243ad41e212cf5cdb308eeb31.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +en: + hello: "Hello from alfa" + plugin: "alfa" diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7746eb3e9f32d7f0749b6c62d75512963079219.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d7746eb3e9f32d7f0749b6c62d75512963079219.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class AllowNullPosition < ActiveRecord::Migration + def self.up + # removes the 'not null' constraint on position fields + change_column :issue_statuses, :position, :integer, :default => 1, :null => true + change_column :roles, :position, :integer, :default => 1, :null => true + change_column :trackers, :position, :integer, :default => 1, :null => true + change_column :boards, :position, :integer, :default => 1, :null => true + change_column :enumerations, :position, :integer, :default => 1, :null => true + end + + def self.down + # nothing to do + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7945f68bd8e0b1c181726c04ed073f7f409138b.svn-base Binary file .svn/pristine/d7/d7945f68bd8e0b1c181726c04ed073f7f409138b.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d79648acb8390e7dfe4f791129d77e634240a8ef.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d79648acb8390e7dfe4f791129d77e634240a8ef.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,287 @@ +module CodeRay +module Scanners + + # Scanner for Python. Supports Python 3. + # + # Based on pygments' PythonLexer, see + # http://dev.pocoo.org/projects/pygments/browser/pygments/lexers/agile.py. + class Python < Scanner + + register_for :python + file_extension 'py' + + KEYWORDS = [ + 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', + 'del', 'elif', 'else', 'except', 'finally', 'for', + 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', + 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', + 'nonlocal', # new in Python 3 + ] # :nodoc: + + OLD_KEYWORDS = [ + 'exec', 'print', # gone in Python 3 + ] # :nodoc: + + PREDEFINED_METHODS_AND_TYPES = %w[ + __import__ abs all any apply basestring bin bool buffer + bytearray bytes callable chr classmethod cmp coerce compile + complex delattr dict dir divmod enumerate eval execfile exit + file filter float frozenset getattr globals hasattr hash hex id + input int intern isinstance issubclass iter len list locals + long map max min next object oct open ord pow property range + raw_input reduce reload repr reversed round set setattr slice + sorted staticmethod str sum super tuple type unichr unicode + vars xrange zip + ] # :nodoc: + + PREDEFINED_EXCEPTIONS = %w[ + ArithmeticError AssertionError AttributeError + BaseException DeprecationWarning EOFError EnvironmentError + Exception FloatingPointError FutureWarning GeneratorExit IOError + ImportError ImportWarning IndentationError IndexError KeyError + KeyboardInterrupt LookupError MemoryError NameError + NotImplemented NotImplementedError OSError OverflowError + OverflowWarning PendingDeprecationWarning ReferenceError + RuntimeError RuntimeWarning StandardError StopIteration + SyntaxError SyntaxWarning SystemError SystemExit TabError + TypeError UnboundLocalError UnicodeDecodeError + UnicodeEncodeError UnicodeError UnicodeTranslateError + UnicodeWarning UserWarning ValueError Warning ZeroDivisionError + ] # :nodoc: + + PREDEFINED_VARIABLES_AND_CONSTANTS = [ + 'False', 'True', 'None', # "keywords" since Python 3 + 'self', 'Ellipsis', 'NotImplemented', + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(OLD_KEYWORDS, :old_keyword). + add(PREDEFINED_METHODS_AND_TYPES, :predefined). + add(PREDEFINED_VARIABLES_AND_CONSTANTS, :predefined_constant). + add(PREDEFINED_EXCEPTIONS, :exception) # :nodoc: + + NAME = / [^\W\d] \w* /x # :nodoc: + ESCAPE = / [abfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} | N\{[-\w ]+\} /x # :nodoc: + + OPERATOR = / + \.\.\. | # ellipsis + \.(?!\d) | # dot but not decimal point + [,;:()\[\]{}] | # simple delimiters + \/\/=? | \*\*=? | # special math + [-+*\/%&|^]=? | # ordinary math and binary logic + [~`] | # binary complement and inspection + <<=? | >>=? | [<>=]=? | != # comparison and assignment + /x # :nodoc: + + STRING_DELIMITER_REGEXP = Hash.new { |h, delimiter| + h[delimiter] = Regexp.union delimiter # :nodoc: + } + + STRING_CONTENT_REGEXP = Hash.new { |h, delimiter| + h[delimiter] = / [^\\\n]+? (?= \\ | $ | #{Regexp.escape(delimiter)} ) /x # :nodoc: + } + + DEF_NEW_STATE = WordList.new(:initial). + add(%w(def), :def_expected). + add(%w(import from), :include_expected). + add(%w(class), :class_expected) # :nodoc: + + DESCRIPTOR = / + #{NAME} + (?: \. #{NAME} )* + | \* + /x # :nodoc: + + DOCSTRING_COMING = / + [ \t]* u?r? ("""|''') + /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + string_raw = false + string_type = nil + docstring_coming = match?(/#{DOCSTRING_COMING}/o) + last_token_dot = false + unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' + from_import_state = [] + + until eos? + + if state == :string + if match = scan(STRING_DELIMITER_REGEXP[string_delimiter]) + encoder.text_token match, :delimiter + encoder.end_group string_type + string_type = nil + state = :initial + next + elsif string_delimiter.size == 3 && match = scan(/\n/) + encoder.text_token match, :content + elsif match = scan(STRING_CONTENT_REGEXP[string_delimiter]) + encoder.text_token match, :content + elsif !string_raw && match = scan(/ \\ #{ESCAPE} /ox) + encoder.text_token match, :char + elsif match = scan(/ \\ #{UNICODE_ESCAPE} /ox) + encoder.text_token match, :char + elsif match = scan(/ \\ . /x) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group string_type + string_type = nil + encoder.text_token match, :error + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder, state + end + + elsif match = scan(/ [ \t]+ | \\?\n /x) + encoder.text_token match, :space + if match == "\n" + state = :initial if state == :include_expected + docstring_coming = true if match?(/#{DOCSTRING_COMING}/o) + end + next + + elsif match = scan(/ \# [^\n]* /mx) + encoder.text_token match, :comment + next + + elsif state == :initial + + if match = scan(/#{OPERATOR}/o) + encoder.text_token match, :operator + + elsif match = scan(/(u?r?|b)?("""|"|'''|')/i) + string_delimiter = self[2] + string_type = docstring_coming ? :docstring : :string + docstring_coming = false if docstring_coming + encoder.begin_group string_type + string_raw = false + modifiers = self[1] + unless modifiers.empty? + string_raw = !!modifiers.index(?r) + encoder.text_token modifiers, :modifier + match = string_delimiter + end + state = :string + encoder.text_token match, :delimiter + + # TODO: backticks + + elsif match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + kind = IDENT_KIND[match] + # TODO: keyword arguments + kind = :ident if last_token_dot + if kind == :old_keyword + kind = check(/\(/) ? :ident : :keyword + elsif kind == :predefined && check(/ *=/) + kind = :ident + elsif kind == :keyword + state = DEF_NEW_STATE[match] + from_import_state << match.to_sym if state == :include_expected + end + encoder.text_token match, kind + + elsif match = scan(/@[a-zA-Z0-9_.]+[lL]?/) + encoder.text_token match, :decorator + + elsif match = scan(/0[xX][0-9A-Fa-f]+[lL]?/) + encoder.text_token match, :hex + + elsif match = scan(/0[bB][01]+[lL]?/) + encoder.text_token match, :binary + + elsif match = scan(/(?:\d*\.\d+|\d+\.\d*)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) + if scan(/[jJ]/) + match << matched + encoder.text_token match, :imaginary + else + encoder.text_token match, :float + end + + elsif match = scan(/0[oO][0-7]+|0[0-7]+(?![89.eE])[lL]?/) + encoder.text_token match, :octal + + elsif match = scan(/\d+([lL])?/) + if self[1] == nil && scan(/[jJ]/) + match << matched + encoder.text_token match, :imaginary + else + encoder.text_token match, :integer + end + + else + encoder.text_token getch, :error + + end + + elsif state == :def_expected + state = :initial + if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + encoder.text_token match, :method + else + next + end + + elsif state == :class_expected + state = :initial + if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + encoder.text_token match, :class + else + next + end + + elsif state == :include_expected + if match = scan(unicode ? /#{DESCRIPTOR}/uo : /#{DESCRIPTOR}/o) + if match == 'as' + encoder.text_token match, :keyword + from_import_state << :as + elsif from_import_state.first == :from && match == 'import' + encoder.text_token match, :keyword + from_import_state << :import + elsif from_import_state.last == :as + # encoder.text_token match, match[0,1][unicode ? /[[:upper:]]/u : /[[:upper:]]/] ? :class : :method + encoder.text_token match, :ident + from_import_state.pop + elsif IDENT_KIND[match] == :keyword + unscan + match = nil + state = :initial + next + else + encoder.text_token match, :include + end + elsif match = scan(/,/) + from_import_state.pop if from_import_state.last == :as + encoder.text_token match, :operator + else + from_import_state = [] + state = :initial + next + end + + else + raise_inspect 'Unknown state', encoder, state + + end + + last_token_dot = match == '.' + + end + + if state == :string + encoder.end_group string_type + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d79a58970645e3cccc641d96056ab588a943ade9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d79a58970645e3cccc641d96056ab588a943ade9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +--- +repositories_001: + project_id: 1 + url: file:///<%= Rails.root %>/tmp/test/subversion_repository + id: 10 + root_url: file:///<%= Rails.root %>/tmp/test/subversion_repository + password: "" + login: "" + type: Subversion +repositories_002: + project_id: 2 + url: svn://localhost/test + id: 11 + root_url: svn://localhost + password: "" + login: "" + type: Subversion diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7c04c454b7207407d511464a1fbd4201c5bd2a6.svn-base Binary file .svn/pristine/d7/d7c04c454b7207407d511464a1fbd4201c5bd2a6.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7cb3e22a5af1c2128900548a729a136400a6330.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d7cb3e22a5af1c2128900548a729a136400a6330.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddRepositoriesType < ActiveRecord::Migration + def self.up + add_column :repositories, :type, :string + # Set class name for existing SVN repositories + Repository.update_all "type = 'Subversion'" + end + + def self.down + remove_column :repositories, :type + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7d1d8fce0533502405732b07d6da9d875d0f83a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d7d1d8fce0533502405732b07d6da9d875d0f83a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToTokens < ActiveRecord::Migration + def self.up + add_index :tokens, :user_id + end + + def self.down + remove_index :tokens, :user_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7dec33f0cffbd1bfe34a5a4d9b65de67d349509.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d7dec33f0cffbd1bfe34a5a4d9b65de67d349509.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Enumeration < ActiveRecord::Base + generator_for :name, :start => 'Enumeration0' + generator_for :type => 'TimeEntryActivity' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d7/d7f9458e2947cc299d62ef136c44d82782d4d09b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d7/d7f9458e2947cc299d62ef136c44d82782d4d09b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +1.00 Added view template functionality +1.10 Added Chinese support +1.11 Added Japanese support +1.12 Added Korean support +1.13 Updated to fpdf.rb 1.53d. + Added makefont and fpdf_eps. + Handle \n at the beginning of a string in MultiCell. + Tried to fix clipping issue in MultiCell - still needs some work. +1.14 2006-09-26 +* Added support for @options_for_rfpdf hash for configuration: + * Added :filename option in this hash +If you're using the same settings for @options_for_rfpdf often, you might want to +put your assignment in a before_filter (perhaps overriding :filename, etc in your actions). +1.15 2009-11-20 Rails 2.* support - Thanks to Prawnto plugin for showing the way to the new TemplateHandler \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d80da60d3b09791df71ff5976cfe2c8e851b79a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d80da60d3b09791df71ff5976cfe2c8e851b79a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1615 @@ +--- +workflows_189: + new_status_id: 5 + role_id: 1 + old_status_id: 2 + id: 189 + tracker_id: 3 +workflows_001: + new_status_id: 2 + role_id: 1 + old_status_id: 1 + id: 1 + tracker_id: 1 +workflows_002: + new_status_id: 3 + role_id: 1 + old_status_id: 1 + id: 2 + tracker_id: 1 +workflows_003: + new_status_id: 4 + role_id: 1 + old_status_id: 1 + id: 3 + tracker_id: 1 +workflows_110: + new_status_id: 6 + role_id: 1 + old_status_id: 4 + id: 110 + tracker_id: 2 +workflows_004: + new_status_id: 5 + role_id: 1 + old_status_id: 1 + id: 4 + tracker_id: 1 +workflows_030: + new_status_id: 5 + role_id: 1 + old_status_id: 6 + id: 30 + tracker_id: 1 +workflows_111: + new_status_id: 1 + role_id: 1 + old_status_id: 5 + id: 111 + tracker_id: 2 +workflows_005: + new_status_id: 6 + role_id: 1 + old_status_id: 1 + id: 5 + tracker_id: 1 +workflows_031: + new_status_id: 2 + role_id: 2 + old_status_id: 1 + id: 31 + tracker_id: 1 +workflows_112: + new_status_id: 2 + role_id: 1 + old_status_id: 5 + id: 112 + tracker_id: 2 +workflows_006: + new_status_id: 1 + role_id: 1 + old_status_id: 2 + id: 6 + tracker_id: 1 +workflows_032: + new_status_id: 3 + role_id: 2 + old_status_id: 1 + id: 32 + tracker_id: 1 +workflows_113: + new_status_id: 3 + role_id: 1 + old_status_id: 5 + id: 113 + tracker_id: 2 +workflows_220: + new_status_id: 6 + role_id: 2 + old_status_id: 2 + id: 220 + tracker_id: 3 +workflows_007: + new_status_id: 3 + role_id: 1 + old_status_id: 2 + id: 7 + tracker_id: 1 +workflows_033: + new_status_id: 4 + role_id: 2 + old_status_id: 1 + id: 33 + tracker_id: 1 +workflows_060: + new_status_id: 5 + role_id: 2 + old_status_id: 6 + id: 60 + tracker_id: 1 +workflows_114: + new_status_id: 4 + role_id: 1 + old_status_id: 5 + id: 114 + tracker_id: 2 +workflows_140: + new_status_id: 6 + role_id: 2 + old_status_id: 4 + id: 140 + tracker_id: 2 +workflows_221: + new_status_id: 1 + role_id: 2 + old_status_id: 3 + id: 221 + tracker_id: 3 +workflows_008: + new_status_id: 4 + role_id: 1 + old_status_id: 2 + id: 8 + tracker_id: 1 +workflows_034: + new_status_id: 5 + role_id: 2 + old_status_id: 1 + id: 34 + tracker_id: 1 +workflows_115: + new_status_id: 6 + role_id: 1 + old_status_id: 5 + id: 115 + tracker_id: 2 +workflows_141: + new_status_id: 1 + role_id: 2 + old_status_id: 5 + id: 141 + tracker_id: 2 +workflows_222: + new_status_id: 2 + role_id: 2 + old_status_id: 3 + id: 222 + tracker_id: 3 +workflows_223: + new_status_id: 4 + role_id: 2 + old_status_id: 3 + id: 223 + tracker_id: 3 +workflows_009: + new_status_id: 5 + role_id: 1 + old_status_id: 2 + id: 9 + tracker_id: 1 +workflows_035: + new_status_id: 6 + role_id: 2 + old_status_id: 1 + id: 35 + tracker_id: 1 +workflows_061: + new_status_id: 2 + role_id: 3 + old_status_id: 1 + id: 61 + tracker_id: 1 +workflows_116: + new_status_id: 1 + role_id: 1 + old_status_id: 6 + id: 116 + tracker_id: 2 +workflows_142: + new_status_id: 2 + role_id: 2 + old_status_id: 5 + id: 142 + tracker_id: 2 +workflows_250: + new_status_id: 6 + role_id: 3 + old_status_id: 2 + id: 250 + tracker_id: 3 +workflows_224: + new_status_id: 5 + role_id: 2 + old_status_id: 3 + id: 224 + tracker_id: 3 +workflows_036: + new_status_id: 1 + role_id: 2 + old_status_id: 2 + id: 36 + tracker_id: 1 +workflows_062: + new_status_id: 3 + role_id: 3 + old_status_id: 1 + id: 62 + tracker_id: 1 +workflows_117: + new_status_id: 2 + role_id: 1 + old_status_id: 6 + id: 117 + tracker_id: 2 +workflows_143: + new_status_id: 3 + role_id: 2 + old_status_id: 5 + id: 143 + tracker_id: 2 +workflows_170: + new_status_id: 6 + role_id: 3 + old_status_id: 4 + id: 170 + tracker_id: 2 +workflows_251: + new_status_id: 1 + role_id: 3 + old_status_id: 3 + id: 251 + tracker_id: 3 +workflows_225: + new_status_id: 6 + role_id: 2 + old_status_id: 3 + id: 225 + tracker_id: 3 +workflows_063: + new_status_id: 4 + role_id: 3 + old_status_id: 1 + id: 63 + tracker_id: 1 +workflows_090: + new_status_id: 5 + role_id: 3 + old_status_id: 6 + id: 90 + tracker_id: 1 +workflows_118: + new_status_id: 3 + role_id: 1 + old_status_id: 6 + id: 118 + tracker_id: 2 +workflows_144: + new_status_id: 4 + role_id: 2 + old_status_id: 5 + id: 144 + tracker_id: 2 +workflows_252: + new_status_id: 2 + role_id: 3 + old_status_id: 3 + id: 252 + tracker_id: 3 +workflows_226: + new_status_id: 1 + role_id: 2 + old_status_id: 4 + id: 226 + tracker_id: 3 +workflows_038: + new_status_id: 4 + role_id: 2 + old_status_id: 2 + id: 38 + tracker_id: 1 +workflows_064: + new_status_id: 5 + role_id: 3 + old_status_id: 1 + id: 64 + tracker_id: 1 +workflows_091: + new_status_id: 2 + role_id: 1 + old_status_id: 1 + id: 91 + tracker_id: 2 +workflows_119: + new_status_id: 4 + role_id: 1 + old_status_id: 6 + id: 119 + tracker_id: 2 +workflows_145: + new_status_id: 6 + role_id: 2 + old_status_id: 5 + id: 145 + tracker_id: 2 +workflows_171: + new_status_id: 1 + role_id: 3 + old_status_id: 5 + id: 171 + tracker_id: 2 +workflows_253: + new_status_id: 4 + role_id: 3 + old_status_id: 3 + id: 253 + tracker_id: 3 +workflows_227: + new_status_id: 2 + role_id: 2 + old_status_id: 4 + id: 227 + tracker_id: 3 +workflows_039: + new_status_id: 5 + role_id: 2 + old_status_id: 2 + id: 39 + tracker_id: 1 +workflows_065: + new_status_id: 6 + role_id: 3 + old_status_id: 1 + id: 65 + tracker_id: 1 +workflows_092: + new_status_id: 3 + role_id: 1 + old_status_id: 1 + id: 92 + tracker_id: 2 +workflows_146: + new_status_id: 1 + role_id: 2 + old_status_id: 6 + id: 146 + tracker_id: 2 +workflows_172: + new_status_id: 2 + role_id: 3 + old_status_id: 5 + id: 172 + tracker_id: 2 +workflows_254: + new_status_id: 5 + role_id: 3 + old_status_id: 3 + id: 254 + tracker_id: 3 +workflows_228: + new_status_id: 3 + role_id: 2 + old_status_id: 4 + id: 228 + tracker_id: 3 +workflows_066: + new_status_id: 1 + role_id: 3 + old_status_id: 2 + id: 66 + tracker_id: 1 +workflows_093: + new_status_id: 4 + role_id: 1 + old_status_id: 1 + id: 93 + tracker_id: 2 +workflows_147: + new_status_id: 2 + role_id: 2 + old_status_id: 6 + id: 147 + tracker_id: 2 +workflows_173: + new_status_id: 3 + role_id: 3 + old_status_id: 5 + id: 173 + tracker_id: 2 +workflows_255: + new_status_id: 6 + role_id: 3 + old_status_id: 3 + id: 255 + tracker_id: 3 +workflows_229: + new_status_id: 5 + role_id: 2 + old_status_id: 4 + id: 229 + tracker_id: 3 +workflows_067: + new_status_id: 3 + role_id: 3 + old_status_id: 2 + id: 67 + tracker_id: 1 +workflows_148: + new_status_id: 3 + role_id: 2 + old_status_id: 6 + id: 148 + tracker_id: 2 +workflows_174: + new_status_id: 4 + role_id: 3 + old_status_id: 5 + id: 174 + tracker_id: 2 +workflows_256: + new_status_id: 1 + role_id: 3 + old_status_id: 4 + id: 256 + tracker_id: 3 +workflows_068: + new_status_id: 4 + role_id: 3 + old_status_id: 2 + id: 68 + tracker_id: 1 +workflows_094: + new_status_id: 5 + role_id: 1 + old_status_id: 1 + id: 94 + tracker_id: 2 +workflows_149: + new_status_id: 4 + role_id: 2 + old_status_id: 6 + id: 149 + tracker_id: 2 +workflows_175: + new_status_id: 6 + role_id: 3 + old_status_id: 5 + id: 175 + tracker_id: 2 +workflows_257: + new_status_id: 2 + role_id: 3 + old_status_id: 4 + id: 257 + tracker_id: 3 +workflows_069: + new_status_id: 5 + role_id: 3 + old_status_id: 2 + id: 69 + tracker_id: 1 +workflows_095: + new_status_id: 6 + role_id: 1 + old_status_id: 1 + id: 95 + tracker_id: 2 +workflows_176: + new_status_id: 1 + role_id: 3 + old_status_id: 6 + id: 176 + tracker_id: 2 +workflows_258: + new_status_id: 3 + role_id: 3 + old_status_id: 4 + id: 258 + tracker_id: 3 +workflows_096: + new_status_id: 1 + role_id: 1 + old_status_id: 2 + id: 96 + tracker_id: 2 +workflows_177: + new_status_id: 2 + role_id: 3 + old_status_id: 6 + id: 177 + tracker_id: 2 +workflows_259: + new_status_id: 5 + role_id: 3 + old_status_id: 4 + id: 259 + tracker_id: 3 +workflows_097: + new_status_id: 3 + role_id: 1 + old_status_id: 2 + id: 97 + tracker_id: 2 +workflows_178: + new_status_id: 3 + role_id: 3 + old_status_id: 6 + id: 178 + tracker_id: 2 +workflows_098: + new_status_id: 4 + role_id: 1 + old_status_id: 2 + id: 98 + tracker_id: 2 +workflows_179: + new_status_id: 4 + role_id: 3 + old_status_id: 6 + id: 179 + tracker_id: 2 +workflows_099: + new_status_id: 5 + role_id: 1 + old_status_id: 2 + id: 99 + tracker_id: 2 +workflows_100: + new_status_id: 6 + role_id: 1 + old_status_id: 2 + id: 100 + tracker_id: 2 +workflows_020: + new_status_id: 6 + role_id: 1 + old_status_id: 4 + id: 20 + tracker_id: 1 +workflows_101: + new_status_id: 1 + role_id: 1 + old_status_id: 3 + id: 101 + tracker_id: 2 +workflows_021: + new_status_id: 1 + role_id: 1 + old_status_id: 5 + id: 21 + tracker_id: 1 +workflows_102: + new_status_id: 2 + role_id: 1 + old_status_id: 3 + id: 102 + tracker_id: 2 +workflows_210: + new_status_id: 5 + role_id: 1 + old_status_id: 6 + id: 210 + tracker_id: 3 +workflows_022: + new_status_id: 2 + role_id: 1 + old_status_id: 5 + id: 22 + tracker_id: 1 +workflows_103: + new_status_id: 4 + role_id: 1 + old_status_id: 3 + id: 103 + tracker_id: 2 +workflows_023: + new_status_id: 3 + role_id: 1 + old_status_id: 5 + id: 23 + tracker_id: 1 +workflows_104: + new_status_id: 5 + role_id: 1 + old_status_id: 3 + id: 104 + tracker_id: 2 +workflows_130: + new_status_id: 6 + role_id: 2 + old_status_id: 2 + id: 130 + tracker_id: 2 +workflows_211: + new_status_id: 2 + role_id: 2 + old_status_id: 1 + id: 211 + tracker_id: 3 +workflows_024: + new_status_id: 4 + role_id: 1 + old_status_id: 5 + id: 24 + tracker_id: 1 +workflows_050: + new_status_id: 6 + role_id: 2 + old_status_id: 4 + id: 50 + tracker_id: 1 +workflows_105: + new_status_id: 6 + role_id: 1 + old_status_id: 3 + id: 105 + tracker_id: 2 +workflows_131: + new_status_id: 1 + role_id: 2 + old_status_id: 3 + id: 131 + tracker_id: 2 +workflows_212: + new_status_id: 3 + role_id: 2 + old_status_id: 1 + id: 212 + tracker_id: 3 +workflows_025: + new_status_id: 6 + role_id: 1 + old_status_id: 5 + id: 25 + tracker_id: 1 +workflows_051: + new_status_id: 1 + role_id: 2 + old_status_id: 5 + id: 51 + tracker_id: 1 +workflows_106: + new_status_id: 1 + role_id: 1 + old_status_id: 4 + id: 106 + tracker_id: 2 +workflows_132: + new_status_id: 2 + role_id: 2 + old_status_id: 3 + id: 132 + tracker_id: 2 +workflows_213: + new_status_id: 4 + role_id: 2 + old_status_id: 1 + id: 213 + tracker_id: 3 +workflows_240: + new_status_id: 5 + role_id: 2 + old_status_id: 6 + id: 240 + tracker_id: 3 +workflows_026: + new_status_id: 1 + role_id: 1 + old_status_id: 6 + id: 26 + tracker_id: 1 +workflows_052: + new_status_id: 2 + role_id: 2 + old_status_id: 5 + id: 52 + tracker_id: 1 +workflows_107: + new_status_id: 2 + role_id: 1 + old_status_id: 4 + id: 107 + tracker_id: 2 +workflows_133: + new_status_id: 4 + role_id: 2 + old_status_id: 3 + id: 133 + tracker_id: 2 +workflows_214: + new_status_id: 5 + role_id: 2 + old_status_id: 1 + id: 214 + tracker_id: 3 +workflows_241: + new_status_id: 2 + role_id: 3 + old_status_id: 1 + id: 241 + tracker_id: 3 +workflows_027: + new_status_id: 2 + role_id: 1 + old_status_id: 6 + id: 27 + tracker_id: 1 +workflows_053: + new_status_id: 3 + role_id: 2 + old_status_id: 5 + id: 53 + tracker_id: 1 +workflows_080: + new_status_id: 6 + role_id: 3 + old_status_id: 4 + id: 80 + tracker_id: 1 +workflows_108: + new_status_id: 3 + role_id: 1 + old_status_id: 4 + id: 108 + tracker_id: 2 +workflows_134: + new_status_id: 5 + role_id: 2 + old_status_id: 3 + id: 134 + tracker_id: 2 +workflows_160: + new_status_id: 6 + role_id: 3 + old_status_id: 2 + id: 160 + tracker_id: 2 +workflows_215: + new_status_id: 6 + role_id: 2 + old_status_id: 1 + id: 215 + tracker_id: 3 +workflows_242: + new_status_id: 3 + role_id: 3 + old_status_id: 1 + id: 242 + tracker_id: 3 +workflows_028: + new_status_id: 3 + role_id: 1 + old_status_id: 6 + id: 28 + tracker_id: 1 +workflows_054: + new_status_id: 4 + role_id: 2 + old_status_id: 5 + id: 54 + tracker_id: 1 +workflows_081: + new_status_id: 1 + role_id: 3 + old_status_id: 5 + id: 81 + tracker_id: 1 +workflows_109: + new_status_id: 5 + role_id: 1 + old_status_id: 4 + id: 109 + tracker_id: 2 +workflows_135: + new_status_id: 6 + role_id: 2 + old_status_id: 3 + id: 135 + tracker_id: 2 +workflows_161: + new_status_id: 1 + role_id: 3 + old_status_id: 3 + id: 161 + tracker_id: 2 +workflows_216: + new_status_id: 1 + role_id: 2 + old_status_id: 2 + id: 216 + tracker_id: 3 +workflows_243: + new_status_id: 4 + role_id: 3 + old_status_id: 1 + id: 243 + tracker_id: 3 +workflows_029: + new_status_id: 4 + role_id: 1 + old_status_id: 6 + id: 29 + tracker_id: 1 +workflows_055: + new_status_id: 6 + role_id: 2 + old_status_id: 5 + id: 55 + tracker_id: 1 +workflows_082: + new_status_id: 2 + role_id: 3 + old_status_id: 5 + id: 82 + tracker_id: 1 +workflows_136: + new_status_id: 1 + role_id: 2 + old_status_id: 4 + id: 136 + tracker_id: 2 +workflows_162: + new_status_id: 2 + role_id: 3 + old_status_id: 3 + id: 162 + tracker_id: 2 +workflows_217: + new_status_id: 3 + role_id: 2 + old_status_id: 2 + id: 217 + tracker_id: 3 +workflows_270: + new_status_id: 5 + role_id: 3 + old_status_id: 6 + id: 270 + tracker_id: 3 +workflows_244: + new_status_id: 5 + role_id: 3 + old_status_id: 1 + id: 244 + tracker_id: 3 +workflows_056: + new_status_id: 1 + role_id: 2 + old_status_id: 6 + id: 56 + tracker_id: 1 +workflows_137: + new_status_id: 2 + role_id: 2 + old_status_id: 4 + id: 137 + tracker_id: 2 +workflows_163: + new_status_id: 4 + role_id: 3 + old_status_id: 3 + id: 163 + tracker_id: 2 +workflows_190: + new_status_id: 6 + role_id: 1 + old_status_id: 2 + id: 190 + tracker_id: 3 +workflows_218: + new_status_id: 4 + role_id: 2 + old_status_id: 2 + id: 218 + tracker_id: 3 +workflows_245: + new_status_id: 6 + role_id: 3 + old_status_id: 1 + id: 245 + tracker_id: 3 +workflows_057: + new_status_id: 2 + role_id: 2 + old_status_id: 6 + id: 57 + tracker_id: 1 +workflows_083: + new_status_id: 3 + role_id: 3 + old_status_id: 5 + id: 83 + tracker_id: 1 +workflows_138: + new_status_id: 3 + role_id: 2 + old_status_id: 4 + id: 138 + tracker_id: 2 +workflows_164: + new_status_id: 5 + role_id: 3 + old_status_id: 3 + id: 164 + tracker_id: 2 +workflows_191: + new_status_id: 1 + role_id: 1 + old_status_id: 3 + id: 191 + tracker_id: 3 +workflows_219: + new_status_id: 5 + role_id: 2 + old_status_id: 2 + id: 219 + tracker_id: 3 +workflows_246: + new_status_id: 1 + role_id: 3 + old_status_id: 2 + id: 246 + tracker_id: 3 +workflows_058: + new_status_id: 3 + role_id: 2 + old_status_id: 6 + id: 58 + tracker_id: 1 +workflows_084: + new_status_id: 4 + role_id: 3 + old_status_id: 5 + id: 84 + tracker_id: 1 +workflows_139: + new_status_id: 5 + role_id: 2 + old_status_id: 4 + id: 139 + tracker_id: 2 +workflows_165: + new_status_id: 6 + role_id: 3 + old_status_id: 3 + id: 165 + tracker_id: 2 +workflows_192: + new_status_id: 2 + role_id: 1 + old_status_id: 3 + id: 192 + tracker_id: 3 +workflows_247: + new_status_id: 3 + role_id: 3 + old_status_id: 2 + id: 247 + tracker_id: 3 +workflows_059: + new_status_id: 4 + role_id: 2 + old_status_id: 6 + id: 59 + tracker_id: 1 +workflows_085: + new_status_id: 6 + role_id: 3 + old_status_id: 5 + id: 85 + tracker_id: 1 +workflows_166: + new_status_id: 1 + role_id: 3 + old_status_id: 4 + id: 166 + tracker_id: 2 +workflows_248: + new_status_id: 4 + role_id: 3 + old_status_id: 2 + id: 248 + tracker_id: 3 +workflows_086: + new_status_id: 1 + role_id: 3 + old_status_id: 6 + id: 86 + tracker_id: 1 +workflows_167: + new_status_id: 2 + role_id: 3 + old_status_id: 4 + id: 167 + tracker_id: 2 +workflows_193: + new_status_id: 4 + role_id: 1 + old_status_id: 3 + id: 193 + tracker_id: 3 +workflows_249: + new_status_id: 5 + role_id: 3 + old_status_id: 2 + id: 249 + tracker_id: 3 +workflows_087: + new_status_id: 2 + role_id: 3 + old_status_id: 6 + id: 87 + tracker_id: 1 +workflows_168: + new_status_id: 3 + role_id: 3 + old_status_id: 4 + id: 168 + tracker_id: 2 +workflows_194: + new_status_id: 5 + role_id: 1 + old_status_id: 3 + id: 194 + tracker_id: 3 +workflows_088: + new_status_id: 3 + role_id: 3 + old_status_id: 6 + id: 88 + tracker_id: 1 +workflows_169: + new_status_id: 5 + role_id: 3 + old_status_id: 4 + id: 169 + tracker_id: 2 +workflows_195: + new_status_id: 6 + role_id: 1 + old_status_id: 3 + id: 195 + tracker_id: 3 +workflows_089: + new_status_id: 4 + role_id: 3 + old_status_id: 6 + id: 89 + tracker_id: 1 +workflows_196: + new_status_id: 1 + role_id: 1 + old_status_id: 4 + id: 196 + tracker_id: 3 +workflows_197: + new_status_id: 2 + role_id: 1 + old_status_id: 4 + id: 197 + tracker_id: 3 +workflows_198: + new_status_id: 3 + role_id: 1 + old_status_id: 4 + id: 198 + tracker_id: 3 +workflows_199: + new_status_id: 5 + role_id: 1 + old_status_id: 4 + id: 199 + tracker_id: 3 +workflows_010: + new_status_id: 6 + role_id: 1 + old_status_id: 2 + id: 10 + tracker_id: 1 +workflows_011: + new_status_id: 1 + role_id: 1 + old_status_id: 3 + id: 11 + tracker_id: 1 +workflows_012: + new_status_id: 2 + role_id: 1 + old_status_id: 3 + id: 12 + tracker_id: 1 +workflows_200: + new_status_id: 6 + role_id: 1 + old_status_id: 4 + id: 200 + tracker_id: 3 +workflows_013: + new_status_id: 4 + role_id: 1 + old_status_id: 3 + id: 13 + tracker_id: 1 +workflows_120: + new_status_id: 5 + role_id: 1 + old_status_id: 6 + id: 120 + tracker_id: 2 +workflows_201: + new_status_id: 1 + role_id: 1 + old_status_id: 5 + id: 201 + tracker_id: 3 +workflows_040: + new_status_id: 6 + role_id: 2 + old_status_id: 2 + id: 40 + tracker_id: 1 +workflows_121: + new_status_id: 2 + role_id: 2 + old_status_id: 1 + id: 121 + tracker_id: 2 +workflows_202: + new_status_id: 2 + role_id: 1 + old_status_id: 5 + id: 202 + tracker_id: 3 +workflows_014: + new_status_id: 5 + role_id: 1 + old_status_id: 3 + id: 14 + tracker_id: 1 +workflows_041: + new_status_id: 1 + role_id: 2 + old_status_id: 3 + id: 41 + tracker_id: 1 +workflows_122: + new_status_id: 3 + role_id: 2 + old_status_id: 1 + id: 122 + tracker_id: 2 +workflows_203: + new_status_id: 3 + role_id: 1 + old_status_id: 5 + id: 203 + tracker_id: 3 +workflows_015: + new_status_id: 6 + role_id: 1 + old_status_id: 3 + id: 15 + tracker_id: 1 +workflows_230: + new_status_id: 6 + role_id: 2 + old_status_id: 4 + id: 230 + tracker_id: 3 +workflows_123: + new_status_id: 4 + role_id: 2 + old_status_id: 1 + id: 123 + tracker_id: 2 +workflows_204: + new_status_id: 4 + role_id: 1 + old_status_id: 5 + id: 204 + tracker_id: 3 +workflows_016: + new_status_id: 1 + role_id: 1 + old_status_id: 4 + id: 16 + tracker_id: 1 +workflows_042: + new_status_id: 2 + role_id: 2 + old_status_id: 3 + id: 42 + tracker_id: 1 +workflows_231: + new_status_id: 1 + role_id: 2 + old_status_id: 5 + id: 231 + tracker_id: 3 +workflows_070: + new_status_id: 6 + role_id: 3 + old_status_id: 2 + id: 70 + tracker_id: 1 +workflows_124: + new_status_id: 5 + role_id: 2 + old_status_id: 1 + id: 124 + tracker_id: 2 +workflows_150: + new_status_id: 5 + role_id: 2 + old_status_id: 6 + id: 150 + tracker_id: 2 +workflows_205: + new_status_id: 6 + role_id: 1 + old_status_id: 5 + id: 205 + tracker_id: 3 +workflows_017: + new_status_id: 2 + role_id: 1 + old_status_id: 4 + id: 17 + tracker_id: 1 +workflows_043: + new_status_id: 4 + role_id: 2 + old_status_id: 3 + id: 43 + tracker_id: 1 +workflows_232: + new_status_id: 2 + role_id: 2 + old_status_id: 5 + id: 232 + tracker_id: 3 +workflows_125: + new_status_id: 6 + role_id: 2 + old_status_id: 1 + id: 125 + tracker_id: 2 +workflows_151: + new_status_id: 2 + role_id: 3 + old_status_id: 1 + id: 151 + tracker_id: 2 +workflows_206: + new_status_id: 1 + role_id: 1 + old_status_id: 6 + id: 206 + tracker_id: 3 +workflows_018: + new_status_id: 3 + role_id: 1 + old_status_id: 4 + id: 18 + tracker_id: 1 +workflows_044: + new_status_id: 5 + role_id: 2 + old_status_id: 3 + id: 44 + tracker_id: 1 +workflows_071: + new_status_id: 1 + role_id: 3 + old_status_id: 3 + id: 71 + tracker_id: 1 +workflows_233: + new_status_id: 3 + role_id: 2 + old_status_id: 5 + id: 233 + tracker_id: 3 +workflows_126: + new_status_id: 1 + role_id: 2 + old_status_id: 2 + id: 126 + tracker_id: 2 +workflows_152: + new_status_id: 3 + role_id: 3 + old_status_id: 1 + id: 152 + tracker_id: 2 +workflows_207: + new_status_id: 2 + role_id: 1 + old_status_id: 6 + id: 207 + tracker_id: 3 +workflows_019: + new_status_id: 5 + role_id: 1 + old_status_id: 4 + id: 19 + tracker_id: 1 +workflows_045: + new_status_id: 6 + role_id: 2 + old_status_id: 3 + id: 45 + tracker_id: 1 +workflows_260: + new_status_id: 6 + role_id: 3 + old_status_id: 4 + id: 260 + tracker_id: 3 +workflows_234: + new_status_id: 4 + role_id: 2 + old_status_id: 5 + id: 234 + tracker_id: 3 +workflows_127: + new_status_id: 3 + role_id: 2 + old_status_id: 2 + id: 127 + tracker_id: 2 +workflows_153: + new_status_id: 4 + role_id: 3 + old_status_id: 1 + id: 153 + tracker_id: 2 +workflows_180: + new_status_id: 5 + role_id: 3 + old_status_id: 6 + id: 180 + tracker_id: 2 +workflows_208: + new_status_id: 3 + role_id: 1 + old_status_id: 6 + id: 208 + tracker_id: 3 +workflows_046: + new_status_id: 1 + role_id: 2 + old_status_id: 4 + id: 46 + tracker_id: 1 +workflows_072: + new_status_id: 2 + role_id: 3 + old_status_id: 3 + id: 72 + tracker_id: 1 +workflows_261: + new_status_id: 1 + role_id: 3 + old_status_id: 5 + id: 261 + tracker_id: 3 +workflows_235: + new_status_id: 6 + role_id: 2 + old_status_id: 5 + id: 235 + tracker_id: 3 +workflows_154: + new_status_id: 5 + role_id: 3 + old_status_id: 1 + id: 154 + tracker_id: 2 +workflows_181: + new_status_id: 2 + role_id: 1 + old_status_id: 1 + id: 181 + tracker_id: 3 +workflows_209: + new_status_id: 4 + role_id: 1 + old_status_id: 6 + id: 209 + tracker_id: 3 +workflows_047: + new_status_id: 2 + role_id: 2 + old_status_id: 4 + id: 47 + tracker_id: 1 +workflows_073: + new_status_id: 4 + role_id: 3 + old_status_id: 3 + id: 73 + tracker_id: 1 +workflows_128: + new_status_id: 4 + role_id: 2 + old_status_id: 2 + id: 128 + tracker_id: 2 +workflows_262: + new_status_id: 2 + role_id: 3 + old_status_id: 5 + id: 262 + tracker_id: 3 +workflows_236: + new_status_id: 1 + role_id: 2 + old_status_id: 6 + id: 236 + tracker_id: 3 +workflows_155: + new_status_id: 6 + role_id: 3 + old_status_id: 1 + id: 155 + tracker_id: 2 +workflows_048: + new_status_id: 3 + role_id: 2 + old_status_id: 4 + id: 48 + tracker_id: 1 +workflows_074: + new_status_id: 5 + role_id: 3 + old_status_id: 3 + id: 74 + tracker_id: 1 +workflows_129: + new_status_id: 5 + role_id: 2 + old_status_id: 2 + id: 129 + tracker_id: 2 +workflows_263: + new_status_id: 3 + role_id: 3 + old_status_id: 5 + id: 263 + tracker_id: 3 +workflows_237: + new_status_id: 2 + role_id: 2 + old_status_id: 6 + id: 237 + tracker_id: 3 +workflows_182: + new_status_id: 3 + role_id: 1 + old_status_id: 1 + id: 182 + tracker_id: 3 +workflows_049: + new_status_id: 5 + role_id: 2 + old_status_id: 4 + id: 49 + tracker_id: 1 +workflows_075: + new_status_id: 6 + role_id: 3 + old_status_id: 3 + id: 75 + tracker_id: 1 +workflows_156: + new_status_id: 1 + role_id: 3 + old_status_id: 2 + id: 156 + tracker_id: 2 +workflows_264: + new_status_id: 4 + role_id: 3 + old_status_id: 5 + id: 264 + tracker_id: 3 +workflows_238: + new_status_id: 3 + role_id: 2 + old_status_id: 6 + id: 238 + tracker_id: 3 +workflows_183: + new_status_id: 4 + role_id: 1 + old_status_id: 1 + id: 183 + tracker_id: 3 +workflows_076: + new_status_id: 1 + role_id: 3 + old_status_id: 4 + id: 76 + tracker_id: 1 +workflows_157: + new_status_id: 3 + role_id: 3 + old_status_id: 2 + id: 157 + tracker_id: 2 +workflows_265: + new_status_id: 6 + role_id: 3 + old_status_id: 5 + id: 265 + tracker_id: 3 +workflows_239: + new_status_id: 4 + role_id: 2 + old_status_id: 6 + id: 239 + tracker_id: 3 +workflows_077: + new_status_id: 2 + role_id: 3 + old_status_id: 4 + id: 77 + tracker_id: 1 +workflows_158: + new_status_id: 4 + role_id: 3 + old_status_id: 2 + id: 158 + tracker_id: 2 +workflows_184: + new_status_id: 5 + role_id: 1 + old_status_id: 1 + id: 184 + tracker_id: 3 +workflows_266: + new_status_id: 1 + role_id: 3 + old_status_id: 6 + id: 266 + tracker_id: 3 +workflows_078: + new_status_id: 3 + role_id: 3 + old_status_id: 4 + id: 78 + tracker_id: 1 +workflows_159: + new_status_id: 5 + role_id: 3 + old_status_id: 2 + id: 159 + tracker_id: 2 +workflows_185: + new_status_id: 6 + role_id: 1 + old_status_id: 1 + id: 185 + tracker_id: 3 +workflows_267: + new_status_id: 2 + role_id: 3 + old_status_id: 6 + id: 267 + tracker_id: 3 +workflows_079: + new_status_id: 5 + role_id: 3 + old_status_id: 4 + id: 79 + tracker_id: 1 +workflows_186: + new_status_id: 1 + role_id: 1 + old_status_id: 2 + id: 186 + tracker_id: 3 +workflows_268: + new_status_id: 3 + role_id: 3 + old_status_id: 6 + id: 268 + tracker_id: 3 +workflows_187: + new_status_id: 3 + role_id: 1 + old_status_id: 2 + id: 187 + tracker_id: 3 +workflows_269: + new_status_id: 4 + role_id: 3 + old_status_id: 6 + id: 269 + tracker_id: 3 +workflows_188: + new_status_id: 4 + role_id: 1 + old_status_id: 2 + id: 188 + tracker_id: 3 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d83bafa7609c4f835b3d41747d13968f00d9ddaf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d83bafa7609c4f835b3d41747d13968f00d9ddaf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,91 @@ +

    <%= l(:label_bulk_edit_selected_issues) %>

    + +
      <%= @issues.collect {|i| content_tag('li', link_to(h("#{i.tracker} ##{i.id}"), { :action => 'show', :id => i }) + h(": #{i.subject}")) }.join("\n") %>
    + +<% form_tag(:action => 'bulk_update') do %> +<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> +
    +
    +<%= l(:label_change_properties) %> + +
    +

    + + <%= select_tag('issue[tracker_id]', "" + options_from_collection_for_select(@trackers, :id, :name)) %> +

    +<% if @available_statuses.any? %> +

    + + <%= select_tag('issue[status_id]', "" + options_from_collection_for_select(@available_statuses, :id, :name)) %> +

    +<% end %> +

    + + <%= select_tag('issue[priority_id]', "" + options_from_collection_for_select(IssuePriority.active, :id, :name)) %> +

    +

    + + <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_nobody), :value => 'none') + + principals_options_for_select(@assignables)) %> +

    +<% if @project %> +

    + + <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + options_from_collection_for_select(@project.issue_categories, :id, :name)) %> +

    +<% end %> +<% #TODO: allow editing versions when multiple projects %> +<% if @project %> +

    + + <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + version_options_for_select(@project.shared_versions.open.sort)) %> +

    +<% end %> + +<% @custom_fields.each do |custom_field| %> +

    +<% end %> + +<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> +
    + +
    +<% if @project && User.current.allowed_to?(:manage_subtasks, @project) %> +

    + + <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> +

    +
    +<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %> +<% end %> +

    + + <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %> +

    +

    + + <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %> +

    +<% if Issue.use_field_for_done_ratio? %> +

    + + <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> +

    +<% end %> +
    + +
    + +
    <%= l(:field_notes) %> +<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> +<%= wikitoolbar_for 'notes' %> +
    +
    + +

    <%= submit_tag l(:button_submit) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d85492482f3555bd4792888f6e64bcab52480eca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d85492482f3555bd4792888f6e64bcab52480eca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,342 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class RepositoryMercurialTest < ActiveSupport::TestCase + fixtures :projects + + REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s + NUM_REV = 32 + CHAR_1_HEX = "\xc3\x9c" + + if File.directory?(REPOSITORY_PATH) + def setup + klass = Repository::Mercurial + assert_equal "Mercurial", klass.scm_name + assert klass.scm_adapter_class + assert_not_equal "", klass.scm_command + assert_equal true, klass.scm_available + + @project = Project.find(3) + @repository = Repository::Mercurial.create( + :project => @project, + :url => REPOSITORY_PATH, + :path_encoding => 'ISO-8859-1' + ) + assert @repository + @char_1 = CHAR_1_HEX.dup + @tag_char_1 = "tag-#{CHAR_1_HEX}-00" + @branch_char_0 = "branch-#{CHAR_1_HEX}-00" + @branch_char_1 = "branch-#{CHAR_1_HEX}-01" + if @char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + @tag_char_1.force_encoding('UTF-8') + @branch_char_0.force_encoding('UTF-8') + @branch_char_1.force_encoding('UTF-8') + end + end + + def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + assert_equal 46, @repository.changes.count + assert_equal "Initial import.\nThe repository contains 3 files.", + @repository.changesets.find_by_revision('0').comments + end + + def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + # Remove changesets with revision > 2 + @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2} + @project.reload + assert_equal 3, @repository.changesets.count + + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + end + + def test_isodatesec + # Template keyword 'isodatesec' supported in Mercurial 1.0 and higher + if @repository.scm.class.client_version_above?([1, 0]) + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + rev0_committed_on = Time.gm(2007, 12, 14, 9, 22, 52) + assert_equal @repository.changesets.find_by_revision('0').committed_on, rev0_committed_on + end + end + + def test_changeset_order_by_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + c0 = @repository.latest_changeset + c1 = @repository.changesets.find_by_revision('0') + # sorted by revision (id), not by date + assert c0.revision.to_i > c1.revision.to_i + assert c0.committed_on < c1.committed_on + end + + def test_latest_changesets + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + # with_limit + changesets = @repository.latest_changesets('', nil, 2) + assert_equal %w|31 30|, changesets.collect(&:revision) + + # with_filepath + changesets = @repository.latest_changesets( + '/sql_escape/percent%dir/percent%file1.txt', nil) + assert_equal %w|30 11 10 9|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets( + '/sql_escape/underscore_dir/understrike_file.txt', nil) + assert_equal %w|30 12 9|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets('README', nil) + assert_equal %w|31 30 28 17 8 6 1 0|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets('README','8') + assert_equal %w|8 6 1 0|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets('README','8', 2) + assert_equal %w|8 6|, changesets.collect(&:revision) + + # with_dirpath + changesets = @repository.latest_changesets('images', nil) + assert_equal %w|1 0|, changesets.collect(&:revision) + + path = 'sql_escape/percent%dir' + changesets = @repository.latest_changesets(path, nil) + assert_equal %w|30 13 11 10 9|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets(path, '11') + assert_equal %w|11 10 9|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets(path, '11', 2) + assert_equal %w|11 10|, changesets.collect(&:revision) + + path = 'sql_escape/underscore_dir' + changesets = @repository.latest_changesets(path, nil) + assert_equal %w|30 13 12 9|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets(path, '12') + assert_equal %w|12 9|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets(path, '12', 1) + assert_equal %w|12|, changesets.collect(&:revision) + + # tag + changesets = @repository.latest_changesets('', 'tag_test.00') + assert_equal %w|5 4 3 2 1 0|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets('', 'tag_test.00', 2) + assert_equal %w|5 4|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets('sources', 'tag_test.00') + assert_equal %w|4 3 2 1 0|, changesets.collect(&:revision) + + changesets = @repository.latest_changesets('sources', 'tag_test.00', 2) + assert_equal %w|4 3|, changesets.collect(&:revision) + + # named branch + if @repository.scm.class.client_version_above?([1, 6]) + changesets = @repository.latest_changesets('', @branch_char_1) + assert_equal %w|27 26|, changesets.collect(&:revision) + end + + changesets = @repository.latest_changesets("latin-1-dir/test-#{@char_1}-subdir", @branch_char_1) + assert_equal %w|27|, changesets.collect(&:revision) + end + + def test_copied_files + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + cs1 = @repository.changesets.find_by_revision('13') + assert_not_nil cs1 + c1 = cs1.changes.sort_by(&:path) + assert_equal 2, c1.size + + assert_equal 'A', c1[0].action + assert_equal '/sql_escape/percent%dir/percentfile1.txt', c1[0].path + assert_equal '/sql_escape/percent%dir/percent%file1.txt', c1[0].from_path + assert_equal '3a330eb32958', c1[0].from_revision + + assert_equal 'A', c1[1].action + assert_equal '/sql_escape/underscore_dir/understrike-file.txt', c1[1].path + assert_equal '/sql_escape/underscore_dir/understrike_file.txt', c1[1].from_path + + cs2 = @repository.changesets.find_by_revision('15') + c2 = cs2.changes + assert_equal 1, c2.size + + assert_equal 'A', c2[0].action + assert_equal '/README (1)[2]&,%.-3_4', c2[0].path + assert_equal '/README', c2[0].from_path + assert_equal '933ca60293d7', c2[0].from_revision + + cs3 = @repository.changesets.find_by_revision('19') + c3 = cs3.changes + assert_equal 1, c3.size + assert_equal 'A', c3[0].action + assert_equal "/latin-1-dir/test-#{@char_1}-1.txt", c3[0].path + assert_equal "/latin-1-dir/test-#{@char_1}.txt", c3[0].from_path + assert_equal '5d9891a1b425', c3[0].from_revision + end + + def test_find_changeset_by_name + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + %w|2 400bb8672109 400|.each do |r| + assert_equal '2', @repository.find_changeset_by_name(r).revision + end + end + + def test_find_changeset_by_invalid_name + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + assert_nil @repository.find_changeset_by_name('100000') + end + + def test_identifier + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + c = @repository.changesets.find_by_revision('2') + assert_equal c.scmid, c.identifier + end + + def test_format_identifier + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + c = @repository.changesets.find_by_revision('2') + assert_equal '2:400bb8672109', c.format_identifier + end + + def test_find_changeset_by_empty_name + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['', ' ', nil].each do |r| + assert_nil @repository.find_changeset_by_name(r) + end + end + + def test_parents + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + r1 = @repository.changesets.find_by_revision('0') + assert_equal [], r1.parents + r2 = @repository.changesets.find_by_revision('1') + assert_equal 1, r2.parents.length + assert_equal "0885933ad4f6", + r2.parents[0].identifier + r3 = @repository.changesets.find_by_revision('30') + assert_equal 2, r3.parents.length + r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort + assert_equal "3a330eb32958", r4[0] + assert_equal "a94b0528f24f", r4[1] + end + + def test_activities + c = Changeset.new(:repository => @repository, + :committed_on => Time.now, + :revision => '123', + :scmid => 'abc400bb8672', + :comments => 'test') + assert c.event_title.include?('123:abc400bb8672:') + assert_equal 'abc400bb8672', c.event_url[:rev] + end + + def test_previous + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + %w|28 3ae45e2d177d 3ae45|.each do |r1| + changeset = @repository.find_changeset_by_name(r1) + %w|27 7bbf4c738e71 7bbf|.each do |r2| + assert_equal @repository.find_changeset_by_name(r2), changeset.previous + end + end + end + + def test_previous_nil + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + %w|0 0885933ad4f6 0885|.each do |r1| + changeset = @repository.find_changeset_by_name(r1) + assert_nil changeset.previous + end + end + + def test_next + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + %w|27 7bbf4c738e71 7bbf|.each do |r2| + changeset = @repository.find_changeset_by_name(r2) + %w|28 3ae45e2d177d 3ae45|.each do |r1| + assert_equal @repository.find_changeset_by_name(r1), changeset.next + end + end + end + + def test_next_nil + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + %w|31 31eeee7395c8 31eee|.each do |r1| + changeset = @repository.find_changeset_by_name(r1) + assert_nil changeset.next + end + end + else + puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d88f7d7dcd6d97a205ee3c239720d0c553c0b965.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d88f7d7dcd6d97a205ee3c239720d0c553c0b965.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToIssueRelations < ActiveRecord::Migration + def self.up + add_index :issue_relations, :issue_from_id + add_index :issue_relations, :issue_to_id + end + + def self.down + remove_index :issue_relations, :issue_from_id + remove_index :issue_relations, :issue_to_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d8a1532f2aee52af2f226f2b6de368773957b39e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d8a1532f2aee52af2f226f2b6de368773957b39e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,85 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class EnumerationsController < ApplicationController + layout 'admin' + + before_filter :require_admin + + helper :custom_fields + include CustomFieldsHelper + + def index + end + + verify :method => :post, :only => [ :destroy, :create, :update ], + :redirect_to => { :action => :index } + + def new + begin + @enumeration = params[:type].constantize.new + rescue NameError + @enumeration = Enumeration.new + end + end + + def create + @enumeration = Enumeration.new(params[:enumeration]) + @enumeration.type = params[:enumeration][:type] + if @enumeration.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'index', :type => @enumeration.type + else + render :action => 'new' + end + end + + def edit + @enumeration = Enumeration.find(params[:id]) + end + + def update + @enumeration = Enumeration.find(params[:id]) + @enumeration.type = params[:enumeration][:type] if params[:enumeration][:type] + if @enumeration.update_attributes(params[:enumeration]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'index', :type => @enumeration.type + else + render :action => 'edit' + end + end + + def destroy + @enumeration = Enumeration.find(params[:id]) + if !@enumeration.in_use? + # No associated objects + @enumeration.destroy + redirect_to :action => 'index' + return + elsif params[:reassign_to_id] + if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id]) + @enumeration.destroy(reassign_to) + redirect_to :action => 'index' + return + end + end + @enumerations = @enumeration.class.find(:all) - [@enumeration] + #rescue + # flash[:error] = 'Unable to delete enumeration' + # redirect_to :action => 'index' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d8c453a6d14c70e120240ba0971c5bfae661a328.svn-base Binary file .svn/pristine/d8/d8c453a6d14c70e120240ba0971c5bfae661a328.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d8e9da00dfea83d984989db0c06cbb5c3633374a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d8e9da00dfea83d984989db0c06cbb5c3633374a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,103 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class WikiTest < ActiveSupport::TestCase + fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions + + def test_create + wiki = Wiki.new(:project => Project.find(2)) + assert !wiki.save + assert_equal 1, wiki.errors.count + + wiki.start_page = "Start page" + assert wiki.save + end + + def test_update + @wiki = Wiki.find(1) + @wiki.start_page = "Another start page" + assert @wiki.save + @wiki.reload + assert_equal "Another start page", @wiki.start_page + end + + def test_find_page_should_not_be_case_sensitive + wiki = Wiki.find(1) + page = WikiPage.find(2) + + assert_equal page, wiki.find_page('Another_page') + assert_equal page, wiki.find_page('Another page') + assert_equal page, wiki.find_page('ANOTHER page') + end + + def test_find_page_with_cyrillic_characters + wiki = Wiki.find(1) + page = WikiPage.find(10) + assert_equal page, wiki.find_page('Этика_менеджмента') + end + + def test_find_page_with_backslashes + wiki = Wiki.find(1) + page = WikiPage.generate!(:wiki => wiki, :title => '2009\\02\\09') + assert_equal page, wiki.find_page('2009\\02\\09') + end + + def test_find_page_without_redirect + wiki = Wiki.find(1) + page = wiki.find_page('Another_page') + assert_not_nil page + assert_equal 'Another_page', page.title + assert_equal false, wiki.page_found_with_redirect? + end + + def test_find_page_with_redirect + wiki = Wiki.find(1) + WikiRedirect.create!(:wiki => wiki, :title => 'Old_title', :redirects_to => 'Another_page') + page = wiki.find_page('Old_title') + assert_not_nil page + assert_equal 'Another_page', page.title + assert_equal true, wiki.page_found_with_redirect? + end + + def test_titleize + assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES') + assert_equal 'テスト', Wiki.titleize('テスト') + end + + context "#sidebar" do + setup do + @wiki = Wiki.find(1) + end + + should "return nil if undefined" do + assert_nil @wiki.sidebar + end + + should "return a WikiPage if defined" do + page = @wiki.pages.new(:title => 'Sidebar') + page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar') + page.save! + + assert_kind_of WikiPage, @wiki.sidebar + assert_equal 'Sidebar', @wiki.sidebar.title + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d8f06d84b93a2b76a16b71b5bb17d4815e42e0ef.svn-base Binary file .svn/pristine/d8/d8f06d84b93a2b76a16b71b5bb17d4815e42e0ef.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d8/d8ff1c547a8ab5f2037b019f178ac4f2175d8b5d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d8/d8ff1c547a8ab5f2037b019f178ac4f2175d8b5d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,201 @@ +module CodeRay + + # This module holds the Encoder class and its subclasses. + # For example, the HTML encoder is named CodeRay::Encoders::HTML + # can be found in coderay/encoders/html. + # + # Encoders also provides methods and constants for the register + # mechanism and the [] method that returns the Encoder class + # belonging to the given format. + module Encoders + + extend PluginHost + plugin_path File.dirname(__FILE__), 'encoders' + + # = Encoder + # + # The Encoder base class. Together with Scanner and + # Tokens, it forms the highlighting triad. + # + # Encoder instances take a Tokens object and do something with it. + # + # The most common Encoder is surely the HTML encoder + # (CodeRay::Encoders::HTML). It highlights the code in a colorful + # html page. + # If you want the highlighted code in a div or a span instead, + # use its subclasses Div and Span. + class Encoder + extend Plugin + plugin_host Encoders + + class << self + + # If FILE_EXTENSION isn't defined, this method returns the + # downcase class name instead. + def const_missing sym + if sym == :FILE_EXTENSION + (defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s + else + super + end + end + + # The default file extension for output file of this encoder class. + def file_extension + self::FILE_EXTENSION + end + + end + + # Subclasses are to store their default options in this constant. + DEFAULT_OPTIONS = { } + + # The options you gave the Encoder at creating. + attr_accessor :options, :scanner + + # Creates a new Encoder. + # +options+ is saved and used for all encode operations, as long + # as you don't overwrite it there by passing additional options. + # + # Encoder objects provide three encode methods: + # - encode simply takes a +code+ string and a +lang+ + # - encode_tokens expects a +tokens+ object instead + # + # Each method has an optional +options+ parameter. These are + # added to the options you passed at creation. + def initialize options = {} + @options = self.class::DEFAULT_OPTIONS.merge options + @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false + end + + # Encode a Tokens object. + def encode_tokens tokens, options = {} + options = @options.merge options + @scanner = tokens.scanner if tokens.respond_to? :scanner + setup options + compile tokens, options + finish options + end + + # Encode the given +code+ using the Scanner for +lang+. + def encode code, lang, options = {} + options = @options.merge options + @scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self) + setup options + @scanner.tokenize + finish options + end + + # You can use highlight instead of encode, if that seems + # more clear to you. + alias highlight encode + + # The default file extension for this encoder. + def file_extension + self.class.file_extension + end + + def << token + unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN + warn 'Using old Tokens#<< interface.' + @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true + end + self.token(*token) + end + + # Called with +content+ and +kind+ of the currently scanned token. + # For simple scanners, it's enougth to implement this method. + # + # By default, it calls text_token, begin_group, end_group, begin_line, + # or end_line, depending on the +content+. + def token content, kind + case content + when String + text_token content, kind + when :begin_group + begin_group kind + when :end_group + end_group kind + when :begin_line + begin_line kind + when :end_line + end_line kind + else + raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind] + end + end + + # Called for each text token ([text, kind]), where text is a String. + def text_token text, kind + @out << text + end + + # Starts a token group with the given +kind+. + def begin_group kind + end + + # Ends a token group with the given +kind+. + def end_group kind + end + + # Starts a new line token group with the given +kind+. + def begin_line kind + end + + # Ends a new line token group with the given +kind+. + def end_line kind + end + + protected + + # Called with merged options before encoding starts. + # Sets @out to an empty string. + # + # See the HTML Encoder for an example of option caching. + def setup options + @out = get_output(options) + end + + def get_output options + options[:out] || '' + end + + # Append data.to_s to the output. Returns the argument. + def output data + @out << data.to_s + data + end + + # Called with merged options after encoding starts. + # The return value is the result of encoding, typically @out. + def finish options + @out + end + + # Do the encoding. + # + # The already created +tokens+ object must be used; it must be a + # Tokens object. + def compile tokens, options = {} + content = nil + for item in tokens + if item.is_a? Array + raise ArgumentError, 'Two-element array tokens are no longer supported.' + end + if content + token content, item + content = nil + else + content = item + end + end + raise 'odd number list for Tokens' if content + end + + alias tokens compile + public :tokens + + end + + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d9/d9145aecdf1e457a5a7621d312378e695962ee1a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d9/d9145aecdf1e457a5a7621d312378e695962ee1a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,237 @@ +require 'redmine/access_control' +require 'redmine/menu_manager' +require 'redmine/activity' +require 'redmine/search' +require 'redmine/custom_field_format' +require 'redmine/mime_type' +require 'redmine/core_ext' +require 'redmine/themes' +require 'redmine/hook' +require 'redmine/plugin' +require 'redmine/notifiable' +require 'redmine/wiki_formatting' +require 'redmine/scm/base' + +begin + require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick) +rescue LoadError + # RMagick is not available +end + +if RUBY_VERSION < '1.9' + require 'faster_csv' +else + require 'csv' + FCSV = CSV +end + +Redmine::Scm::Base.add "Subversion" +Redmine::Scm::Base.add "Darcs" +Redmine::Scm::Base.add "Mercurial" +Redmine::Scm::Base.add "Cvs" +Redmine::Scm::Base.add "Bazaar" +Redmine::Scm::Base.add "Git" +Redmine::Scm::Base.add "Filesystem" + +Redmine::CustomFieldFormat.map do |fields| + fields.register Redmine::CustomFieldFormat.new('string', :label => :label_string, :order => 1) + fields.register Redmine::CustomFieldFormat.new('text', :label => :label_text, :order => 2) + fields.register Redmine::CustomFieldFormat.new('int', :label => :label_integer, :order => 3) + fields.register Redmine::CustomFieldFormat.new('float', :label => :label_float, :order => 4) + fields.register Redmine::CustomFieldFormat.new('list', :label => :label_list, :order => 5) + fields.register Redmine::CustomFieldFormat.new('date', :label => :label_date, :order => 6) + fields.register Redmine::CustomFieldFormat.new('bool', :label => :label_boolean, :order => 7) + fields.register Redmine::CustomFieldFormat.new('user', :label => :label_user, :only => %w(Issue TimeEntry Version Project), :edit_as => 'list', :order => 8) + fields.register Redmine::CustomFieldFormat.new('version', :label => :label_version, :only => %w(Issue TimeEntry Version Project), :edit_as => 'list', :order => 9) +end + +# Permissions +Redmine::AccessControl.map do |map| + map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true + map.permission :search_project, {:search => :index}, :public => true + map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin + map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member + map.permission :select_project_modules, {:projects => :modules}, :require => :member + map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member + map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member + map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member + + map.project_module :issue_tracking do |map| + # Issue categories + map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member + # Issues + map.permission :view_issues, {:issues => [:index, :show], + :auto_complete => [:issues], + :context_menus => [:issues], + :versions => [:index, :show, :status_by], + :journals => [:index, :diff], + :queries => :index, + :reports => [:issue_report, :issue_report_details]} + map.permission :add_issues, {:issues => [:new, :create, :update_form]} + map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new]} + map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]} + map.permission :manage_subtasks, {} + map.permission :set_issues_private, {} + map.permission :set_own_issues_private, {}, :require => :loggedin + map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]} + map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin + map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin + map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin + map.permission :delete_issues, {:issues => :destroy}, :require => :member + # Queries + map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member + map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin + # Watchers + map.permission :view_issue_watchers, {} + map.permission :add_issue_watchers, {:watchers => :new} + map.permission :delete_issue_watchers, {:watchers => :destroy} + end + + map.project_module :time_tracking do |map| + map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin + map.permission :view_time_entries, :timelog => [:index, :show], :time_entry_reports => [:report] + map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member + map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin + map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member + end + + map.project_module :news do |map| + map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member + map.permission :view_news, {:news => [:index, :show]}, :public => true + map.permission :comment_news, {:comments => :create} + end + + map.project_module :documents do |map| + map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin + map.permission :view_documents, :documents => [:index, :show, :download] + end + + map.project_module :files do |map| + map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin + map.permission :view_files, :files => :index, :versions => :download + end + + map.project_module :wiki do |map| + map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member + map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member + map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member + map.permission :view_wiki_pages, :wiki => [:index, :show, :special, :date_index] + map.permission :export_wiki_pages, :wiki => [:export] + map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate] + map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment] + map.permission :delete_wiki_pages_attachments, {} + map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member + end + + map.project_module :repository do |map| + map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member + map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph] + map.permission :view_changesets, :repositories => [:show, :revisions, :revision] + map.permission :commit_access, {} + end + + map.project_module :boards do |map| + map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member + map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true + map.permission :add_messages, {:messages => [:new, :reply, :quote]} + map.permission :edit_messages, {:messages => :edit}, :require => :member + map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin + map.permission :delete_messages, {:messages => :destroy}, :require => :member + map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin + end + + map.project_module :calendar do |map| + map.permission :view_calendar, :calendars => [:show, :update] + end + + map.project_module :gantt do |map| + map.permission :view_gantt, :gantts => [:show, :update] + end +end + +Redmine::MenuManager.map :top_menu do |menu| + menu.push :home, :home_path + menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? } + menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural + menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true + menu.push :help, Redmine::Info.help_url, :last => true +end + +Redmine::MenuManager.map :account_menu do |menu| + menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? } + menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? } + menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? } + menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? } +end + +Redmine::MenuManager.map :application_menu do |menu| + # Empty +end + +Redmine::MenuManager.map :admin_menu do |menu| + menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural + menu.push :users, {:controller => 'users'}, :caption => :label_user_plural + menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural + menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions + menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural + menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural, + :html => {:class => 'issue_statuses'} + menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow + menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural, + :html => {:class => 'custom_fields'} + menu.push :enumerations, {:controller => 'enumerations'} + menu.push :settings, {:controller => 'settings'} + menu.push :ldap_authentication, {:controller => 'ldap_auth_sources', :action => 'index'}, + :html => {:class => 'server_authentication'} + menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true + menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true +end + +Redmine::MenuManager.map :project_menu do |menu| + menu.push :overview, { :controller => 'projects', :action => 'show' } + menu.push :activity, { :controller => 'activities', :action => 'index' } + menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id, + :if => Proc.new { |p| p.shared_versions.any? } + menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural + menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, + :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } + menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt + menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar + menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural + menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural + menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id, + :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } + menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, + :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural + menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id + menu.push :repository, { :controller => 'repositories', :action => 'show' }, + :if => Proc.new { |p| p.repository && !p.repository.new_record? } + menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true +end + +Redmine::Activity.map do |activity| + activity.register :issues, :class_name => %w(Issue Journal) + activity.register :changesets + activity.register :news + activity.register :documents, :class_name => %w(Document Attachment) + activity.register :files, :class_name => 'Attachment' + activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false + activity.register :messages, :default => false + activity.register :time_entries, :default => false +end + +Redmine::Search.map do |search| + search.register :issues + search.register :news + search.register :documents + search.register :changesets + search.register :wiki_pages + search.register :messages + search.register :projects +end + +Redmine::WikiFormatting.map do |format| + format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper +end + +ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d9/d9545294de024a7e3a5f7c74daf7f80255e0f5d7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d9/d9545294de024a7e3a5f7c74daf7f80255e0f5d7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,215 @@ +module CodeRay + + # GZip library for writing and reading token dumps. + autoload :GZip, 'coderay/helpers/gzip' + + # = Tokens TODO: Rewrite! + # + # The Tokens class represents a list of tokens returnd from + # a Scanner. + # + # A token is not a special object, just a two-element Array + # consisting of + # * the _token_ _text_ (the original source of the token in a String) or + # a _token_ _action_ (begin_group, end_group, begin_line, end_line) + # * the _token_ _kind_ (a Symbol representing the type of the token) + # + # A token looks like this: + # + # ['# It looks like this', :comment] + # ['3.1415926', :float] + # ['$^', :error] + # + # Some scanners also yield sub-tokens, represented by special + # token actions, namely begin_group and end_group. + # + # The Ruby scanner, for example, splits "a string" into: + # + # [ + # [:begin_group, :string], + # ['"', :delimiter], + # ['a string', :content], + # ['"', :delimiter], + # [:end_group, :string] + # ] + # + # Tokens is the interface between Scanners and Encoders: + # The input is split and saved into a Tokens object. The Encoder + # then builds the output from this object. + # + # Thus, the syntax below becomes clear: + # + # CodeRay.scan('price = 2.59', :ruby).html + # # the Tokens object is here -------^ + # + # See how small it is? ;) + # + # Tokens gives you the power to handle pre-scanned code very easily: + # You can convert it to a webpage, a YAML file, or dump it into a gzip'ed string + # that you put in your DB. + # + # It also allows you to generate tokens directly (without using a scanner), + # to load them from a file, and still use any Encoder that CodeRay provides. + class Tokens < Array + + # The Scanner instance that created the tokens. + attr_accessor :scanner + + # Encode the tokens using encoder. + # + # encoder can be + # * a symbol like :html oder :statistic + # * an Encoder class + # * an Encoder object + # + # options are passed to the encoder. + def encode encoder, options = {} + encoder = Encoders[encoder].new options if encoder.respond_to? :to_sym + encoder.encode_tokens self, options + end + + # Turn tokens into a string by concatenating them. + def to_s + encode CodeRay::Encoders::Encoder.new + end + + # Redirects unknown methods to encoder calls. + # + # For example, if you call +tokens.html+, the HTML encoder + # is used to highlight the tokens. + def method_missing meth, options = {} + encode meth, options + rescue PluginHost::PluginNotFound + super + end + + # Split the tokens into parts of the given +sizes+. + # + # The result will be an Array of Tokens objects. The parts have + # the text size specified by the parameter. In addition, each + # part closes all opened tokens. This is useful to insert tokens + # betweem them. + # + # This method is used by @Scanner#tokenize@ when called with an Array + # of source strings. The Diff encoder uses it for inline highlighting. + def split_into_parts *sizes + parts = [] + opened = [] + content = nil + part = Tokens.new + part_size = 0 + size = sizes.first + i = 0 + for item in self + case content + when nil + content = item + when String + if size && part_size + content.size > size # token must be cut + if part_size < size # some part of the token goes into this part + content = content.dup # content may no be safe to change + part << content.slice!(0, size - part_size) << item + end + # close all open groups and lines... + closing = opened.reverse.flatten.map do |content_or_kind| + case content_or_kind + when :begin_group + :end_group + when :begin_line + :end_line + else + content_or_kind + end + end + part.concat closing + begin + parts << part + part = Tokens.new + size = sizes[i += 1] + end until size.nil? || size > 0 + # ...and open them again. + part.concat opened.flatten + part_size = 0 + redo unless content.empty? + else + part << content << item + part_size += content.size + end + content = nil + when Symbol + case content + when :begin_group, :begin_line + opened << [content, item] + when :end_group, :end_line + opened.pop + else + raise ArgumentError, 'Unknown token action: %p, kind = %p' % [content, item] + end + part << content << item + content = nil + else + raise ArgumentError, 'Token input junk: %p, kind = %p' % [content, item] + end + end + parts << part + parts << Tokens.new while parts.size < sizes.size + parts + end + + # Dumps the object into a String that can be saved + # in files or databases. + # + # The dump is created with Marshal.dump; + # In addition, it is gzipped using GZip.gzip. + # + # The returned String object includes Undumping + # so it has an #undump method. See Tokens.load. + # + # You can configure the level of compression, + # but the default value 7 should be what you want + # in most cases as it is a good compromise between + # speed and compression rate. + # + # See GZip module. + def dump gzip_level = 7 + dump = Marshal.dump self + dump = GZip.gzip dump, gzip_level + dump.extend Undumping + end + + # Return the actual number of tokens. + def count + size / 2 + end + + # Include this module to give an object an #undump + # method. + # + # The string returned by Tokens.dump includes Undumping. + module Undumping + # Calls Tokens.load with itself. + def undump + Tokens.load self + end + end + + # Undump the object using Marshal.load, then + # unzip it using GZip.gunzip. + # + # The result is commonly a Tokens object, but + # this is not guaranteed. + def Tokens.load dump + dump = GZip.gunzip dump + @dump = Marshal.load dump + end + + alias text_token push + def begin_group kind; push :begin_group, kind end + def end_group kind; push :end_group, kind end + def begin_line kind; push :begin_line, kind end + def end_line kind; push :end_line, kind end + alias tokens concat + + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d9/d986f7b46fa5ce6dde5f77817cfb4867911e726d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d9/d986f7b46fa5ce6dde5f77817cfb4867911e726d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,201 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 "digest/md5" + +class Attachment < ActiveRecord::Base + belongs_to :container, :polymorphic => true + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + + validates_presence_of :container, :filename, :author + validates_length_of :filename, :maximum => 255 + validates_length_of :disk_filename, :maximum => 255 + validate :validate_max_file_size + + acts_as_event :title => :filename, + :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} + + acts_as_activity_provider :type => 'files', + :permission => :view_files, + :author_key => :author_id, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + + "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"} + + acts_as_activity_provider :type => 'documents', + :permission => :view_documents, + :author_key => :author_id, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " + + "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} + + cattr_accessor :storage_path + @@storage_path = Redmine::Configuration['attachments_storage_path'] || "#{Rails.root}/files" + + before_save :files_to_final_location + after_destroy :delete_from_disk + + def validate_max_file_size + if self.filesize > Setting.attachment_max_size.to_i.kilobytes + errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes) + end + end + + def file=(incoming_file) + unless incoming_file.nil? + @temp_file = incoming_file + if @temp_file.size > 0 + self.filename = sanitize_filename(@temp_file.original_filename) + self.disk_filename = Attachment.disk_filename(filename) + self.content_type = @temp_file.content_type.to_s.chomp + if content_type.blank? + self.content_type = Redmine::MimeType.of(filename) + end + self.filesize = @temp_file.size + end + end + end + + def file + nil + end + + # Copies the temporary file to its final location + # and computes its MD5 hash + def files_to_final_location + if @temp_file && (@temp_file.size > 0) + logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") + md5 = Digest::MD5.new + File.open(diskfile, "wb") do |f| + buffer = "" + while (buffer = @temp_file.read(8192)) + f.write(buffer) + md5.update(buffer) + end + end + self.digest = md5.hexdigest + end + @temp_file = nil + # Don't save the content type if it's longer than the authorized length + if self.content_type && self.content_type.length > 255 + self.content_type = nil + end + end + + # Deletes file on the disk + def delete_from_disk + File.delete(diskfile) if !filename.blank? && File.exist?(diskfile) + end + + # Returns file's location on disk + def diskfile + "#{@@storage_path}/#{self.disk_filename}" + end + + def increment_download + increment!(:downloads) + end + + def project + container.project + end + + def visible?(user=User.current) + container.attachments_visible?(user) + end + + def deletable?(user=User.current) + container.attachments_deletable?(user) + end + + def image? + self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i + end + + def is_text? + Redmine::MimeType.is_type?('text', filename) + end + + def is_diff? + self.filename =~ /\.(patch|diff)$/i + end + + # Returns true if the file is readable + def readable? + File.readable?(diskfile) + end + + # Bulk attaches a set of files to an object + # + # Returns a Hash of the results: + # :files => array of the attached files + # :unsaved => array of the files that could not be attached + def self.attach_files(obj, attachments) + attached = [] + if attachments && attachments.is_a?(Hash) + attachments.each_value do |attachment| + file = attachment['file'] + next unless file && file.size > 0 + a = Attachment.create(:container => obj, + :file => file, + :description => attachment['description'].to_s.strip, + :author => User.current) + obj.attachments << a + + if a.new_record? + obj.unsaved_attachments ||= [] + obj.unsaved_attachments << a + else + attached << a + end + end + end + {:files => attached, :unsaved => obj.unsaved_attachments} + end + + def self.latest_attach(attachments, filename) + attachments.sort_by(&:created_on).reverse.detect { + |att| att.filename.downcase == filename.downcase + } + end + +private + def sanitize_filename(value) + # get only the filename, not the whole path + just_filename = value.gsub(/^.*(\\|\/)/, '') + + # Finally, replace invalid characters with underscore + @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') + end + + # Returns an ASCII or hashed filename + def self.disk_filename(filename) + timestamp = DateTime.now.strftime("%y%m%d%H%M%S") + ascii = '' + if filename =~ %r{^[a-zA-Z0-9_\.\-]*$} + ascii = filename + else + ascii = Digest::MD5.hexdigest(filename) + # keep the extension if any + ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$} + end + while File.exist?(File.join(@@storage_path, "#{timestamp}_#{ascii}")) + timestamp.succ! + end + "#{timestamp}_#{ascii}" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d9/d99d005bc4c66e06d02d4fede2fc4aa27612b15b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d9/d99d005bc4c66e06d02d4fede2fc4aa27612b15b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,70 @@ +
    +<%= watcher_tag(@news, User.current) %> +<%= link_to(l(:button_edit), + edit_news_path(@news), + :class => 'icon icon-edit', + :accesskey => accesskey(:edit), + :onclick => 'Element.show("edit-news"); return false;') if User.current.allowed_to?(:manage_news, @project) %> +<%= link_to(l(:button_delete), + news_path(@news), + :confirm => l(:text_are_you_sure), + :method => :delete, + :class => 'icon icon-del') if User.current.allowed_to?(:manage_news, @project) %> +
    + +

    <%= avatar(@news.author, :size => "24") %><%=h @news.title %>

    + +<% if authorize_for('news', 'edit') %> + +<% end %> + +

    <% unless @news.summary.blank? %><%=h @news.summary %>
    <% end %> +<%= authoring @news.created_on, @news.author %>

    +
    +<%= textilizable(@news.description) %> +
    +
    + +
    +

    <%= l(:label_comment_plural) %>

    +<% @comments.each do |comment| %> + <% next if comment.new_record? %> +
    + <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment}, + :confirm => l(:text_are_you_sure), :method => :delete, :title => l(:button_delete) %> +
    +

    <%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %>

    + <%= textilizable(comment.comments) %> +<% end if @comments.any? %> +
    + +<% if authorize_for 'comments', 'create' %> +

    <%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %>

    +<% form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %> +
    + <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'comment_comments' %> +
    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +<% end %> + +<% html_title @news.title -%> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/d9/d9f90dc7d55a0df3da8624b05aded4dcb90a0add.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/d9/d9f90dc7d55a0df3da8624b05aded4dcb90a0add.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class CreateWikis < ActiveRecord::Migration + def self.up + create_table :wikis do |t| + t.column :project_id, :integer, :null => false + t.column :start_page, :string, :limit => 255, :null => false + t.column :status, :integer, :default => 1, :null => false + end + add_index :wikis, :project_id, :name => :wikis_project_id + end + + def self.down + drop_table :wikis + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da0cd915314f46c50c5c7c46f0225abb1b6aeea8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da0cd915314f46c50c5c7c46f0225abb1b6aeea8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +<%= principals_check_box_tags 'user_ids[]', @users %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da30f481208d9237a3f64922ab33dc92a83a4114.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da30f481208d9237a3f64922ab33dc92a83a4114.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,119 @@ +# Don't change this file! +# Configure your app in config/environment.rb and config/environments/*.rb + +if RUBY_VERSION >= '1.9' + require 'yaml' + YAML::ENGINE.yamler = 'syck' +end + +RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) + +module Rails + class << self + def boot! + unless booted? + preinitialize + pick_boot.run + end + end + + def booted? + defined? Rails::Initializer + end + + def pick_boot + (vendor_rails? ? VendorBoot : GemBoot).new + end + + def vendor_rails? + File.exist?("#{RAILS_ROOT}/vendor/rails") + end + + def preinitialize + load(preinitializer_path) if File.exist?(preinitializer_path) + end + + def preinitializer_path + "#{RAILS_ROOT}/config/preinitializer.rb" + end + end + + class Boot + def run + load_initializer + Rails::Initializer.run(:set_load_path) + end + end + + class VendorBoot < Boot + def load_initializer + require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" + Rails::Initializer.run(:install_gem_spec_stubs) + Rails::GemDependency.add_frozen_gem_path + end + end + + class GemBoot < Boot + def load_initializer + self.class.load_rubygems + load_rails_gem + require 'initializer' + end + + def load_rails_gem + if version = self.class.gem_version + gem 'rails', version + else + gem 'rails' + end + rescue Gem::LoadError => load_error + if load_error.message =~ /Could not find RubyGem rails/ + STDERR.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) + exit 1 + else + raise + end + end + + class << self + def rubygems_version + Gem::RubyGemsVersion rescue nil + end + + def gem_version + if defined? RAILS_GEM_VERSION + RAILS_GEM_VERSION + elsif ENV.include?('RAILS_GEM_VERSION') + ENV['RAILS_GEM_VERSION'] + else + parse_gem_version(read_environment_rb) + end + end + + def load_rubygems + min_version = '1.3.2' + require 'rubygems' + unless rubygems_version >= min_version + $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.) + exit 1 + end + + rescue LoadError + $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org) + exit 1 + end + + def parse_gem_version(text) + $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/ + end + + private + def read_environment_rb + File.read("#{RAILS_ROOT}/config/environment.rb") + end + end + end +end + +# All that for this: +Rails.boot! diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da537956704422014aaac51b3eca6fc3565a3bb2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da537956704422014aaac51b3eca6fc3565a3bb2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +
    +<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %> +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %> +<%= watcher_tag(@issue, User.current) %> +<%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %> +<%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %> +<%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %> +<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => issues_destroy_confirmation_message(@issue), :method => :post, :class => 'icon icon-del' %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da5d2841572970a1cf259b4374a2ceda5138a513.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da5d2841572970a1cf259b4374a2ceda5138a513.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,341 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssuesController < ApplicationController + menu_item :new_issue, :only => [:new, :create] + default_search_scope :issues + + before_filter :find_issue, :only => [:show, :edit, :update] + before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy] + before_filter :check_project_uniqueness, :only => [:move, :perform_move] + before_filter :find_project, :only => [:new, :create] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => [:index] + before_filter :check_for_default_issue_status, :only => [:new, :create] + before_filter :build_new_issue_from_params, :only => [:new, :create] + accept_rss_auth :index, :show + accept_api_auth :index, :show, :create, :update, :destroy + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :journals + helper :projects + include ProjectsHelper + helper :custom_fields + include CustomFieldsHelper + helper :issue_relations + include IssueRelationsHelper + helper :watchers + include WatchersHelper + helper :attachments + include AttachmentsHelper + helper :queries + include QueriesHelper + helper :repositories + include RepositoriesHelper + helper :sort + include SortHelper + include IssuesHelper + helper :timelog + helper :gantt + include Redmine::Export::PDF + + verify :method => [:post, :delete], + :only => :destroy, + :render => { :nothing => true, :status => :method_not_allowed } + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed } + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + + def index + retrieve_query + sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns) + + if @query.valid? + case params[:format] + when 'csv', 'pdf' + @limit = Setting.issues_export_limit.to_i + when 'atom' + @limit = Setting.feeds_limit.to_i + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @issue_count = @query.issue_count + @issue_pages = Paginator.new self, @issue_count, @limit, params['page'] + @offset ||= @issue_pages.current.offset + @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], + :order => sort_clause, + :offset => @offset, + :limit => @limit) + @issue_count_by_group = @query.issue_count_by_group + + respond_to do |format| + format.html { render :template => 'issues/index', :layout => !request.xhr? } + format.api { + Issue.load_relations(@issues) if include_in_api_response?('relations') + } + format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } + format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') } + format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') } + end + else + respond_to do |format| + format.html { render(:template => 'issues/index', :layout => !request.xhr?) } + format.any(:atom, :csv, :pdf) { render(:nothing => true) } + format.api { render_validation_errors(@query) } + end + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def show + @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") + @journals.each_with_index {|j,i| j.indice = i+1} + @journals.reverse! if User.current.wants_comments_in_reverse_order? + + if User.current.allowed_to?(:view_changesets, @project) + @changesets = @issue.changesets.visible.all + @changesets.reverse! if User.current.wants_comments_in_reverse_order? + end + + @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @priorities = IssuePriority.active + @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + respond_to do |format| + format.html { render :template => 'issues/show' } + format.api + format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' } + format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } + end + end + + # Add a new issue + # The new issue will be created from an existing one if copy_from parameter is given + def new + respond_to do |format| + format.html { render :action => 'new', :layout => !request.xhr? } + format.js { render :partial => 'attributes' } + end + end + + def create + call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) + if @issue.save + attachments = Attachment.attach_files(@issue, params[:attachments]) + call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) + respond_to do |format| + format.html { + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_issue_successful_create, :id => "##{@issue.id}") + redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : + { :action => 'show', :id => @issue }) + } + format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) } + end + return + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@issue) } + end + end + end + + def edit + update_issue_from_params + + @journal = @issue.current_journal + + respond_to do |format| + format.html { } + format.xml { } + end + end + + def update + update_issue_from_params + + if @issue.save_issue_with_child_records(params, @time_entry) + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? + + respond_to do |format| + format.html { redirect_back_or_default({:action => 'show', :id => @issue}) } + format.api { head :ok } + end + else + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? + @journal = @issue.current_journal + + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@issue) } + end + end + end + + # Bulk edit a set of issues + def bulk_edit + @issues.sort! + @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w} + @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c} + @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a} + @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t} + end + + def bulk_update + @issues.sort! + attributes = parse_params_for_bulk_issue_attributes(params) + + unsaved_issue_ids = [] + @issues.each do |issue| + issue.reload + journal = issue.init_journal(User.current, params[:notes]) + issue.safe_attributes = attributes + call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) + unless issue.save + # Keep unsaved issue ids to display them in flash error + unsaved_issue_ids << issue.id + end + end + set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) + redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project}) + end + + def destroy + @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f + if @hours > 0 + case params[:todo] + when 'destroy' + # nothing to do + when 'nullify' + TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues]) + when 'reassign' + reassign_to = @project.issues.find_by_id(params[:reassign_to_id]) + if reassign_to.nil? + flash.now[:error] = l(:error_issue_not_found_in_project) + return + else + TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues]) + end + else + # display the destroy form if it's a user request + return unless api_request? + end + end + @issues.each do |issue| + begin + issue.reload.destroy + rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists + # nothing to do, issue was already deleted (eg. by a parent) + end + end + respond_to do |format| + format.html { redirect_back_or_default(:action => 'index', :project_id => @project) } + format.api { head :ok } + end + end + +private + def find_issue + # Issue.visible.find(...) can not be used to redirect user to the login form + # if the issue actually exists but requires authentication + @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) + unless @issue.visible? + deny_access + return + end + @project = @issue.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_project + project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Used by #edit and #update to set some common instance variables + # from the params + # TODO: Refactor, not everything in here is needed by #edit + def update_issue_from_params + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + @priorities = IssuePriority.active + @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + @time_entry.attributes = params[:time_entry] + + @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil) + @issue.init_journal(User.current, @notes) + @issue.safe_attributes = params[:issue] + end + + # TODO: Refactor, lots of extra code in here + # TODO: Changing tracker on an existing issue should not trigger this + def build_new_issue_from_params + if params[:id].blank? + @issue = Issue.new + @issue.copy_from(params[:copy_from]) if params[:copy_from] + @issue.project = @project + else + @issue = @project.issues.visible.find(params[:id]) + end + + @issue.project = @project + @issue.author = User.current + # Tracker must be set before custom field values + @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) + if @issue.tracker.nil? + render_error l(:error_no_tracker_in_project) + return false + end + @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date? + if params[:issue].is_a?(Hash) + @issue.safe_attributes = params[:issue] + if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record? + @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] + end + end + @priorities = IssuePriority.active + @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) + end + + def check_for_default_issue_status + if IssueStatus.default.nil? + render_error l(:error_no_default_issue_status) + return false + end + end + + def parse_params_for_bulk_issue_attributes(params) + attributes = (params[:issue] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] + attributes + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da67ec83b6dba38455d4e59b22d0d5a6342a9fd9.svn-base Binary file .svn/pristine/da/da67ec83b6dba38455d4e59b22d0d5a6342a9fd9.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da7369cd8f5f0b2ca40bf09589238bd7f30ff840.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da7369cd8f5f0b2ca40bf09589238bd7f30ff840.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar HE language +// Author: Saggi Mizrahi +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("ראשון", + "שני", + "שלישי", + "רביעי", + "חמישי", + "שישי", + "שבת", + "ראשון"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("א", + "ב", + "ג", + "ד", + "ה", + "ו", + "ש", + "א"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("ינואר", + "פברואר", + "מרץ", + "אפריל", + "מאי", + "יוני", + "יולי", + "אוגוסט", + "ספטמבר", + "אוקטובר", + "נובמבר", + "דצמבר"); + +// short month names +Calendar._SMN = new Array +("ינו'", + "פבו'", + "מרץ", + "אפר'", + "מאי", + "יונ'", + "יול'", + "אוג'", + "ספט'", + "אוקט'", + "נוב'", + "דצמ'"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "אודות לוח השנה"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "שנה קודמת (החזק לתפריט)"; +Calendar._TT["PREV_MONTH"] = "חודש קודם (החזק לתפריט)"; +Calendar._TT["GO_TODAY"] = "לך להיום"; +Calendar._TT["NEXT_MONTH"] = "חודש הבא (החזק לתפריט)"; +Calendar._TT["NEXT_YEAR"] = "שנה הבאה (החזק לתפריט)"; +Calendar._TT["SEL_DATE"] = "בחר תאריך"; +Calendar._TT["DRAG_TO_MOVE"] = "משוך כדי להזיז"; +Calendar._TT["PART_TODAY"] = " (היום)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "הצג %s קודם"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "5,6"; + +Calendar._TT["CLOSE"] = "סגור"; +Calendar._TT["TODAY"] = "היום"; +Calendar._TT["TIME_PART"] = "(Shift-)לחץ או משוך כדי לשנות את הערך"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "זמן:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da77bc020b3601bbe557cb2b9152c1bf47512dd3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da77bc020b3601bbe557cb2b9152c1bf47512dd3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +

    <%=h @issue.tracker %> #<%= @issue.id %>

    +

    <%= authoring @journal.created_on, @journal.user, :label => :label_updated_time_by %>

    + +
    +<%= simple_format_without_paragraph @diff.to_html %> +
    + +

    <%= link_to l(:button_back), issue_path(@issue), :onclick => 'history.back(); return false;' %>

    + +<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/da90b715e93c3c141bb44fb1b5742be6981e034a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/da90b715e93c3c141bb44fb1b5742be6981e034a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,973 @@ +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(Object.isUndefined(Effect)) + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || { }); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if(Object.isArray(containment)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var drop, affected = []; + + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) + drop = Droppables.findDeepestChild(affected); + + if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); + if (drop) { + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + if (drop != this.last_active) Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) { + this.last_active.onDrop(element, this.last_active.element, event); + return true; + } + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +}; + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +}; + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create({ + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || { }); + + this.element = $(element); + + if(options.handle && Object.isString(options.handle)) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(!Object.isUndefined(Draggable._dragging[this.element]) && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if((tag_name = src.tagName.toUpperCase()) && ( + tag_name=='INPUT' || + tag_name=='SELECT' || + tag_name=='OPTION' || + tag_name=='BUTTON' || + tag_name=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + if(!this.delta) + this.delta = this.currentDelta(); + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); + if (!this._originallyAbsolute) + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + + if(!this.options.quiet){ + Position.prepare(); + Droppables.show(pointer, this.element); + } + + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(Prototype.Browser.WebKit) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.quiet){ + Position.prepare(); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + Droppables.show(pointer, this.element); + } + + if(this.options.ghosting) { + if (!this._originallyAbsolute) + Position.relativize(this.element); + delete this._originallyAbsolute; + Element.remove(this._clone); + this._clone = null; + } + + var dropped = false; + if(success) { + dropped = Droppables.fire(event, this.element); + if (!dropped) dropped = false; + } + if(dropped && this.options.onDropped) this.options.onDropped(this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && Object.isFunction(revert)) revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + if (dropped == 0 || revert != 'failure') + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(Object.isFunction(this.options.snap)) { + p = this.options.snap(p[0],p[1],this); + } else { + if(Object.isArray(this.options.snap)) { + p = p.map( function(v, i) { + return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)); + } else { + p = p.map( function(v) { + return (v/this.options.snap).round()*this.options.snap }.bind(this)); + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight; + } + } + return { top: T, left: L, width: W, height: H }; + } +}); + +Draggable._dragging = { }; + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create({ + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +}); + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: { }, + + _findRootElement: function(element) { + while (element.tagName.toUpperCase() != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + element = $(element); + var s = Sortable.sortables[element.id]; + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + + // these take arrays of elements or ids and can be + // used for better initialization performance + elements: false, + handles: false, + + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || { }); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + quiet: options.quiet, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + }; + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + }; + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (options.elements || this.findElements(element, options) || []).each( function(e,i) { + var handle = options.handles ? $(options.handles[i]) : + (options.handle ? $(e).select('.' + options.handle)[0] : e); + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + }; + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child); + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || { }); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + }; + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || { }); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || { }); + + var nodeMap = { }; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || { }); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +}; + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +}; + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +}; + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +}; \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/da/daec043929c9800ec1c86a096d250b8584050bd6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/da/daec043929c9800ec1c86a096d250b8584050bd6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,79 @@ +module Redmine + module I18n + def self.included(base) + base.extend Redmine::I18n + end + + def l(*args) + case args.size + when 1 + ::I18n.t(*args) + when 2 + if args.last.is_a?(Hash) + ::I18n.t(*args) + elsif args.last.is_a?(String) + ::I18n.t(args.first, :value => args.last) + else + ::I18n.t(args.first, :count => args.last) + end + else + raise "Translation string with multiple values: #{args.first}" + end + end + + def l_or_humanize(s, options={}) + k = "#{options[:prefix]}#{s}".to_sym + ::I18n.t(k, :default => s.to_s.humanize) + end + + def l_hours(hours) + hours = hours.to_f + l((hours < 2.0 ? :label_f_hour : :label_f_hour_plural), :value => ("%.2f" % hours.to_f)) + end + + def ll(lang, str, value=nil) + ::I18n.t(str.to_s, :value => value, :locale => lang.to_s.gsub(%r{(.+)\-(.+)$}) { "#{$1}-#{$2.upcase}" }) + end + + def format_date(date) + return nil unless date + Setting.date_format.blank? ? ::I18n.l(date.to_date) : date.strftime(Setting.date_format) + end + + def format_time(time, include_date = true) + return nil unless time + time = time.to_time if time.is_a?(String) + zone = User.current.time_zone + local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time) + (include_date ? "#{format_date(local)} " : "") + + (Setting.time_format.blank? ? ::I18n.l(local, :format => :time) : local.strftime(Setting.time_format)) + end + + def day_name(day) + ::I18n.t('date.day_names')[day % 7] + end + + def month_name(month) + ::I18n.t('date.month_names')[month] + end + + def valid_languages + @@valid_languages ||= Dir.glob(File.join(Rails.root, 'config', 'locales', '*.yml')).collect {|f| File.basename(f).split('.').first}.collect(&:to_sym) + end + + def find_language(lang) + @@languages_lookup = valid_languages.inject({}) {|k, v| k[v.to_s.downcase] = v; k } + @@languages_lookup[lang.to_s.downcase] + end + + def set_language_if_valid(lang) + if l = find_language(lang) + ::I18n.locale = l + end + end + + def current_language + ::I18n.locale + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/db18df3b1c31182d33c399059e03e424e46e11b8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/db18df3b1c31182d33c399059e03e424e46e11b8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +// jsToolBar EU language +// Author: Ales Zabala Alava (Shagi), +// 2010-01-25 +// Distributed under the same terms as the jsToolBar itself. +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Lodia'; +jsToolBar.strings['Italic'] = 'Etzana'; +jsToolBar.strings['Underline'] = 'Azpimarra'; +jsToolBar.strings['Deleted'] = 'Ezabatuta'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = '1 Goiburua'; +jsToolBar.strings['Heading 2'] = '2 Goiburua'; +jsToolBar.strings['Heading 3'] = '3 Goiburua'; +jsToolBar.strings['Unordered list'] = 'Ordenatu gabeko zerrenda'; +jsToolBar.strings['Ordered list'] = 'Ordenatutako zerrenda'; +jsToolBar.strings['Quote'] = 'Aipamena'; +jsToolBar.strings['Unquote'] = 'Aipamena kendu'; +jsToolBar.strings['Preformatted text'] = 'Aurrez formateatutako testua'; +jsToolBar.strings['Wiki link'] = 'Wiki orri baterako esteka'; +jsToolBar.strings['Image'] = 'Irudia'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/db759cd3ab8cd175fe41bbaf241b7a49ab7f0619.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/db759cd3ab8cd175fe41bbaf241b7a49ab7f0619.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeAuthSourcesAccountLimit < ActiveRecord::Migration + def self.up + change_column :auth_sources, :account, :string, :limit => nil + end + + def self.down + change_column :auth_sources, :account, :string, :limit => 60 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/db9d5de4e29d812e502d8ee4c3a6a7311df17b3f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/db9d5de4e29d812e502d8ee4c3a6a7311df17b3f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,108 @@ +# $Id: dataset.rb 78 2006-04-26 02:57:34Z blackhedd $ +# +# +#---------------------------------------------------------------------------- +# +# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. +# +# Gmail: garbagecat10 +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +#--------------------------------------------------------------------------- +# +# + + + + +module Net +class LDAP + +class Dataset < Hash + + attr_reader :comments + + + def Dataset::read_ldif io + ds = Dataset.new + + line = io.gets && chomp + dn = nil + + while line + io.gets and chomp + if $_ =~ /^[\s]+/ + line << " " << $' + else + nextline = $_ + + if line =~ /^\#/ + ds.comments << line + elsif line =~ /^dn:[\s]*/i + dn = $' + ds[dn] = Hash.new {|k,v| k[v] = []} + elsif line.length == 0 + dn = nil + elsif line =~ /^([^:]+):([\:]?)[\s]*/ + # $1 is the attribute name + # $2 is a colon iff the attr-value is base-64 encoded + # $' is the attr-value + # Avoid the Base64 class because not all Ruby versions have it. + attrvalue = ($2 == ":") ? $'.unpack('m').shift : $' + ds[dn][$1.downcase.intern] << attrvalue + end + + line = nextline + end + end + + ds + end + + + def initialize + @comments = [] + end + + + def to_ldif + ary = [] + ary += (@comments || []) + + keys.sort.each {|dn| + ary << "dn: #{dn}" + + self[dn].keys.map {|sym| sym.to_s}.sort.each {|attr| + self[dn][attr.intern].each {|val| + ary << "#{attr}: #{val}" + } + } + + ary << "" + } + + block_given? and ary.each {|line| yield line} + + ary + end + + +end # Dataset + +end # LDAP +end # Net + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/db9e904490ce0fdbeaf9fc8c27e1c7ab2c4b6c9a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/db9e904490ce0fdbeaf9fc8c27e1c7ab2c4b6c9a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,189 @@ +module CodeRay +module Scanners + + # Scanner for C. + class C < Scanner + + register_for :c + file_extension 'c' + + KEYWORDS = [ + 'asm', 'break', 'case', 'continue', 'default', 'do', + 'else', 'enum', 'for', 'goto', 'if', 'return', + 'sizeof', 'struct', 'switch', 'typedef', 'union', 'while', + 'restrict', # added in C99 + ] # :nodoc: + + PREDEFINED_TYPES = [ + 'int', 'long', 'short', 'char', + 'signed', 'unsigned', 'float', 'double', + 'bool', 'complex', # added in C99 + ] # :nodoc: + + PREDEFINED_CONSTANTS = [ + 'EOF', 'NULL', + 'true', 'false', # added in C99 + ] # :nodoc: + DIRECTIVES = [ + 'auto', 'extern', 'register', 'static', 'void', + 'const', 'volatile', # added in C89 + 'inline', # added in C99 + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_TYPES, :predefined_type). + add(DIRECTIVES, :directive). + add(PREDEFINED_CONSTANTS, :predefined_constant) # :nodoc: + + ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + label_expected = true + case_expected = false + label_expected_before_preproc_line = nil + in_preproc_line = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + if in_preproc_line && match != "\\\n" && match.index(?\n) + in_preproc_line = false + label_expected = label_expected_before_preproc_line + end + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + + elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) + label_expected = match =~ /[;\{\}]/ + if case_expected + label_expected = true if match == ':' + case_expected = false + end + encoder.text_token match, :operator + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + kind = IDENT_KIND[match] + if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) + kind = :label + match << matched + else + label_expected = false + if kind == :keyword + case match + when 'case', 'default' + case_expected = true + end + end + end + encoder.text_token match, kind + + elsif match = scan(/L?"/) + encoder.begin_group :string + if match[0] == ?L + encoder.text_token 'L', :modifier + match = '"' + end + encoder.text_token match, :delimiter + state = :string + + elsif match = scan(/ \# \s* if \s* 0 /x) + match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? + encoder.text_token match, :comment + + elsif match = scan(/#[ \t]*(\w*)/) + encoder.text_token match, :preprocessor + in_preproc_line = true + label_expected_before_preproc_line = label_expected + state = :include_expected if self[1] == 'include' + + elsif match = scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) + label_expected = false + encoder.text_token match, :char + + elsif match = scan(/\$/) + encoder.text_token match, :ident + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + label_expected = false + encoder.text_token match, :hex + + elsif match = scan(/(?:0[0-7]+)(?![89.eEfF])/) + label_expected = false + encoder.text_token match, :octal + + elsif match = scan(/(?:\d+)(?![.eEfF])L?L?/) + label_expected = false + encoder.text_token match, :integer + + elsif match = scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + label_expected = false + encoder.text_token match, :float + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(/[^\\\n"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + label_expected = false + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ | $ /x) + encoder.end_group :string + encoder.text_token match, :error + state = :initial + label_expected = false + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + when :include_expected + if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) + encoder.text_token match, :include + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + state = :initial if match.index ?\n + + else + state = :initial + + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if state == :string + encoder.end_group :string + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/dbade5d8da663a5733ac92615c38fec3343906d0.svn-base Binary file .svn/pristine/db/dbade5d8da663a5733ac92615c38fec3343906d0.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/dbb1cd10e4a0f1e628733be53e77306d7e9d3f4a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/dbb1cd10e4a0f1e628733be53e77306d7e9d3f4a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddIndexOnChangesetsScmid < ActiveRecord::Migration + def self.up + add_index :changesets, [:repository_id, :scmid], :name => :changesets_repos_scmid + end + + def self.down + remove_index :changesets, :name => :changesets_repos_scmid + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/dbbe02344b02394382c3153c6c0b7b7ba7f46fe0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/dbbe02344b02394382c3153c6c0b7b7ba7f46fe0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +Event.observe(window,'load',function() { + /* + If we're viewing a tag or branch, don't display it in the + revision box + */ + var branch_selected = $('branch') && $('rev').getValue() == $('branch').getValue(); + var tag_selected = $('tag') && $('rev').getValue() == $('tag').getValue(); + if (branch_selected || tag_selected) { + $('rev').setValue(''); + } + + /* + Copy the branch/tag value into the revision box, then disable + the dropdowns before submitting the form + */ + $$('#branch,#tag').each(function(e) { + e.observe('change',function(e) { + $('rev').setValue(e.element().getValue()); + $$('#branch,#tag').invoke('disable'); + e.element().parentNode.submit(); + $$('#branch,#tag').invoke('enable'); + }); + }); + + /* + Disable the branch/tag dropdowns before submitting the revision form + */ + $('rev').observe('keydown', function(e) { + if (e.keyCode == 13) { + $$('#branch,#tag').invoke('disable'); + e.element().parentNode.submit(); + $$('#branch,#tag').invoke('enable'); + } + }); +}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/dbc46038d6ca88355c685476f996976a5a2b5d23.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/dbc46038d6ca88355c685476f996976a5a2b5d23.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/lib/acts_as_attachable' +ActiveRecord::Base.send(:include, Redmine::Acts::Attachable) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/db/dbd27b2d43c3f418a10ceae5e4a72e0cd0b0a99c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/db/dbd27b2d43c3f418a10ceae5e4a72e0cd0b0a99c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +#-- +# Copyright (c) 2004-2006 David Heinemeier Hansson +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#++ + +require 'pagination' +require 'pagination_helper' + +ActionController::Base.class_eval do + include ActionController::Pagination +end + +ActionView::Base.class_eval do + include ActionView::Helpers::PaginationHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dc0b4be494ea301b961f3a7c8e25f53fd78f87cd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dc0b4be494ea301b961f3a7c8e25f53fd78f87cd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,200 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of DotClear. + * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All + * rights reserved. + * + * DotClear 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. + * + * DotClear 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 DotClear; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***** END LICENSE BLOCK ***** +*/ + +/* Modified by JP LANG for textile formatting */ + +// strong +jsToolBar.prototype.elements.strong = { + type: 'button', + title: 'Strong', + fn: { + wiki: function() { this.singleTag('*') } + } +} + +// em +jsToolBar.prototype.elements.em = { + type: 'button', + title: 'Italic', + fn: { + wiki: function() { this.singleTag("_") } + } +} + +// ins +jsToolBar.prototype.elements.ins = { + type: 'button', + title: 'Underline', + fn: { + wiki: function() { this.singleTag('+') } + } +} + +// del +jsToolBar.prototype.elements.del = { + type: 'button', + title: 'Deleted', + fn: { + wiki: function() { this.singleTag('-') } + } +} + +// code +jsToolBar.prototype.elements.code = { + type: 'button', + title: 'Code', + fn: { + wiki: function() { this.singleTag('@') } + } +} + +// spacer +jsToolBar.prototype.elements.space1 = {type: 'space'} + +// headings +jsToolBar.prototype.elements.h1 = { + type: 'button', + title: 'Heading 1', + fn: { + wiki: function() { + this.encloseLineSelection('h1. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} +jsToolBar.prototype.elements.h2 = { + type: 'button', + title: 'Heading 2', + fn: { + wiki: function() { + this.encloseLineSelection('h2. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} +jsToolBar.prototype.elements.h3 = { + type: 'button', + title: 'Heading 3', + fn: { + wiki: function() { + this.encloseLineSelection('h3. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} + +// spacer +jsToolBar.prototype.elements.space2 = {type: 'space'} + +// ul +jsToolBar.prototype.elements.ul = { + type: 'button', + title: 'Unordered list', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^)[#-]?\s*/g,"$1* "); + }); + } + } +} + +// ol +jsToolBar.prototype.elements.ol = { + type: 'button', + title: 'Ordered list', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^)[*-]?\s*/g,"$1# "); + }); + } + } +} + +// spacer +jsToolBar.prototype.elements.space3 = {type: 'space'} + +// bq +jsToolBar.prototype.elements.bq = { + type: 'button', + title: 'Quote', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^) *([^\n]*)/g,"$1> $2"); + }); + } + } +} + +// unbq +jsToolBar.prototype.elements.unbq = { + type: 'button', + title: 'Unquote', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2"); + }); + } + } +} + +// pre +jsToolBar.prototype.elements.pre = { + type: 'button', + title: 'Preformatted text', + fn: { + wiki: function() { this.encloseLineSelection('
    \n', '\n
    ') } + } +} + +// spacer +jsToolBar.prototype.elements.space4 = {type: 'space'} + +// wiki page +jsToolBar.prototype.elements.link = { + type: 'button', + title: 'Wiki link', + fn: { + wiki: function() { this.encloseSelection("[[", "]]") } + } +} +// image +jsToolBar.prototype.elements.img = { + type: 'button', + title: 'Image', + fn: { + wiki: function() { this.encloseSelection("!", "!") } + } +} diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dc231e8a382bad8f57c4f1f8d58c2fe3cb3a5e5d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dc231e8a382bad8f57c4f1f8d58c2fe3cb3a5e5d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,36 @@ +Installing gems for testing +=========================== + +Run `rake gems RAILS_ENV=test` to list the required gems. Run +`rake gems:install RAILS_ENV=test` to install any missing gems. + +Running Tests +============= + +Run `rake --tasks test` to see available tests. +`rake test` will run the entire testsuite. +You can run `ruby test/unit/issue_test.rb` for an each test. + +Before running tests, you need to configure both development +and test databases. + +Creating test repositories +=================== + +Redmine supports a wide array of different version control systems. +To test the support, a test repository needs to be created for each of those. + +Run `rake --tasks test:scm:setup` for a list of available test-repositories or +run `rake test:scm:setup:all` to set up all of them + +Creating a test ldap database +============================= + +Redmine supports using LDAP for user authentications. To test LDAP +with Redmine, load the LDAP export from test/fixtures/ldap/test-ldap.ldif +into a testing LDAP server. Test that the ldap server can be accessed +at 127.0.0.1 on port 389. + +Setting up the test ldap server is beyond the scope of this documentation. +The OpenLDAP project provides a simple LDAP implementation that should work +good as a test server. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dc4adf759d88394a5073997f3ad66185b26b8013.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dc4adf759d88394a5073997f3ad66185b26b8013.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar HR language +// Author: Helix d.o.o., +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Nedjelja", + "Ponedjeljak", + "Utorak", + "Srijeda", + "Cetvrtak", + "Petak", + "Subota", + "Nedjelja"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ned", + "Pon", + "Uto", + "Sri", + "Cet", + "Pet", + "Sub", + "Ned"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Sijecanj", + "Veljaca", + "Ožujak", + "Travanj", + "Svibanj", + "Lipanj", + "Srpanj", + "Kolovoz", + "Rujan", + "Listopad", + "Studeni", + "Prosinac"); + +// short month names +Calendar._SMN = new Array +("Sij", + "Velj", + "Ožu", + "Tra", + "Svi", + "Lip", + "Srp", + "Kol", + "Ruj", + "List", + "Stu", + "Pro"); + + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "About the calendar"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Prethodna godina (hold for menu)"; +Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (hold for menu)"; +Calendar._TT["GO_TODAY"] = "Na današnji dan"; +Calendar._TT["NEXT_MONTH"] = "Naredni mjesec (hold for menu)"; +Calendar._TT["NEXT_YEAR"] = "Naredna godina (hold for menu)"; +Calendar._TT["SEL_DATE"] = "Odaberite datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; +Calendar._TT["PART_TODAY"] = " (Danas)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Prikaži %s prvo"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zatvori"; +Calendar._TT["TODAY"] = "Danas"; +Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Vrijeme:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dc72dc360fcebca8e2972a84e7d6d09313cabbe7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dc72dc360fcebca8e2972a84e7d6d09313cabbe7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +class EnabledModule < ActiveRecord::Base + generator_for :name, :start => 'module_001' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dcac5a29f794b90b0c70d7b180bb1c20ea9606aa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dcac5a29f794b90b0c70d7b180bb1c20ea9606aa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +desc "Run the Continous Integration tests for Redmine" +task :ci do + # RAILS_ENV and ENV[] can diverge so force them both to test + ENV['RAILS_ENV'] = 'test' + RAILS_ENV = 'test' + Rake::Task["ci:setup"].invoke + Rake::Task["ci:build"].invoke + Rake::Task["ci:teardown"].invoke +end + +# Tasks can be hooked into by redefining them in a plugin +namespace :ci do + desc "Setup Redmine for a new build." + task :setup do + Rake::Task["ci:dump_environment"].invoke + Rake::Task["db:create"].invoke + Rake::Task["db:migrate"].invoke + Rake::Task["db:schema:dump"].invoke + Rake::Task["test:scm:update"].invoke + end + + desc "Build Redmine" + task :build do + Rake::Task["test"].invoke + end + + # Use this to cleanup after building or run post-build analysis. + desc "Finish the build" + task :teardown do + end + + desc "Dump the environment information to a BUILD_ENVIRONMENT ENV variable for debugging" + task :dump_environment do + + ENV['BUILD_ENVIRONMENT'] = ['ruby -v', 'gem -v', 'gem list'].collect do |command| + result = `#{command}` + "$ #{command}\n#{result}" + end.join("\n") + + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dcd8300edc662a87086c09fd122175e47ec511a0.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dcd8300edc662a87086c09fd122175e47ec511a0.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +

    <%=l(:text_workflow_edit)%>:

    + +<% form_tag({}, :method => 'get') do %> +

    + + + + + <%= hidden_field_tag 'used_statuses_only', '0' %> + +

    +

    +<%= submit_tag l(:button_edit), :name => nil %> +

    +<% end %> + +<% if @tracker && @role && @statuses.any? %> + <% form_tag({}, :id => 'workflow_form' ) do %> + <%= hidden_field_tag 'tracker_id', @tracker.id %> + <%= hidden_field_tag 'role_id', @role.id %> +
    + <%= render :partial => 'form', :locals => {:name => 'always', :workflows => @workflows['always']} %> + +
    + <%= l(:label_additional_workflow_transitions_for_author) %> +
    + <%= render :partial => 'form', :locals => {:name => 'author', :workflows => @workflows['author']} %> +
    +
    + <%= javascript_tag "hideFieldset($('author_workflows'))" unless @workflows['author'].present? %> + +
    + <%= l(:label_additional_workflow_transitions_for_assignee) %> +
    + <%= render :partial => 'form', :locals => {:name => 'assignee', :workflows => @workflows['assignee']} %> +
    +
    + <%= javascript_tag "hideFieldset($('assignee_workflows'))" unless @workflows['assignee'].present? %> +
    + <%= submit_tag l(:button_save) %> + <% end %> +<% end %> + +<% html_title(l(:label_workflow)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dc/dcf99a0e606d6b2ed7f6db815ac2c355eb779695.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dc/dcf99a0e606d6b2ed7f6db815ac2c355eb779695.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +Texte encod en ISO-8859-1. \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dd/dd0aa83c766a2c2e132d5e6eda1f9a1afdce4ca7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dd/dd0aa83c766a2c2e132d5e6eda1f9a1afdce4ca7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddIndexToSettingsName < ActiveRecord::Migration + def self.up + add_index :settings, :name + end + + def self.down + remove_index :settings, :name + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dd/dd203a5a6750b57817c4b5777ab59c772c375a96.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dd/dd203a5a6750b57817c4b5777ab59c772c375a96.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class MailHandlerController < ActionController::Base + before_filter :check_credential + + verify :method => :post, + :only => :index, + :render => { :nothing => true, :status => 405 } + + # Submits an incoming email to MailHandler + def index + options = params.dup + email = options.delete(:email) + if MailHandler.receive(email, options) + render :nothing => true, :status => :created + else + render :nothing => true, :status => :unprocessable_entity + end + end + + private + + def check_credential + User.current = nil + unless Setting.mail_handler_api_enabled? && params[:key].to_s == Setting.mail_handler_api_key + render :text => 'Access denied. Incoming emails WS is disabled or key is invalid.', :status => 403 + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dd/dd399fa1a533cae4a2e81fcf5c95ee72c18cacea.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dd/dd399fa1a533cae4a2e81fcf5c95ee72c18cacea.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Tučné'; +jsToolBar.strings['Italic'] = 'Kurzíva'; +jsToolBar.strings['Underline'] = 'Podčiarknuté'; +jsToolBar.strings['Deleted'] = 'Preškrtnuté'; +jsToolBar.strings['Code'] = 'Zobrazenie kódu'; +jsToolBar.strings['Heading 1'] = 'Záhlavie 1'; +jsToolBar.strings['Heading 2'] = 'Záhlavie 2'; +jsToolBar.strings['Heading 3'] = 'Záhlavie 3'; +jsToolBar.strings['Unordered list'] = 'Zoznam'; +jsToolBar.strings['Ordered list'] = 'Zoradený zoznam'; +jsToolBar.strings['Quote'] = 'Citácia'; +jsToolBar.strings['Unquote'] = 'Odstránenie citácie'; +jsToolBar.strings['Preformatted text'] = 'Predformátovaný text'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stránku'; +jsToolBar.strings['Image'] = 'Obrázok'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dd/ddc34f2c3196ca0b8688d877276e4a02664665f2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dd/ddc34f2c3196ca0b8688d877276e4a02664665f2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +class WikiPage < ActiveRecord::Base + generator_for :title, :start => 'AWikiPage' + generator_for :wiki, :method => :generate_wiki + + def self.generate_wiki + Wiki.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dd/ddc9dd8fa5fd66274ed32c9e1958c8093d3ccee4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dd/ddc9dd8fa5fd66274ed32c9e1958c8093d3ccee4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fed'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Understreget'; +jsToolBar.strings['Deleted'] = 'Slettet'; +jsToolBar.strings['Code'] = 'Inline-kode'; +jsToolBar.strings['Heading 1'] = 'Overskrift 1'; +jsToolBar.strings['Heading 2'] = 'Overskrift 2'; +jsToolBar.strings['Heading 3'] = 'Overskrift 3'; +jsToolBar.strings['Unordered list'] = 'Unummereret liste'; +jsToolBar.strings['Ordered list'] = 'Nummereret liste'; +jsToolBar.strings['Quote'] = 'Citér'; +jsToolBar.strings['Unquote'] = 'Fjern citér'; +jsToolBar.strings['Preformatted text'] = 'Præformateret tekst'; +jsToolBar.strings['Wiki link'] = 'Link til en wiki-side'; +jsToolBar.strings['Image'] = 'Billede'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/dd/ddf5a9b4d21215ca73da3908db0512fbeee7a2ed.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/dd/ddf5a9b4d21215ca73da3908db0512fbeee7a2ed.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class CreateUserPreferences < ActiveRecord::Migration + def self.up + create_table :user_preferences do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "others", :text + end + end + + def self.down + drop_table :user_preferences + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/de/de28294aaae4f7b627f7d8be23b384b587f38419.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/de/de28294aaae4f7b627f7d8be23b384b587f38419.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +$LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info" +require 'commands/about' + +Redmine::About.print_plugin_info diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/de/de4649b899e4b3b64fbf0d7e44653599c87a54ca.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/de/de4649b899e4b3b64fbf0d7e44653599c87a54ca.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +# -*- mode: outline; coding: utf-8-unix; -*- + +* Add logic in Rakefile to read the file list from Manifest.txt file. + +* Add a YAML export method to the TreeNode class. + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/de/de5d92ebbac6f996f9c447dfe646769615cd7350.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/de/de5d92ebbac6f996f9c447dfe646769615cd7350.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1029 @@ +# German translations for Ruby on Rails +# by Clemens Kofler (clemens@railway.at) +# additions for Redmine 1.2 by Jens Martsch (jmartsch@gmail.com) + +de: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y" + short: "%e. %b" + long: "%e. %B %Y" + + day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag] + abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember] + abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d.%m.%Y %H:%M" + time: "%H:%M" + short: "%e. %b %H:%M" + long: "%A, %e. %B %Y, %H:%M Uhr" + am: "vormittags" + pm: "nachmittags" + + datetime: + distance_in_words: + half_a_minute: 'eine halbe Minute' + less_than_x_seconds: + one: 'weniger als 1 Sekunde' + other: 'weniger als %{count} Sekunden' + x_seconds: + one: '1 Sekunde' + other: '%{count} Sekunden' + less_than_x_minutes: + one: 'weniger als 1 Minute' + other: 'weniger als %{count} Minuten' + x_minutes: + one: '1 Minute' + other: '%{count} Minuten' + about_x_hours: + one: 'etwa 1 Stunde' + other: 'etwa %{count} Stunden' + x_days: + one: '1 Tag' + other: '%{count} Tagen' + about_x_months: + one: 'etwa 1 Monat' + other: 'etwa %{count} Monaten' + x_months: + one: '1 Monat' + other: '%{count} Monaten' + about_x_years: + one: 'etwa 1 Jahr' + other: 'etwa %{count} Jahren' + over_x_years: + one: 'mehr als 1 Jahr' + other: 'mehr als %{count} Jahren' + almost_x_years: + one: "fast 1 Jahr" + other: "fast %{count} Jahren" + + number: + # Default format for numbers + format: + separator: ',' + delimiter: '.' + precision: 2 + currency: + format: + unit: '€' + format: '%n %u' + separator: + delimiter: + precision: + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "und" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "Dieses %{model}-Objekt konnte nicht gespeichert werden: %{count} Fehler." + other: "Dieses %{model}-Objekt konnte nicht gespeichert werden: %{count} Fehler." + body: "Bitte überprüfen Sie die folgenden Felder:" + + messages: + inclusion: "ist kein gültiger Wert" + exclusion: "ist nicht verfügbar" + invalid: "ist nicht gültig" + confirmation: "stimmt nicht mit der Bestätigung überein" + accepted: "muss akzeptiert werden" + empty: "muss ausgefüllt werden" + blank: "muss ausgefüllt werden" + too_long: "ist zu lang (nicht mehr als %{count} Zeichen)" + too_short: "ist zu kurz (nicht weniger als %{count} Zeichen)" + wrong_length: "hat die falsche Länge (muss genau %{count} Zeichen haben)" + taken: "ist bereits vergeben" + not_a_number: "ist keine Zahl" + not_a_date: "is kein gültiges Datum" + greater_than: "muss größer als %{count} sein" + greater_than_or_equal_to: "muss größer oder gleich %{count} sein" + equal_to: "muss genau %{count} sein" + less_than: "muss kleiner als %{count} sein" + less_than_or_equal_to: "muss kleiner oder gleich %{count} sein" + odd: "muss ungerade sein" + even: "muss gerade sein" + greater_than_start_date: "muss größer als Anfangsdatum sein" + not_same_project: "gehört nicht zum selben Projekt" + circular_dependency: "Diese Beziehung würde eine zyklische Abhängigkeit erzeugen" + cant_link_an_issue_with_a_descendant: "Ein Ticket kann nicht mit einer ihrer Unteraufgaben verlinkt werden" + + actionview_instancetag_blank_option: Bitte auswählen + + general_text_No: 'Nein' + general_text_Yes: 'Ja' + general_text_no: 'nein' + general_text_yes: 'ja' + general_lang_name: 'Deutsch' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Konto wurde erfolgreich aktualisiert. + notice_account_invalid_creditentials: Benutzer oder Kennwort ist ungültig. + notice_account_password_updated: Kennwort wurde erfolgreich aktualisiert. + notice_account_wrong_password: Falsches Kennwort. + notice_account_register_done: Konto wurde erfolgreich angelegt. + notice_account_unknown_email: Unbekannter Benutzer. + notice_can_t_change_password: Dieses Konto verwendet eine externe Authentifizierungs-Quelle. Unmöglich, das Kennwort zu ändern. + notice_account_lost_email_sent: Eine E-Mail mit Anweisungen, ein neues Kennwort zu wählen, wurde Ihnen geschickt. + notice_account_activated: Ihr Konto ist aktiviert. Sie können sich jetzt anmelden. + notice_successful_create: Erfolgreich angelegt + notice_successful_update: Erfolgreich aktualisiert. + notice_successful_delete: Erfolgreich gelöscht. + notice_successful_connection: Verbindung erfolgreich. + notice_file_not_found: Anhang existiert nicht oder ist gelöscht worden. + notice_locking_conflict: Datum wurde von einem anderen Benutzer geändert. + notice_not_authorized: Sie sind nicht berechtigt, auf diese Seite zuzugreifen. + notice_email_sent: "Eine E-Mail wurde an %{value} gesendet." + notice_email_error: "Beim Senden einer E-Mail ist ein Fehler aufgetreten (%{value})." + notice_feeds_access_key_reseted: Ihr Atom-Zugriffsschlüssel wurde zurückgesetzt. + notice_api_access_key_reseted: Ihr API-Zugriffsschlüssel wurde zurückgesetzt. + notice_failed_to_save_issues: "%{count} von %{total} ausgewählten Tickets konnte(n) nicht gespeichert werden: %{ids}." + notice_failed_to_save_members: "Benutzer konnte nicht gespeichert werden: %{errors}." + notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten." + notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators." + notice_default_data_loaded: Die Standard-Konfiguration wurde erfolgreich geladen. + notice_unable_delete_version: Die Version konnte nicht gelöscht werden. + notice_unable_delete_time_entry: Der Zeiterfassungseintrag konnte nicht gelöscht werden. + notice_issue_done_ratios_updated: Der Ticket-Fortschritt wurde aktualisiert. + + error_can_t_load_default_data: "Die Standard-Konfiguration konnte nicht geladen werden: %{value}" + error_scm_not_found: Eintrag und/oder Revision existiert nicht im Projektarchiv. + error_scm_command_failed: "Beim Zugriff auf das Projektarchiv ist ein Fehler aufgetreten: %{value}" + error_scm_annotate: "Der Eintrag existiert nicht oder kann nicht annotiert werden." + error_issue_not_found_in_project: 'Das Ticket wurde nicht gefunden oder gehört nicht zu diesem Projekt.' + error_no_tracker_in_project: Diesem Projekt ist kein Tracker zugeordnet. Bitte überprüfen Sie die Projekteinstellungen. + error_no_default_issue_status: Es ist kein Status als Standard definiert. Bitte überprüfen Sie Ihre Konfiguration (unter "Administration -> Ticket-Status"). + error_can_not_delete_custom_field: Kann das benutzerdefinierte Feld nicht löschen. + error_can_not_delete_tracker: Dieser Tracker enthält Tickets und kann nicht gelöscht werden. + error_can_not_remove_role: Diese Rolle wird verwendet und kann nicht gelöscht werden. + error_can_not_reopen_issue_on_closed_version: Das Ticket ist einer abgeschlossenen Version zugeordnet und kann daher nicht wieder geöffnet werden. + error_can_not_archive_project: Dieses Projekt kann nicht archiviert werden. + error_issue_done_ratios_not_updated: Der Ticket-Fortschritt wurde nicht aktualisiert. + error_workflow_copy_source: Bitte wählen Sie einen Quell-Tracker und eine Quell-Rolle. + error_workflow_copy_target: Bitte wählen Sie die Ziel-Tracker und -Rollen. + error_unable_delete_issue_status: "Der Ticket-Status konnte nicht gelöscht werden." + error_unable_to_connect: Fehler beim Verbinden (%{value}) + warning_attachments_not_saved: "%{count} Datei(en) konnten nicht gespeichert werden." + + mail_subject_lost_password: "Ihr %{value} Kennwort" + mail_body_lost_password: 'Benutzen Sie den folgenden Link, um Ihr Kennwort zu ändern:' + mail_subject_register: "%{value} Kontoaktivierung" + mail_body_register: 'Um Ihr Konto zu aktivieren, benutzen Sie folgenden Link:' + mail_body_account_information_external: "Sie können sich mit Ihrem Konto %{value} an anmelden." + mail_body_account_information: Ihre Konto-Informationen + mail_subject_account_activation_request: "Antrag auf %{value} Kontoaktivierung" + mail_body_account_activation_request: "Ein neuer Benutzer (%{value}) hat sich registriert. Sein Konto wartet auf Ihre Genehmigung:" + mail_subject_reminder: "%{count} Tickets müssen in den nächsten %{days} Tagen abgegeben werden" + mail_body_reminder: "%{count} Tickets, die Ihnen zugewiesen sind, müssen in den nächsten %{days} Tagen abgegeben werden:" + mail_subject_wiki_content_added: "Wiki-Seite '%{id}' hinzugefügt" + mail_body_wiki_content_added: "Die Wiki-Seite '%{id}' wurde von %{author} hinzugefügt." + mail_subject_wiki_content_updated: "Wiki-Seite '%{id}' erfolgreich aktualisiert" + mail_body_wiki_content_updated: "Die Wiki-Seite '%{id}' wurde von %{author} aktualisiert." + + gui_validation_error: 1 Fehler + gui_validation_error_plural: "%{count} Fehler" + + field_name: Name + field_description: Beschreibung + field_summary: Zusammenfassung + field_is_required: Erforderlich + field_firstname: Vorname + field_lastname: Nachname + field_mail: E-Mail + field_filename: Datei + field_filesize: Größe + field_downloads: Downloads + field_author: Autor + field_created_on: Angelegt + field_updated_on: Aktualisiert + field_field_format: Format + field_is_for_all: Für alle Projekte + field_possible_values: Mögliche Werte + field_regexp: Regulärer Ausdruck + field_min_length: Minimale Länge + field_max_length: Maximale Länge + field_value: Wert + field_category: Kategorie + field_title: Titel + field_project: Projekt + field_issue: Ticket + field_status: Status + field_notes: Kommentare + field_is_closed: Ticket geschlossen + field_is_default: Standardeinstellung + field_tracker: Tracker + field_subject: Thema + field_due_date: Abgabedatum + field_assigned_to: Zugewiesen an + field_priority: Priorität + field_fixed_version: Zielversion + field_user: Benutzer + field_principal: Auftraggeber + field_role: Rolle + field_homepage: Projekt-Homepage + field_is_public: Öffentlich + field_parent: Unterprojekt von + field_is_in_roadmap: In der Roadmap anzeigen + field_login: Mitgliedsname + field_mail_notification: Mailbenachrichtigung + field_admin: Administrator + field_last_login_on: Letzte Anmeldung + field_language: Sprache + field_effective_date: Datum + field_password: Kennwort + field_new_password: Neues Kennwort + field_password_confirmation: Bestätigung + field_version: Version + field_type: Typ + field_host: Host + field_port: Port + field_account: Konto + field_base_dn: Base DN + field_attr_login: Mitgliedsname-Attribut + field_attr_firstname: Vorname-Attribut + field_attr_lastname: Name-Attribut + field_attr_mail: E-Mail-Attribut + field_onthefly: On-the-fly-Benutzererstellung + field_start_date: Beginn + field_done_ratio: "% erledigt" + field_auth_source: Authentifizierungs-Modus + field_hide_mail: E-Mail-Adresse nicht anzeigen + field_comments: Kommentar + field_url: URL + field_start_page: Hauptseite + field_subproject: Unterprojekt von + field_hours: Stunden + field_activity: Aktivität + field_spent_on: Datum + field_identifier: Kennung + field_is_filter: Als Filter benutzen + field_issue_to: Zugehöriges Ticket + field_delay: Pufferzeit + field_assignable: Tickets können dieser Rolle zugewiesen werden + field_redirect_existing_links: Existierende Links umleiten + field_estimated_hours: Geschätzter Aufwand + field_column_names: Spalten + field_time_entries: Logzeit + field_time_zone: Zeitzone + field_searchable: Durchsuchbar + field_default_value: Standardwert + field_comments_sorting: Kommentare anzeigen + field_parent_title: Übergeordnete Seite + field_editable: Bearbeitbar + field_watcher: Beobachter + field_identity_url: OpenID-URL + field_content: Inhalt + field_group_by: Gruppiere Ergebnisse nach + field_sharing: Gemeinsame Verwendung + field_parent_issue: Übergeordnete Aufgabe + + setting_app_title: Applikations-Titel + setting_app_subtitle: Applikations-Untertitel + setting_welcome_text: Willkommenstext + setting_default_language: Default-Sprache + setting_login_required: Authentifizierung erforderlich + setting_self_registration: Anmeldung ermöglicht + setting_attachment_max_size: Max. Dateigröße + setting_issues_export_limit: Max. Anzahl Tickets bei CSV/PDF-Export + setting_mail_from: E-Mail-Absender + setting_bcc_recipients: E-Mails als Blindkopie (BCC) senden + setting_plain_text_mail: Nur reinen Text (kein HTML) senden + setting_host_name: Hostname + setting_text_formatting: Textformatierung + setting_wiki_compression: Wiki-Historie komprimieren + setting_feeds_limit: Max. Anzahl Einträge pro Atom-Feed + setting_default_projects_public: Neue Projekte sind standardmäßig öffentlich + setting_autofetch_changesets: Changesets automatisch abrufen + setting_sys_api_enabled: Webservice zur Verwaltung der Projektarchive benutzen + setting_commit_ref_keywords: Schlüsselwörter (Beziehungen) + setting_commit_fix_keywords: Schlüsselwörter (Status) + setting_autologin: Automatische Anmeldung + setting_date_format: Datumsformat + setting_time_format: Zeitformat + setting_cross_project_issue_relations: Ticket-Beziehungen zwischen Projekten erlauben + setting_issue_list_default_columns: Default-Spalten in der Ticket-Auflistung + setting_emails_footer: E-Mail-Fußzeile + setting_protocol: Protokoll + setting_per_page_options: Objekte pro Seite + setting_user_format: Benutzer-Anzeigeformat + setting_activity_days_default: Anzahl Tage pro Seite der Projekt-Aktivität + setting_display_subprojects_issues: Tickets von Unterprojekten im Hauptprojekt anzeigen + setting_enabled_scm: Aktivierte Versionskontrollsysteme + setting_mail_handler_body_delimiters: "Schneide E-Mails nach einer dieser Zeilen ab" + setting_mail_handler_api_enabled: Abruf eingehender E-Mails aktivieren + setting_mail_handler_api_key: API-Schlüssel + setting_sequential_project_identifiers: Fortlaufende Projektkennungen generieren + setting_gravatar_enabled: Gravatar-Benutzerbilder benutzen + setting_gravatar_default: Standard-Gravatar-Bild + setting_diff_max_lines_displayed: Maximale Anzahl anzuzeigender Diff-Zeilen + setting_file_max_size_displayed: Maximale Größe inline angezeigter Textdateien + setting_repository_log_display_limit: Maximale Anzahl anzuzeigender Revisionen in der Historie einer Datei + setting_openid: Erlaube OpenID-Anmeldung und -Registrierung + setting_password_min_length: Mindestlänge des Kennworts + setting_new_project_user_role_id: Rolle, die einem Nicht-Administrator zugeordnet wird, der ein Projekt erstellt + setting_default_projects_modules: Standardmäßig aktivierte Module für neue Projekte + setting_issue_done_ratio: Berechne den Ticket-Fortschritt mittels + setting_issue_done_ratio_issue_field: Ticket-Feld %-erledigt + setting_issue_done_ratio_issue_status: Ticket-Status + setting_start_of_week: Wochenanfang + setting_rest_api_enabled: REST-Schnittstelle aktivieren + setting_cache_formatted_text: Formatierten Text im Cache speichern + + permission_add_project: Projekt erstellen + permission_add_subprojects: Unterprojekte erstellen + permission_edit_project: Projekt bearbeiten + permission_select_project_modules: Projektmodule auswählen + permission_manage_members: Mitglieder verwalten + permission_manage_project_activities: Aktivitäten (Zeiterfassung) verwalten + permission_manage_versions: Versionen verwalten + permission_manage_categories: Ticket-Kategorien verwalten + permission_view_issues: Tickets anzeigen + permission_add_issues: Tickets hinzufügen + permission_edit_issues: Tickets bearbeiten + permission_manage_issue_relations: Ticket-Beziehungen verwalten + permission_add_issue_notes: Kommentare hinzufügen + permission_edit_issue_notes: Kommentare bearbeiten + permission_edit_own_issue_notes: Eigene Kommentare bearbeiten + permission_move_issues: Tickets verschieben + permission_delete_issues: Tickets löschen + permission_manage_public_queries: Öffentliche Filter verwalten + permission_save_queries: Filter speichern + permission_view_gantt: Gantt-Diagramm ansehen + permission_view_calendar: Kalender ansehen + permission_view_issue_watchers: Liste der Beobachter ansehen + permission_add_issue_watchers: Beobachter hinzufügen + permission_delete_issue_watchers: Beobachter löschen + permission_log_time: Aufwände buchen + permission_view_time_entries: Gebuchte Aufwände ansehen + permission_edit_time_entries: Gebuchte Aufwände bearbeiten + permission_edit_own_time_entries: Selbst gebuchte Aufwände bearbeiten + permission_manage_news: News verwalten + permission_comment_news: News kommentieren + permission_manage_documents: Dokumente verwalten + permission_view_documents: Dokumente ansehen + permission_manage_files: Dateien verwalten + permission_view_files: Dateien ansehen + permission_manage_wiki: Wiki verwalten + permission_rename_wiki_pages: Wiki-Seiten umbenennen + permission_delete_wiki_pages: Wiki-Seiten löschen + permission_view_wiki_pages: Wiki ansehen + permission_view_wiki_edits: Wiki-Versionsgeschichte ansehen + permission_edit_wiki_pages: Wiki-Seiten bearbeiten + permission_delete_wiki_pages_attachments: Anhänge löschen + permission_protect_wiki_pages: Wiki-Seiten schützen + permission_manage_repository: Projektarchiv verwalten + permission_browse_repository: Projektarchiv ansehen + permission_view_changesets: Changesets ansehen + permission_commit_access: Commit-Zugriff (über WebDAV) + permission_manage_boards: Foren verwalten + permission_view_messages: Forenbeiträge ansehen + permission_add_messages: Forenbeiträge hinzufügen + permission_edit_messages: Forenbeiträge bearbeiten + permission_edit_own_messages: Eigene Forenbeiträge bearbeiten + permission_delete_messages: Forenbeiträge löschen + permission_delete_own_messages: Eigene Forenbeiträge löschen + permission_export_wiki_pages: Wiki-Seiten exportieren + permission_manage_subtasks: Unteraufgaben verwalten + + project_module_issue_tracking: Ticket-Verfolgung + project_module_time_tracking: Zeiterfassung + project_module_news: News + project_module_documents: Dokumente + project_module_files: Dateien + project_module_wiki: Wiki + project_module_repository: Projektarchiv + project_module_boards: Foren + project_module_calendar: Kalender + project_module_gantt: Gantt + + label_user: Benutzer + label_user_plural: Benutzer + label_user_new: Neuer Benutzer + label_user_anonymous: Anonym + label_project: Projekt + label_project_new: Neues Projekt + label_project_plural: Projekte + label_x_projects: + zero: keine Projekte + one: 1 Projekt + other: "%{count} Projekte" + label_project_all: Alle Projekte + label_project_latest: Neueste Projekte + label_issue: Ticket + label_issue_new: Neues Ticket + label_issue_plural: Tickets + label_issue_view_all: Alle Tickets anzeigen + label_issues_by: "Tickets von %{value}" + label_issue_added: Ticket hinzugefügt + label_issue_updated: Ticket aktualisiert + label_document: Dokument + label_document_new: Neues Dokument + label_document_plural: Dokumente + label_document_added: Dokument hinzugefügt + label_role: Rolle + label_role_plural: Rollen + label_role_new: Neue Rolle + label_role_and_permissions: Rollen und Rechte + label_member: Mitglied + label_member_new: Neues Mitglied + label_member_plural: Mitglieder + label_tracker: Tracker + label_tracker_plural: Tracker + label_tracker_new: Neuer Tracker + label_workflow: Workflow + label_issue_status: Ticket-Status + label_issue_status_plural: Ticket-Status + label_issue_status_new: Neuer Status + label_issue_category: Ticket-Kategorie + label_issue_category_plural: Ticket-Kategorien + label_issue_category_new: Neue Kategorie + label_custom_field: Benutzerdefiniertes Feld + label_custom_field_plural: Benutzerdefinierte Felder + label_custom_field_new: Neues Feld + label_enumerations: Aufzählungen + label_enumeration_new: Neuer Wert + label_information: Information + label_information_plural: Informationen + label_please_login: Anmelden + label_register: Registrieren + label_login_with_open_id_option: oder mit OpenID anmelden + label_password_lost: Kennwort vergessen + label_home: Hauptseite + label_my_page: Meine Seite + label_my_account: Mein Konto + label_my_projects: Meine Projekte + label_my_page_block: Bereich "Meine Seite" + label_administration: Administration + label_login: Anmelden + label_logout: Abmelden + label_help: Hilfe + label_reported_issues: Gemeldete Tickets + label_assigned_to_me_issues: Mir zugewiesen + label_last_login: Letzte Anmeldung + label_registered_on: Angemeldet am + label_activity: Aktivität + label_overall_activity: Aktivität aller Projekte anzeigen + label_user_activity: "Aktivität von %{value}" + label_new: Neu + label_logged_as: Angemeldet als + label_environment: Umgebung + label_authentication: Authentifizierung + label_auth_source: Authentifizierungs-Modus + label_auth_source_new: Neuer Authentifizierungs-Modus + label_auth_source_plural: Authentifizierungs-Arten + label_subproject_plural: Unterprojekte + label_subproject_new: Neues Unterprojekt + label_and_its_subprojects: "%{value} und dessen Unterprojekte" + label_min_max_length: Länge (Min. - Max.) + label_list: Liste + label_date: Datum + label_integer: Zahl + label_float: Fließkommazahl + label_boolean: Boolean + label_string: Text + label_text: Langer Text + label_attribute: Attribut + label_attribute_plural: Attribute + label_download: "%{count} Download" + label_download_plural: "%{count} Downloads" + label_no_data: Nichts anzuzeigen + label_change_status: Statuswechsel + label_history: Historie + label_attachment: Datei + label_attachment_new: Neue Datei + label_attachment_delete: Anhang löschen + label_attachment_plural: Dateien + label_file_added: Datei hinzugefügt + label_report: Bericht + label_report_plural: Berichte + label_news: News + label_news_new: News hinzufügen + label_news_plural: News + label_news_latest: Letzte News + label_news_view_all: Alle News anzeigen + label_news_added: News hinzugefügt + label_settings: Konfiguration + label_overview: Übersicht + label_version: Version + label_version_new: Neue Version + label_version_plural: Versionen + label_close_versions: Vollständige Versionen schließen + label_confirmation: Bestätigung + label_export_to: "Auch abrufbar als:" + label_read: Lesen... + label_public_projects: Öffentliche Projekte + label_open_issues: offen + label_open_issues_plural: offen + label_closed_issues: geschlossen + label_closed_issues_plural: geschlossen + label_x_open_issues_abbr_on_total: + zero: 0 offen / %{total} + one: 1 offen / %{total} + other: "%{count} offen / %{total}" + label_x_open_issues_abbr: + zero: 0 offen + one: 1 offen + other: "%{count} offen" + label_x_closed_issues_abbr: + zero: 0 geschlossen + one: 1 geschlossen + other: "%{count} geschlossen" + label_total: Gesamtzahl + label_permissions: Berechtigungen + label_current_status: Gegenwärtiger Status + label_new_statuses_allowed: Neue Berechtigungen + label_all: alle + label_none: kein + label_nobody: Niemand + label_next: Weiter + label_previous: Zurück + label_used_by: Benutzt von + label_details: Details + label_add_note: Kommentar hinzufügen + label_per_page: Pro Seite + label_calendar: Kalender + label_months_from: Monate ab + label_gantt: Gantt-Diagramm + label_internal: Intern + label_last_changes: "%{count} letzte Änderungen" + label_change_view_all: Alle Änderungen anzeigen + label_personalize_page: Diese Seite anpassen + label_comment: Kommentar + label_comment_plural: Kommentare + label_x_comments: + zero: keine Kommentare + one: 1 Kommentar + other: "%{count} Kommentare" + label_comment_add: Kommentar hinzufügen + label_comment_added: Kommentar hinzugefügt + label_comment_delete: Kommentar löschen + label_query: Benutzerdefinierte Abfrage + label_query_plural: Benutzerdefinierte Berichte + label_query_new: Neuer Bericht + label_filter_add: Filter hinzufügen + label_filter_plural: Filter + label_equals: ist + label_not_equals: ist nicht + label_in_less_than: in weniger als + label_in_more_than: in mehr als + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + label_in: an + label_today: heute + label_all_time: gesamter Zeitraum + label_yesterday: gestern + label_this_week: aktuelle Woche + label_last_week: vorige Woche + label_last_n_days: "die letzten %{count} Tage" + label_this_month: aktueller Monat + label_last_month: voriger Monat + label_this_year: aktuelles Jahr + label_date_range: Zeitraum + label_less_than_ago: vor weniger als + label_more_than_ago: vor mehr als + label_ago: vor + label_contains: enthält + label_not_contains: enthält nicht + label_day_plural: Tage + label_repository: Projektarchiv + label_repository_plural: Projektarchive + label_browse: Codebrowser + label_modification: "%{count} Änderung" + label_modification_plural: "%{count} Änderungen" + label_branch: Zweig + label_tag: Markierung + label_revision: Revision + label_revision_plural: Revisionen + label_revision_id: Revision %{value} + label_associated_revisions: Zugehörige Revisionen + label_added: hinzugefügt + label_modified: geändert + label_copied: kopiert + label_renamed: umbenannt + label_deleted: gelöscht + label_latest_revision: Aktuellste Revision + label_latest_revision_plural: Aktuellste Revisionen + label_view_revisions: Revisionen anzeigen + label_view_all_revisions: Alle Revisionen anzeigen + label_max_size: Maximale Größe + label_sort_highest: An den Anfang + label_sort_higher: Eins höher + label_sort_lower: Eins tiefer + label_sort_lowest: Ans Ende + label_roadmap: Roadmap + label_roadmap_due_in: "Fällig in %{value}" + label_roadmap_overdue: "%{value} verspätet" + label_roadmap_no_issues: Keine Tickets für diese Version + label_search: Suche + label_result_plural: Resultate + label_all_words: Alle Wörter + label_wiki: Wiki + label_wiki_edit: Wiki-Bearbeitung + label_wiki_edit_plural: Wiki-Bearbeitungen + label_wiki_page: Wiki-Seite + label_wiki_page_plural: Wiki-Seiten + label_index_by_title: Seiten nach Titel sortiert + label_index_by_date: Seiten nach Datum sortiert + label_current_version: Gegenwärtige Version + label_preview: Vorschau + label_feed_plural: Feeds + label_changes_details: Details aller Änderungen + label_issue_tracking: Tickets + label_spent_time: Aufgewendete Zeit + label_overall_spent_time: Aufgewendete Zeit aller Projekte anzeigen + label_f_hour: "%{value} Stunde" + label_f_hour_plural: "%{value} Stunden" + label_time_tracking: Zeiterfassung + label_change_plural: Änderungen + label_statistics: Statistiken + label_commits_per_month: Übertragungen pro Monat + label_commits_per_author: Übertragungen pro Autor + label_view_diff: Unterschiede anzeigen + label_diff_inline: einspaltig + label_diff_side_by_side: nebeneinander + label_options: Optionen + label_copy_workflow_from: Workflow kopieren von + label_permissions_report: Berechtigungsübersicht + label_watched_issues: Beobachtete Tickets + label_related_issues: Zugehörige Tickets + label_applied_status: Zugewiesener Status + label_loading: Lade... + label_relation_new: Neue Beziehung + label_relation_delete: Beziehung löschen + label_relates_to: Beziehung mit + label_duplicates: Duplikat von + label_duplicated_by: Dupliziert durch + label_blocks: Blockiert + label_blocked_by: Blockiert durch + label_precedes: Vorgänger von + label_follows: folgt + label_end_to_start: Ende - Anfang + label_end_to_end: Ende - Ende + label_start_to_start: Anfang - Anfang + label_start_to_end: Anfang - Ende + label_stay_logged_in: Angemeldet bleiben + label_disabled: gesperrt + label_show_completed_versions: Abgeschlossene Versionen anzeigen + label_me: ich + label_board: Forum + label_board_new: Neues Forum + label_board_plural: Foren + label_board_locked: Gesperrt + label_board_sticky: Wichtig (immer oben) + label_topic_plural: Themen + label_message_plural: Forenbeiträge + label_message_last: Letzter Forenbeitrag + label_message_new: Neues Thema + label_message_posted: Forenbeitrag hinzugefügt + label_reply_plural: Antworten + label_send_information: Sende Kontoinformationen zum Benutzer + label_year: Jahr + label_month: Monat + label_week: Woche + label_date_from: Von + label_date_to: Bis + label_language_based: Sprachabhängig + label_sort_by: "Sortiert nach %{value}" + label_send_test_email: Test-E-Mail senden + label_feeds_access_key: RSS-Zugriffsschlüssel + label_missing_feeds_access_key: Der RSS-Zugriffsschlüssel fehlt. + label_feeds_access_key_created_on: "Atom-Zugriffsschlüssel vor %{value} erstellt" + label_module_plural: Module + label_added_time_by: "Von %{author} vor %{age} hinzugefügt" + label_updated_time_by: "Von %{author} vor %{age} aktualisiert" + label_updated_time: "Vor %{value} aktualisiert" + label_jump_to_a_project: Zu einem Projekt springen... + label_file_plural: Dateien + label_changeset_plural: Changesets + label_default_columns: Standard-Spalten + label_no_change_option: (Keine Änderung) + label_bulk_edit_selected_issues: Alle ausgewählten Tickets bearbeiten + label_theme: Stil + label_default: Standard + label_search_titles_only: Nur Titel durchsuchen + label_user_mail_option_all: "Für alle Ereignisse in all meinen Projekten" + label_user_mail_option_selected: "Für alle Ereignisse in den ausgewählten Projekten..." + label_user_mail_no_self_notified: "Ich möchte nicht über Änderungen benachrichtigt werden, die ich selbst durchführe." + label_registration_activation_by_email: Kontoaktivierung durch E-Mail + label_registration_manual_activation: Manuelle Kontoaktivierung + label_registration_automatic_activation: Automatische Kontoaktivierung + label_display_per_page: "Pro Seite: %{value}" + label_age: Geändert vor + label_change_properties: Eigenschaften ändern + label_general: Allgemein + label_more: Mehr + label_scm: Versionskontrollsystem + label_plugins: Plugins + label_ldap_authentication: LDAP-Authentifizierung + label_downloads_abbr: D/L + label_optional_description: Beschreibung (optional) + label_add_another_file: Eine weitere Datei hinzufügen + label_preferences: Präferenzen + label_chronological_order: in zeitlicher Reihenfolge + label_reverse_chronological_order: in umgekehrter zeitlicher Reihenfolge + label_planning: Terminplanung + label_incoming_emails: Eingehende E-Mails + label_generate_key: Generieren + label_issue_watchers: Beobachter + label_example: Beispiel + label_display: Anzeige + label_sort: Sortierung + label_ascending: Aufsteigend + label_descending: Absteigend + label_date_from_to: von %{start} bis %{end} + label_wiki_content_added: Die Wiki-Seite wurde erfolgreich hinzugefügt. + label_wiki_content_updated: Die Wiki-Seite wurde erfolgreich aktualisiert. + label_group: Gruppe + label_group_plural: Gruppen + label_group_new: Neue Gruppe + label_time_entry_plural: Benötigte Zeit + label_version_sharing_none: Nicht gemeinsam verwenden + label_version_sharing_descendants: Mit Unterprojekten + label_version_sharing_hierarchy: Mit Projekthierarchie + label_version_sharing_tree: Mit Projektbaum + label_version_sharing_system: Mit allen Projekten + label_update_issue_done_ratios: Ticket-Fortschritt aktualisieren + label_copy_source: Quelle + label_copy_target: Ziel + label_copy_same_as_target: So wie das Ziel + label_display_used_statuses_only: Zeige nur Status an, die von diesem Tracker verwendet werden + label_api_access_key: API-Zugriffsschlüssel + label_missing_api_access_key: Der API-Zugriffsschlüssel fehlt. + label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt + label_profile: Profil + label_subtask_plural: Unteraufgaben + label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts. + label_principal_search: "Nach Benutzer oder Gruppe suchen:" + label_user_search: "Nach Benutzer suchen:" + + button_login: Anmelden + button_submit: OK + button_save: Speichern + button_check_all: Alles auswählen + button_uncheck_all: Alles abwählen + button_delete: Löschen + button_create: Anlegen + button_create_and_continue: Anlegen und weiter + button_test: Testen + button_edit: Bearbeiten + button_edit_associated_wikipage: "Zugehörige Wikiseite bearbeiten: %{page_title}" + button_add: Hinzufügen + button_change: Wechseln + button_apply: Anwenden + button_clear: Zurücksetzen + button_lock: Sperren + button_unlock: Entsperren + button_download: Download + button_list: Liste + button_view: Anzeigen + button_move: Verschieben + button_move_and_follow: Verschieben und Ticket anzeigen + button_back: Zurück + button_cancel: Abbrechen + button_activate: Aktivieren + button_sort: Sortieren + button_log_time: Aufwand buchen + button_rollback: Auf diese Version zurücksetzen + button_watch: Beobachten + button_unwatch: Nicht beobachten + button_reply: Antworten + button_archive: Archivieren + button_unarchive: Entarchivieren + button_reset: Zurücksetzen + button_rename: Umbenennen + button_change_password: Kennwort ändern + button_copy: Kopieren + button_copy_and_follow: Kopieren und Ticket anzeigen + button_annotate: Annotieren + button_update: Bearbeiten + button_configure: Konfigurieren + button_quote: Zitieren + button_duplicate: Duplizieren + button_show: Anzeigen + + status_active: aktiv + status_registered: angemeldet + status_locked: gesperrt + + version_status_open: offen + version_status_locked: gesperrt + version_status_closed: abgeschlossen + + field_active: Aktiv + + text_select_mail_notifications: Bitte wählen Sie die Aktionen aus, für die eine Mailbenachrichtigung gesendet werden soll. + text_regexp_info: z. B. ^[A-Z0-9]+$ + text_min_max_length_info: 0 heißt keine Beschränkung + text_project_destroy_confirmation: Sind Sie sicher, dass sie das Projekt löschen wollen? + text_subprojects_destroy_warning: "Dessen Unterprojekte (%{value}) werden ebenfalls gelöscht." + text_workflow_edit: Workflow zum Bearbeiten auswählen + text_are_you_sure: Sind Sie sicher? + text_are_you_sure_with_children: "Lösche Aufgabe und alle Unteraufgaben?" + text_journal_changed: "%{label} wurde von %{old} zu %{new} geändert" + text_journal_set_to: "%{label} wurde auf %{value} gesetzt" + text_journal_deleted: "%{label} %{old} wurde gelöscht" + text_journal_added: "%{label} %{value} wurde hinzugefügt" + text_tip_issue_begin_day: Aufgabe, die an diesem Tag beginnt + text_tip_issue_end_day: Aufgabe, die an diesem Tag endet + text_tip_issue_begin_end_day: Aufgabe, die an diesem Tag beginnt und endet + text_project_identifier_info: 'Kleinbuchstaben (a-z), Ziffern und Bindestriche erlaubt.
    Einmal gespeichert, kann die Kennung nicht mehr geändert werden.' + text_caracters_maximum: "Max. %{count} Zeichen." + text_caracters_minimum: "Muss mindestens %{count} Zeichen lang sein." + text_length_between: "Länge zwischen %{min} und %{max} Zeichen." + text_tracker_no_workflow: Kein Workflow für diesen Tracker definiert. + text_unallowed_characters: Nicht erlaubte Zeichen + text_comma_separated: Mehrere Werte erlaubt (durch Komma getrennt). + text_line_separated: Mehrere Werte sind erlaubt (eine Zeile pro Wert). + text_issues_ref_in_commit_messages: Ticket-Beziehungen und -Status in Commit-Log-Meldungen + text_issue_added: "Ticket %{id} wurde erstellt von %{author}." + text_issue_updated: "Ticket %{id} wurde aktualisiert von %{author}." + text_wiki_destroy_confirmation: Sind Sie sicher, dass Sie dieses Wiki mit sämtlichem Inhalt löschen möchten? + text_issue_category_destroy_question: "Einige Tickets (%{count}) sind dieser Kategorie zugeodnet. Was möchten Sie tun?" + text_issue_category_destroy_assignments: Kategorie-Zuordnung entfernen + text_issue_category_reassign_to: Tickets dieser Kategorie zuordnen + text_user_mail_option: "Für nicht ausgewählte Projekte werden Sie nur Benachrichtigungen für Dinge erhalten, die Sie beobachten oder an denen Sie beteiligt sind (z. B. Tickets, deren Autor Sie sind oder die Ihnen zugewiesen sind)." + text_no_configuration_data: "Rollen, Tracker, Ticket-Status und Workflows wurden noch nicht konfiguriert.\nEs ist sehr zu empfehlen, die Standard-Konfiguration zu laden. Sobald sie geladen ist, können Sie sie abändern." + text_load_default_configuration: Standard-Konfiguration laden + text_status_changed_by_changeset: "Status geändert durch Changeset %{value}." + text_issues_destroy_confirmation: 'Sind Sie sicher, dass Sie die ausgewählten Tickets löschen möchten?' + text_select_project_modules: 'Bitte wählen Sie die Module aus, die in diesem Projekt aktiviert sein sollen:' + text_default_administrator_account_changed: Administrator-Kennwort geändert + text_file_repository_writable: Verzeichnis für Dateien beschreibbar + text_plugin_assets_writable: Verzeichnis für Plugin-Assets beschreibbar + text_rmagick_available: RMagick verfügbar (optional) + text_destroy_time_entries_question: Es wurden bereits %{hours} Stunden auf dieses Ticket gebucht. Was soll mit den Aufwänden geschehen? + text_destroy_time_entries: Gebuchte Aufwände löschen + text_assign_time_entries_to_project: Gebuchte Aufwände dem Projekt zuweisen + text_reassign_time_entries: 'Gebuchte Aufwände diesem Ticket zuweisen:' + text_user_wrote: "%{value} schrieb:" + text_enumeration_destroy_question: "%{count} Objekt(e) sind diesem Wert zugeordnet." + text_enumeration_category_reassign_to: 'Die Objekte stattdessen diesem Wert zuordnen:' + text_email_delivery_not_configured: "Der SMTP-Server ist nicht konfiguriert und Mailbenachrichtigungen sind ausgeschaltet.\nNehmen Sie die Einstellungen für Ihren SMTP-Server in config/configuration.yml vor und starten Sie die Applikation neu." + text_repository_usernames_mapping: "Bitte legen Sie die Zuordnung der Redmine-Benutzer zu den Benutzernamen der Commit-Log-Meldungen des Projektarchivs fest.\nBenutzer mit identischen Redmine- und Projektarchiv-Benutzernamen oder -E-Mail-Adressen werden automatisch zugeordnet." + text_diff_truncated: '... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.' + text_custom_field_possible_values_info: 'Eine Zeile pro Wert' + text_wiki_page_destroy_question: "Diese Seite hat %{descendants} Unterseite(n). Was möchten Sie tun?" + text_wiki_page_nullify_children: Verschiebe die Unterseiten auf die oberste Ebene + text_wiki_page_destroy_children: Lösche alle Unterseiten + text_wiki_page_reassign_children: Ordne die Unterseiten dieser Seite zu + text_own_membership_delete_confirmation: "Sie sind dabei, einige oder alle Ihre Berechtigungen zu entfernen. Es ist möglich, dass Sie danach das Projekt nicht mehr ansehen oder bearbeiten dürfen.\nSind Sie sicher, dass Sie dies tun möchten?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + + default_role_manager: Manager + default_role_developer: Entwickler + default_role_reporter: Reporter + default_tracker_bug: Fehler + default_tracker_feature: Feature + default_tracker_support: Unterstützung + default_issue_status_new: Neu + default_issue_status_in_progress: In Bearbeitung + default_issue_status_resolved: Gelöst + default_issue_status_feedback: Feedback + default_issue_status_closed: Erledigt + default_issue_status_rejected: Abgewiesen + default_doc_category_user: Benutzerdokumentation + default_doc_category_tech: Technische Dokumentation + default_priority_low: Niedrig + default_priority_normal: Normal + default_priority_high: Hoch + default_priority_urgent: Dringend + default_priority_immediate: Sofort + default_activity_design: Design + default_activity_development: Entwicklung + + enumeration_issue_priorities: Ticket-Prioritäten + enumeration_doc_categories: Dokumentenkategorien + enumeration_activities: Aktivitäten (Zeiterfassung) + enumeration_system_activity: System-Aktivität + + field_text: Textfeld + label_user_mail_option_only_owner: Nur für Aufgaben die ich angelegt habe + setting_default_notification_option: Standard Benachrichtigungsoptionen + label_user_mail_option_only_my_events: Nur für Aufgaben die ich beobachte oder an welchen ich mitarbeite + label_user_mail_option_only_assigned: Nur für Aufgaben für die ich zuständig bin. + notice_not_authorized_archived_project: Das Projekt wurde archiviert und ist daher nicht nicht verfügbar. + label_user_mail_option_none: keine Ereignisse + field_member_of_group: Zuständigkeitsgruppe + field_assigned_to_role: Zuständigkeitsrolle + field_visible: Sichtbar + setting_emails_header: E-Mail Betreffzeile + setting_commit_logtime_activity_id: Aktivität für die Zeiterfassung + text_time_logged_by_changeset: Angewendet in Changeset %{value}. + setting_commit_logtime_enabled: Aktiviere Zeitlogging + notice_gantt_chart_truncated: Die Grafik ist unvollständig, da das Maximum der anzeigbaren Aufgaben überschritten wurde (%{max}) + setting_gantt_items_limit: Maximale Anzahl von Aufgaben die im Gantt-Chart angezeigt werden. + field_warn_on_leaving_unsaved: vor dem Verlassen einer Seite mit ungesichertem Text im Editor warnen + text_warn_on_leaving_unsaved: Die aktuellen Änderungen gehen verloren, wenn Sie diese Seite verlassen. + label_my_queries: Meine eigenen Abfragen + text_journal_changed_no_detail: "%{label} aktualisiert" + label_news_comment_added: Kommentar zu einer News hinzugefügt + button_expand_all: Alle ausklappen + button_collapse_all: Alle einklappen + label_additional_workflow_transitions_for_assignee: Zusätzliche Berechtigungen wenn der Benutzer der Zugewiesene ist + label_additional_workflow_transitions_for_author: Zusätzliche Berechtigungen wenn der Benutzer der Autor ist + label_bulk_edit_selected_time_entries: Ausgewählte Zeitaufwände bearbeiten + text_time_entries_destroy_confirmation: Sind Sie sicher, dass Sie die ausgewählten Zeitaufwände löschen möchten? + label_role_anonymous: Anonymous + label_role_non_member: Nichtmitglied + label_issue_note_added: Notiz hinzugefügt + label_issue_status_updated: Status aktualisiert + label_issue_priority_updated: Priorität aktualisiert + label_issues_visibility_own: Tickets die folgender User erstellt hat oder die ihm zugewiesen sind + field_issues_visibility: Ticket Sichtbarkeit + label_issues_visibility_all: Alle Tickets + permission_set_own_issues_private: Eigene Tickets privat oder öffentlich markieren + field_is_private: Privat + permission_set_issues_private: Tickets privat oder öffentlich markieren + label_issues_visibility_public: Alle öffentlichen Tickets + text_issues_destroy_descendants_confirmation: Dies wird auch %{count} Unteraufgabe/n löschen. + field_commit_logs_encoding: Kodierung der Commit-Log-Meldungen + field_scm_path_encoding: Pfad Kodierung + text_scm_path_encoding_note: "Standard: UTF-8" + field_path_to_repository: Pfad zum repository + field_root_directory: Wurzelverzeichnis + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokales repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Kommando + text_scm_command_version: Version + label_git_report_last_commit: Bericht des letzten Commits für Dateien und Verzeichnisse + text_scm_config: Die SCM-Kommandos können in der in config/configuration.yml konfiguriert werden. Redmine muss anschließend neu gestartet werden. + text_scm_command_not_available: Scm Kommando ist nicht verfügbar. Bitte prüfen Sie die Einstellungen im Administrationspanel. + + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + + description_filter: Filter + description_search: Suchfeld + description_choose_project: Projekte + description_project_scope: Suchbereich + description_notes: Kommentare + description_message_content: Nachrichteninhalt + description_query_sort_criteria_attribute: Sortierattribut + description_query_sort_criteria_direction: Sortierrichtung + description_user_mail_notification: Mailbenachrichtigungseinstellung + description_available_columns: Verfügbare Spalten + description_selected_columns: Ausgewählte Spalten + description_issue_category_reassign: Neue Kategorie wählen + description_wiki_subpages_reassign: Neue Elternseite wählen + description_date_range_list: Zeitraum aus einer Liste wählen + description_date_range_interval: Zeitraum durch Start- und Enddatum festlegen + description_date_from: Startdatum eintragen + description_date_to: Enddatum eintragen + + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/de/de71f387d0c606eebf684b499bd4901c9d91a85f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/de/de71f387d0c606eebf684b499bd4901c9d91a85f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,174 @@ +require File.expand_path('../../test_helper', __FILE__) + +class IssueMovesControllerTest < ActionController::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :journals, :journal_details + + def setup + User.current = nil + end + + def test_get_issue_moves_new + @request.session[:user_id] = 2 + get :new, :id => 1 + + assert_tag :tag => 'option', :content => 'eCookbook', + :attributes => { :value => '1', :selected => 'selected' } + %w(new_tracker_id status_id priority_id assigned_to_id).each do |field| + assert_tag :tag => 'option', :content => '(No change)', :attributes => { :value => '' }, + :parent => {:tag => 'select', :attributes => {:id => field}} + assert_no_tag :tag => 'option', :attributes => {:selected => 'selected'}, + :parent => {:tag => 'select', :attributes => {:id => field}} + end + + # Be sure we don't include inactive enumerations + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'priority_id'} } + end + + def test_create_one_issue_to_another_project + @request.session[:user_id] = 2 + post :create, :id => 1, :new_project_id => 2, :tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + assert_equal 2, Issue.find(1).project_id + end + + def test_create_one_issue_to_another_project_should_follow_when_needed + @request.session[:user_id] = 2 + post :create, :id => 1, :new_project_id => 2, :follow => '1' + assert_redirected_to '/issues/1' + end + + def test_bulk_create_to_another_project + @request.session[:user_id] = 2 + post :create, :ids => [1, 2], :new_project_id => 2 + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + # Issues moved to project 2 + assert_equal 2, Issue.find(1).project_id + assert_equal 2, Issue.find(2).project_id + # No tracker change + assert_equal 1, Issue.find(1).tracker_id + assert_equal 2, Issue.find(2).tracker_id + end + + def test_bulk_create_to_another_tracker + @request.session[:user_id] = 2 + post :create, :ids => [1, 2], :new_tracker_id => 2 + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + assert_equal 2, Issue.find(1).tracker_id + assert_equal 2, Issue.find(2).tracker_id + end + + context "#create via bulk move" do + setup do + @request.session[:user_id] = 2 + end + + should "allow changing the issue priority" do + post :create, :ids => [1, 2], :priority_id => 6 + + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + assert_equal 6, Issue.find(1).priority_id + assert_equal 6, Issue.find(2).priority_id + + end + + should "allow adding a note when moving" do + post :create, :ids => [1, 2], :notes => 'Moving two issues' + + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes + assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes + + end + + end + + def test_bulk_copy_to_another_project + @request.session[:user_id] = 2 + assert_difference 'Issue.count', 2 do + assert_no_difference 'Project.find(1).issues.count' do + post :create, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} + end + end + assert_redirected_to '/projects/ecookbook/issues' + end + + context "#create via bulk copy" do + should "allow not changing the issue's attributes" do + @request.session[:user_id] = 2 + issue_before_move = Issue.find(1) + assert_difference 'Issue.count', 1 do + assert_no_difference 'Project.find(1).issues.count' do + post :create, :ids => [1], :new_project_id => 2, + :copy_options => {:copy => '1'}, :new_tracker_id => '', + :assigned_to_id => '', :status_id => '', + :start_date => '', :due_date => '' + end + end + issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) + assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id + assert_equal issue_before_move.status_id, issue_after_move.status_id + assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id + end + + should "allow changing the issue's attributes" do + # Fixes random test failure with Mysql + # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) + # doesn't return the expected results + Issue.delete_all("project_id=2") + + @request.session[:user_id] = 2 + assert_difference 'Issue.count', 2 do + assert_no_difference 'Project.find(1).issues.count' do + post :create, :ids => [1, 2], :new_project_id => 2, + :copy_options => {:copy => '1'}, :new_tracker_id => '', + :assigned_to_id => 4, :status_id => 3, + :start_date => '2009-12-01', :due_date => '2009-12-31' + end + end + + copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) + assert_equal 2, copied_issues.size + copied_issues.each do |issue| + assert_equal 2, issue.project_id, "Project is incorrect" + assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect" + assert_equal 3, issue.status_id, "Status is incorrect" + assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect" + assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect" + end + end + + should "allow adding a note when copying" do + @request.session[:user_id] = 2 + assert_difference 'Issue.count', 1 do + post :create, :ids => [1], :copy_options => {:copy => '1'}, + :notes => 'Copying one issue', :new_tracker_id => '', + :assigned_to_id => 4, :status_id => 3, + :start_date => '2009-12-01', :due_date => '2009-12-31' + end + + issue = Issue.first(:order => 'id DESC') + assert_equal 1, issue.journals.size + journal = issue.journals.first + assert_equal 0, journal.details.size + assert_equal 'Copying one issue', journal.notes + end + end + + def test_copy_to_another_project_should_follow_when_needed + @request.session[:user_id] = 2 + post :create, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' + issue = Issue.first(:order => 'id DESC') + assert_redirected_to :controller => 'issues', :action => 'show', :id => issue + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/de/deb8226384e62bff3e0cb6d730d94aefe36c81a4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/de/deb8226384e62bff3e0cb6d730d94aefe36c81a4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +

    <%= l(@enumeration.option_name) %>: <%=h @enumeration %>

    + +<% form_tag({}) do %> +
    +

    <%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %>

    +

    +<%= select_tag 'reassign_to_id', ("" + options_from_collection_for_select(@enumerations, 'id', 'name')) %>

    +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'enumerations', :action => 'index' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/de/decdadb03925d799d63df58963fbba434c375130.svn-base Binary file .svn/pristine/de/decdadb03925d799d63df58963fbba434c375130.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/df3886ebb0000dac35671d112fc063ec223717dd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/df3886ebb0000dac35671d112fc063ec223717dd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,78 @@ +--- !ruby/object:Gem::Specification +name: coderay +version: !ruby/object:Gem::Version + hash: 23 + prerelease: + segments: + - 1 + - 0 + - 0 + version: 1.0.0 +platform: ruby +authors: +- Kornelius Kalnbach +autorequire: +bindir: bin +cert_chain: [] + +date: 2011-09-21 00:00:00 Z +default_executable: coderay +dependencies: [] + +description: Fast and easy syntax highlighting for selected languages, written in Ruby. Comes with RedCloth integration and LOC counter. +email: +- murphy@rubychan.de +executables: +- coderay +extensions: [] + +extra_rdoc_files: [] + +files: +- test/functional/basic.rb +- test/functional/examples.rb +- test/functional/for_redcloth.rb +- test/functional/suite.rb +- bin/coderay +has_rdoc: true +homepage: http://coderay.rubychan.de +licenses: [] + +post_install_message: +rdoc_options: [] + +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 59 + segments: + - 1 + - 8 + - 6 + version: 1.8.6 +required_rubygems_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" +requirements: [] + +rubyforge_project: coderay +rubygems_version: 1.6.2 +signing_key: +specification_version: 3 +summary: Fast syntax highlighting for selected languages. +test_files: +- test/functional/basic.rb +- test/functional/examples.rb +- test/functional/for_redcloth.rb +- test/functional/suite.rb + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/df56c25b6062cf9dcb8a0c3d7c5240c16861e2f7.svn-base Binary file .svn/pristine/df/df56c25b6062cf9dcb8a0c3d7c5240c16861e2f7.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/df6eb9a639b9b009d73d6b8d9897042b64a47066.svn-base Binary file .svn/pristine/df/df6eb9a639b9b009d73d6b8d9897042b64a47066.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/df8b371ed525f463b2814ba63c3245f1661898e6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/df8b371ed525f463b2814ba63c3245f1661898e6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ + + + + + +<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_header) %> +<%= yield %> +
    +<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer) %> + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/df905b0644ccdf0c1abfa3eb8cd4085be481962e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/df905b0644ccdf0c1abfa3eb8cd4085be481962e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +# The Plugin::Migrator class contains the logic to run migrations from +# within plugin directories. The directory in which a plugin's migrations +# should be is determined by the Plugin#migration_directory method. +# +# To migrate a plugin, you can simple call the migrate method (Plugin#migrate) +# with the version number that plugin should be at. The plugin's migrations +# will then be used to migrate up (or down) to the given version. +# +# For more information, see Engines::RailsExtensions::Migrations +class Engines::Plugin::Migrator < ActiveRecord::Migrator + + # We need to be able to set the 'current' engine being migrated. + cattr_accessor :current_plugin + + class << self + # Runs the migrations from a plugin, up (or down) to the version given + def migrate_plugin(plugin, version) + self.current_plugin = plugin + return if current_version(plugin) == version + migrate(plugin.migration_directory, version) + end + + def current_version(plugin=current_plugin) + # Delete migrations that don't match .. to_i will work because the number comes first + ::ActiveRecord::Base.connection.select_values( + "SELECT version FROM #{schema_migrations_table_name}" + ).delete_if{ |v| v.match(/-#{plugin.name}/) == nil }.map(&:to_i).max || 0 + end + end + + def migrated + sm_table = self.class.schema_migrations_table_name + ::ActiveRecord::Base.connection.select_values( + "SELECT version FROM #{sm_table}" + ).delete_if{ |v| v.match(/-#{current_plugin.name}/) == nil }.map(&:to_i).sort + end + + def record_version_state_after_migrating(version) + super(version.to_s + "-" + current_plugin.name) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/dfae037e99ba26462449559915851052f4865887.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/dfae037e99ba26462449559915851052f4865887.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class <%= class_name %> < ActiveRecord::Base + unloadable +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/dfb3acb9226878b28e389fb4105ce64bd182e491.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/dfb3acb9226878b28e389fb4105ce64bd182e491.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,385 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'cgi' + +module Redmine + module Scm + module Adapters + class CommandFailed < StandardError #:nodoc: + end + + class AbstractAdapter #:nodoc: + + # raised if scm command exited with error, e.g. unknown revision. + class ScmCommandAborted < CommandFailed; end + + class << self + def client_command + "" + end + + def shell_quote_command + if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java' + client_command + else + shell_quote(client_command) + end + end + + # Returns the version of the scm client + # Eg: [1, 5, 0] or [] if unknown + def client_version + [] + end + + # Returns the version string of the scm client + # Eg: '1.5.0' or 'Unknown version' if unknown + def client_version_string + v = client_version || 'Unknown version' + v.is_a?(Array) ? v.join('.') : v.to_s + end + + # Returns true if the current client version is above + # or equals the given one + # If option is :unknown is set to true, it will return + # true if the client version is unknown + def client_version_above?(v, options={}) + ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown]) + end + + def client_available + true + end + + def shell_quote(str) + if Redmine::Platform.mswin? + '"' + str.gsub(/"/, '\\"') + '"' + else + "'" + str.gsub(/'/, "'\"'\"'") + "'" + end + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @url = url + @login = login if login && !login.empty? + @password = (password || "") if @login + @root_url = root_url.blank? ? retrieve_root_url : root_url + end + + def adapter_name + 'Abstract' + end + + def supports_cat? + true + end + + def supports_annotate? + respond_to?('annotate') + end + + def root_url + @root_url + end + + def url + @url + end + + def path_encoding + nil + end + + # get info about the svn repository + def info + return nil + end + + # Returns the entry identified by path and revision identifier + # or nil if entry doesn't exist in the repository + def entry(path=nil, identifier=nil) + parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} + search_path = parts[0..-2].join('/') + search_name = parts[-1] + if search_path.blank? && search_name.blank? + # Root entry + Entry.new(:path => '', :kind => 'dir') + else + # Search for the entry in the parent directory + es = entries(search_path, identifier) + es ? es.detect {|e| e.name == search_name} : nil + end + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + return nil + end + + def branches + return nil + end + + def tags + return nil + end + + def default_branch + return nil + end + + def properties(path, identifier=nil) + return nil + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + return nil + end + + def diff(path, identifier_from, identifier_to=nil) + return nil + end + + def cat(path, identifier=nil) + return nil + end + + def with_leading_slash(path) + path ||= '' + (path[0,1]!="/") ? "/#{path}" : path + end + + def with_trailling_slash(path) + path ||= '' + (path[-1,1] == "/") ? path : "#{path}/" + end + + def without_leading_slash(path) + path ||= '' + path.gsub(%r{^/+}, '') + end + + def without_trailling_slash(path) + path ||= '' + (path[-1,1] == "/") ? path[0..-2] : path + end + + def shell_quote(str) + self.class.shell_quote(str) + end + + private + def retrieve_root_url + info = self.info + info ? info.root_url : nil + end + + def target(path, sq=true) + path ||= '' + base = path.match(/^\//) ? root_url : url + str = "#{base}/#{path}".gsub(/[?<>\*]/, '') + if sq + str = shell_quote(str) + end + str + end + + def logger + self.class.logger + end + + def shellout(cmd, &block) + self.class.shellout(cmd, &block) + end + + def self.logger + Rails.logger + end + + def self.shellout(cmd, &block) + if logger && logger.debug? + logger.debug "Shelling out: #{strip_credential(cmd)}" + end + if Rails.env == 'development' + # Capture stderr when running in dev environment + cmd = "#{cmd} 2>>#{Rails.root}/log/scm.stderr.log" + end + begin + if RUBY_VERSION < '1.9' + mode = "r+" + else + mode = "r+:ASCII-8BIT" + end + IO.popen(cmd, mode) do |io| + io.close_write + block.call(io) if block_given? + end + ## If scm command does not exist, + ## Linux JRuby 1.6.2 (ruby-1.8.7-p330) raises java.io.IOException + ## in production environment. + # rescue Errno::ENOENT => e + rescue Exception => e + msg = strip_credential(e.message) + # The command failed, log it and re-raise + logmsg = "SCM command failed, " + logmsg += "make sure that your SCM command (e.g. svn) is " + logmsg += "in PATH (#{ENV['PATH']})\n" + logmsg += "You can configure your scm commands in config/configuration.yml.\n" + logmsg += "#{strip_credential(cmd)}\n" + logmsg += "with: #{msg}" + logger.error(logmsg) + raise CommandFailed.new(msg) + end + end + + # Hides username/password in a given command + def self.strip_credential(cmd) + q = (Redmine::Platform.mswin? ? '"' : "'") + cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx') + end + + def strip_credential(cmd) + self.class.strip_credential(cmd) + end + + def scm_iconv(to, from, str) + return nil if str.nil? + return str if to == from + begin + Iconv.conv(to, from, str) + rescue Iconv::Failure => err + logger.error("failed to convert from #{from} to #{to}. #{err}") + nil + end + end + end + + class Entries < Array + def sort_by_name + sort {|x,y| + if x.kind == y.kind + x.name.to_s <=> y.name.to_s + else + x.kind <=> y.kind + end + } + end + + def revisions + revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact) + end + end + + class Info + attr_accessor :root_url, :lastrev + def initialize(attributes={}) + self.root_url = attributes[:root_url] if attributes[:root_url] + self.lastrev = attributes[:lastrev] + end + end + + class Entry + attr_accessor :name, :path, :kind, :size, :lastrev + def initialize(attributes={}) + self.name = attributes[:name] if attributes[:name] + self.path = attributes[:path] if attributes[:path] + self.kind = attributes[:kind] if attributes[:kind] + self.size = attributes[:size].to_i if attributes[:size] + self.lastrev = attributes[:lastrev] + end + + def is_file? + 'file' == self.kind + end + + def is_dir? + 'dir' == self.kind + end + + def is_text? + Redmine::MimeType.is_type?('text', name) + end + end + + class Revisions < Array + def latest + sort {|x,y| + unless x.time.nil? or y.time.nil? + x.time <=> y.time + else + 0 + end + }.last + end + end + + class Revision + attr_accessor :scmid, :name, :author, :time, :message, + :paths, :revision, :branch, :identifier, + :parents + + def initialize(attributes={}) + self.identifier = attributes[:identifier] + self.scmid = attributes[:scmid] + self.name = attributes[:name] || self.identifier + self.author = attributes[:author] + self.time = attributes[:time] + self.message = attributes[:message] || "" + self.paths = attributes[:paths] + self.revision = attributes[:revision] + self.branch = attributes[:branch] + self.parents = attributes[:parents] + end + + # Returns the readable identifier. + def format_identifier + self.identifier.to_s + end + end + + class Annotate + attr_reader :lines, :revisions + + def initialize + @lines = [] + @revisions = [] + end + + def add_line(line, revision) + @lines << line + @revisions << revision + end + + def content + content = lines.join("\n") + end + + def empty? + lines.empty? + end + end + + class Branch < String + attr_accessor :revision, :scmid + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/dfc1e477a4cb72dd0ef065e3d0ac9d62cc729189.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/dfc1e477a4cb72dd0ef065e3d0ac9d62cc729189.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,78 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class RolesController < ApplicationController + layout 'admin' + + before_filter :require_admin + + verify :method => :post, :only => [ :destroy ], + :redirect_to => { :action => :index } + + def index + @role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position' + render :action => "index", :layout => false if request.xhr? + end + + def new + # Prefills the form with 'Non member' role permissions + @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions}) + if request.post? && @role.save + # workflow copy + if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from])) + @role.workflows.copy(copy_from) + end + flash[:notice] = l(:notice_successful_create) + redirect_to :action => 'index' + else + @permissions = @role.setable_permissions + @roles = Role.find :all, :order => 'builtin, position' + end + end + + def edit + @role = Role.find(params[:id]) + if request.post? and @role.update_attributes(params[:role]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'index' + else + @permissions = @role.setable_permissions + end + end + + def destroy + @role = Role.find(params[:id]) + @role.destroy + redirect_to :action => 'index' + rescue + flash[:error] = l(:error_can_not_remove_role) + redirect_to :action => 'index' + end + + def report + @roles = Role.find(:all, :order => 'builtin, position') + @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } + if request.post? + @roles.each do |role| + role.permissions = params[:permissions][role.id.to_s] + role.save + end + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'index' + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/df/dff22ee1a80fd2494a9dc8550694f802db7e71a2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/df/dff22ee1a80fd2494a9dc8550694f802db7e71a2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%=l(:label_administration)%>

    + +
    + <%= render :partial => 'no_data' if @no_configuration_data %> + <%= render :partial => 'menu' %> +
    + +<% html_title(l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e016f7bcdcab31cab9c67782c8874b33b52e7b82.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e016f7bcdcab31cab9c67782c8874b33b52e7b82.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,963 @@ +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = { }; +Autocompleter.Base = Class.create({ + baseInitialize: function(element, update, options) { + element = $(element); + this.element = element; + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + this.oldElementValue = this.element.value; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || { }; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + // Force carriage returns as token delimiters anyway + if (!this.options.tokens.include('\n')) + this.options.tokens.push('\n'); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (Prototype.Browser.IE) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index--; + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++; + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = $(selectedElement).select('.' + this.options.select) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var bounds = this.getTokenBounds(); + if (bounds[0] != -1) { + var newValue = this.element.value.substr(0, bounds[0]); + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value + this.element.value.substr(bounds[1]); + } else { + this.element.value = value; + } + this.oldElementValue = this.element.value; + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + this.tokenBounds = null; + if(this.getToken().length>=this.options.minChars) { + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + this.oldElementValue = this.element.value; + }, + + getToken: function() { + var bounds = this.getTokenBounds(); + return this.element.value.substring(bounds[0], bounds[1]).strip(); + }, + + getTokenBounds: function() { + if (null != this.tokenBounds) return this.tokenBounds; + var value = this.element.value; + if (value.strip().empty()) return [-1, 0]; + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); + var offset = (diff == this.oldElementValue.length ? 1 : 0); + var prevTokenPos = -1, nextTokenPos = value.length; + var tp; + for (var index = 0, l = this.options.tokens.length; index < l; ++index) { + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); + if (tp > prevTokenPos) prevTokenPos = tp; + tp = value.indexOf(this.options.tokens[index], diff + offset); + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; + } + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); + } +}); + +Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { + var boundary = Math.min(newS.length, oldS.length); + for (var index = 0; index < boundary; ++index) + if (newS[index] != oldS[index]) + return index; + return boundary; +}; + +Ajax.Autocompleter = Class.create(Autocompleter.Base, { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + this.startIndicator(); + + var entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); + return "
      " + ret.join('') + "
    "; + } + }, options || { }); + } +}); + +// AJAX in-place editor and collection editor +// Full rewrite by Christophe Porteneuve (April 2007). + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +}; + +Ajax.InPlaceEditor = Class.create({ + initialize: function(element, url, options) { + this.url = url; + this.element = element = $(element); + this.prepareOptions(); + this._controls = { }; + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! + Object.extend(this.options, options || { }); + if (!this.options.formId && this.element.id) { + this.options.formId = this.element.id + '-inplaceeditor'; + if ($(this.options.formId)) + this.options.formId = ''; + } + if (this.options.externalControl) + this.options.externalControl = $(this.options.externalControl); + if (!this.options.externalControl) + this.options.externalControlOnly = false; + this._originalBackground = this.element.getStyle('background-color') || 'transparent'; + this.element.title = this.options.clickToEditText; + this._boundCancelHandler = this.handleFormCancellation.bind(this); + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); + this._boundFailureHandler = this.handleAJAXFailure.bind(this); + this._boundSubmitHandler = this.handleFormSubmission.bind(this); + this._boundWrapperHandler = this.wrapUp.bind(this); + this.registerListeners(); + }, + checkForEscapeOrReturn: function(e) { + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; + if (Event.KEY_ESC == e.keyCode) + this.handleFormCancellation(e); + else if (Event.KEY_RETURN == e.keyCode) + this.handleFormSubmission(e); + }, + createControl: function(mode, handler, extraClasses) { + var control = this.options[mode + 'Control']; + var text = this.options[mode + 'Text']; + if ('button' == control) { + var btn = document.createElement('input'); + btn.type = 'submit'; + btn.value = text; + btn.className = 'editor_' + mode + '_button'; + if ('cancel' == mode) + btn.onclick = this._boundCancelHandler; + this._form.appendChild(btn); + this._controls[mode] = btn; + } else if ('link' == control) { + var link = document.createElement('a'); + link.href = '#'; + link.appendChild(document.createTextNode(text)); + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; + link.className = 'editor_' + mode + '_link'; + if (extraClasses) + link.className += ' ' + extraClasses; + this._form.appendChild(link); + this._controls[mode] = link; + } + }, + createEditField: function() { + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); + var fld; + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { + fld = document.createElement('input'); + fld.type = 'text'; + var size = this.options.size || this.options.cols || 0; + if (0 < size) fld.size = size; + } else { + fld = document.createElement('textarea'); + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); + fld.cols = this.options.cols || 40; + } + fld.name = this.options.paramName; + fld.value = text; // No HTML breaks conversion anymore + fld.className = 'editor_field'; + if (this.options.submitOnBlur) + fld.onblur = this._boundSubmitHandler; + this._controls.editor = fld; + if (this.options.loadTextURL) + this.loadExternalText(); + this._form.appendChild(this._controls.editor); + }, + createForm: function() { + var ipe = this; + function addText(mode, condition) { + var text = ipe.options['text' + mode + 'Controls']; + if (!text || condition === false) return; + ipe._form.appendChild(document.createTextNode(text)); + }; + this._form = $(document.createElement('form')); + this._form.id = this.options.formId; + this._form.addClassName(this.options.formClassName); + this._form.onsubmit = this._boundSubmitHandler; + this.createEditField(); + if ('textarea' == this._controls.editor.tagName.toLowerCase()) + this._form.appendChild(document.createElement('br')); + if (this.options.onFormCustomization) + this.options.onFormCustomization(this, this._form); + addText('Before', this.options.okControl || this.options.cancelControl); + this.createControl('ok', this._boundSubmitHandler); + addText('Between', this.options.okControl && this.options.cancelControl); + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); + addText('After', this.options.okControl || this.options.cancelControl); + }, + destroy: function() { + if (this._oldInnerHTML) + this.element.innerHTML = this._oldInnerHTML; + this.leaveEditMode(); + this.unregisterListeners(); + }, + enterEditMode: function(e) { + if (this._saving || this._editing) return; + this._editing = true; + this.triggerCallback('onEnterEditMode'); + if (this.options.externalControl) + this.options.externalControl.hide(); + this.element.hide(); + this.createForm(); + this.element.parentNode.insertBefore(this._form, this.element); + if (!this.options.loadTextURL) + this.postProcessEditField(); + if (e) Event.stop(e); + }, + enterHover: function(e) { + if (this.options.hoverClassName) + this.element.addClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onEnterHover'); + }, + getText: function() { + return this.element.innerHTML.unescapeHTML(); + }, + handleAJAXFailure: function(transport) { + this.triggerCallback('onFailure', transport); + if (this._oldInnerHTML) { + this.element.innerHTML = this._oldInnerHTML; + this._oldInnerHTML = null; + } + }, + handleFormCancellation: function(e) { + this.wrapUp(); + if (e) Event.stop(e); + }, + handleFormSubmission: function(e) { + var form = this._form; + var value = $F(this._controls.editor); + this.prepareSubmission(); + var params = this.options.callback(form, value) || ''; + if (Object.isString(params)) + params = params.toQueryParams(); + params.editorId = this.element.id; + if (this.options.htmlResponse) { + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Updater({ success: this.element }, this.url, options); + } else { + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.url, options); + } + if (e) Event.stop(e); + }, + leaveEditMode: function() { + this.element.removeClassName(this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + if (this.options.externalControl) + this.options.externalControl.show(); + this._saving = false; + this._editing = false; + this._oldInnerHTML = null; + this.triggerCallback('onLeaveEditMode'); + }, + leaveHover: function(e) { + if (this.options.hoverClassName) + this.element.removeClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onLeaveHover'); + }, + loadExternalText: function() { + this._form.addClassName(this.options.loadingClassName); + this._controls.editor.disabled = true; + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._form.removeClassName(this.options.loadingClassName); + var text = transport.responseText; + if (this.options.stripLoadedTextTags) + text = text.stripTags(); + this._controls.editor.value = text; + this._controls.editor.disabled = false; + this.postProcessEditField(); + }.bind(this), + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + postProcessEditField: function() { + var fpc = this.options.fieldPostCreation; + if (fpc) + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); + }, + prepareOptions: function() { + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); + [this._extraDefaultOptions].flatten().compact().each(function(defs) { + Object.extend(this.options, defs); + }.bind(this)); + }, + prepareSubmission: function() { + this._saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + registerListeners: function() { + this._listeners = { }; + var listener; + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { + listener = this[pair.value].bind(this); + this._listeners[pair.key] = listener; + if (!this.options.externalControlOnly) + this.element.observe(pair.key, listener); + if (this.options.externalControl) + this.options.externalControl.observe(pair.key, listener); + }.bind(this)); + }, + removeForm: function() { + if (!this._form) return; + this._form.remove(); + this._form = null; + this._controls = { }; + }, + showSaving: function() { + this._oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + this.element.addClassName(this.options.savingClassName); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + }, + triggerCallback: function(cbName, arg) { + if ('function' == typeof this.options[cbName]) { + this.options[cbName](this, arg); + } + }, + unregisterListeners: function() { + $H(this._listeners).each(function(pair) { + if (!this.options.externalControlOnly) + this.element.stopObserving(pair.key, pair.value); + if (this.options.externalControl) + this.options.externalControl.stopObserving(pair.key, pair.value); + }.bind(this)); + }, + wrapUp: function(transport) { + this.leaveEditMode(); + // Can't use triggerCallback due to backward compatibility: requires + // binding + direct element + this._boundComplete(transport, this.element); + } +}); + +Object.extend(Ajax.InPlaceEditor.prototype, { + dispose: Ajax.InPlaceEditor.prototype.destroy +}); + +Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { + initialize: function($super, element, url, options) { + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; + $super(element, url, options); + }, + + createEditField: function() { + var list = document.createElement('select'); + list.name = this.options.paramName; + list.size = 1; + this._controls.editor = list; + this._collection = this.options.collection || []; + if (this.options.loadCollectionURL) + this.loadCollection(); + else + this.checkForExternalText(); + this._form.appendChild(this._controls.editor); + }, + + loadCollection: function() { + this._form.addClassName(this.options.loadingClassName); + this.showLoadingText(this.options.loadingCollectionText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + var js = transport.responseText.strip(); + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check + throw('Server returned an invalid collection representation.'); + this._collection = eval(js); + this.checkForExternalText(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadCollectionURL, options); + }, + + showLoadingText: function(text) { + this._controls.editor.disabled = true; + var tempOption = this._controls.editor.firstChild; + if (!tempOption) { + tempOption = document.createElement('option'); + tempOption.value = ''; + this._controls.editor.appendChild(tempOption); + tempOption.selected = true; + } + tempOption.update((text || '').stripScripts().stripTags()); + }, + + checkForExternalText: function() { + this._text = this.getText(); + if (this.options.loadTextURL) + this.loadExternalText(); + else + this.buildOptionList(); + }, + + loadExternalText: function() { + this.showLoadingText(this.options.loadingText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._text = transport.responseText.strip(); + this.buildOptionList(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + + buildOptionList: function() { + this._form.removeClassName(this.options.loadingClassName); + this._collection = this._collection.map(function(entry) { + return 2 === entry.length ? entry : [entry, entry].flatten(); + }); + var marker = ('value' in this.options) ? this.options.value : this._text; + var textFound = this._collection.any(function(entry) { + return entry[0] == marker; + }.bind(this)); + this._controls.editor.update(''); + var option; + this._collection.each(function(entry, index) { + option = document.createElement('option'); + option.value = entry[0]; + option.selected = textFound ? entry[0] == marker : 0 == index; + option.appendChild(document.createTextNode(entry[1])); + this._controls.editor.appendChild(option); + }.bind(this)); + this._controls.editor.disabled = false; + Field.scrollFreeActivate(this._controls.editor); + } +}); + +//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** +//**** This only exists for a while, in order to let **** +//**** users adapt to the new API. Read up on the new **** +//**** API and convert your code to it ASAP! **** + +Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { + if (!options) return; + function fallback(name, expr) { + if (name in options || expr === undefined) return; + options[name] = expr; + }; + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : + options.cancelLink == options.cancelButton == false ? false : undefined))); + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : + options.okLink == options.okButton == false ? false : undefined))); + fallback('highlightColor', options.highlightcolor); + fallback('highlightEndColor', options.highlightendcolor); +}; + +Object.extend(Ajax.InPlaceEditor, { + DefaultOptions: { + ajaxOptions: { }, + autoRows: 3, // Use when multi-line w/ rows == 1 + cancelControl: 'link', // 'link'|'button'|false + cancelText: 'cancel', + clickToEditText: 'Click to edit', + externalControl: null, // id|elt + externalControlOnly: false, + fieldPostCreation: 'activate', // 'activate'|'focus'|false + formClassName: 'inplaceeditor-form', + formId: null, // id|elt + highlightColor: '#ffff99', + highlightEndColor: '#ffffff', + hoverClassName: '', + htmlResponse: true, + loadingClassName: 'inplaceeditor-loading', + loadingText: 'Loading...', + okControl: 'button', // 'link'|'button'|false + okText: 'ok', + paramName: 'value', + rows: 1, // If 1 and multi-line, uses autoRows + savingClassName: 'inplaceeditor-saving', + savingText: 'Saving...', + size: 0, + stripLoadedTextTags: false, + submitOnBlur: false, + textAfterControls: '', + textBeforeControls: '', + textBetweenControls: '' + }, + DefaultCallbacks: { + callback: function(form) { + return Form.serialize(form); + }, + onComplete: function(transport, element) { + // For backward compatibility, this one is bound to the IPE, and passes + // the element directly. It was too often customized, so we don't break it. + new Effect.Highlight(element, { + startcolor: this.options.highlightColor, keepBackgroundImage: true }); + }, + onEnterEditMode: null, + onEnterHover: function(ipe) { + ipe.element.style.backgroundColor = ipe.options.highlightColor; + if (ipe._effect) + ipe._effect.cancel(); + }, + onFailure: function(transport, ipe) { + alert('Error communication with the server: ' + transport.responseText.stripTags()); + }, + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. + onLeaveEditMode: null, + onLeaveHover: function(ipe) { + ipe._effect = new Effect.Highlight(ipe.element, { + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, + restorecolor: ipe._originalBackground, keepBackgroundImage: true + }); + } + }, + Listeners: { + click: 'enterEditMode', + keydown: 'checkForEscapeOrReturn', + mouseover: 'enterHover', + mouseout: 'leaveHover' + } +}); + +Ajax.InPlaceCollectionEditor.DefaultOptions = { + loadingCollectionText: 'Loading options...' +}; + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create({ + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}); \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e024de91ca039f46f93f26d8b35e2dac179b2d3a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e024de91ca039f46f93f26d8b35e2dac179b2d3a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,53 @@ +<% if @statuses.empty? or rows.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> +<% col_width = 70 / (@statuses.length+3) %> + + + +<% for status in @statuses %> + +<% end %> + + + + + +<% for row in rows %> +"> + + <% for status in @statuses %> + + <% end %> + + + + +<% end %> + +
    <%=h status.name %><%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to h(row.name), :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "status_id" => status.id }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "status_id" => status.id, + "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "o" %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "c" %><%= aggregate_link data, { field_name => row.id }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "*" %>
    +<% end + reset_cycle %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e03b3539b5eda7cb68bffc68e4f6d9f643e92475.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e03b3539b5eda7cb68bffc68e4f6d9f643e92475.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,707 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'wiki_controller' + +# Re-raise errors caught by the controller. +class WikiController; def rescue_action(e) raise e end; end + +class WikiControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, + :enabled_modules, :wikis, :wiki_pages, :wiki_contents, + :wiki_content_versions, :attachments + + def setup + @controller = WikiController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_show_start_page + get :show, :project_id => 'ecookbook' + assert_response :success + assert_template 'show' + assert_tag :tag => 'h1', :content => /CookBook documentation/ + + # child_pages macro + assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, + :child => { :tag => 'li', + :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, + :content => 'Page with an inline image' } } + end + + def test_export_link + Role.anonymous.add_permission! :export_wiki_pages + get :show, :project_id => 'ecookbook' + assert_response :success + assert_tag 'a', :attributes => {:href => '/projects/ecookbook/wiki/CookBook_documentation.txt'} + end + + def test_show_page_with_name + get :show, :project_id => 1, :id => 'Another_page' + assert_response :success + assert_template 'show' + assert_tag :tag => 'h1', :content => /Another page/ + # Included page with an inline image + assert_tag :tag => 'p', :content => /This is an inline image/ + assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3', + :alt => 'This is a logo' } + end + + def test_show_redirected_page + WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page') + + get :show, :project_id => 'ecookbook', :id => 'Old_title' + assert_redirected_to '/projects/ecookbook/wiki/Another_page' + end + + def test_show_with_sidebar + page = Project.find(1).wiki.pages.new(:title => 'Sidebar') + page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar') + page.save! + + get :show, :project_id => 1, :id => 'Another_page' + assert_response :success + assert_tag :tag => 'div', :attributes => {:id => 'sidebar'}, + :content => /Side bar content for test_show_with_sidebar/ + end + + def test_show_unexistent_page_without_edit_right + get :show, :project_id => 1, :id => 'Unexistent page' + assert_response 404 + end + + def test_show_should_display_section_edit_links + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Page with sections' + assert_no_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=1' + } + assert_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2' + } + assert_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=3' + } + end + + def test_show_current_version_should_display_section_edit_links + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Page with sections', :version => 3 + + assert_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2' + } + end + + def test_show_old_version_should_not_display_section_edit_links + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Page with sections', :version => 2 + + assert_no_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2' + } + end + + def test_show_unexistent_page_with_edit_right + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Unexistent page' + assert_response :success + assert_template 'edit' + end + + def test_create_page + @request.session[:user_id] = 2 + put :update, :project_id => 1, + :id => 'New page', + :content => {:comments => 'Created the page', + :text => "h1. New page\n\nThis is a new page", + :version => 0} + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page' + page = Project.find(1).wiki.find_page('New page') + assert !page.new_record? + assert_not_nil page.content + assert_equal 'Created the page', page.content.comments + end + + def test_create_page_with_attachments + @request.session[:user_id] = 2 + assert_difference 'WikiPage.count' do + assert_difference 'Attachment.count' do + put :update, :project_id => 1, + :id => 'New page', + :content => {:comments => 'Created the page', + :text => "h1. New page\n\nThis is a new page", + :version => 0}, + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} + end + end + page = Project.find(1).wiki.find_page('New page') + assert_equal 1, page.attachments.count + assert_equal 'testfile.txt', page.attachments.first.filename + end + + def test_edit_page + @request.session[:user_id] = 2 + get :edit, :project_id => 'ecookbook', :id => 'Another_page' + + assert_response :success + assert_template 'edit' + + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => WikiPage.find_by_title('Another_page').content.text + end + + def test_edit_section + @request.session[:user_id] = 2 + get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2 + + assert_response :success + assert_template 'edit' + + page = WikiPage.find_by_title('Page_with_sections') + section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2) + + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => section + assert_tag 'input', + :attributes => { :name => 'section', :type => 'hidden', :value => '2' } + assert_tag 'input', + :attributes => { :name => 'section_hash', :type => 'hidden', :value => hash } + end + + def test_edit_invalid_section_should_respond_with_404 + @request.session[:user_id] = 2 + get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10 + + assert_response 404 + end + + def test_update_page + @request.session[:user_id] = 2 + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, + :id => 'Another_page', + :content => { + :comments => "my comments", + :text => "edited", + :version => 1 + } + end + end + end + assert_redirected_to '/projects/ecookbook/wiki/Another_page' + + page = Wiki.find(1).pages.find_by_title('Another_page') + assert_equal "edited", page.content.text + assert_equal 2, page.content.version + assert_equal "my comments", page.content.comments + end + + def test_update_page_with_failure + @request.session[:user_id] = 2 + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_no_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, + :id => 'Another_page', + :content => { + :comments => 'a' * 300, # failure here, comment is too long + :text => 'edited', + :version => 1 + } + end + end + end + assert_response :success + assert_template 'edit' + + assert_error_tag :descendant => {:content => /Comment is too long/} + assert_tag :tag => 'textarea', :attributes => {:id => 'content_text'}, :content => 'edited' + assert_tag :tag => 'input', :attributes => {:id => 'content_version', :value => '1'} + end + + def test_update_stale_page_should_not_raise_an_error + @request.session[:user_id] = 2 + c = Wiki.find(1).find_page('Another_page').content + c.text = 'Previous text' + c.save! + assert_equal 2, c.version + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_no_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, + :id => 'Another_page', + :content => { + :comments => 'My comments', + :text => 'Text should not be lost', + :version => 1 + } + end + end + end + assert_response :success + assert_template 'edit' + assert_tag :div, + :attributes => { :class => /error/ }, + :content => /Data has been updated by another user/ + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => /Text should not be lost/ + assert_tag 'input', + :attributes => { :name => 'content[comments]', :value => 'My comments' } + + c.reload + assert_equal 'Previous text', c.text + assert_equal 2, c.version + end + + def test_update_section + @request.session[:user_id] = 2 + page = WikiPage.find_by_title('Page_with_sections') + section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2) + text = page.content.text + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, :id => 'Page_with_sections', + :content => { + :text => "New section content", + :version => 3 + }, + :section => 2, + :section_hash => hash + end + end + end + assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections' + assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text + end + + def test_update_section_should_allow_stale_page_update + @request.session[:user_id] = 2 + page = WikiPage.find_by_title('Page_with_sections') + section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2) + text = page.content.text + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, :id => 'Page_with_sections', + :content => { + :text => "New section content", + :version => 2 # Current version is 3 + }, + :section => 2, + :section_hash => hash + end + end + end + assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections' + page.reload + assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text + assert_equal 4, page.content.version + end + + def test_update_section_should_not_allow_stale_section_update + @request.session[:user_id] = 2 + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_no_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, :id => 'Page_with_sections', + :content => { + :comments => 'My comments', + :text => "Text should not be lost", + :version => 3 + }, + :section => 2, + :section_hash => Digest::MD5.hexdigest("wrong hash") + end + end + end + assert_response :success + assert_template 'edit' + assert_tag :div, + :attributes => { :class => /error/ }, + :content => /Data has been updated by another user/ + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => /Text should not be lost/ + assert_tag 'input', + :attributes => { :name => 'content[comments]', :value => 'My comments' } + end + + def test_preview + @request.session[:user_id] = 2 + xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation', + :content => { :comments => '', + :text => 'this is a *previewed text*', + :version => 3 } + assert_response :success + assert_template 'common/_preview' + assert_tag :tag => 'strong', :content => /previewed text/ + end + + def test_preview_new_page + @request.session[:user_id] = 2 + xhr :post, :preview, :project_id => 1, :id => 'New page', + :content => { :text => 'h1. New page', + :comments => '', + :version => 0 } + assert_response :success + assert_template 'common/_preview' + assert_tag :tag => 'h1', :content => /New page/ + end + + def test_history + get :history, :project_id => 1, :id => 'CookBook_documentation' + assert_response :success + assert_template 'history' + assert_not_nil assigns(:versions) + assert_equal 3, assigns(:versions).size + assert_select "input[type=submit][name=commit]" + end + + def test_history_with_one_version + get :history, :project_id => 1, :id => 'Another_page' + assert_response :success + assert_template 'history' + assert_not_nil assigns(:versions) + assert_equal 1, assigns(:versions).size + assert_select "input[type=submit][name=commit]", false + end + + def test_diff + get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => 2, :version_from => 1 + assert_response :success + assert_template 'diff' + assert_tag :tag => 'span', :attributes => { :class => 'diff_in'}, + :content => /updated/ + end + + def test_annotate + get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2 + assert_response :success + assert_template 'annotate' + + # Line 1 + assert_tag :tag => 'tr', :child => { + :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1', :sibling => { + :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/, :sibling => { + :tag => 'td', :content => /h1\. CookBook documentation/ + } + } + } + + # Line 5 + assert_tag :tag => 'tr', :child => { + :tag => 'th', :attributes => {:class => 'line-num'}, :content => '5', :sibling => { + :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/, :sibling => { + :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ + } + } + } + end + + def test_get_rename + @request.session[:user_id] = 2 + get :rename, :project_id => 1, :id => 'Another_page' + assert_response :success + assert_template 'rename' + assert_tag 'option', + :attributes => {:value => ''}, + :content => '', + :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}} + assert_no_tag 'option', + :attributes => {:selected => 'selected'}, + :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}} + end + + def test_get_rename_child_page + @request.session[:user_id] = 2 + get :rename, :project_id => 1, :id => 'Child_1' + assert_response :success + assert_template 'rename' + assert_tag 'option', + :attributes => {:value => ''}, + :content => '', + :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}} + assert_tag 'option', + :attributes => {:value => '2', :selected => 'selected'}, + :content => /Another page/, + :parent => { + :tag => 'select', + :attributes => {:name => 'wiki_page[parent_id]'} + } + end + + def test_rename_with_redirect + @request.session[:user_id] = 2 + post :rename, :project_id => 1, :id => 'Another_page', + :wiki_page => { :title => 'Another renamed page', + :redirect_existing_links => 1 } + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page' + wiki = Project.find(1).wiki + # Check redirects + assert_not_nil wiki.find_page('Another page') + assert_nil wiki.find_page('Another page', :with_redirect => false) + end + + def test_rename_without_redirect + @request.session[:user_id] = 2 + post :rename, :project_id => 1, :id => 'Another_page', + :wiki_page => { :title => 'Another renamed page', + :redirect_existing_links => "0" } + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page' + wiki = Project.find(1).wiki + # Check that there's no redirects + assert_nil wiki.find_page('Another page') + end + + def test_rename_with_parent_assignment + @request.session[:user_id] = 2 + post :rename, :project_id => 1, :id => 'Another_page', + :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' } + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page' + assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent + end + + def test_rename_with_parent_unassignment + @request.session[:user_id] = 2 + post :rename, :project_id => 1, :id => 'Child_1', + :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' } + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1' + assert_nil WikiPage.find_by_title('Child_1').parent + end + + def test_destroy_child + @request.session[:user_id] = 2 + delete :destroy, :project_id => 1, :id => 'Child_1' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + end + + def test_destroy_parent + @request.session[:user_id] = 2 + assert_no_difference('WikiPage.count') do + delete :destroy, :project_id => 1, :id => 'Another_page' + end + assert_response :success + assert_template 'destroy' + end + + def test_destroy_parent_with_nullify + @request.session[:user_id] = 2 + assert_difference('WikiPage.count', -1) do + delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify' + end + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert_nil WikiPage.find_by_id(2) + end + + def test_destroy_parent_with_cascade + @request.session[:user_id] = 2 + assert_difference('WikiPage.count', -3) do + delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy' + end + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert_nil WikiPage.find_by_id(2) + assert_nil WikiPage.find_by_id(5) + end + + def test_destroy_parent_with_reassign + @request.session[:user_id] = 2 + assert_difference('WikiPage.count', -1) do + delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1 + end + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert_nil WikiPage.find_by_id(2) + assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent + end + + def test_index + get :index, :project_id => 'ecookbook' + assert_response :success + assert_template 'index' + pages = assigns(:pages) + assert_not_nil pages + assert_equal Project.find(1).wiki.pages.size, pages.size + assert_equal pages.first.content.updated_on, pages.first.updated_on + + assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, + :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' }, + :content => 'CookBook documentation' }, + :child => { :tag => 'ul', + :child => { :tag => 'li', + :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, + :content => 'Page with an inline image' } } } }, + :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' }, + :content => 'Another page' } } + end + + def test_index_should_include_atom_link + get :index, :project_id => 'ecookbook' + assert_tag 'a', :attributes => { :href => '/projects/ecookbook/activity.atom?show_wiki_edits=1'} + end + + context "GET :export" do + context "with an authorized user to export the wiki" do + setup do + @request.session[:user_id] = 2 + get :export, :project_id => 'ecookbook' + end + + should_respond_with :success + should_assign_to :pages + should_respond_with_content_type "text/html" + should "export all of the wiki pages to a single html file" do + assert_select "a[name=?]", "CookBook_documentation" + assert_select "a[name=?]", "Another_page" + assert_select "a[name=?]", "Page_with_an_inline_image" + end + + end + + context "with an unauthorized user" do + setup do + get :export, :project_id => 'ecookbook' + + should_respond_with :redirect + should_redirect_to('wiki index') { {:action => 'show', :project_id => @project, :id => nil} } + end + end + end + + context "GET :date_index" do + setup do + get :date_index, :project_id => 'ecookbook' + end + + should_respond_with :success + should_assign_to :pages + should_assign_to :pages_by_date + should_render_template 'wiki/date_index' + + should "include atom link" do + assert_tag 'a', :attributes => { :href => '/projects/ecookbook/activity.atom?show_wiki_edits=1'} + end + end + + def test_not_found + get :show, :project_id => 999 + assert_response 404 + end + + def test_protect_page + page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page') + assert !page.protected? + @request.session[:user_id] = 2 + post :protect, :project_id => 1, :id => page.title, :protected => '1' + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page' + assert page.reload.protected? + end + + def test_unprotect_page + page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation') + assert page.protected? + @request.session[:user_id] = 2 + post :protect, :project_id => 1, :id => page.title, :protected => '0' + assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation' + assert !page.reload.protected? + end + + def test_show_page_with_edit_link + @request.session[:user_id] = 2 + get :show, :project_id => 1 + assert_response :success + assert_template 'show' + assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } + end + + def test_show_page_without_edit_link + @request.session[:user_id] = 4 + get :show, :project_id => 1 + assert_response :success + assert_template 'show' + assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } + end + + def test_show_pdf + @request.session[:user_id] = 2 + get :show, :project_id => 1, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:page) + assert_equal 'application/pdf', @response.content_type + assert_equal 'attachment; filename="CookBook_documentation.pdf"', + @response.headers['Content-Disposition'] + end + + def test_show_html + @request.session[:user_id] = 2 + get :show, :project_id => 1, :format => 'html' + assert_response :success + assert_not_nil assigns(:page) + assert_equal 'text/html', @response.content_type + assert_equal 'attachment; filename="CookBook_documentation.html"', + @response.headers['Content-Disposition'] + end + + def test_show_txt + @request.session[:user_id] = 2 + get :show, :project_id => 1, :format => 'txt' + assert_response :success + assert_not_nil assigns(:page) + assert_equal 'text/plain', @response.content_type + assert_equal 'attachment; filename="CookBook_documentation.txt"', + @response.headers['Content-Disposition'] + end + + def test_edit_unprotected_page + # Non members can edit unprotected wiki pages + @request.session[:user_id] = 4 + get :edit, :project_id => 1, :id => 'Another_page' + assert_response :success + assert_template 'edit' + end + + def test_edit_protected_page_by_nonmember + # Non members can't edit protected wiki pages + @request.session[:user_id] = 4 + get :edit, :project_id => 1, :id => 'CookBook_documentation' + assert_response 403 + end + + def test_edit_protected_page_by_member + @request.session[:user_id] = 2 + get :edit, :project_id => 1, :id => 'CookBook_documentation' + assert_response :success + assert_template 'edit' + end + + def test_history_of_non_existing_page_should_return_404 + get :history, :project_id => 1, :id => 'Unknown_page' + assert_response 404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e05aa95bf99a3917bb79c084e2f744f98528a8e7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e05aa95bf99a3917bb79c084e2f744f98528a8e7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,505 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'repositories_controller' + +# Re-raise errors caught by the controller. +class RepositoriesController; def rescue_action(e) raise e end; end + +class RepositoriesMercurialControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules + + REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s + CHAR_1_HEX = "\xc3\x9c" + PRJ_ID = 3 + NUM_REV = 32 + + ruby19_non_utf8_pass = + (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8') + + def setup + @controller = RepositoriesController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @project = Project.find(PRJ_ID) + @repository = Repository::Mercurial.create( + :project => @project, + :url => REPOSITORY_PATH, + :path_encoding => 'ISO-8859-1' + ) + assert @repository + @diff_c_support = true + @char_1 = CHAR_1_HEX.dup + @tag_char_1 = "tag-#{CHAR_1_HEX}-00" + @branch_char_0 = "branch-#{CHAR_1_HEX}-00" + @branch_char_1 = "branch-#{CHAR_1_HEX}-01" + if @char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + @tag_char_1.force_encoding('UTF-8') + @branch_char_0.force_encoding('UTF-8') + @branch_char_1.force_encoding('UTF-8') + end + end + + if ruby19_non_utf8_pass + puts "TODO: Mercurial functional test fails in Ruby 1.9 " + + "and Encoding.default_external is not UTF-8. " + + "Current value is '#{Encoding.default_external.to_s}'" + def test_fake; assert true end + elsif File.directory?(REPOSITORY_PATH) + def test_show_root + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal 4, assigns(:entries).size + assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} + assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_show_directory + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID, :path => ['images'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name) + entry = assigns(:entries).detect {|e| e.name == 'edit.png'} + assert_not_nil entry + assert_equal 'file', entry.kind + assert_equal 'images/edit.png', entry.path + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + + def test_show_at_given_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [0, '0', '0885933ad4f6'].each do |r1| + get :show, :id => PRJ_ID, :path => ['images'], :rev => r1 + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert_equal ['delete.png'], assigns(:entries).collect(&:name) + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + end + + def test_show_directory_sql_escape_percent + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [13, '13', '3a330eb32958'].each do |r1| + get :show, :id => PRJ_ID, :path => ['sql_escape', 'percent%dir'], + :rev => r1 + assert_response :success + assert_template 'show' + + assert_not_nil assigns(:entries) + assert_equal ['percent%file1.txt', 'percentfile1.txt'], + assigns(:entries).collect(&:name) + changesets = assigns(:changesets) + assert_not_nil changesets + assert assigns(:changesets).size > 0 + assert_equal %w(13 11 10 9), changesets.collect(&:revision) + end + end + + def test_show_directory_latin_1_path + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [21, '21', 'adf805632193'].each do |r1| + get :show, :id => PRJ_ID, :path => ['latin-1-dir'], :rev => r1 + assert_response :success + assert_template 'show' + + assert_not_nil assigns(:entries) + assert_equal ["make-latin-1-file.rb", + "test-#{@char_1}-1.txt", + "test-#{@char_1}-2.txt", + "test-#{@char_1}.txt"], assigns(:entries).collect(&:name) + changesets = assigns(:changesets) + assert_not_nil changesets + assert_equal %w(21 20 19 18 17), changesets.collect(&:revision) + end + end + + def test_show_branch + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [ + 'default', + @branch_char_1, + 'branch (1)[2]&,%.-3_4', + @branch_char_0, + 'test_branch.latin-1', + 'test-branch-00', + ].each do |bra| + get :show, :id => PRJ_ID, :rev => bra + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert assigns(:entries).size > 0 + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + end + + def test_show_tag + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [ + @tag_char_1, + 'tag_test.00', + 'tag-init-revision' + ].each do |tag| + get :show, :id => PRJ_ID, :rev => tag + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entries) + assert assigns(:entries).size > 0 + assert_not_nil assigns(:changesets) + assert assigns(:changesets).size > 0 + end + end + + def test_changes + get :changes, :id => PRJ_ID, :path => ['images', 'edit.png'] + assert_response :success + assert_template 'changes' + assert_tag :tag => 'h2', :content => 'edit.png' + end + + def test_entry_show + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'entry' + # Line 10 + assert_tag :tag => 'th', + :content => '10', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } + end + + def test_entry_show_latin_1_path + [21, '21', 'adf805632193'].each do |r1| + get :entry, :id => PRJ_ID, + :path => ['latin-1-dir', "test-#{@char_1}-2.txt"], :rev => r1 + assert_response :success + assert_template 'entry' + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', + :content => /Mercurial is a distributed version control system/ } + end + end + + def test_entry_show_latin_1_contents + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + [27, '27', '7bbf4c738e71'].each do |r1| + get :entry, :id => PRJ_ID, + :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1 + assert_response :success + assert_template 'entry' + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', + :content => /test-#{@char_1}.txt/ } + end + end + end + + def test_entry_download + get :entry, :id => PRJ_ID, + :path => ['sources', 'watchers_controller.rb'], :format => 'raw' + assert_response :success + # File content + assert @response.body.include?('WITHOUT ANY WARRANTY') + end + + def test_entry_binary_force_download + get :entry, :id => PRJ_ID, :rev => 1, :path => ['images', 'edit.png'] + assert_response :success + assert_equal 'image/png', @response.content_type + end + + def test_directory_entry + get :entry, :id => PRJ_ID, :path => ['sources'] + assert_response :success + assert_template 'show' + assert_not_nil assigns(:entry) + assert_equal 'sources', assigns(:entry).name + end + + def test_diff + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [4, '4', 'def6d2f1254a'].each do |r1| + # Full diff of changeset 4 + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => r1, :type => dt + assert_response :success + assert_template 'diff' + if @diff_c_support + # Line 22 removed + assert_tag :tag => 'th', + :content => '22', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /def remove/ } + assert_tag :tag => 'h2', :content => /4:def6d2f1254a/ + end + end + end + end + + def test_diff_two_revs + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [2, '400bb8672109', '400', 400].each do |r1| + [4, 'def6d2f1254a'].each do |r2| + ['inline', 'sbs'].each do |dt| + get :diff, + :id => PRJ_ID, + :rev => r1, + :rev_to => r2, + :type => dt + assert_response :success + assert_template 'diff' + diff = assigns(:diff) + assert_not_nil diff + assert_tag :tag => 'h2', + :content => /4:def6d2f1254a 2:400bb8672109/ + end + end + end + end + + def test_diff_latin_1_path + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + [21, 'adf805632193'].each do |r1| + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => r1, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'thead', + :descendant => { + :tag => 'th', + :attributes => { :class => 'filename' } , + :content => /latin-1-dir\/test-#{@char_1}-2.txt/ , + }, + :sibling => { + :tag => 'tbody', + :descendant => { + :tag => 'td', + :attributes => { :class => /diff_in/ }, + :content => /It is written in Python/ + } + } + end + end + end + end + + def test_annotate + get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'annotate' + # Line 23, revision 4:def6d2f1254a + assert_tag :tag => 'th', + :content => '23', + :attributes => { :class => 'line-num' }, + :sibling => + { + :tag => 'td', + :attributes => { :class => 'revision' }, + :child => { :tag => 'a', :content => '4:def6d2f1254a' } + } + assert_tag :tag => 'th', + :content => '23', + :attributes => { :class => 'line-num' }, + :sibling => + { + :tag => 'td' , + :content => 'jsmith' , + :attributes => { :class => 'author' }, + } + assert_tag :tag => 'th', + :content => '23', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /watcher =/ } + end + + def test_annotate_not_in_tip + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :annotate, :id => PRJ_ID, + :path => ['sources', 'welcome_controller.rb'] + assert_response 404 + assert_error_tag :content => /was not found/ + end + + def test_annotate_at_given_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + [2, '400bb8672109', '400', 400].each do |r1| + get :annotate, :id => PRJ_ID, :rev => r1, + :path => ['sources', 'watchers_controller.rb'] + assert_response :success + assert_template 'annotate' + assert_tag :tag => 'h2', :content => /@ 2:400bb8672109/ + end + end + + def test_annotate_latin_1_path + [21, '21', 'adf805632193'].each do |r1| + get :annotate, :id => PRJ_ID, + :path => ['latin-1-dir', "test-#{@char_1}-2.txt"], :rev => r1 + assert_response :success + assert_template 'annotate' + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => + { + :tag => 'td', + :attributes => { :class => 'revision' }, + :child => { :tag => 'a', :content => '20:709858aafd1b' } + } + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => + { + :tag => 'td' , + :content => 'jsmith' , + :attributes => { :class => 'author' }, + } + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', + :content => /Mercurial is a distributed version control system/ } + + end + end + + def test_annotate_latin_1_contents + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + [27, '7bbf4c738e71'].each do |r1| + get :annotate, :id => PRJ_ID, + :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1 + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', + :content => /test-#{@char_1}.txt/ } + end + end + end + + def test_empty_revision + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['', ' ', nil].each do |r| + get :revision, :id => PRJ_ID, :rev => r + assert_response 404 + assert_error_tag :content => /was not found/ + end + end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Mercurial.create( + :project => Project.find(PRJ_ID), + :url => "/invalid", + :path_encoding => 'ISO-8859-1' + ) + assert @repository + @repository.fetch_changesets + @project.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + else + puts "Mercurial test repository NOT FOUND. Skipping functional tests !!!" + def test_fake; assert true end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e06c6b7247c11f5c7b45c36ab3ee4c82d2c34951.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e06c6b7247c11f5c7b45c36ab3ee4c82d2c34951.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,164 @@ +--- +users_004: + created_on: 2006-07-19 19:34:07 +02:00 + status: 1 + last_login_on: + language: en + # password = foo + salt: 3126f764c3c5ac61cbfc103f25f934cf + hashed_password: 9e4dd7eeb172c12a0691a6d9d3a269f7e9fe671b + updated_on: 2006-07-19 19:34:07 +02:00 + admin: false + mail: rhill@somenet.foo + lastname: Hill + firstname: Robert + id: 4 + auth_source_id: + mail_notification: all + login: rhill + type: User +users_001: + created_on: 2006-07-19 19:12:21 +02:00 + status: 1 + last_login_on: 2006-07-19 22:57:52 +02:00 + language: en + # password = admin + salt: 82090c953c4a0000a7db253b0691a6b4 + hashed_password: b5b6ff9543bf1387374cdfa27a54c96d236a7150 + updated_on: 2006-07-19 22:57:52 +02:00 + admin: true + mail: admin@somenet.foo + lastname: Admin + firstname: redMine + id: 1 + auth_source_id: + mail_notification: all + login: admin + type: User +users_002: + created_on: 2006-07-19 19:32:09 +02:00 + status: 1 + last_login_on: 2006-07-19 22:42:15 +02:00 + language: en + # password = jsmith + salt: 67eb4732624d5a7753dcea7ce0bb7d7d + hashed_password: bfbe06043353a677d0215b26a5800d128d5413bc + updated_on: 2006-07-19 22:42:15 +02:00 + admin: false + mail: jsmith@somenet.foo + lastname: Smith + firstname: John + id: 2 + auth_source_id: + mail_notification: all + login: jsmith + type: User +users_003: + created_on: 2006-07-19 19:33:19 +02:00 + status: 1 + last_login_on: + language: en + # password = foo + salt: 7599f9963ec07b5a3b55b354407120c0 + hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: dlopper@somenet.foo + lastname: Lopper + firstname: Dave + id: 3 + auth_source_id: + mail_notification: all + login: dlopper + type: User +users_005: + id: 5 + created_on: 2006-07-19 19:33:19 +02:00 + # Locked + status: 3 + last_login_on: + language: en + hashed_password: 1 + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: dlopper2@somenet.foo + lastname: Lopper2 + firstname: Dave2 + auth_source_id: + mail_notification: all + login: dlopper2 + type: User +users_006: + id: 6 + created_on: 2006-07-19 19:33:19 +02:00 + status: 0 + last_login_on: + language: '' + hashed_password: 1 + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: '' + lastname: Anonymous + firstname: '' + auth_source_id: + mail_notification: only_my_events + login: '' + type: AnonymousUser +users_007: + id: 7 + created_on: 2006-07-19 19:33:19 +02:00 + status: 1 + last_login_on: + language: '' + hashed_password: 1 + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: someone@foo.bar + lastname: One + firstname: Some + auth_source_id: + mail_notification: only_my_events + login: someone + type: User +users_008: + id: 8 + created_on: 2006-07-19 19:33:19 +02:00 + status: 1 + last_login_on: + language: 'it' + hashed_password: 1 + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: miscuser8@foo.bar + lastname: Misc + firstname: User + auth_source_id: + mail_notification: only_my_events + login: miscuser8 + type: User +users_009: + id: 9 + created_on: 2006-07-19 19:33:19 +02:00 + status: 1 + last_login_on: + language: 'it' + hashed_password: 1 + updated_on: 2006-07-19 19:33:19 +02:00 + admin: false + mail: miscuser9@foo.bar + lastname: Misc + firstname: User + auth_source_id: + mail_notification: only_my_events + login: miscuser9 + type: User +groups_010: + id: 10 + lastname: A Team + type: Group +groups_011: + id: 11 + lastname: B Team + type: Group + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e0d8ddb4de157f5d746d18c71ff6aa4fb77eab1a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e0d8ddb4de157f5d746d18c71ff6aa4fb77eab1a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class User < Principal + generator_for :login, :start => 'user1' + generator_for :mail, :method => :next_email + generator_for :firstname, :start => 'Bob' + generator_for :lastname, :start => 'Doe' + + def self.next_email + @last_email ||= 'user1' + @last_email.succ! + "#{@last_email}@example.com" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e0/e0ded1cb3e9db9162722719b443602d020469fa5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e0/e0ded1cb3e9db9162722719b443602d020469fa5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,59 @@ +

    <%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %>

    +

    <%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %>

    + +
    +<% @events_by_day.keys.sort.reverse.each do |day| %> +

    <%= format_activity_day(day) %>

    +
    +<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> +
    + <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %> + <%= format_time(e.event_datetime, false) %> + <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> + <%= link_to format_activity_title(e.event_title), e.event_url %>
    +
    <%= format_activity_description(e.event_description) %> + <%= link_to_user(e.event_author) if e.respond_to?(:event_author) %>
    +<% end -%> +
    +<% end -%> +
    + +<%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %> + +
    +<%= link_to_content_update("\xc2\xab " + l(:label_previous), + params.merge(:from => @date_to - @days - 1), + :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))) %> +
    +
    +<%= link_to_content_update(l(:label_next) + " \xc2\xbb", + params.merge(:from => @date_to + @days - 1), + :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))) unless @date_to >= Date.today %> +
    +  +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %> +<% end %> + +<% content_for :sidebar do %> +<% form_tag({}, :method => :get) do %> +

    <%= l(:label_activity) %>

    +

    <% @activity.event_types.each do |t| %> +<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> + +
    +<% end %>

    +<% if @project && @project.descendants.active.any? %> + <%= hidden_field_tag 'with_subprojects', 0 %> +

    +<% end %> +<%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %> +

    <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %>

    +<% end %> +<% end %> + +<% html_title(l(:label_activity), @author) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e107366c1a6751ac8fc0593f4fc17da1868e7064.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e107366c1a6751ac8fc0593f4fc17da1868e7064.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,510 @@ +# -*- coding: utf-8 -*- +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'timelog_controller' + +# Re-raise errors caught by the controller. +class TimelogController; def rescue_action(e) raise e end; end + +class TimelogControllerTest < ActionController::TestCase + fixtures :projects, :enabled_modules, :roles, :members, + :member_roles, :issues, :time_entries, :users, + :trackers, :enumerations, :issue_statuses, + :custom_fields, :custom_values + + include Redmine::I18n + + def setup + @controller = TimelogController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_get_new + @request.session[:user_id] = 3 + get :new, :project_id => 1 + assert_response :success + assert_template 'edit' + # Default activity selected + assert_tag :tag => 'option', :attributes => { :selected => 'selected' }, + :content => 'Development' + end + + def test_get_new_should_only_show_active_time_entry_activities + @request.session[:user_id] = 3 + get :new, :project_id => 1 + assert_response :success + assert_template 'edit' + assert_no_tag :tag => 'option', :content => 'Inactive Activity' + end + + def test_get_edit_existing_time + @request.session[:user_id] = 2 + get :edit, :id => 2, :project_id => nil + assert_response :success + assert_template 'edit' + # Default activity selected + assert_tag :tag => 'form', :attributes => { :action => '/projects/ecookbook/time_entries/2' } + end + + def test_get_edit_with_an_existing_time_entry_with_inactive_activity + te = TimeEntry.find(1) + te.activity = TimeEntryActivity.find_by_name("Inactive Activity") + te.save! + + @request.session[:user_id] = 1 + get :edit, :project_id => 1, :id => 1 + assert_response :success + assert_template 'edit' + # Blank option since nothing is pre-selected + assert_tag :tag => 'option', :content => '--- Please select ---' + end + + def test_post_create + # TODO: should POST to issues’ time log instead of project. change form + # and routing + @request.session[:user_id] = 3 + post :create, :project_id => 1, + :time_entry => {:comments => 'Some work on TimelogControllerTest', + # Not the default activity + :activity_id => '11', + :spent_on => '2008-03-14', + :issue_id => '1', + :hours => '7.3'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + + i = Issue.find(1) + t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') + assert_not_nil t + assert_equal 11, t.activity_id + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + assert_equal i, t.issue + assert_equal i.project, t.project + end + + def test_post_create_with_blank_issue + # TODO: should POST to issues’ time log instead of project. change form + # and routing + @request.session[:user_id] = 3 + post :create, :project_id => 1, + :time_entry => {:comments => 'Some work on TimelogControllerTest', + # Not the default activity + :activity_id => '11', + :issue_id => '', + :spent_on => '2008-03-14', + :hours => '7.3'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + + t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') + assert_not_nil t + assert_equal 11, t.activity_id + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + end + + def test_create_without_log_time_permission_should_be_denied + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :log_time + post :create, :project_id => 1, + :time_entry => {:activity_id => '11', + :issue_id => '', + :spent_on => '2008-03-14', + :hours => '7.3'} + + assert_response 403 + end + + def test_update + entry = TimeEntry.find(1) + assert_equal 1, entry.issue_id + assert_equal 2, entry.user_id + + @request.session[:user_id] = 1 + put :update, :id => 1, + :time_entry => {:issue_id => '2', + :hours => '8'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + entry.reload + + assert_equal 8, entry.hours + assert_equal 2, entry.issue_id + assert_equal 2, entry.user_id + end + + def test_get_bulk_edit + @request.session[:user_id] = 2 + get :bulk_edit, :ids => [1, 2] + assert_response :success + assert_template 'bulk_edit' + + # System wide custom field + assert_tag :select, :attributes => {:name => 'time_entry[custom_field_values][10]'} + end + + def test_get_bulk_edit_on_different_projects + @request.session[:user_id] = 2 + get :bulk_edit, :ids => [1, 2, 6] + assert_response :success + assert_template 'bulk_edit' + end + + def test_bulk_update + @request.session[:user_id] = 2 + # update time entry activity + post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9} + + assert_response 302 + # check that the issues were updated + assert_equal [9, 9], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.activity_id} + end + + def test_bulk_update_on_different_projects + @request.session[:user_id] = 2 + # makes user a manager on the other project + Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1]) + + # update time entry activity + post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 } + + assert_response 302 + # check that the issues were updated + assert_equal [9, 9, 9], TimeEntry.find_all_by_id([1, 2, 4]).collect {|i| i.activity_id} + end + + def test_bulk_update_on_different_projects_without_rights + @request.session[:user_id] = 3 + user = User.find(3) + action = { :controller => "timelog", :action => "bulk_update" } + assert user.allowed_to?(action, TimeEntry.find(1).project) + assert ! user.allowed_to?(action, TimeEntry.find(5).project) + post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 } + assert_response 403 + end + + def test_bulk_update_custom_field + @request.session[:user_id] = 2 + post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} } + + assert_response 302 + assert_equal ["0", "0"], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.custom_value_for(10).value} + end + + def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter + @request.session[:user_id] = 2 + post :bulk_update, :ids => [1,2], :back_url => '/time_entries' + + assert_response :redirect + assert_redirected_to '/time_entries' + end + + def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host + @request.session[:user_id] = 2 + post :bulk_update, :ids => [1,2], :back_url => 'http://google.com' + + assert_response :redirect + assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier + end + + def test_post_bulk_update_without_edit_permission_should_be_denied + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :edit_time_entries + post :bulk_update, :ids => [1,2] + + assert_response 403 + end + + def test_destroy + @request.session[:user_id] = 2 + delete :destroy, :id => 1 + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert_equal I18n.t(:notice_successful_delete), flash[:notice] + assert_nil TimeEntry.find_by_id(1) + end + + def test_destroy_should_fail + # simulate that this fails (e.g. due to a plugin), see #5700 + TimeEntry.any_instance.expects(:destroy).returns(false) + + @request.session[:user_id] = 2 + delete :destroy, :id => 1 + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error] + assert_not_nil TimeEntry.find_by_id(1) + end + + def test_index_all_projects + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:total_hours) + assert_equal "162.90", "%.2f" % assigns(:total_hours) + assert_tag :form, + :attributes => {:action => "/time_entries", :id => 'query_form'} + end + + def test_index_at_project_level + get :index, :project_id => 'ecookbook' + assert_response :success + assert_template 'index' + assert_not_nil assigns(:entries) + assert_equal 4, assigns(:entries).size + # project and subproject + assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort + assert_not_nil assigns(:total_hours) + assert_equal "162.90", "%.2f" % assigns(:total_hours) + # display all time by default + assert_equal '2007-03-12'.to_date, assigns(:from) + assert_equal '2007-04-22'.to_date, assigns(:to) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} + end + + def test_index_at_project_level_with_date_range + get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30' + assert_response :success + assert_template 'index' + assert_not_nil assigns(:entries) + assert_equal 3, assigns(:entries).size + assert_not_nil assigns(:total_hours) + assert_equal "12.90", "%.2f" % assigns(:total_hours) + assert_equal '2007-03-20'.to_date, assigns(:from) + assert_equal '2007-04-30'.to_date, assigns(:to) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} + end + + def test_index_at_project_level_with_period + get :index, :project_id => 'ecookbook', :period => '7_days' + assert_response :success + assert_template 'index' + assert_not_nil assigns(:entries) + assert_not_nil assigns(:total_hours) + assert_equal Date.today - 7, assigns(:from) + assert_equal Date.today, assigns(:to) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} + end + + def test_index_one_day + get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => "2007-03-23" + assert_response :success + assert_template 'index' + assert_not_nil assigns(:total_hours) + assert_equal "4.25", "%.2f" % assigns(:total_hours) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} + end + + def test_index_at_issue_level + get :index, :issue_id => 1 + assert_response :success + assert_template 'index' + assert_not_nil assigns(:entries) + assert_equal 2, assigns(:entries).size + assert_not_nil assigns(:total_hours) + assert_equal 154.25, assigns(:total_hours) + # display all time based on what's been logged + assert_equal '2007-03-12'.to_date, assigns(:from) + assert_equal '2007-04-22'.to_date, assigns(:to) + # TODO: remove /projects/:project_id/issues/:issue_id/time_entries routes + # to use /issues/:issue_id/time_entries + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/issues/1/time_entries", :id => 'query_form'} + end + + def test_index_atom_feed + get :index, :project_id => 1, :format => 'atom' + assert_response :success + assert_equal 'application/atom+xml', @response.content_type + assert_not_nil assigns(:items) + assert assigns(:items).first.is_a?(TimeEntry) + end + + def test_index_all_projects_csv_export + Setting.date_format = '%m/%d/%Y' + get :index, :format => 'csv' + assert_response :success + assert_equal 'text/csv', @response.content_type + assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n") + assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n") + end + + def test_index_csv_export + Setting.date_format = '%m/%d/%Y' + get :index, :project_id => 1, :format => 'csv' + assert_response :success + assert_equal 'text/csv', @response.content_type + assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n") + assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n") + end + + def test_csv_big_5 + user = User.find_by_id(3) + user.language = "zh-TW" + assert user.save + str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88" + str_big5 = "\xa4@\xa4\xeb" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + str_big5.force_encoding('Big5') + end + @request.session[:user_id] = 3 + post :create, :project_id => 1, + :time_entry => {:comments => str_utf8, + # Not the default activity + :activity_id => '11', + :issue_id => '', + :spent_on => '2011-11-10', + :hours => '7.3'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + + t = TimeEntry.find_by_comments(str_utf8) + assert_not_nil t + assert_equal 11, t.activity_id + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + ar = @response.body.chomp.split("\n") + s1 = "\xa4\xe9\xb4\xc1" + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert ar[0].include?(s1) + assert ar[1].include?(str_big5) + end + + def test_csv_cannot_convert_should_be_replaced_big_5 + user = User.find_by_id(3) + user.language = "zh-TW" + assert user.save + str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + end + @request.session[:user_id] = 3 + post :create, :project_id => 1, + :time_entry => {:comments => str_utf8, + # Not the default activity + :activity_id => '11', + :issue_id => '', + :spent_on => '2011-11-10', + :hours => '7.3'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + + t = TimeEntry.find_by_comments(str_utf8) + assert_not_nil t + assert_equal 11, t.activity_id + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + ar = @response.body.chomp.split("\n") + s1 = "\xa4\xe9\xb4\xc1" + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert ar[0].include?(s1) + s2 = ar[1].split(",")[8] + if s2.respond_to?(:force_encoding) + s3 = "\xa5H?" + s3.force_encoding('Big5') + assert_equal s3, s2 + elsif RUBY_PLATFORM == 'java' + assert_equal "??", s2 + else + assert_equal "\xa5H???", s2 + end + end + + def test_csv_tw + with_settings :default_language => "zh-TW" do + str1 = "test_csv_tw" + user = User.find_by_id(3) + te1 = TimeEntry.create(:spent_on => '2011-11-10', + :hours => 999.9, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => str1) + te2 = TimeEntry.find_by_comments(str1) + assert_not_nil te2 + assert_equal 999.9, te2.hours + assert_equal 3, te2.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + + ar = @response.body.chomp.split("\n") + s2 = ar[1].split(",")[7] + assert_equal '999.9', s2 + + str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)" + if str_tw.respond_to?(:force_encoding) + str_tw.force_encoding('UTF-8') + end + assert_equal str_tw, l(:general_lang_name) + assert_equal ',', l(:general_csv_separator) + assert_equal '.', l(:general_csv_decimal_separator) + end + end + + def test_csv_fr + with_settings :default_language => "fr" do + str1 = "test_csv_fr" + user = User.find_by_id(3) + te1 = TimeEntry.create(:spent_on => '2011-11-10', + :hours => 999.9, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => str1) + te2 = TimeEntry.find_by_comments(str1) + assert_not_nil te2 + assert_equal 999.9, te2.hours + assert_equal 3, te2.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + + ar = @response.body.chomp.split("\n") + s2 = ar[1].split(";")[7] + assert_equal '999,9', s2 + + str_fr = "Fran\xc3\xa7ais" + if str_fr.respond_to?(:force_encoding) + str_fr.force_encoding('UTF-8') + end + assert_equal str_fr, l(:general_lang_name) + assert_equal ';', l(:general_csv_separator) + assert_equal ',', l(:general_csv_decimal_separator) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e11cf7d34a74b2639bd351484ee891dbd76b4d76.svn-base Binary file .svn/pristine/e1/e11cf7d34a74b2639bd351484ee891dbd76b4d76.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e11e4b4f0c5381a061b098e00586564872bd5c98.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e11e4b4f0c5381a061b098e00586564872bd5c98.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Principal < ActiveRecord::Base + set_table_name "#{table_name_prefix}users#{table_name_suffix}" + + has_many :members, :foreign_key => 'user_id', :dependent => :destroy + has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name" + has_many :projects, :through => :memberships + has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify + + # Groups and active users + named_scope :active, :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status = 1)" + + named_scope :like, lambda {|q| + s = "%#{q.to_s.strip.downcase}%" + {:conditions => ["LOWER(login) LIKE :s OR LOWER(firstname) LIKE :s OR LOWER(lastname) LIKE :s OR LOWER(mail) LIKE :s", {:s => s}], + :order => 'type, login, lastname, firstname, mail' + } + } + + before_create :set_default_empty_values + + def name(formatter = nil) + to_s + end + + def <=>(principal) + if self.class.name == principal.class.name + self.to_s.downcase <=> principal.to_s.downcase + else + # groups after users + principal.class.name <=> self.class.name + end + end + + protected + + # Make sure we don't try to insert NULL values (see #4632) + def set_default_empty_values + self.login ||= '' + self.hashed_password ||= '' + self.firstname ||= '' + self.lastname ||= '' + self.mail ||= '' + true + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e13d4eff8ef6e4c2192ff1fb6a6cfbcfa8709f65.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e13d4eff8ef6e4c2192ff1fb6a6cfbcfa8709f65.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,304 @@ +# encoding: utf-8 +require 'test/unit' +require File.expand_path('../../lib/assert_warning', __FILE__) + +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +class BasicTest < Test::Unit::TestCase + + def test_version + assert_nothing_raised do + assert_match(/\A\d\.\d\.\d?\z/, CodeRay::VERSION) + end + end + + RUBY_TEST_CODE = 'puts "Hello, World!"' + + RUBY_TEST_TOKENS = [ + ['puts', :ident], + [' ', :space], + [:begin_group, :string], + ['"', :delimiter], + ['Hello, World!', :content], + ['"', :delimiter], + [:end_group, :string] + ].flatten + def test_simple_scan + assert_nothing_raised do + assert_equal RUBY_TEST_TOKENS, CodeRay.scan(RUBY_TEST_CODE, :ruby).tokens + end + end + + RUBY_TEST_HTML = 'puts "' + + 'Hello, World!"' + def test_simple_highlight + assert_nothing_raised do + assert_equal RUBY_TEST_HTML, CodeRay.scan(RUBY_TEST_CODE, :ruby).html + end + end + + def test_scan_file + CodeRay.scan_file __FILE__ + end + + def test_encode + assert_equal 1, CodeRay.encode('test', :python, :count) + end + + def test_encode_tokens + assert_equal 1, CodeRay.encode_tokens(CodeRay::Tokens['test', :string], :count) + end + + def test_encode_file + assert_equal File.read(__FILE__), CodeRay.encode_file(__FILE__, :text) + end + + def test_highlight + assert_match '
    test
    ', CodeRay.highlight('test', :python) + end + + def test_highlight_file + assert_match "require 'test/unit'\n", CodeRay.highlight_file(__FILE__) + end + + def test_duo + assert_equal(RUBY_TEST_CODE, + CodeRay::Duo[:plain, :text].highlight(RUBY_TEST_CODE)) + assert_equal(RUBY_TEST_CODE, + CodeRay::Duo[:plain => :text].highlight(RUBY_TEST_CODE)) + end + + def test_duo_stream + assert_equal(RUBY_TEST_CODE, + CodeRay::Duo[:plain, :text].highlight(RUBY_TEST_CODE, :stream => true)) + end + + def test_comment_filter + assert_equal <<-EXPECTED, CodeRay.scan(<<-INPUT, :ruby).comment_filter.text +#!/usr/bin/env ruby + +code + +more code + EXPECTED +#!/usr/bin/env ruby +=begin +A multi-line comment. +=end +code +# A single-line comment. +more code # and another comment, in-line. + INPUT + end + + def test_lines_of_code + assert_equal 2, CodeRay.scan(<<-INPUT, :ruby).lines_of_code +#!/usr/bin/env ruby +=begin +A multi-line comment. +=end +code +# A single-line comment. +more code # and another comment, in-line. + INPUT + rHTML = <<-RHTML + + + + + + <%= controller.controller_name.titleize %>: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +

    <%= flash[:notice] %>

    + +
    + <%= yield %> +
    + + + + RHTML + assert_equal 0, CodeRay.scan(rHTML, :html).lines_of_code + assert_equal 0, CodeRay.scan(rHTML, :php).lines_of_code + assert_equal 0, CodeRay.scan(rHTML, :yaml).lines_of_code + assert_equal 4, CodeRay.scan(rHTML, :erb).lines_of_code + end + + def test_list_of_encoders + assert_kind_of(Array, CodeRay::Encoders.list) + assert CodeRay::Encoders.list.include?(:count) + end + + def test_list_of_scanners + assert_kind_of(Array, CodeRay::Scanners.list) + assert CodeRay::Scanners.list.include?(:text) + end + + def test_token_kinds + assert_kind_of Hash, CodeRay::TokenKinds + for kind, css_class in CodeRay::TokenKinds + assert_kind_of Symbol, kind + if css_class != false + assert_kind_of String, css_class, "TokenKinds[%p] == %p" % [kind, css_class] + end + end + assert_equal 'reserved', CodeRay::TokenKinds[:reserved] + assert_warning 'Undefined Token kind: :shibboleet' do + assert_equal false, CodeRay::TokenKinds[:shibboleet] + end + end + + class Milk < CodeRay::Encoders::Encoder + FILE_EXTENSION = 'cocoa' + end + + class HoneyBee < CodeRay::Encoders::Encoder + end + + def test_encoder_file_extension + assert_nothing_raised do + assert_equal 'html', CodeRay::Encoders::Page::FILE_EXTENSION + assert_equal 'cocoa', Milk::FILE_EXTENSION + assert_equal 'cocoa', Milk.new.file_extension + assert_equal 'honeybee', HoneyBee::FILE_EXTENSION + assert_equal 'honeybee', HoneyBee.new.file_extension + end + assert_raise NameError do + HoneyBee::MISSING_CONSTANT + end + end + + def test_encoder_tokens + encoder = CodeRay::Encoders::Encoder.new + encoder.send :setup, {} + assert_raise(ArgumentError) { encoder.token :strange, '' } + encoder.token 'test', :debug + end + + def test_encoder_deprecated_interface + encoder = CodeRay::Encoders::Encoder.new + encoder.send :setup, {} + assert_warning 'Using old Tokens#<< interface.' do + encoder << ['test', :content] + end + assert_raise ArgumentError do + encoder << [:strange, :input] + end + assert_raise ArgumentError do + encoder.encode_tokens [['test', :token]] + end + end + + def encoder_token_interface_deprecation_warning_given + CodeRay::Encoders::Encoder.send :class_variable_get, :@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN + end + + def test_scanner_file_extension + assert_equal 'rb', CodeRay::Scanners::Ruby.file_extension + assert_equal 'rb', CodeRay::Scanners::Ruby.new.file_extension + assert_equal 'java', CodeRay::Scanners::Java.file_extension + assert_equal 'java', CodeRay::Scanners::Java.new.file_extension + end + + def test_scanner_lang + assert_equal :ruby, CodeRay::Scanners::Ruby.lang + assert_equal :ruby, CodeRay::Scanners::Ruby.new.lang + assert_equal :java, CodeRay::Scanners::Java.lang + assert_equal :java, CodeRay::Scanners::Java.new.lang + end + + def test_scanner_tokenize + assert_equal ['foo', :plain], CodeRay::Scanners::Plain.new.tokenize('foo') + assert_equal [['foo', :plain], ['bar', :plain]], CodeRay::Scanners::Plain.new.tokenize(['foo', 'bar']) + CodeRay::Scanners::Plain.new.tokenize 42 + end + + def test_scanner_tokens + scanner = CodeRay::Scanners::Plain.new + scanner.tokenize('foo') + assert_equal ['foo', :plain], scanner.tokens + scanner.string = '' + assert_equal ['', :plain], scanner.tokens + end + + def test_scanner_line_and_column + scanner = CodeRay::Scanners::Plain.new "foo\nbär+quux" + assert_equal 0, scanner.pos + assert_equal 1, scanner.line + assert_equal 1, scanner.column + scanner.scan(/foo/) + assert_equal 3, scanner.pos + assert_equal 1, scanner.line + assert_equal 4, scanner.column + scanner.scan(/\n/) + assert_equal 4, scanner.pos + assert_equal 2, scanner.line + assert_equal 1, scanner.column + scanner.scan(/b/) + assert_equal 5, scanner.pos + assert_equal 2, scanner.line + assert_equal 2, scanner.column + scanner.scan(/a/) + assert_equal 5, scanner.pos + assert_equal 2, scanner.line + assert_equal 2, scanner.column + scanner.scan(/ä/) + assert_equal 7, scanner.pos + assert_equal 2, scanner.line + assert_equal 4, scanner.column + scanner.scan(/r/) + assert_equal 8, scanner.pos + assert_equal 2, scanner.line + assert_equal 5, scanner.column + end + + def test_scanner_use_subclasses + assert_raise NotImplementedError do + CodeRay::Scanners::Scanner.new + end + end + + class InvalidScanner < CodeRay::Scanners::Scanner + end + + def test_scanner_scan_tokens + assert_raise NotImplementedError do + InvalidScanner.new.tokenize '' + end + end + + class RaisingScanner < CodeRay::Scanners::Scanner + def scan_tokens encoder, options + raise_inspect 'message', [], :initial + end + end + + def test_scanner_raise_inspect + assert_raise CodeRay::Scanners::Scanner::ScanError do + RaisingScanner.new.tokenize '' + end + end + + def test_scan_a_frozen_string + assert_nothing_raised do + CodeRay.scan RUBY_VERSION, :ruby + CodeRay.scan RUBY_VERSION, :plain + end + end + + def test_scan_a_non_string + assert_nothing_raised do + CodeRay.scan 42, :ruby + CodeRay.scan nil, :ruby + CodeRay.scan self, :ruby + CodeRay.encode ENV.to_hash, :ruby, :page + CodeRay.highlight CodeRay, :plain + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e140ffeb12ccebdeac6bae46d7abe6d081f9bac4.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e140ffeb12ccebdeac6bae46d7abe6d081f9bac4.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,64 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %>

    + +<% if !@entries.nil? && authorize_for('repositories', 'browse') %> +<%= render :partial => 'dir_list' %> +<% end %> + +<%= render_properties(@properties) %> + +<% if authorize_for('repositories', 'revisions') %> +<% if @changesets && !@changesets.empty? %> +

    <%= l(:label_latest_revision_plural) %>

    +<%= render :partial => 'revisions', + :locals => {:project => @project, :path => @path, + :revisions => @changesets, :entry => nil }%> +<% end %> +

    +<% + has_branches = (!@repository.branches.nil? && @repository.branches.length > 0) + sep = '' + %> +<% if @repository.supports_all_revisions? && @path.blank? %> +<%= link_to l(:label_view_all_revisions), :action => 'revisions', :id => @project %> +<% sep = '|' %> +<% end %> +<% + if @repository.supports_directory_revisions? && + ( has_branches || !@path.blank? || !@rev.blank? ) + %> +<%= sep %> +<%= + link_to l(:label_view_revisions), + :action => 'changes', + :path => to_path_param(@path), + :id => @project, + :rev => @rev + %> +<% end %> +

    + +<% if true # @path.blank? %> +<% content_for :header_tags do %> + <%= auto_discovery_link_tag( + :atom, params.merge( + {:format => 'atom', :action => 'revisions', + :id => @project, :page => nil, :key => User.current.rss_key})) %> +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %> +<% end %> +<% end %> +<% end %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title(l(:label_repository)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e17ca0541629d2464b57fcb96cfe91d5da5a7317.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e17ca0541629d2464b57fcb96cfe91d5da5a7317.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,76 @@ +TCPDFFontDescriptor.define('freesansbi') do |font| + font[:type]='TrueTypeUnicode'; + font[:name]='FreeSansBoldOblique'; + font[:desc]={'Ascent'=>979,'Descent'=>-309,'CapHeight'=>979,'Flags'=>96,'FontBBox'=>'[-379 -309 1283 979]','ItalicAngle'=>-12,'StemV'=>120,'MissingWidth'=>600}; + font[:up]=-111; + font[:ut]=69; + font[:cw]={ + 13=>333, 32=>278, 33=>333, 34=>474, 35=>556, 36=>556, 37=>889, 38=>722, 39=>238, 40=>333, 41=>333, 42=>389, 43=>584, 44=>278, 45=>333, 46=>278, + 47=>278, 48=>556, 49=>556, 50=>556, 51=>556, 52=>556, 53=>556, 54=>556, 55=>556, 56=>556, 57=>556, 58=>333, 59=>333, 60=>584, 61=>584, 62=>584, + 63=>611, 64=>975, 65=>722, 66=>722, 67=>722, 68=>722, 69=>667, 70=>611, 71=>778, 72=>722, 73=>278, 74=>556, 75=>722, 76=>611, 77=>833, 78=>722, + 79=>778, 80=>667, 81=>778, 82=>722, 83=>667, 84=>611, 85=>722, 86=>667, 87=>944, 88=>667, 89=>667, 90=>611, 91=>333, 92=>278, 93=>333, 94=>584, + 95=>556, 96=>333, 97=>556, 98=>611, 99=>556, 100=>611, 101=>556, 102=>333, 103=>611, 104=>611, 105=>278, 106=>278, 107=>556, 108=>278, 109=>889, 110=>611, + 111=>611, 112=>611, 113=>611, 114=>389, 115=>556, 116=>333, 117=>611, 118=>556, 119=>778, 120=>556, 121=>556, 122=>500, 123=>389, 124=>280, 125=>389, 126=>584, + 8364=>556, 1027=>611, 8218=>278, 402=>556, 8222=>500, 8230=>1000, 8224=>556, 8225=>556, 710=>333, 8240=>1000, 352=>667, 8249=>333, 338=>1000, 1036=>722, 381=>611, 1039=>722, + 8216=>278, 8217=>278, 8220=>500, 8221=>500, 8226=>350, 8211=>556, 8212=>1000, 732=>333, 8482=>1000, 353=>556, 8250=>333, 339=>944, 1116=>556, 382=>500, 376=>667, 161=>333, + 162=>556, 163=>556, 164=>556, 165=>556, 166=>280, 167=>556, 168=>333, 169=>737, 170=>370, 171=>556, 172=>584, 174=>737, 175=>333, 176=>606, 177=>584, 178=>444, + 179=>444, 180=>333, 181=>611, 182=>556, 183=>278, 184=>333, 185=>444, 186=>365, 187=>556, 188=>1055, 189=>1055, 190=>1055, 191=>611, 192=>722, 193=>722, 194=>722, + 195=>722, 196=>722, 197=>722, 198=>1000, 199=>722, 200=>667, 201=>667, 202=>667, 203=>667, 204=>278, 205=>278, 206=>278, 207=>278, 208=>722, 209=>722, 210=>778, + 211=>778, 212=>778, 213=>778, 214=>778, 215=>584, 216=>778, 217=>722, 218=>722, 219=>722, 220=>722, 221=>667, 222=>667, 223=>611, 224=>556, 225=>556, 226=>556, + 227=>556, 228=>556, 229=>556, 230=>889, 231=>556, 232=>556, 233=>556, 234=>556, 235=>556, 236=>278, 237=>278, 238=>278, 239=>278, 240=>611, 241=>611, 242=>611, + 243=>611, 244=>611, 245=>611, 246=>611, 247=>584, 248=>611, 249=>611, 250=>611, 251=>611, 252=>611, 253=>556, 254=>611, 255=>556, 256=>722, 257=>556, 258=>722, + 259=>556, 260=>722, 261=>556, 262=>722, 263=>556, 264=>722, 265=>556, 266=>722, 267=>556, 268=>722, 269=>556, 270=>722, 271=>722, 272=>722, 273=>611, 274=>667, + 275=>556, 276=>667, 277=>556, 278=>667, 279=>556, 280=>667, 281=>556, 282=>667, 283=>556, 284=>778, 285=>611, 286=>778, 287=>611, 288=>778, 289=>611, 290=>778, + 291=>611, 292=>722, 293=>611, 294=>722, 295=>611, 296=>278, 297=>278, 298=>278, 299=>278, 300=>278, 301=>278, 302=>278, 303=>268, 304=>278, 305=>278, 306=>278, + 307=>278, 308=>556, 309=>278, 310=>722, 311=>556, 312=>529, 313=>611, 314=>278, 315=>611, 316=>278, 317=>611, 318=>384, 319=>611, 320=>556, 321=>611, 322=>278, + 323=>722, 324=>611, 325=>722, 326=>611, 327=>722, 328=>611, 329=>611, 330=>722, 331=>611, 332=>778, 333=>611, 334=>778, 335=>611, 336=>778, 337=>611, 340=>722, + 341=>389, 342=>722, 343=>389, 344=>722, 345=>389, 346=>667, 347=>556, 348=>667, 349=>556, 350=>667, 351=>556, 354=>611, 355=>333, 356=>611, 357=>404, 358=>611, + 359=>333, 360=>722, 361=>611, 362=>722, 363=>611, 364=>722, 365=>611, 366=>722, 367=>611, 368=>722, 369=>611, 370=>722, 371=>611, 372=>944, 373=>778, 374=>667, + 375=>556, 377=>611, 378=>500, 379=>611, 380=>500, 383=>333, 536=>667, 537=>556, 538=>611, 539=>333, 711=>333, 728=>333, 729=>333, 730=>333, 731=>333, 733=>333, + 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 774=>0, 775=>0, 776=>0, 778=>0, 779=>0, 780=>0, 783=>0, 785=>0, 787=>0, 788=>0, 884=>208, + 885=>247, 890=>364, 894=>333, 900=>308, 901=>446, 902=>688, 903=>418, 904=>642, 905=>743, 906=>228, 908=>754, 910=>736, 911=>743, 912=>346, 913=>764, 914=>688, + 915=>642, 916=>744, 917=>710, 918=>688, 919=>743, 920=>810, 921=>296, 922=>744, 923=>744, 924=>860, 925=>714, 926=>690, 927=>822, 928=>781, 929=>698, 931=>688, + 932=>688, 933=>744, 934=>777, 935=>783, 936=>805, 937=>780, 938=>296, 939=>744, 940=>640, 941=>530, 942=>597, 943=>339, 944=>575, 945=>656, 946=>576, 947=>591, + 948=>620, 949=>570, 950=>522, 951=>586, 952=>586, 953=>346, 954=>576, 955=>620, 956=>667, 957=>564, 958=>530, 959=>610, 960=>721, 961=>626, 962=>595, 963=>676, + 964=>592, 965=>575, 966=>801, 967=>632, 968=>722, 969=>800, 970=>346, 971=>575, 972=>609, 973=>604, 974=>769, 1024=>666, 1025=>666, 1026=>790, 1028=>722, 1029=>667, + 1030=>278, 1031=>278, 1032=>556, 1033=>1110, 1034=>1088, 1035=>790, 1037=>722, 1038=>718, 1040=>722, 1041=>722, 1042=>723, 1043=>611, 1044=>918, 1045=>666, 1046=>1054, 1047=>659, + 1048=>722, 1049=>722, 1050=>720, 1051=>722, 1052=>843, 1053=>722, 1054=>778, 1055=>722, 1056=>649, 1057=>837, 1058=>611, 1059=>698, 1060=>902, 1061=>664, 1062=>730, 1063=>671, + 1064=>1101, 1065=>1179, 1066=>816, 1067=>939, 1068=>639, 1069=>737, 1070=>1080, 1071=>690, 1072=>554, 1073=>611, 1074=>621, 1075=>475, 1076=>804, 1077=>552, 1078=>775, 1079=>556, + 1080=>636, 1081=>636, 1082=>529, 1083=>608, 1084=>697, 1085=>636, 1086=>611, 1087=>636, 1088=>611, 1089=>554, 1090=>454, 1091=>552, 1092=>989, 1093=>554, 1094=>690, 1095=>606, + 1096=>934, 1097=>987, 1098=>741, 1099=>839, 1100=>619, 1101=>575, 1102=>908, 1103=>636, 1104=>552, 1105=>552, 1106=>606, 1107=>454, 1108=>556, 1109=>556, 1110=>278, 1111=>278, + 1112=>278, 1113=>900, 1114=>611, 1115=>606, 1117=>636, 1118=>556, 1119=>636, 1164=>639, 1165=>619, 1166=>649, 1167=>611, 1168=>611, 1169=>454, 1170=>611, 1171=>475, 1172=>611, + 1173=>475, 1174=>1054, 1175=>775, 1176=>659, 1177=>556, 1178=>720, 1179=>529, 1180=>720, 1181=>529, 1182=>720, 1183=>529, 1184=>720, 1185=>529, 1186=>722, 1187=>636, 1188=>722, + 1189=>636, 1190=>722, 1191=>636, 1192=>837, 1193=>554, 1194=>837, 1195=>554, 1196=>611, 1197=>454, 1198=>667, 1199=>556, 1200=>667, 1201=>556, 1202=>664, 1203=>554, 1204=>730, + 1205=>690, 1206=>671, 1207=>606, 1208=>671, 1209=>606, 1210=>671, 1211=>606, 1212=>837, 1213=>554, 1214=>837, 1215=>554, 1216=>278, 1217=>1054, 1218=>775, 1219=>720, 1220=>529, + 1223=>722, 1224=>636, 1227=>671, 1228=>606, 1232=>722, 1233=>554, 1234=>722, 1235=>554, 1236=>1000, 1237=>889, 1238=>666, 1239=>552, 1240=>837, 1241=>554, 1242=>837, 1243=>554, + 1244=>1054, 1245=>775, 1246=>659, 1247=>556, 1248=>659, 1249=>556, 1250=>722, 1251=>636, 1252=>722, 1253=>636, 1254=>778, 1255=>611, 1256=>778, 1257=>611, 1258=>778, 1259=>611, + 1260=>737, 1261=>575, 1262=>698, 1263=>552, 1264=>698, 1265=>552, 1266=>698, 1267=>552, 1268=>671, 1269=>606, 1272=>939, 1273=>839, 1456=>82, 1457=>347, 1458=>341, 1459=>341, + 1460=>82, 1461=>211, 1462=>211, 1463=>200, 1464=>200, 1465=>82, 1467=>341, 1468=>82, 1469=>82, 1470=>516, 1471=>200, 1472=>297, 1473=>1038, 1474=>1038, 1475=>333, 1476=>82, + 1488=>714, 1489=>651, 1490=>557, 1491=>638, 1492=>682, 1493=>297, 1494=>443, 1495=>682, 1496=>670, 1497=>284, 1498=>590, 1499=>595, 1500=>667, 1501=>683, 1502=>704, 1503=>297, + 1504=>429, 1505=>670, 1506=>653, 1507=>661, 1508=>660, 1509=>616, 1510=>671, 1511=>672, 1512=>600, 1513=>840, 1514=>756, 1520=>554, 1521=>550, 1522=>542, 1523=>238, 1524=>474, + 7936=>656, 7937=>656, 7938=>656, 7939=>656, 7940=>656, 7941=>656, 7942=>656, 7943=>656, 7944=>764, 7945=>764, 7946=>764, 7947=>764, 7948=>764, 7949=>764, 7950=>764, 7951=>764, + 7952=>570, 7953=>570, 7954=>570, 7955=>570, 7956=>570, 7957=>570, 7960=>710, 7961=>710, 7962=>710, 7963=>710, 7964=>710, 7965=>710, 7968=>586, 7969=>586, 7970=>586, 7971=>586, + 7972=>586, 7973=>586, 7974=>586, 7975=>586, 7976=>743, 7977=>743, 7978=>743, 7979=>743, 7980=>743, 7981=>743, 7982=>743, 7983=>743, 7984=>346, 7985=>346, 7986=>346, 7987=>346, + 7988=>346, 7989=>346, 7990=>346, 7991=>346, 7992=>296, 7993=>296, 7994=>296, 7995=>296, 7996=>296, 7997=>296, 7998=>296, 7999=>296, 8000=>610, 8001=>610, 8002=>610, 8003=>610, + 8004=>610, 8005=>610, 8008=>822, 8009=>822, 8010=>822, 8011=>822, 8012=>822, 8013=>822, 8016=>575, 8017=>575, 8018=>575, 8019=>575, 8020=>575, 8021=>575, 8022=>575, 8023=>575, + 8025=>744, 8027=>744, 8029=>744, 8031=>744, 8032=>800, 8033=>800, 8034=>800, 8035=>800, 8036=>800, 8037=>800, 8038=>800, 8039=>800, 8040=>780, 8041=>780, 8042=>780, 8043=>780, + 8044=>780, 8045=>780, 8046=>780, 8047=>780, 8048=>656, 8049=>656, 8050=>570, 8051=>570, 8052=>586, 8053=>586, 8054=>346, 8055=>346, 8056=>610, 8057=>610, 8058=>575, 8059=>575, + 8060=>800, 8061=>800, 8064=>656, 8065=>656, 8066=>656, 8067=>656, 8068=>656, 8069=>656, 8070=>656, 8071=>656, 8072=>1007, 8073=>1007, 8074=>1007, 8075=>1007, 8076=>1007, 8077=>1007, + 8078=>1007, 8079=>1007, 8080=>586, 8081=>586, 8082=>586, 8083=>586, 8084=>586, 8085=>586, 8086=>586, 8087=>586, 8088=>986, 8089=>986, 8090=>986, 8091=>986, 8092=>986, 8093=>986, + 8094=>986, 8095=>986, 8096=>800, 8097=>800, 8098=>800, 8099=>800, 8100=>800, 8101=>800, 8102=>800, 8103=>800, 8104=>1023, 8105=>1023, 8106=>1023, 8107=>1023, 8108=>1023, 8109=>1023, + 8110=>1023, 8111=>1023, 8112=>656, 8113=>656, 8114=>656, 8115=>656, 8116=>640, 8118=>656, 8119=>656, 8120=>764, 8121=>764, 8122=>764, 8123=>764, 8124=>1007, 8125=>278, 8126=>201, + 8127=>147, 8128=>278, 8129=>333, 8130=>586, 8131=>586, 8132=>597, 8134=>586, 8135=>586, 8136=>710, 8137=>710, 8138=>743, 8139=>743, 8140=>986, 8141=>402, 8142=>403, 8143=>147, + 8144=>346, 8145=>346, 8146=>346, 8147=>346, 8150=>346, 8151=>346, 8152=>296, 8153=>296, 8154=>296, 8155=>296, 8157=>434, 8158=>433, 8159=>333, 8160=>575, 8161=>575, 8162=>575, + 8163=>575, 8164=>626, 8165=>626, 8166=>575, 8167=>575, 8168=>744, 8169=>744, 8173=>333, 8174=>351, 8175=>303, 8182=>800, 8183=>800, 8184=>822, 8185=>822, 8186=>780, 8187=>780, + 8188=>1023, 8189=>333, 8190=>159, 8260=>167, 8263=>1222, 8264=>944, 8265=>944, 8362=>1049, 8706=>490, 8710=>729, 8721=>711, 8722=>584, 8730=>542, 8800=>584, 8804=>584, 8805=>584, + 9674=>489, 63033=>556, 63034=>556, 63035=>556, 63036=>556, 63037=>556, 63038=>556, 63039=>556, 63040=>556, 63041=>556, 63166=>278, 63171=>333, 63196=>556, 64256=>666, 64257=>611, 64258=>611, + 64259=>944, 64260=>944, 64261=>666, 64262=>889, 64285=>284, 64286=>305, 64287=>542, 64288=>653, 64289=>964, 64290=>888, 64291=>932, 64292=>845, 64293=>917, 64294=>933, 64295=>850, 64296=>1006, + 64297=>584, 64298=>840, 64299=>840, 64300=>840, 64301=>840, 64302=>714, 64303=>714, 64304=>714, 64305=>651, 64306=>557, 64307=>638, 64308=>682, 64309=>367, 64310=>443, 64312=>670, 64313=>354, + 64314=>590, 64315=>595, 64316=>667, 64318=>704, 64320=>429, 64321=>670, 64323=>661, 64324=>660, 64326=>671, 64327=>672, 64328=>600, 64329=>840, 64330=>756, 64331=>297, 64332=>651, 64333=>595, + 64334=>660, 64335=>714}; + font[:enc]=''; + font[:diff]=''; + font[:file]='FreeSansBoldOblique.z'; + font[:ctg]='FreeSansBoldOblique.ctg.z'; + font[:originalsize]=95508; +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e199d0c76f6f203be690378ec8e723334e3b28db.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e199d0c76f6f203be690378ec8e723334e3b28db.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,298 @@ +module Core::RFPDF + COLOR_PALETTE = { + :black => [0x00, 0x00, 0x00], + :white => [0xff, 0xff, 0xff], + }.freeze + + # Draw a circle at (mid_x, mid_y) with radius. + # + # Options are: + # * :border - Draw a border, 0 = no, 1 = yes? Default value is 1. + # * :border_color - Default value is COLOR_PALETTE[:black]. + # * :border_width - Default value is 0.5. + # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. + # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. + # * :fill_colorspace - Default value is :rgb or ''. + # + # Example: + # + # draw_circle(x, y, radius, :border_color => ReportHelper::COLOR_PALETTE[:dark_blue], :border_width => 1) + # + def draw_circle(mid_x, mid_y, radius, options = {}) + options[:border] ||= 1 + options[:border_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:border_width] ||= 0.5 + options[:fill] ||= 1 + options[:fill_color] ||= Core::RFPDF::COLOR_PALETTE[:white] + options[:fill_colorspace] ||= :rgb + SetLineWidth(options[:border_width]) + set_draw_color_a(options[:border_color]) + set_fill_color_a(options[:fill_color], options[:colorspace]) + fd = "" + fd = "D" if options[:border] == 1 + fd += "F" if options[:fill] == 1 + Circle(mid_x, mid_y, radius, fd) + end + + # Draw a line from (x1, y1) to (x2, y2). + # + # Options are: + # * :line_color - Default value is COLOR_PALETTE[:black]. + # * :line_width - Default value is 0.5. + # + # Example: + # + # draw_line(x1, y1, x1, y1+h, :line_color => ReportHelper::COLOR_PALETTE[:dark_blue], :line_width => 1) + # + def draw_line(x1, y1, x2, y2, options = {}) + options[:line_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:line_width] ||= 0.5 + set_draw_color_a(options[:line_color]) + SetLineWidth(options[:line_width]) + Line(x1, y1, x2, y2) + end + + # Draw a string of text at (x, y). + # + # Options are: + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is 10. + # * :font_style - Default value is nothing or ''. + # * :colorspace - Default value is :rgb or ''. + # + # Example: + # + # draw_text(x, y, header_left, :font_size => 10) + # + def draw_text(x, y, text, options = {}) + options[:font_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:font] ||= default_font + options[:font_size] ||= 10 + options[:font_style] ||= '' + set_text_color_a(options[:font_color], options[:colorspace]) + SetFont(options[:font], options[:font_style], options[:font_size]) + SetXY(x, y) + Write(options[:font_size] + 4, text) + end + + # Draw a block of text at (x, y) bounded by left_margin and right_margin_from_right_edge. Both + # margins are measured from their corresponding edge. + # + # Options are: + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is 10. + # * :font_style - Default value is nothing or ''. + # * :colorspace - Default value is :rgb or ''. + # + # Example: + # + # draw_text_block(left_margin, 85, "question", left_margin, 280, + # :font_color => ReportHelper::COLOR_PALETTE[:dark_blue], + # :font_size => 12, + # :font_style => 'I') + # + def draw_text_block(x, y, text, left_margin, right_margin_from_right_edge, options = {}) + options[:font] ||= default_font + options[:font_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:font_size] ||= 10 + options[:font_style] ||= '' + set_text_color_a(options[:font_color], options[:colorspace]) + SetFont(options[:font], options[:font_style], options[:font_size]) + SetXY(x, y) + SetLeftMargin(left_margin) + SetRightMargin(right_margin_from_right_edge) + Write(options[:font_size] + 4, text) + SetMargins(0,0,0) + end + + # Draw a box at (x, y), w wide and h high. + # + # Options are: + # * :border - Draw a border, 0 = no, 1 = yes? Default value is 1. + # * :border_color - Default value is COLOR_PALETTE[:black]. + # * :border_width - Default value is 0.5. + # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. + # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. + # * :fill_colorspace - Default value is :rgb or ''. + # + # Example: + # + # draw_box(x, y - 1, 38, 22) + # + def draw_box(x, y, w, h, options = {}) + options[:border] ||= 1 + options[:border_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:border_width] ||= 0.5 + options[:fill] ||= 1 + options[:fill_color] ||= Core::RFPDF::COLOR_PALETTE[:white] + options[:fill_colorspace] ||= :rgb + SetLineWidth(options[:border_width]) + set_draw_color_a(options[:border_color]) + set_fill_color_a(options[:fill_color], options[:fill_colorspace]) + fd = "" + fd = "D" if options[:border] == 1 + fd += "F" if options[:fill] == 1 + Rect(x, y, w, h, fd) + end + + # Draw a string of text at (x, y) in a box w wide and h high. + # + # Options are: + # * :align - Vertical alignment 'C' = center, 'L' = left, 'R' = right. Default value is 'C'. + # * :border - Draw a border, 0 = no, 1 = yes? Default value is 0. + # * :border_color - Default value is COLOR_PALETTE[:black]. + # * :border_width - Default value is 0.5. + # * :fill - Fill the box, 0 = no, 1 = yes? Default value is 1. + # * :fill_color - Default value is nothing or COLOR_PALETTE[:white]. + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is nothing or 8. + # * :font_style - 'B' = bold, 'I' = italic, 'U' = underline. Default value is nothing ''. + # * :padding - Default value is nothing or 2. + # * :x_padding - Default value is nothing. + # * :valign - 'M' = middle, 'T' = top, 'B' = bottom. Default value is nothing or 'M'. + # * :colorspace - Default value is :rgb or ''. + # + # Example: + # + # draw_text_box(x, y - 1, 38, 22, + # "your_score_title", + # :fill => 0, + # :font_color => ReportHelper::COLOR_PALETTE[:blue], + # :font_line_spacing => 0, + # :font_style => "B", + # :valign => "M") + # + def draw_text_box(x, y, w, h, text, options = {}) + options[:align] ||= 'C' + options[:border] ||= 0 + options[:border_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:border_width] ||= 0.5 + options[:fill] ||= 1 + options[:fill_color] ||= Core::RFPDF::COLOR_PALETTE[:white] + options[:font] ||= default_font + options[:font_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:font_size] ||= 8 + options[:font_line_spacing] ||= options[:font_size] * 0.3 + options[:font_style] ||= '' + options[:padding] ||= 2 + options[:x_padding] ||= 0 + options[:valign] ||= "M" + if options[:fill] == 1 or options[:border] == 1 + draw_box(x, y, w, h, options) + end + SetMargins(0,0,0) + set_text_color_a(options[:font_color], options[:colorspace]) + font_size = options[:font_size] + SetFont(options[:font], options[:font_style], font_size) + font_size += options[:font_line_spacing] + case options[:valign] + when "B", "bottom" + y -= options[:padding] + when "T", "top" + y += options[:padding] + end + case options[:align] + when "L", "left" + x += options[:x_padding] + w -= options[:x_padding] + w -= options[:x_padding] + when "R", "right" + x += options[:x_padding] + w -= options[:x_padding] + w -= options[:x_padding] + end + SetXY(x, y) + if GetStringWidth(text) < w or not text["\n"].nil? and (options[:valign] == "T" || options[:valign] == "top") + text = text + "\n" + end + if GetStringWidth(text) > w or not text["\n"].nil? or (options[:valign] == "B" || options[:valign] == "bottom") + font_size += options[:font_size] * 0.1 + # TODO 2006-07-21 Level=1 - this is assuming a 2 line text + SetXY(x, y + ((h - (font_size * 2)) / 2)) if (options[:valign] == "M" || options[:valign] == "middle") + MultiCell(w, font_size, text, 0, options[:align]) + else + Cell(w, h, text, 0, 0, options[:align]) + end + end + + # Draw a string of text at (x, y) as a title. + # + # Options are: + # * :font_color - Default value is COLOR_PALETTE[:black]. + # * :font_size - Default value is 18. + # * :font_style - Default value is nothing or ''. + # * :colorspace - Default value is :rgb or ''. + # + # Example: + # + # draw_title(left_margin, 60, + # "title:", + # :font_color => ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def draw_title(x, y, title, options = {}) + options[:font_color] ||= Core::RFPDF::COLOR_PALETTE[:black] + options[:font] ||= default_font + options[:font_size] ||= 18 + options[:font_style] ||= '' + set_text_color_a(options[:font_color], options[:colorspace]) + SetFont(options[:font], options[:font_style], options[:font_size]) + SetXY(x, y) + Write(options[:font_size] + 2, title) + end + + # Set the draw color. Default value is COLOR_PALETTE[:black]. + # + # Example: + # + # set_draw_color_a(ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def set_draw_color_a(color = Core::RFPDF::COLOR_PALETTE[:black]) + SetDrawColor(color[0], color[1], color[2]) + end + + # Set the fill color. Default value is COLOR_PALETTE[:white]. + # + # Example: + # + # set_fill_color_a(ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def set_fill_color_a(color = Core::RFPDF::COLOR_PALETTE[:white], colorspace = :rgb) + if colorspace == :cmyk + SetCmykFillColor(color[0], color[1], color[2], color[3]) + else + SetFillColor(color[0], color[1], color[2]) + end + end + + # Set the text color. Default value is COLOR_PALETTE[:white]. + # + # Example: + # + # set_text_color_a(ReportHelper::COLOR_PALETTE[:dark_blue]) + # + def set_text_color_a(color = Core::RFPDF::COLOR_PALETTE[:black], colorspace = :rgb) + if colorspace == :cmyk + SetCmykTextColor(color[0], color[1], color[2], color[3]) + else + SetTextColor(color[0], color[1], color[2]) + end + end + + # Write a string containing html characters. Default value is COLOR_PALETTE[:white]. + # + # Options are: + # * :height - Line height. Default value is 20. + # + # Example: + # + # write_html_with_options(html, :height => 12) + # + #FIXME 2007-08-07 (EJM) Level=0 - This needs to call the TCPDF version. + def write_html_with_options(html, options = {}) + options[:fill] ||= 0 + options[:height] ||= 20 + options[:new_line_after] ||= false + write_html(html, options[:new_line_after], options[:fill], options[:height]) + return + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e1ad05eb66ac646a39350ef0e74e3c3caf45be4b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e1ad05eb66ac646a39350ef0e74e3c3caf45be4b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,158 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/mercurial_adapter' + +class Repository::Mercurial < Repository + # sort changesets by revision number + has_many :changesets, + :order => "#{Changeset.table_name}.id DESC", + :foreign_key => 'repository_id' + + attr_protected :root_url + validates_presence_of :url + + # number of changesets to fetch at once + FETCH_AT_ONCE = 100 + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::MercurialAdapter + end + + def self.scm_name + 'Mercurial' + end + + def supports_directory_revisions? + true + end + + def supports_revision_graph? + true + end + + def repo_log_encoding + 'UTF-8' + end + + # Returns the readable identifier for the given mercurial changeset + def self.format_changeset_identifier(changeset) + "#{changeset.revision}:#{changeset.scmid}" + end + + # Returns the identifier for the given Mercurial changeset + def self.changeset_identifier(changeset) + changeset.scmid + end + + def diff_format_revisions(cs, cs_to, sep=':') + super(cs, cs_to, ' ') + end + + # Finds and returns a revision with a number or the beginning of a hash + def find_changeset_by_name(name) + return nil if name.nil? || name.empty? + if /[^\d]/ =~ name or name.to_s.size > 8 + e = changesets.find(:first, :conditions => ['scmid = ?', name.to_s]) + else + e = changesets.find(:first, :conditions => ['revision = ?', name.to_s]) + end + return e if e + changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"]) # last ditch + end + + # Returns the latest changesets for +path+; sorted by revision number + # + # Because :order => 'id DESC' is defined at 'has_many', + # there is no need to set 'order'. + # But, MySQL test fails. + # Sqlite3 and PostgreSQL pass. + # Is this MySQL bug? + def latest_changesets(path, rev, limit=10) + changesets.find(:all, + :include => :user, + :conditions => latest_changesets_cond(path, rev, limit), + :limit => limit, + :order => "#{Changeset.table_name}.id DESC") + end + + def latest_changesets_cond(path, rev, limit) + cond, args = [], [] + if scm.branchmap.member? rev + # Mercurial named branch is *stable* in each revision. + # So, named branch can be stored in database. + # Mercurial provides *bookmark* which is equivalent with git branch. + # But, bookmark is not implemented. + cond << "#{Changeset.table_name}.scmid IN (?)" + # Revisions in root directory and sub directory are not equal. + # So, in order to get correct limit, we need to get all revisions. + # But, it is very heavy. + # Mercurial does not treat direcotry. + # So, "hg log DIR" is very heavy. + branch_limit = path.blank? ? limit : ( limit * 5 ) + args << scm.nodes_in_branch(rev, :limit => branch_limit) + elsif last = rev ? find_changeset_by_name(scm.tagmap[rev] || rev) : nil + cond << "#{Changeset.table_name}.id <= ?" + args << last.id + end + unless path.blank? + cond << "EXISTS (SELECT * FROM #{Change.table_name} + WHERE #{Change.table_name}.changeset_id = #{Changeset.table_name}.id + AND (#{Change.table_name}.path = ? + OR #{Change.table_name}.path LIKE ? ESCAPE ?))" + args << path.with_leading_slash + args << "#{path.with_leading_slash.gsub(%r{[%_\\]}) { |s| "\\#{s}" }}/%" << '\\' + end + [cond.join(' AND '), *args] unless cond.empty? + end + private :latest_changesets_cond + + def fetch_changesets + return if scm.info.nil? + scm_rev = scm.info.lastrev.revision.to_i + db_rev = latest_changeset ? latest_changeset.revision.to_i : -1 + return unless db_rev < scm_rev # already up-to-date + + logger.debug "Fetching changesets for repository #{url}" if logger + (db_rev + 1).step(scm_rev, FETCH_AT_ONCE) do |i| + transaction do + scm.each_revision('', i, [i + FETCH_AT_ONCE - 1, scm_rev].min) do |re| + cs = Changeset.create(:repository => self, + :revision => re.revision, + :scmid => re.scmid, + :committer => re.author, + :committed_on => re.time, + :comments => re.message) + re.paths.each { |e| cs.create_change(e) } + parents = {} + parents[cs] = re.parents unless re.parents.nil? + parents.each do |ch, chparents| + ch.parents = chparents.collect{|rp| find_changeset_by_name(rp)}.compact + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e1ade5140c036735af4b0ad735c4d03a68cc6596.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e1ade5140c036735af4b0ad735c4d03a68cc6596.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,175 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + module Ruby::Patterns # :nodoc: all + + KEYWORDS = %w[ + and def end in or unless begin + defined? ensure module redo super until + BEGIN break do next rescue then + when END case else for retry + while alias class elsif if not return + undef yield + ] + + # See http://murfy.de/ruby-constants. + PREDEFINED_CONSTANTS = %w[ + nil true false self + DATA ARGV ARGF ENV + FALSE TRUE NIL + STDERR STDIN STDOUT + TOPLEVEL_BINDING + RUBY_COPYRIGHT RUBY_DESCRIPTION RUBY_ENGINE RUBY_PATCHLEVEL + RUBY_PLATFORM RUBY_RELEASE_DATE RUBY_REVISION RUBY_VERSION + __FILE__ __LINE__ __ENCODING__ + ] + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant) + + KEYWORD_NEW_STATE = WordList.new(:initial). + add(%w[ def ], :def_expected). + add(%w[ undef ], :undef_expected). + add(%w[ alias ], :alias_expected). + add(%w[ class module ], :module_expected) + + IDENT = 'ä'[/[[:alpha:]]/] == 'ä' ? /[[:alpha:]_][[:alnum:]_]*/ : /[^\W\d]\w*/ + + METHOD_NAME = / #{IDENT} [?!]? /ox + METHOD_NAME_OPERATOR = / + \*\*? # multiplication and power + | [-+~]@? # plus, minus, tilde with and without at sign + | [\/%&|^`] # division, modulo or format strings, and, or, xor, system + | \[\]=? # array getter and setter + | << | >> # append or shift left, shift right + | <=?>? | >=? # comparison, rocket operator + | ===? | =~ # simple equality, case equality, match + | ![~=@]? # negation with and without at sign, not-equal and not-match + /ox + METHOD_SUFFIX = / (?: [?!] | = (?![~>]|=(?!>)) ) /x + METHOD_NAME_EX = / #{IDENT} #{METHOD_SUFFIX}? | #{METHOD_NAME_OPERATOR} /ox + METHOD_AFTER_DOT = / #{IDENT} [?!]? | #{METHOD_NAME_OPERATOR} /ox + INSTANCE_VARIABLE = / @ #{IDENT} /ox + CLASS_VARIABLE = / @@ #{IDENT} /ox + OBJECT_VARIABLE = / @@? #{IDENT} /ox + GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox + PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox + VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox + + QUOTE_TO_TYPE = { + '`' => :shell, + '/'=> :regexp, + } + QUOTE_TO_TYPE.default = :string + + REGEXP_MODIFIERS = /[mousenix]*/ + + DECIMAL = /\d+(?:_\d+)*/ + OCTAL = /0_?[0-7]+(?:_[0-7]+)*/ + HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/ + BINARY = /0b[01]+(?:_[01]+)*/ + + EXPONENT = / [eE] [+-]? #{DECIMAL} /ox + FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox + FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox + NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox + + SYMBOL = / + : + (?: + #{METHOD_NAME_EX} + | #{PREFIX_VARIABLE} + | ['"] + ) + /ox + METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox + + SIMPLE_ESCAPE = / + [abefnrstv] + | [0-7]{1,3} + | x[0-9A-Fa-f]{1,2} + | . + /mx + + CONTROL_META_ESCAPE = / + (?: M-|C-|c ) + (?: \\ (?: M-|C-|c ) )* + (?: [^\\] | \\ #{SIMPLE_ESCAPE} )? + /mox + + ESCAPE = / + #{CONTROL_META_ESCAPE} | #{SIMPLE_ESCAPE} + /mox + + CHARACTER = / + \? + (?: + [^\s\\] + | \\ #{ESCAPE} + ) + /mox + + # NOTE: This is not completely correct, but + # nobody needs heredoc delimiters ending with \n. + HEREDOC_OPEN = / + << (-)? # $1 = float + (?: + ( [A-Za-z_0-9]+ ) # $2 = delim + | + ( ["'`\/] ) # $3 = quote, type + ( [^\n]*? ) \3 # $4 = delim + ) + /mx + + RUBYDOC = / + =begin (?!\S) + .*? + (?: \Z | ^=end (?!\S) [^\n]* ) + /mx + + DATA = / + __END__$ + .*? + (?: \Z | (?=^\#CODE) ) + /mx + + RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo + + # Checks for a valid value to follow. This enables + # value_expected in method calls without parentheses. + VALUE_FOLLOWS = / + (?>[ \t\f\v]+) + (?: + [%\/][^\s=] + | <<-?\S + | [-+] \d + | #{CHARACTER} + ) + /ox + KEYWORDS_EXPECTING_VALUE = WordList.new.add(%w[ + and end in or unless begin + defined? ensure redo super until + break do next rescue then + when case else for retry + while elsif if not return + yield + ]) + + FANCY_STRING_START = / % ( [QqrsWwx] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /x + FANCY_STRING_KIND = Hash.new(:string).merge({ + 'r' => :regexp, + 's' => :symbol, + 'x' => :shell, + }) + FANCY_STRING_INTERPRETED = Hash.new(true).merge({ + 'q' => false, + 's' => false, + 'w' => false, + }) + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e1b019608202e48e45b7a91c615a2ac50c71ab6a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e1b019608202e48e45b7a91c615a2ac50c71ab6a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +

    <%=l(:label_assigned_to_me_issues)%> (<%= Issue.visible.open.count(:conditions => {:assigned_to_id => ([User.current.id] + User.current.group_ids)})%>)

    + +<% assigned_issues = Issue.visible.open.find(:all, + :conditions => {:assigned_to_id => ([User.current.id] + User.current.group_ids)}, + :limit => 10, + :include => [ :status, :project, :tracker, :priority ], + :order => "#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC") %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> +<% if assigned_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :assigned_to_id => 'me', + :sort => 'priority:desc,updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :assigned_to_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_assigned_to_me_issues)}) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e1b9b340fadfb7e6bd98d84b279ad7feab877137.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e1b9b340fadfb7e6bd98d84b279ad7feab877137.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,89 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'watchers_controller' + +# Re-raise errors caught by the controller. +class WatchersController; def rescue_action(e) raise e end; end + +class WatchersControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, + :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers + + def setup + @controller = WatchersController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_get_watch_should_be_invalid + @request.session[:user_id] = 3 + get :watch, :object_type => 'issue', :object_id => '1' + assert_response 405 + end + + def test_watch + @request.session[:user_id] = 3 + assert_difference('Watcher.count') do + xhr :post, :watch, :object_type => 'issue', :object_id => '1' + assert_response :success + assert @response.body.include?('$$(".issue-1-watcher")') + end + assert Issue.find(1).watched_by?(User.find(3)) + end + + def test_watch_should_be_denied_without_permission + Role.find(2).remove_permission! :view_issues + @request.session[:user_id] = 3 + assert_no_difference('Watcher.count') do + xhr :post, :watch, :object_type => 'issue', :object_id => '1' + assert_response 403 + end + end + + def test_unwatch + @request.session[:user_id] = 3 + assert_difference('Watcher.count', -1) do + xhr :post, :unwatch, :object_type => 'issue', :object_id => '2' + assert_response :success + assert @response.body.include?('$$(".issue-2-watcher")') + end + assert !Issue.find(1).watched_by?(User.find(3)) + end + + def test_new_watcher + @request.session[:user_id] = 2 + assert_difference('Watcher.count') do + xhr :post, :new, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'} + assert_response :success + assert_select_rjs :replace_html, 'watchers' + end + assert Issue.find(2).watched_by?(User.find(4)) + end + + def test_remove_watcher + @request.session[:user_id] = 2 + assert_difference('Watcher.count', -1) do + xhr :post, :destroy, :object_type => 'issue', :object_id => '2', :user_id => '3' + assert_response :success + assert_select_rjs :replace_html, 'watchers' + end + assert !Issue.find(2).watched_by?(User.find(3)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e1ba3e53c732b378a9d000cce4792c744ea0af38.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e1ba3e53c732b378a9d000cce4792c744ea0af38.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,47 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'action_view/helpers/form_helper' + +class TabularFormBuilder < ActionView::Helpers::FormBuilder + include Redmine::I18n + + (field_helpers.map(&:to_s) - %w(radio_button hidden_field fields_for) + + %w(date_select)).each do |selector| + src = <<-END_SRC + def #{selector}(field, options = {}) + label_for_field(field, options) + super + end + END_SRC + class_eval src, __FILE__, __LINE__ + end + + def select(field, choices, options = {}, html_options = {}) + label_for_field(field, options) + super + end + + # Returns a label tag for the given field + def label_for_field(field, options = {}) + return ''.html_safe if options.delete(:no_label) + text = options[:label].is_a?(Symbol) ? l(options[:label]) : options[:label] + text ||= l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) + text += @template.content_tag("span", " *", :class => "required") if options.delete(:required) + @template.content_tag("label", text.html_safe, + :class => (@object && @object.errors[field] ? "error" : nil), + :for => (@object_name.to_s + "_" + field.to_s)) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e1/e1dbf667eb8497c663cf2596785972babe1d4947.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e1/e1dbf667eb8497c663cf2596785972babe1d4947.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<% if @statuses.empty? or rows.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> + + + + + + + + +<% for row in rows %> +"> + + + + + +<% end %> + +
    <%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to h(row.name), :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "o" %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "c" %><%= aggregate_link data, { field_name => row.id }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "*" %>
    +<% end + reset_cycle %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e2/e2217f43c0e991a1cb8790cb4bc4f4cf7be6b81c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e2/e2217f43c0e991a1cb8790cb4bc4f4cf7be6b81c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,87 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::SafeAttributesTest < ActiveSupport::TestCase + + class Base + def attributes=(attrs) + attrs.each do |key, value| + send("#{key}=", value) + end + end + end + + class Person < Base + attr_accessor :firstname, :lastname, :login + include Redmine::SafeAttributes + safe_attributes :firstname, :lastname + safe_attributes :login, :if => lambda {|person, user| user.admin?} + end + + class Book < Base + attr_accessor :title + include Redmine::SafeAttributes + safe_attributes :title + end + + def test_safe_attribute_names + p = Person.new + assert_equal ['firstname', 'lastname'], p.safe_attribute_names(User.anonymous) + assert_equal ['firstname', 'lastname', 'login'], p.safe_attribute_names(User.find(1)) + end + + def test_safe_attribute_names_without_user + p = Person.new + User.current = nil + assert_equal ['firstname', 'lastname'], p.safe_attribute_names + User.current = User.find(1) + assert_equal ['firstname', 'lastname', 'login'], p.safe_attribute_names + end + + def test_set_safe_attributes + p = Person.new + p.send('safe_attributes=', {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}, User.anonymous) + assert_equal 'John', p.firstname + assert_equal 'Smith', p.lastname + assert_nil p.login + + p = Person.new + User.current = User.find(1) + p.send('safe_attributes=', {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}, User.find(1)) + assert_equal 'John', p.firstname + assert_equal 'Smith', p.lastname + assert_equal 'jsmith', p.login + end + + def test_set_safe_attributes_without_user + p = Person.new + User.current = nil + p.safe_attributes = {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'} + assert_equal 'John', p.firstname + assert_equal 'Smith', p.lastname + assert_nil p.login + + p = Person.new + User.current = User.find(1) + p.safe_attributes = {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'} + assert_equal 'John', p.firstname + assert_equal 'Smith', p.lastname + assert_equal 'jsmith', p.login + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e2/e260493f1ee8824999edbd6b5d851d6864f39570.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e2/e260493f1ee8824999edbd6b5d851d6864f39570.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +class WikiContent < ActiveRecord::Base + generator_for :text => 'Some content' + generator_for :page, :method => :generate_page + + def self.generate_page + WikiPage.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e2/e266e25b07a78428f3a93344eb6302f16e43b884.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e2/e266e25b07a78428f3a93344eb6302f16e43b884.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,66 @@ + + + + + +Wiki formatting + + + + +

    Wiki Syntax Quick Reference

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Font Styles
    Strong*Strong*Strong
    Italic_Italic_Italic
    Underline+Underline+Underline
    Deleted-Deleted-Deleted
    ??Quote??Quote
    Inline Code@Inline Code@Inline Code
    Preformatted text<pre>
     lines
     of code
    </pre>
    +
    + lines
    + of code
    +
    +
    Lists
    Unordered list* Item 1
    * Item 2
    • Item 1
    • Item 2
    Ordered list# Item 1
    # Item 2
    1. Item 1
    2. Item 2
    Headings
    Heading 1h1. Title 1

    Title 1

    Heading 2h2. Title 2

    Title 2

    Heading 3h3. Title 3

    Title 3

    Links
    http://foo.barhttp://foo.bar
    "Foo":http://foo.barFoo
    Redmine links
    Link to a Wiki page[[Wiki page]]Wiki page
    Issue #12Issue #12
    Revision r43Revision r43
    commit:f30e13e43f30e13e4
    source:some/filesource:some/file
    Inline images
    Image!image_url!
    !attached_image!
    + +

    More Information

    + + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e31701d543027feaaec6f5716a6efe5c0c48db65.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e31701d543027feaaec6f5716a6efe5c0c48db65.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,122 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 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.expand_path('../../../../../test_helper', __FILE__) + +module RedmineMenuTestHelper + # Helpers + def get_menu_item(menu_name, item_name) + Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym} + end +end + +class Redmine::MenuManager::MenuItemTest < ActiveSupport::TestCase + include RedmineMenuTestHelper + + Redmine::MenuManager.map :test_menu do |menu| + menu.push(:parent, '/test', { }) + menu.push(:child_menu, '/test', { :parent => :parent}) + menu.push(:child2_menu, '/test', { :parent => :parent}) + end + + context "MenuItem#caption" do + should "be tested" + end + + context "MenuItem#html_options" do + should "be tested" + end + + # context new menu item + def test_new_menu_item_should_require_a_name + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new + end + end + + def test_new_menu_item_should_require_an_url + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new(:test_missing_url) + end + end + + def test_new_menu_item_should_require_the_options + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new(:test_missing_options, '/test') + end + end + + def test_new_menu_item_with_all_required_parameters + assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {}) + end + + def test_new_menu_item_should_require_a_proc_to_use_for_the_if_condition + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new(:test_error, '/test', + { + :if => ['not_a_proc'] + }) + end + + assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test', + { + :if => Proc.new{} + }) + end + + def test_new_menu_item_should_allow_a_hash_for_extra_html_options + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new(:test_error, '/test', + { + :html => ['not_a_hash'] + }) + end + + assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test', + { + :html => { :onclick => 'doSomething'} + }) + end + + def test_new_menu_item_should_require_a_proc_to_use_the_children_option + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new(:test_error, '/test', + { + :children => ['not_a_proc'] + }) + end + + assert Redmine::MenuManager::MenuItem.new(:test_good_children, '/test', + { + :children => Proc.new{} + }) + end + + def test_new_should_not_allow_setting_the_parent_item_to_the_current_item + assert_raises ArgumentError do + Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent => :test_error }) + end + end + + def test_has_children + parent_item = get_menu_item(:test_menu, :parent) + assert parent_item.hasChildren? + assert_equal 2, parent_item.children.size + assert_equal get_menu_item(:test_menu, :child_menu), parent_item.children[0] + assert_equal get_menu_item(:test_menu, :child2_menu), parent_item.children[1] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e354d26876e9a19dc212c7bfe45506eaea725d1b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e354d26876e9a19dc212c7bfe45506eaea725d1b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1012 @@ +# Redmine EU language +# Author: Ales Zabala Alava (Shagi), +# 2010-01-25 +# Distributed under the same terms as the Redmine itself. +eu: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%b %d" + long: "%Y %B %d" + + day_names: [Igandea, Astelehena, Asteartea, Asteazkena, Osteguna, Ostirala, Larunbata] + abbr_day_names: [Ig., Al., Ar., Az., Og., Or., La.] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Urtarrila, Otsaila, Martxoa, Apirila, Maiatza, Ekaina, Uztaila, Abuztua, Iraila, Urria, Azaroa, Abendua] + abbr_month_names: [~, Urt, Ots, Mar, Api, Mai, Eka, Uzt, Abu, Ira, Urr, Aza, Abe] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d %H:%M" + time: "%H:%M" + short: "%b %d %H:%M" + long: "%Y %B %d %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "minutu erdi" + less_than_x_seconds: + one: "segundu bat baino gutxiago" + other: "%{count} segundu baino gutxiago" + x_seconds: + one: "segundu 1" + other: "%{count} segundu" + less_than_x_minutes: + one: "minutu bat baino gutxiago" + other: "%{count} minutu baino gutxiago" + x_minutes: + one: "minutu 1" + other: "%{count} minutu" + about_x_hours: + one: "ordu 1 inguru" + other: "%{count} ordu inguru" + x_days: + one: "egun 1" + other: "%{count} egun" + about_x_months: + one: "hilabete 1 inguru" + other: "%{count} hilabete inguru" + x_months: + one: "hilabete 1" + other: "%{count} hilabete" + about_x_years: + one: "urte 1 inguru" + other: "%{count} urte inguru" + over_x_years: + one: "urte 1 baino gehiago" + other: "%{count} urte baino gehiago" + almost_x_years: + one: "ia urte 1" + other: "ia %{count} urte" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Byte" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "eta" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "Errore batek %{model} hau godetzea galarazi du." + other: "%{count} errorek %{model} hau gordetzea galarazi dute." + messages: + inclusion: "ez dago zerrendan" + exclusion: "erreserbatuta dago" + invalid: "baliogabea da" + confirmation: "ez du berrespenarekin bat egiten" + accepted: "onartu behar da" + empty: "ezin da hutsik egon" + blank: "ezin da hutsik egon" + too_long: "luzeegia da (maximoa %{count} karaktere dira)" + too_short: "laburregia da (minimoa %{count} karaktere dira)" + wrong_length: "luzera ezegokia da (%{count} karakter izan beharko litzake)" + taken: "dagoeneko hartuta dago" + not_a_number: "ez da zenbaki bat" + not_a_date: "ez da baliozko data" + greater_than: "%{count} baino handiagoa izan behar du" + greater_than_or_equal_to: "%{count} edo handiagoa izan behar du" + equal_to: "%{count} izan behar du" + less_than: "%{count} baino gutxiago izan behar du" + less_than_or_equal_to: "%{count} edo gutxiago izan behar du" + odd: "bakoitia izan behar du" + even: "bikoitia izan behar du" + greater_than_start_date: "hasiera data baino handiagoa izan behar du" + not_same_project: "ez dago proiektu berdinean" + circular_dependency: "Erlazio honek mendekotasun zirkular bat sortuko luke" + cant_link_an_issue_with_a_descendant: "Zeregin bat ezin da bere azpiataza batekin estekatu." + + actionview_instancetag_blank_option: Hautatu mesedez + + general_text_No: 'Ez' + general_text_Yes: 'Bai' + general_text_no: 'ez' + general_text_yes: 'bai' + general_lang_name: 'Euskara' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Kontua ongi eguneratu da. + notice_account_invalid_creditentials: Erabiltzaile edo pasahitz ezegokia + notice_account_password_updated: Pasahitza ongi eguneratu da. + notice_account_wrong_password: Pasahitz ezegokia. + notice_account_register_done: Kontua ongi sortu da. Kontua gaitzeko klikatu epostan adierazi zaizun estekan. + notice_account_unknown_email: Erabiltzaile ezezaguna. + notice_can_t_change_password: Kontu honek kanpoko autentikazio bat erabiltzen du. Ezinezkoa da pasahitza aldatzea. + notice_account_lost_email_sent: Pasahitz berria aukeratzeko jarraibideak dituen eposta bat bidali zaizu. + notice_account_activated: Zure kontua gaituta dago. Orain saioa has dezakezu + notice_successful_create: Sortze arrakastatsua. + notice_successful_update: Eguneratze arrakastatsua. + notice_successful_delete: Ezabaketa arrakastatsua. + notice_successful_connection: Konexio arrakastatsua. + notice_file_not_found: Atzitu nahi duzun orria ez da exisitzen edo ezabatua izan da. + notice_locking_conflict: Beste erabiltzaile batek datuak eguneratu ditu. + notice_not_authorized: Ez duzu orri hau atzitzeko baimenik. + notice_email_sent: "%{value} helbidera eposta bat bidali da" + notice_email_error: "Errorea eposta bidaltzean (%{value})" + notice_feeds_access_key_reseted: Zure RSS atzipen giltza berrezarri da. + notice_api_access_key_reseted: Zure API atzipen giltza berrezarri da. + notice_failed_to_save_issues: "Hautatutako %{total} zereginetatik %{count} ezin izan dira konpondu: %{ids}." + notice_no_issue_selected: "Ez da zereginik hautatu! Mesedez, editatu nahi dituzun arazoak markatu." + notice_account_pending: "Zure kontua sortu da, orain kudeatzailearen onarpenaren zain dago." + notice_default_data_loaded: Lehenetsitako konfigurazioa ongi kargatu da. + notice_unable_delete_version: Ezin da bertsioa ezabatu. + notice_issue_done_ratios_updated: Burututako zereginen erlazioa eguneratu da. + + error_can_t_load_default_data: "Ezin izan da lehenetsitako konfigurazioa kargatu: %{value}" + error_scm_not_found: "Sarrera edo berrikuspena ez da biltegian topatu." + error_scm_command_failed: "Errorea gertatu da biltegia atzitzean: %{value}" + error_scm_annotate: "Sarrera ez da existitzen edo ezin da anotatu." + error_issue_not_found_in_project: 'Zeregina ez da topatu edo ez da proiektu honetakoa' + error_no_tracker_in_project: 'Proiektu honek ez du aztarnaririk esleituta. Mesedez egiaztatu Proiektuaren ezarpenak.' + error_no_default_issue_status: 'Zereginek ez dute lehenetsitako egoerarik. Mesedez egiaztatu zure konfigurazioa ("Kudeaketa -> Arazoen egoerak" atalera joan).' + error_can_not_reopen_issue_on_closed_version: 'Itxitako bertsio batera esleitutako zereginak ezin dira berrireki' + error_can_not_archive_project: Proiektu hau ezin da artxibatu + error_issue_done_ratios_not_updated: "Burututako zereginen erlazioa ez da eguneratu." + error_workflow_copy_source: 'Mesedez hautatu iturburuko aztarnari edo rola' + error_workflow_copy_target: 'Mesedez hautatu helburuko aztarnari(ak) edo rola(k)' + + warning_attachments_not_saved: "%{count} fitxategi ezin izan d(ir)a gorde." + + mail_subject_lost_password: "Zure %{value} pasahitza" + mail_body_lost_password: 'Zure pasahitza aldatzeko hurrengo estekan klikatu:' + mail_subject_register: "Zure %{value} kontuaren gaitzea" + mail_body_register: 'Zure kontua gaitzeko hurrengo estekan klikatu:' + mail_body_account_information_external: "Zure %{value} kontua erabil dezakezu saioa hasteko." + mail_body_account_information: Zure kontuaren informazioa + mail_subject_account_activation_request: "%{value} kontu gaitzeko eskaera" + mail_body_account_activation_request: "Erabiltzaile berri bat (%{value}) erregistratu da. Kontua zure onarpenaren zain dago:" + mail_subject_reminder: "%{count} arazo hurrengo %{days} egunetan amaitzen d(ir)a" + mail_body_reminder: "Zuri esleituta dauden %{count} arazo hurrengo %{days} egunetan amaitzen d(ir)a:" + mail_subject_wiki_content_added: "'%{id}' wiki orria gehitu da" + mail_body_wiki_content_added: "%{author}-(e)k '%{id}' wiki orria gehitu du." + mail_subject_wiki_content_updated: "'%{id}' wiki orria eguneratu da" + mail_body_wiki_content_updated: "%{author}-(e)k '%{id}' wiki orria eguneratu du." + + gui_validation_error: akats 1 + gui_validation_error_plural: "%{count} akats" + + field_name: Izena + field_description: Deskribapena + field_summary: Laburpena + field_is_required: Beharrezkoa + field_firstname: Izena + field_lastname: Abizenak + field_mail: Eposta + field_filename: Fitxategia + field_filesize: Tamaina + field_downloads: Deskargak + field_author: Egilea + field_created_on: Sortuta + field_updated_on: Eguneratuta + field_field_format: Formatua + field_is_for_all: Proiektu guztietarako + field_possible_values: Balio posibleak + field_regexp: Expresio erregularra + field_min_length: Luzera minimoa + field_max_length: Luzera maxioma + field_value: Balioa + field_category: Kategoria + field_title: Izenburua + field_project: Proiektua + field_issue: Zeregina + field_status: Egoera + field_notes: Oharrak + field_is_closed: Itxitako arazoa + field_is_default: Lehenetsitako balioa + field_tracker: Aztarnaria + field_subject: Gaia + field_due_date: Amaiera data + field_assigned_to: Esleituta + field_priority: Lehentasuna + field_fixed_version: Helburuko bertsioa + field_user: Erabiltzilea + field_role: Rola + field_homepage: Orri nagusia + field_is_public: Publikoa + field_parent: "Honen azpiproiektua:" + field_is_in_chlog: Zereginak aldaketa egunkarian ikusten dira + field_is_in_roadmap: Arazoak ibilbide-mapan erakutsi + field_login: Erabiltzaile izena + field_mail_notification: Eposta jakinarazpenak + field_admin: Kudeatzailea + field_last_login_on: Azken konexioa + field_language: Hizkuntza + field_effective_date: Data + field_password: Pasahitza + field_new_password: Pasahitz berria + field_password_confirmation: Berrespena + field_version: Bertsioa + field_type: Mota + field_host: Ostalaria + field_port: Portua + field_account: Kontua + field_base_dn: Base DN + field_attr_login: Erabiltzaile atributua + field_attr_firstname: Izena atributua + field_attr_lastname: Abizenak atributua + field_attr_mail: Eposta atributua + field_onthefly: Zuzeneko erabiltzaile sorrera + field_start_date: Hasiera + field_done_ratio: Egindako % + field_auth_source: Autentikazio modua + field_hide_mail: Nire eposta helbidea ezkutatu + field_comments: Iruzkina + field_url: URL + field_start_page: Hasierako orria + field_subproject: Azpiproiektua + field_hours: Ordu + field_activity: Jarduera + field_spent_on: Data + field_identifier: Identifikatzailea + field_is_filter: Iragazki moduan erabilita + field_issue_to: Erlazionatutako zereginak + field_delay: Atzerapena + field_assignable: Arazoak rol honetara esleitu daitezke + field_redirect_existing_links: Existitzen diren estekak berbideratu + field_estimated_hours: Estimatutako denbora + field_column_names: Zutabeak + field_time_zone: Ordu zonaldea + field_searchable: Bilagarria + field_default_value: Lehenetsitako balioa + field_comments_sorting: Iruzkinak erakutsi + field_parent_title: Orri gurasoa + field_editable: Editagarria + field_watcher: Behatzailea + field_identity_url: OpenID URLa + field_content: Edukia + field_group_by: Emaitzak honegatik taldekatu + field_sharing: Partekatzea + + setting_app_title: Aplikazioaren izenburua + setting_app_subtitle: Aplikazioaren azpizenburua + setting_welcome_text: Ongietorriko testua + setting_default_language: Lehenetsitako hizkuntza + setting_login_required: Autentikazioa derrigorrezkoa + setting_self_registration: Norberak erregistratu + setting_attachment_max_size: Eranskinen tamaina max. + setting_issues_export_limit: Zereginen esportatze limitea + setting_mail_from: Igorlearen eposta helbidea + setting_bcc_recipients: Hartzaileak ezkutuko kopian (bcc) + setting_plain_text_mail: Testu soileko epostak (HTML-rik ez) + setting_host_name: Ostalari izena eta bidea + setting_text_formatting: Testu formatua + setting_wiki_compression: Wikiaren historia konprimitu + setting_feeds_limit: Jarioaren edukiera limitea + setting_default_projects_public: Proiektu berriak defektuz publikoak dira + setting_autofetch_changesets: Commit-ak automatikoki hartu + setting_sys_api_enabled: Biltegien kudeaketarako WS gaitu + setting_commit_ref_keywords: Erreferentzien gako-hitzak + setting_commit_fix_keywords: Konpontze gako-hitzak + setting_autologin: Saioa automatikoki hasi + setting_date_format: Data formatua + setting_time_format: Ordu formatua + setting_cross_project_issue_relations: Zereginak proiektuen artean erlazionatzea baimendu + setting_issue_list_default_columns: Zereginen zerrendan defektuz ikusten diren zutabeak + setting_emails_footer: Eposten oina + setting_protocol: Protokoloa + setting_per_page_options: Orriko objektuen aukerak + setting_user_format: Erabiltzaileak erakusteko formatua + setting_activity_days_default: Proiektuen jardueran erakusteko egunak + setting_display_subprojects_issues: Azpiproiektuen zereginak proiektu nagusian erakutsi defektuz + setting_enabled_scm: Gaitutako IKKak + setting_mail_handler_body_delimiters: "Lerro hauteko baten ondoren epostak moztu" + setting_mail_handler_api_enabled: Sarrerako epostentzako WS gaitu + setting_mail_handler_api_key: API giltza + setting_sequential_project_identifiers: Proiektuen identifikadore sekuentzialak sortu + setting_gravatar_enabled: Erabili Gravatar erabiltzaile ikonoak + setting_gravatar_default: Lehenetsitako Gravatar irudia + setting_diff_max_lines_displayed: Erakutsiko diren diff lerro kopuru maximoa + setting_file_max_size_displayed: Barnean erakuzten diren testu fitxategien tamaina maximoa + setting_repository_log_display_limit: Egunkari fitxategian erakutsiko diren berrikuspen kopuru maximoa. + setting_openid: Baimendu OpenID saio hasiera eta erregistatzea + setting_password_min_length: Pasahitzen luzera minimoa + setting_new_project_user_role_id: Proiektu berriak sortzerakoan kudeatzaile ez diren erabiltzaileei esleitutako rola + setting_default_projects_modules: Proiektu berrientzako defektuz gaitutako moduluak + setting_issue_done_ratio: "Zereginen burututako tasa kalkulatzean erabili:" + setting_issue_done_ratio_issue_field: Zeregin eremua erabili + setting_issue_done_ratio_issue_status: Zeregin egoera erabili + setting_start_of_week: "Egutegiak noiz hasi:" + setting_rest_api_enabled: Gaitu REST web zerbitzua + + permission_add_project: Proiektua sortu + permission_add_subprojects: Azpiproiektuak sortu + permission_edit_project: Proiektua editatu + permission_select_project_modules: Proiektuaren moduluak hautatu + permission_manage_members: Kideak kudeatu + permission_manage_versions: Bertsioak kudeatu + permission_manage_categories: Arazoen kategoriak kudeatu + permission_view_issues: Zereginak ikusi + permission_add_issues: Zereginak gehitu + permission_edit_issues: Zereginak aldatu + permission_manage_issue_relations: Zereginen erlazioak kudeatu + permission_add_issue_notes: Oharrak gehitu + permission_edit_issue_notes: Oharrak aldatu + permission_edit_own_issue_notes: Nork bere oharrak aldatu + permission_move_issues: Zereginak mugitu + permission_delete_issues: Zereginak ezabatu + permission_manage_public_queries: Galdera publikoak kudeatu + permission_save_queries: Galderak gorde + permission_view_gantt: Gantt grafikoa ikusi + permission_view_calendar: Egutegia ikusi + permission_view_issue_watchers: Behatzaileen zerrenda ikusi + permission_add_issue_watchers: Behatzaileak gehitu + permission_delete_issue_watchers: Behatzaileak ezabatu + permission_log_time: Igarotako denbora erregistratu + permission_view_time_entries: Igarotako denbora ikusi + permission_edit_time_entries: Denbora egunkariak editatu + permission_edit_own_time_entries: Nork bere denbora egunkariak editatu + permission_manage_news: Berriak kudeatu + permission_comment_news: Berrien iruzkinak egin + permission_manage_documents: Dokumentuak kudeatu + permission_view_documents: Dokumentuak ikusi + permission_manage_files: Fitxategiak kudeatu + permission_view_files: Fitxategiak ikusi + permission_manage_wiki: Wikia kudeatu + permission_rename_wiki_pages: Wiki orriak berrizendatu + permission_delete_wiki_pages: Wiki orriak ezabatu + permission_view_wiki_pages: Wikia ikusi + permission_view_wiki_edits: Wikiaren historia ikusi + permission_edit_wiki_pages: Wiki orriak editatu + permission_delete_wiki_pages_attachments: Eranskinak ezabatu + permission_protect_wiki_pages: Wiki orriak babestu + permission_manage_repository: Biltegiak kudeatu + permission_browse_repository: Biltegia arakatu + permission_view_changesets: Aldaketak ikusi + permission_commit_access: Commit atzipena + permission_manage_boards: Foroak kudeatu + permission_view_messages: Mezuak ikusi + permission_add_messages: Mezuak bidali + permission_edit_messages: Mezuak aldatu + permission_edit_own_messages: Nork bere mezuak aldatu + permission_delete_messages: Mezuak ezabatu + permission_delete_own_messages: Nork bere mezuak ezabatu + + project_module_issue_tracking: Zereginen jarraipena + project_module_time_tracking: Denbora jarraipena + project_module_news: Berriak + project_module_documents: Dokumentuak + project_module_files: Fitxategiak + project_module_wiki: Wiki + project_module_repository: Biltegia + project_module_boards: Foroak + + label_user: Erabiltzailea + label_user_plural: Erabiltzaileak + label_user_new: Erabiltzaile berria + label_user_anonymous: Ezezaguna + label_project: Proiektua + label_project_new: Proiektu berria + label_project_plural: Proiektuak + label_x_projects: + zero: proiekturik ez + one: proiektu bat + other: "%{count} proiektu" + label_project_all: Proiektu guztiak + label_project_latest: Azken proiektuak + label_issue: Zeregina + label_issue_new: Zeregin berria + label_issue_plural: Zereginak + label_issue_view_all: Zeregin guztiak ikusi + label_issues_by: "Zereginak honengatik: %{value}" + label_issue_added: Zeregina gehituta + label_issue_updated: Zeregina eguneratuta + label_document: Dokumentua + label_document_new: Dokumentu berria + label_document_plural: Dokumentuak + label_document_added: Dokumentua gehituta + label_role: Rola + label_role_plural: Rolak + label_role_new: Rol berria + label_role_and_permissions: Rolak eta baimenak + label_member: Kidea + label_member_new: Kide berria + label_member_plural: Kideak + label_tracker: Aztarnaria + label_tracker_plural: Aztarnariak + label_tracker_new: Aztarnari berria + label_workflow: Lan-fluxua + label_issue_status: Zeregin egoera + label_issue_status_plural: Zeregin egoerak + label_issue_status_new: Egoera berria + label_issue_category: Zeregin kategoria + label_issue_category_plural: Zeregin kategoriak + label_issue_category_new: Kategoria berria + label_custom_field: Eremu pertsonalizatua + label_custom_field_plural: Eremu pertsonalizatuak + label_custom_field_new: Eremu pertsonalizatu berria + label_enumerations: Enumerazioak + label_enumeration_new: Balio berria + label_information: Informazioa + label_information_plural: Informazioa + label_please_login: Saioa hasi mesedez + label_register: Erregistratu + label_login_with_open_id_option: edo OpenID-rekin saioa hasi + label_password_lost: Pasahitza galduta + label_home: Hasiera + label_my_page: Nire orria + label_my_account: Nire kontua + label_my_projects: Nire proiektuak + label_administration: Kudeaketa + label_login: Saioa hasi + label_logout: Saioa bukatu + label_help: Laguntza + label_reported_issues: Berri emandako zereginak + label_assigned_to_me_issues: Niri esleitutako arazoak + label_last_login: Azken konexioa + label_registered_on: Noiz erregistratuta + label_activity: Jarduerak + label_overall_activity: Jarduera guztiak + label_user_activity: "%{value}-(r)en jarduerak" + label_new: Berria + label_logged_as: "Sartutako erabiltzailea:" + label_environment: Ingurune + label_authentication: Autentikazioa + label_auth_source: Autentikazio modua + label_auth_source_new: Autentikazio modu berria + label_auth_source_plural: Autentikazio moduak + label_subproject_plural: Azpiproiektuak + label_subproject_new: Azpiproiektu berria + label_and_its_subprojects: "%{value} eta bere azpiproiektuak" + label_min_max_length: Luzera min - max + label_list: Zerrenda + label_date: Data + label_integer: Osokoa + label_float: Koma higikorrekoa + label_boolean: Boolearra + label_string: Testua + label_text: Testu luzea + label_attribute: Atributua + label_attribute_plural: Atributuak + label_download: "Deskarga %{count}" + label_download_plural: "%{count} Deskarga" + label_no_data: Ez dago erakusteko daturik + label_change_status: Egoera aldatu + label_history: Historikoa + label_attachment: Fitxategia + label_attachment_new: Fitxategi berria + label_attachment_delete: Fitxategia ezabatu + label_attachment_plural: Fitxategiak + label_file_added: Fitxategia gehituta + label_report: Berri ematea + label_report_plural: Berri emateak + label_news: Berria + label_news_new: Berria gehitu + label_news_plural: Berriak + label_news_latest: Azken berriak + label_news_view_all: Berri guztiak ikusi + label_news_added: Berria gehituta + label_change_log: Aldaketa egunkaria + label_settings: Ezarpenak + label_overview: Gainbegirada + label_version: Bertsioa + label_version_new: Bertsio berria + label_version_plural: Bertsioak + label_close_versions: Burututako bertsioak itxi + label_confirmation: Baieztapena + label_export_to: 'Eskuragarri baita:' + label_read: Irakurri... + label_public_projects: Proiektu publikoak + label_open_issues: irekita + label_open_issues_plural: irekiak + label_closed_issues: itxita + label_closed_issues_plural: itxiak + label_x_open_issues_abbr_on_total: + zero: 0 irekita / %{total} + one: 1 irekita / %{total} + other: "%{count} irekiak / %{total}" + label_x_open_issues_abbr: + zero: 0 irekita + one: 1 irekita + other: "%{count} irekiak" + label_x_closed_issues_abbr: + zero: 0 itxita + one: 1 itxita + other: "%{count} itxiak" + label_total: Guztira + label_permissions: Baimenak + label_current_status: Uneko egoera + label_new_statuses_allowed: Baimendutako egoera berriak + label_all: guztiak + label_none: ezer + label_nobody: inor + label_next: Hurrengoa + label_previous: Aurrekoak + label_used_by: Erabilita + label_details: Xehetasunak + label_add_note: Oharra gehitu + label_per_page: Orriko + label_calendar: Egutegia + label_months_from: hilabete noiztik + label_gantt: Gantt + label_internal: Barnekoa + label_last_changes: "azken %{count} aldaketak" + label_change_view_all: Aldaketa guztiak ikusi + label_personalize_page: Orri hau pertsonalizatu + label_comment: Iruzkin + label_comment_plural: Iruzkinak + label_x_comments: + zero: iruzkinik ez + one: iruzkin 1 + other: "%{count} iruzkin" + label_comment_add: Iruzkina gehitu + label_comment_added: Iruzkina gehituta + label_comment_delete: Iruzkinak ezabatu + label_query: Galdera pertsonalizatua + label_query_plural: Pertsonalizatutako galderak + label_query_new: Galdera berria + label_filter_add: Iragazkia gehitu + label_filter_plural: Iragazkiak + label_equals: da + label_not_equals: ez da + label_in_less_than: baino gutxiagotan + label_in_more_than: baino gehiagotan + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: hauetan + label_today: gaur + label_all_time: denbora guztia + label_yesterday: atzo + label_this_week: aste honetan + label_last_week: pasadan astean + label_last_n_days: "azken %{count} egunetan" + label_this_month: hilabete hau + label_last_month: pasadan hilabetea + label_this_year: urte hau + label_date_range: Data tartea + label_less_than_ago: egun hauek baino gutxiago + label_more_than_ago: egun hauek baino gehiago + label_ago: orain dela + label_contains: dauka + label_not_contains: ez dauka + label_day_plural: egun + label_repository: Biltegia + label_repository_plural: Biltegiak + label_browse: Arakatu + label_modification: "aldaketa %{count}" + label_modification_plural: "%{count} aldaketa" + label_branch: Adarra + label_tag: Etiketa + label_revision: Berrikuspena + label_revision_plural: Berrikuspenak + label_revision_id: "%{value} berrikuspen" + label_associated_revisions: Elkartutako berrikuspenak + label_added: gehituta + label_modified: aldatuta + label_copied: kopiatuta + label_renamed: berrizendatuta + label_deleted: ezabatuta + label_latest_revision: Azken berrikuspena + label_latest_revision_plural: Azken berrikuspenak + label_view_revisions: Berrikuspenak ikusi + label_view_all_revisions: Berrikuspen guztiak ikusi + label_max_size: Tamaina maximoa + label_sort_highest: Goraino mugitu + label_sort_higher: Gora mugitu + label_sort_lower: Behera mugitu + label_sort_lowest: Beheraino mugitu + label_roadmap: Ibilbide-mapa + label_roadmap_due_in: "Epea: %{value}" + label_roadmap_overdue: "%{value} berandu" + label_roadmap_no_issues: Ez dago zereginik bertsio honetan + label_search: Bilatu + label_result_plural: Emaitzak + label_all_words: hitz guztiak + label_wiki: Wikia + label_wiki_edit: Wiki edizioa + label_wiki_edit_plural: Wiki edizioak + label_wiki_page: Wiki orria + label_wiki_page_plural: Wiki orriak + label_index_by_title: Izenburuaren araberako indizea + label_index_by_date: Dataren araberako indizea + label_current_version: Uneko bertsioa + label_preview: Aurreikusi + label_feed_plural: Jarioak + label_changes_details: Aldaketa guztien xehetasunak + label_issue_tracking: Zeregin jarraipena + label_spent_time: Igarotako denbora + label_f_hour: "ordu %{value}" + label_f_hour_plural: "%{value} ordu" + label_time_tracking: Denbora jarraipena + label_change_plural: Aldaketak + label_statistics: Estatistikak + label_commits_per_month: Commit-ak hilabeteka + label_commits_per_author: Commit-ak egileka + label_view_diff: Ezberdintasunak ikusi + label_diff_inline: barnean + label_diff_side_by_side: aldez alde + label_options: Aukerak + label_copy_workflow_from: Kopiatu workflow-a hemendik + label_permissions_report: Baimenen txostena + label_watched_issues: Behatutako zereginak + label_related_issues: Erlazionatutako zereginak + label_applied_status: Aplikatutako egoera + label_loading: Kargatzen... + label_relation_new: Erlazio berria + label_relation_delete: Erlazioa ezabatu + label_relates_to: erlazionatuta dago + label_duplicates: bikoizten du + label_duplicated_by: honek bikoiztuta + label_blocks: blokeatzen du + label_blocked_by: honek blokeatuta + label_precedes: aurretik doa + label_follows: jarraitzen du + label_end_to_start: bukaeratik hasierara + label_end_to_end: bukaeratik bukaerara + label_start_to_start: hasieratik hasierhasieratik bukaerara + label_start_to_end: hasieratik bukaerara + label_stay_logged_in: Saioa mantendu + label_disabled: ezgaituta + label_show_completed_versions: Bukatutako bertsioak ikusi + label_me: ni + label_board: Foroa + label_board_new: Foro berria + label_board_plural: Foroak + label_topic_plural: Gaiak + label_message_plural: Mezuak + label_message_last: Azken mezua + label_message_new: Mezu berria + label_message_posted: Mezua gehituta + label_reply_plural: Erantzunak + label_send_information: Erabiltzaileai kontuaren informazioa bidali + label_year: Urtea + label_month: Hilabetea + label_week: Astea + label_date_from: Nork + label_date_to: Nori + label_language_based: Erabiltzailearen hizkuntzaren arabera + label_sort_by: "Ordenazioa: %{value}" + label_send_test_email: Frogako mezua bidali + label_feeds_access_key: RSS atzipen giltza + label_missing_feeds_access_key: RSS atzipen giltza falta da + label_feeds_access_key_created_on: "RSS atzipen giltza orain dela %{value} sortuta" + label_module_plural: Moduluak + label_added_time_by: "%{author}, orain dela %{age} gehituta" + label_updated_time_by: "%{author}, orain dela %{age} eguneratuta" + label_updated_time: "Orain dela %{value} eguneratuta" + label_jump_to_a_project: Joan proiektura... + label_file_plural: Fitxategiak + label_changeset_plural: Aldaketak + label_default_columns: Lehenetsitako zutabeak + label_no_change_option: (Aldaketarik ez) + label_bulk_edit_selected_issues: Hautatutako zereginak batera editatu + label_theme: Itxura + label_default: Lehenetsia + label_search_titles_only: Izenburuetan bakarrik bilatu + label_user_mail_option_all: "Nire proiektu guztietako gertakari guztientzat" + label_user_mail_option_selected: "Hautatutako proiektuetako edozein gertakarientzat..." + label_user_mail_no_self_notified: "Ez dut nik egiten ditudan aldeketen jakinarazpenik jaso nahi" + label_registration_activation_by_email: kontuak epostaz gaitu + label_registration_manual_activation: kontuak eskuz gaitu + label_registration_automatic_activation: kontuak automatikoki gaitu + label_display_per_page: "Orriko: %{value}" + label_age: Adina + label_change_properties: Propietateak aldatu + label_general: Orokorra + label_more: Gehiago + label_scm: IKK + label_plugins: Pluginak + label_ldap_authentication: LDAP autentikazioa + label_downloads_abbr: Desk. + label_optional_description: Aukerako deskribapena + label_add_another_file: Beste fitxategia gehitu + label_preferences: Hobespenak + label_chronological_order: Orden kronologikoan + label_reverse_chronological_order: Alderantzizko orden kronologikoan + label_planning: Planifikazioa + label_incoming_emails: Sarrerako epostak + label_generate_key: Giltza sortu + label_issue_watchers: Behatzaileak + label_example: Adibidea + label_display: Bistaratzea + label_sort: Ordenatu + label_ascending: Gorantz + label_descending: Beherantz + label_date_from_to: "%{start}-tik %{end}-ra" + label_wiki_content_added: Wiki orria gehituta + label_wiki_content_updated: Wiki orria eguneratuta + label_group: Taldea + label_group_plural: Taldeak + label_group_new: Talde berria + label_time_entry_plural: Igarotako denbora + label_version_sharing_none: Ez partekatuta + label_version_sharing_descendants: Azpiproiektuekin + label_version_sharing_hierarchy: Proiektu Hierarkiarekin + label_version_sharing_tree: Proiektu zuhaitzarekin + label_version_sharing_system: Proiektu guztiekin + label_update_issue_done_ratios: Zereginen burututako erlazioa eguneratu + label_copy_source: Iturburua + label_copy_target: Helburua + label_copy_same_as_target: Helburuaren berdina + label_display_used_statuses_only: Aztarnari honetan erabiltzen diren egoerak bakarrik erakutsi + label_api_access_key: API atzipen giltza + label_missing_api_access_key: API atzipen giltza falta da + label_api_access_key_created_on: "API atzipen giltza sortuta orain dela %{value}" + + button_login: Saioa hasi + button_submit: Bidali + button_save: Gorde + button_check_all: Guztiak markatu + button_uncheck_all: Guztiak desmarkatu + button_delete: Ezabatu + button_create: Sortu + button_create_and_continue: Sortu eta jarraitu + button_test: Frogatu + button_edit: Editatu + button_add: Gehitu + button_change: Aldatu + button_apply: Aplikatu + button_clear: Garbitu + button_lock: Blokeatu + button_unlock: Desblokeatu + button_download: Deskargatu + button_list: Zerrenda + button_view: Ikusi + button_move: Mugitu + button_move_and_follow: Mugitu eta jarraitu + button_back: Atzera + button_cancel: Ezeztatu + button_activate: Gahitu + button_sort: Ordenatu + button_log_time: Denbora erregistratu + button_rollback: Itzuli bertsio honetara + button_watch: Behatu + button_unwatch: Behatzen utzi + button_reply: Erantzun + button_archive: Artxibatu + button_unarchive: Desartxibatu + button_reset: Berrezarri + button_rename: Berrizendatu + button_change_password: Pasahitza aldatu + button_copy: Kopiatu + button_copy_and_follow: Kopiatu eta jarraitu + button_annotate: Anotatu + button_update: Eguneratu + button_configure: Konfiguratu + button_quote: Aipatu + button_duplicate: Bikoiztu + button_show: Ikusi + + status_active: gaituta + status_registered: izena emanda + status_locked: blokeatuta + + version_status_open: irekita + version_status_locked: blokeatuta + version_status_closed: itxita + + field_active: Gaituta + + text_select_mail_notifications: Jakinarazpenak zein ekintzetarako bidaliko diren hautatu. + text_regexp_info: adib. ^[A-Z0-9]+$ + text_min_max_length_info: 0k mugarik gabe esan nahi du + text_project_destroy_confirmation: Ziur zaude proiektu hau eta erlazionatutako datu guztiak ezabatu nahi dituzula? + text_subprojects_destroy_warning: "%{value} azpiproiektuak ere ezabatuko dira." + text_workflow_edit: Hautatu rola eta aztarnaria workflow-a editatzeko + text_are_you_sure: Ziur zaude? + text_journal_changed: "%{label} %{old}-(e)tik %{new}-(e)ra aldatuta" + text_journal_set_to: "%{label}-k %{value} balioa hartu du" + text_journal_deleted: "%{label} ezabatuta (%{old})" + text_journal_added: "%{label} %{value} gehituta" + text_tip_issue_begin_day: gaur hasten diren zereginak + text_tip_issue_end_day: gaur bukatzen diren zereginak + text_tip_issue_begin_end_day: gaur hasi eta bukatzen diren zereginak + text_project_identifier_info: 'Letra xeheak (a-z), zenbakiak eta marrak erabil daitezke bakarrik.
    Gorde eta gero identifikadorea ezin da aldatu.' + text_caracters_maximum: "%{count} karaktere gehienez." + text_caracters_minimum: "Gutxienez %{count} karaktereetako luzerakoa izan behar du." + text_length_between: "Luzera %{min} eta %{max} karaktereen artekoa." + text_tracker_no_workflow: Ez da workflow-rik definitu aztarnari honentzako + text_unallowed_characters: Debekatutako karaktereak + text_comma_separated: Balio anitz izan daitezke (komaz banatuta). + text_line_separated: Balio anitz izan daitezke (balio bakoitza lerro batean). + text_issues_ref_in_commit_messages: Commit-en mezuetan zereginak erlazionatu eta konpontzen + text_issue_added: "%{id} zeregina %{author}-(e)k jakinarazi du." + text_issue_updated: "%{id} zeregina %{author}-(e)k eguneratu du." + text_wiki_destroy_confirmation: Ziur zaude wiki hau eta bere eduki guztiak ezabatu nahi dituzula? + text_issue_category_destroy_question: "Zeregin batzuk (%{count}) kategoria honetara esleituta daude. Zer egin nahi duzu?" + text_issue_category_destroy_assignments: Kategoria esleipenak kendu + text_issue_category_reassign_to: Zereginak kategoria honetara esleitu + text_user_mail_option: "Hautatu gabeko proiektuetan, behatzen edo parte hartzen duzun gauzei buruzko jakinarazpenak jasoko dituzu (adib. zu egile zaren edo esleituta dituzun zereginak)." + text_no_configuration_data: "Rolak, aztarnariak, zeregin egoerak eta workflow-ak ez dira oraindik konfiguratu.\nOso gomendagarria de lehenetsitako kkonfigurazioa kargatzea. Kargatu eta gero aldatu ahalko duzu." + text_load_default_configuration: Lehenetsitako konfigurazioa kargatu + text_status_changed_by_changeset: "%{value} aldaketan aplikatuta." + text_issues_destroy_confirmation: 'Ziur zaude hautatutako zeregina(k) ezabatu nahi dituzula?' + text_select_project_modules: 'Hautatu proiektu honetan gaitu behar diren moduluak:' + text_default_administrator_account_changed: Lehenetsitako kudeatzaile kontua aldatuta + text_file_repository_writable: Eranskinen direktorioan idatz daiteke + text_plugin_assets_writable: Pluginen baliabideen direktorioan idatz daiteke + text_rmagick_available: RMagick eskuragarri (aukerazkoa) + text_destroy_time_entries_question: "%{hours} orduei buruz berri eman zen zuk ezabatzera zoazen zereginean. Zer egin nahi duzu?" + text_destroy_time_entries: Ezabatu berri emandako orduak + text_assign_time_entries_to_project: Berri emandako orduak proiektura esleitu + text_reassign_time_entries: 'Berri emandako orduak zeregin honetara esleitu:' + text_user_wrote: "%{value}-(e)k idatzi zuen:" + text_enumeration_destroy_question: "%{count} objetu balio honetara esleituta daude." + text_enumeration_category_reassign_to: 'Beste balio honetara esleitu:' + text_email_delivery_not_configured: "Eposta bidalketa ez dago konfiguratuta eta jakinarazpenak ezgaituta daude.\nKonfiguratu zure SMTP zerbitzaria config/configuration.yml-n eta aplikazioa berrabiarazi hauek gaitzeko." + text_repository_usernames_mapping: "Hautatu edo eguneratu Redmineko erabiltzailea biltegiko egunkarietan topatzen diren erabiltzaile izenekin erlazionatzeko.\nRedmine-n eta biltegian erabiltzaile izen edo eposta berdina duten erabiltzaileak automatikoki erlazionatzen dira." + text_diff_truncated: '... Diff hau moztua izan da erakus daitekeen tamaina maximoa gainditu duelako.' + text_custom_field_possible_values_info: 'Lerro bat balio bakoitzeko' + text_wiki_page_destroy_question: "Orri honek %{descendants} orri seme eta ondorengo ditu. Zer egin nahi duzu?" + text_wiki_page_nullify_children: "Orri semeak erro orri moduan mantendu" + text_wiki_page_destroy_children: "Orri semeak eta beraien ondorengo guztiak ezabatu" + text_wiki_page_reassign_children: "Orri semeak orri guraso honetara esleitu" + text_own_membership_delete_confirmation: "Zure baimen batzuk (edo guztiak) kentzera zoaz eta baliteke horren ondoren proiektu hau ezin editatzea.\n Ziur zaude jarraitu nahi duzula?" + + default_role_manager: Kudeatzailea + default_role_developer: Garatzailea + default_role_reporter: Berriemailea + default_tracker_bug: Errorea + default_tracker_feature: Eginbidea + default_tracker_support: Laguntza + default_issue_status_new: Berria + default_issue_status_in_progress: Lanean + default_issue_status_resolved: Ebatzita + default_issue_status_feedback: Berrelikadura + default_issue_status_closed: Itxita + default_issue_status_rejected: Baztertua + default_doc_category_user: Erabiltzaile dokumentazioa + default_doc_category_tech: Dokumentazio teknikoa + default_priority_low: Baxua + default_priority_normal: Normala + default_priority_high: Altua + default_priority_urgent: Larria + default_priority_immediate: Berehalakoa + default_activity_design: Diseinua + default_activity_development: Garapena + + enumeration_issue_priorities: Zeregin lehentasunak + enumeration_doc_categories: Dokumentu kategoriak + enumeration_activities: Jarduerak (denbora kontrola)) + enumeration_system_activity: Sistemako Jarduera + label_board_sticky: Itsaskorra + label_board_locked: Blokeatuta + permission_export_wiki_pages: Wiki orriak esportatu + setting_cache_formatted_text: Formatudun testua katxeatu + permission_manage_project_activities: Proiektuaren jarduerak kudeatu + error_unable_delete_issue_status: Ezine da zereginaren egoera ezabatu + label_profile: Profila + permission_manage_subtasks: Azpiatazak kudeatu + field_parent_issue: Zeregin gurasoa + label_subtask_plural: Azpiatazak + label_project_copy_notifications: Proiektua kopiatzen den bitartean eposta jakinarazpenak bidali + error_can_not_delete_custom_field: Ezin da eremu pertsonalizatua ezabatu + error_unable_to_connect: Ezin da konektatu (%{value}) + error_can_not_remove_role: Rol hau erabiltzen hari da eta ezin da ezabatu. + error_can_not_delete_tracker: Aztarnari honek zereginak ditu eta ezin da ezabatu. + field_principal: Ekintzaile + label_my_page_block: "Nire orriko blokea" + notice_failed_to_save_members: "Kidea(k) gordetzean errorea: %{errors}." + text_zoom_out: Zooma txikiagotu + text_zoom_in: Zooma handiagotu + notice_unable_delete_time_entry: "Ezin da hautatutako denbora erregistroa ezabatu." + label_overall_spent_time: Igarotako denbora guztira + field_time_entries: "Denbora erregistratu" + project_module_gantt: Gantt + project_module_calendar: Egutegia + button_edit_associated_wikipage: "Esleitutako wiki orria editatu: %{page_title}" + text_are_you_sure_with_children: "Zeregina eta azpi zeregin guztiak ezabatu?" + field_text: Testu eremua + label_user_mail_option_only_owner: "Jabea naizen gauzetarako barrarik" + setting_default_notification_option: "Lehenetsitako ohartarazpen aukera" + label_user_mail_option_only_my_events: "Behatzen ditudan edo partaide naizen gauzetarako bakarrik" + label_user_mail_option_only_assigned: "Niri esleitutako gauzentzat bakarrik" + label_user_mail_option_none: "Gertakaririk ez" + field_member_of_group: "Esleituta duenaren taldea" + field_assigned_to_role: "Esleituta duenaren rola" + notice_not_authorized_archived_project: "Atzitu nahi duzun proiektua artxibatua izan da." + label_principal_search: "Bilatu erabiltzaile edo taldea:" + label_user_search: "Erabiltzailea bilatu:" + field_visible: Ikusgai + setting_emails_header: "Eposten goiburua" + setting_commit_logtime_activity_id: "Erregistratutako denboraren jarduera" + text_time_logged_by_changeset: "%{value} aldaketan egindakoa." + setting_commit_logtime_enabled: "Erregistrutako denbora gaitu" + notice_gantt_chart_truncated: Grafikoa moztu da bistara daitekeen elementuen kopuru maximoa gainditu delako (%{max}) + setting_gantt_items_limit: "Gantt grafikoan bistara daitekeen elementu kopuru maximoa" + field_warn_on_leaving_unsaved: Gorde gabeko testua duen orri batetik ateratzen naizenean ohartarazi + text_warn_on_leaving_unsaved: Uneko orritik joaten bazara gorde gabeko testua galduko da. + label_my_queries: Nire galdera pertsonalizatuak + text_journal_changed_no_detail: "%{label} eguneratuta" + label_news_comment_added: Berri batera iruzkina gehituta + button_expand_all: Guztia zabaldu + button_collapse_all: Guztia tolestu + label_additional_workflow_transitions_for_assignee: Erabiltzaileak esleitua duenean baimendutako transtsizio gehigarriak + label_additional_workflow_transitions_for_author: Erabiltzailea egilea denean baimendutako transtsizio gehigarriak + label_bulk_edit_selected_time_entries: Hautatutako denbora egunkariak batera editatu + text_time_entries_destroy_confirmation: Ziur zaude hautatutako denbora egunkariak ezabatu nahi dituzula? + label_role_anonymous: Ezezaguna + label_role_non_member: Ez kidea + label_issue_note_added: Oharra gehituta + label_issue_status_updated: Egoera eguneratuta + label_issue_priority_updated: Lehentasuna eguneratuta + label_issues_visibility_own: Erabiltzaileak sortu edo esleituta dituen zereginak + field_issues_visibility: Zeregin ikusgarritasuna + label_issues_visibility_all: Zeregin guztiak + permission_set_own_issues_private: Nork bere zereginak publiko edo pribatu jarri + field_is_private: Pribatu + permission_set_issues_private: Zereginak publiko edo pribatu jarri + label_issues_visibility_public: Pribatu ez diren zeregin guztiak + text_issues_destroy_descendants_confirmation: Honek %{count} azpiataza ezabatuko ditu baita ere. + field_commit_logs_encoding: Commit-en egunkarien kodetzea + field_scm_path_encoding: Bidearen kodeketa + text_scm_path_encoding_note: "Lehentsita: UTF-8" + field_path_to_repository: Biltegirako bidea + field_root_directory: Erro direktorioa + field_cvs_module: Modulua + field_cvsroot: CVSROOT + text_mercurial_repository_note: Biltegi locala (adib. /hgrepo, c:\hgrepo) + text_scm_command: Komandoa + text_scm_command_version: Bertsioa + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e355771449df712f641ffb87ad8c228fd09d9152.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e355771449df712f641ffb87ad8c228fd09d9152.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +# Re-raise errors caught by the controller. +class StubController < ApplicationController + def rescue_action(e) raise e end; + attr_accessor :request, :url +end + +class HelperTestCase < ActiveSupport::TestCase + + # Add other helpers here if you need them + include ActionView::Helpers::ActiveRecordHelper + include ActionView::Helpers::TagHelper + include ActionView::Helpers::FormTagHelper + include ActionView::Helpers::FormOptionsHelper + include ActionView::Helpers::FormHelper + include ActionView::Helpers::UrlHelper + include ActionView::Helpers::AssetTagHelper + include ActionView::Helpers::PrototypeHelper + + def setup + super + + @request = ActionController::TestRequest.new + @controller = StubController.new + @controller.request = @request + + # Fake url rewriter so we can test url_for + @controller.url = ActionController::UrlRewriter.new @request, {} + + ActionView::Helpers::AssetTagHelper::reset_javascript_include_default + end + + def test_dummy + # do nothing - required by test/unit + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e3717673d3341037068a46026d2f7990e0e1fb85.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e3717673d3341037068a46026d2f7990e0e1fb85.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +.DS_Store +test_app +doc \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e37759dea55d14e3086ea2b9ced5bbf696b3c056.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e37759dea55d14e3086ea2b9ced5bbf696b3c056.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'wikis_controller' + +# Re-raise errors caught by the controller. +class WikisController; def rescue_action(e) raise e end; end + +class WikisControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis + + def setup + @controller = WikisController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_create + @request.session[:user_id] = 1 + assert_nil Project.find(3).wiki + post :edit, :id => 3, :wiki => { :start_page => 'Start page' } + assert_response :success + wiki = Project.find(3).wiki + assert_not_nil wiki + assert_equal 'Start page', wiki.start_page + end + + def test_destroy + @request.session[:user_id] = 1 + post :destroy, :id => 1, :confirm => 1 + assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'ecookbook', :tab => 'wiki' + assert_nil Project.find(1).wiki + end + + def test_not_found + @request.session[:user_id] = 1 + post :destroy, :id => 999, :confirm => 1 + assert_response 404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e383d141d18d0ab6640f2f0c195a246ce39b140f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e383d141d18d0ab6640f2f0c195a246ce39b140f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,131 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class IssueStatusTest < ActiveSupport::TestCase + fixtures :issue_statuses, :issues, :roles, :trackers + + def test_create + status = IssueStatus.new :name => "Assigned" + assert !status.save + # status name uniqueness + assert_equal 1, status.errors.count + + status.name = "Test Status" + assert status.save + assert !status.is_default + end + + def test_destroy + status = IssueStatus.find(3) + assert_difference 'IssueStatus.count', -1 do + assert status.destroy + end + assert_nil Workflow.first(:conditions => {:old_status_id => status.id}) + assert_nil Workflow.first(:conditions => {:new_status_id => status.id}) + end + + def test_destroy_status_in_use + # Status assigned to an Issue + status = Issue.find(1).status + assert_raise(RuntimeError, "Can't delete status") { status.destroy } + end + + def test_default + status = IssueStatus.default + assert_kind_of IssueStatus, status + end + + def test_change_default + status = IssueStatus.find(2) + assert !status.is_default + status.is_default = true + assert status.save + status.reload + + assert_equal status, IssueStatus.default + assert !IssueStatus.find(1).is_default + end + + def test_reorder_should_not_clear_default_status + status = IssueStatus.default + status.move_to_bottom + status.reload + assert status.is_default? + end + + def test_new_statuses_allowed_to + Workflow.delete_all + + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false) + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false) + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true) + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5, :author => true, :assignee => true) + status = IssueStatus.find(1) + role = Role.find(1) + tracker = Tracker.find(1) + + assert_equal [2], status.new_statuses_allowed_to([role], tracker, false, false).map(&:id) + assert_equal [2], status.find_new_statuses_allowed_to([role], tracker, false, false).map(&:id) + + assert_equal [2, 3, 5], status.new_statuses_allowed_to([role], tracker, true, false).map(&:id) + assert_equal [2, 3, 5], status.find_new_statuses_allowed_to([role], tracker, true, false).map(&:id) + + assert_equal [2, 4, 5], status.new_statuses_allowed_to([role], tracker, false, true).map(&:id) + assert_equal [2, 4, 5], status.find_new_statuses_allowed_to([role], tracker, false, true).map(&:id) + + assert_equal [2, 3, 4, 5], status.new_statuses_allowed_to([role], tracker, true, true).map(&:id) + assert_equal [2, 3, 4, 5], status.find_new_statuses_allowed_to([role], tracker, true, true).map(&:id) + end + + context "#update_done_ratios" do + setup do + @issue = Issue.find(1) + @issue_status = IssueStatus.find(1) + @issue_status.update_attribute(:default_done_ratio, 50) + end + + context "with Setting.issue_done_ratio using the issue_field" do + setup do + Setting.issue_done_ratio = 'issue_field' + end + + should "change nothing" do + IssueStatus.update_issue_done_ratios + + assert_equal 0, Issue.count(:conditions => {:done_ratio => 50}) + end + end + + context "with Setting.issue_done_ratio using the issue_status" do + setup do + Setting.issue_done_ratio = 'issue_status' + end + + should "update all of the issue's done_ratios to match their Issue Status" do + IssueStatus.update_issue_done_ratios + + issues = Issue.find([1,3,4,5,6,7,9,10]) + issues.each do |issue| + assert_equal @issue_status, issue.status + assert_equal 50, issue.read_attribute(:done_ratio) + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e38f15d25eddac622827eb4fb140d82f4ed1a927.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e38f15d25eddac622827eb4fb140d82f4ed1a927.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +

    <%= l(:label_board_plural) %>

    + + + + + + + + + +<% for board in @boards %> + + + + + + +<% end %> + +
    <%= l(:label_board) %><%= l(:label_topic_plural) %><%= l(:label_message_plural) %><%= l(:label_message_last) %>
    + <%= link_to h(board.name), {:action => 'show', :id => board}, :class => "board" %>
    + <%=h board.description %> +
    <%= board.topics_count %><%= board.messages_count %> + + <% if board.last_message %> + <%= authoring board.last_message.created_on, board.last_message.author %>
    + <%= link_to_message board.last_message %> + <% end %> +
    +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_messages => 1, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %> +<% end %> + +<% html_title l(:label_board_plural) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e3/e3ce93992f0dcb5926074deef74a2fe1bdbea820.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e3/e3ce93992f0dcb5926074deef74a2fe1bdbea820.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ + <% if @users_by_role.any? %> +
    +

    <%=l(:label_member_plural)%>

    +

    <% @users_by_role.keys.sort.each do |role| %> + <%=h role %>: <%= @users_by_role[role].sort.collect{|u| link_to_user u}.join(", ") %>
    + <% end %>

    +
    + <% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e4090c8aca96da6a48e07596b08d96af2c68fc96.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e4090c8aca96da6a48e07596b08d96af2c68fc96.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class DocumentCategory < Enumeration + has_many :documents, :foreign_key => 'category_id' + + OptionName = :enumeration_doc_categories + + def option_name + OptionName + end + + def objects_count + documents.count + end + + def transfer_relations(to) + documents.update_all("category_id = #{to.id}") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e434adb14429b8cc074a58c6d665c61f517b82fd.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e434adb14429b8cc074a58c6d665c61f517b82fd.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e47191dbbf538fac3be57c09212894140f807e22.svn-base Binary file .svn/pristine/e4/e47191dbbf538fac3be57c09212894140f807e22.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e4761d2f058832869302289c70454235fc70d557.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e4761d2f058832869302289c70454235fc70d557.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +@import url(../../../stylesheets/application.css); + +body{ color:#303030; background:#e8eaec; } + +#top-menu { font-size: 80%; height: 2em; padding-top: 0.5em; background-color: #578bb8; } +#top-menu a { font-weight: bold; } +#header { background: #467aa7; height:5.8em; padding: 10px 0 0 0; } +#header h1 { margin-left: 6px; } +#quick-search { margin-right: 6px; } +#main-menu { background-color: #578bb8; left: 0; border-top: 1px solid #fff; width: 100%; } +#main-menu li { margin: 0; padding: 0; } +#main-menu li a { background-color: #578bb8; border-right: 1px solid #fff; font-size: 90%; padding: 4px 8px 4px 8px; font-weight: bold; } +#main-menu li a:hover { background-color: #80b0da; color: #ffffff; } +#main-menu li a.selected, #main-menu li a.selected:hover { background-color: #80b0da; color: #ffffff; } + +#footer { background-color: #578bb8; border: 0; color: #fff;} +#footer a { color: #fff; font-weight: bold; } + +#main { font:90% Verdana,Tahoma,Arial,sans-serif; background: #e8eaec; } +#main a { font-weight: bold; color: #467aa7;} +#main a:hover { color: #2a5a8a; text-decoration: underline; } +#content { background: #fff; } +#content .tabs ul { bottom:-1px; } + +h2, h3, h4, .wiki h1, .wiki h2, .wiki h3 { border-bottom: 0px; color:#606060; font-family: Trebuchet MS,Georgia,"Times New Roman",serif; } +h2, .wiki h1 { letter-spacing:-1px; } +h4 { border-bottom: dotted 1px #c0c0c0; } + +#top-menu a.home, #top-menu a.my-page, #top-menu a.projects, #top-menu a.administration, #top-menu a.help { + background-position: 0% 40%; + background-repeat: no-repeat; + padding-left: 20px; + padding-top: 2px; + padding-bottom: 3px; +} + +#top-menu a.home { background-image: url(../images/home.png); } +#top-menu a.my-page { background-image: url(../../../images/user.png); } +#top-menu a.projects { background-image: url(../../../images/projects.png); } +#top-menu a.administration { background-image: url(../images/wrench.png); } +#top-menu a.help { background-image: url(../../../images/help.png); } diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e479c671ce697e72b11bd49cf15871d767b7e451.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e479c671ce697e72b11bd49cf15871d767b7e451.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,121 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 WikiFormatting + module Macros + module Definitions + def exec_macro(name, obj, args) + method_name = "macro_#{name}" + send(method_name, obj, args) if respond_to?(method_name) + end + + def extract_macro_options(args, *keys) + options = {} + while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym) + options[$1.downcase.to_sym] = $2 + args.pop + end + return [args, options] + end + end + + @@available_macros = {} + + class << self + # Called with a block to define additional macros. + # Macro blocks accept 2 arguments: + # * obj: the object that is rendered + # * args: macro arguments + # + # Plugins can use this method to define new macros: + # + # Redmine::WikiFormatting::Macros.register do + # desc "This is my macro" + # macro :my_macro do |obj, args| + # "My macro output" + # end + # end + def register(&block) + class_eval(&block) if block_given? + end + + private + # Defines a new macro with the given name and block. + def macro(name, &block) + name = name.to_sym if name.is_a?(String) + @@available_macros[name] = @@desc || '' + @@desc = nil + raise "Can not create a macro without a block!" unless block_given? + Definitions.send :define_method, "macro_#{name}".downcase, &block + end + + # Sets description for the next macro to be defined + def desc(txt) + @@desc = txt + end + end + + # Builtin macros + desc "Sample macro." + macro :hello_world do |obj, args| + "Hello world! Object: #{obj.class.name}, " + (args.empty? ? "Called with no argument." : "Arguments: #{args.join(', ')}") + end + + desc "Displays a list of all available macros, including description if available." + macro :macro_list do |obj, args| + out = '' + @@available_macros.keys.collect(&:to_s).sort.each do |macro| + out << content_tag('dt', content_tag('code', macro)) + out << content_tag('dd', textilizable(@@available_macros[macro.to_sym])) + end + content_tag('dl', out) + end + + desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" + + " !{{child_pages}} -- can be used from a wiki page only\n" + + " !{{child_pages(Foo)}} -- lists all children of page Foo\n" + + " !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo" + macro :child_pages do |obj, args| + args, options = extract_macro_options(args, :parent) + page = nil + if args.size > 0 + page = Wiki.find_page(args.first.to_s, :project => @project) + elsif obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version) + page = obj.page + else + raise 'With no argument, this macro can be called from wiki pages only.' + end + raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) + pages = ([page] + page.descendants).group_by(&:parent_id) + render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id) + end + + desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" + macro :include do |obj, args| + page = Wiki.find_page(args.first.to_s, :project => @project) + raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) + @included_wiki_pages ||= [] + raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) + @included_wiki_pages << page.title + out = textilizable(page.content, :text, :attachments => page.attachments, :headings => false) + @included_wiki_pages.pop + out + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e47c28874d93e63d4ec1ec20c05fe818fb5867d7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e47c28874d93e63d4ec1ec20c05fe818fb5867d7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,309 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'diff' + +# The WikiController follows the Rails REST controller pattern but with +# a few differences +# +# * index - shows a list of WikiPages grouped by page or date +# * new - not used +# * create - not used +# * show - will also show the form for creating a new wiki page +# * edit - used to edit an existing or new page +# * update - used to save a wiki page update to the database, including new pages +# * destroy - normal +# +# Other member and collection methods are also used +# +# TODO: still being worked on +class WikiController < ApplicationController + default_search_scope :wiki_pages + before_filter :find_wiki, :authorize + before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] + before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy] + + helper :attachments + include AttachmentsHelper + helper :watchers + include Redmine::Export::PDF + + # List of pages, sorted alphabetically and by parent (hierarchy) + def index + load_pages_for_index + @pages_by_parent_id = @pages.group_by(&:parent_id) + end + + # List of page, by last update + def date_index + load_pages_for_index + @pages_by_date = @pages.group_by {|p| p.updated_on.to_date} + end + + # display a page (in editing mode if it doesn't exist) + def show + if @page.new_record? + if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? + edit + render :action => 'edit' + else + render_404 + end + return + end + if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project) + # Redirects user to the current version if he's not allowed to view previous versions + redirect_to :version => nil + return + end + @content = @page.content_for_version(params[:version]) + if User.current.allowed_to?(:export_wiki_pages, @project) + if params[:format] == 'pdf' + send_data(wiki_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf") + return + elsif params[:format] == 'html' + export = render_to_string :action => 'export', :layout => false + send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") + return + elsif params[:format] == 'txt' + send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") + return + end + end + @editable = editable? + @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) && + @content.current_version? && + Redmine::WikiFormatting.supports_section_edit? + + render :action => 'show' + end + + # edit an existing page or a new one + def edit + return render_403 unless editable? + @page.content = WikiContent.new(:page => @page) if @page.new_record? + + @content = @page.content_for_version(params[:version]) + @content.text = initial_page_content(@page) if @content.text.blank? + # don't keep previous comment + @content.comments = nil + + # To prevent StaleObjectError exception when reverting to a previous version + @content.version = @page.content.version + + @text = @content.text + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section) + render_404 if @text.blank? + end + end + + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + # Creates a new page or updates an existing one + def update + return render_403 unless editable? + @page.content = WikiContent.new(:page => @page) if @page.new_record? + + @content = @page.content_for_version(params[:version]) + @content.text = initial_page_content(@page) if @content.text.blank? + # don't keep previous comment + @content.comments = nil + + if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text] + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + # don't save if text wasn't changed + redirect_to :action => 'show', :project_id => @project, :id => @page.title + return + end + + @content.comments = params[:content][:comments] + @text = params[:content][:text] + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @section_hash = params[:section_hash] + @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) + else + @content.version = params[:content][:version] + @content.text = @text + end + @content.author = User.current + # if page is new @page.save will also save content, but not if page isn't a new record + if (@page.new_record? ? @page.save : @content.save) + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) + redirect_to :action => 'show', :project_id => @project, :id => @page.title + else + render :action => 'edit' + end + + rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError + # Optimistic locking exception + flash.now[:error] = l(:notice_locking_conflict) + render :action => 'edit' + end + + # rename a page + def rename + return render_403 unless editable? + @page.redirect_existing_links = true + # used to display the *original* title if some AR validation errors occur + @original_title = @page.pretty_title + if request.post? && @page.update_attributes(params[:wiki_page]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'show', :project_id => @project, :id => @page.title + end + end + + verify :method => :post, :only => :protect, :redirect_to => { :action => :show } + def protect + @page.update_attribute :protected, params[:protected] + redirect_to :action => 'show', :project_id => @project, :id => @page.title + end + + # show page history + def history + @version_count = @page.content.versions.count + @version_pages = Paginator.new self, @version_count, per_page_option, params['p'] + # don't load text + @versions = @page.content.versions.find :all, + :select => "id, author_id, comments, updated_on, version", + :order => 'version DESC', + :limit => @version_pages.items_per_page + 1, + :offset => @version_pages.current.offset + + render :layout => false if request.xhr? + end + + def diff + @diff = @page.diff(params[:version], params[:version_from]) + render_404 unless @diff + end + + def annotate + @annotate = @page.annotate(params[:version]) + render_404 unless @annotate + end + + verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show } + # Removes a wiki page and its history + # Children can be either set as root pages, removed or reassigned to another parent page + def destroy + return render_403 unless editable? + + @descendants_count = @page.descendants.size + if @descendants_count > 0 + case params[:todo] + when 'nullify' + # Nothing to do + when 'destroy' + # Removes all its descendants + @page.descendants.each(&:destroy) + when 'reassign' + # Reassign children to another parent page + reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i) + return unless reassign_to + @page.children.each do |child| + child.update_attribute(:parent, reassign_to) + end + else + @reassignable_to = @wiki.pages - @page.self_and_descendants + return + end + end + @page.destroy + redirect_to :action => 'index', :project_id => @project + end + + # Export wiki to a single html file + def export + if User.current.allowed_to?(:export_wiki_pages, @project) + @pages = @wiki.pages.find :all, :order => 'title' + export = render_to_string :action => 'export_multiple', :layout => false + send_data(export, :type => 'text/html', :filename => "wiki.html") + else + redirect_to :action => 'show', :project_id => @project, :id => nil + end + end + + def preview + page = @wiki.find_page(params[:id]) + # page is nil when previewing a new page + return render_403 unless page.nil? || editable?(page) + if page + @attachements = page.attachments + @previewed = page.content + end + @text = params[:content][:text] + render :partial => 'common/preview' + end + + def add_attachment + return render_403 unless editable? + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + redirect_to :action => 'show', :id => @page.title, :project_id => @project + end + +private + + def find_wiki + @project = Project.find(params[:project_id]) + @wiki = @project.wiki + render_404 unless @wiki + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Finds the requested page or a new page if it doesn't exist + def find_existing_or_new_page + @page = @wiki.find_or_new_page(params[:id]) + if @wiki.page_found_with_redirect? + redirect_to params.update(:id => @page.title) + end + end + + # Finds the requested page and returns a 404 error if it doesn't exist + def find_existing_page + @page = @wiki.find_page(params[:id]) + if @page.nil? + render_404 + return + end + if @wiki.page_found_with_redirect? + redirect_to params.update(:id => @page.title) + end + end + + # Returns true if the current user is allowed to edit the page, otherwise false + def editable?(page = @page) + page.editable_by?(User.current) + end + + # Returns the default content of a new wiki page + def initial_page_content(page) + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper unless self.instance_of?(helper) + helper.instance_method(:initial_page_content).bind(self).call(page) + end + + def load_pages_for_index + @pages = @wiki.pages.with_updated_on.all(:order => 'title', :include => {:wiki => :project}) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e47cb90efa63229aa14e53e4ddde691e5e77e91c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e47cb90efa63229aa14e53e4ddde691e5e77e91c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddMissingIndexesToDocuments < ActiveRecord::Migration + def self.up + add_index :documents, :category_id + end + + def self.down + remove_index :documents, :category_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e4ab6d8e5432db058f2447acda154774358a5665.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e4ab6d8e5432db058f2447acda154774358a5665.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1029 @@ +# Finnish translations for Ruby on Rails +# by Marko Seppä (marko.seppa@gmail.com) + +fi: + direction: ltr + date: + formats: + default: "%e. %Bta %Y" + long: "%A%e. %Bta %Y" + short: "%e.%m.%Y" + + day_names: [Sunnuntai, Maanantai, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai] + abbr_day_names: [Su, Ma, Ti, Ke, To, Pe, La] + month_names: [~, Tammikuu, Helmikuu, Maaliskuu, Huhtikuu, Toukokuu, Kesäkuu, Heinäkuu, Elokuu, Syyskuu, Lokakuu, Marraskuu, Joulukuu] + abbr_month_names: [~, Tammi, Helmi, Maalis, Huhti, Touko, Kesä, Heinä, Elo, Syys, Loka, Marras, Joulu] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %e. %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%e. %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "aamupäivä" + pm: "iltapäivä" + + support: + array: + words_connector: ", " + two_words_connector: " ja " + last_word_connector: " ja " + + + + number: + format: + separator: "," + delimiter: "." + precision: 3 + + currency: + format: + format: "%n %u" + unit: "€" + separator: "," + delimiter: "." + precision: 2 + + percentage: + format: + # separator: + delimiter: "" + # precision: + + precision: + format: + # separator: + delimiter: "" + # precision: + + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Tavua" + other: "Tavua" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + datetime: + distance_in_words: + half_a_minute: "puoli minuuttia" + less_than_x_seconds: + one: "aiemmin kuin sekunti" + other: "aiemmin kuin %{count} sekuntia" + x_seconds: + one: "sekunti" + other: "%{count} sekuntia" + less_than_x_minutes: + one: "aiemmin kuin minuutti" + other: "aiemmin kuin %{count} minuuttia" + x_minutes: + one: "minuutti" + other: "%{count} minuuttia" + about_x_hours: + one: "noin tunti" + other: "noin %{count} tuntia" + x_days: + one: "päivä" + other: "%{count} päivää" + about_x_months: + one: "noin kuukausi" + other: "noin %{count} kuukautta" + x_months: + one: "kuukausi" + other: "%{count} kuukautta" + about_x_years: + one: "vuosi" + other: "noin %{count} vuotta" + over_x_years: + one: "yli vuosi" + other: "yli %{count} vuotta" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + prompts: + year: "Vuosi" + month: "Kuukausi" + day: "Päivä" + hour: "Tunti" + minute: "Minuutti" + second: "Sekuntia" + + activerecord: + errors: + template: + header: + one: "1 virhe esti tämän %{model} mallinteen tallentamisen" + other: "%{count} virhettä esti tämän %{model} mallinteen tallentamisen" + body: "Seuraavat kentät aiheuttivat ongelmia:" + messages: + inclusion: "ei löydy listauksesta" + exclusion: "on jo varattu" + invalid: "on kelvoton" + confirmation: "ei vastaa varmennusta" + accepted: "täytyy olla hyväksytty" + empty: "ei voi olla tyhjä" + blank: "ei voi olla sisällötön" + too_long: "on liian pitkä (maksimi on %{count} merkkiä)" + too_short: "on liian lyhyt (minimi on %{count} merkkiä)" + wrong_length: "on väärän pituinen (täytyy olla täsmälleen %{count} merkkiä)" + taken: "on jo käytössä" + not_a_number: "ei ole numero" + greater_than: "täytyy olla suurempi kuin %{count}" + greater_than_or_equal_to: "täytyy olla suurempi tai yhtä suuri kuin%{count}" + equal_to: "täytyy olla yhtä suuri kuin %{count}" + less_than: "täytyy olla pienempi kuin %{count}" + less_than_or_equal_to: "täytyy olla pienempi tai yhtä suuri kuin %{count}" + odd: "täytyy olla pariton" + even: "täytyy olla parillinen" + greater_than_start_date: "tulee olla aloituspäivän jälkeinen" + not_same_project: "ei kuulu samaan projektiin" + circular_dependency: "Tämä suhde loisi kehän." + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Valitse, ole hyvä + + general_text_No: 'Ei' + general_text_Yes: 'Kyllä' + general_text_no: 'ei' + general_text_yes: 'kyllä' + general_lang_name: 'Finnish (Suomi)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-15 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Tilin päivitys onnistui. + notice_account_invalid_creditentials: Virheellinen käyttäjätunnus tai salasana + notice_account_password_updated: Salasanan päivitys onnistui. + notice_account_wrong_password: Väärä salasana + notice_account_register_done: Tilin luonti onnistui. Aktivoidaksesi tilin seuraa linkkiä joka välitettiin sähköpostiisi. + notice_account_unknown_email: Tuntematon käyttäjä. + notice_can_t_change_password: Tämä tili käyttää ulkoista tunnistautumisjärjestelmää. Salasanaa ei voi muuttaa. + notice_account_lost_email_sent: Sinulle on lähetetty sähköposti jossa on ohje kuinka vaihdat salasanasi. + notice_account_activated: Tilisi on nyt aktivoitu, voit kirjautua sisälle. + notice_successful_create: Luonti onnistui. + notice_successful_update: Päivitys onnistui. + notice_successful_delete: Poisto onnistui. + notice_successful_connection: Yhteyden muodostus onnistui. + notice_file_not_found: Hakemaasi sivua ei löytynyt tai se on poistettu. + notice_locking_conflict: Toinen käyttäjä on päivittänyt tiedot. + notice_not_authorized: Sinulla ei ole oikeutta näyttää tätä sivua. + notice_email_sent: "Sähköposti on lähetty osoitteeseen %{value}" + notice_email_error: "Sähköpostilähetyksessä tapahtui virhe (%{value})" + notice_feeds_access_key_reseted: RSS salasana on nollaantunut. + notice_failed_to_save_issues: "%{count} Tapahtum(an/ien) tallennus epäonnistui %{total} valitut: %{ids}." + notice_no_issue_selected: "Tapahtumia ei ole valittu! Valitse tapahtumat joita haluat muokata." + notice_account_pending: "Tilisi on luotu ja odottaa ylläpitäjän hyväksyntää." + notice_default_data_loaded: Vakioasetusten palautus onnistui. + + error_can_t_load_default_data: "Vakioasetuksia ei voitu ladata: %{value}" + error_scm_not_found: "Syötettä ja/tai versiota ei löydy tietovarastosta." + error_scm_command_failed: "Tietovarastoon pääsyssä tapahtui virhe: %{value}" + + mail_subject_lost_password: "Sinun %{value} salasanasi" + mail_body_lost_password: 'Vaihtaaksesi salasanasi, napsauta seuraavaa linkkiä:' + mail_subject_register: "%{value} tilin aktivointi" + mail_body_register: 'Aktivoidaksesi tilisi, napsauta seuraavaa linkkiä:' + mail_body_account_information_external: "Voit nyt käyttää %{value} tiliäsi kirjautuaksesi järjestelmään." + mail_body_account_information: Sinun tilin tiedot + mail_subject_account_activation_request: "%{value} tilin aktivointi pyyntö" + mail_body_account_activation_request: "Uusi käyttäjä (%{value}) on rekisteröitynyt. Hänen tili odottaa hyväksyntääsi:" + + gui_validation_error: 1 virhe + gui_validation_error_plural: "%{count} virhettä" + + field_name: Nimi + field_description: Kuvaus + field_summary: Yhteenveto + field_is_required: Vaaditaan + field_firstname: Etunimi + field_lastname: Sukunimi + field_mail: Sähköposti + field_filename: Tiedosto + field_filesize: Koko + field_downloads: Latausta + field_author: Tekijä + field_created_on: Luotu + field_updated_on: Päivitetty + field_field_format: Muoto + field_is_for_all: Kaikille projekteille + field_possible_values: Mahdolliset arvot + field_regexp: Säännöllinen lauseke (reg exp) + field_min_length: Minimipituus + field_max_length: Maksimipituus + field_value: Arvo + field_category: Luokka + field_title: Otsikko + field_project: Projekti + field_issue: Tapahtuma + field_status: Tila + field_notes: Muistiinpanot + field_is_closed: Tapahtuma suljettu + field_is_default: Vakioarvo + field_tracker: Tapahtuma + field_subject: Aihe + field_due_date: Määräaika + field_assigned_to: Nimetty + field_priority: Prioriteetti + field_fixed_version: Kohdeversio + field_user: Käyttäjä + field_role: Rooli + field_homepage: Kotisivu + field_is_public: Julkinen + field_parent: Aliprojekti + field_is_in_roadmap: Tapahtumat näytetään roadmap näkymässä + field_login: Kirjautuminen + field_mail_notification: Sähköposti muistutukset + field_admin: Ylläpitäjä + field_last_login_on: Viimeinen yhteys + field_language: Kieli + field_effective_date: Päivä + field_password: Salasana + field_new_password: Uusi salasana + field_password_confirmation: Vahvistus + field_version: Versio + field_type: Tyyppi + field_host: Verkko-osoite + field_port: Portti + field_account: Tili + field_base_dn: Base DN + field_attr_login: Kirjautumismääre + field_attr_firstname: Etuminenmääre + field_attr_lastname: Sukunimenmääre + field_attr_mail: Sähköpostinmääre + field_onthefly: Automaattinen käyttäjien luonti + field_start_date: Alku + field_done_ratio: "% Tehty" + field_auth_source: Varmennusmuoto + field_hide_mail: Piiloita sähköpostiosoitteeni + field_comments: Kommentti + field_url: URL + field_start_page: Aloitussivu + field_subproject: Aliprojekti + field_hours: Tuntia + field_activity: Historia + field_spent_on: Päivä + field_identifier: Tunniste + field_is_filter: Käytetään suodattimena + field_issue_to: Liittyvä tapahtuma + field_delay: Viive + field_assignable: Tapahtumia voidaan nimetä tälle roolille + field_redirect_existing_links: Uudelleenohjaa olemassa olevat linkit + field_estimated_hours: Arvioitu aika + field_column_names: Saraketta + field_time_zone: Aikavyöhyke + field_searchable: Haettava + field_default_value: Vakioarvo + + setting_app_title: Ohjelman otsikko + setting_app_subtitle: Ohjelman alaotsikko + setting_welcome_text: Tervehdysteksti + setting_default_language: Vakiokieli + setting_login_required: Pakollinen kirjautuminen + setting_self_registration: Itserekisteröinti + setting_attachment_max_size: Liitteen maksimikoko + setting_issues_export_limit: Tapahtumien vientirajoite + setting_mail_from: Lähettäjän sähköpostiosoite + setting_bcc_recipients: Vastaanottajat piilokopiona (bcc) + setting_host_name: Verkko-osoite + setting_text_formatting: Tekstin muotoilu + setting_wiki_compression: Wiki historian pakkaus + setting_feeds_limit: Syötteen sisällön raja + setting_autofetch_changesets: Automaattisten muutosjoukkojen haku + setting_sys_api_enabled: Salli WS tietovaraston hallintaan + setting_commit_ref_keywords: Viittaavat hakusanat + setting_commit_fix_keywords: Korjaavat hakusanat + setting_autologin: Automaatinen kirjautuminen + setting_date_format: Päivän muoto + setting_time_format: Ajan muoto + setting_cross_project_issue_relations: Salli projektien väliset tapahtuminen suhteet + setting_issue_list_default_columns: Vakiosarakkeiden näyttö tapahtumalistauksessa + setting_emails_footer: Sähköpostin alatunniste + setting_protocol: Protokolla + setting_per_page_options: Sivun objektien määrän asetukset + + label_user: Käyttäjä + label_user_plural: Käyttäjät + label_user_new: Uusi käyttäjä + label_project: Projekti + label_project_new: Uusi projekti + label_project_plural: Projektit + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Kaikki projektit + label_project_latest: Uusimmat projektit + label_issue: Tapahtuma + label_issue_new: Uusi tapahtuma + label_issue_plural: Tapahtumat + label_issue_view_all: Näytä kaikki tapahtumat + label_issues_by: "Tapahtumat %{value}" + label_document: Dokumentti + label_document_new: Uusi dokumentti + label_document_plural: Dokumentit + label_role: Rooli + label_role_plural: Roolit + label_role_new: Uusi rooli + label_role_and_permissions: Roolit ja oikeudet + label_member: Jäsen + label_member_new: Uusi jäsen + label_member_plural: Jäsenet + label_tracker: Tapahtuma + label_tracker_plural: Tapahtumat + label_tracker_new: Uusi tapahtuma + label_workflow: Työnkulku + label_issue_status: Tapahtuman tila + label_issue_status_plural: Tapahtumien tilat + label_issue_status_new: Uusi tila + label_issue_category: Tapahtumaluokka + label_issue_category_plural: Tapahtumaluokat + label_issue_category_new: Uusi luokka + label_custom_field: Räätälöity kenttä + label_custom_field_plural: Räätälöidyt kentät + label_custom_field_new: Uusi räätälöity kenttä + label_enumerations: Lista + label_enumeration_new: Uusi arvo + label_information: Tieto + label_information_plural: Tiedot + label_please_login: Kirjaudu ole hyvä + label_register: Rekisteröidy + label_password_lost: Hukattu salasana + label_home: Koti + label_my_page: Omasivu + label_my_account: Oma tili + label_my_projects: Omat projektit + label_administration: Ylläpito + label_login: Kirjaudu sisään + label_logout: Kirjaudu ulos + label_help: Ohjeet + label_reported_issues: Raportoidut tapahtumat + label_assigned_to_me_issues: Minulle nimetyt tapahtumat + label_last_login: Viimeinen yhteys + label_registered_on: Rekisteröity + label_activity: Historia + label_new: Uusi + label_logged_as: Kirjauduttu nimellä + label_environment: Ympäristö + label_authentication: Varmennus + label_auth_source: Varmennustapa + label_auth_source_new: Uusi varmennustapa + label_auth_source_plural: Varmennustavat + label_subproject_plural: Aliprojektit + label_min_max_length: Min - Max pituudet + label_list: Lista + label_date: Päivä + label_integer: Kokonaisluku + label_float: Liukuluku + label_boolean: Totuusarvomuuttuja + label_string: Merkkijono + label_text: Pitkä merkkijono + label_attribute: Määre + label_attribute_plural: Määreet + label_download: "%{count} Lataus" + label_download_plural: "%{count} Lataukset" + label_no_data: Ei tietoa näytettäväksi + label_change_status: Muutos tila + label_history: Historia + label_attachment: Tiedosto + label_attachment_new: Uusi tiedosto + label_attachment_delete: Poista tiedosto + label_attachment_plural: Tiedostot + label_report: Raportti + label_report_plural: Raportit + label_news: Uutinen + label_news_new: Lisää uutinen + label_news_plural: Uutiset + label_news_latest: Viimeisimmät uutiset + label_news_view_all: Näytä kaikki uutiset + label_settings: Asetukset + label_overview: Yleiskatsaus + label_version: Versio + label_version_new: Uusi versio + label_version_plural: Versiot + label_confirmation: Vahvistus + label_export_to: Vie + label_read: Lukee... + label_public_projects: Julkiset projektit + label_open_issues: avoin, yhteensä + label_open_issues_plural: avointa, yhteensä + label_closed_issues: suljettu + label_closed_issues_plural: suljettua + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Yhteensä + label_permissions: Oikeudet + label_current_status: Nykyinen tila + label_new_statuses_allowed: Uudet tilat sallittu + label_all: kaikki + label_none: ei mitään + label_nobody: ei kukaan + label_next: Seuraava + label_previous: Edellinen + label_used_by: Käytetty + label_details: Yksityiskohdat + label_add_note: Lisää muistiinpano + label_per_page: Per sivu + label_calendar: Kalenteri + label_months_from: kuukauden päässä + label_gantt: Gantt + label_internal: Sisäinen + label_last_changes: "viimeiset %{count} muutokset" + label_change_view_all: Näytä kaikki muutokset + label_personalize_page: Personoi tämä sivu + label_comment: Kommentti + label_comment_plural: Kommentit + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Lisää kommentti + label_comment_added: Kommentti lisätty + label_comment_delete: Poista kommentti + label_query: Räätälöity haku + label_query_plural: Räätälöidyt haut + label_query_new: Uusi haku + label_filter_add: Lisää suodatin + label_filter_plural: Suodattimet + label_equals: sama kuin + label_not_equals: eri kuin + label_in_less_than: pienempi kuin + label_in_more_than: suurempi kuin + label_today: tänään + label_this_week: tällä viikolla + label_less_than_ago: vähemmän kuin päivää sitten + label_more_than_ago: enemän kuin päivää sitten + label_ago: päiviä sitten + label_contains: sisältää + label_not_contains: ei sisällä + label_day_plural: päivää + label_repository: Tietovarasto + label_repository_plural: Tietovarastot + label_browse: Selaus + label_modification: "%{count} muutos" + label_modification_plural: "%{count} muutettu" + label_revision: Versio + label_revision_plural: Versiot + label_added: lisätty + label_modified: muokattu + label_deleted: poistettu + label_latest_revision: Viimeisin versio + label_latest_revision_plural: Viimeisimmät versiot + label_view_revisions: Näytä versiot + label_max_size: Suurin koko + label_sort_highest: Siirrä ylimmäiseksi + label_sort_higher: Siirrä ylös + label_sort_lower: Siirrä alas + label_sort_lowest: Siirrä alimmaiseksi + label_roadmap: Roadmap + label_roadmap_due_in: "Määräaika %{value}" + label_roadmap_overdue: "%{value} myöhässä" + label_roadmap_no_issues: Ei tapahtumia tälle versiolle + label_search: Haku + label_result_plural: Tulokset + label_all_words: kaikki sanat + label_wiki: Wiki + label_wiki_edit: Wiki muokkaus + label_wiki_edit_plural: Wiki muokkaukset + label_wiki_page: Wiki sivu + label_wiki_page_plural: Wiki sivut + label_index_by_title: Hakemisto otsikoittain + label_index_by_date: Hakemisto päivittäin + label_current_version: Nykyinen versio + label_preview: Esikatselu + label_feed_plural: Syötteet + label_changes_details: Kaikkien muutosten yksityiskohdat + label_issue_tracking: Tapahtumien seuranta + label_spent_time: Käytetty aika + label_f_hour: "%{value} tunti" + label_f_hour_plural: "%{value} tuntia" + label_time_tracking: Ajan seuranta + label_change_plural: Muutokset + label_statistics: Tilastot + label_commits_per_month: Tapahtumaa per kuukausi + label_commits_per_author: Tapahtumaa per tekijä + label_view_diff: Näytä erot + label_diff_inline: sisällössä + label_diff_side_by_side: vierekkäin + label_options: Valinnat + label_copy_workflow_from: Kopioi työnkulku + label_permissions_report: Oikeuksien raportti + label_watched_issues: Seurattavat tapahtumat + label_related_issues: Liittyvät tapahtumat + label_applied_status: Lisätty tila + label_loading: Lataa... + label_relation_new: Uusi suhde + label_relation_delete: Poista suhde + label_relates_to: liittyy + label_duplicates: kopio + label_blocks: estää + label_blocked_by: estetty + label_precedes: edeltää + label_follows: seuraa + label_end_to_start: lopusta alkuun + label_end_to_end: lopusta loppuun + label_start_to_start: alusta alkuun + label_start_to_end: alusta loppuun + label_stay_logged_in: Pysy kirjautuneena + label_disabled: poistettu käytöstä + label_show_completed_versions: Näytä valmiit versiot + label_me: minä + label_board: Keskustelupalsta + label_board_new: Uusi keskustelupalsta + label_board_plural: Keskustelupalstat + label_topic_plural: Aiheet + label_message_plural: Viestit + label_message_last: Viimeisin viesti + label_message_new: Uusi viesti + label_reply_plural: Vastaukset + label_send_information: Lähetä tilin tiedot käyttäjälle + label_year: Vuosi + label_month: Kuukausi + label_week: Viikko + label_language_based: Pohjautuen käyttäjän kieleen + label_sort_by: "Lajittele %{value}" + label_send_test_email: Lähetä testi sähköposti + label_feeds_access_key_created_on: "RSS salasana luotiin %{value} sitten" + label_module_plural: Moduulit + label_added_time_by: "Lisännyt %{author} %{age} sitten" + label_updated_time: "Päivitetty %{value} sitten" + label_jump_to_a_project: Siirry projektiin... + label_file_plural: Tiedostot + label_changeset_plural: Muutosryhmät + label_default_columns: Vakiosarakkeet + label_no_change_option: (Ei muutosta) + label_bulk_edit_selected_issues: Perusmuotoile valitut tapahtumat + label_theme: Teema + label_default: Vakio + label_search_titles_only: Hae vain otsikot + label_user_mail_option_all: "Kaikista tapahtumista kaikissa projekteistani" + label_user_mail_option_selected: "Kaikista tapahtumista vain valitsemistani projekteista..." + label_user_mail_no_self_notified: "En halua muistutusta muutoksista joita itse teen" + label_registration_activation_by_email: tilin aktivointi sähköpostitse + label_registration_manual_activation: tilin aktivointi käsin + label_registration_automatic_activation: tilin aktivointi automaattisesti + label_display_per_page: "Per sivu: %{value}" + label_age: Ikä + label_change_properties: Vaihda asetuksia + label_general: Yleinen + + button_login: Kirjaudu + button_submit: Lähetä + button_save: Tallenna + button_check_all: Valitse kaikki + button_uncheck_all: Poista valinnat + button_delete: Poista + button_create: Luo + button_test: Testaa + button_edit: Muokkaa + button_add: Lisää + button_change: Muuta + button_apply: Ota käyttöön + button_clear: Tyhjää + button_lock: Lukitse + button_unlock: Vapauta + button_download: Lataa + button_list: Lista + button_view: Näytä + button_move: Siirrä + button_back: Takaisin + button_cancel: Peruuta + button_activate: Aktivoi + button_sort: Järjestä + button_log_time: Seuraa aikaa + button_rollback: Siirry takaisin tähän versioon + button_watch: Seuraa + button_unwatch: Älä seuraa + button_reply: Vastaa + button_archive: Arkistoi + button_unarchive: Palauta + button_reset: Nollaus + button_rename: Uudelleen nimeä + button_change_password: Vaihda salasana + button_copy: Kopioi + button_annotate: Lisää selitys + button_update: Päivitä + + status_active: aktiivinen + status_registered: rekisteröity + status_locked: lukittu + + text_select_mail_notifications: Valitse tapahtumat joista tulisi lähettää sähköpostimuistutus. + text_regexp_info: esim. ^[A-Z0-9]+$ + text_min_max_length_info: 0 tarkoittaa, ei rajoitusta + text_project_destroy_confirmation: Oletko varma että haluat poistaa tämän projektin ja kaikki siihen kuuluvat tiedot? + text_workflow_edit: Valitse rooli ja tapahtuma muokataksesi työnkulkua + text_are_you_sure: Oletko varma? + text_tip_issue_begin_day: tehtävä joka alkaa tänä päivänä + text_tip_issue_end_day: tehtävä joka loppuu tänä päivänä + text_tip_issue_begin_end_day: tehtävä joka alkaa ja loppuu tänä päivänä + text_project_identifier_info: 'Pienet kirjaimet (a-z), numerot ja viivat ovat sallittu.
    Tallentamisen jälkeen tunnistetta ei voi muuttaa.' + text_caracters_maximum: "%{count} merkkiä enintään." + text_caracters_minimum: "Täytyy olla vähintään %{count} merkkiä pitkä." + text_length_between: "Pituus välillä %{min} ja %{max} merkkiä." + text_tracker_no_workflow: Työnkulkua ei määritelty tälle tapahtumalle + text_unallowed_characters: Kiellettyjä merkkejä + text_comma_separated: Useat arvot sallittu (pilkku eroteltuna). + text_issues_ref_in_commit_messages: Liitän ja korjaan ongelmia syötetyssä viestissä + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Oletko varma että haluat poistaa tämän wiki:n ja kaikki sen sisältämän tiedon? + text_issue_category_destroy_question: "Jotkut tapahtumat (%{count}) ovat nimetty tälle luokalle. Mitä haluat tehdä?" + text_issue_category_destroy_assignments: Poista luokan tehtävät + text_issue_category_reassign_to: Vaihda tapahtuma tähän luokkaan + text_user_mail_option: "Valitsemattomille projekteille, saat vain muistutuksen asioista joita seuraat tai olet mukana (esim. tapahtumat joissa olet tekijä tai nimettynä)." + text_no_configuration_data: "Rooleja, tapahtumien tiloja ja työnkulkua ei vielä olla määritelty.\nOn erittäin suotavaa ladata vakioasetukset. Voit muuttaa sitä latauksen jälkeen." + text_load_default_configuration: Lataa vakioasetukset + + default_role_manager: Päälikkö + default_role_developer: Kehittäjä + default_role_reporter: Tarkastelija + default_tracker_bug: Ohjelmointivirhe + default_tracker_feature: Ominaisuus + default_tracker_support: Tuki + default_issue_status_new: Uusi + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Hyväksytty + default_issue_status_feedback: Palaute + default_issue_status_closed: Suljettu + default_issue_status_rejected: Hylätty + default_doc_category_user: Käyttäjä dokumentaatio + default_doc_category_tech: Tekninen dokumentaatio + default_priority_low: Matala + default_priority_normal: Normaali + default_priority_high: Korkea + default_priority_urgent: Kiireellinen + default_priority_immediate: Valitön + default_activity_design: Suunnittelu + default_activity_development: Kehitys + + enumeration_issue_priorities: Tapahtuman tärkeysjärjestys + enumeration_doc_categories: Dokumentin luokat + enumeration_activities: Historia (ajan seuranta) + label_associated_revisions: Liittyvät versiot + setting_user_format: Käyttäjien esitysmuoto + text_status_changed_by_changeset: "Päivitetty muutosversioon %{value}." + text_issues_destroy_confirmation: 'Oletko varma että haluat poistaa valitut tapahtumat ?' + label_more: Lisää + label_issue_added: Tapahtuma lisätty + label_issue_updated: Tapahtuma päivitetty + label_document_added: Dokumentti lisätty + label_message_posted: Viesti lisätty + label_file_added: Tiedosto lisätty + label_scm: SCM + text_select_project_modules: 'Valitse modulit jotka haluat käyttöön tähän projektiin:' + label_news_added: Uutinen lisätty + project_module_boards: Keskustelupalsta + project_module_issue_tracking: Tapahtuman seuranta + project_module_wiki: Wiki + project_module_files: Tiedostot + project_module_documents: Dokumentit + project_module_repository: Tietovarasto + project_module_news: Uutiset + project_module_time_tracking: Ajan seuranta + text_file_repository_writable: Kirjoitettava tiedostovarasto + text_default_administrator_account_changed: Vakio hallinoijan tunnus muutettu + text_rmagick_available: RMagick saatavilla (valinnainen) + button_configure: Asetukset + label_plugins: Lisäosat + label_ldap_authentication: LDAP tunnistautuminen + label_downloads_abbr: D/L + label_add_another_file: Lisää uusi tiedosto + label_this_month: tässä kuussa + text_destroy_time_entries_question: "%{hours} tuntia on raportoitu tapahtumasta jonka aiot poistaa. Mitä haluat tehdä ?" + label_last_n_days: "viimeiset %{count} päivää" + label_all_time: koko ajalta + error_issue_not_found_in_project: 'Tapahtumaa ei löytynyt tai se ei kuulu tähän projektiin' + label_this_year: tänä vuonna + text_assign_time_entries_to_project: Määritä tunnit projektille + label_date_range: Aikaväli + label_last_week: viime viikolla + label_yesterday: eilen + label_optional_description: Lisäkuvaus + label_last_month: viime kuussa + text_destroy_time_entries: Poista raportoidut tunnit + text_reassign_time_entries: 'Siirrä raportoidut tunnit tälle tapahtumalle:' + label_chronological_order: Aikajärjestyksessä + label_date_to: '' + setting_activity_days_default: Päivien esittäminen projektien historiassa + label_date_from: '' + label_in: '' + setting_display_subprojects_issues: Näytä aliprojektien tapahtumat pääprojektissa oletusarvoisesti + field_comments_sorting: Näytä kommentit + label_reverse_chronological_order: Käänteisessä aikajärjestyksessä + label_preferences: Asetukset + setting_default_projects_public: Uudet projektit ovat oletuksena julkisia + label_overall_activity: Kokonaishistoria + error_scm_annotate: "Merkintää ei ole tai siihen ei voi lisätä selityksiä." + label_planning: Suunnittelu + text_subprojects_destroy_warning: "Tämän aliprojekti(t): %{value} tullaan myös poistamaan." + label_and_its_subprojects: "%{value} ja aliprojektit" + mail_body_reminder: "%{count} sinulle nimettyä tapahtuma(a) erääntyy %{days} päivä sisään:" + mail_subject_reminder: "%{count} tapahtuma(a) erääntyy %{days} lähipäivinä" + text_user_wrote: "%{value} kirjoitti:" + label_duplicated_by: kopioinut + setting_enabled_scm: Versionhallinta käytettävissä + text_enumeration_category_reassign_to: 'Siirrä täksi arvoksi:' + text_enumeration_destroy_question: "%{count} kohdetta on sijoitettu tälle arvolle." + label_incoming_emails: Saapuvat sähköpostiviestit + label_generate_key: Luo avain + setting_mail_handler_api_enabled: Ota käyttöön WS saapuville sähköposteille + setting_mail_handler_api_key: API avain + text_email_delivery_not_configured: "Sähköpostin jakelu ei ole määritelty ja sähköpostimuistutukset eivät ole käytössä.\nKonfiguroi sähköpostipalvelinasetukset (SMTP) config/configuration.yml tiedostosta ja uudelleenkäynnistä sovellus jotta asetukset astuvat voimaan." + field_parent_title: Aloitussivu + label_issue_watchers: Tapahtuman seuraajat + button_quote: Vastaa + setting_sequential_project_identifiers: Luo peräkkäiset projektien tunnisteet + notice_unable_delete_version: Version poisto epäonnistui + label_renamed: uudelleennimetty + label_copied: kopioitu + setting_plain_text_mail: vain muotoilematonta tekstiä (ei HTML) + permission_view_files: Näytä tiedostot + permission_edit_issues: Muokkaa tapahtumia + permission_edit_own_time_entries: Muokka omia aikamerkintöjä + permission_manage_public_queries: Hallinnoi julkisia hakuja + permission_add_issues: Lisää tapahtumia + permission_log_time: Lokita käytettyä aikaa + permission_view_changesets: Näytä muutosryhmät + permission_view_time_entries: Näytä käytetty aika + permission_manage_versions: Hallinnoi versioita + permission_manage_wiki: Hallinnoi wikiä + permission_manage_categories: Hallinnoi tapahtumien luokkia + permission_protect_wiki_pages: Suojaa wiki sivut + permission_comment_news: Kommentoi uutisia + permission_delete_messages: Poista viestit + permission_select_project_modules: Valitse projektin modulit + permission_manage_documents: Hallinnoi dokumentteja + permission_edit_wiki_pages: Muokkaa wiki sivuja + permission_add_issue_watchers: Lisää seuraajia + permission_view_gantt: Näytä gantt kaavio + permission_move_issues: Siirrä tapahtuma + permission_manage_issue_relations: Hallinoi tapahtuman suhteita + permission_delete_wiki_pages: Poista wiki sivuja + permission_manage_boards: Hallinnoi keskustelupalstaa + permission_delete_wiki_pages_attachments: Poista liitteitä + permission_view_wiki_edits: Näytä wiki historia + permission_add_messages: Jätä viesti + permission_view_messages: Näytä viestejä + permission_manage_files: Hallinnoi tiedostoja + permission_edit_issue_notes: Muokkaa muistiinpanoja + permission_manage_news: Hallinnoi uutisia + permission_view_calendar: Näytä kalenteri + permission_manage_members: Hallinnoi jäseniä + permission_edit_messages: Muokkaa viestejä + permission_delete_issues: Poista tapahtumia + permission_view_issue_watchers: Näytä seuraaja lista + permission_manage_repository: Hallinnoi tietovarastoa + permission_commit_access: Tee pääsyoikeus + permission_browse_repository: Selaa tietovarastoa + permission_view_documents: Näytä dokumentit + permission_edit_project: Muokkaa projektia + permission_add_issue_notes: Lisää muistiinpanoja + permission_save_queries: Tallenna hakuja + permission_view_wiki_pages: Näytä wiki + permission_rename_wiki_pages: Uudelleennimeä wiki sivuja + permission_edit_time_entries: Muokkaa aika lokeja + permission_edit_own_issue_notes: Muokkaa omia muistiinpanoja + setting_gravatar_enabled: Käytä Gravatar käyttäjä ikoneita + label_example: Esimerkki + text_repository_usernames_mapping: "Valitse päivittääksesi Redmine käyttäjä jokaiseen käyttäjään joka löytyy tietovaraston lokista.\nKäyttäjät joilla on sama Redmine ja tietovaraston käyttäjänimi tai sähköpostiosoite, yhdistetään automaattisesti." + permission_edit_own_messages: Muokkaa omia viestejä + permission_delete_own_messages: Poista omia viestejä + label_user_activity: "Käyttäjän %{value} historia" + label_updated_time_by: "Updated by %{author} %{age} ago" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} file(s) could not be saved." + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + label_display: Display + field_editable: Editable + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Tee viestien koodaus + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e4/e4ae7944e9fb3ffff151b8eb6520ef3b01eae152.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e4/e4ae7944e9fb3ffff151b8eb6520ef3b01eae152.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +--- +boards_001: + name: Help + project_id: 1 + topics_count: 2 + id: 1 + description: Help board + position: 1 + last_message_id: 6 + messages_count: 6 +boards_002: + name: Discussion + project_id: 1 + topics_count: 0 + id: 2 + description: Discussion board + position: 2 + last_message_id: + messages_count: 0 +boards_003: + name: Discussion + project_id: 2 + topics_count: 0 + id: 3 + description: Discussion board + position: 1 + last_message_id: + messages_count: 0 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e503a43fce804a351af87e02ff0079c3add37355.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e503a43fce804a351af87e02ff0079c3add37355.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +the implicit plaintext part of the email \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e50a761d62eea449ace86c3d71d1d450b464aa81.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e50a761d62eea449ace86c3d71d1d450b464aa81.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Niedziela", + "Poniedziałek", + "Wtorek", + "Środa", + "Czwartek", + "Piątek", + "Sobota", + "Niedziela"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Nie", + "Pon", + "Wto", + "Śro", + "Czw", + "Pią", + "Sob", + "Nie"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Styczeń", + "Luty", + "Marzec", + "Kwiecień", + "Maj", + "Czerwiec", + "Lipiec", + "Sierpień", + "Wrzesień", + "Październik", + "Listopad", + "Grudzień"); + +// short month names +Calendar._SMN = new Array +("Sty", + "Lut", + "Mar", + "Kwi", + "Maj", + "Cze", + "Lip", + "Sie", + "Wrz", + "Paź", + "Lis", + "Gru"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O kalendarzu"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Po ostatnią wersję odwiedź: http://www.dynarch.com/projects/calendar/\n" + +"Rozpowszechniany pod licencją GNU LGPL. Zobacz: http://gnu.org/licenses/lgpl.html z celu zapoznania się ze szczegółami." + +"\n\n" + +"Wybór daty:\n" + +"- Użyj \xab, \xbb przycisków by zaznaczyć rok\n" + +"- Użyj " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " przycisków by zaznaczyć miesiąc\n" + +"- Trzymaj wciśnięty przycisk myszy na każdym z powyższych przycisków by przyśpieszyć zaznaczanie."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Wybór czasu:\n" + +"- Kliknij na każdym przedziale czasu aby go powiększyć\n" + +"- lub kliknij z przyciskiem Shift by go zmniejszyć\n" + +"- lub kliknij i przeciągnij dla szybszego zaznaczenia."; + +Calendar._TT["PREV_YEAR"] = "Poprz. rok (przytrzymaj dla menu)"; +Calendar._TT["PREV_MONTH"] = "Poprz. miesiąc (przytrzymaj dla menu)"; +Calendar._TT["GO_TODAY"] = "Idź do Dzisiaj"; +Calendar._TT["NEXT_MONTH"] = "Następny miesiąc(przytrzymaj dla menu)"; +Calendar._TT["NEXT_YEAR"] = "Następny rok (przytrzymaj dla menu)"; +Calendar._TT["SEL_DATE"] = "Zaznacz datę"; +Calendar._TT["DRAG_TO_MOVE"] = "Przeciągnij by przenieść"; +Calendar._TT["PART_TODAY"] = " (dzisiaj)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Pokaż %s pierwszy"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zamknij"; +Calendar._TT["TODAY"] = "Dzisiaj"; +Calendar._TT["TIME_PART"] = "(Shift-)Kliknij lub upuść by zmienić wartość"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%R-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Czas:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e54ebef30cd91954813654717934375e733126f9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e54ebef30cd91954813654717934375e733126f9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +<% fields_for :issue, @issue, :builder => TabularFormBuilder do |f| %> + +
    +<% if @issue.new_record? || @allowed_statuses.any? %> +

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    +<% else %> +

    <%= h(@issue.status.name) %>

    +<% end %> + +

    <%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %>

    +

    <%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %>

    +<% unless @project.issue_categories.empty? %> +

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> +<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), + l(:label_issue_category_new), + 'issue_category[name]', + {:controller => 'issue_categories', :action => 'create', :project_id => @project}, + :title => l(:label_issue_category_new), + :tabindex => 199) if authorize_for('issue_categories', 'new') %>

    +<% end %> +<% unless @issue.assignable_versions.empty? %> +

    <%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %> +<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), + l(:label_version_new), + 'version[name]', + {:controller => 'versions', :action => 'create', :project_id => @project}, + :title => l(:label_version_new), + :tabindex => 200) if authorize_for('versions', 'new') %> +

    +<% end %> +
    + +
    +<% if User.current.allowed_to?(:manage_subtasks, @project) %> +

    <%= f.text_field :parent_issue_id, :size => 10 %>

    +
    +<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> +<% end %> +

    <%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_start_date') if @issue.leaf? %>

    +

    <%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_due_date') if @issue.leaf? %>

    +

    <%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf? %> <%= l(:field_hours) %>

    +<% if @issue.leaf? && Issue.use_field_for_done_ratio? %> +

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    +<% end %> +
    + +
    +<%= render :partial => 'issues/form_custom_fields' %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e555989e34fe97a4b801d1d07f6843200d68c88c.svn-base Binary file .svn/pristine/e5/e555989e34fe97a4b801d1d07f6843200d68c88c.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e57df997ff48c90646e41377ffe484e755bccea7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e57df997ff48c90646e41377ffe484e755bccea7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class IssueCustomField < CustomField + has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id" + has_and_belongs_to_many :trackers, :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :foreign_key => "custom_field_id" + has_many :issues, :through => :issue_custom_values + + def type_name + :label_issue_plural + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e58c2b42a5313477b70486289636b96261ea464c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e58c2b42a5313477b70486289636b96261ea464c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,209 @@ +class TimeEntryReportsController < ApplicationController + menu_item :issues + before_filter :find_optional_project + before_filter :load_available_criterias + + helper :sort + include SortHelper + helper :issues + helper :timelog + include TimelogHelper + helper :custom_fields + include CustomFieldsHelper + + def report + @criterias = params[:criterias] || [] + @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria} + @criterias.uniq! + @criterias = @criterias[0,3] + + @columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month' + + retrieve_date_range + + unless @criterias.empty? + sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ') + sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ') + sql_condition = '' + + if @project.nil? + sql_condition = Project.allowed_to_condition(User.current, :view_time_entries) + elsif @issue.nil? + sql_condition = @project.project_condition(Setting.display_subprojects_issues?) + else + sql_condition = "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" + end + + sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours" + sql << " FROM #{TimeEntry.table_name}" + sql << time_report_joins + sql << " WHERE" + sql << " (%s) AND" % sql_condition + sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from), ActiveRecord::Base.connection.quoted_date(@to)] + sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on" + + @hours = ActiveRecord::Base.connection.select_all(sql) + + @hours.each do |row| + case @columns + when 'year' + row['year'] = row['tyear'] + when 'month' + row['month'] = "#{row['tyear']}-#{row['tmonth']}" + when 'week' + row['week'] = "#{row['tyear']}-#{row['tweek']}" + when 'day' + row['day'] = "#{row['spent_on']}" + end + end + + @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} + + @periods = [] + # Date#at_beginning_of_ not supported in Rails 1.2.x + date_from = @from.to_time + # 100 columns max + while date_from <= @to.to_time && @periods.length < 100 + case @columns + when 'year' + @periods << "#{date_from.year}" + date_from = (date_from + 1.year).at_beginning_of_year + when 'month' + @periods << "#{date_from.year}-#{date_from.month}" + date_from = (date_from + 1.month).at_beginning_of_month + when 'week' + @periods << "#{date_from.year}-#{date_from.to_date.cweek}" + date_from = (date_from + 7.day).at_beginning_of_week + when 'day' + @periods << "#{date_from.to_date}" + date_from = date_from + 1.day + end + end + end + + respond_to do |format| + format.html { render :layout => !request.xhr? } + format.csv { send_data(report_to_csv(@criterias, @periods, @hours), :type => 'text/csv; header=present', :filename => 'timelog.csv') } + end + end + + private + + # TODO: duplicated in TimelogController + def find_optional_project + if !params[:issue_id].blank? + @issue = Issue.find(params[:issue_id]) + @project = @issue.project + elsif !params[:project_id].blank? + @project = Project.find(params[:project_id]) + end + deny_access unless User.current.allowed_to?(:view_time_entries, @project, :global => true) + end + + # Retrieves the date range based on predefined ranges or specific from/to param dates + # TODO: duplicated in TimelogController + def retrieve_date_range + @free_period = false + @from, @to = nil, nil + + if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?) + case params[:period].to_s + when 'today' + @from = @to = Date.today + when 'yesterday' + @from = @to = Date.today - 1 + when 'current_week' + @from = Date.today - (Date.today.cwday - 1)%7 + @to = @from + 6 + when 'last_week' + @from = Date.today - 7 - (Date.today.cwday - 1)%7 + @to = @from + 6 + when '7_days' + @from = Date.today - 7 + @to = Date.today + when 'current_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) + @to = (@from >> 1) - 1 + when 'last_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) << 1 + @to = (@from >> 1) - 1 + when '30_days' + @from = Date.today - 30 + @to = Date.today + when 'current_year' + @from = Date.civil(Date.today.year, 1, 1) + @to = Date.civil(Date.today.year, 12, 31) + end + elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?)) + begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end + begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end + @free_period = true + else + # default + end + + @from, @to = @to, @from if @from && @to && @from > @to + @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) + @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) + end + + def load_available_criterias + @available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id", + :klass => Project, + :label => :label_project}, + 'version' => {:sql => "#{Issue.table_name}.fixed_version_id", + :klass => Version, + :label => :label_version}, + 'category' => {:sql => "#{Issue.table_name}.category_id", + :klass => IssueCategory, + :label => :field_category}, + 'member' => {:sql => "#{TimeEntry.table_name}.user_id", + :klass => User, + :label => :label_member}, + 'tracker' => {:sql => "#{Issue.table_name}.tracker_id", + :klass => Tracker, + :label => :label_tracker}, + 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id", + :klass => TimeEntryActivity, + :label => :label_activity}, + 'issue' => {:sql => "#{TimeEntry.table_name}.issue_id", + :klass => Issue, + :label => :label_issue} + } + + # Add list and boolean custom fields as available criterias + custom_fields = (@project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields) + custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf| + @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = #{Issue.table_name}.id)", + :format => cf.field_format, + :label => cf.name} + end if @project + + # Add list and boolean time entry custom fields + TimeEntryCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| + @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id)", + :format => cf.field_format, + :label => cf.name} + end + + # Add list and boolean time entry activity custom fields + TimeEntryActivityCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| + @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Enumeration' AND c.customized_id = #{TimeEntry.table_name}.activity_id)", + :format => cf.field_format, + :label => cf.name} + end + + call_hook(:controller_timelog_available_criterias, { :available_criterias => @available_criterias, :project => @project }) + @available_criterias + end + + def time_report_joins + sql = '' + sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" + sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id" + # TODO: rename hook + call_hook(:controller_timelog_time_report_joins, {:sql => sql} ) + sql + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e5cda32edd4891be4e2904e07eac74ee29c11391.svn-base Binary file .svn/pristine/e5/e5cda32edd4891be4e2904e07eac74ee29c11391.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e5e1ad43baf0abb2a829f70671bb4b2174f60107.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e5e1ad43baf0abb2a829f70671bb4b2174f60107.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,162 @@ +Bitstream Vera Fonts - April 16, 2003 +===================================== + +The version number of these fonts is 1.10 to distinguish them from the +beta test fonts. + +Note that the Vera copyright is incorporated in the fonts themselves. +The License field in the fonts contains the copyright license as it +appears below. The TrueType copyright field is not large enough to +contain the full license, so the license is incorporated (as you might +think if you thought about it) into the license field, which +unfortunately can be obscure to find. (In pfaedit, see: Element->Font +Info->TTFNames->License). + +Our apologies for it taking longer to complete the fonts than planned. +Beta testers requested a tighter line spacing (less leading) and Jim +Lyles redesigned Vera's accents to bring its line spacing to more +typical of other fonts. This took additional time and effort. Our +thanks to Jim for this effort above and beyond the call of duty. + +There are four monospace and sans faces (normal, oblique, bold, bold +oblique) and two serif faces (normal and bold). Fontconfig/Xft2 (see +www.fontconfig.org) can artificially oblique the serif faces for you: +this loses hinting and distorts the faces slightly, but is visibly +different than normal and bold, and reasonably pleasing. + +On systems with fontconfig 2.0 or 2.1 installed, making your sans, +serif and monospace fonts default to these fonts is very easy. Just +drop the file local.conf into your /etc/fonts directory. This will +make the Bitstream fonts your default fonts for all applications using +fontconfig (if sans, serif, or monospace names are used, as they often +are as default values in many desktops). The XML in local.conf may +need modification to enable subpixel decimation, if appropriate, +however, the commented out phrase does so for XFree86 4.3, in the case +that the server does not have sufficient information to identify the +use of a flat panel. Fontconfig 2.2 adds Vera to the list of font +families and will, by default use it as the default sans, serif and +monospace fonts. + +During the testing of the final Vera fonts, we learned that screen +fonts in general are only typically hinted to work correctly at +integer pixel sizes. Vera is coded internally for integer sizes only. +We need to investigate further to see if there are commonly used fonts +that are hinted to be rounded but are not rounded to integer sizes due +to oversights in their coding. + +Most fonts work best at 8 pixels and below if anti-aliased only, as +the amount of work required to hint well at smaller and smaller sizes +becomes astronomical. GASP tables are typically used to control +whether hinting is used or not, but Freetype/Xft does not currently +support GASP tables (which are present in Vera). + +To mitigate this problem, both for Vera and other fonts, there will be +(very shortly) a new fontconfig 2.2 release that will, by default not +apply hints if the size is below 8 pixels. if you should have a font +that in fact has been hinted more agressively, you can use fontconfig +to note this exception. We believe this should improve many hinted +fonts in addition to Vera, though implemeting GASP support is likely +the right long term solution. + +Font rendering in Gnome or KDE is the combination of algorithms in +Xft2 and Freetype, along with hinting in the fonts themselves. It is +vital to have sufficient information to disentangle problems that you +may observe. + +Note that having your font rendering system set up correctly is vital +to proper judgement of problems of the fonts: + + # Freetype may or may not be configured to in ways that may + implement execution of possibly patented (in some parts of the world) + TrueType hinting algorithms, particularly at small sizes. Best + results are obtained while using these algorithms. + + # The freetype autohinter (used when the possibly patented + algorithms are not used) continues to improve with each release. If + you are using the autohinter, please ensure you are using an up to + date version of freetype before reporting problems. + + # Please identify what version of freetype you are using in any + bug reports, and how your freetype is configured. + + # Make sure you are not using the freetype version included in + XFree86 4.3, as it has bugs that significantly degrade most fonts, + including Vera. if you build XFree86 4.3 from source yourself, you may + have installed this broken version without intending it (as I + did). Vera was verified with the recently released Freetype 2.1.4. On + many systems, 'ldd" can be used to see which freetype shared library + is actually being used. + + # Xft/X Render does not (yet) implement gamma correction. This + causes significant problems rendering white text on a black background + (causing partial pixels to be insufficiently shaded) if the gamma of + your monitor has not been compensated for, and minor problems with + black text on a while background. The program "xgamma" can be used to + set a gamma correction value in the X server's color pallette. Most + monitors have a gamma near 2. + + # Note that the Vera family uses minimal delta hinting. Your + results on other systems when not used anti-aliased may not be + entirely satisfying. We are primarily interested in reports of + problems on open source systems implementing Xft2/fontconfig/freetype + (which implements antialiasing and hinting adjustements, and + sophisticated subpixel decimation on flatpanels). Also, the + algorithms used by Xft2 adjust the hints to integer widths and the + results are crisper on open source systems than on Windows or + MacIntosh. + + # Your fontconfig may (probably does) predate the release of + fontconfig 2.2, and you may see artifacts not present when the font is + used at very small sizes with hinting enabled. "vc-list -V" can be + used to see what version you have installed. + +We believe and hope that these fonts will resolve the problems +reported during beta test. The largest change is the reduction of +leading (interline spacing), which had annoyed a number of people, and +reduced Vera's utility for some applcations. The Vera monospace font +should also now make '0' and 'O' and '1' and 'l' more clearly +distinguishable. + +The version of these fonts is version 1.10. Fontconfig should be +choosing the new version of the fonts if both the released fonts and +beta test fonts are installed (though please discard them: they have +names of form tt20[1-12]gn.ttf). Note that older versions of +fontconfig sometimes did not rebuild their cache correctly when new +fonts are installed: please upgrade to fontconfig 2.2. "fc-cache -f" +can be used to force rebuilding fontconfig's cache files. + +If you note problems, please send them to fonts at gnome dot org, with +exactly which face and size and unicode point you observe the problem +at. The xfd utility from XFree86 CVS may be useful for this (e.g. "xfd +-fa sans"). A possibly more useful program to examine fonts at a +variety of sizes is the "waterfall" program found in Keith Packard's +CVS. + + $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS login + Logging in to :pserver:anoncvs@keithp.com:2401/local/src/CVS + CVS password: + $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS co waterfall + $ cd waterfall + $ xmkmf -a + $ make + # make install + # make install.man + +Again, please make sure you are running an up-to-date freetype, and +that you are only examining integer sizes. + +Reporting Problems +================== + +Please send problem reports to fonts at gnome org, with the following +information: + + 1. Version of Freetype, Xft2 and fontconfig + 2. Whether TT hinting is being used, or the autohinter + 3. Application being used + 4. Character/Unicode code point that has problems (if applicable) + 5. Version of which operating system + 6. Please include a screenshot, when possible. + +Please check the fonts list archives before reporting problems to cut +down on duplication. diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e5/e5e73f56cc8c107df23a1314f092764691036b13.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e5/e5e73f56cc8c107df23a1314f092764691036b13.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,120 @@ +<%= error_messages_for 'custom_field' %> + + + +
    +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :onchange => "toggle_custom_field_format();", + :disabled => !@custom_field.new_record? %>

    +

    + <%= f.text_field :min_length, :size => 5, :no_label => true %> - + <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

    +

    <%= f.text_field :regexp, :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    +

    + <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %> +
    <%= l(:text_custom_field_possible_values_info) %> +

    +

    <%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>

    +<%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %> +
    + +
    +<% case @custom_field.class.name +when "IssueCustomField" %> + +
    <%=l(:label_tracker_plural)%> + <% for tracker in @trackers %> + <%= check_box_tag "custom_field[tracker_ids][]", + tracker.id, + (@custom_field.trackers.include? tracker), + :id => "custom_field_tracker_ids_#{tracker.id}" %> + + <% end %> + <%= hidden_field_tag "custom_field[tracker_ids][]", '' %> +
    +   +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :is_for_all %>

    +

    <%= f.check_box :is_filter %>

    +

    <%= f.check_box :searchable %>

    + +<% when "UserCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :visible %>

    +

    <%= f.check_box :editable %>

    + +<% when "ProjectCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :visible %>

    +

    <%= f.check_box :searchable %>

    + +<% when "TimeEntryCustomField" %> +

    <%= f.check_box :is_required %>

    + +<% else %> +

    <%= f.check_box :is_required %>

    + +<% end %> +<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %> +
    +<%= javascript_tag "toggle_custom_field_format();" %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e6/e61ed8d8686f44c14e6b3df087c2971015ce850b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e6/e61ed8d8686f44c14e6b3df087c2971015ce850b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e6/e65faaa354628b13af7044cf9f8731b43aa5e548.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e6/e65faaa354628b13af7044cf9f8731b43aa5e548.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/lib/acts_as_searchable' +ActiveRecord::Base.send(:include, Redmine::Acts::Searchable) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e6/e68980e453bcaeab54d767cd68eee8a10b8ecd17.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e6/e68980e453bcaeab54d767cd68eee8a10b8ecd17.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,120 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 AccessControl + + class << self + def map + mapper = Mapper.new + yield mapper + @permissions ||= [] + @permissions += mapper.mapped_permissions + end + + def permissions + @permissions + end + + # Returns the permission of given name or nil if it wasn't found + # Argument should be a symbol + def permission(name) + permissions.detect {|p| p.name == name} + end + + # Returns the actions that are allowed by the permission of given name + def allowed_actions(permission_name) + perm = permission(permission_name) + perm ? perm.actions : [] + end + + def public_permissions + @public_permissions ||= @permissions.select {|p| p.public?} + end + + def members_only_permissions + @members_only_permissions ||= @permissions.select {|p| p.require_member?} + end + + def loggedin_only_permissions + @loggedin_only_permissions ||= @permissions.select {|p| p.require_loggedin?} + end + + def available_project_modules + @available_project_modules ||= @permissions.collect(&:project_module).uniq.compact + end + + def modules_permissions(modules) + @permissions.select {|p| p.project_module.nil? || modules.include?(p.project_module.to_s)} + end + end + + class Mapper + def initialize + @project_module = nil + end + + def permission(name, hash, options={}) + @permissions ||= [] + options.merge!(:project_module => @project_module) + @permissions << Permission.new(name, hash, options) + end + + def project_module(name, options={}) + @project_module = name + yield self + @project_module = nil + end + + def mapped_permissions + @permissions + end + end + + class Permission + attr_reader :name, :actions, :project_module + + def initialize(name, hash, options) + @name = name + @actions = [] + @public = options[:public] || false + @require = options[:require] + @project_module = options[:project_module] + hash.each do |controller, actions| + if actions.is_a? Array + @actions << actions.collect {|action| "#{controller}/#{action}"} + else + @actions << "#{controller}/#{actions}" + end + end + @actions.flatten! + end + + def public? + @public + end + + def require_member? + @require && @require == :member + end + + def require_loggedin? + @require && (@require == :member || @require == :loggedin) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e6/e6b0db274ce059d213550c8e6860020fa512f648.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e6/e6b0db274ce059d213550c8e6860020fa512f648.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +<% form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params) %> +
    + + + + <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %> + <% query.columns.each do |column| %> + <%= column_header(column) %> + <% end %> + + <% previous_group = false %> + + <% issue_list(issues) do |issue, level| -%> + <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %> + <% reset_cycle %> + + + + <% previous_group = group %> + <% end %> + "> + + + <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.css_classes %><% end %> + + <% end -%> + +
    <%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> +
    +   + <%= group.blank? ? 'None' : column_content(@query.group_by_column, issue) %> (<%= @issue_count_by_group[group] %>) + <%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %> +
    <%= check_box_tag("ids[]", issue.id, false, :id => nil) %><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
    +
    +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e6/e6bda0fade07e3c97fb5d8fdb6396feed05e26ae.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e6/e6bda0fade07e3c97fb5d8fdb6396feed05e26ae.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddWatchersUserIdTypeIndex < ActiveRecord::Migration + def self.up + add_index :watchers, [:user_id, :watchable_type], :name => :watchers_user_id_type + end + + def self.down + remove_index :watchers, :name => :watchers_user_id_type + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e6/e6c6e613ff0d2c3cc9757a8612a421623bc71bcc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e6/e6c6e613ff0d2c3cc9757a8612a421623bc71bcc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,147 @@ + + __ _ _ + /__\_ _| |__ _ _| |_ _ __ ___ ___ + / \// | | | '_ \| | | | __| '__/ _ \/ _ \ + / _ \ |_| | |_) | |_| | |_| | | __/ __/ + \/ \_/\__,_|_.__/ \__, |\__|_| \___|\___| + |___/ + + (c) 2006, 2007 Anupam Sengupta + http://rubytree.rubyforge.org + +Rubytree is a simple implementation of the generic Tree data structure. This +implementation is node-centric, where the individual nodes on the tree are the +primary objects and drive the structure. + +== INSTALL: + +Rubytree is an open source project and is hosted at: + + http://rubytree.rubyforge.org + +Rubytree can be downloaded as a Rubygem or as a tar/zip file from: + + http://rubyforge.org/frs/?group_id=1215&release_id=8817 + +The file-name is one of: + + rubytree-.gem - The Rubygem + rubytree-.tgz - GZipped source files + rubytree-.zip - Zipped source files + +Download the appropriate file-type for your system. + +It is recommended to install Rubytree as a Ruby Gem, as this is an easy way to +keep the version updated, and keep multiple versions of the library available on +your system. + +=== Installing the Gem + +To Install the Gem, from a Terminal/CLI command prompt, issue the command: + + gem install rubytree + +This should install the gem file for Rubytree. Note that you may need to be a +super-user (root) to successfully install the gem. + +=== Installing from the tgz/zip file + +Extract the archive file (tgz or zip) and run the following command from the +top-level source directory: + + ruby ./setup.rb + +You may need administrator/super-user privileges to complete the setup using +this method. + +== DOCUMENTATION: + +The primary class for this implementation is Tree::TreeNode. See the +class documentation for an usage example. + +From a command line/terminal prompt, you can issue the following command to view +the text mode ri documentation: + + ri Tree::TreeNode + +Documentation on the web is available at: + +http://rubytree.rubyforge.org/rdoc + +== EXAMPLE: + +The following code-snippet implements this tree structure: + + +------------+ + | ROOT | + +-----+------+ + +-------------+------------+ + | | + +-------+-------+ +-------+-------+ + | CHILD 1 | | CHILD 2 | + +-------+-------+ +---------------+ + | + | + +-------+-------+ + | GRANDCHILD 1 | + +---------------+ + + require 'tree' + + myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content") + + myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content") + + myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content") + + myTreeRoot.printTree + + child1 = myTreeRoot["CHILD1"] + + grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"] + + siblingsOfChild1Array = child1.siblings + + immediateChildrenArray = myTreeRoot.children + + # Process all nodes + + myTreeRoot.each { |node| node.content.reverse } + + myTreeRoot.remove!(child1) # Remove the child + +== LICENSE: + +Rubytree is licensed under BSD license. + +Copyright (c) 2006, 2007 Anupam Sengupta + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +- Neither the name of the organization nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +(Document Revision: $Revision: 1.16 $ by $Author: anupamsg $) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e735d81a3ddf113ea34dcc2d3e6455904085deeb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e735d81a3ddf113ea34dcc2d3e6455904085deeb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,97 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 MimeType + + MIME_TYPES = { + 'text/plain' => 'txt,tpl,properties,patch,diff,ini,readme,install,upgrade', + 'text/css' => 'css', + 'text/html' => 'html,htm,xhtml', + 'text/jsp' => 'jsp', + 'text/x-c' => 'c,cpp,cc,h,hh', + 'text/x-csharp' => 'cs', + 'text/x-java' => 'java', + 'text/x-javascript' => 'js', + 'text/x-html-template' => 'rhtml', + 'text/x-perl' => 'pl,pm', + 'text/x-php' => 'php,php3,php4,php5', + 'text/x-python' => 'py', + 'text/x-ruby' => 'rb,rbw,ruby,rake,erb', + 'text/x-csh' => 'csh', + 'text/x-sh' => 'sh', + 'text/xml' => 'xml,xsd,mxml', + 'text/yaml' => 'yml,yaml', + 'text/csv' => 'csv', + 'text/x-po' => 'po', + 'image/gif' => 'gif', + 'image/jpeg' => 'jpg,jpeg,jpe', + 'image/png' => 'png', + 'image/tiff' => 'tiff,tif', + 'image/x-ms-bmp' => 'bmp', + 'image/x-xpixmap' => 'xpm', + 'application/pdf' => 'pdf', + 'application/rtf' => 'rtf', + 'application/msword' => 'doc', + 'application/vnd.ms-excel' => 'xls', + 'application/vnd.ms-powerpoint' => 'ppt,pps', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx', + 'application/vnd.oasis.opendocument.spreadsheet' => 'ods', + 'application/vnd.oasis.opendocument.text' => 'odt', + 'application/vnd.oasis.opendocument.presentation' => 'odp', + 'application/x-7z-compressed' => '7z', + 'application/x-rar-compressed' => 'rar', + 'application/x-tar' => 'tar', + 'application/zip' => 'zip', + 'application/x-gzip' => 'gz', + }.freeze + + EXTENSIONS = MIME_TYPES.inject({}) do |map, (type, exts)| + exts.split(',').each {|ext| map[ext.strip] = type} + map + end + + # returns mime type for name or nil if unknown + def self.of(name) + return nil unless name + m = name.to_s.match(/(^|\.)([^\.]+)$/) + EXTENSIONS[m[2].downcase] if m + end + + # Returns the css class associated to + # the mime type of name + def self.css_class_of(name) + mime = of(name) + mime && mime.gsub('/', '-') + end + + def self.main_mimetype_of(name) + mimetype = of(name) + mimetype.split('/').first if mimetype + end + + # return true if mime-type for name is type/* + # otherwise false + def self.is_type?(type, name) + main_mimetype = main_mimetype_of(name) + type.to_s == main_mimetype + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e7562c9a312f124c1337559279a6a5070fb30eb1.svn-base Binary file .svn/pristine/e7/e7562c9a312f124c1337559279a6a5070fb30eb1.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e77868c1cdde27df85411c7926b5e0864306b501.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e77868c1cdde27df85411c7926b5e0864306b501.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,143 @@ +module CodeRay +module Styles + + # A colorful theme using CSS 3 colors (with alpha channel). + class Alpha < Style + + register_for :alpha + + code_background = 'hsl(0,0%,95%)' + numbers_background = 'hsl(180,65%,90%)' + border_color = 'silver' + normal_color = 'black' + + CSS_MAIN_STYLES = <<-MAIN # :nodoc: +.CodeRay { + background-color: #{code_background}; + border: 1px solid #{border_color}; + color: #{normal_color}; +} +.CodeRay pre { + margin: 0px; +} + +span.CodeRay { white-space: pre; border: 0px; padding: 2px; } + +table.CodeRay { border-collapse: collapse; width: 100%; padding: 2px; } +table.CodeRay td { padding: 2px 4px; vertical-align: top; } + +.CodeRay .line-numbers { + background-color: #{numbers_background}; + color: gray; + text-align: right; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.CodeRay .line-numbers a { + background-color: #{numbers_background} !important; + color: gray !important; + text-decoration: none !important; +} +.CodeRay .line-numbers a:target { color: blue !important; } +.CodeRay .line-numbers .highlighted { color: red !important; } +.CodeRay .line-numbers .highlighted a { color: red !important; } +.CodeRay span.line-numbers { padding: 0px 4px; } +.CodeRay .line { display: block; float: left; width: 100%; } +.CodeRay .code { width: 100%; } +.CodeRay .code pre { overflow: auto; } + MAIN + + TOKEN_COLORS = <<-'TOKENS' +.debug { color: white !important; background: blue !important; } + +.annotation { color:#007 } +.attribute-name { color:#b48 } +.attribute-value { color:#700 } +.binary { color:#509 } +.char .content { color:#D20 } +.char .delimiter { color:#710 } +.char { color:#D20 } +.class { color:#B06; font-weight:bold } +.class-variable { color:#369 } +.color { color:#0A0 } +.comment { color:#777 } +.comment .char { color:#444 } +.comment .delimiter { color:#444 } +.complex { color:#A08 } +.constant { color:#036; font-weight:bold } +.decorator { color:#B0B } +.definition { color:#099; font-weight:bold } +.delimiter { color:black } +.directive { color:#088; font-weight:bold } +.doc { color:#970 } +.doc-string { color:#D42; font-weight:bold } +.doctype { color:#34b } +.entity { color:#800; font-weight:bold } +.error { color:#F00; background-color:#FAA } +.escape { color:#666 } +.exception { color:#C00; font-weight:bold } +.float { color:#60E } +.function { color:#06B; font-weight:bold } +.global-variable { color:#d70 } +.hex { color:#02b } +.imaginary { color:#f00 } +.include { color:#B44; font-weight:bold } +.inline { background-color: hsla(0,0%,0%,0.07); color: black } +.inline-delimiter { font-weight: bold; color: #666 } +.instance-variable { color:#33B } +.integer { color:#00D } +.key .char { color: #60f } +.key .delimiter { color: #404 } +.key { color: #606 } +.keyword { color:#080; font-weight:bold } +.label { color:#970; font-weight:bold } +.local-variable { color:#963 } +.namespace { color:#707; font-weight:bold } +.octal { color:#40E } +.operator { } +.predefined { color:#369; font-weight:bold } +.predefined-constant { color:#069 } +.predefined-type { color:#0a5; font-weight:bold } +.preprocessor { color:#579 } +.pseudo-class { color:#00C; font-weight:bold } +.regexp .content { color:#808 } +.regexp .delimiter { color:#404 } +.regexp .modifier { color:#C2C } +.regexp { background-color:hsla(300,100%,50%,0.06); } +.reserved { color:#080; font-weight:bold } +.shell .content { color:#2B2 } +.shell .delimiter { color:#161 } +.shell { background-color:hsla(120,100%,50%,0.06); } +.string .char { color: #b0b } +.string .content { color: #D20 } +.string .delimiter { color: #710 } +.string .modifier { color: #E40 } +.string { background-color:hsla(0,100%,50%,0.05); } +.symbol .content { color:#A60 } +.symbol .delimiter { color:#630 } +.symbol { color:#A60 } +.tag { color:#070 } +.type { color:#339; font-weight:bold } +.value { color: #088; } +.variable { color:#037 } + +.insert { background: hsla(120,100%,50%,0.12) } +.delete { background: hsla(0,100%,50%,0.12) } +.change { color: #bbf; background: #007; } +.head { color: #f8f; background: #505 } +.head .filename { color: white; } + +.delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; } +.insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +.insert .insert { color: #0c0; background:transparent; font-weight:bold } +.delete .delete { color: #c00; background:transparent; font-weight:bold } +.change .change { color: #88f } +.head .head { color: #f4f } + TOKENS + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e77d4ee988f0ee0cedc3ea42fee306534d1cb4e6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e77d4ee988f0ee0cedc3ea42fee306534d1cb4e6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,553 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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' +require 'fpdf/chinese' +require 'fpdf/japanese' +require 'fpdf/korean' +require 'core/rmagick' + +module Redmine + module Export + module PDF + include ActionView::Helpers::TextHelper + include ActionView::Helpers::NumberHelper + include IssuesHelper + + class ITCPDF < TCPDF + include Redmine::I18n + attr_accessor :footer_date + + def initialize(lang) + @@k_path_cache = Rails.root.join('tmp', 'pdf') + FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache) + set_language_if_valid lang + pdf_encoding = l(:general_pdf_encoding).upcase + super('P', 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding) + case current_language.to_s.downcase + when 'vi' + @font_for_content = 'DejaVuSans' + @font_for_footer = 'DejaVuSans' + else + case pdf_encoding + when 'UTF-8' + @font_for_content = 'FreeSans' + @font_for_footer = 'FreeSans' + when 'CP949' + extend(PDF_Korean) + AddUHCFont() + @font_for_content = 'UHC' + @font_for_footer = 'UHC' + when 'CP932', 'SJIS', 'SHIFT_JIS' + extend(PDF_Japanese) + AddSJISFont() + @font_for_content = 'SJIS' + @font_for_footer = 'SJIS' + when 'GB18030' + extend(PDF_Chinese) + AddGBFont() + @font_for_content = 'GB' + @font_for_footer = 'GB' + when 'BIG5' + extend(PDF_Chinese) + AddBig5Font() + @font_for_content = 'Big5' + @font_for_footer = 'Big5' + else + @font_for_content = 'Arial' + @font_for_footer = 'Helvetica' + end + end + SetCreator(Redmine::Info.app_name) + SetFont(@font_for_content) + end + + def SetFontStyle(style, size) + SetFont(@font_for_content, style, size) + end + + def SetTitle(txt) + txt = begin + utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) + hextxt = "" + rescue + txt + end || '' + super(txt) + end + + def textstring(s) + # Format a text string + if s =~ /^ space_left + pdf.AddPage("L") + base_x = pdf.GetX + base_y = pdf.GetY + end + + # write the cells on page + pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1) + issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) + issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) + pdf.SetY(base_y + max_height); + end + + if issues.size == Setting.issues_export_limit.to_i + pdf.SetFontStyle('B',10) + pdf.RDMCell(0, row_height, '...') + end + pdf.Output + end + + # Renders MultiCells and returns the maximum height used + def issues_to_pdf_write_cells(pdf, col_values, col_widths, + row_height, head=false) + base_y = pdf.GetY + max_height = row_height + col_values.each_with_index do |column, i| + col_x = pdf.GetX + if head == true + pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1) + else + pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1) + end + max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height + pdf.SetXY(col_x + col_widths[i], base_y); + end + return max_height + end + + # Draw lines to close the row (MultiCell border drawing in not uniform) + def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, + id_width, col_widths) + col_x = top_x + id_width + pdf.Line(col_x, top_y, col_x, lower_y) # id right border + col_widths.each do |width| + col_x += width + pdf.Line(col_x, top_y, col_x, lower_y) # columns right border + end + pdf.Line(top_x, top_y, top_x, lower_y) # left border + pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border + end + + # Returns a PDF string of a single issue + def issue_to_pdf(issue) + pdf = ITCPDF.new(current_language) + pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}") + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + pdf.SetFontStyle('B',11) + buf = "#{issue.project} - #{issue.tracker} # #{issue.id}" + pdf.RDMMultiCell(190, 5, buf) + pdf.Ln + pdf.SetFontStyle('',8) + base_x = pdf.GetX + i = 1 + issue.ancestors.each do |ancestor| + pdf.SetX(base_x + i) + buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}" + pdf.RDMMultiCell(190 - i, 5, buf) + i += 1 if i < 35 + end + pdf.Ln + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_status) + ":","LT") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, issue.status.to_s,"RT") + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_priority) + ":","LT") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, issue.priority.to_s,"RT") + pdf.Ln + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_author) + ":","L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, issue.author.to_s,"R") + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_category) + ":","L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, issue.category.to_s,"R") + pdf.Ln + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_created_on) + ":","L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, format_date(issue.created_on),"R") + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, issue.assigned_to.to_s,"R") + pdf.Ln + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, format_date(issue.updated_on),"RB") + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_due_date) + ":","LB") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, format_date(issue.due_date),"RB") + pdf.Ln + + for custom_value in issue.custom_field_values + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L") + pdf.SetFontStyle('',9) + pdf.RDMMultiCell(155,5, (show_value custom_value),"R") + end + + y0 = pdf.GetY + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, l(:field_subject) + ":","LT") + pdf.SetFontStyle('',9) + pdf.RDMMultiCell(155,5, issue.subject,"RT") + pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1) + pdf.SetFontStyle('',9) + + # Set resize image scale + pdf.SetImageScale(1.6) + pdf.RDMwriteHTMLCell(35+155, 5, 0, 0, + issue.description.to_s, issue.attachments, "LRB") + + unless issue.leaf? + # for CJK + truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 ) + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR") + pdf.Ln + issue_list(issue.descendants.sort_by(&:lft)) do |child, level| + buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}", + :length => truncate_length) + level = 10 if level >= 10 + pdf.SetFontStyle('',8) + pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L") + pdf.SetFontStyle('B',8) + pdf.RDMCell(20,5, child.status.to_s, "R") + pdf.Ln + end + end + + relations = issue.relations.select { |r| r.other_issue(issue).visible? } + unless relations.empty? + # for CJK + truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 ) + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR") + pdf.Ln + relations.each do |relation| + buf = "" + buf += "#{l(relation.label_for(issue))} " + if relation.delay && relation.delay != 0 + buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) " + end + if Setting.cross_project_issue_relations? + buf += "#{relation.other_issue(issue).project} - " + end + buf += "#{relation.other_issue(issue).tracker}" + + " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}" + buf = truncate(buf, :length => truncate_length) + pdf.SetFontStyle('', 8) + pdf.RDMCell(35+155-60, 5, buf, "L") + pdf.SetFontStyle('B',8) + pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "") + pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "") + pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R") + pdf.Ln + end + end + pdf.RDMCell(190,5, "", "T") + pdf.Ln + + if issue.changesets.any? && + User.current.allowed_to?(:view_changesets, issue.project) + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_associated_revisions), "B") + pdf.Ln + for changeset in issue.changesets + pdf.SetFontStyle('B',8) + csstr = "#{l(:label_revision)} #{changeset.format_identifier} - " + csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s + pdf.RDMCell(190, 5, csstr) + pdf.Ln + unless changeset.comments.blank? + pdf.SetFontStyle('',8) + pdf.RDMwriteHTMLCell(190,5,0,0, + changeset.comments.to_s, issue.attachments, "") + end + pdf.Ln + end + end + + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_history), "B") + pdf.Ln + indice = 0 + for journal in issue.journals.find( + :all, :include => [:user, :details], + :order => "#{Journal.table_name}.created_on ASC") + indice = indice + 1 + pdf.SetFontStyle('B',8) + pdf.RDMCell(190,5, + "#" + indice.to_s + + " - " + format_time(journal.created_on) + + " - " + journal.user.name) + pdf.Ln + pdf.SetFontStyle('I',8) + for detail in journal.details + pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true)) + end + if journal.notes? + pdf.Ln unless journal.details.empty? + pdf.SetFontStyle('',8) + pdf.RDMwriteHTMLCell(190,5,0,0, + journal.notes.to_s, issue.attachments, "") + end + pdf.Ln + end + + if issue.attachments.any? + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_attachment_plural), "B") + pdf.Ln + for attachment in issue.attachments + pdf.SetFontStyle('',8) + pdf.RDMCell(80,5, attachment.filename) + pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R") + pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R") + pdf.RDMCell(65,5, attachment.author.name,0,0,"R") + pdf.Ln + end + end + pdf.Output + end + + # Returns a PDF string of a single wiki page + def wiki_to_pdf(page, project) + pdf = ITCPDF.new(current_language) + pdf.SetTitle("#{project} - #{page.title}") + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + pdf.SetFontStyle('B',11) + pdf.RDMMultiCell(190,5, + "#{project} - #{page.title} - # #{page.content.version}") + pdf.Ln + # Set resize image scale + pdf.SetImageScale(1.6) + pdf.SetFontStyle('',9) + pdf.RDMwriteHTMLCell(190,5,0,0, + page.content.text.to_s, page.attachments, "TLRB") + if page.attachments.any? + pdf.Ln + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_attachment_plural), "B") + pdf.Ln + for attachment in page.attachments + pdf.SetFontStyle('',8) + pdf.RDMCell(80,5, attachment.filename) + pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R") + pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R") + pdf.RDMCell(65,5, attachment.author.name,0,0,"R") + pdf.Ln + end + end + pdf.Output + end + + class RDMPdfEncoding + def self.rdm_from_utf8(txt, encoding) + txt ||= '' + txt = Redmine::CodesetUtil.from_utf8(txt, encoding) + if txt.respond_to?(:force_encoding) + txt.force_encoding('ASCII-8BIT') + end + txt + end + + def self.attach(attachments, filename, encoding) + filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding) + atta = nil + if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i + atta = Attachment.latest_attach(attachments, filename_utf8) + end + if atta && atta.readable? && atta.visible? + return atta + else + return nil + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e77ecc74553bd5c08ca184a88695f37ae32190fc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e77ecc74553bd5c08ca184a88695f37ae32190fc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ViewHelpersTest < ActionController::TestCase + tests AssetsController + + def setup + get :index + end + + def test_plugin_javascript_helpers + base_selector = "script[type='text/javascript']" + js_dir = "/plugin_assets/test_assets/javascripts" + assert_select "#{base_selector}[src='#{js_dir}/file.1.js']" + assert_select "#{base_selector}[src='#{js_dir}/file2.js']" + end + + def test_plugin_stylesheet_helpers + base_selector = "link[media='screen'][rel='stylesheet'][type='text/css']" + css_dir = "/plugin_assets/test_assets/stylesheets" + assert_select "#{base_selector}[href='#{css_dir}/file.1.css']" + assert_select "#{base_selector}[href='#{css_dir}/file2.css']" + end + + def test_plugin_image_helpers + assert_select "img[src='/plugin_assets/test_assets/images/image.png'][alt='Image']" + end + + def test_plugin_layouts + get :index + assert_select "div[id='assets_layout']" + end + + def test_plugin_image_submit_helpers + assert_select "input[src='/plugin_assets/test_assets/images/image.png'][type='image']" + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e789b49c2d19dabe0b26f8b8d9732b786d1d4c29.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e789b49c2d19dabe0b26f8b8d9732b786d1d4c29.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRepositoriesPathEncoding < ActiveRecord::Migration + def self.up + add_column :repositories, :path_encoding, :string, :limit => 64, :default => nil + end + + def self.down + remove_column :repositories, :path_encoding + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e797f09f8ee9ca99436baf7817780fe7558fef10.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e797f09f8ee9ca99436baf7817780fe7558fef10.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Ням", + "Даваа", + "Мягмар", + "Лхагва", + "Пүрэв", + "Баасан", + "Бямба", + "Ням"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ням", + "Дав", + "Мяг", + "Лха", + "Пүр", + "Бсн", + "Бям", + "Ням"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("1-р сар", + "2-р сар", + "3-р сар", + "4-р сар", + "5-р сар", + "6-р сар", + "7-р сар", + "8-р сар", + "9-р сар", + "10-р сар", + "11-р сар", + "12-р сар"); + +// short month names +Calendar._SMN = new Array +("1-р сар", + "2-р сар", + "3-р сар", + "4-р сар", + "5-р сар", + "6-р сар", + "7-р сар", + "8-р сар", + "9-р сар", + "10-р сар", + "11-р сар", + "12-р сар"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Календарын тухай"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Өмнөх. жил"; +Calendar._TT["PREV_MONTH"] = "Өмнөх. сар"; +Calendar._TT["GO_TODAY"] = "Өнөөдрийг сонго"; +Calendar._TT["NEXT_MONTH"] = "Дараа сар"; +Calendar._TT["NEXT_YEAR"] = "Дараа жил"; +Calendar._TT["SEL_DATE"] = "Өдөр сонгох"; +Calendar._TT["DRAG_TO_MOVE"] = "Хөдөлгөх бол чир"; +Calendar._TT["PART_TODAY"] = " (өнөөдөр)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s -г эхэлж гарга"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Хаах"; +Calendar._TT["TODAY"] = "Өнөөдөр"; +Calendar._TT["TIME_PART"] = "(Shift-)Click эсвэл чирж утгийг өөрчил"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "7 хоног"; +Calendar._TT["TIME"] = "Цаг:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e79ecfee8517012e1c66ce8650c075185ad708ff.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e79ecfee8517012e1c66ce8650c075185ad708ff.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2022 bullet +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+0454 afii10101 +!A5 U+2554 SF390000 +!A6 U+0456 afii10103 +!A7 U+0457 afii10104 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+0491 afii10098 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+0404 afii10053 +!B5 U+2563 SF230000 +!B6 U+0406 afii10055 +!B7 U+0407 afii10056 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+0490 afii10050 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e7a7b8709d232fbdbeb2be18741eefc510e32665.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e7a7b8709d232fbdbeb2be18741eefc510e32665.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,102 @@ +--- +wiki_content_versions_001: + updated_on: 2007-03-07 00:08:07 +01:00 + page_id: 1 + id: 1 + version: 1 + author_id: 2 + comments: Page creation + wiki_content_id: 1 + compression: "" + data: |- + h1. CookBook documentation + + + + Some [[documentation]] here... +wiki_content_versions_002: + updated_on: 2007-03-07 00:08:34 +01:00 + page_id: 1 + id: 2 + version: 2 + author_id: 1 + comments: Small update + wiki_content_id: 1 + compression: "" + data: |- + h1. CookBook documentation + + + + Some updated [[documentation]] here... +wiki_content_versions_003: + updated_on: 2007-03-07 00:10:51 +01:00 + page_id: 1 + id: 3 + version: 3 + author_id: 1 + comments: "" + wiki_content_id: 1 + compression: "" + data: |- + h1. CookBook documentation + Some updated [[documentation]] here... +wiki_content_versions_004: + data: |- + h1. Another page + + This is a link to a ticket: #2 + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 2 + wiki_content_id: 2 + id: 4 + version: 1 + author_id: 1 + comments: +wiki_content_versions_005: + data: |- + h1. Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + + h2. Heading 1 + + @WHATEVER@ + + Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + + Cras ipsum felis, ultrices at porttitor vel, faucibus eu nunc. + + h2. Heading 2 + + Morbi facilisis accumsan orci non pharetra. + updated_on: 2007-03-08 00:16:07 +01:00 + page_id: 11 + wiki_content_id: 11 + id: 5 + version: 2 + author_id: 1 + comments: +wiki_content_versions_006: + data: |- + h1. Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + + h2. Heading 1 + + @WHATEVER@ + + Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + + h2. Heading 2 + + Morbi facilisis accumsan orci non pharetra. + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 11 + wiki_content_id: 11 + id: 6 + version: 3 + author_id: 1 + comments: + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e7c57199f09f372f673303ec05380ff197d1616b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e7c57199f09f372f673303ec05380ff197d1616b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +require File.expand_path('../../config/boot', __FILE__) +require 'commands/process/spinner' diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e7f59d38bb10065e83d125e940b355005f481782.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e7f59d38bb10065e83d125e940b355005f481782.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +class CreateQueries < ActiveRecord::Migration + def self.up + create_table :queries, :force => true do |t| + t.column "project_id", :integer + t.column "name", :string, :default => "", :null => false + t.column "filters", :text + t.column "user_id", :integer, :default => 0, :null => false + t.column "is_public", :boolean, :default => false, :null => false + end + end + + def self.down + drop_table :queries + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e7/e7fcc49601a6dc5187fcac0c86a47bebd148eb02.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e7/e7fcc49601a6dc5187fcac0c86a47bebd148eb02.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '強調'; +jsToolBar.strings['Italic'] = '斜体'; +jsToolBar.strings['Underline'] = '下線'; +jsToolBar.strings['Deleted'] = '取り消し線'; +jsToolBar.strings['Code'] = 'コード'; +jsToolBar.strings['Heading 1'] = '見出し 1'; +jsToolBar.strings['Heading 2'] = '見出し 2'; +jsToolBar.strings['Heading 3'] = '見出し 3'; +jsToolBar.strings['Unordered list'] = '順不同リスト'; +jsToolBar.strings['Ordered list'] = '番号つきリスト'; +jsToolBar.strings['Quote'] = '引用'; +jsToolBar.strings['Unquote'] = '引用解除'; +jsToolBar.strings['Preformatted text'] = '整形済みテキスト'; +jsToolBar.strings['Wiki link'] = 'Wikiページへのリンク'; +jsToolBar.strings['Image'] = '画像'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e808b282df9d286146c74f4e3a4ae2fbebc0eb8d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e808b282df9d286146c74f4e3a4ae2fbebc0eb8d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,287 @@ +TCPDFFontDescriptor.define('dejavusans') do |font| + font[:type]='TrueTypeUnicode'; + font[:name]='DejaVuSans'; + font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-1021 -356 1681 1068]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600}; + font[:up]=-42; + font[:ut]=44; + font[:cw]={ + 0=>600, 32=>318, 33=>401, 34=>460, 35=>838, 36=>636, 37=>950, 38=>780, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>361, 46=>318, + 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, + 63=>531, 64=>1000, 65=>684, 66=>686, 67=>698, 68=>770, 69=>632, 70=>575, 71=>775, 72=>752, 73=>295, 74=>295, 75=>656, 76=>557, 77=>863, 78=>748, + 79=>787, 80=>603, 81=>787, 82=>695, 83=>635, 84=>611, 85=>732, 86=>684, 87=>989, 88=>685, 89=>611, 90=>685, 91=>390, 92=>337, 93=>390, 94=>838, + 95=>500, 96=>500, 97=>613, 98=>635, 99=>550, 100=>635, 101=>615, 102=>352, 103=>635, 104=>634, 105=>278, 106=>278, 107=>579, 108=>278, 109=>974, 110=>634, + 111=>612, 112=>635, 113=>635, 114=>411, 115=>521, 116=>392, 117=>634, 118=>592, 119=>818, 120=>592, 121=>592, 122=>525, 123=>636, 124=>337, 125=>636, 126=>838, + 8364=>636, 1027=>610, 8218=>318, 402=>352, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1342, 352=>635, 8249=>400, 338=>1070, 1036=>710, 381=>685, 1039=>752, + 8216=>318, 8217=>318, 8220=>518, 8221=>518, 8226=>590, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>521, 8250=>400, 339=>1023, 1116=>604, 382=>525, 376=>611, 160=>318, + 161=>401, 162=>636, 163=>636, 164=>636, 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>471, 171=>612, 172=>838, 173=>361, 174=>1000, 175=>500, 176=>500, + 177=>838, 178=>401, 179=>401, 180=>500, 181=>636, 182=>636, 183=>318, 184=>500, 185=>401, 186=>471, 187=>612, 188=>969, 189=>969, 190=>969, 191=>531, 192=>684, + 193=>684, 194=>684, 195=>684, 196=>684, 197=>684, 198=>974, 199=>698, 200=>632, 201=>632, 202=>632, 203=>632, 204=>295, 205=>295, 206=>295, 207=>295, 208=>775, + 209=>748, 210=>787, 211=>787, 212=>787, 213=>787, 214=>787, 215=>838, 216=>787, 217=>732, 218=>732, 219=>732, 220=>732, 221=>611, 222=>605, 223=>630, 224=>613, + 225=>613, 226=>613, 227=>613, 228=>613, 229=>613, 230=>982, 231=>550, 232=>615, 233=>615, 234=>615, 235=>615, 236=>278, 237=>278, 238=>278, 239=>278, 240=>612, + 241=>634, 242=>612, 243=>612, 244=>612, 245=>612, 246=>612, 247=>838, 248=>612, 249=>634, 250=>634, 251=>634, 252=>634, 253=>592, 254=>635, 255=>592, 256=>684, + 257=>613, 258=>684, 259=>613, 260=>684, 261=>613, 262=>698, 263=>550, 264=>698, 265=>550, 266=>698, 267=>550, 268=>698, 269=>550, 270=>770, 271=>635, 272=>775, + 273=>635, 274=>632, 275=>615, 276=>632, 277=>615, 278=>632, 279=>615, 280=>632, 281=>615, 282=>632, 283=>615, 284=>775, 285=>635, 286=>775, 287=>635, 288=>775, + 289=>635, 290=>775, 291=>635, 292=>752, 293=>634, 294=>916, 295=>695, 296=>295, 297=>278, 298=>295, 299=>278, 300=>295, 301=>278, 302=>295, 303=>278, 304=>295, + 305=>278, 306=>590, 307=>556, 308=>295, 309=>278, 310=>656, 311=>579, 312=>579, 313=>557, 314=>293, 315=>557, 316=>278, 317=>557, 318=>375, 319=>557, 320=>342, + 321=>562, 322=>284, 323=>748, 324=>634, 325=>748, 326=>634, 327=>748, 328=>634, 329=>813, 330=>748, 331=>634, 332=>787, 333=>612, 334=>787, 335=>612, 336=>787, + 337=>612, 340=>695, 341=>411, 342=>695, 343=>411, 344=>695, 345=>411, 346=>635, 347=>521, 348=>635, 349=>521, 350=>635, 351=>521, 354=>611, 355=>392, 356=>611, + 357=>392, 358=>611, 359=>392, 360=>732, 361=>634, 362=>732, 363=>634, 364=>732, 365=>634, 366=>732, 367=>634, 368=>732, 369=>634, 370=>732, 371=>634, 372=>989, + 373=>818, 374=>611, 375=>592, 377=>685, 378=>525, 379=>685, 380=>525, 383=>352, 384=>635, 385=>735, 386=>686, 387=>635, 388=>686, 389=>635, 390=>703, 391=>698, + 392=>550, 393=>775, 394=>819, 395=>686, 396=>635, 397=>612, 398=>632, 399=>787, 400=>614, 401=>575, 403=>775, 404=>687, 405=>984, 406=>354, 407=>295, 408=>746, + 409=>579, 410=>278, 411=>592, 412=>974, 413=>748, 414=>634, 415=>787, 416=>913, 417=>612, 418=>949, 419=>759, 420=>652, 421=>635, 422=>695, 423=>635, 424=>521, + 425=>632, 426=>336, 427=>392, 428=>611, 429=>392, 430=>611, 431=>858, 432=>634, 433=>764, 434=>721, 435=>744, 436=>729, 437=>685, 438=>525, 439=>666, 440=>666, + 441=>578, 442=>525, 443=>636, 444=>666, 445=>578, 446=>510, 447=>635, 448=>295, 449=>492, 450=>459, 451=>295, 452=>1422, 453=>1299, 454=>1154, 455=>835, 456=>787, + 457=>457, 458=>931, 459=>924, 460=>797, 461=>684, 462=>613, 463=>295, 464=>278, 465=>787, 466=>612, 467=>732, 468=>634, 469=>732, 470=>634, 471=>732, 472=>634, + 473=>732, 474=>634, 475=>732, 476=>634, 477=>615, 478=>684, 479=>613, 480=>684, 481=>613, 482=>974, 483=>982, 484=>775, 485=>635, 486=>775, 487=>635, 488=>656, + 489=>579, 490=>787, 491=>612, 492=>787, 493=>612, 494=>666, 495=>578, 496=>278, 497=>1422, 498=>1299, 499=>1154, 500=>775, 501=>635, 502=>1113, 503=>682, 504=>748, + 505=>634, 506=>684, 507=>613, 508=>974, 509=>982, 510=>787, 511=>612, 512=>684, 513=>613, 514=>684, 515=>613, 516=>632, 517=>615, 518=>632, 519=>615, 520=>295, + 521=>278, 522=>295, 523=>278, 524=>787, 525=>612, 526=>787, 527=>612, 528=>695, 529=>411, 530=>695, 531=>411, 532=>732, 533=>634, 534=>732, 535=>634, 536=>635, + 537=>521, 538=>611, 539=>392, 540=>627, 541=>521, 542=>752, 543=>634, 544=>735, 545=>838, 546=>698, 547=>610, 548=>685, 549=>525, 550=>684, 551=>613, 552=>632, + 553=>615, 554=>787, 555=>612, 556=>787, 557=>612, 558=>787, 559=>612, 560=>787, 561=>612, 562=>611, 563=>592, 564=>475, 565=>843, 566=>477, 567=>278, 568=>998, + 569=>998, 570=>684, 571=>698, 572=>550, 573=>557, 574=>611, 575=>521, 576=>525, 577=>603, 578=>479, 579=>686, 580=>732, 581=>684, 582=>632, 583=>615, 584=>295, + 585=>278, 586=>781, 587=>635, 588=>695, 589=>411, 590=>611, 591=>592, 592=>600, 593=>635, 594=>635, 595=>635, 596=>549, 597=>550, 598=>635, 599=>696, 600=>615, + 601=>615, 602=>819, 603=>541, 604=>532, 605=>775, 606=>664, 607=>278, 608=>696, 609=>635, 610=>629, 611=>596, 612=>596, 613=>634, 614=>634, 615=>634, 616=>278, + 617=>338, 618=>372, 619=>396, 620=>487, 621=>278, 622=>706, 623=>974, 624=>974, 625=>974, 626=>646, 627=>642, 628=>634, 629=>612, 630=>858, 631=>728, 632=>660, + 633=>414, 634=>414, 635=>414, 636=>411, 637=>411, 638=>437, 639=>530, 640=>604, 641=>604, 642=>521, 643=>336, 644=>336, 645=>461, 646=>336, 647=>392, 648=>392, + 649=>634, 650=>618, 651=>598, 652=>592, 653=>818, 654=>592, 655=>611, 656=>525, 657=>525, 658=>578, 659=>578, 660=>510, 661=>510, 662=>510, 663=>510, 664=>787, + 665=>580, 666=>664, 667=>708, 668=>654, 669=>292, 670=>667, 671=>507, 672=>727, 673=>510, 674=>510, 675=>1014, 676=>1058, 677=>1013, 678=>824, 679=>610, 680=>778, + 681=>848, 682=>641, 683=>654, 684=>515, 685=>515, 686=>570, 687=>664, 688=>404, 689=>399, 690=>175, 691=>259, 692=>295, 693=>296, 694=>379, 695=>515, 696=>373, + 697=>278, 698=>460, 699=>318, 700=>318, 701=>318, 702=>307, 703=>307, 704=>370, 705=>370, 706=>500, 707=>500, 708=>500, 709=>500, 711=>500, 712=>275, 713=>500, + 714=>500, 715=>500, 716=>275, 717=>500, 718=>500, 719=>500, 720=>337, 721=>337, 722=>307, 723=>307, 724=>500, 725=>500, 726=>413, 727=>500, 728=>500, 729=>500, + 730=>500, 731=>500, 733=>500, 734=>315, 735=>500, 736=>426, 737=>166, 738=>373, 739=>444, 740=>370, 741=>493, 742=>493, 743=>493, 744=>493, 745=>493, 748=>500, + 749=>500, 750=>500, 755=>500, 759=>500, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, + 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, + 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, + 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, + 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, + 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 850=>0, 851=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, + 884=>278, 885=>278, 890=>500, 891=>549, 892=>550, 893=>549, 894=>337, 900=>500, 901=>500, 902=>692, 903=>318, 904=>746, 905=>871, 906=>408, 908=>813, 910=>825, + 911=>826, 912=>338, 913=>684, 914=>686, 915=>557, 916=>684, 917=>632, 918=>685, 919=>752, 920=>787, 921=>295, 922=>656, 923=>684, 924=>863, 925=>748, 926=>632, + 927=>787, 928=>752, 929=>603, 931=>632, 932=>611, 933=>611, 934=>787, 935=>685, 936=>787, 937=>764, 938=>295, 939=>611, 940=>659, 941=>548, 942=>654, 943=>338, + 944=>579, 945=>659, 946=>638, 947=>592, 948=>612, 949=>541, 950=>544, 951=>634, 952=>612, 953=>338, 954=>589, 955=>592, 956=>636, 957=>559, 958=>558, 959=>612, + 960=>602, 961=>635, 962=>587, 963=>634, 964=>602, 965=>579, 966=>660, 967=>578, 968=>660, 969=>837, 970=>338, 971=>579, 972=>612, 973=>579, 974=>837, 976=>614, + 977=>619, 978=>699, 979=>842, 980=>699, 981=>660, 982=>837, 983=>664, 984=>787, 985=>612, 986=>648, 987=>587, 988=>575, 989=>458, 990=>660, 991=>660, 992=>865, + 993=>627, 994=>934, 995=>837, 996=>758, 997=>659, 998=>792, 999=>615, 1000=>687, 1001=>607, 1002=>768, 1003=>625, 1004=>699, 1005=>612, 1006=>611, 1007=>536, 1008=>664, + 1009=>635, 1010=>550, 1011=>278, 1012=>787, 1013=>615, 1014=>615, 1015=>605, 1016=>635, 1017=>698, 1018=>863, 1019=>651, 1020=>635, 1021=>703, 1022=>698, 1023=>703, 1024=>632, + 1025=>632, 1026=>786, 1028=>698, 1029=>635, 1030=>295, 1031=>295, 1032=>295, 1033=>1094, 1034=>1045, 1035=>786, 1037=>748, 1038=>609, 1040=>684, 1041=>686, 1042=>686, 1043=>610, + 1044=>781, 1045=>632, 1046=>1077, 1047=>641, 1048=>748, 1049=>748, 1050=>710, 1051=>752, 1052=>863, 1053=>752, 1054=>787, 1055=>752, 1056=>603, 1057=>698, 1058=>611, 1059=>609, + 1060=>861, 1061=>685, 1062=>776, 1063=>686, 1064=>1069, 1065=>1094, 1066=>833, 1067=>882, 1068=>686, 1069=>698, 1070=>1080, 1071=>695, 1072=>613, 1073=>617, 1074=>589, 1075=>525, + 1076=>691, 1077=>615, 1078=>901, 1079=>532, 1080=>650, 1081=>650, 1082=>604, 1083=>639, 1084=>754, 1085=>654, 1086=>612, 1087=>654, 1088=>635, 1089=>550, 1090=>583, 1091=>592, + 1092=>855, 1093=>592, 1094=>681, 1095=>591, 1096=>915, 1097=>942, 1098=>707, 1099=>790, 1100=>589, 1101=>549, 1102=>842, 1103=>602, 1104=>615, 1105=>615, 1106=>625, 1107=>525, + 1108=>549, 1109=>521, 1110=>278, 1111=>278, 1112=>278, 1113=>902, 1114=>898, 1115=>652, 1117=>650, 1118=>592, 1119=>654, 1120=>934, 1121=>837, 1122=>771, 1123=>672, 1124=>942, + 1125=>749, 1126=>879, 1127=>783, 1128=>1160, 1129=>1001, 1130=>787, 1131=>612, 1132=>1027, 1133=>824, 1134=>636, 1135=>541, 1136=>856, 1137=>876, 1138=>787, 1139=>592, 1140=>781, + 1141=>665, 1142=>781, 1143=>665, 1144=>992, 1145=>904, 1146=>953, 1147=>758, 1148=>1180, 1149=>1028, 1150=>934, 1151=>837, 1152=>698, 1153=>550, 1154=>502, 1155=>0, 1156=>0, + 1157=>0, 1158=>0, 1160=>418, 1161=>418, 1162=>772, 1163=>677, 1164=>686, 1165=>589, 1166=>603, 1167=>635, 1168=>610, 1169=>525, 1170=>675, 1171=>556, 1172=>624, 1173=>530, + 1174=>1077, 1175=>901, 1176=>641, 1177=>532, 1178=>710, 1179=>604, 1180=>710, 1181=>604, 1182=>710, 1183=>604, 1184=>856, 1185=>832, 1186=>752, 1187=>661, 1188=>1014, 1189=>877, + 1190=>1081, 1191=>916, 1192=>796, 1193=>651, 1194=>698, 1195=>550, 1196=>611, 1197=>529, 1198=>611, 1199=>592, 1200=>611, 1201=>592, 1202=>685, 1203=>592, 1204=>934, 1205=>807, + 1206=>686, 1207=>591, 1208=>686, 1209=>591, 1210=>686, 1211=>634, 1212=>941, 1213=>728, 1214=>941, 1215=>728, 1216=>295, 1217=>1077, 1218=>901, 1219=>656, 1220=>604, 1221=>776, + 1222=>670, 1223=>752, 1224=>661, 1225=>776, 1226=>681, 1227=>686, 1228=>591, 1229=>888, 1230=>774, 1231=>278, 1232=>684, 1233=>613, 1234=>684, 1235=>613, 1236=>974, 1237=>982, + 1238=>632, 1239=>615, 1240=>787, 1241=>615, 1242=>787, 1243=>615, 1244=>1077, 1245=>901, 1246=>641, 1247=>532, 1248=>666, 1249=>578, 1250=>748, 1251=>650, 1252=>748, 1253=>650, + 1254=>787, 1255=>612, 1256=>787, 1257=>612, 1258=>787, 1259=>612, 1260=>698, 1261=>549, 1262=>609, 1263=>592, 1264=>609, 1265=>592, 1266=>609, 1267=>592, 1268=>686, 1269=>591, + 1270=>557, 1271=>491, 1272=>882, 1273=>790, 1274=>675, 1275=>556, 1276=>685, 1277=>592, 1278=>685, 1279=>592, 1280=>686, 1281=>589, 1282=>1006, 1283=>897, 1284=>975, 1285=>869, + 1286=>679, 1287=>588, 1288=>1072, 1289=>957, 1290=>1072, 1291=>967, 1292=>775, 1293=>660, 1294=>773, 1295=>711, 1296=>614, 1297=>541, 1298=>752, 1299=>639, 1329=>867, 1330=>732, + 1331=>882, 1332=>882, 1333=>732, 1334=>644, 1335=>682, 1336=>732, 1337=>851, 1338=>882, 1339=>732, 1340=>557, 1341=>824, 1342=>986, 1343=>732, 1344=>707, 1345=>644, 1346=>882, + 1347=>777, 1348=>882, 1349=>732, 1350=>840, 1351=>732, 1352=>732, 1353=>732, 1354=>791, 1355=>644, 1356=>882, 1357=>732, 1358=>882, 1359=>635, 1360=>732, 1361=>732, 1362=>799, + 1363=>861, 1364=>790, 1365=>787, 1366=>635, 1369=>307, 1370=>318, 1371=>500, 1372=>500, 1373=>392, 1374=>526, 1375=>500, 1377=>974, 1378=>634, 1379=>762, 1380=>767, 1381=>634, + 1382=>697, 1383=>533, 1384=>634, 1385=>700, 1386=>697, 1387=>634, 1388=>404, 1389=>894, 1390=>641, 1391=>634, 1392=>634, 1393=>635, 1394=>702, 1395=>634, 1396=>659, 1397=>278, + 1398=>760, 1399=>516, 1400=>634, 1401=>453, 1402=>974, 1403=>516, 1404=>769, 1405=>634, 1406=>696, 1407=>974, 1408=>634, 1409=>635, 1410=>501, 1411=>974, 1412=>648, 1413=>612, + 1414=>629, 1415=>763, 1417=>337, 1418=>433, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, + 1469=>0, 1471=>0, 1472=>295, 1473=>0, 1474=>0, 1475=>295, 1478=>456, 1479=>0, 1488=>629, 1489=>608, 1490=>448, 1491=>594, 1492=>640, 1493=>272, 1494=>423, 1495=>640, + 1496=>648, 1497=>272, 1498=>592, 1499=>556, 1500=>599, 1501=>640, 1502=>659, 1503=>272, 1504=>441, 1505=>700, 1506=>636, 1507=>640, 1508=>604, 1509=>521, 1510=>581, 1511=>663, + 1512=>592, 1513=>808, 1514=>657, 1520=>471, 1521=>454, 1522=>471, 1548=>323, 1557=>0, 1563=>318, 1567=>531, 1569=>470, 1570=>278, 1571=>278, 1572=>483, 1573=>278, 1574=>783, + 1575=>278, 1576=>941, 1577=>524, 1578=>941, 1579=>941, 1580=>646, 1581=>646, 1582=>646, 1583=>445, 1584=>445, 1585=>483, 1586=>483, 1587=>1221, 1588=>1221, 1589=>1209, 1590=>1209, + 1591=>925, 1592=>925, 1593=>597, 1594=>597, 1600=>293, 1601=>1037, 1602=>776, 1603=>824, 1604=>727, 1605=>619, 1606=>734, 1607=>524, 1608=>483, 1609=>783, 1610=>783, 1611=>0, + 1612=>0, 1613=>0, 1614=>0, 1615=>0, 1616=>0, 1617=>0, 1618=>0, 1619=>0, 1620=>0, 1621=>0, 1626=>500, 1632=>537, 1633=>537, 1634=>537, 1635=>537, 1636=>537, + 1637=>537, 1638=>537, 1639=>537, 1640=>537, 1641=>537, 1642=>537, 1643=>325, 1644=>318, 1645=>545, 1646=>941, 1647=>776, 1652=>292, 1657=>941, 1658=>941, 1659=>941, 1660=>941, + 1661=>941, 1662=>941, 1663=>941, 1664=>941, 1665=>646, 1666=>646, 1667=>646, 1668=>646, 1669=>646, 1670=>646, 1671=>646, 1681=>483, 1682=>483, 1685=>610, 1688=>483, 1697=>1037, + 1700=>1037, 1702=>1037, 1705=>895, 1711=>895, 1717=>727, 1722=>734, 1727=>646, 1734=>483, 1740=>783, 1742=>783, 1749=>524, 1776=>537, 1777=>537, 1778=>537, 1779=>537, 1780=>537, + 1781=>537, 1782=>537, 1783=>537, 1784=>537, 1785=>537, 3647=>652, 3713=>670, 3714=>684, 3716=>688, 3719=>482, 3720=>628, 3722=>684, 3725=>688, 3732=>669, 3733=>642, 3734=>645, + 3735=>655, 3737=>659, 3738=>625, 3739=>625, 3740=>745, 3741=>767, 3742=>687, 3743=>687, 3745=>702, 3746=>688, 3747=>684, 3749=>649, 3751=>632, 3754=>703, 3755=>819, 3757=>633, + 3758=>684, 3759=>788, 3760=>632, 3761=>0, 3762=>539, 3763=>539, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>663, 3776=>375, + 3777=>657, 3778=>460, 3779=>547, 3780=>491, 3782=>674, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>1028, 3805=>1028, 5121=>684, 5122=>684, 5123=>684, + 5124=>684, 5125=>769, 5126=>769, 5127=>769, 5129=>769, 5130=>769, 5131=>769, 5132=>835, 5133=>834, 5134=>835, 5135=>834, 5136=>835, 5137=>834, 5138=>967, 5139=>1007, 5140=>967, + 5141=>1007, 5142=>769, 5143=>967, 5144=>1007, 5145=>967, 5146=>1007, 5147=>769, 5149=>256, 5150=>543, 5151=>423, 5152=>423, 5153=>389, 5154=>389, 5155=>393, 5156=>389, 5157=>466, + 5158=>385, 5159=>256, 5160=>389, 5161=>389, 5162=>389, 5163=>1090, 5164=>909, 5165=>953, 5166=>1117, 5167=>684, 5168=>684, 5169=>684, 5170=>684, 5171=>729, 5172=>729, 5173=>729, + 5175=>729, 5176=>729, 5177=>729, 5178=>835, 5179=>834, 5180=>835, 5181=>834, 5182=>835, 5183=>834, 5184=>967, 5185=>1007, 5186=>967, 5187=>1007, 5188=>967, 5189=>1007, 5190=>967, + 5191=>1007, 5192=>729, 5193=>508, 5194=>192, 5196=>732, 5197=>732, 5198=>732, 5199=>732, 5200=>730, 5201=>730, 5202=>730, 5204=>730, 5205=>730, 5206=>730, 5207=>921, 5208=>889, + 5209=>921, 5210=>889, 5211=>921, 5212=>889, 5213=>928, 5214=>900, 5215=>928, 5216=>900, 5217=>947, 5218=>900, 5219=>947, 5220=>900, 5221=>947, 5222=>434, 5223=>877, 5224=>877, + 5225=>866, 5226=>890, 5227=>628, 5228=>628, 5229=>628, 5230=>628, 5231=>628, 5232=>694, 5233=>628, 5234=>628, 5235=>628, 5236=>860, 5237=>771, 5238=>815, 5239=>816, 5240=>815, + 5241=>816, 5242=>860, 5243=>771, 5244=>860, 5245=>771, 5246=>815, 5247=>816, 5248=>815, 5249=>816, 5250=>815, 5251=>407, 5252=>407, 5253=>750, 5254=>775, 5255=>750, 5256=>775, + 5257=>628, 5258=>628, 5259=>628, 5260=>628, 5261=>628, 5262=>628, 5263=>628, 5264=>628, 5265=>628, 5266=>860, 5267=>771, 5268=>815, 5269=>816, 5270=>815, 5271=>816, 5272=>860, + 5273=>771, 5274=>860, 5275=>771, 5276=>815, 5277=>816, 5278=>815, 5279=>816, 5280=>815, 5281=>435, 5282=>435, 5283=>610, 5284=>557, 5285=>557, 5286=>557, 5287=>610, 5288=>522, + 5289=>610, 5290=>557, 5291=>557, 5292=>749, 5293=>769, 5294=>746, 5295=>764, 5296=>746, 5297=>764, 5298=>749, 5299=>769, 5300=>749, 5301=>769, 5302=>746, 5303=>764, 5304=>746, + 5305=>764, 5306=>746, 5307=>386, 5308=>508, 5309=>386, 5312=>852, 5313=>852, 5314=>852, 5315=>823, 5316=>852, 5317=>852, 5318=>852, 5319=>852, 5320=>852, 5321=>1069, 5322=>1035, + 5323=>1059, 5324=>852, 5325=>1059, 5326=>852, 5327=>852, 5328=>600, 5329=>453, 5330=>600, 5331=>852, 5332=>852, 5333=>852, 5334=>852, 5335=>852, 5336=>852, 5337=>852, 5338=>852, + 5339=>852, 5340=>1069, 5341=>1035, 5342=>1059, 5343=>1030, 5344=>1059, 5345=>1030, 5346=>1069, 5347=>1035, 5348=>1069, 5349=>1035, 5350=>1083, 5351=>1030, 5352=>1083, 5353=>1030, 5354=>600, + 5356=>729, 5357=>603, 5358=>603, 5359=>603, 5360=>603, 5361=>603, 5362=>661, 5363=>603, 5364=>603, 5365=>603, 5366=>834, 5367=>754, 5368=>792, 5369=>771, 5370=>792, 5371=>771, + 5372=>834, 5373=>754, 5374=>834, 5375=>754, 5376=>792, 5377=>771, 5378=>792, 5379=>771, 5380=>792, 5381=>418, 5382=>420, 5383=>418, 5392=>712, 5393=>712, 5394=>712, 5395=>892, + 5396=>892, 5397=>892, 5398=>892, 5399=>910, 5400=>872, 5401=>910, 5402=>872, 5403=>910, 5404=>872, 5405=>1140, 5406=>1100, 5407=>1140, 5408=>1100, 5409=>1140, 5410=>1100, 5411=>1140, + 5412=>1100, 5413=>641, 5414=>627, 5415=>627, 5416=>627, 5417=>627, 5418=>627, 5419=>667, 5420=>627, 5421=>627, 5422=>627, 5423=>844, 5424=>781, 5425=>816, 5426=>818, 5427=>816, + 5428=>818, 5429=>844, 5430=>781, 5431=>844, 5432=>781, 5433=>816, 5434=>818, 5435=>816, 5436=>818, 5437=>816, 5438=>418, 5440=>389, 5441=>484, 5442=>916, 5443=>916, 5444=>916, + 5445=>916, 5446=>916, 5447=>916, 5448=>603, 5449=>603, 5450=>603, 5451=>603, 5452=>603, 5453=>603, 5454=>834, 5455=>754, 5456=>418, 5458=>729, 5459=>684, 5460=>684, 5461=>684, + 5462=>684, 5463=>726, 5464=>726, 5465=>726, 5466=>726, 5467=>924, 5468=>1007, 5469=>508, 5470=>732, 5471=>732, 5472=>732, 5473=>732, 5474=>732, 5475=>732, 5476=>730, 5477=>730, + 5478=>730, 5479=>730, 5480=>947, 5481=>900, 5482=>508, 5492=>831, 5493=>831, 5494=>831, 5495=>831, 5496=>831, 5497=>831, 5498=>831, 5499=>563, 5500=>752, 5501=>484, 5502=>1047, + 5503=>1047, 5504=>1047, 5505=>1047, 5506=>1047, 5507=>1047, 5508=>1047, 5509=>825, 5514=>831, 5515=>831, 5516=>831, 5517=>831, 5518=>1259, 5519=>1259, 5520=>1259, 5521=>1002, 5522=>1002, + 5523=>1259, 5524=>1259, 5525=>700, 5526=>1073, 5536=>852, 5537=>852, 5538=>852, 5539=>852, 5540=>852, 5541=>852, 5542=>600, 5543=>643, 5544=>643, 5545=>643, 5546=>643, 5547=>643, + 5548=>643, 5549=>643, 5550=>418, 5551=>628, 5598=>770, 5601=>767, 5702=>468, 5703=>468, 5742=>444, 5743=>1047, 5744=>1310, 5745=>1632, 5746=>1632, 5747=>1375, 5748=>1375, 5749=>1632, + 5750=>1632, 7424=>592, 7425=>717, 7426=>982, 7427=>586, 7428=>550, 7429=>605, 7430=>605, 7431=>491, 7432=>541, 7433=>278, 7434=>395, 7435=>579, 7436=>583, 7437=>754, 7438=>650, + 7439=>612, 7440=>550, 7441=>684, 7442=>684, 7443=>684, 7444=>1023, 7446=>612, 7447=>612, 7448=>524, 7449=>602, 7450=>602, 7451=>583, 7452=>574, 7453=>737, 7454=>948, 7455=>638, + 7456=>592, 7457=>818, 7458=>525, 7459=>526, 7462=>583, 7463=>592, 7464=>564, 7465=>524, 7466=>590, 7467=>639, 7468=>431, 7469=>613, 7470=>432, 7472=>485, 7473=>398, 7474=>398, + 7475=>488, 7476=>474, 7477=>186, 7478=>186, 7479=>413, 7480=>351, 7481=>543, 7482=>471, 7483=>471, 7484=>496, 7485=>439, 7486=>380, 7487=>438, 7488=>385, 7489=>461, 7490=>623, + 7491=>392, 7492=>392, 7493=>405, 7494=>648, 7495=>428, 7496=>405, 7497=>417, 7498=>417, 7499=>360, 7500=>359, 7501=>405, 7502=>179, 7503=>426, 7504=>623, 7505=>409, 7506=>414, + 7507=>370, 7508=>414, 7509=>414, 7510=>428, 7511=>295, 7512=>405, 7513=>470, 7514=>623, 7515=>417, 7517=>402, 7518=>373, 7519=>385, 7520=>416, 7521=>364, 7522=>179, 7523=>259, + 7524=>405, 7525=>417, 7526=>402, 7527=>373, 7528=>385, 7529=>416, 7530=>364, 7543=>635, 7544=>474, 7547=>372, 7557=>278, 7579=>405, 7580=>370, 7581=>370, 7582=>414, 7583=>360, + 7584=>296, 7585=>233, 7586=>405, 7587=>405, 7588=>261, 7589=>250, 7590=>261, 7591=>261, 7592=>234, 7593=>250, 7594=>235, 7595=>376, 7596=>623, 7597=>623, 7598=>411, 7599=>479, + 7600=>409, 7601=>414, 7602=>414, 7603=>360, 7604=>287, 7605=>295, 7606=>508, 7607=>418, 7608=>361, 7609=>406, 7610=>417, 7611=>366, 7612=>437, 7613=>366, 7614=>392, 7615=>414, + 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>684, 7681=>613, 7682=>686, 7683=>635, 7684=>686, 7685=>635, 7686=>686, 7687=>635, 7688=>698, 7689=>550, + 7690=>770, 7691=>635, 7692=>770, 7693=>635, 7694=>770, 7695=>635, 7696=>770, 7697=>635, 7698=>770, 7699=>635, 7700=>632, 7701=>615, 7702=>632, 7703=>615, 7704=>632, 7705=>615, + 7706=>632, 7707=>615, 7708=>632, 7709=>615, 7710=>575, 7711=>352, 7712=>775, 7713=>635, 7714=>752, 7715=>634, 7716=>752, 7717=>634, 7718=>752, 7719=>634, 7720=>752, 7721=>634, + 7722=>752, 7723=>634, 7724=>295, 7725=>278, 7726=>295, 7727=>278, 7728=>656, 7729=>579, 7730=>656, 7731=>579, 7732=>656, 7733=>579, 7734=>557, 7735=>288, 7736=>557, 7737=>288, + 7738=>557, 7739=>278, 7740=>557, 7741=>278, 7742=>863, 7743=>974, 7744=>863, 7745=>974, 7746=>863, 7747=>974, 7748=>748, 7749=>634, 7750=>748, 7751=>634, 7752=>748, 7753=>634, + 7754=>748, 7755=>634, 7756=>787, 7757=>612, 7758=>787, 7759=>612, 7760=>787, 7761=>612, 7762=>787, 7763=>612, 7764=>603, 7765=>635, 7766=>603, 7767=>635, 7768=>695, 7769=>411, + 7770=>695, 7771=>411, 7772=>695, 7773=>411, 7774=>695, 7775=>411, 7776=>635, 7777=>521, 7778=>635, 7779=>521, 7780=>635, 7781=>521, 7782=>635, 7783=>521, 7784=>635, 7785=>521, + 7786=>611, 7787=>392, 7788=>611, 7789=>392, 7790=>611, 7791=>392, 7792=>611, 7793=>392, 7794=>732, 7795=>634, 7796=>732, 7797=>634, 7798=>732, 7799=>634, 7800=>732, 7801=>634, + 7802=>732, 7803=>634, 7804=>684, 7805=>592, 7806=>684, 7807=>592, 7808=>989, 7809=>818, 7810=>989, 7811=>818, 7812=>989, 7813=>818, 7814=>989, 7815=>818, 7816=>989, 7817=>818, + 7818=>685, 7819=>592, 7820=>685, 7821=>592, 7822=>611, 7823=>592, 7824=>685, 7825=>525, 7826=>685, 7827=>525, 7828=>685, 7829=>525, 7830=>634, 7831=>392, 7832=>818, 7833=>592, + 7834=>613, 7835=>352, 7840=>684, 7841=>613, 7842=>684, 7843=>613, 7844=>684, 7845=>613, 7846=>684, 7847=>613, 7848=>684, 7849=>613, 7850=>684, 7851=>613, 7852=>684, 7853=>613, + 7854=>684, 7855=>613, 7856=>684, 7857=>613, 7858=>684, 7859=>613, 7860=>684, 7861=>613, 7862=>684, 7863=>613, 7864=>632, 7865=>615, 7866=>632, 7867=>615, 7868=>632, 7869=>615, + 7870=>632, 7871=>615, 7872=>632, 7873=>615, 7874=>632, 7875=>615, 7876=>632, 7877=>615, 7878=>632, 7879=>615, 7880=>295, 7881=>278, 7882=>295, 7883=>278, 7884=>787, 7885=>612, + 7886=>787, 7887=>612, 7888=>787, 7889=>612, 7890=>787, 7891=>612, 7892=>787, 7893=>612, 7894=>787, 7895=>612, 7896=>787, 7897=>612, 7898=>913, 7899=>612, 7900=>913, 7901=>612, + 7902=>913, 7903=>612, 7904=>913, 7905=>612, 7906=>913, 7907=>612, 7908=>732, 7909=>634, 7910=>732, 7911=>634, 7912=>858, 7913=>634, 7914=>858, 7915=>634, 7916=>858, 7917=>634, + 7918=>858, 7919=>634, 7920=>858, 7921=>634, 7922=>611, 7923=>592, 7924=>611, 7925=>592, 7926=>611, 7927=>592, 7928=>611, 7929=>592, 7936=>659, 7937=>659, 7938=>659, 7939=>659, + 7940=>659, 7941=>659, 7942=>659, 7943=>659, 7944=>684, 7945=>684, 7946=>877, 7947=>877, 7948=>769, 7949=>801, 7950=>708, 7951=>743, 7952=>541, 7953=>541, 7954=>541, 7955=>541, + 7956=>541, 7957=>541, 7960=>711, 7961=>711, 7962=>966, 7963=>975, 7964=>898, 7965=>928, 7968=>634, 7969=>634, 7970=>634, 7971=>634, 7972=>634, 7973=>634, 7974=>634, 7975=>634, + 7976=>837, 7977=>835, 7978=>1086, 7979=>1089, 7980=>1027, 7981=>1051, 7982=>934, 7983=>947, 7984=>338, 7985=>338, 7986=>338, 7987=>338, 7988=>338, 7989=>338, 7990=>338, 7991=>338, + 7992=>380, 7993=>374, 7994=>635, 7995=>635, 7996=>570, 7997=>600, 7998=>489, 7999=>493, 8000=>612, 8001=>612, 8002=>612, 8003=>612, 8004=>612, 8005=>612, 8008=>804, 8009=>848, + 8010=>1095, 8011=>1100, 8012=>938, 8013=>970, 8016=>579, 8017=>579, 8018=>579, 8019=>579, 8020=>579, 8021=>579, 8022=>579, 8023=>579, 8025=>784, 8027=>998, 8029=>1012, 8031=>897, + 8032=>837, 8033=>837, 8034=>837, 8035=>837, 8036=>837, 8037=>837, 8038=>837, 8039=>837, 8040=>802, 8041=>843, 8042=>1089, 8043=>1095, 8044=>946, 8045=>972, 8046=>921, 8047=>952, + 8048=>659, 8049=>659, 8050=>541, 8051=>548, 8052=>634, 8053=>654, 8054=>338, 8055=>338, 8056=>612, 8057=>612, 8058=>579, 8059=>579, 8060=>837, 8061=>837, 8064=>659, 8065=>659, + 8066=>659, 8067=>659, 8068=>659, 8069=>659, 8070=>659, 8071=>659, 8072=>684, 8073=>684, 8074=>877, 8075=>877, 8076=>769, 8077=>801, 8078=>708, 8079=>743, 8080=>634, 8081=>634, + 8082=>634, 8083=>634, 8084=>634, 8085=>634, 8086=>634, 8087=>634, 8088=>837, 8089=>835, 8090=>1086, 8091=>1089, 8092=>1027, 8093=>1051, 8094=>934, 8095=>947, 8096=>837, 8097=>837, + 8098=>837, 8099=>837, 8100=>837, 8101=>837, 8102=>837, 8103=>837, 8104=>802, 8105=>843, 8106=>1089, 8107=>1095, 8108=>946, 8109=>972, 8110=>921, 8111=>952, 8112=>659, 8113=>659, + 8114=>659, 8115=>659, 8116=>659, 8118=>659, 8119=>659, 8120=>684, 8121=>684, 8122=>716, 8123=>692, 8124=>684, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>634, + 8131=>634, 8132=>654, 8134=>634, 8135=>634, 8136=>805, 8137=>746, 8138=>931, 8139=>871, 8140=>752, 8141=>500, 8142=>500, 8143=>500, 8144=>338, 8145=>338, 8146=>338, 8147=>338, + 8150=>338, 8151=>338, 8152=>295, 8153=>295, 8154=>475, 8155=>408, 8157=>500, 8158=>500, 8159=>500, 8160=>579, 8161=>579, 8162=>579, 8163=>579, 8164=>635, 8165=>635, 8166=>579, + 8167=>579, 8168=>611, 8169=>611, 8170=>845, 8171=>825, 8172=>685, 8173=>500, 8174=>500, 8175=>500, 8178=>837, 8179=>837, 8180=>837, 8182=>837, 8183=>837, 8184=>941, 8185=>813, + 8186=>922, 8187=>826, 8188=>764, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, 8196=>330, 8197=>250, 8198=>167, 8199=>636, 8200=>318, 8201=>200, 8202=>100, + 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>361, 8209=>361, 8210=>636, 8213=>1000, 8214=>500, 8215=>500, 8219=>318, 8223=>518, 8227=>590, 8228=>334, 8229=>667, + 8231=>318, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1735, 8242=>227, 8243=>374, 8244=>520, 8245=>227, 8246=>374, 8247=>520, 8248=>339, 8251=>838, + 8252=>485, 8253=>531, 8254=>500, 8255=>804, 8256=>804, 8257=>250, 8258=>1000, 8259=>500, 8260=>167, 8261=>390, 8262=>390, 8263=>922, 8264=>733, 8265=>733, 8266=>497, 8267=>636, + 8268=>500, 8269=>500, 8270=>500, 8271=>337, 8272=>804, 8273=>500, 8274=>450, 8275=>838, 8276=>804, 8277=>838, 8278=>586, 8279=>663, 8280=>838, 8281=>838, 8282=>318, 8283=>797, + 8284=>838, 8285=>318, 8286=>318, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>401, 8305=>179, + 8308=>401, 8309=>401, 8310=>401, 8311=>401, 8312=>401, 8313=>401, 8314=>528, 8315=>528, 8316=>528, 8317=>246, 8318=>246, 8319=>398, 8320=>401, 8321=>401, 8322=>401, 8323=>401, + 8324=>401, 8325=>401, 8326=>401, 8327=>401, 8328=>401, 8329=>401, 8330=>528, 8331=>528, 8332=>528, 8333=>246, 8334=>246, 8336=>392, 8337=>417, 8338=>414, 8339=>444, 8340=>417, + 8352=>877, 8353=>636, 8354=>636, 8355=>636, 8356=>636, 8357=>974, 8358=>748, 8359=>1272, 8360=>1074, 8361=>989, 8362=>784, 8363=>636, 8365=>636, 8366=>636, 8367=>1272, 8368=>636, + 8369=>636, 8370=>636, 8371=>636, 8372=>774, 8373=>641, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>1019, 8449=>1019, 8450=>698, 8451=>1123, 8452=>642, 8453=>1019, 8454=>1067, + 8455=>614, 8456=>698, 8457=>952, 8459=>988, 8460=>754, 8461=>850, 8462=>634, 8463=>634, 8464=>470, 8465=>697, 8466=>720, 8467=>413, 8468=>818, 8469=>801, 8470=>1040, 8471=>1000, + 8472=>697, 8473=>702, 8474=>787, 8475=>798, 8476=>814, 8477=>792, 8478=>896, 8479=>684, 8480=>1020, 8481=>1074, 8483=>684, 8484=>745, 8485=>578, 8486=>764, 8487=>764, 8488=>616, + 8489=>338, 8490=>656, 8491=>684, 8492=>786, 8493=>703, 8494=>854, 8495=>592, 8496=>605, 8497=>786, 8498=>575, 8499=>1069, 8500=>462, 8501=>745, 8502=>674, 8503=>469, 8504=>648, + 8505=>380, 8506=>926, 8507=>1194, 8508=>702, 8509=>728, 8510=>655, 8511=>849, 8512=>811, 8513=>775, 8514=>557, 8515=>557, 8516=>611, 8517=>819, 8518=>708, 8519=>615, 8520=>351, + 8521=>351, 8523=>780, 8526=>526, 8531=>969, 8532=>969, 8533=>969, 8534=>969, 8535=>969, 8536=>969, 8537=>969, 8538=>969, 8539=>969, 8540=>969, 8541=>969, 8542=>969, 8543=>568, + 8544=>295, 8545=>492, 8546=>689, 8547=>923, 8548=>684, 8549=>922, 8550=>1120, 8551=>1317, 8552=>917, 8553=>685, 8554=>933, 8555=>1131, 8556=>557, 8557=>698, 8558=>770, 8559=>863, + 8560=>278, 8561=>458, 8562=>637, 8563=>812, 8564=>592, 8565=>811, 8566=>991, 8567=>1170, 8568=>819, 8569=>592, 8570=>822, 8571=>1002, 8572=>278, 8573=>550, 8574=>635, 8575=>974, + 8576=>1245, 8577=>770, 8578=>1245, 8579=>703, 8580=>549, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8596=>838, 8597=>838, 8598=>838, 8599=>838, 8600=>838, 8601=>838, 8602=>838, + 8603=>838, 8604=>838, 8605=>838, 8606=>838, 8607=>838, 8608=>838, 8609=>838, 8610=>838, 8611=>838, 8612=>838, 8613=>838, 8614=>838, 8615=>838, 8616=>838, 8617=>838, 8618=>838, + 8619=>838, 8620=>838, 8621=>838, 8622=>838, 8623=>838, 8624=>838, 8625=>838, 8626=>838, 8627=>838, 8628=>838, 8629=>838, 8630=>838, 8631=>838, 8632=>838, 8633=>838, 8634=>838, + 8635=>838, 8636=>838, 8637=>838, 8638=>838, 8639=>838, 8640=>838, 8641=>838, 8642=>838, 8643=>838, 8644=>838, 8645=>838, 8646=>838, 8647=>838, 8648=>838, 8649=>838, 8650=>838, + 8651=>838, 8652=>838, 8653=>838, 8654=>838, 8655=>838, 8656=>838, 8657=>838, 8658=>838, 8659=>838, 8660=>838, 8661=>838, 8662=>838, 8663=>838, 8664=>838, 8665=>838, 8666=>838, + 8667=>838, 8668=>838, 8669=>838, 8670=>838, 8671=>838, 8672=>838, 8673=>838, 8674=>838, 8675=>838, 8676=>838, 8677=>838, 8678=>838, 8679=>838, 8680=>838, 8681=>838, 8682=>838, + 8683=>838, 8684=>838, 8685=>838, 8686=>838, 8687=>838, 8688=>838, 8689=>838, 8690=>838, 8691=>838, 8692=>838, 8693=>838, 8694=>838, 8695=>838, 8696=>838, 8697=>838, 8698=>838, + 8699=>838, 8700=>838, 8701=>838, 8702=>838, 8703=>838, 8704=>684, 8705=>636, 8706=>517, 8707=>632, 8708=>632, 8709=>871, 8710=>669, 8711=>669, 8712=>871, 8713=>871, 8714=>718, + 8715=>871, 8716=>871, 8717=>718, 8718=>636, 8719=>757, 8720=>757, 8721=>674, 8722=>838, 8723=>838, 8724=>838, 8725=>167, 8726=>637, 8727=>838, 8728=>626, 8729=>318, 8730=>637, + 8731=>637, 8732=>637, 8733=>677, 8734=>833, 8735=>838, 8736=>896, 8737=>896, 8738=>838, 8739=>500, 8740=>500, 8741=>500, 8742=>500, 8743=>732, 8744=>732, 8745=>732, 8746=>732, + 8747=>521, 8748=>789, 8749=>1057, 8750=>521, 8751=>789, 8752=>1057, 8753=>521, 8754=>521, 8755=>521, 8756=>636, 8757=>636, 8758=>260, 8759=>636, 8760=>838, 8761=>838, 8762=>838, + 8763=>838, 8764=>838, 8765=>838, 8766=>838, 8767=>838, 8768=>375, 8769=>838, 8770=>838, 8771=>838, 8772=>838, 8773=>838, 8774=>838, 8775=>838, 8776=>838, 8777=>838, 8778=>838, + 8779=>838, 8780=>838, 8781=>838, 8782=>838, 8783=>838, 8784=>838, 8785=>838, 8786=>839, 8787=>839, 8788=>1000, 8789=>1000, 8790=>838, 8791=>838, 8792=>838, 8793=>838, 8794=>838, + 8795=>838, 8796=>838, 8797=>838, 8798=>838, 8799=>838, 8800=>838, 8801=>838, 8802=>838, 8803=>838, 8804=>838, 8805=>838, 8806=>838, 8807=>838, 8808=>838, 8809=>838, 8810=>1047, + 8811=>1047, 8812=>464, 8813=>838, 8814=>838, 8815=>838, 8816=>838, 8817=>838, 8818=>838, 8819=>838, 8820=>838, 8821=>838, 8822=>838, 8823=>838, 8824=>838, 8825=>838, 8826=>838, + 8827=>838, 8828=>838, 8829=>838, 8830=>838, 8831=>838, 8832=>838, 8833=>838, 8834=>838, 8835=>838, 8836=>838, 8837=>838, 8838=>838, 8839=>838, 8840=>838, 8841=>838, 8842=>838, + 8843=>838, 8844=>732, 8845=>732, 8846=>732, 8847=>838, 8848=>838, 8849=>838, 8850=>838, 8851=>722, 8852=>722, 8853=>838, 8854=>838, 8855=>838, 8856=>838, 8857=>838, 8858=>838, + 8859=>838, 8860=>838, 8861=>838, 8862=>838, 8863=>838, 8864=>838, 8865=>838, 8866=>871, 8867=>871, 8868=>871, 8869=>871, 8870=>521, 8871=>521, 8872=>871, 8873=>871, 8874=>871, + 8875=>871, 8876=>871, 8877=>871, 8878=>871, 8879=>871, 8882=>838, 8883=>838, 8884=>838, 8885=>838, 8886=>1000, 8887=>1000, 8888=>838, 8889=>838, 8890=>521, 8891=>732, 8892=>732, + 8893=>732, 8896=>820, 8897=>820, 8898=>820, 8899=>820, 8900=>494, 8901=>318, 8902=>626, 8904=>1000, 8905=>1000, 8906=>1000, 8907=>1000, 8908=>1000, 8909=>838, 8918=>838, 8919=>838, + 8920=>1422, 8921=>1422, 8922=>838, 8923=>838, 8924=>838, 8925=>838, 8926=>838, 8927=>838, 8928=>838, 8929=>838, 8930=>838, 8931=>838, 8932=>838, 8933=>838, 8934=>838, 8935=>838, + 8936=>838, 8937=>838, 8938=>838, 8939=>838, 8940=>838, 8941=>838, 8946=>1000, 8947=>871, 8948=>718, 8949=>871, 8950=>871, 8951=>718, 8952=>871, 8953=>871, 8954=>1000, 8955=>871, + 8956=>718, 8957=>871, 8958=>718, 8959=>871, 8962=>635, 8966=>871, 8968=>390, 8969=>390, 8970=>390, 8971=>390, 8976=>838, 8977=>513, 8984=>1000, 8985=>838, 8992=>521, 8993=>521, + 8997=>1000, 9000=>1443, 9085=>757, 9115=>500, 9116=>500, 9117=>500, 9118=>500, 9119=>500, 9120=>500, 9121=>500, 9122=>500, 9123=>500, 9124=>500, 9125=>500, 9126=>500, 9127=>750, + 9128=>750, 9129=>750, 9130=>750, 9131=>750, 9132=>750, 9133=>750, 9134=>521, 9166=>838, 9167=>945, 9250=>635, 9251=>635, 9312=>896, 9313=>896, 9314=>896, 9315=>896, 9316=>896, + 9317=>896, 9318=>896, 9319=>896, 9320=>896, 9321=>896, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, 9609=>769, 9610=>769, + 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, 9625=>769, 9626=>769, + 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, 9641=>945, 9642=>678, + 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, 9657=>502, 9658=>769, + 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, 9673=>873, 9674=>494, + 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>791, 9689=>970, 9690=>970, + 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>873, 9697=>873, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>590, 9703=>945, 9704=>945, 9705=>945, 9706=>945, + 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, 9721=>769, 9722=>769, + 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9729=>1000, 9730=>896, 9731=>896, 9732=>896, 9733=>896, 9734=>896, 9735=>573, 9736=>896, 9737=>896, 9738=>888, + 9739=>888, 9740=>671, 9741=>1013, 9742=>1246, 9743=>1250, 9744=>896, 9745=>896, 9746=>896, 9747=>532, 9748=>896, 9749=>896, 9750=>896, 9751=>896, 9752=>896, 9753=>896, 9754=>896, + 9755=>896, 9756=>896, 9757=>609, 9758=>896, 9759=>609, 9760=>896, 9761=>896, 9762=>896, 9763=>896, 9764=>669, 9765=>746, 9766=>649, 9767=>784, 9768=>545, 9769=>896, 9770=>896, + 9771=>896, 9772=>710, 9773=>896, 9774=>896, 9775=>896, 9776=>896, 9777=>896, 9778=>896, 9779=>896, 9780=>896, 9781=>896, 9782=>896, 9783=>896, 9784=>896, 9785=>896, 9786=>896, + 9787=>896, 9788=>896, 9789=>896, 9790=>896, 9791=>614, 9792=>731, 9793=>731, 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9800=>896, 9801=>896, 9802=>896, + 9803=>896, 9804=>896, 9805=>896, 9806=>896, 9807=>896, 9808=>896, 9809=>896, 9810=>896, 9811=>896, 9812=>896, 9813=>896, 9814=>896, 9815=>896, 9816=>896, 9817=>896, 9818=>896, + 9819=>896, 9820=>896, 9821=>896, 9822=>896, 9823=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9832=>896, 9833=>472, 9834=>638, + 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 9840=>748, 9841=>766, 9842=>896, 9843=>896, 9844=>896, 9845=>896, 9846=>896, 9847=>896, 9848=>896, 9849=>896, 9850=>896, + 9851=>896, 9852=>896, 9853=>896, 9854=>896, 9855=>896, 9856=>869, 9857=>869, 9858=>869, 9859=>869, 9860=>869, 9861=>869, 9862=>896, 9863=>896, 9864=>896, 9865=>896, 9866=>896, + 9867=>896, 9868=>896, 9869=>896, 9870=>896, 9871=>896, 9872=>896, 9873=>896, 9874=>896, 9875=>896, 9876=>896, 9877=>541, 9878=>896, 9879=>896, 9880=>896, 9881=>896, 9882=>896, + 9883=>896, 9884=>896, 9888=>896, 9889=>702, 9890=>838, 9891=>838, 9892=>838, 9893=>838, 9894=>838, 9895=>838, 9896=>838, 9897=>838, 9898=>838, 9899=>838, 9900=>838, 9901=>838, + 9902=>838, 9903=>838, 9904=>844, 9905=>838, 9906=>731, 9985=>838, 9986=>838, 9987=>838, 9988=>838, 9990=>838, 9991=>838, 9992=>838, 9993=>838, 9996=>838, 9997=>838, 9998=>838, + 9999=>838, 10000=>838, 10001=>838, 10002=>838, 10003=>838, 10004=>838, 10005=>838, 10006=>838, 10007=>838, 10008=>838, 10009=>838, 10010=>838, 10011=>838, 10012=>838, 10013=>838, 10014=>838, + 10015=>838, 10016=>838, 10017=>838, 10018=>838, 10019=>838, 10020=>838, 10021=>838, 10022=>838, 10023=>838, 10025=>838, 10026=>838, 10027=>838, 10028=>838, 10029=>838, 10030=>838, 10031=>838, + 10032=>838, 10033=>838, 10034=>838, 10035=>838, 10036=>838, 10037=>838, 10038=>838, 10039=>838, 10040=>838, 10041=>838, 10042=>838, 10043=>838, 10044=>838, 10045=>838, 10046=>838, 10047=>838, + 10048=>838, 10049=>838, 10050=>838, 10051=>838, 10052=>838, 10053=>838, 10054=>838, 10055=>838, 10056=>838, 10057=>838, 10058=>838, 10059=>838, 10061=>896, 10063=>896, 10064=>896, 10065=>896, + 10066=>896, 10070=>896, 10072=>838, 10073=>838, 10074=>838, 10075=>322, 10076=>322, 10077=>538, 10078=>538, 10081=>838, 10082=>838, 10083=>838, 10084=>838, 10085=>838, 10086=>838, 10087=>838, + 10088=>838, 10089=>838, 10090=>838, 10091=>838, 10092=>838, 10093=>838, 10094=>838, 10095=>838, 10096=>838, 10097=>838, 10098=>838, 10099=>838, 10100=>838, 10101=>838, 10102=>896, 10103=>896, + 10104=>896, 10105=>896, 10106=>896, 10107=>896, 10108=>896, 10109=>896, 10110=>896, 10111=>896, 10112=>838, 10113=>838, 10114=>838, 10115=>838, 10116=>838, 10117=>838, 10118=>838, 10119=>838, + 10120=>838, 10121=>838, 10122=>838, 10123=>838, 10124=>838, 10125=>838, 10126=>838, 10127=>838, 10128=>838, 10129=>838, 10130=>838, 10131=>838, 10132=>838, 10136=>838, 10137=>838, 10138=>838, + 10139=>838, 10140=>838, 10141=>838, 10142=>838, 10143=>838, 10144=>838, 10145=>838, 10146=>838, 10147=>838, 10148=>838, 10149=>838, 10150=>838, 10151=>838, 10152=>838, 10153=>838, 10154=>838, + 10155=>838, 10156=>838, 10157=>838, 10158=>838, 10159=>838, 10161=>838, 10162=>838, 10163=>838, 10164=>838, 10165=>838, 10166=>838, 10167=>838, 10168=>838, 10169=>838, 10170=>838, 10171=>838, + 10172=>838, 10173=>838, 10174=>838, 10208=>494, 10214=>495, 10215=>495, 10216=>390, 10217=>390, 10218=>556, 10219=>556, 10224=>838, 10225=>838, 10226=>838, 10227=>838, 10228=>1157, 10229=>1434, + 10230=>1434, 10231=>1434, 10232=>1434, 10233=>1434, 10234=>1434, 10235=>1434, 10236=>1434, 10237=>1434, 10238=>1434, 10239=>1434, 10240=>732, 10241=>732, 10242=>732, 10243=>732, 10244=>732, 10245=>732, + 10246=>732, 10247=>732, 10248=>732, 10249=>732, 10250=>732, 10251=>732, 10252=>732, 10253=>732, 10254=>732, 10255=>732, 10256=>732, 10257=>732, 10258=>732, 10259=>732, 10260=>732, 10261=>732, + 10262=>732, 10263=>732, 10264=>732, 10265=>732, 10266=>732, 10267=>732, 10268=>732, 10269=>732, 10270=>732, 10271=>732, 10272=>732, 10273=>732, 10274=>732, 10275=>732, 10276=>732, 10277=>732, + 10278=>732, 10279=>732, 10280=>732, 10281=>732, 10282=>732, 10283=>732, 10284=>732, 10285=>732, 10286=>732, 10287=>732, 10288=>732, 10289=>732, 10290=>732, 10291=>732, 10292=>732, 10293=>732, + 10294=>732, 10295=>732, 10296=>732, 10297=>732, 10298=>732, 10299=>732, 10300=>732, 10301=>732, 10302=>732, 10303=>732, 10304=>732, 10305=>732, 10306=>732, 10307=>732, 10308=>732, 10309=>732, + 10310=>732, 10311=>732, 10312=>732, 10313=>732, 10314=>732, 10315=>732, 10316=>732, 10317=>732, 10318=>732, 10319=>732, 10320=>732, 10321=>732, 10322=>732, 10323=>732, 10324=>732, 10325=>732, + 10326=>732, 10327=>732, 10328=>732, 10329=>732, 10330=>732, 10331=>732, 10332=>732, 10333=>732, 10334=>732, 10335=>732, 10336=>732, 10337=>732, 10338=>732, 10339=>732, 10340=>732, 10341=>732, + 10342=>732, 10343=>732, 10344=>732, 10345=>732, 10346=>732, 10347=>732, 10348=>732, 10349=>732, 10350=>732, 10351=>732, 10352=>732, 10353=>732, 10354=>732, 10355=>732, 10356=>732, 10357=>732, + 10358=>732, 10359=>732, 10360=>732, 10361=>732, 10362=>732, 10363=>732, 10364=>732, 10365=>732, 10366=>732, 10367=>732, 10368=>732, 10369=>732, 10370=>732, 10371=>732, 10372=>732, 10373=>732, + 10374=>732, 10375=>732, 10376=>732, 10377=>732, 10378=>732, 10379=>732, 10380=>732, 10381=>732, 10382=>732, 10383=>732, 10384=>732, 10385=>732, 10386=>732, 10387=>732, 10388=>732, 10389=>732, + 10390=>732, 10391=>732, 10392=>732, 10393=>732, 10394=>732, 10395=>732, 10396=>732, 10397=>732, 10398=>732, 10399=>732, 10400=>732, 10401=>732, 10402=>732, 10403=>732, 10404=>732, 10405=>732, + 10406=>732, 10407=>732, 10408=>732, 10409=>732, 10410=>732, 10411=>732, 10412=>732, 10413=>732, 10414=>732, 10415=>732, 10416=>732, 10417=>732, 10418=>732, 10419=>732, 10420=>732, 10421=>732, + 10422=>732, 10423=>732, 10424=>732, 10425=>732, 10426=>732, 10427=>732, 10428=>732, 10429=>732, 10430=>732, 10431=>732, 10432=>732, 10433=>732, 10434=>732, 10435=>732, 10436=>732, 10437=>732, + 10438=>732, 10439=>732, 10440=>732, 10441=>732, 10442=>732, 10443=>732, 10444=>732, 10445=>732, 10446=>732, 10447=>732, 10448=>732, 10449=>732, 10450=>732, 10451=>732, 10452=>732, 10453=>732, + 10454=>732, 10455=>732, 10456=>732, 10457=>732, 10458=>732, 10459=>732, 10460=>732, 10461=>732, 10462=>732, 10463=>732, 10464=>732, 10465=>732, 10466=>732, 10467=>732, 10468=>732, 10469=>732, + 10470=>732, 10471=>732, 10472=>732, 10473=>732, 10474=>732, 10475=>732, 10476=>732, 10477=>732, 10478=>732, 10479=>732, 10480=>732, 10481=>732, 10482=>732, 10483=>732, 10484=>732, 10485=>732, + 10486=>732, 10487=>732, 10488=>732, 10489=>732, 10490=>732, 10491=>732, 10492=>732, 10493=>732, 10494=>732, 10495=>732, 10502=>838, 10503=>838, 10506=>838, 10507=>838, 10560=>683, 10561=>683, + 10702=>838, 10703=>1000, 10704=>1000, 10705=>1000, 10706=>1000, 10707=>1000, 10708=>1000, 10709=>1000, 10731=>494, 10752=>1000, 10753=>1000, 10754=>1000, 10764=>1325, 10765=>521, 10766=>521, 10767=>521, + 10768=>521, 10769=>521, 10770=>521, 10771=>521, 10772=>521, 10773=>521, 10774=>521, 10775=>521, 10776=>521, 10777=>521, 10778=>521, 10779=>521, 10780=>521, 10877=>838, 10878=>838, 10879=>838, + 10880=>838, 10881=>838, 10882=>838, 10883=>838, 10884=>838, 10885=>838, 10886=>838, 10887=>838, 10888=>838, 10889=>838, 10890=>838, 10891=>838, 10892=>838, 10893=>838, 10894=>838, 10895=>838, + 10896=>838, 10897=>838, 10898=>838, 10899=>838, 10900=>838, 10901=>838, 10902=>838, 10903=>838, 10904=>838, 10905=>838, 10906=>838, 10907=>838, 10908=>838, 10909=>838, 10910=>838, 10911=>838, + 10912=>838, 10926=>838, 10927=>838, 10928=>838, 10929=>838, 10930=>838, 10931=>838, 10932=>838, 10933=>838, 10934=>838, 10935=>838, 10936=>838, 10937=>838, 10938=>838, 11001=>838, 11002=>838, + 11008=>838, 11009=>838, 11010=>838, 11011=>838, 11012=>838, 11013=>838, 11014=>838, 11015=>838, 11016=>838, 11017=>838, 11018=>838, 11019=>838, 11020=>838, 11021=>838, 11022=>836, 11023=>836, + 11024=>836, 11025=>836, 11026=>945, 11027=>945, 11028=>945, 11029=>945, 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 11040=>869, 11041=>873, 11042=>873, 11043=>873, 11360=>557, + 11361=>278, 11362=>557, 11363=>603, 11364=>695, 11365=>613, 11366=>392, 11367=>752, 11368=>634, 11369=>656, 11370=>579, 11371=>685, 11372=>525, 11380=>592, 11381=>654, 11382=>568, 11383=>660, + 61440=>977, 61441=>977, 61960=>781, 62047=>592, 63173=>612, 64256=>689, 64257=>630, 64258=>630, 64259=>967, 64260=>967, 64261=>686, 64262=>861, 64275=>1202, 64276=>1202, 64277=>1196, 64278=>1186, + 64279=>1529, 64285=>296, 64287=>494, 64288=>636, 64297=>838, 64298=>799, 64299=>799, 64300=>799, 64301=>799, 64302=>663, 64303=>663, 64304=>663, 64305=>655, 64306=>454, 64307=>607, 64308=>690, + 64309=>336, 64310=>437, 64312=>683, 64313=>336, 64314=>642, 64315=>666, 64316=>635, 64318=>736, 64320=>456, 64321=>771, 64323=>651, 64324=>666, 64326=>639, 64327=>688, 64328=>642, 64329=>799, + 64330=>726, 64331=>272, 64332=>655, 64333=>666, 64334=>666, 64338=>941, 64339=>982, 64340=>278, 64341=>302, 64342=>941, 64343=>982, 64344=>278, 64345=>302, 64346=>941, 64347=>982, 64348=>278, + 64349=>302, 64350=>941, 64351=>982, 64352=>278, 64353=>302, 64354=>941, 64355=>982, 64356=>278, 64357=>302, 64358=>941, 64359=>982, 64360=>278, 64361=>302, 64362=>1037, 64363=>1035, 64364=>478, + 64365=>506, 64366=>1037, 64367=>1035, 64368=>478, 64369=>506, 64370=>646, 64371=>646, 64372=>618, 64373=>646, 64374=>646, 64375=>646, 64376=>618, 64377=>646, 64378=>646, 64379=>646, 64380=>618, + 64381=>646, 64382=>646, 64383=>646, 64384=>618, 64385=>646, 64394=>483, 64395=>552, 64396=>483, 64397=>552, 64398=>895, 64399=>895, 64400=>476, 64401=>552, 64402=>895, 64403=>895, 64404=>476, + 64405=>552, 64414=>734, 64415=>761, 64473=>483, 64474=>517, 64488=>278, 64489=>302, 64508=>783, 64509=>833, 64510=>278, 64511=>302, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, + 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65136=>293, 65137=>293, 65138=>293, 65139=>262, 65140=>293, + 65142=>293, 65143=>293, 65144=>293, 65145=>293, 65146=>293, 65147=>293, 65148=>293, 65149=>293, 65150=>293, 65151=>293, 65152=>470, 65153=>278, 65154=>305, 65155=>278, 65156=>305, 65157=>483, + 65158=>517, 65159=>278, 65160=>305, 65161=>783, 65162=>833, 65163=>278, 65164=>302, 65165=>278, 65166=>305, 65167=>941, 65168=>982, 65169=>278, 65170=>302, 65171=>524, 65172=>536, 65173=>941, + 65174=>982, 65175=>278, 65176=>302, 65177=>941, 65178=>982, 65179=>278, 65180=>302, 65181=>646, 65182=>646, 65183=>618, 65184=>646, 65185=>646, 65186=>646, 65187=>618, 65188=>646, 65189=>646, + 65190=>646, 65191=>618, 65192=>646, 65193=>445, 65194=>525, 65195=>445, 65196=>525, 65197=>483, 65198=>552, 65199=>483, 65200=>552, 65201=>1221, 65202=>1275, 65203=>838, 65204=>892, 65205=>1221, + 65206=>1275, 65207=>838, 65208=>892, 65209=>1209, 65210=>1225, 65211=>849, 65212=>867, 65213=>1209, 65214=>1225, 65215=>849, 65216=>867, 65217=>925, 65218=>949, 65219=>796, 65220=>820, 65221=>925, + 65222=>949, 65223=>796, 65224=>820, 65225=>597, 65226=>532, 65227=>597, 65228=>482, 65229=>597, 65230=>532, 65231=>523, 65232=>482, 65233=>1037, 65234=>1035, 65235=>478, 65236=>506, 65237=>776, + 65238=>834, 65239=>478, 65240=>506, 65241=>824, 65242=>843, 65243=>476, 65244=>552, 65245=>727, 65246=>757, 65247=>305, 65248=>331, 65249=>619, 65250=>666, 65251=>536, 65252=>578, 65253=>734, + 65254=>761, 65255=>278, 65256=>302, 65257=>524, 65258=>536, 65259=>527, 65260=>461, 65261=>483, 65262=>517, 65263=>783, 65264=>833, 65265=>783, 65266=>833, 65267=>278, 65268=>302, 65269=>570, + 65270=>597, 65271=>570, 65272=>597, 65273=>570, 65274=>597, 65275=>570, 65276=>597, 65279=>0, 65533=>1025}; + font[:enc]=''; + font[:diff]=''; + font[:file]='DejaVuSans.z'; + font[:ctg]='DejaVuSans.ctg.z'; + font[:originalsize]=520788; +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e867d702d670ca00a87cd683a9e4a85aba9b478b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e867d702d670ca00a87cd683a9e4a85aba9b478b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +Description: + The plugin migration generator assists in working with schema additions + required by plugins. Instead of running migrations from plugins directly, + the generator creates a regular Rails migration which will be responsible + for migrating the plugins from their current version to the latest version + installed. + + This is important because the set of application migrations remains an + accurate record of the state of the database, even as plugins are installed + and removed during the development process. + +Example: + ./script/generate plugin_migration [ ...] + + This will generate: + + RAILS_ROOT + |- db + |-migrate + |- xxx_plugin_migrations.rb + + which contains the migrations for the given plugin(s). + + +Advanced Usage: + +There may be situations where you need *complete* control over the migrations +of plugins in your application, migrating a certainly plugin down to X, and +another plugin up to Y, where neither X or Y are the latest migrations for those +plugins. + +For those unfortunate few, I have two pieces of advice: + + 1. Why? This is a code smell [http://c2.com/xp/CodeSmell.html]. + + 2. Well, OK. Don't panic. You can completely control plugin migrations by + creating your own migrations. To manually migrate a plugin to a specific + version, simply use + + Engines.plugins[:your_plugin_name].migrate(version) + + where version is the integer of the migration this plugin should end + up at. + +With great power comes great responsibility. Use this wisely. \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e86b4aa0a3e324955e92b3f7034e99d911b3a474.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e86b4aa0a3e324955e92b3f7034e99d911b3a474.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,186 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +namespace :redmine do + namespace :email do + + desc <<-END_DESC +Read an email from standard input. + +General options: + unknown_user=ACTION how to handle emails from an unknown user + ACTION can be one of the following values: + ignore: email is ignored (default) + accept: accept as anonymous user + create: create a user account + no_permission_check=1 disable permission checking when receiving + the email + +Issue attributes control options: + project=PROJECT identifier of the target project + status=STATUS name of the target status + tracker=TRACKER name of the target tracker + category=CATEGORY name of the target category + priority=PRIORITY name of the target priority + allow_override=ATTRS allow email content to override attributes + specified by previous options + ATTRS is a comma separated list of attributes + +Examples: + # No project specified. Emails MUST contain the 'Project' keyword: + rake redmine:email:read RAILS_ENV="production" < raw_email + + # Fixed project and default tracker specified, but emails can override + # both tracker and priority attributes: + rake redmine:email:read RAILS_ENV="production" \\ + project=foo \\ + tracker=bug \\ + allow_override=tracker,priority < raw_email +END_DESC + + task :read => :environment do + options = { :issue => {} } + %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } + options[:allow_override] = ENV['allow_override'] if ENV['allow_override'] + options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user'] + options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check'] + + MailHandler.receive(STDIN.read, options) + end + + desc <<-END_DESC +Read emails from an IMAP server. + +General options: + unknown_user=ACTION how to handle emails from an unknown user + ACTION can be one of the following values: + ignore: email is ignored (default) + accept: accept as anonymous user + create: create a user account + no_permission_check=1 disable permission checking when receiving + the email + +Available IMAP options: + host=HOST IMAP server host (default: 127.0.0.1) + port=PORT IMAP server port (default: 143) + ssl=SSL Use SSL? (default: false) + username=USERNAME IMAP account + password=PASSWORD IMAP password + folder=FOLDER IMAP folder to read (default: INBOX) + +Issue attributes control options: + project=PROJECT identifier of the target project + status=STATUS name of the target status + tracker=TRACKER name of the target tracker + category=CATEGORY name of the target category + priority=PRIORITY name of the target priority + allow_override=ATTRS allow email content to override attributes + specified by previous options + ATTRS is a comma separated list of attributes + +Processed emails control options: + move_on_success=MAILBOX move emails that were successfully received + to MAILBOX instead of deleting them + move_on_failure=MAILBOX move emails that were ignored to MAILBOX + +Examples: + # No project specified. Emails MUST contain the 'Project' keyword: + + rake redmine:email:receive_imap RAILS_ENV="production" \\ + host=imap.foo.bar username=redmine@example.net password=xxx + + + # Fixed project and default tracker specified, but emails can override + # both tracker and priority attributes: + + rake redmine:email:receive_imap RAILS_ENV="production" \\ + host=imap.foo.bar username=redmine@example.net password=xxx ssl=1 \\ + project=foo \\ + tracker=bug \\ + allow_override=tracker,priority +END_DESC + + task :receive_imap => :environment do + imap_options = {:host => ENV['host'], + :port => ENV['port'], + :ssl => ENV['ssl'], + :username => ENV['username'], + :password => ENV['password'], + :folder => ENV['folder'], + :move_on_success => ENV['move_on_success'], + :move_on_failure => ENV['move_on_failure']} + + options = { :issue => {} } + %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } + options[:allow_override] = ENV['allow_override'] if ENV['allow_override'] + options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user'] + options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check'] + + Redmine::IMAP.check(imap_options, options) + end + + desc <<-END_DESC +Read emails from an POP3 server. + +Available POP3 options: + host=HOST POP3 server host (default: 127.0.0.1) + port=PORT POP3 server port (default: 110) + username=USERNAME POP3 account + password=PASSWORD POP3 password + apop=1 use APOP authentication (default: false) + delete_unprocessed=1 delete messages that could not be processed + successfully from the server (default + behaviour is to leave them on the server) + +See redmine:email:receive_imap for more options and examples. +END_DESC + + task :receive_pop3 => :environment do + pop_options = {:host => ENV['host'], + :port => ENV['port'], + :apop => ENV['apop'], + :username => ENV['username'], + :password => ENV['password'], + :delete_unprocessed => ENV['delete_unprocessed']} + + options = { :issue => {} } + %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } + options[:allow_override] = ENV['allow_override'] if ENV['allow_override'] + options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user'] + options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check'] + + Redmine::POP3.check(pop_options, options) + end + + desc "Send a test email to the user with the provided login name" + task :test, [:login] => :environment do |task, args| + include Redmine::I18n + abort l(:notice_email_error, "Please include the user login to test with. Example: rake redmine:email:test[login]") if args[:login].blank? + + user = User.find_by_login(args[:login]) + abort l(:notice_email_error, "User #{args[:login]} not found") unless user && user.logged? + + ActionMailer::Base.raise_delivery_errors = true + begin + Mailer.deliver_test(User.current) + puts l(:notice_email_sent, user.mail) + rescue Exception => e + abort l(:notice_email_error, e.message) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e86d85eb618c6e24990065c17ebdff0b53cd27dc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e86d85eb618c6e24990065c17ebdff0b53cd27dc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Pastorinti'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Pabraukti'; +jsToolBar.strings['Deleted'] = 'Užbraukti'; +jsToolBar.strings['Code'] = 'Kodas'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Nenumeruotas sąrašas'; +jsToolBar.strings['Ordered list'] = 'Numeruotas sąrašas'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatuotas tekstas'; +jsToolBar.strings['Wiki link'] = 'Nuoroda į Wiki puslapį'; +jsToolBar.strings['Image'] = 'Paveikslas'; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e87c2d32962212d14971d920efe32c7ad65735cf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e87c2d32962212d14971d920efe32c7ad65735cf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +require 'rexml/document' + +module Redmine + module VERSION #:nodoc: + MAJOR = 1 + MINOR = 3 + TINY = 1 + + # Branch values: + # * official release: nil + # * stable branch: stable + # * trunk: devel + BRANCH = 'stable' + + def self.revision + revision = nil + entries_path = "#{Rails.root}/.svn/entries" + if File.readable?(entries_path) + begin + f = File.open(entries_path, 'r') + entries = f.read + f.close + if entries.match(%r{^\d+}) + revision = $1.to_i if entries.match(%r{^\d+\s+dir\s+(\d+)\s}) + else + xml = REXML::Document.new(entries) + revision = + xml.elements['wc-entries'].elements[1].attributes['revision'].to_i + end + rescue + # Could not find the current revision + end + end + revision + end + + REVISION = self.revision + ARRAY = [MAJOR, MINOR, TINY, BRANCH, REVISION].compact + STRING = ARRAY.join('.') + + def self.to_a; ARRAY end + def self.to_s; STRING end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e88aba932f20a0c9bf3c41d56d6f0315fbfd93e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e88aba932f20a0c9bf3c41d56d6f0315fbfd93e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1068 @@ +# Lithuanian translations for Ruby on Rails +# by Laurynas Butkus (laurynas.butkus@gmail.com) +# Redmine translation by Gediminas Muižis gediminas.muizis@gmail.com +# and Sergej Jegorov sergej.jegorov@gmail.com +# and Gytis Gurklys gytis.gurklys@gmail.com +lt: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [sekmadienis, pirmadienis, antradienis, trečiadienis, ketvirtadienis, penktadienis, šeštadienis] +# standalone_day_names: [Sekmadienis, Pirmadienis, Antradienis, Trečiadienis, Ketvirtadienis, Penktadienis, Šeštadienis] + abbr_day_names: [Sek, Pir, Ant, Tre, Ket, Pen, Šeš] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, sausio, vasario, kovo, balandžio, gegužės, birželio, liepos, rugpjūčio, rugsėjo, spalio, lapkričio, gruodžio] + abbr_month_names: [~, Sau, Vas, Kov, Bal, Geg, Bir, Lie, Rgp, Rgs, Spa, Lap, Grd] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "ryto" + pm: "vakaro" + + datetime: + distance_in_words: + half_a_minute: "pusė minutės" + less_than_x_seconds: + one: "mažiau nei %{count} sekundė" + few: "mažiau nei %{count} sekundžių" + many: "mažiau nei %{count} sekundžių" + other: "mažiau nei %{count} sekundės" + x_seconds: + one: "%{count} sekundė" + few: "%{count} sekundžių" + many: "%{count} sekundžių" + other: "%{count} sekundės" + less_than_x_minutes: + one: "mažiau nei minutė" + other: "mažiau nei %{count} minutės" + x_minutes: + one: "1 minutė" + other: "%{count} minutės" + about_x_hours: + one: "apie 1 valanda" + other: "apie %{count} valandų" + x_days: + one: "1 diena" + other: "%{count} dienų" + about_x_months: + one: "apie 1 mėnuo" + other: "apie %{count} mėnesiai" + x_months: + one: "1 mėnuo" + other: "%{count} mėnesiai" + about_x_years: + one: "apie 1 metai" + other: "apie %{count} metų" + over_x_years: + one: "virš 1 metų" + other: "virš %{count} metų" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + prompts: + year: "Metai" + month: "Mėnuo" + day: "Diena" + hour: "Valanda" + minute: "Minutė" + second: "Sekundės" + + number: + format: + separator: "," + delimiter: " " + precision: 3 + + currency: + format: + format: "%n %u" + unit: "Lt" + separator: "," + delimiter: " " + precision: 2 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 1 + storage_units: + # Storage units output formatting. + # %u is the storage unit, %n is the number (default: 2 MB) + format: "%n %u" + units: + byte: + one: "baitas" + few: "baitų" + many: "baitų" + other: "baitai" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + # Rails 2.2 + sentence_connector: "ir" + skip_last_comma: true + # Rails 2.3 + words_connector: ", " + two_words_connector: " ir " + last_word_connector: " ir " + + activerecord: + errors: + template: + header: + one: "Išsaugant objektą %{model} rasta %{count} klaida" + few: "Išsaugant objektą %{model} rasta %{count} klaidų" + many: "Išsaugant objektą %{model} rasta %{count} klaidų" + other: "Išsaugant objektą %{model} rastos %{count} klaidos" + body: "Šiuose laukuose yra klaidų:" + + messages: + inclusion: "nenumatyta reikšmė" + exclusion: "užimtas" + invalid: "neteisingas" + confirmation: "neteisingai pakartotas" + accepted: "turi būti patvirtintas" + empty: "negali būti tuščias" + blank: "negali būti tuščias" + too_long: + one: "per ilgas (daugiausiai %{count} simbolius)" + few: "per ilgas (daugiausiai %{count} simboliu)" + many: "per ilgas (daugiausiai %{count} simboliu)" + other: "per ilgas (daugiausiai %{count} simboliai)" + too_short: + one: "per trumpas (mažiausiai %{count} simbolius)" + few: "per trumpas (mažiausiai %{count} simboliu)" + many: "per trumpas (mažiausiai %{count} simboliu)" + other: "per trumpas (mažiausiai %{count} simboliai)" + wrong_length: + one: "neteisingo ilgio (turi būti lygiai %{count} simbolius)" + few: "neteisingo ilgio (turi būti lygiai %{count} simboliu)" + many: "neteisingo ilgio (turi būti lygiai %{count} simboliu)" + other: "neteisingo ilgio (turi būti lygiai %{count} simboliai)" + taken: "jau užimtas" + not_a_number: "ne skaičius" + not_a_date: "is not a valid date" + greater_than: "turi būti didesnis už %{count}" + greater_than_or_equal_to: "turi būti didesnis arba lygus %{count}" + equal_to: "turi būti lygus %{count}" + less_than: "turi būti mažesnis už %{count}" + less_than_or_equal_to: "turi būti mažesnis arba lygus %{count}" + odd: "turi būti nelyginis" + even: "turi būti lyginis" + greater_than_start_date: "turi būti didesnė negu pradžios data" + not_same_project: "nepriklauso tam pačiam projektui" + circular_dependency: "Šis ryšys sukurtų ciklinę priklausomybę" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: prašom parinkti + + general_text_No: 'Ne' + general_text_Yes: 'Taip' + general_text_no: 'ne' + general_text_yes: 'taip' + general_lang_name: 'Lithuanian (lietuvių)' + general_csv_separator: ';' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Paskyra buvo sėkmingai atnaujinta. + notice_account_invalid_creditentials: Negaliojantis vartotojo vardas ar slaptažodis + notice_account_password_updated: Slaptažodis buvo sėkmingai atnaujintas. + notice_account_wrong_password: Neteisingas slaptažodis + notice_account_register_done: Paskyra buvo sėkmingai sukurta. Kad aktyvintumėte savo paskyrą, paspauskite sąsają, kuri jums buvo siųsta elektroniniu paštu. + notice_account_unknown_email: Nežinomas vartotojas. + notice_can_t_change_password: Šis pranešimas naudoja išorinį autentiškumo nustatymo šaltinį. Neįmanoma pakeisti slaptažodį. + notice_account_lost_email_sent: Į Jūsų paštą išsiųstas laiškas su naujo slaptažodžio pasirinkimo instrukcija. + notice_account_activated: Jūsų paskyra aktyvuota. Galite prisijungti. + notice_successful_create: Sėkmingas sukūrimas. + notice_successful_update: Sėkmingas atnaujinimas. + notice_successful_delete: Sėkmingas panaikinimas. + notice_successful_connection: Sėkmingas susijungimas. + notice_file_not_found: Puslapis, į kurį ketinate įeiti, neegzistuoja arba yra pašalintas. + notice_locking_conflict: Duomenys atnaujinti kito vartotojo. + notice_not_authorized: Jūs neturite teisių gauti prieigą prie šio puslapio. + notice_email_sent: "Laiškas išsiųstas %{value}" + notice_email_error: "Laiško siuntimo metu įvyko klaida (%{value})" + notice_feeds_access_key_reseted: Jūsų RSS raktas buvo atnaujintas. + notice_failed_to_save_issues: "Nepavyko išsaugoti %{count} problemos(ų) iš %{total} pasirinkto: %{ids}." + notice_no_issue_selected: "Nepasirinkta nė viena problema! Prašom pažymėti problemą, kurią norite redaguoti." + notice_account_pending: "Jūsų paskyra buvo sukurta ir dabar laukiama administratoriaus patvirtinimo." + notice_default_data_loaded: Numatytoji konfiguracija sėkmingai užkrauta. + notice_unable_delete_version: Neįmanoma panaikinti versiją + + error_can_t_load_default_data: "Numatytoji konfiguracija negali būti užkrauta: %{value}" + error_scm_not_found: "Duomenys ir/ar pakeitimai saugykloje(repozitorojoje) neegzistuoja." + error_scm_command_failed: "Įvyko klaida jungiantis prie saugyklos: %{value}" + error_scm_annotate: "Įrašas neegzistuoja arba negalima jo atvaizduoti." + error_issue_not_found_in_project: 'Darbas nerastas arba nesurištas su šiuo projektu' + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: Nenustatyta numatytoji darbų būsena. Prašome patikrinti konfigūravimą ("Administravimas -> Darbų būsenos"). + error_can_not_reopen_issue_on_closed_version: Uždarytai versijai priskirtas darbas negali būti atnaujintas. + error_can_not_archive_project: Šio projekto negalima suarchyvuoti + + warning_attachments_not_saved: "%{count} byla(ų) negali būti išsaugota." + + mail_subject_lost_password: "Jūsų %{value} slaptažodis" + mail_body_lost_password: 'Norėdami pakeisti slaptažodį, spauskite nuorodą:' + mail_subject_register: "Jūsų %{value} paskyros aktyvavimas" + mail_body_register: 'Norėdami aktyvuoti paskyrą, spauskite nuorodą:' + mail_body_account_information_external: "Jūs galite naudoti Jūsų %{value} paskyrą, norėdami prisijungti." + mail_body_account_information: Informacija apie Jūsų paskyrą + mail_subject_account_activation_request: "%{value} paskyros aktyvavimo prašymas" + mail_body_account_activation_request: "Užsiregistravo naujas vartotojas (%{value}). Jo paskyra laukia jūsų patvirtinimo:" + mail_subject_reminder: "%{count} darbas(ai) po kelių %{days} dienų" + mail_body_reminder: "%{count} darbas(ai), kurie yra jums priskirti, baigiasi po %{days} dienų(os):" + mail_subject_wiki_content_added: "'%{id}' pridėtas wiki puslapis" + mail_body_wiki_content_added: "The '%{id}' wiki puslapi pridėjo %{author}." + mail_subject_wiki_content_updated: "'%{id}' atnaujintas wiki puslapis" + mail_body_wiki_content_updated: "The '%{id}' wiki puslapį atnaujino %{author}." + + gui_validation_error: 1 klaida + gui_validation_error_plural: "%{count} klaidų(os)" + + field_name: Pavadinimas + field_description: Aprašas + field_summary: Santrauka + field_is_required: Reikalaujama + field_firstname: Vardas + field_lastname: Pavardė + field_mail: El.paštas + field_filename: Byla + field_filesize: Dydis + field_downloads: Atsiuntimai + field_author: Autorius + field_created_on: Sukurta + field_updated_on: Atnaujinta + field_field_format: Formatas + field_is_for_all: Visiems projektams + field_possible_values: Galimos reikšmės + field_regexp: Pastovi išraiška + field_min_length: Minimalus ilgis + field_max_length: Maksimalus ilgis + field_value: Vertė + field_category: Kategorija + field_title: Pavadinimas + field_project: Projektas + field_issue: Darbas + field_status: Būsena + field_notes: Pastabos + field_is_closed: Darbas uždarytas + field_is_default: Numatytoji vertė + field_tracker: Pėdsekys + field_subject: Tema + field_due_date: Užbaigimo data + field_assigned_to: Paskirtas + field_priority: Prioritetas + field_fixed_version: Tikslinė versija + field_user: Vartotojas + field_role: Vaidmuo + field_homepage: Pagrindinis puslapis + field_is_public: Viešas + field_parent: Priklauso projektui + field_is_in_chlog: Darbai rodomi pokyčių žurnale + field_is_in_roadmap: Darbai rodomi veiklos grafike + field_login: Registracijos vardas + field_mail_notification: Elektroninio pašto pranešimai + field_admin: Administratorius + field_last_login_on: Paskutinis ryšys + field_language: Kalba + field_effective_date: Data + field_password: Slaptažodis + field_new_password: Naujas slaptažodis + field_password_confirmation: Patvirtinimas + field_version: Versija + field_type: Tipas + field_host: Pagrindinis kompiuteris + field_port: Prievadas + field_account: Paskyra + field_base_dn: Bazinis skiriamasis vardas (base DN) + field_attr_login: Registracijos vardo požymis (login) + field_attr_firstname: Vardo priskiria + field_attr_lastname: Pavardės priskiria + field_attr_mail: Elektroninio pašto požymis + field_onthefly: Automatinis vartotojų registravimas + field_start_date: Pradėti + field_done_ratio: "% atlikta" + field_auth_source: Autentiškumo nustatymo būdas + field_hide_mail: Paslėpkite mano elektroninio pašto adresą + field_comments: Komentaras + field_url: URL + field_start_page: Pradžios puslapis + field_subproject: Subprojektas + field_hours: valandos + field_activity: Veikla + field_spent_on: Data + field_identifier: Identifikuotojas + field_is_filter: Panaudotas kaip filtras + field_issue_to: Susijęs darbas + field_delay: Užlaikymas + field_assignable: Darbai gali būti paskirti šiam vaidmeniui + field_redirect_existing_links: Peradresuokite egzistuojančias sąsajas + field_estimated_hours: Numatyta trukmė + field_column_names: Skiltys + field_time_zone: Laiko juosta + field_searchable: Randamas + field_default_value: Numatytoji vertė + field_comments_sorting: rodyti komentarus + field_parent_title: Aukštesnio lygio puslapis + field_editable: Redaguojamas + field_watcher: Stebėtojas + field_identity_url: OpenID URL + field_content: Turinys + field_group_by: Sugrupuoti pagal + field_active: Activis + field_sharing: Dalijimasis (Sharing) + + setting_app_title: Programos pavadinimas + setting_app_subtitle: Programos paantraštė + setting_welcome_text: Pasveikinimas + setting_default_language: Numatytoji kalba + setting_login_required: Reikalingas autentiškumo nustatymas + setting_self_registration: Saviregistracija + setting_attachment_max_size: Priedo maks. dydis + setting_issues_export_limit: Darbų eksportavimo riba + setting_mail_from: Emisijos elektroninio pašto adresas + setting_bcc_recipients: Akli tikslios kopijos gavėjai (bcc) + setting_plain_text_mail: tik tekstas (be HTML) + setting_host_name: Pagrindinio kompiuterio vardas + setting_text_formatting: Teksto apipavidalinimas + setting_wiki_compression: Wiki istorijos suspaudimas + setting_feeds_limit: Perdavimo turinio riba + setting_default_projects_public: Naujas projektas viešas pagal nutylėjimą + setting_autofetch_changesets: Automatinis pakeitimų siuntimas + setting_sys_api_enabled: Įgalinkite WS sandėlio vadybai + setting_commit_ref_keywords: Nurodymo reikšminiai žodžiai + setting_commit_fix_keywords: Fiksavimo reikšminiai žodžiai + setting_autologin: Autoregistracija + setting_date_format: Datos formatas + setting_time_format: Laiko formatas + setting_cross_project_issue_relations: Leisti tarprojektinius darbų ryšius + setting_issue_list_default_columns: Numatytosios skiltys darbų sąraše + setting_emails_footer: elektroninio pašto puslapinė poraštė + setting_protocol: Protokolas + setting_per_page_options: Įrašų puslapyje nustatimas + setting_user_format: Vartotojo atvaizdavimo formatas + setting_activity_days_default: Atvaizduojamos dienos projekto veikloje + setting_display_subprojects_issues: Pagal nutylėjimą rodyti subprojektų darbus pagrindiniame projekte + setting_enabled_scm: Įgalintas SCM + setting_mail_handler_api_enabled: Įgalinti WS įeinantiems laiškams + setting_mail_handler_api_key: API raktas + setting_sequential_project_identifiers: Generuoti nuoseklius projekto identifikatorius + setting_gravatar_enabled: Naudoti Gravatar vartotojo paveiksliukus + setting_gravatar_default: Gravatar paveiksliukas pagal nutylėjimą + setting_diff_max_lines_displayed: Maksimalus rodomas eilučiu skaičius diff\'e + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Leisti OpenID prisijungimą ir registraciją + setting_password_min_length: Minimalus slaptažodžio ilgis + setting_new_project_user_role_id: Vaidmuo, suteikiamas vartotojui (non-admin), kuris sukuria projektą + setting_default_projects_modules: Nustatytieji naujam projektui priskirti moduliai + + permission_add_project: Sukurti projektą + permission_edit_project: Taisyti projektą + permission_select_project_modules: Parinkti projekto modulius + permission_manage_members: Valdyti narius + permission_manage_versions: Valdyti versijas + permission_manage_categories: Valdyti darbų kategorijas + permission_add_issues: Sukurti darbus + permission_edit_issues: Redaguoti darbus + permission_manage_issue_relations: Valdyti darbų ryšius + permission_add_issue_notes: Sukurti pastabas + permission_edit_issue_notes: Redaguoti pastabas + permission_edit_own_issue_notes: Redaguoti savo pastabas + permission_move_issues: Perkelti darbus + permission_delete_issues: Pašalinti darbus + permission_manage_public_queries: Valdyti viešas užklausas + permission_save_queries: Išsaugoti užklausas + permission_view_gantt: Matyti Gantt grafiką + permission_view_calendar: Matyti kalendorių + permission_view_issue_watchers: Matyti stebėtojų sąrašą + permission_add_issue_watchers: Pridėti stebėtojus + permission_delete_issue_watchers: Pašalinti stebėtojus + permission_log_time: Regsitruoti dirbtą laiką + permission_view_time_entries: Matyti dirbtą laiką + permission_edit_time_entries: Redaguoti laiko įrašus + permission_edit_own_time_entries: Redguoti savo laiko įrašus + permission_manage_news: Valdyti naujienas + permission_comment_news: Komentuoti naujienas + permission_manage_documents: Valdyti dokumentus + permission_view_documents: Matyti dokumentus + permission_manage_files: Valdyti bylas + permission_view_files: Matyti bylas + permission_manage_wiki: Valdyti wiki + permission_rename_wiki_pages: Pevadinti wiki puslapius + permission_delete_wiki_pages: Pašalinti wiki puslapius + permission_view_wiki_pages: Matyti wiki + permission_view_wiki_edits: Matyti wiki istoriją + permission_edit_wiki_pages: Redaguoti wiki puslapius + permission_delete_wiki_pages_attachments: Pašalinti priedus + permission_protect_wiki_pages: Apsaugoti wiki puslapius + permission_manage_repository: Pašalinti repository + permission_browse_repository: Peržiūrėti repository + permission_view_changesets: Matyti pakeitimus + permission_commit_access: Commit access + permission_manage_boards: Valdyti boards + permission_view_messages: Matyti pranešimus + permission_add_messages: Post pranešimus + permission_edit_messages: Redaguoti pranešimus + permission_edit_own_messages: Redaguoti savo pranešimus + permission_delete_messages: Pašalinti pranešimus + permission_delete_own_messages: Pašalinti savo pranešimus + permission_delete_issue_watchers: Pašalinti stebėtojus + + project_module_issue_tracking: Darbu pėdsekys + project_module_time_tracking: Laiko pėdsekys + project_module_news: Naujienos + project_module_documents: Dokumentai + project_module_files: Rinkmenos + project_module_wiki: Wiki + project_module_repository: Saugykla + project_module_boards: Forumai + + label_user: Vartotojas + label_user_plural: Vartotojai + label_user_new: Naujas vartotojas + label_project: Projektas + label_project_new: Naujas projektas + label_project_plural: Projektai + label_x_projects: + zero: nėra projektų + one: 1 projektas + other: "%{count} projektų" + label_project_all: Visi Projektai + label_project_latest: Paskutiniai projektai + label_issue: Darbas + label_issue_new: Naujas darbas + label_issue_plural: Darbai + label_issue_view_all: Peržiūrėti visus darbus + label_issues_by: "Darbai pagal %{value}" + label_issue_added: Darbas pridėtas + label_issue_updated: Darbas atnaujintas + label_document: Dokumentas + label_document_new: Naujas dokumentas + label_document_plural: Dokumentai + label_document_added: Dokumentas pridėtas + label_role: Vaidmuo + label_role_plural: Vaidmenys + label_role_new: Naujas vaidmuo + label_role_and_permissions: Vaidmenys ir leidimai + label_member: Narys + label_member_new: Naujas narys + label_member_plural: Nariai + label_tracker: Pėdsekys + label_tracker_plural: Pėdsekiai + label_tracker_new: Naujas pėdsekys + label_workflow: Darbų eiga + label_issue_status: Darbo būsena + label_issue_status_plural: Darbų būsenos + label_issue_status_new: Nauja būsena + label_issue_category: Darbo kategorija + label_issue_category_plural: Darbo kategorijos + label_issue_category_new: Nauja kategorija + label_custom_field: Kliento laukas + label_custom_field_plural: Kliento laukai + label_custom_field_new: Naujas kliento laukas + label_enumerations: Išvardinimai + label_enumeration_new: Nauja vertė + label_information: Informacija + label_information_plural: Informacija + label_please_login: Prašom prisijungti + label_register: Užsiregistruoti + label_password_lost: Prarastas slaptažodis + label_home: Pagrindinis + label_my_page: Mano puslapis + label_my_account: Mano paskyra + label_my_projects: Mano projektai + label_administration: Administravimas + label_login: Prisijungti + label_logout: Atsijungti + label_help: Pagalba + label_reported_issues: Pranešti darbai + label_assigned_to_me_issues: Darbai, priskirti man + label_last_login: Paskutinis ryšys + label_registered_on: Užregistruota + label_activity: Veikla + label_overall_activity: Visa veikla + label_user_activity: "%{value}o veiksmai" + label_new: Naujas + label_logged_as: Prisijungęs kaip + label_environment: Aplinka + label_authentication: Autentiškumo nustatymas + label_auth_source: Autentiškumo nustatymo būdas + label_auth_source_new: Naujas autentiškumo nustatymo būdas + label_auth_source_plural: Autentiškumo nustatymo būdai + label_subproject_plural: Subprojektai + label_and_its_subprojects: "%{value} projektas ir jo subprojektai" + label_min_max_length: Min - Maks ilgis + label_list: Sąrašas + label_date: Data + label_integer: Sveikasis skaičius + label_float: Float + label_boolean: Boolean + label_string: Tekstas + label_text: Ilgas tekstas + label_attribute: Požymis + label_attribute_plural: Požymiai + label_download: "%{count} persiuntimas" + label_download_plural: "%{count} persiuntimai" + label_no_data: Nėra ką atvaizduoti + label_change_status: Pakeitimo būsena + label_history: Istorija + label_attachment: Rinkmena + label_attachment_new: Nauja rinkmena + label_attachment_delete: Pašalinkite rinkmeną + label_attachment_plural: Rinkmenos + label_file_added: Byla pridėta + label_report: Ataskaita + label_report_plural: Ataskaitos + label_news: Naujiena + label_news_new: Pridėkite naujieną + label_news_plural: Naujienos + label_news_latest: Paskutinės naujienos + label_news_view_all: Peržiūrėti visas naujienas + label_news_added: Naujiena pridėta + label_change_log: Pakeitimų žurnalas + label_settings: Nustatymai + label_overview: Apžvalga + label_version: Versija + label_version_new: Nauja versija + label_version_plural: Versijos + label_confirmation: Patvirtinimas + label_export_to: Eksportuoti į + label_read: Skaitykite... + label_public_projects: Vieši projektai + label_open_issues: atidaryta + label_open_issues_plural: atidaryti + label_closed_issues: uždaryta + label_closed_issues_plural: uždaryti + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 uždarytu + one: 1 uždarytas + other: "%{count} uždarytu" + label_total: Bendra suma + label_permissions: Leidimai + label_current_status: Einamoji būsena + label_new_statuses_allowed: Naujos būsenos galimos + label_all: visi + label_none: niekas + label_nobody: niekas + label_next: Kitas + label_previous: Ankstesnis + label_used_by: Naudotas + label_details: Detalės + label_add_note: Pridėkite pastabą + label_per_page: Per puslapį + label_calendar: Kalendorius + label_months_from: mėnesiai nuo + label_gantt: Gantt + label_internal: Vidinis + label_last_changes: "paskutiniai %{count}, pokyčiai" + label_change_view_all: Peržiūrėti visus pakeitimus + label_personalize_page: Suasmeninti šį puslapį + label_comment: Komentaras + label_comment_plural: Komentarai + label_x_comments: + zero: nėra komentarų + one: 1 komentaras + other: "%{count} komentarų" + label_comment_add: Pridėkite komentarą + label_comment_added: Komentaras pridėtas + label_comment_delete: Pašalinkite komentarus + label_query: Užklausa + label_query_plural: Užklausos + label_query_new: Nauja užklausa + label_filter_add: Pridėti filtrą + label_filter_plural: Filtrai + label_equals: yra + label_not_equals: nėra + label_in_less_than: mažiau negu + label_in_more_than: daugiau negu + label_in: in + label_today: šiandien + label_all_time: visas laikas + label_yesterday: vakar + label_this_week: šią savaitę + label_last_week: paskutinė savaitė + label_last_n_days: "paskutinių %{count} dienų" + label_this_month: šis menuo + label_last_month: paskutinis menuo + label_this_year: šiemet + label_date_range: Dienų diapazonas + label_less_than_ago: mažiau negu dienomis prieš + label_more_than_ago: daugiau negu dienomis prieš + label_ago: dienomis prieš + label_contains: turi savyje + label_not_contains: neturi savyje + label_day_plural: dienos + label_repository: Saugykla + label_repository_plural: Saugyklos + label_browse: Naršyti + label_modification: "%{count} pakeitimas" + label_modification_plural: "%{count} pakeitimai" + label_revision: Revizija + label_revision_plural: Revizijos + label_associated_revisions: susijusios revizijos + label_added: pridėtas + label_modified: pakeistas + label_copied: nukopijuotas + label_renamed: pervardintas + label_deleted: pašalintas + label_latest_revision: Paskutinė revizija + label_latest_revision_plural: Paskutinės revizijos + label_view_revisions: Pežiūrėti revizijas + label_max_size: Maksimalus dydis + label_sort_highest: Perkelti į viršūnę + label_sort_higher: Perkelti į viršų + label_sort_lower: Perkelti žemyn + label_sort_lowest: Perkelti į apačią + label_roadmap: Veiklos grafikas + label_roadmap_due_in: "Baigiasi po %{value}" + label_roadmap_overdue: "%{value} vėluojama" + label_roadmap_no_issues: Jokio darbo šiai versijai nėra + label_search: Ieškoti + label_result_plural: Rezultatai + label_all_words: Visi žodžiai + label_wiki: Wiki + label_wiki_edit: Wiki redakcija + label_wiki_edit_plural: Wiki redakcijos + label_wiki_page: Wiki puslapis + label_wiki_page_plural: Wiki puslapiai + label_index_by_title: Indeksas prie pavadinimo + label_index_by_date: Indeksas prie datos + label_current_version: Einamoji versija + label_preview: Peržiūra + label_feed_plural: Įeitys(Feeds) + label_changes_details: Visų pakeitimų detalės + label_issue_tracking: Darbų sekimas + label_spent_time: Dirbtas laikas + label_f_hour: "%{value} valanda" + label_f_hour_plural: "%{value} valandų" + label_time_tracking: Laiko sekimas + label_change_plural: Pakeitimai + label_statistics: Statistika + label_commits_per_month: Paveda(commit) per mėnesį + label_commits_per_author: Autoriaus pavedos(commit) + label_view_diff: Skirtumų peržiūra + label_diff_inline: įterptas + label_diff_side_by_side: šalia + label_options: Pasirinkimai + label_copy_workflow_from: Kopijuoti darbų eiga iš + label_permissions_report: Leidimų pranešimas + label_watched_issues: Stebimi darbai + label_related_issues: Susiję darbai + label_applied_status: Taikomoji būsena + label_loading: Kraunama... + label_relation_new: Naujas ryšys + label_relation_delete: Pašalinkite ryšį + label_relates_to: susietas su + label_duplicates: dubliuoja + label_duplicated_by: dubliuojasi + label_blocks: blokuoja + label_blocked_by: blokuojasi + label_precedes: ankstesnė + label_follows: seka + label_end_to_start: užbaigti, kad pradėti + label_end_to_end: užbaigti, kad pabaigti + label_start_to_start: pradėkite pradėti + label_start_to_end: pradėkite užbaigti + label_stay_logged_in: Likti prisijungus + label_disabled: išjungta(as) + label_show_completed_versions: Parodyti užbaigtas versijas + label_me: aš + label_board: Forumas + label_board_new: Naujas forumas + label_board_plural: Forumai + label_topic_plural: Temos + label_message_plural: Pranešimai + label_message_last: Paskutinis pranešimas + label_message_new: Naujas pranešimas + label_message_posted: Pranešimas pridėtas + label_reply_plural: Atsakymai + label_send_information: Nusiųsti paskyros informaciją vartotojui + label_year: Metai + label_month: Mėnuo + label_week: Savaitė + label_date_from: Nuo + label_date_to: Iki + label_language_based: Pagrįsta vartotojo kalba + label_sort_by: "Rūšiuoti pagal %{value}" + label_send_test_email: Nusiųsti bandomąjį elektroninį laišką + label_feeds_access_key_created_on: "RSS prieigos raktas sukurtas prieš %{value}" + label_module_plural: Moduliai + label_added_time_by: "Pridėjo %{author} prieš %{age}" + label_updated_time_by: "Atnaujino %{author} %{age} atgal" + label_updated_time: "Atnaujinta prieš %{value}" + label_jump_to_a_project: Šuolis į projektą... + label_file_plural: Bylos + label_changeset_plural: Changesets + label_default_columns: Numatyti stulpeliai + label_no_change_option: (Jokio pakeitimo) + label_bulk_edit_selected_issues: Masinis pasirinktų darbų(issues) redagavimas + label_theme: Tema + label_default: Numatyta(as) + label_search_titles_only: Ieškoti pavadinimų tiktai + label_user_mail_option_all: "Bet kokiam įvykiui visuose mano projektuose" + label_user_mail_option_selected: "Bet kokiam įvykiui tiktai pasirinktuose projektuose ..." + label_user_mail_no_self_notified: "Nenoriu būti informuotas apie pakeitimus, kuriuos pats atlieku" + label_registration_activation_by_email: "paskyros aktyvacija per e-paštą" + label_registration_manual_activation: "rankinė paskyros aktyvacija" + label_registration_automatic_activation: "automatinė paskyros aktyvacija" + label_display_per_page: "%{value} įrašų puslapyje" + label_age: Amžius + label_change_properties: Pakeisti nustatymus + label_general: Bendri + label_more: Daugiau + label_scm: SCM + label_plugins: Įskiepiai + label_ldap_authentication: LDAP autentifikacija + label_downloads_abbr: siunt. + label_optional_description: Apibūdinimas (laisvai pasirenkamas) + label_add_another_file: Pridėti kitą bylą + label_preferences: Savybės + label_chronological_order: Chronologine tvarka + label_reverse_chronological_order: Atbuline chronologine tvarka + label_planning: Planavimas + label_incoming_emails: Įeinantys laiškai + label_generate_key: Generuoti raktą + label_issue_watchers: Stebėtojai + label_example: Pavyzdys + label_display: Display + label_login_with_open_id_option: arba prisijunkite su OpenID + label_descending: Descending + label_sort: Rūšiuoti + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_wiki_content_added: Wiki puslapis pridėtas + label_wiki_content_updated: Wiki puslapis atnaujintas + label_view_all_revisions: Rodyti visos revizijas + label_tag: Tag'as + label_branch: Branch'as + label_group_plural: Grupės + label_group: Grupė + label_group_new: Nauja grupė + label_time_entry_plural: Sprendimo laikas + label_user_anonymous: Anonimas + label_version_sharing_hierarchy: Su projekto hierarchija + label_version_sharing_system: Su visais projektais + label_version_sharing_descendants: Su subprojektais + label_version_sharing_tree: Su projekto medžiu + label_version_sharing_none: Nesidalinama + + button_login: Registruotis + button_submit: Pateikti + button_save: Išsaugoti + button_check_all: Žymėti visus + button_uncheck_all: Atžymėti visus + button_delete: Pašalinti + button_create: Sukurti + button_create_and_continue: Sukurti ir tęsti + button_test: Testas + button_edit: Redaguoti + button_add: Pridėti + button_change: Keisti + button_apply: Pritaikyti + button_clear: Išvalyti + button_lock: Rakinti + button_unlock: Atrakinti + button_download: Atsisiųsti + button_list: Sąrašas + button_view: Žiūrėti + button_move: Perkelti + button_move_and_follow: Perkelti ir sekti + button_back: Atgal + button_cancel: Atšaukti + button_activate: Aktyvinti + button_sort: Rūšiuoti + button_log_time: Dirbtas laikas + button_rollback: Grįžti į šią versiją + button_watch: Stebėti + button_unwatch: Nestebėti + button_reply: Atsakyti + button_archive: Archyvuoti + button_unarchive: Išpakuoti + button_reset: Atstatyti + button_rename: Pervadinti + button_change_password: Pakeisti slaptažodį + button_copy: Kopijuoti + button_annotate: Rašyti pastabą + button_update: Atnaujinti + button_configure: Konfigūruoti + button_quote: Cituoti + button_duplicate: Dubliuoti + button_copy_and_follow: Kopijuoti ir laikytis + + status_active: aktyvus + status_registered: užregistruotas + status_locked: užrakintas + + version_status_open: atidaryta + version_status_locked: užrakinta + version_status_closed: uždaryta + + text_select_mail_notifications: Išrinkite veiksmus, apie kuriuos būtų pranešta elektroniniu paštu. + text_regexp_info: pvz. ^[A-Z0-9]+$ + text_min_max_length_info: 0 reiškia jokių apribojimų + text_project_destroy_confirmation: Ar esate įsitikinęs, kad jūs norite pašalinti šį projektą ir visus susijusius duomenis? + text_subprojects_destroy_warning: "Šis(ie) subprojektas(ai): %{value} taip pat bus ištrintas(i)." + text_workflow_edit: Išrinkite vaidmenį ir pėdsekį, kad redaguotumėte darbų eigą + text_are_you_sure: Ar esate įsitikinęs? + text_journal_changed: "%{label} pakeista iš %{old} į %{new}" + text_journal_set_to: "%{label} pakeista į %{value}" + text_journal_deleted: "%{label} ištrintas (%{old})" + text_journal_added: "%{label} %{value} pridėtas" + text_tip_issue_begin_day: užduotis, prasidedanti šią dieną + text_tip_issue_end_day: užduotis, pasibaigianti šią dieną + text_tip_issue_begin_end_day: užduotis, prasidedanti ir pasibaigianti šią dieną + text_project_identifier_info: 'Mažosios raidės (a-z), skaičiai ir brūkšniai galimi.
    Išsaugojus, identifikuotojas negali būti keičiamas.' + text_caracters_maximum: "%{count} simbolių maksimumas." + text_caracters_minimum: "Turi būti mažiausiai %{count} simbolių ilgio." + text_length_between: "Ilgis tarp %{min} ir %{max} simbolių." + text_tracker_no_workflow: Jokia darbų eiga neapibrėžta šiam pėdsekiui + text_unallowed_characters: Neleistini simboliai + text_comma_separated: Leistinos kelios reikšmės (atskirtos kableliu). + text_issues_ref_in_commit_messages: Darbų pavedimų(commit) nurodymas ir fiksavimas pranešimuose + text_issue_added: "Darbas %{id} buvo praneštas (by %{author})." + text_issue_updated: "Darbas %{id} buvo atnaujintas (by %{author})." + text_wiki_destroy_confirmation: Ar esate įsitikinęs, kad jūs norite pašalinti wiki ir visą jos turinį? + text_issue_category_destroy_question: "Kai kurie darbai (%{count}) yra paskirti šiai kategorijai. Ką jūs norite daryti?" + text_issue_category_destroy_assignments: Pašalinti kategorijos užduotis + text_issue_category_reassign_to: Iš naujo priskirti darbus šiai kategorijai + text_user_mail_option: "neišrinktiems projektams, jūs tiktai gausite pranešimus apie įvykius, kuriuos jūs stebite, arba į kuriuos esate įtrauktas (pvz. darbai, jūs esate autorius ar įgaliotinis)." + text_no_configuration_data: "Vaidmenys, pėdsekiai, darbų būsenos ir darbų eiga dar nebuvo konfigūruoti.\nGriežtai rekomenduojam užkrauti numatytąją(default)konfiguraciją. Užkrovus, galėsite ją modifikuoti." + text_load_default_configuration: Užkrauti numatytąj konfiguraciją + text_status_changed_by_changeset: "Pakeista %{value} revizijoje." + text_issues_destroy_confirmation: 'Ar jūs tikrai norite sunaikinti pažymėtą(us) darbą(us)?' + text_select_project_modules: 'Parinkite modulius, kuriuos norite naudoti šiame projekte:' + text_default_administrator_account_changed: Administratoriaus numatyta paskyra pakeista + text_file_repository_writable: Į rinkmenu saugyklą galima saugoti (RW) + text_plugin_assets_writable: Įskiepių 'assets' katalogas įrašomas + text_rmagick_available: RMagick pasiekiamas (pasirinktinai) + text_destroy_time_entries_question: Naikinamam darbui priskirta %{hours} valandų. Ką jūs noryte su jomis daryti? + text_destroy_time_entries: Ištrinti paskelbtas valandas + text_assign_time_entries_to_project: Priskirti valandas prie projekto + text_reassign_time_entries: 'Priskirti paskelbtas valandas šiam darbui:' + text_user_wrote: "%{value} parašė:" + text_enumeration_destroy_question: "%{count} objektai priskirti šiai reikšmei." + text_enumeration_category_reassign_to: 'Priskirti juos šiai reikšmei:' + text_email_delivery_not_configured: "El.pašto siuntimas nesukonfigūruotas, ir perspėjimai neaktyvus.\nSukonfigūruokite savo SMTP serverį byloje config/configuration.yml ir perleiskite programą norėdami pritaikyti pakeitimus." + text_repository_usernames_mapping: "Parinkite ar atnaujinkite Redmine vartotojo vardą kiekvienam saugyklos vardui, kuris paminėtas saugyklos log'e.\nVartotojai, turintys tą patį Redmine ir saugyklos vardą ar el.paštą automatiškai surišti." + text_diff_truncated: "... Šis diff'as nukarpytas, nes jis viršijo maksimalų rodomą eilučių skaičių." + text_custom_field_possible_values_info: 'Po vieną eilutę kiekvienai reikšmei' + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Priskirkite iš naujo 'child' puslapius šiam puslapiui + text_wiki_page_nullify_children: Laikyti child puslapius as root puslapius + text_wiki_page_destroy_children: Pašalinti child puslapius ir jų sekinius + + default_role_manager: Vadovas + default_role_developer: Projektuotojas + default_role_reporter: Pranešėjas + default_tracker_bug: Klaida + default_tracker_feature: Ypatybė + default_tracker_support: Palaikymas + default_issue_status_new: Naujas + default_issue_status_in_progress: Vykdomas + default_issue_status_resolved: Išspręstas + default_issue_status_feedback: Grįžtamasis ryšys + default_issue_status_closed: Uždarytas + default_issue_status_rejected: Atmestas + default_doc_category_user: Vartotojo dokumentacija + default_doc_category_tech: Techninė dokumentacija + default_priority_low: Žemas + default_priority_normal: Normalus + default_priority_high: Aukštas + default_priority_urgent: Skubus + default_priority_immediate: Neatidėliotinas + default_activity_design: Projektavimas + default_activity_development: Vystymas + + enumeration_issue_priorities: Darbo prioritetai + enumeration_doc_categories: Dokumento kategorijos + enumeration_activities: Veiklos (laiko sekimas) + enumeration_system_activity: Sistemos veikla + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + setting_start_of_week: Start calendars on + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit pranešimų koduotė + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e8/e8fc419080a0a4bab2022b5cb881a3e0c59a807b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e8/e8fc419080a0a4bab2022b5cb881a3e0c59a807b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +<%= call_hook :view_account_login_top %> +
    +<% form_tag({:action=> "login"}) do %> +<%= back_url_hidden_field_tag %> + + + + + + + + + +<% if Setting.openid? %> + + + + +<% end %> + + + + + + + + +
    <%= text_field_tag 'username', nil, :tabindex => '1' %>
    <%= password_field_tag 'password', nil, :tabindex => '2' %>
    <%= text_field_tag "openid_url", nil, :tabindex => '3' %>
    + <% if Setting.autologin? %> + + <% end %> +
    + <% if Setting.lost_password? %> + <%= link_to l(:label_password_lost), :controller => 'account', :action => 'lost_password' %> + <% end %> + + +
    +<%= javascript_tag "Form.Element.focus('username');" %> +<% end %> +
    +<%= call_hook :view_account_login_bottom %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e90ecb07920dae7aff5529270a744f9fa3000daa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e90ecb07920dae7aff5529270a744f9fa3000daa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class Changeset < ActiveRecord::Base + generator_for :revision, :start => '1' + generator_for :committed_on => Date.today + generator_for :repository, :method => :generate_repository + + def self.generate_repository + Repository::Subversion.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e976575ad14616deae0436ec7cdb5401b0fe26dc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e976575ad14616deae0436ec7cdb5401b0fe26dc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddParentIdToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :parent_id, :integer, :null => true, :default => nil + end + + def self.down + remove_column :enumerations, :parent_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e983e3278ec4a038212a8ec1e595dbdd03e2c9d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e983e3278ec4a038212a8ec1e595dbdd03e2c9d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +welcome_2: + id: 1 + page_id: 1 + title: Welcome to the weblog + body: Such a lovely day + version: 24 + author_id: 1 + revisor_id: 1 +welcome_1: + id: 2 + page_id: 1 + title: Welcome to the weblg + body: Such a lovely day + version: 23 + author_id: 2 + revisor_id: 2 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e98415a2db41aabe4184a766f6897f1f0ee7203f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e98415a2db41aabe4184a766f6897f1f0ee7203f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +class AddProjectsTrackersUniqueIndex < ActiveRecord::Migration + def self.up + remove_duplicates + add_index :projects_trackers, [:project_id, :tracker_id], :name => :projects_trackers_unique, :unique => true + end + + def self.down + remove_index :projects_trackers, :name => :projects_trackers_unique + end + + # Removes duplicates in projects_trackers table + def self.remove_duplicates + Project.find(:all).each do |project| + ids = project.trackers.collect(&:id) + unless ids == ids.uniq + project.trackers.clear + project.tracker_ids = ids.uniq + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e991ef0d3aa419949ea4d57b865d3c4f1fbb3aee.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e991ef0d3aa419949ea4d57b865d3c4f1fbb3aee.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRolesIssuesVisibility < ActiveRecord::Migration + def self.up + add_column :roles, :issues_visibility, :string, :limit => 30, :default => 'default', :null => false + end + + def self.down + remove_column :roles, :issues_visibility + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e9990f128dfb945f216de87f320fffbd740baf36.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e9990f128dfb945f216de87f320fffbd740baf36.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1984 @@ +#!/usr/local/bin/ruby -w + +# = faster_csv.rb -- Faster CSV Reading and Writing +# +# Created by James Edward Gray II on 2005-10-31. +# Copyright 2005 Gray Productions. All rights reserved. +# +# See FasterCSV for documentation. + +if RUBY_VERSION >= "1.9" + abort <<-VERSION_WARNING.gsub(/^\s+/, "") + Please switch to Ruby 1.9's standard CSV library. It's FasterCSV plus + support for Ruby 1.9's m17n encoding engine. + VERSION_WARNING +end + +require "forwardable" +require "English" +require "enumerator" +require "date" +require "stringio" + +# +# This class provides a complete interface to CSV files and data. It offers +# tools to enable you to read and write to and from Strings or IO objects, as +# needed. +# +# == Reading +# +# === From a File +# +# ==== A Line at a Time +# +# FasterCSV.foreach("path/to/file.csv") do |row| +# # use row here... +# end +# +# ==== All at Once +# +# arr_of_arrs = FasterCSV.read("path/to/file.csv") +# +# === From a String +# +# ==== A Line at a Time +# +# FasterCSV.parse("CSV,data,String") do |row| +# # use row here... +# end +# +# ==== All at Once +# +# arr_of_arrs = FasterCSV.parse("CSV,data,String") +# +# == Writing +# +# === To a File +# +# FasterCSV.open("path/to/file.csv", "w") do |csv| +# csv << ["row", "of", "CSV", "data"] +# csv << ["another", "row"] +# # ... +# end +# +# === To a String +# +# csv_string = FasterCSV.generate do |csv| +# csv << ["row", "of", "CSV", "data"] +# csv << ["another", "row"] +# # ... +# end +# +# == Convert a Single Line +# +# csv_string = ["CSV", "data"].to_csv # to CSV +# csv_array = "CSV,String".parse_csv # from CSV +# +# == Shortcut Interface +# +# FCSV { |csv_out| csv_out << %w{my data here} } # to $stdout +# FCSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String +# FCSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr +# +class FasterCSV + # The version of the installed library. + VERSION = "1.5.0".freeze + + # + # A FasterCSV::Row is part Array and part Hash. It retains an order for the + # fields and allows duplicates just as an Array would, but also allows you to + # access fields by name just as you could if they were in a Hash. + # + # All rows returned by FasterCSV will be constructed from this class, if + # header row processing is activated. + # + class Row + # + # Construct a new FasterCSV::Row from +headers+ and +fields+, which are + # expected to be Arrays. If one Array is shorter than the other, it will be + # padded with +nil+ objects. + # + # The optional +header_row+ parameter can be set to +true+ to indicate, via + # FasterCSV::Row.header_row?() and FasterCSV::Row.field_row?(), that this is + # a header row. Otherwise, the row is assumes to be a field row. + # + # A FasterCSV::Row object supports the following Array methods through + # delegation: + # + # * empty?() + # * length() + # * size() + # + def initialize(headers, fields, header_row = false) + @header_row = header_row + + # handle extra headers or fields + @row = if headers.size > fields.size + headers.zip(fields) + else + fields.zip(headers).map { |pair| pair.reverse } + end + end + + # Internal data format used to compare equality. + attr_reader :row + protected :row + + ### Array Delegation ### + + extend Forwardable + def_delegators :@row, :empty?, :length, :size + + # Returns +true+ if this is a header row. + def header_row? + @header_row + end + + # Returns +true+ if this is a field row. + def field_row? + not header_row? + end + + # Returns the headers of this row. + def headers + @row.map { |pair| pair.first } + end + + # + # :call-seq: + # field( header ) + # field( header, offset ) + # field( index ) + # + # This method will fetch the field value by +header+ or +index+. If a field + # is not found, +nil+ is returned. + # + # When provided, +offset+ ensures that a header match occurrs on or later + # than the +offset+ index. You can use this to find duplicate headers, + # without resorting to hard-coding exact indices. + # + def field(header_or_index, minimum_index = 0) + # locate the pair + finder = header_or_index.is_a?(Integer) ? :[] : :assoc + pair = @row[minimum_index..-1].send(finder, header_or_index) + + # return the field if we have a pair + pair.nil? ? nil : pair.last + end + alias_method :[], :field + + # + # :call-seq: + # []=( header, value ) + # []=( header, offset, value ) + # []=( index, value ) + # + # Looks up the field by the semantics described in FasterCSV::Row.field() + # and assigns the +value+. + # + # Assigning past the end of the row with an index will set all pairs between + # to [nil, nil]. Assigning to an unused header appends the new + # pair. + # + def []=(*args) + value = args.pop + + if args.first.is_a? Integer + if @row[args.first].nil? # extending past the end with index + @row[args.first] = [nil, value] + @row.map! { |pair| pair.nil? ? [nil, nil] : pair } + else # normal index assignment + @row[args.first][1] = value + end + else + index = index(*args) + if index.nil? # appending a field + self << [args.first, value] + else # normal header assignment + @row[index][1] = value + end + end + end + + # + # :call-seq: + # <<( field ) + # <<( header_and_field_array ) + # <<( header_and_field_hash ) + # + # If a two-element Array is provided, it is assumed to be a header and field + # and the pair is appended. A Hash works the same way with the key being + # the header and the value being the field. Anything else is assumed to be + # a lone field which is appended with a +nil+ header. + # + # This method returns the row for chaining. + # + def <<(arg) + if arg.is_a?(Array) and arg.size == 2 # appending a header and name + @row << arg + elsif arg.is_a?(Hash) # append header and name pairs + arg.each { |pair| @row << pair } + else # append field value + @row << [nil, arg] + end + + self # for chaining + end + + # + # A shortcut for appending multiple fields. Equivalent to: + # + # args.each { |arg| faster_csv_row << arg } + # + # This method returns the row for chaining. + # + def push(*args) + args.each { |arg| self << arg } + + self # for chaining + end + + # + # :call-seq: + # delete( header ) + # delete( header, offset ) + # delete( index ) + # + # Used to remove a pair from the row by +header+ or +index+. The pair is + # located as described in FasterCSV::Row.field(). The deleted pair is + # returned, or +nil+ if a pair could not be found. + # + def delete(header_or_index, minimum_index = 0) + if header_or_index.is_a? Integer # by index + @row.delete_at(header_or_index) + else # by header + @row.delete_at(index(header_or_index, minimum_index)) + end + end + + # + # The provided +block+ is passed a header and field for each pair in the row + # and expected to return +true+ or +false+, depending on whether the pair + # should be deleted. + # + # This method returns the row for chaining. + # + def delete_if(&block) + @row.delete_if(&block) + + self # for chaining + end + + # + # This method accepts any number of arguments which can be headers, indices, + # Ranges of either, or two-element Arrays containing a header and offset. + # Each argument will be replaced with a field lookup as described in + # FasterCSV::Row.field(). + # + # If called with no arguments, all fields are returned. + # + def fields(*headers_and_or_indices) + if headers_and_or_indices.empty? # return all fields--no arguments + @row.map { |pair| pair.last } + else # or work like values_at() + headers_and_or_indices.inject(Array.new) do |all, h_or_i| + all + if h_or_i.is_a? Range + index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin : + index(h_or_i.begin) + index_end = h_or_i.end.is_a?(Integer) ? h_or_i.end : + index(h_or_i.end) + new_range = h_or_i.exclude_end? ? (index_begin...index_end) : + (index_begin..index_end) + fields.values_at(new_range) + else + [field(*Array(h_or_i))] + end + end + end + end + alias_method :values_at, :fields + + # + # :call-seq: + # index( header ) + # index( header, offset ) + # + # This method will return the index of a field with the provided +header+. + # The +offset+ can be used to locate duplicate header names, as described in + # FasterCSV::Row.field(). + # + def index(header, minimum_index = 0) + # find the pair + index = headers[minimum_index..-1].index(header) + # return the index at the right offset, if we found one + index.nil? ? nil : index + minimum_index + end + + # Returns +true+ if +name+ is a header for this row, and +false+ otherwise. + def header?(name) + headers.include? name + end + alias_method :include?, :header? + + # + # Returns +true+ if +data+ matches a field in this row, and +false+ + # otherwise. + # + def field?(data) + fields.include? data + end + + include Enumerable + + # + # Yields each pair of the row as header and field tuples (much like + # iterating over a Hash). + # + # Support for Enumerable. + # + # This method returns the row for chaining. + # + def each(&block) + @row.each(&block) + + self # for chaining + end + + # + # Returns +true+ if this row contains the same headers and fields in the + # same order as +other+. + # + def ==(other) + @row == other.row + end + + # + # Collapses the row into a simple Hash. Be warning that this discards field + # order and clobbers duplicate fields. + # + def to_hash + # flatten just one level of the internal Array + Hash[*@row.inject(Array.new) { |ary, pair| ary.push(*pair) }] + end + + # + # Returns the row as a CSV String. Headers are not used. Equivalent to: + # + # faster_csv_row.fields.to_csv( options ) + # + def to_csv(options = Hash.new) + fields.to_csv(options) + end + alias_method :to_s, :to_csv + + # A summary of fields, by header. + def inspect + str = "#<#{self.class}" + each do |header, field| + str << " #{header.is_a?(Symbol) ? header.to_s : header.inspect}:" << + field.inspect + end + str << ">" + end + end + + # + # A FasterCSV::Table is a two-dimensional data structure for representing CSV + # documents. Tables allow you to work with the data by row or column, + # manipulate the data, and even convert the results back to CSV, if needed. + # + # All tables returned by FasterCSV will be constructed from this class, if + # header row processing is activated. + # + class Table + # + # Construct a new FasterCSV::Table from +array_of_rows+, which are expected + # to be FasterCSV::Row objects. All rows are assumed to have the same + # headers. + # + # A FasterCSV::Table object supports the following Array methods through + # delegation: + # + # * empty?() + # * length() + # * size() + # + def initialize(array_of_rows) + @table = array_of_rows + @mode = :col_or_row + end + + # The current access mode for indexing and iteration. + attr_reader :mode + + # Internal data format used to compare equality. + attr_reader :table + protected :table + + ### Array Delegation ### + + extend Forwardable + def_delegators :@table, :empty?, :length, :size + + # + # Returns a duplicate table object, in column mode. This is handy for + # chaining in a single call without changing the table mode, but be aware + # that this method can consume a fair amount of memory for bigger data sets. + # + # This method returns the duplicate table for chaining. Don't chain + # destructive methods (like []=()) this way though, since you are working + # with a duplicate. + # + def by_col + self.class.new(@table.dup).by_col! + end + + # + # Switches the mode of this table to column mode. All calls to indexing and + # iteration methods will work with columns until the mode is changed again. + # + # This method returns the table and is safe to chain. + # + def by_col! + @mode = :col + + self + end + + # + # Returns a duplicate table object, in mixed mode. This is handy for + # chaining in a single call without changing the table mode, but be aware + # that this method can consume a fair amount of memory for bigger data sets. + # + # This method returns the duplicate table for chaining. Don't chain + # destructive methods (like []=()) this way though, since you are working + # with a duplicate. + # + def by_col_or_row + self.class.new(@table.dup).by_col_or_row! + end + + # + # Switches the mode of this table to mixed mode. All calls to indexing and + # iteration methods will use the default intelligent indexing system until + # the mode is changed again. In mixed mode an index is assumed to be a row + # reference while anything else is assumed to be column access by headers. + # + # This method returns the table and is safe to chain. + # + def by_col_or_row! + @mode = :col_or_row + + self + end + + # + # Returns a duplicate table object, in row mode. This is handy for chaining + # in a single call without changing the table mode, but be aware that this + # method can consume a fair amount of memory for bigger data sets. + # + # This method returns the duplicate table for chaining. Don't chain + # destructive methods (like []=()) this way though, since you are working + # with a duplicate. + # + def by_row + self.class.new(@table.dup).by_row! + end + + # + # Switches the mode of this table to row mode. All calls to indexing and + # iteration methods will work with rows until the mode is changed again. + # + # This method returns the table and is safe to chain. + # + def by_row! + @mode = :row + + self + end + + # + # Returns the headers for the first row of this table (assumed to match all + # other rows). An empty Array is returned for empty tables. + # + def headers + if @table.empty? + Array.new + else + @table.first.headers + end + end + + # + # In the default mixed mode, this method returns rows for index access and + # columns for header access. You can force the index association by first + # calling by_col!() or by_row!(). + # + # Columns are returned as an Array of values. Altering that Array has no + # effect on the table. + # + def [](index_or_header) + if @mode == :row or # by index + (@mode == :col_or_row and index_or_header.is_a? Integer) + @table[index_or_header] + else # by header + @table.map { |row| row[index_or_header] } + end + end + + # + # In the default mixed mode, this method assigns rows for index access and + # columns for header access. You can force the index association by first + # calling by_col!() or by_row!(). + # + # Rows may be set to an Array of values (which will inherit the table's + # headers()) or a FasterCSV::Row. + # + # Columns may be set to a single value, which is copied to each row of the + # column, or an Array of values. Arrays of values are assigned to rows top + # to bottom in row major order. Excess values are ignored and if the Array + # does not have a value for each row the extra rows will receive a +nil+. + # + # Assigning to an existing column or row clobbers the data. Assigning to + # new columns creates them at the right end of the table. + # + def []=(index_or_header, value) + if @mode == :row or # by index + (@mode == :col_or_row and index_or_header.is_a? Integer) + if value.is_a? Array + @table[index_or_header] = Row.new(headers, value) + else + @table[index_or_header] = value + end + else # set column + if value.is_a? Array # multiple values + @table.each_with_index do |row, i| + if row.header_row? + row[index_or_header] = index_or_header + else + row[index_or_header] = value[i] + end + end + else # repeated value + @table.each do |row| + if row.header_row? + row[index_or_header] = index_or_header + else + row[index_or_header] = value + end + end + end + end + end + + # + # The mixed mode default is to treat a list of indices as row access, + # returning the rows indicated. Anything else is considered columnar + # access. For columnar access, the return set has an Array for each row + # with the values indicated by the headers in each Array. You can force + # column or row mode using by_col!() or by_row!(). + # + # You cannot mix column and row access. + # + def values_at(*indices_or_headers) + if @mode == :row or # by indices + ( @mode == :col_or_row and indices_or_headers.all? do |index| + index.is_a?(Integer) or + ( index.is_a?(Range) and + index.first.is_a?(Integer) and + index.last.is_a?(Integer) ) + end ) + @table.values_at(*indices_or_headers) + else # by headers + @table.map { |row| row.values_at(*indices_or_headers) } + end + end + + # + # Adds a new row to the bottom end of this table. You can provide an Array, + # which will be converted to a FasterCSV::Row (inheriting the table's + # headers()), or a FasterCSV::Row. + # + # This method returns the table for chaining. + # + def <<(row_or_array) + if row_or_array.is_a? Array # append Array + @table << Row.new(headers, row_or_array) + else # append Row + @table << row_or_array + end + + self # for chaining + end + + # + # A shortcut for appending multiple rows. Equivalent to: + # + # rows.each { |row| self << row } + # + # This method returns the table for chaining. + # + def push(*rows) + rows.each { |row| self << row } + + self # for chaining + end + + # + # Removes and returns the indicated column or row. In the default mixed + # mode indices refer to rows and everything else is assumed to be a column + # header. Use by_col!() or by_row!() to force the lookup. + # + def delete(index_or_header) + if @mode == :row or # by index + (@mode == :col_or_row and index_or_header.is_a? Integer) + @table.delete_at(index_or_header) + else # by header + @table.map { |row| row.delete(index_or_header).last } + end + end + + # + # Removes any column or row for which the block returns +true+. In the + # default mixed mode or row mode, iteration is the standard row major + # walking of rows. In column mode, interation will +yield+ two element + # tuples containing the column name and an Array of values for that column. + # + # This method returns the table for chaining. + # + def delete_if(&block) + if @mode == :row or @mode == :col_or_row # by index + @table.delete_if(&block) + else # by header + to_delete = Array.new + headers.each_with_index do |header, i| + to_delete << header if block[[header, self[header]]] + end + to_delete.map { |header| delete(header) } + end + + self # for chaining + end + + include Enumerable + + # + # In the default mixed mode or row mode, iteration is the standard row major + # walking of rows. In column mode, interation will +yield+ two element + # tuples containing the column name and an Array of values for that column. + # + # This method returns the table for chaining. + # + def each(&block) + if @mode == :col + headers.each { |header| block[[header, self[header]]] } + else + @table.each(&block) + end + + self # for chaining + end + + # Returns +true+ if all rows of this table ==() +other+'s rows. + def ==(other) + @table == other.table + end + + # + # Returns the table as an Array of Arrays. Headers will be the first row, + # then all of the field rows will follow. + # + def to_a + @table.inject([headers]) do |array, row| + if row.header_row? + array + else + array + [row.fields] + end + end + end + + # + # Returns the table as a complete CSV String. Headers will be listed first, + # then all of the field rows. + # + def to_csv(options = Hash.new) + @table.inject([headers.to_csv(options)]) do |rows, row| + if row.header_row? + rows + else + rows + [row.fields.to_csv(options)] + end + end.join + end + alias_method :to_s, :to_csv + + def inspect + "#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>" + end + end + + # The error thrown when the parser encounters illegal CSV formatting. + class MalformedCSVError < RuntimeError; end + + # + # A FieldInfo Struct contains details about a field's position in the data + # source it was read from. FasterCSV will pass this Struct to some blocks + # that make decisions based on field structure. See + # FasterCSV.convert_fields() for an example. + # + # index:: The zero-based index of the field in its row. + # line:: The line of the data source this row is from. + # header:: The header for the column, when available. + # + FieldInfo = Struct.new(:index, :line, :header) + + # A Regexp used to find and convert some common Date formats. + DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} | + \d{4}-\d{2}-\d{2} )\z /x + # A Regexp used to find and convert some common DateTime formats. + DateTimeMatcher = + / \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} | + \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2} )\z /x + # + # This Hash holds the built-in converters of FasterCSV that can be accessed by + # name. You can select Converters with FasterCSV.convert() or through the + # +options+ Hash passed to FasterCSV::new(). + # + # :integer:: Converts any field Integer() accepts. + # :float:: Converts any field Float() accepts. + # :numeric:: A combination of :integer + # and :float. + # :date:: Converts any field Date::parse() accepts. + # :date_time:: Converts any field DateTime::parse() accepts. + # :all:: All built-in converters. A combination of + # :date_time and :numeric. + # + # This Hash is intetionally left unfrozen and users should feel free to add + # values to it that can be accessed by all FasterCSV objects. + # + # To add a combo field, the value should be an Array of names. Combo fields + # can be nested with other combo fields. + # + Converters = { :integer => lambda { |f| Integer(f) rescue f }, + :float => lambda { |f| Float(f) rescue f }, + :numeric => [:integer, :float], + :date => lambda { |f| + f =~ DateMatcher ? (Date.parse(f) rescue f) : f + }, + :date_time => lambda { |f| + f =~ DateTimeMatcher ? (DateTime.parse(f) rescue f) : f + }, + :all => [:date_time, :numeric] } + + # + # This Hash holds the built-in header converters of FasterCSV that can be + # accessed by name. You can select HeaderConverters with + # FasterCSV.header_convert() or through the +options+ Hash passed to + # FasterCSV::new(). + # + # :downcase:: Calls downcase() on the header String. + # :symbol:: The header String is downcased, spaces are + # replaced with underscores, non-word characters + # are dropped, and finally to_sym() is called. + # + # This Hash is intetionally left unfrozen and users should feel free to add + # values to it that can be accessed by all FasterCSV objects. + # + # To add a combo field, the value should be an Array of names. Combo fields + # can be nested with other combo fields. + # + HeaderConverters = { + :downcase => lambda { |h| h.downcase }, + :symbol => lambda { |h| + h.downcase.tr(" ", "_").delete("^a-z0-9_").to_sym + } + } + + # + # The options used when no overrides are given by calling code. They are: + # + # :col_sep:: "," + # :row_sep:: :auto + # :quote_char:: '"' + # :converters:: +nil+ + # :unconverted_fields:: +nil+ + # :headers:: +false+ + # :return_headers:: +false+ + # :header_converters:: +nil+ + # :skip_blanks:: +false+ + # :force_quotes:: +false+ + # + DEFAULT_OPTIONS = { :col_sep => ",", + :row_sep => :auto, + :quote_char => '"', + :converters => nil, + :unconverted_fields => nil, + :headers => false, + :return_headers => false, + :header_converters => nil, + :skip_blanks => false, + :force_quotes => false }.freeze + + # + # This method will build a drop-in replacement for many of the standard CSV + # methods. It allows you to write code like: + # + # begin + # require "faster_csv" + # FasterCSV.build_csv_interface + # rescue LoadError + # require "csv" + # end + # # ... use CSV here ... + # + # This is not a complete interface with completely identical behavior. + # However, it is intended to be close enough that you won't notice the + # difference in most cases. CSV methods supported are: + # + # * foreach() + # * generate_line() + # * open() + # * parse() + # * parse_line() + # * readlines() + # + # Be warned that this interface is slower than vanilla FasterCSV due to the + # extra layer of method calls. Depending on usage, this can slow it down to + # near CSV speeds. + # + def self.build_csv_interface + Object.const_set(:CSV, Class.new).class_eval do + def self.foreach(path, rs = :auto, &block) # :nodoc: + FasterCSV.foreach(path, :row_sep => rs, &block) + end + + def self.generate_line(row, fs = ",", rs = "") # :nodoc: + FasterCSV.generate_line(row, :col_sep => fs, :row_sep => rs) + end + + def self.open(path, mode, fs = ",", rs = :auto, &block) # :nodoc: + if block and mode.include? "r" + FasterCSV.open(path, mode, :col_sep => fs, :row_sep => rs) do |csv| + csv.each(&block) + end + else + FasterCSV.open(path, mode, :col_sep => fs, :row_sep => rs, &block) + end + end + + def self.parse(str_or_readable, fs = ",", rs = :auto, &block) # :nodoc: + FasterCSV.parse(str_or_readable, :col_sep => fs, :row_sep => rs, &block) + end + + def self.parse_line(src, fs = ",", rs = :auto) # :nodoc: + FasterCSV.parse_line(src, :col_sep => fs, :row_sep => rs) + end + + def self.readlines(path, rs = :auto) # :nodoc: + FasterCSV.readlines(path, :row_sep => rs) + end + end + end + + # + # This method allows you to serialize an Array of Ruby objects to a String or + # File of CSV data. This is not as powerful as Marshal or YAML, but perhaps + # useful for spreadsheet and database interaction. + # + # Out of the box, this method is intended to work with simple data objects or + # Structs. It will serialize a list of instance variables and/or + # Struct.members(). + # + # If you need need more complicated serialization, you can control the process + # by adding methods to the class to be serialized. + # + # A class method csv_meta() is responsible for returning the first row of the + # document (as an Array). This row is considered to be a Hash of the form + # key_1,value_1,key_2,value_2,... FasterCSV::load() expects to find a class + # key with a value of the stringified class name and FasterCSV::dump() will + # create this, if you do not define this method. This method is only called + # on the first object of the Array. + # + # The next method you can provide is an instance method called csv_headers(). + # This method is expected to return the second line of the document (again as + # an Array), which is to be used to give each column a header. By default, + # FasterCSV::load() will set an instance variable if the field header starts + # with an @ character or call send() passing the header as the method name and + # the field value as an argument. This method is only called on the first + # object of the Array. + # + # Finally, you can provide an instance method called csv_dump(), which will + # be passed the headers. This should return an Array of fields that can be + # serialized for this object. This method is called once for every object in + # the Array. + # + # The +io+ parameter can be used to serialize to a File, and +options+ can be + # anything FasterCSV::new() accepts. + # + def self.dump(ary_of_objs, io = "", options = Hash.new) + obj_template = ary_of_objs.first + + csv = FasterCSV.new(io, options) + + # write meta information + begin + csv << obj_template.class.csv_meta + rescue NoMethodError + csv << [:class, obj_template.class] + end + + # write headers + begin + headers = obj_template.csv_headers + rescue NoMethodError + headers = obj_template.instance_variables.sort + if obj_template.class.ancestors.find { |cls| cls.to_s =~ /\AStruct\b/ } + headers += obj_template.members.map { |mem| "#{mem}=" }.sort + end + end + csv << headers + + # serialize each object + ary_of_objs.each do |obj| + begin + csv << obj.csv_dump(headers) + rescue NoMethodError + csv << headers.map do |var| + if var[0] == ?@ + obj.instance_variable_get(var) + else + obj[var[0..-2]] + end + end + end + end + + if io.is_a? String + csv.string + else + csv.close + end + end + + # + # :call-seq: + # filter( options = Hash.new ) { |row| ... } + # filter( input, options = Hash.new ) { |row| ... } + # filter( input, output, options = Hash.new ) { |row| ... } + # + # This method is a convenience for building Unix-like filters for CSV data. + # Each row is yielded to the provided block which can alter it as needed. + # After the block returns, the row is appended to +output+ altered or not. + # + # The +input+ and +output+ arguments can be anything FasterCSV::new() accepts + # (generally String or IO objects). If not given, they default to + # ARGF and $stdout. + # + # The +options+ parameter is also filtered down to FasterCSV::new() after some + # clever key parsing. Any key beginning with :in_ or + # :input_ will have that leading identifier stripped and will only + # be used in the +options+ Hash for the +input+ object. Keys starting with + # :out_ or :output_ affect only +output+. All other keys + # are assigned to both objects. + # + # The :output_row_sep +option+ defaults to + # $INPUT_RECORD_SEPARATOR ($/). + # + def self.filter(*args) + # parse options for input, output, or both + in_options, out_options = Hash.new, {:row_sep => $INPUT_RECORD_SEPARATOR} + if args.last.is_a? Hash + args.pop.each do |key, value| + case key.to_s + when /\Ain(?:put)?_(.+)\Z/ + in_options[$1.to_sym] = value + when /\Aout(?:put)?_(.+)\Z/ + out_options[$1.to_sym] = value + else + in_options[key] = value + out_options[key] = value + end + end + end + # build input and output wrappers + input = FasterCSV.new(args.shift || ARGF, in_options) + output = FasterCSV.new(args.shift || $stdout, out_options) + + # read, yield, write + input.each do |row| + yield row + output << row + end + end + + # + # This method is intended as the primary interface for reading CSV files. You + # pass a +path+ and any +options+ you wish to set for the read. Each row of + # file will be passed to the provided +block+ in turn. + # + # The +options+ parameter can be anything FasterCSV::new() understands. + # + def self.foreach(path, options = Hash.new, &block) + open(path, "rb", options) do |csv| + csv.each(&block) + end + end + + # + # :call-seq: + # generate( str, options = Hash.new ) { |faster_csv| ... } + # generate( options = Hash.new ) { |faster_csv| ... } + # + # This method wraps a String you provide, or an empty default String, in a + # FasterCSV object which is passed to the provided block. You can use the + # block to append CSV rows to the String and when the block exits, the + # final String will be returned. + # + # Note that a passed String *is* modfied by this method. Call dup() before + # passing if you need a new String. + # + # The +options+ parameter can be anthing FasterCSV::new() understands. + # + def self.generate(*args) + # add a default empty String, if none was given + if args.first.is_a? String + io = StringIO.new(args.shift) + io.seek(0, IO::SEEK_END) + args.unshift(io) + else + args.unshift("") + end + faster_csv = new(*args) # wrap + yield faster_csv # yield for appending + faster_csv.string # return final String + end + + # + # This method is a shortcut for converting a single row (Array) into a CSV + # String. + # + # The +options+ parameter can be anthing FasterCSV::new() understands. + # + # The :row_sep +option+ defaults to $INPUT_RECORD_SEPARATOR + # ($/) when calling this method. + # + def self.generate_line(row, options = Hash.new) + options = {:row_sep => $INPUT_RECORD_SEPARATOR}.merge(options) + (new("", options) << row).string + end + + # + # This method will return a FasterCSV instance, just like FasterCSV::new(), + # but the instance will be cached and returned for all future calls to this + # method for the same +data+ object (tested by Object#object_id()) with the + # same +options+. + # + # If a block is given, the instance is passed to the block and the return + # value becomes the return value of the block. + # + def self.instance(data = $stdout, options = Hash.new) + # create a _signature_ for this method call, data object and options + sig = [data.object_id] + + options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s }) + + # fetch or create the instance for this signature + @@instances ||= Hash.new + instance = (@@instances[sig] ||= new(data, options)) + + if block_given? + yield instance # run block, if given, returning result + else + instance # or return the instance + end + end + + # + # This method is the reading counterpart to FasterCSV::dump(). See that + # method for a detailed description of the process. + # + # You can customize loading by adding a class method called csv_load() which + # will be passed a Hash of meta information, an Array of headers, and an Array + # of fields for the object the method is expected to return. + # + # Remember that all fields will be Strings after this load. If you need + # something else, use +options+ to setup converters or provide a custom + # csv_load() implementation. + # + def self.load(io_or_str, options = Hash.new) + csv = FasterCSV.new(io_or_str, options) + + # load meta information + meta = Hash[*csv.shift] + cls = meta["class"].split("::").inject(Object) do |c, const| + c.const_get(const) + end + + # load headers + headers = csv.shift + + # unserialize each object stored in the file + results = csv.inject(Array.new) do |all, row| + begin + obj = cls.csv_load(meta, headers, row) + rescue NoMethodError + obj = cls.allocate + headers.zip(row) do |name, value| + if name[0] == ?@ + obj.instance_variable_set(name, value) + else + obj.send(name, value) + end + end + end + all << obj + end + + csv.close unless io_or_str.is_a? String + + results + end + + # + # :call-seq: + # open( filename, mode="rb", options = Hash.new ) { |faster_csv| ... } + # open( filename, mode="rb", options = Hash.new ) + # + # This method opens an IO object, and wraps that with FasterCSV. This is + # intended as the primary interface for writing a CSV file. + # + # You may pass any +args+ Ruby's open() understands followed by an optional + # Hash containing any +options+ FasterCSV::new() understands. + # + # This method works like Ruby's open() call, in that it will pass a FasterCSV + # object to a provided block and close it when the block termminates, or it + # will return the FasterCSV object when no block is provided. (*Note*: This + # is different from the standard CSV library which passes rows to the block. + # Use FasterCSV::foreach() for that behavior.) + # + # An opened FasterCSV object will delegate to many IO methods, for + # convenience. You may call: + # + # * binmode() + # * close() + # * close_read() + # * close_write() + # * closed?() + # * eof() + # * eof?() + # * fcntl() + # * fileno() + # * flush() + # * fsync() + # * ioctl() + # * isatty() + # * pid() + # * pos() + # * reopen() + # * seek() + # * stat() + # * sync() + # * sync=() + # * tell() + # * to_i() + # * to_io() + # * tty?() + # + def self.open(*args) + # find the +options+ Hash + options = if args.last.is_a? Hash then args.pop else Hash.new end + # default to a binary open mode + args << "rb" if args.size == 1 + # wrap a File opened with the remaining +args+ + csv = new(File.open(*args), options) + + # handle blocks like Ruby's open(), not like the CSV library + if block_given? + begin + yield csv + ensure + csv.close + end + else + csv + end + end + + # + # :call-seq: + # parse( str, options = Hash.new ) { |row| ... } + # parse( str, options = Hash.new ) + # + # This method can be used to easily parse CSV out of a String. You may either + # provide a +block+ which will be called with each row of the String in turn, + # or just use the returned Array of Arrays (when no +block+ is given). + # + # You pass your +str+ to read from, and an optional +options+ Hash containing + # anything FasterCSV::new() understands. + # + def self.parse(*args, &block) + csv = new(*args) + if block.nil? # slurp contents, if no block is given + begin + csv.read + ensure + csv.close + end + else # or pass each row to a provided block + csv.each(&block) + end + end + + # + # This method is a shortcut for converting a single line of a CSV String into + # a into an Array. Note that if +line+ contains multiple rows, anything + # beyond the first row is ignored. + # + # The +options+ parameter can be anthing FasterCSV::new() understands. + # + def self.parse_line(line, options = Hash.new) + new(line, options).shift + end + + # + # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the + # file and any +options+ FasterCSV::new() understands. + # + def self.read(path, options = Hash.new) + open(path, "rb", options) { |csv| csv.read } + end + + # Alias for FasterCSV::read(). + def self.readlines(*args) + read(*args) + end + + # + # A shortcut for: + # + # FasterCSV.read( path, { :headers => true, + # :converters => :numeric, + # :header_converters => :symbol }.merge(options) ) + # + def self.table(path, options = Hash.new) + read( path, { :headers => true, + :converters => :numeric, + :header_converters => :symbol }.merge(options) ) + end + + # + # This constructor will wrap either a String or IO object passed in +data+ for + # reading and/or writing. In addition to the FasterCSV instance methods, + # several IO methods are delegated. (See FasterCSV::open() for a complete + # list.) If you pass a String for +data+, you can later retrieve it (after + # writing to it, for example) with FasterCSV.string(). + # + # Note that a wrapped String will be positioned at at the beginning (for + # reading). If you want it at the end (for writing), use + # FasterCSV::generate(). If you want any other positioning, pass a preset + # StringIO object instead. + # + # You may set any reading and/or writing preferences in the +options+ Hash. + # Available options are: + # + # :col_sep:: The String placed between each field. + # :row_sep:: The String appended to the end of each + # row. This can be set to the special + # :auto setting, which requests + # that FasterCSV automatically discover + # this from the data. Auto-discovery + # reads ahead in the data looking for + # the next "\r\n", + # "\n", or "\r" + # sequence. A sequence will be selected + # even if it occurs in a quoted field, + # assuming that you would have the same + # line endings there. If none of those + # sequences is found, +data+ is + # ARGF, STDIN, + # STDOUT, or STDERR, + # or the stream is only available for + # output, the default + # $INPUT_RECORD_SEPARATOR + # ($/) is used. Obviously, + # discovery takes a little time. Set + # manually if speed is important. Also + # note that IO objects should be opened + # in binary mode on Windows if this + # feature will be used as the + # line-ending translation can cause + # problems with resetting the document + # position to where it was before the + # read ahead. + # :quote_char:: The character used to quote fields. + # This has to be a single character + # String. This is useful for + # application that incorrectly use + # ' as the quote character + # instead of the correct ". + # FasterCSV will always consider a + # double sequence this character to be + # an escaped quote. + # :encoding:: The encoding to use when parsing the + # file. Defaults to your $KDOCE + # setting. Valid values: `n’ or + # `N’ for none, `e’ or + # `E’ for EUC, `s’ or + # `S’ for SJIS, and + # `u’ or `U’ for UTF-8 + # (see Regexp.new()). + # :field_size_limit:: This is a maximum size FasterCSV will + # read ahead looking for the closing + # quote for a field. (In truth, it + # reads to the first line ending beyond + # this size.) If a quote cannot be + # found within the limit FasterCSV will + # raise a MalformedCSVError, assuming + # the data is faulty. You can use this + # limit to prevent what are effectively + # DoS attacks on the parser. However, + # this limit can cause a legitimate + # parse to fail and thus is set to + # +nil+, or off, by default. + # :converters:: An Array of names from the Converters + # Hash and/or lambdas that handle custom + # conversion. A single converter + # doesn't have to be in an Array. + # :unconverted_fields:: If set to +true+, an + # unconverted_fields() method will be + # added to all returned rows (Array or + # FasterCSV::Row) that will return the + # fields as they were before convertion. + # Note that :headers supplied + # by Array or String were not fields of + # the document and thus will have an + # empty Array attached. + # :headers:: If set to :first_row or + # +true+, the initial row of the CSV + # file will be treated as a row of + # headers. If set to an Array, the + # contents will be used as the headers. + # If set to a String, the String is run + # through a call of + # FasterCSV::parse_line() with the same + # :col_sep, :row_sep, + # and :quote_char as this + # instance to produce an Array of + # headers. This setting causes + # FasterCSV.shift() to return rows as + # FasterCSV::Row objects instead of + # Arrays and FasterCSV.read() to return + # FasterCSV::Table objects instead of + # an Array of Arrays. + # :return_headers:: When +false+, header rows are silently + # swallowed. If set to +true+, header + # rows are returned in a FasterCSV::Row + # object with identical headers and + # fields (save that the fields do not go + # through the converters). + # :write_headers:: When +true+ and :headers is + # set, a header row will be added to the + # output. + # :header_converters:: Identical in functionality to + # :converters save that the + # conversions are only made to header + # rows. + # :skip_blanks:: When set to a +true+ value, FasterCSV + # will skip over any rows with no + # content. + # :force_quotes:: When set to a +true+ value, FasterCSV + # will quote all CSV fields it creates. + # + # See FasterCSV::DEFAULT_OPTIONS for the default settings. + # + # Options cannot be overriden in the instance methods for performance reasons, + # so be sure to set what you want here. + # + def initialize(data, options = Hash.new) + # build the options for this read/write + options = DEFAULT_OPTIONS.merge(options) + + # create the IO object we will read from + @io = if data.is_a? String then StringIO.new(data) else data end + + init_separators(options) + init_parsers(options) + init_converters(options) + init_headers(options) + + unless options.empty? + raise ArgumentError, "Unknown options: #{options.keys.join(', ')}." + end + + # track our own lineno since IO gets confused about line-ends is CSV fields + @lineno = 0 + end + + # + # The line number of the last row read from this file. Fields with nested + # line-end characters will not affect this count. + # + attr_reader :lineno + + ### IO and StringIO Delegation ### + + extend Forwardable + def_delegators :@io, :binmode, :close, :close_read, :close_write, :closed?, + :eof, :eof?, :fcntl, :fileno, :flush, :fsync, :ioctl, + :isatty, :pid, :pos, :reopen, :seek, :stat, :string, + :sync, :sync=, :tell, :to_i, :to_io, :tty? + + # Rewinds the underlying IO object and resets FasterCSV's lineno() counter. + def rewind + @headers = nil + @lineno = 0 + + @io.rewind + end + + ### End Delegation ### + + # + # The primary write method for wrapped Strings and IOs, +row+ (an Array or + # FasterCSV::Row) is converted to CSV and appended to the data source. When a + # FasterCSV::Row is passed, only the row's fields() are appended to the + # output. + # + # The data source must be open for writing. + # + def <<(row) + # make sure headers have been assigned + if header_row? and [Array, String].include? @use_headers.class + parse_headers # won't read data for Array or String + self << @headers if @write_headers + end + + # Handle FasterCSV::Row objects and Hashes + row = case row + when self.class::Row then row.fields + when Hash then @headers.map { |header| row[header] } + else row + end + + @headers = row if header_row? + @lineno += 1 + + @io << row.map(&@quote).join(@col_sep) + @row_sep # quote and separate + + self # for chaining + end + alias_method :add_row, :<< + alias_method :puts, :<< + + # + # :call-seq: + # convert( name ) + # convert { |field| ... } + # convert { |field, field_info| ... } + # + # You can use this method to install a FasterCSV::Converters built-in, or + # provide a block that handles a custom conversion. + # + # If you provide a block that takes one argument, it will be passed the field + # and is expected to return the converted value or the field itself. If your + # block takes two arguments, it will also be passed a FieldInfo Struct, + # containing details about the field. Again, the block should return a + # converted field or the field itself. + # + def convert(name = nil, &converter) + add_converter(:converters, self.class::Converters, name, &converter) + end + + # + # :call-seq: + # header_convert( name ) + # header_convert { |field| ... } + # header_convert { |field, field_info| ... } + # + # Identical to FasterCSV.convert(), but for header rows. + # + # Note that this method must be called before header rows are read to have any + # effect. + # + def header_convert(name = nil, &converter) + add_converter( :header_converters, + self.class::HeaderConverters, + name, + &converter ) + end + + include Enumerable + + # + # Yields each row of the data source in turn. + # + # Support for Enumerable. + # + # The data source must be open for reading. + # + def each + while row = shift + yield row + end + end + + # + # Slurps the remaining rows and returns an Array of Arrays. + # + # The data source must be open for reading. + # + def read + rows = to_a + if @use_headers + Table.new(rows) + else + rows + end + end + alias_method :readlines, :read + + # Returns +true+ if the next row read will be a header row. + def header_row? + @use_headers and @headers.nil? + end + + # + # The primary read method for wrapped Strings and IOs, a single row is pulled + # from the data source, parsed and returned as an Array of fields (if header + # rows are not used) or a FasterCSV::Row (when header rows are used). + # + # The data source must be open for reading. + # + def shift + ######################################################################### + ### This method is purposefully kept a bit long as simple conditional ### + ### checks are faster than numerous (expensive) method calls. ### + ######################################################################### + + # handle headers not based on document content + if header_row? and @return_headers and + [Array, String].include? @use_headers.class + if @unconverted_fields + return add_unconverted_fields(parse_headers, Array.new) + else + return parse_headers + end + end + + # begin with a blank line, so we can always add to it + line = String.new + + # + # it can take multiple calls to @io.gets() to get a full line, + # because of \r and/or \n characters embedded in quoted fields + # + loop do + # add another read to the line + begin + line += @io.gets(@row_sep) + rescue + return nil + end + # copy the line so we can chop it up in parsing + parse = line.dup + parse.sub!(@parsers[:line_end], "") + + # + # I believe a blank line should be an Array.new, not + # CSV's [nil] + # + if parse.empty? + @lineno += 1 + if @skip_blanks + line = "" + next + elsif @unconverted_fields + return add_unconverted_fields(Array.new, Array.new) + elsif @use_headers + return FasterCSV::Row.new(Array.new, Array.new) + else + return Array.new + end + end + + # parse the fields with a mix of String#split and regular expressions + csv = Array.new + current_field = String.new + field_quotes = 0 + parse.split(@col_sep, -1).each do |match| + if current_field.empty? && match.count(@quote_and_newlines).zero? + csv << (match.empty? ? nil : match) + elsif(current_field.empty? ? match[0] : current_field[0]) == @quote_char[0] + current_field << match + field_quotes += match.count(@quote_char) + if field_quotes % 2 == 0 + in_quotes = current_field[@parsers[:quoted_field], 1] + raise MalformedCSVError unless in_quotes + current_field = in_quotes + current_field.gsub!(@quote_char * 2, @quote_char) # unescape contents + csv << current_field + current_field = String.new + field_quotes = 0 + else # we found a quoted field that spans multiple lines + current_field << @col_sep + end + elsif match.count("\r\n").zero? + raise MalformedCSVError, "Illegal quoting on line #{lineno + 1}." + else + raise MalformedCSVError, "Unquoted fields do not allow " + + "\\r or \\n (line #{lineno + 1})." + end + end + + # if parse is empty?(), we found all the fields on the line... + if field_quotes % 2 == 0 + @lineno += 1 + + # save fields unconverted fields, if needed... + unconverted = csv.dup if @unconverted_fields + + # convert fields, if needed... + csv = convert_fields(csv) unless @use_headers or @converters.empty? + # parse out header rows and handle FasterCSV::Row conversions... + csv = parse_headers(csv) if @use_headers + + # inject unconverted fields and accessor, if requested... + if @unconverted_fields and not csv.respond_to? :unconverted_fields + add_unconverted_fields(csv, unconverted) + end + + # return the results + break csv + end + # if we're not empty?() but at eof?(), a quoted field wasn't closed... + if @io.eof? + raise MalformedCSVError, "Unclosed quoted field on line #{lineno + 1}." + elsif @field_size_limit and current_field.size >= @field_size_limit + raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}." + end + # otherwise, we need to loop and pull some more data to complete the row + end + end + alias_method :gets, :shift + alias_method :readline, :shift + + # Returns a simplified description of the key FasterCSV attributes. + def inspect + str = "<##{self.class} io_type:" + # show type of wrapped IO + if @io == $stdout then str << "$stdout" + elsif @io == $stdin then str << "$stdin" + elsif @io == $stderr then str << "$stderr" + else str << @io.class.to_s + end + # show IO.path(), if available + if @io.respond_to?(:path) and (p = @io.path) + str << " io_path:#{p.inspect}" + end + # show other attributes + %w[ lineno col_sep row_sep + quote_char skip_blanks encoding ].each do |attr_name| + if a = instance_variable_get("@#{attr_name}") + str << " #{attr_name}:#{a.inspect}" + end + end + if @use_headers + str << " headers:#{(@headers || true).inspect}" + end + str << ">" + end + + private + + # + # Stores the indicated separators for later use. + # + # If auto-discovery was requested for @row_sep, this method will read + # ahead in the @io and try to find one. +ARGF+, +STDIN+, +STDOUT+, + # +STDERR+ and any stream open for output only with a default + # @row_sep of $INPUT_RECORD_SEPARATOR ($/). + # + # This method also establishes the quoting rules used for CSV output. + # + def init_separators(options) + # store the selected separators + @col_sep = options.delete(:col_sep) + @row_sep = options.delete(:row_sep) + @quote_char = options.delete(:quote_char) + @quote_and_newlines = "#{@quote_char}\r\n" + + if @quote_char.length != 1 + raise ArgumentError, ":quote_char has to be a single character String" + end + + # automatically discover row separator when requested + if @row_sep == :auto + if [ARGF, STDIN, STDOUT, STDERR].include?(@io) or + (defined?(Zlib) and @io.class == Zlib::GzipWriter) + @row_sep = $INPUT_RECORD_SEPARATOR + else + begin + saved_pos = @io.pos # remember where we were + while @row_sep == :auto + # + # if we run out of data, it's probably a single line + # (use a sensible default) + # + if @io.eof? + @row_sep = $INPUT_RECORD_SEPARATOR + break + end + + # read ahead a bit + sample = @io.read(1024) + sample += @io.read(1) if sample[-1..-1] == "\r" and not @io.eof? + + # try to find a standard separator + if sample =~ /\r\n?|\n/ + @row_sep = $& + break + end + end + # tricky seek() clone to work around GzipReader's lack of seek() + @io.rewind + # reset back to the remembered position + while saved_pos > 1024 # avoid loading a lot of data into memory + @io.read(1024) + saved_pos -= 1024 + end + @io.read(saved_pos) if saved_pos.nonzero? + rescue IOError # stream not opened for reading + @row_sep = $INPUT_RECORD_SEPARATOR + end + end + end + + # establish quoting rules + do_quote = lambda do |field| + @quote_char + + String(field).gsub(@quote_char, @quote_char * 2) + + @quote_char + end + @quote = if options.delete(:force_quotes) + do_quote + else + lambda do |field| + if field.nil? # represent +nil+ fields as empty unquoted fields + "" + else + field = String(field) # Stringify fields + # represent empty fields as empty quoted fields + if field.empty? or + field.count("\r\n#{@col_sep}#{@quote_char}").nonzero? + do_quote.call(field) + else + field # unquoted field + end + end + end + end + end + + # Pre-compiles parsers and stores them by name for access during reads. + def init_parsers(options) + # store the parser behaviors + @skip_blanks = options.delete(:skip_blanks) + @encoding = options.delete(:encoding) # nil will use $KCODE + @field_size_limit = options.delete(:field_size_limit) + + # prebuild Regexps for faster parsing + esc_col_sep = Regexp.escape(@col_sep) + esc_row_sep = Regexp.escape(@row_sep) + esc_quote = Regexp.escape(@quote_char) + @parsers = { + :any_field => Regexp.new( "[^#{esc_col_sep}]+", + Regexp::MULTILINE, + @encoding ), + :quoted_field => Regexp.new( "^#{esc_quote}(.*)#{esc_quote}$", + Regexp::MULTILINE, + @encoding ), + # safer than chomp!() + :line_end => Regexp.new("#{esc_row_sep}\\z", nil, @encoding) + } + end + + # + # Loads any converters requested during construction. + # + # If +field_name+ is set :converters (the default) field converters + # are set. When +field_name+ is :header_converters header converters + # are added instead. + # + # The :unconverted_fields option is also actived for + # :converters calls, if requested. + # + def init_converters(options, field_name = :converters) + if field_name == :converters + @unconverted_fields = options.delete(:unconverted_fields) + end + + instance_variable_set("@#{field_name}", Array.new) + + # find the correct method to add the coverters + convert = method(field_name.to_s.sub(/ers\Z/, "")) + + # load converters + unless options[field_name].nil? + # allow a single converter not wrapped in an Array + unless options[field_name].is_a? Array + options[field_name] = [options[field_name]] + end + # load each converter... + options[field_name].each do |converter| + if converter.is_a? Proc # custom code block + convert.call(&converter) + else # by name + convert.call(converter) + end + end + end + + options.delete(field_name) + end + + # Stores header row settings and loads header converters, if needed. + def init_headers(options) + @use_headers = options.delete(:headers) + @return_headers = options.delete(:return_headers) + @write_headers = options.delete(:write_headers) + + # headers must be delayed until shift(), in case they need a row of content + @headers = nil + + init_converters(options, :header_converters) + end + + # + # The actual work method for adding converters, used by both + # FasterCSV.convert() and FasterCSV.header_convert(). + # + # This method requires the +var_name+ of the instance variable to place the + # converters in, the +const+ Hash to lookup named converters in, and the + # normal parameters of the FasterCSV.convert() and FasterCSV.header_convert() + # methods. + # + def add_converter(var_name, const, name = nil, &converter) + if name.nil? # custom converter + instance_variable_get("@#{var_name}") << converter + else # named converter + combo = const[name] + case combo + when Array # combo converter + combo.each do |converter_name| + add_converter(var_name, const, converter_name) + end + else # individual named converter + instance_variable_get("@#{var_name}") << combo + end + end + end + + # + # Processes +fields+ with @converters, or @header_converters + # if +headers+ is passed as +true+, returning the converted field set. Any + # converter that changes the field into something other than a String halts + # the pipeline of conversion for that field. This is primarily an efficiency + # shortcut. + # + def convert_fields(fields, headers = false) + # see if we are converting headers or fields + converters = headers ? @header_converters : @converters + + fields.enum_for(:each_with_index).map do |field, index| # map_with_index + converters.each do |converter| + field = if converter.arity == 1 # straight field converter + converter[field] + else # FieldInfo converter + header = @use_headers && !headers ? @headers[index] : nil + converter[field, FieldInfo.new(index, lineno, header)] + end + break unless field.is_a? String # short-curcuit pipeline for speed + end + field # return final state of each field, converted or original + end + end + + # + # This methods is used to turn a finished +row+ into a FasterCSV::Row. Header + # rows are also dealt with here, either by returning a FasterCSV::Row with + # identical headers and fields (save that the fields do not go through the + # converters) or by reading past them to return a field row. Headers are also + # saved in @headers for use in future rows. + # + # When +nil+, +row+ is assumed to be a header row not based on an actual row + # of the stream. + # + def parse_headers(row = nil) + if @headers.nil? # header row + @headers = case @use_headers # save headers + # Array of headers + when Array then @use_headers + # CSV header String + when String + self.class.parse_line( @use_headers, + :col_sep => @col_sep, + :row_sep => @row_sep, + :quote_char => @quote_char ) + # first row is headers + else row + end + + # prepare converted and unconverted copies + row = @headers if row.nil? + @headers = convert_fields(@headers, true) + + if @return_headers # return headers + return FasterCSV::Row.new(@headers, row, true) + elsif not [Array, String].include? @use_headers.class # skip to field row + return shift + end + end + + FasterCSV::Row.new(@headers, convert_fields(row)) # field row + end + + # + # Thiw methods injects an instance variable unconverted_fields into + # +row+ and an accessor method for it called unconverted_fields(). The + # variable is set to the contents of +fields+. + # + def add_unconverted_fields(row, fields) + class << row + attr_reader :unconverted_fields + end + row.instance_eval { @unconverted_fields = fields } + row + end +end + +# Another name for FasterCSV. +FCSV = FasterCSV + +# Another name for FasterCSV::instance(). +def FasterCSV(*args, &block) + FasterCSV.instance(*args, &block) +end + +# Another name for FCSV::instance(). +def FCSV(*args, &block) + FCSV.instance(*args, &block) +end + +class Array + # Equivalent to FasterCSV::generate_line(self, options). + def to_csv(options = Hash.new) + FasterCSV.generate_line(self, options) + end +end + +class String + # Equivalent to FasterCSV::parse_line(self, options). + def parse_csv(options = Hash.new) + FasterCSV.parse_line(self, options) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e9c50cfa0f09eef5fbfc8e1f3183fe79d6fe1c0b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e9c50cfa0f09eef5fbfc8e1f3183fe79d6fe1c0b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +top_level: + id: 1 + name: Top Level + lft: 1 + rgt: 10 +child_1: + id: 2 + name: Child 1 + parent_id: 1 + lft: 2 + rgt: 3 +child_2: + id: 3 + name: Child 2 + parent_id: 1 + lft: 4 + rgt: 7 +child_2_1: + id: 4 + name: Child 2.1 + parent_id: 3 + lft: 5 + rgt: 6 +child_3: + id: 5 + name: Child 3 + parent_id: 1 + lft: 8 + rgt: 9 +top_level_2: + id: 6 + name: Top Level 2 + lft: 11 + rgt: 12 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/e9/e9fb13e0f0d6d422082491d6e14bdb1d021bb202.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/e9/e9fb13e0f0d6d422082491d6e14bdb1d021bb202.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,824 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class QueryTest < ActiveSupport::TestCase + fixtures :projects, :enabled_modules, :users, :members, + :member_roles, :roles, :trackers, :issue_statuses, + :issue_categories, :enumerations, :issues, + :watchers, :custom_fields, :custom_values, :versions, + :queries, + :projects_trackers + + def test_custom_fields_for_all_projects_should_be_available_in_global_queries + query = Query.new(:project => nil, :name => '_') + assert query.available_filters.has_key?('cf_1') + assert !query.available_filters.has_key?('cf_3') + end + + def test_system_shared_versions_should_be_available_in_global_queries + Version.find(2).update_attribute :sharing, 'system' + query = Query.new(:project => nil, :name => '_') + assert query.available_filters.has_key?('fixed_version_id') + assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'} + end + + def test_project_filter_in_global_queries + query = Query.new(:project => nil, :name => '_') + project_filter = query.available_filters["project_id"] + assert_not_nil project_filter + project_ids = project_filter[:values].map{|p| p[1]} + assert project_ids.include?("1") #public project + assert !project_ids.include?("2") #private project user cannot see + end + + def find_issues_with_query(query) + Issue.find :all, + :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :conditions => query.statement + end + + def assert_find_issues_with_query_is_successful(query) + assert_nothing_raised do + find_issues_with_query(query) + end + end + + def assert_query_statement_includes(query, condition) + assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}" + end + + def assert_query_result(expected, query) + assert_nothing_raised do + assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort + assert_equal expected.size, query.issue_count + end + end + + def test_query_should_allow_shared_versions_for_a_project_query + subproject_version = Version.find(4) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s]) + + assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')") + end + + def test_query_with_multiple_custom_fields + query = Query.find(1) + assert query.valid? + assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')") + issues = find_issues_with_query(query) + assert_equal 1, issues.length + assert_equal Issue.find(3), issues.first + end + + def test_operator_none + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('fixed_version_id', '!*', ['']) + query.add_filter('cf_1', '!*', ['']) + assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL") + assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''") + find_issues_with_query(query) + end + + def test_operator_none_for_integer + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('estimated_hours', '!*', ['']) + issues = find_issues_with_query(query) + assert !issues.empty? + assert issues.all? {|i| !i.estimated_hours} + end + + def test_operator_none_for_date + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('start_date', '!*', ['']) + issues = find_issues_with_query(query) + assert !issues.empty? + assert issues.all? {|i| i.start_date.nil?} + end + + def test_operator_all + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('fixed_version_id', '*', ['']) + query.add_filter('cf_1', '*', ['']) + assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL") + assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''") + find_issues_with_query(query) + end + + def test_operator_all_for_date + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('start_date', '*', ['']) + issues = find_issues_with_query(query) + assert !issues.empty? + assert issues.all? {|i| i.start_date.present?} + end + + def test_numeric_filter_should_not_accept_non_numeric_values + query = Query.new(:name => '_') + query.add_filter('estimated_hours', '=', ['a']) + + assert query.has_filter?('estimated_hours') + assert !query.valid? + end + + def test_operator_is_on_float + Issue.update_all("estimated_hours = 171.2", "id=2") + + query = Query.new(:name => '_') + query.add_filter('estimated_hours', '=', ['171.20']) + issues = find_issues_with_query(query) + assert_equal 1, issues.size + assert_equal 2, issues.first.id + end + + def test_operator_greater_than + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('done_ratio', '>=', ['40']) + assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0") + find_issues_with_query(query) + end + + def test_operator_greater_than_a_float + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('estimated_hours', '>=', ['40.5']) + assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5") + find_issues_with_query(query) + end + + def test_operator_greater_than_on_custom_field + f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter("cf_#{f.id}", '>=', ['40']) + assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) >= 40.0") + find_issues_with_query(query) + end + + def test_operator_lesser_than + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('done_ratio', '<=', ['30']) + assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0") + find_issues_with_query(query) + end + + def test_operator_lesser_than_on_custom_field + f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter("cf_#{f.id}", '<=', ['30']) + assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0") + find_issues_with_query(query) + end + + def test_operator_between + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('done_ratio', '><', ['30', '40']) + assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement + find_issues_with_query(query) + end + + def test_operator_between_on_custom_field + f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter("cf_#{f.id}", '><', ['30', '40']) + assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement + find_issues_with_query(query) + end + + def test_date_filter_should_not_accept_non_date_values + query = Query.new(:name => '_') + query.add_filter('created_on', '=', ['a']) + + assert query.has_filter?('created_on') + assert !query.valid? + end + + def test_date_filter_should_not_accept_invalid_date_values + query = Query.new(:name => '_') + query.add_filter('created_on', '=', ['2011-01-34']) + + assert query.has_filter?('created_on') + assert !query.valid? + end + + def test_relative_date_filter_should_not_accept_non_integer_values + query = Query.new(:name => '_') + query.add_filter('created_on', '>t-', ['a']) + + assert query.has_filter?('created_on') + assert !query.valid? + end + + def test_operator_date_equals + query = Query.new(:name => '_') + query.add_filter('due_date', '=', ['2011-07-10']) + assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement + find_issues_with_query(query) + end + + def test_operator_date_lesser_than + query = Query.new(:name => '_') + query.add_filter('due_date', '<=', ['2011-07-10']) + assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement + find_issues_with_query(query) + end + + def test_operator_date_greater_than + query = Query.new(:name => '_') + query.add_filter('due_date', '>=', ['2011-07-10']) + assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement + find_issues_with_query(query) + end + + def test_operator_date_between + query = Query.new(:name => '_') + query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10']) + assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement + find_issues_with_query(query) + end + + def test_operator_in_more_than + Issue.find(7).update_attribute(:due_date, (Date.today + 15)) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('due_date', '>t+', ['15']) + issues = find_issues_with_query(query) + assert !issues.empty? + issues.each {|issue| assert(issue.due_date >= (Date.today + 15))} + end + + def test_operator_in_less_than + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('due_date', '= Date.today && issue.due_date <= (Date.today + 15))} + end + + def test_operator_less_than_ago + Issue.find(7).update_attribute(:due_date, (Date.today - 3)) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('due_date', '>t-', ['3']) + issues = find_issues_with_query(query) + assert !issues.empty? + issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)} + end + + def test_operator_more_than_ago + Issue.find(7).update_attribute(:due_date, (Date.today - 10)) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('due_date', ' Project.find(1), :name => '_') + query.add_filter('due_date', 'w', ['']) + assert query.statement.match(/issues\.due_date > '2011-04-24 23:59:59(\.9+)?' AND issues\.due_date <= '2011-05-01 23:59:59(\.9+)?/), "range not found in #{query.statement}" + I18n.locale = :en + end + + def test_range_for_this_week_with_week_starting_on_sunday + I18n.locale = :en + assert_equal '7', I18n.t(:general_first_day_of_week) + + Date.stubs(:today).returns(Date.parse('2011-04-29')) + + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('due_date', 'w', ['']) + assert query.statement.match(/issues\.due_date > '2011-04-23 23:59:59(\.9+)?' AND issues\.due_date <= '2011-04-30 23:59:59(\.9+)?/), "range not found in #{query.statement}" + end + + def test_operator_does_not_contains + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('subject', '!~', ['uNable']) + assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'") + find_issues_with_query(query) + end + + def test_filter_assigned_to_me + user = User.find(2) + group = Group.find(10) + User.current = user + i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user) + i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group) + i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11)) + group.users << user + + query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}}) + result = query.issues + assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id) + + assert result.include?(i1) + assert result.include?(i2) + assert !result.include?(i3) + end + + def test_filter_watched_issues + User.current = User.find(1) + query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}}) + result = find_issues_with_query(query) + assert_not_nil result + assert !result.empty? + assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id) + User.current = nil + end + + def test_filter_unwatched_issues + User.current = User.find(1) + query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}}) + result = find_issues_with_query(query) + assert_not_nil result + assert !result.empty? + assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size) + User.current = nil + end + + def test_statement_should_be_nil_with_no_filters + q = Query.new(:name => '_') + q.filters = {} + + assert q.valid? + assert_nil q.statement + end + + def test_default_columns + q = Query.new + assert !q.columns.empty? + end + + def test_set_column_names + q = Query.new + q.column_names = ['tracker', :subject, '', 'unknonw_column'] + assert_equal [:tracker, :subject], q.columns.collect {|c| c.name} + c = q.columns.first + assert q.has_column?(c) + end + + def test_groupable_columns_should_include_custom_fields + q = Query.new + assert q.groupable_columns.detect {|c| c.is_a? QueryCustomFieldColumn} + end + + def test_grouped_with_valid_column + q = Query.new(:group_by => 'status') + assert q.grouped? + assert_not_nil q.group_by_column + assert_equal :status, q.group_by_column.name + assert_not_nil q.group_by_statement + assert_equal 'status', q.group_by_statement + end + + def test_grouped_with_invalid_column + q = Query.new(:group_by => 'foo') + assert !q.grouped? + assert_nil q.group_by_column + assert_nil q.group_by_statement + end + + def test_sortable_columns_should_sort_assignees_according_to_user_format_setting + with_settings :user_format => 'lastname_coma_firstname' do + q = Query.new + assert q.sortable_columns.has_key?('assigned_to') + assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to'] + end + end + + def test_sortable_columns_should_sort_authors_according_to_user_format_setting + with_settings :user_format => 'lastname_coma_firstname' do + q = Query.new + assert q.sortable_columns.has_key?('author') + assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author'] + end + end + + def test_default_sort + q = Query.new + assert_equal [], q.sort_criteria + end + + def test_set_sort_criteria_with_hash + q = Query.new + q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']} + assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria + end + + def test_set_sort_criteria_with_array + q = Query.new + q.sort_criteria = [['priority', 'desc'], 'tracker'] + assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria + end + + def test_create_query_with_sort + q = Query.new(:name => 'Sorted') + q.sort_criteria = [['priority', 'desc'], 'tracker'] + assert q.save + q.reload + assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria + end + + def test_sort_by_string_custom_field_asc + q = Query.new + c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' } + assert c + assert c.sortable + issues = Issue.find :all, + :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :conditions => q.statement, + :order => "#{c.sortable} ASC" + values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s} + assert !values.empty? + assert_equal values.sort, values + end + + def test_sort_by_string_custom_field_desc + q = Query.new + c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' } + assert c + assert c.sortable + issues = Issue.find :all, + :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :conditions => q.statement, + :order => "#{c.sortable} DESC" + values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s} + assert !values.empty? + assert_equal values.sort.reverse, values + end + + def test_sort_by_float_custom_field_asc + q = Query.new + c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' } + assert c + assert c.sortable + issues = Issue.find :all, + :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :conditions => q.statement, + :order => "#{c.sortable} ASC" + values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact + assert !values.empty? + assert_equal values.sort, values + end + + def test_invalid_query_should_raise_query_statement_invalid_error + q = Query.new + assert_raise Query::StatementInvalid do + q.issues(:conditions => "foo = 1") + end + end + + def test_issue_count + q = Query.new(:name => '_') + issue_count = q.issue_count + assert_equal q.issues.size, issue_count + end + + def test_issue_count_with_archived_issues + p = Project.generate!( :status => Project::STATUS_ARCHIVED ) + i = Issue.generate!( :project => p, :tracker => p.trackers.first ) + assert !i.visible? + + test_issue_count + end + + def test_issue_count_by_association_group + q = Query.new(:name => '_', :group_by => 'assigned_to') + count_by_group = q.issue_count_by_group + assert_kind_of Hash, count_by_group + assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort + assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq + assert count_by_group.has_key?(User.find(3)) + end + + def test_issue_count_by_list_custom_field_group + q = Query.new(:name => '_', :group_by => 'cf_1') + count_by_group = q.issue_count_by_group + assert_kind_of Hash, count_by_group + assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort + assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq + assert count_by_group.has_key?('MySQL') + end + + def test_issue_count_by_date_custom_field_group + q = Query.new(:name => '_', :group_by => 'cf_8') + count_by_group = q.issue_count_by_group + assert_kind_of Hash, count_by_group + assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort + assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq + end + + def test_label_for + q = Query.new + assert_equal 'assigned_to', q.label_for('assigned_to_id') + end + + def test_editable_by + admin = User.find(1) + manager = User.find(2) + developer = User.find(3) + + # Public query on project 1 + q = Query.find(1) + assert q.editable_by?(admin) + assert q.editable_by?(manager) + assert !q.editable_by?(developer) + + # Private query on project 1 + q = Query.find(2) + assert q.editable_by?(admin) + assert !q.editable_by?(manager) + assert q.editable_by?(developer) + + # Private query for all projects + q = Query.find(3) + assert q.editable_by?(admin) + assert !q.editable_by?(manager) + assert q.editable_by?(developer) + + # Public query for all projects + q = Query.find(4) + assert q.editable_by?(admin) + assert !q.editable_by?(manager) + assert !q.editable_by?(developer) + end + + def test_visible_scope + query_ids = Query.visible(User.anonymous).map(&:id) + + assert query_ids.include?(1), 'public query on public project was not visible' + assert query_ids.include?(4), 'public query for all projects was not visible' + assert !query_ids.include?(2), 'private query on public project was visible' + assert !query_ids.include?(3), 'private query for all projects was visible' + assert !query_ids.include?(7), 'public query on private project was visible' + end + + context "#available_filters" do + setup do + @query = Query.new(:name => "_") + end + + should "include users of visible projects in cross-project view" do + users = @query.available_filters["assigned_to_id"] + assert_not_nil users + assert users[:values].map{|u|u[1]}.include?("3") + end + + should "include visible projects in cross-project view" do + projects = @query.available_filters["project_id"] + assert_not_nil projects + assert projects[:values].map{|u|u[1]}.include?("1") + end + + context "'member_of_group' filter" do + should "be present" do + assert @query.available_filters.keys.include?("member_of_group") + end + + should "be an optional list" do + assert_equal :list_optional, @query.available_filters["member_of_group"][:type] + end + + should "have a list of the groups as values" do + Group.destroy_all # No fixtures + group1 = Group.generate!.reload + group2 = Group.generate!.reload + + expected_group_list = [ + [group1.name, group1.id.to_s], + [group2.name, group2.id.to_s] + ] + assert_equal expected_group_list.sort, @query.available_filters["member_of_group"][:values].sort + end + + end + + context "'assigned_to_role' filter" do + should "be present" do + assert @query.available_filters.keys.include?("assigned_to_role") + end + + should "be an optional list" do + assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type] + end + + should "have a list of the Roles as values" do + assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1']) + assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2']) + assert @query.available_filters["assigned_to_role"][:values].include?(['Reporter','3']) + end + + should "not include the built in Roles as values" do + assert ! @query.available_filters["assigned_to_role"][:values].include?(['Non member','4']) + assert ! @query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5']) + end + + end + + end + + context "#statement" do + context "with 'member_of_group' filter" do + setup do + Group.destroy_all # No fixtures + @user_in_group = User.generate! + @second_user_in_group = User.generate! + @user_in_group2 = User.generate! + @user_not_in_group = User.generate! + + @group = Group.generate!.reload + @group.users << @user_in_group + @group.users << @second_user_in_group + + @group2 = Group.generate!.reload + @group2.users << @user_in_group2 + + end + + should "search assigned to for users in the group" do + @query = Query.new(:name => '_') + @query.add_filter('member_of_group', '=', [@group.id.to_s]) + + assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')" + assert_find_issues_with_query_is_successful @query + end + + should "search not assigned to any group member (none)" do + @query = Query.new(:name => '_') + @query.add_filter('member_of_group', '!*', ['']) + + # Users not in a group + assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')" + assert_find_issues_with_query_is_successful @query + end + + should "search assigned to any group member (all)" do + @query = Query.new(:name => '_') + @query.add_filter('member_of_group', '*', ['']) + + # Only users in a group + assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')" + assert_find_issues_with_query_is_successful @query + end + + should "return an empty set with = empty group" do + @empty_group = Group.generate! + @query = Query.new(:name => '_') + @query.add_filter('member_of_group', '=', [@empty_group.id.to_s]) + + assert_equal [], find_issues_with_query(@query) + end + + should "return issues with ! empty group" do + @empty_group = Group.generate! + @query = Query.new(:name => '_') + @query.add_filter('member_of_group', '!', [@empty_group.id.to_s]) + + assert_find_issues_with_query_is_successful @query + end + end + + context "with 'assigned_to_role' filter" do + setup do + @manager_role = Role.find_by_name('Manager') + @developer_role = Role.find_by_name('Developer') + + @project = Project.generate! + @manager = User.generate! + @developer = User.generate! + @boss = User.generate! + @guest = User.generate! + User.add_to_project(@manager, @project, @manager_role) + User.add_to_project(@developer, @project, @developer_role) + User.add_to_project(@boss, @project, [@manager_role, @developer_role]) + + @issue1 = Issue.generate_for_project!(@project, :assigned_to_id => @manager.id) + @issue2 = Issue.generate_for_project!(@project, :assigned_to_id => @developer.id) + @issue3 = Issue.generate_for_project!(@project, :assigned_to_id => @boss.id) + @issue4 = Issue.generate_for_project!(@project, :assigned_to_id => @guest.id) + @issue5 = Issue.generate_for_project!(@project) + end + + should "search assigned to for users with the Role" do + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s]) + + assert_query_result [@issue1, @issue3], @query + end + + should "search assigned to for users with the Role on the issue project" do + other_project = Project.generate! + User.add_to_project(@developer, other_project, @manager_role) + + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s]) + + assert_query_result [@issue1, @issue3], @query + end + + should "return an empty set with empty role" do + @empty_role = Role.generate! + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s]) + + assert_query_result [], @query + end + + should "search assigned to for users without the Role" do + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s]) + + assert_query_result [@issue2, @issue4, @issue5], @query + end + + should "search assigned to for users not assigned to any Role (none)" do + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '!*', ['']) + + assert_query_result [@issue4, @issue5], @query + end + + should "search assigned to for users assigned to any Role (all)" do + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '*', ['']) + + assert_query_result [@issue1, @issue2, @issue3], @query + end + + should "return issues with ! empty role" do + @empty_role = Role.generate! + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s]) + + assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query + end + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ea/ea02b59fa79aca505f8f4ffb6c006259f701162a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ea/ea02b59fa79aca505f8f4ffb6c006259f701162a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,630 @@ +2003-10-08 Primoz Peterlin + + # FreeMonoOblique.sfd, FreeSerifBoldItalic.sfd, + FreeSerifItalic.sfd - applied Josef Segur's corrections from + Oct. 5. + +2003-10-02 Primoz Peterlin + + # sfd/FreeSerif.sfd - Abbas Izad's contributed Arabic/Farsi + characters added. + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansBoldOblique.sfd, sfd/FreeSerif.sfd, + sfd/FreeSerifItalic.sfd, sfd/FreeSerifBold.sfd, + sfd/FreeSerifBoldItalic.sfd - Combining characters (U+0300 - + U+036F) moved left, so that they have negative horizontal values + and zero advance width. + +2003-09-15 Primoz Peterlin + + # sfd/FreeSerifBold.sfd, sfd/FreeSerifItalic.sfd - Started working + on super- and subscripts. + +2003-09-12 Primoz Peterlin + + # sfd/FreeSans.sfd, sfd/FreeSerif.sfd - Added some missing + Hiragana and Katakana characters. + + # sfd/FreeSansBold.sfd - Cleared background characters in Latin + Extended-A. Added some automatically constructed characters in + Latin Extended-B. Started with superscripts and subscripts. + + # sfd/FreeSans.sfd - Subscript numerals (U+2080-U+2089) completed. + +2003-05-19 Primoz Peterlin + + # sfd/FreeSerif.sfd - Thai characters po pla and bo baimai + swapped; Thai character fongman corrected; all courtesy Theppitak + Karoonboonyanan. + +2003-05-17 Panayotis Katsaloulis + + # sfd/FreeSerif.sfd, sfd/FreeSerifItalic.sfd, + sfd/FreeSerifBold.sfd, sfd/FreeSerifBoldItalic.sfd - Full support + of all ancient greek glyphs + +2003-05-15 Primoz Peterlin + + # tools/KerningNumerals.pl - A Perl script for moving kerning + information from ASCII numerals (U+0030...) to characters in the + Adobe corporate use area (U+F6xx). + + # sfd/FreeSansBold.sfd, sfd/FreeSansOblique.sfd, + sfd/FreeSansBoldOblique.sfd - Created kerned numerals in the Adobe + corporate use area (U+F6xx) and moved kerning information from + ASCII numerals to the kerned numerals. + +2003-05-14 Primoz Peterlin + + # sfd/FreeSans.sfd - First approximation of super- and subscript + numerals and vulgar fractions. + + # sfd/FreeSerif.sfd - Super- and subscript numerals complete, + vulgar fractions completed and redone as references rather than + outlines. + +2003-05-12 Primoz Peterlin + + # sfd/FreeSerif.sfd - Clean-up of the Cyrillic letters added on + March 27; super- and subscripts, vulgar fractions. + +2003-05-09 Primoz Peterlin + + # sfd/FreeMonoBold.sfd - Added a couple of characters to + the Latin Extended-B area and the IPA extensions area. + +2003-05-08 Primoz Peterlin + + # sfd/FreeSerifBoldItalic.sfd - Added a couple of characters to + the Latin Extended-B area. + + # sfd/FreeSerif.sfd, sfd/FreeSerifItalic.sfd, + sfd/FreeSerifBold.sfd, sfd/FreeSerifBoldItalic.sfd - ASCII + numerals now monospaced; kerned numerals moved to Adobe corporate + use area + (U+F6xx). + +2003-05-07 Primoz Peterlin + + # sfd/FreeSerif.sfd - Roman numerals now more complete. + + # sfd/FreeSansOblique.sfd, sfd/FreeSansBoldOblique.sfd - Accented + characters added in the Latin Extended-B area. + + # sfd/FreeSans.sfd - Greek accents added in the Greek Extended + area, characters added in the Latin Extended-B area, Roman + numerals added. + + # sfd/FreeMonoOblique.sfd - Kerning pairs removed (what were they + doing in a monospaced font, anyway?). + + # sfd/FreeMonoBoldOblique.sfd - Additions in Latin Extended-B and + Basic Greek. + + # sfd/FreeMono.sfd, sfd/FreeMonoBold.sfd, sfd/FreeMonoOblique.sfd, + sfd/FreeMonoBoldOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansBold.sfd, sfd/FreeSansOblique.sfd, + sfd/FreeSansBoldOblique.sfd - Major cleanup (fixed widths, open + paths, path directions (clockwise/counter-clockwise), points + rounded to integer values; outlines simplified etc.) + +2003-05-06 Primoz Peterlin + + # tools/OS2UnicodeRange - A simple script to display OS/2 Unicode + range table in TrueType fonts. + + # sfd/FreeSans.sfd, sfd/FreeSansBold.sfd - ASCII numerals now + monospaced; kerned numerals moved to Adobe corporate use area + (U+F6xx). FreeSans is done, FreeSansBold half-way. + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansBoldOblique.sfd, sfd/FreeSerif.sfd, + sfd/FreeSerifItalic.sfd, sfd/FreeSerifBold.sfd, + sfd/FreeSerifBoldItalic.sfd - Added 2003 in copyright info. + +2003-03-27 Primoz Peterlin + + # sfd/FreeSerif.sfd - Cyrillic and Cyrillic Supplement blocks + brought to conformance with Unicode 3.2, courtesy Daniel Shurovich + Chirkov. + +2003-03-19 Primoz Peterlin + + # sfd/FreeSans.sfd, sfd/FreeSansOblique.sfd - somewhat wider + germandbls (U+00DF), due to complaints by Walter Schmidt. + +2003-03-18 Primoz Peterlin + + # sfd/FreeSans.sfd - Added Sinhala glyphs from the Tipitaka + project , recoded to Unicode by Noah Levitt. + +2003-02-19 Primoz Peterlin + + # sfd/FreeSans.sfd - Minor changes on mathematical operators. + +2003-02-18 Primoz Peterlin + + # sfd/FreeMono.sfd - minor cleanup of glyph backgrounds; changed + integral signs (U+222B - U+2230) + +2003-02-05 Primoz Peterlin + + # sfd/FreeSans.sfd - added a couple of glyphs in the IPA and + African Latin ranges. + +2003-01-30 Primoz Peterlin + + # sfd/FreeSans.sfd, sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansBoldOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd - Corrected Maltese Hbar (U+0126) + and/or hbar (U+0127). + +2003-01-28 Primoz Peterlin + + # sfd/FreeSerifItalic.sfd - Corrected Maltese hbar (U+0127). + +2002-12-18 Primoz Peterlin + + # tools/ConvertFont - PfaEdit script for converting SFD files to + TrueType fonts. + + # sfd/FreeSans.sfd - Added Tamil and Kannada glyphs from the + Akruti Indic fonts. + +2002-12-17 Primoz Peterlin + + # sfd/FreeSans.sfd - Added Devanagari and Gujarati glyphs from the + Akruti Indic fonts. + + # www/index.html - Added information on Rogier van Dalen's tools. + + # AUTHORS - Added M.S. Sridhar. + + # CREDITS - Correct spelling of Culmus project. Added M.S. Sridhar. + +2002-12-06 Primoz Peterlin + + # sfd/FreeMono.sfd - Added Braille glyphs, courtesy Vyacheslav + Dikonov. + + # sfd/FreeSans.sfd - Added Unicode Syriac glyphs, courtesy + Vyacheslav Dikonov. + +2002-10-11 Primoz Peterlin + + # www/index.html - Added information on the availability of the + Debian GNU/Linux package. + + # sfd/FreeSerif.sfd, sfd/FreeSans.sfd - added some kern pairs + beyond Latin-1 area. + + # sfd/FreeSerif.sfd, sfd/FreeSerifItalic.sfd, + sfd/FreeSerifBold.sfd, sfd/FreeSerifBoldItalic.sfd - re-introduced + all the emtpy glyph slots (changes from Sep 23 made PfaEdit + crash). + +2002-09-23 Primoz Peterlin + + # sfd/FreeSerif.sfd, sfd/FreeSerifItalic.sfd, + sfd/FreeSerifBold.sfd, sfd/FreeSerifBoldItalic.sfd - imported + kerning information from the URW++ AFM files + +2002-09-11 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoOblique.sfd - updated Hebrew parts to comply with + Culmus v0.6. + + # sfd/FreeSans.sfd, sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansOblique.sfd - Added Danilo Segan's Serbian Cyrillic + glyphs; updated Hebrew parts to comply with Culmus v0.6. + +2002-09-09 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansOblique.sfd - Updated Cyrillic part to match + Filippov's 1.0.7pre14 + + # sfd/FreeSansOblique.sfd - added Sam Stepanyan's Armenian glyphs + from FreeSans (skewed for 12 degrees). + +2002-09-06 Primoz Peterlin + + # sfd/FreeSans.sfd, sfd/FreeSansOblique.sfd, + sfd/FreeSansBold.sfd, sfd/FreeSansOblique.sfd - Added Maxim + Iorsh's Hebrew characters. + +2002-08-29 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, + sfd/FreeMonoBold.sfd, sfd/FreeMonoOblique.sfd - Added Maxim + Iorsh's Hebrew characters. + + # AUTHORS, CREDITS - Added Maxim Iorsh as author. + +2002-08-28 Primoz Peterlin + + # www/index.html - Added information of Microsoft's withdrawal of + freely available Unicode TrueType fonts + + # www/resources.html - Added link to Maxim Iorsh's Culmus project. + +2002-07-26 Primoz Peterlin + + # sfd/FreeMono.sfd - Added a couple of characters (Arrows area). + +2002-06-11 Primoz Peterlin + + # sfd/FreeMono.sfd - Applied Michalis Kabrianis's patch concerning + perispomeni in Greek politoniko. + +2002-05-23 Primoz Peterlin + + # sfd/FreeMono.sfd - Applied Michalis Kabrianis's patch concerning + psili in Greek politoniko. Also added two working variants of + chars in the IPA range. + +2002-05-15 Primoz Peterlin + + # sfd/FreeSans.sfd, sfd/FreeSansBold.sfd, sfd/FreeSerif.sfd, + sfd/FreeSerifBold.sfd - Deleted explicit ".notdef" character with + no contours. + +2002-05-14 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansBoldOblique.sfd, sfd/FreeSerif.sfd, + sfd/FreeSerifItalic.sfd, sfd/FreeSerifBold.sfd, + sfd/FreeSerifBoldItalic.sfd - The new version of PfaEdit saves + correctly formed Panose and LineGap lines. + + # sfd/FreeSansBoldOblique.sfd - Filled-in the missing TTFWidth and + TTFWeight values. + +2002-05-09 Primoz Peterlin + + # sfd/FreeSans.sfd - Added diacritics to the Spacing Modifier + Letters and Combining Diacritical Marks areas. Added composed + glyphs to the Latin Extended-B area. + +2002-05-07 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansBoldOblique.sfd, sfd/FreeSerif.sfd, + sfd/FreeSerifItalic.sfd, sfd/FreeSerifBold.sfd, + sfd/FreeSerifBoldItalic.sfd - Updated Panose information with data + provided by Josef W. Segur. Updated TTF headers with English and + Slovenian text. + +2002-04-30 Primoz Peterlin + + # sfd/FreeMonoBold.sfd - Working on Greek small letters. Several + minor changes (lower carons etc.) + +2002-04-29 Primoz Peterlin + + # FreeMonoBoldOblique.sfd - Started adding Greek. + + # sfd/FreeMonoBold.sfd - Added glyphs in the Geometrical Shapes + and Miscellaneous Symbols area. Harmonizing Greek with Latin. Done + with capitals. + + # sfd/FreeMono.sfd - Deleted the explicit .notdef character. Added + one glyph to the Geometrical Shapes area, which is now completed; + added three glyphs to the Miscellaneous Symbols area. Harmonizing + Greek with Latin. Done with the capitals. + +2002-04-26 Primoz Peterlin + + # sfd/FreeSans.sfd - Adjusted accent positions on several glyphs + in the Latin Extended-A area. + +2002-04-25 Primoz Peterlin + + # sfd/FreeMonoBold.sfd - Box Drawing area completed. Added a + couple of glyphs in the Geometrical Shapes area. + + # sfd/FreeMono.sfd - Small corrections in the Box Drawing area. + +2002-04-24 Primoz Peterlin + + # sfd/FreeMono.sfd - Box Drawing area completed. + +2002-04-23 Primoz Peterlin + + # tools/WGL4.lst - corrected. + + # sfd/FreeMono.sfd, sfd/FreeMonoBold.sfd - Working on Box Drawing + area. + +2002-04-22 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoBold.sfd - Working on Latin + Extended-B and Greek. + +2002-04-19 Primoz Peterlin + + # sfd/FreeSerif.sfd - Somewhat cleaner chess figures. + + # tools/MES-2.txt, tools/MES-2.lst - Corrected list (it is not + 203C-203E, it is 203C and 203E). + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd, sfd/FreeSans.sfd, + sfd/FreeSansOblique.sfd, sfd/FreeSansBold.sfd, + sfd/FreeSansBoldOblique.sfd, sfd/FreeSerif.sfd, + sfd/FreeSerifItalic.sfd, sfd/FreeSerifBold.sfd, + sfd/FreeSerifBoldItalic.sfd - Changed "Family Name" from Free to + FreeSerif, FreeSans and FreeMono, as appropriate. Changed Font + Modifiers from MonoBold etc. to Bold, Italic, Oblique, BoldOblique + and BoldItalic. + +2002-04-18 Primoz Peterlin + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd, sfd/FreeMonoBold.sfd, + sfd/FreeMonoBoldOblique.sfd - Corrected metrics; now all character + widths are set to 600. + +2002-04-17 Primoz Peterlin + + # sfd/FreeSerif.sfd - Corrected glyphs in the Box Drawing area and + Block Elements area, which should extend through the ascender#and + descender# height. + + # sfd/FreeMonoBold.sfd - Continued working on harmonizing Greek + letters with Latin and Cyrillic. + + # sfd/FreeMonoBold.sfd - Added some box drawing characters. + +2002-04-16 Primoz Peterlin + + # www/design-notes.html - Updated notes on stroke width for + symbols in Free Mono Bold. + + # sfd/FreeMono.sfd - Added a handful of characters in the + Miscellaneous Symbols area. + + # sfd/FreeMonoBoldOblique.sfd - Added subscripts, superscripts and + vulgar fractions. + + # sfd/FreeMonoBold.sfd - Started harmonizing Greek letters with + Latin and Cyrillic. + + # sfd/FreeMonoBold.sfd - Added subscripts, superscripts and vulgar + fractions. + +2002-04-15 Primoz Peterlin + + # www/design-notes.html - Updated notes on super-/subscripts in + Free Mono Bold. Separate subsections for Free Mono regular and + Free Mono Bold. + +2002-04-12 Primoz Peterlin + + # sfd/FreeSerif.sfd - Added Ethiopian glyphs, converted from the + Metafont sources from TGI, Universitt Hamburg (authors Berhanu + Beyene, Prof. Dr. Manfred Kudlek, Olaf Kummer, and Jochen + Metzinger) using Szabo's TeXtrace and retouched using + PfaEdit. Ethiopian metafonts are released under GNU GPL, + . + + # sfd/FreeMonoBold.sfd - Added 40 characters, mostly in the Latin + Extended-B and IPA Extensions areas. + +2002-04-11 Primoz Peterlin + + # sfd/FreeMono.sfd - Added a handful of characters in the Latin + Extended-B, IPA Extensions, Currency Symbols and Miscellaneous + Symbols areas. + +2002-04-09 Primoz Peterlin + + # sfd/FreeMono.sfd - Correcting accent positioning in the Extended + Greek area; adding a couple of characters here and there. Still 20 + characters short of MES-2 conformance. + +2002-04-08 Primoz Peterlin + + # sfd/FreeMono.sfd - Added some characters in the Arrows area; + more or less completed Extended Greek area (accents still need to + be fine-tuned). + +2002-04-05 Primoz Peterlin + + # sfd/FreeMono.sfd - Modern non-Russian Cyrilic mostly completed. + + # sfd/FreeMonoOblique.sfd - Synchronized with FreeMono. + + # sfd/FreeSerif.sfd - Added Thomas Ridgeway's Tamil characters + (converted from Metafont and edited somehwat). + +2002-04-04 Primoz Peterlin + + # sfd/FreeMonoOblique.sfd - Armenian letters added. + + # sfd/FreeMonoBold.sfd - Serbian Cyrillic letters dje, tshe, lje + and nje corrected. + + # sfd/FreeMono.sfd - Serbian Cyrillic letters dje and tshe + corrected. Some other non-Russian Cyrillic letters modified and + "welded together". + +2002-04-03 Primoz Peterlin + + # sfd/FreeMono.sfd - Added more or less complete Armenian + area. The glyphs are a tidied-up version based on the Armenian + Courier on the . Now we have + 1673 characters. + +2002-03-28 Primoz Peterlin + + # sfd/FreeMono.sfd - Added some mathematical symbols. + +2002-03-26 Primoz Peterlin + + # sfd/FreeSans.sfd - took H.S. Pannu's Gurmukhi from FreeSerif. It + actually fits to FreeSans much better. It seems I'll have to look + for another Gurmukhi font with modulated stroke for FreeSerif. + + # sfd/FreeSerifItalic.sfd - replaced existing Hebrew glyphs by + those from FreeSerif (slanted for 15.5 degrees). + + # sfd/FreeSerif.sfd - Added dotted Hebrew letters. Changed barred H. + + # sfd/FreeMono.sfd - Completed vulgar fractions; minor changes in + Greek; added some mathematical operators. + + # sfd/FreeMonoBold.sfd - added 12 characters to Latin Extended-B + and IPA Extensions areas (total 984). + +2002-03-25 Primoz Peterlin + + # sfd/FreeMonoBold.sfd - started adding Latin Extended-B and IPA + Extensions. + + # sfd/FreeMono.sfd - Minor cosmetic changes; cleaning up Greek + (removing redundant control points), added some non-European + Cyrillic glyphs as a test. + +2002-03-22 Primoz Peterlin + + # sfd/FreeMono.sfd - Some minor modifications; letters in Latin + Extended-B area "welded" together. + +2002-03-20 Primoz Peterlin + + # www/index.html - finally linked the resources and design notes + pages. + + # www/design-notes.html - added scaling information for super- and + subscript numerals in FreeMono. + +2002-03-19 Primoz Peterlin + + # sfd/FreeMono.sfd - the Latin Extended-B and IPA Extension area + characters moved from FreeMono and skewed for 12 degrees. + +2002-03-18 Primoz Peterlin + + # sfd/FreeMono.sfd - added a dozen or two of new characters, in + particular in the Latin Extended-B and IPA Extension area. + +2002-03-15 Primoz Peterlin + + # sfd/FreeMono.sfd - added a dozen of two of new characters, in + particular in the IPA Extension area. + + # www/design-notes.html - Corrected data for x-height in FreeMono; + information on constructing small caps. + +2002-03-14 Primoz Peterlin + + # sfd/FreeMono.sfd - added three smiley characters to the + Miscallaneous Symbols area. + +2002-03-10 Primoz Peterlin + + # sfd/FreeSerif.sfd - Anshuman Pandey has only converted Gurmukhi + from TrueType to Metafont; the original author of Gurkmukhi font + is Hardip Singh Pannu . + Got the permission from him to include the Gurmukhi glyph set. + +2002-03-08 Primoz Peterlin + + # sfd/FreeSerif.sfd - Added some more glyphs in the Mathematical + Symbols area to a total number of 3374. + +2002-03-06 Primoz Peterlin + + # sfd/FreeSerif.sfd - Added a basic Gurmukhi set. + + # www/design-notes.html - started a page on design notes + + # sfd/FreeMono.sfd - realized that glyphs in the Box Drawing area + and Block Elements area should extend through the ascender#and + descender# height, and corrected it. + + # sfd/FreeMono.sfd, sfd/FreeMonoOblique.sfd - added some musical + glyphs, linking "no-break space" to space, "soft hyphen" to + hyphen-minus etc. + +2002-03-05 Primoz Peterlin + + # tools/WGL4.lst - Added Windows Glyph List 4.0 + + # tools/LigatureList.pl - Wrote a Perl script, which lists the + GSUB list (ligature list) of a OpenType font. + + # sfd/FreeSerifBold.sfd, sfd/FreeSerifBoldItalic.sfd, + sfd/FreeSerifItalic.sfd - auxilliary Hebrew glyphs added. They are + too light compared with Latin and will be substituted with better + ones. + +2002-03-04 Primoz Peterlin + + # sfd/FreeSerif.sfd - Added some more glyphs to the Mathematical + Operators area (page 0x22). + + # sfd/FreeSerif.sfd - Incomplete and fragmentary support for + Devanagari, originating from Harsh Kumar's Shusha fonts was + replaced by Frans Velthuis' Devanagari metafont, now maintained by + Anshuman Pandey and available under + GPL. Until I figure out how to provide glyph substitution table in + OpenType, only the Unicode part is there. + +2002-02-28 Primoz Peterlin + + # ChangeLog file created + + # sfd/FreeSerif.sfd - Added some Telugu glyphs to page 0x0C, + courtesy Prasad A. Chodavarapu + + # sfd/FreeSerif.sfd - Added some glyphs to the Miscellaneous + Symbols page (0x26). + +2002-02-26 Primoz Peterlin + + # mailing lists freefont-announce and freefont-bugs created + +2002-02-25 Primoz Peterlin + + # sfd/FreeSerif.sfd - Added a couple of glyphs in Mathematics + Operators area. + + # sfd/FreeMono.sfd + - Added some more glyphs, in particular in the Mathematical + Operators section. + - Changed FamilyName to Free, FontName to FreeMono, and Full name + to "Free Monospaced". + +2002-02-20 Primoz Peterlin + + # sfd/ directory added containing FreeSerif, FreeSans and FreeMono + families. + + # tools/ directory added containing lists with characters required + for MES (Multilinguag European Subset) compliance. + + # tools/mes-list-expand.pl created - a Perl script for expanding MES + ranges into simple one-char-per-line format + + # tools/CheckConformance.pl created - a Perl script for checking + conformance of a font file with a given coded character set + + # homepage created + +2002-02-19 Primoz Peterlin + + # freefont (Free UCS Scalable Fonts) project approved on + savannah.gnu.org: diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ea/ea1722961c125100f4532f404db336110a651ed6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ea/ea1722961c125100f4532f404db336110a651ed6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> + » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %> + » <%= l(:label_custom_field_new) %>

    + +<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "new" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= hidden_field_tag 'type', @custom_field.type %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ea/ea2191a28669b9785530a0c4d38a5256d47b0fa8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ea/ea2191a28669b9785530a0c4d38a5256d47b0fa8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::TrackersTest < ActionController::IntegrationTest + fixtures :trackers + + def setup + Setting.rest_api_enabled = '1' + end + + context "/trackers" do + context "GET" do + + should "return trackers" do + get '/trackers.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'trackers', + :attributes => {:type => 'array'}, + :child => { + :tag => 'tracker', + :child => { + :tag => 'id', + :content => '2', + :sibling => { + :tag => 'name', + :content => 'Feature request' + } + } + } + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ea/ead12a798cd7fbc9307a2825275198bbad223275.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ea/ead12a798cd7fbc9307a2825275198bbad223275.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,130 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Acts + module Searchable + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + # Options: + # * :columns - a column or an array of columns to search + # * :project_key - project foreign key (default to project_id) + # * :date_column - name of the datetime column (default to created_on) + # * :sort_order - name of the column used to sort results (default to :date_column or created_on) + # * :permission - permission required to search the model (default to :view_"objects") + def acts_as_searchable(options = {}) + return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods) + + cattr_accessor :searchable_options + self.searchable_options = options + + if searchable_options[:columns].nil? + raise 'No searchable column defined.' + elsif !searchable_options[:columns].is_a?(Array) + searchable_options[:columns] = [] << searchable_options[:columns] + end + + searchable_options[:project_key] ||= "#{table_name}.project_id" + searchable_options[:date_column] ||= "#{table_name}.created_on" + searchable_options[:order_column] ||= searchable_options[:date_column] + + # Should we search custom fields on this model ? + searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil? + + send :include, Redmine::Acts::Searchable::InstanceMethods + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + # Searches the model for the given tokens + # projects argument can be either nil (will search all projects), a project or an array of projects + # Returns the results and the results count + def search(tokens, projects=nil, options={}) + # TODO: make user an argument + user = User.current + tokens = [] << tokens unless tokens.is_a?(Array) + projects = [] << projects unless projects.nil? || projects.is_a?(Array) + + find_options = {:include => searchable_options[:include]} + find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC') + + limit_options = {} + limit_options[:limit] = options[:limit] if options[:limit] + if options[:offset] + limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')" + end + + columns = searchable_options[:columns] + columns = columns[0..0] if options[:titles_only] + + token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"} + + if !options[:titles_only] && searchable_options[:search_custom_fields] + searchable_custom_field_ids = CustomField.find(:all, + :select => 'id', + :conditions => { :type => "#{self.name}CustomField", + :searchable => true }).collect(&:id) + if searchable_custom_field_ids.any? + custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" + + " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" + + " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))" + token_clauses << custom_field_sql + end + end + + sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ') + + find_options[:conditions] = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort] + + scope = self + project_conditions = [] + if searchable_options.has_key?(:permission) + project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project) + elsif respond_to?(:visible) + scope = scope.visible(user) + else + ActiveSupport::Deprecation.warn "acts_as_searchable with implicit :permission option is deprecated. Add a visible scope to the #{self.name} model or use explicit :permission option." + project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym) + end + # TODO: use visible scope options instead + project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil? + project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ') + + results = [] + results_count = 0 + + with_scope(:find => {:conditions => project_conditions}) do + with_scope(:find => find_options) do + results_count = scope.count(:all) + results = scope.find(:all, limit_options) + end + end + [results, results_count] + end + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ea/ead648f8695b39d393ec1029db862f15de288d0d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ea/ead648f8695b39d393ec1029db862f15de288d0d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +require File.expand_path('../../test_helper', __FILE__) + +class AutoCompletesControllerTest < ActionController::TestCase + fixtures :projects, :issues, :issue_statuses, + :enumerations, :users, :issue_categories, + :trackers, + :projects_trackers, + :roles, + :member_roles, + :members, + :auth_sources, + :enabled_modules, + :workflows, + :journals, :journal_details + + def test_issues_should_not_be_case_sensitive + get :issues, :project_id => 'ecookbook', :q => 'ReCiPe' + assert_response :success + assert_not_nil assigns(:issues) + assert assigns(:issues).detect {|issue| issue.subject.match /recipe/} + end + + def test_issues_should_return_issue_with_given_id + get :issues, :project_id => 'subproject1', :q => '13' + assert_response :success + assert_not_nil assigns(:issues) + assert assigns(:issues).include?(Issue.find(13)) + end + + def test_auto_complete_with_scope_all_and_cross_project_relations + Setting.cross_project_issue_relations = '1' + get :issues, :project_id => 'ecookbook', :q => '13', :scope => 'all' + assert_response :success + assert_not_nil assigns(:issues) + assert assigns(:issues).include?(Issue.find(13)) + end + + def test_auto_complete_with_scope_all_without_cross_project_relations + Setting.cross_project_issue_relations = '0' + get :issues, :project_id => 'ecookbook', :q => '13', :scope => 'all' + assert_response :success + assert_equal [], assigns(:issues) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb1d3aa61c20874487a644da3b1043fef950635b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eb1d3aa61c20874487a644da3b1043fef950635b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ + + + + + + + serif + + Bitstream Vera Serif + + + + sans-serif + + Bitstream Vera Sans + + + + monospace + + Bitstream Vera Sans Mono + + + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb223097a73640bc8df209f3cf1b3d589efdedb1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eb223097a73640bc8df209f3cf1b3d589efdedb1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class TimeEntryActivity < Enumeration + has_many :time_entries, :foreign_key => 'activity_id' + + OptionName = :enumeration_activities + + def option_name + OptionName + end + + def objects_count + time_entries.count + end + + def transfer_relations(to) + time_entries.update_all("activity_id = #{to.id}") + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb2ac8ca4ec0f3913058ccd239dd984bda31a821.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eb2ac8ca4ec0f3913058ccd239dd984bda31a821.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +日本語 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb34c07a1c8b0e261ba996612b090515510add98.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eb34c07a1c8b0e261ba996612b090515510add98.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<% unless controller_name == 'admin' && action_name == 'index' %> + <% content_for :sidebar do %> +

    <%=l(:label_administration)%>

    + <%= render :partial => 'admin/menu' %> + <% end %> +<% end %> + +<%= render :file => "layouts/base" %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb39c7e3f144ec8ff3c5fa66637d7456ecca5e83.svn-base Binary file .svn/pristine/eb/eb39c7e3f144ec8ff3c5fa66637d7456ecca5e83.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb69c2ca8a8f994d660e1f0618205141bdb05f6b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eb69c2ca8a8f994d660e1f0618205141bdb05f6b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +
    +<%= link_to l(:label_tracker_new), new_tracker_path, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_tracker_plural)%>

    + + + + + + + + + +<% for tracker in @trackers %> + "> + + + + + +<% end %> + +
    <%=l(:label_tracker)%><%=l(:button_sort)%>
    <%= link_to h(tracker.name), edit_tracker_path(tracker) %><% unless tracker.workflows.count > 0 %><%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), {:controller => 'workflows', :action => 'edit', :tracker_id => tracker} %>)<% end %><%= reorder_links('tracker', {:action => 'update', :id => tracker}, :put) %> + <%= link_to(l(:button_delete), tracker_path(tracker), + :method => :delete, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + +

    <%= pagination_links_full @tracker_pages %>

    + +<% html_title(l(:label_tracker_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eb93ec8172fa40acff3b40f1f28de22acda650a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eb93ec8172fa40acff3b40f1f28de22acda650a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +

    <%=l(:label_project_new)%>

    + +<% labelled_tabular_form_for @project, :url => { :action => "copy" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> + +
    <%= l(:button_copy) %> + + + + + + + + <%= hidden_field_tag 'only[]', '' %> +
    + +
    + +<%= submit_tag l(:button_copy) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/eba575f0f35d5fa34b9a800fc6641ac537b6126c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/eba575f0f35d5fa34b9a800fc6641ac537b6126c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +
    +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %> +
    + +<%= render_timelog_breadcrumb %> + +

    <%= l(:label_spent_time) %>

    + +<% form_tag({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> +<%= render :partial => 'date_range' %> +<% end %> + +
    +

    <%= l(:label_total) %>: <%= html_hours(l_hours(@total_hours)) %>

    +
    + +<% unless @entries.empty? %> +<%= render :partial => 'list', :locals => { :entries => @entries }%> +

    <%= pagination_links_full @entry_pages, @entry_count %>

    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge({:issue_id => @issue, :key => User.current.rss_key}) %> + <%= f.link_to 'CSV', :url => params %> +<% end %> +<% end %> + +<% html_title l(:label_spent_time), l(:label_details) %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :title => l(:label_spent_time)) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/ebb7abb0d59e1f4cd8902b17ea6fa3c9ebb74d65.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/ebb7abb0d59e1f4cd8902b17ea6fa3c9ebb74d65.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +class Repository < ActiveRecord::Base + generator_for :type => 'Subversion' + generator_for :url, :start => 'file:///test/svn' + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/eb/ebc29b85d0fc4382920254eae5d8a3fdd2a6d9ce.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/eb/ebc29b85d0fc4382920254eae5d8a3fdd2a6d9ce.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +module ObjectDaddyHelpers + # TODO: Remove these three once everyone has ported their code to use the + # new object_daddy version with protected attribute support + def User.generate_with_protected(attributes={}) + User.generate(attributes) + end + + def User.generate_with_protected!(attributes={}) + User.generate!(attributes) + end + + def User.spawn_with_protected(attributes={}) + User.spawn(attributes) + end + + def User.add_to_project(user, project, roles) + roles = [roles] unless roles.is_a?(Array) + Member.generate!(:principal => user, :project => project, :roles => roles) + end + + # Generate the default Query + def Query.generate_default!(attributes={}) + query = Query.spawn(attributes) + query.name ||= '_' + query.save! + query + end + + # Generate an issue for a project, using it's trackers + def Issue.generate_for_project!(project, attributes={}) + issue = Issue.spawn(attributes) do |issue| + issue.project = project + issue.tracker = project.trackers.first unless project.trackers.empty? + yield issue if block_given? + end + issue.save! + issue + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ec/ec80e6b58d5a9273315682fa45876f90222c9b81.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ec/ec80e6b58d5a9273315682fa45876f90222c9b81.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddProjectToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :project_id, :integer, :null => true, :default => nil + add_index :enumerations, :project_id + end + + def self.down + remove_index :enumerations, :project_id + remove_column :enumerations, :project_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ec/ec842fc17afa1fb04bc8ffad9cc30b0150dabde2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ec/ec842fc17afa1fb04bc8ffad9cc30b0150dabde2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar pt_BR language +// Author: Adalberto Machado, +// Review: Alexandre da Silva, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Segunda", + "Terça", + "Quarta", + "Quinta", + "Sexta", + "Sabado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Seg", + "Ter", + "Qua", + "Qui", + "Sex", + "Sab", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Janeiro", + "Fevereiro", + "Março", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Fev", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Out", + "Nov", + "Dez"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Sobre o calendário"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Última versão visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuído sobre GNU LGPL. Veja http://gnu.org/licenses/lgpl.html para detalhes." + +"\n\n" + +"Seleção de data:\n" + +"- Use os botões \xab, \xbb para selecionar o ano\n" + +"- Use os botões " + String.fromCharCode(0x2039) + ", " + +String.fromCharCode(0x203a) + " para selecionar o mês\n" + +"- Segure o botão do mouse em qualquer um desses botões para seleção rápida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Seleção de hora:\n" + +"- Clique em qualquer parte da hora para incrementar\n" + +"- ou Shift-click para decrementar\n" + +"- ou clique e segure para seleção rápida."; + +Calendar._TT["PREV_YEAR"] = "Ant. ano (segure para menu)"; +Calendar._TT["PREV_MONTH"] = "Ant. mês (segure para menu)"; +Calendar._TT["GO_TODAY"] = "Hoje"; +Calendar._TT["NEXT_MONTH"] = "Próx. mes (segure para menu)"; +Calendar._TT["NEXT_YEAR"] = "Próx. ano (segure para menu)"; +Calendar._TT["SEL_DATE"] = "Selecione a data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arraste para mover"; +Calendar._TT["PART_TODAY"] = " (hoje)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Mostre %s primeiro"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Fechar"; +Calendar._TT["TODAY"] = "Hoje"; +Calendar._TT["TIME_PART"] = "(Shift-)Click ou arraste para mudar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; + +Calendar._TT["WK"] = "sm"; +Calendar._TT["TIME"] = "Hora:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ec/ecbf27ee9e3ecfb43def234f66674080007c170c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ec/ecbf27ee9e3ecfb43def234f66674080007c170c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +--- +issue_statuses_001: + id: 1 + name: New + is_default: true + is_closed: false + position: 1 +issue_statuses_002: + id: 2 + name: Assigned + is_default: false + is_closed: false + position: 2 +issue_statuses_003: + id: 3 + name: Resolved + is_default: false + is_closed: false + position: 3 +issue_statuses_004: + name: Feedback + id: 4 + is_default: false + is_closed: false + position: 4 +issue_statuses_005: + id: 5 + name: Closed + is_default: false + is_closed: true + position: 5 +issue_statuses_006: + id: 6 + name: Rejected + is_default: false + is_closed: true + position: 6 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ec/eccd397cd94a8e11a0b2f72327549287bc13fcfa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ec/eccd397cd94a8e11a0b2f72327549287bc13fcfa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1003 @@ +# translated by Dzintars Bergs (dzintars.bergs@gmail.com) + +lv: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%d %b" + long: "%d %B %Y" + + day_names: [Svētdiena, Pirmdiena, Otrdiena, Trešdiena, Ceturtdiena, Piektdiena, Sestdiena] + abbr_day_names: [Sv, Pr, Ot, Tr, Ct, Pk, St] + + month_names: [~, Janvāris, Februāris, Marts, Aprīlis , Maijs, Jūnijs, Jūlijs, Augusts, Septembris, Oktobris, Novembris, Decembris] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Mai, Jūn, Jūl, Aug, Sep, Okt, Nov, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%B %d, %Y %H:%M" + am: "rītā" + pm: "vakarā" + + datetime: + distance_in_words: + half_a_minute: "pus minūte" + less_than_x_seconds: + one: "mazāk kā 1 sekunde" + other: "mazāk kā %{count} sekundes" + x_seconds: + one: "1 sekunde" + other: "%{count} sekundes" + less_than_x_minutes: + one: "mazāk kā minūte" + other: "mazāk kā %{count} minūtes" + x_minutes: + one: "1 minūte" + other: "%{count} minūtes" + about_x_hours: + one: "aptuveni 1 stunda" + other: "aptuveni %{count} stundas" + x_days: + one: "1 diena" + other: "%{count} dienas" + about_x_months: + one: "aptuveni 1 mēnesis" + other: "aptuveni %{count} mēneši" + x_months: + one: "1 mēnesis" + other: "%{count} mēneši" + about_x_years: + one: "aptuveni 1 gads" + other: "aptuveni %{count} gadi" + over_x_years: + one: "ilgāk par 1 gadu" + other: "ilgāk par %{count} gadiem" + almost_x_years: + one: "gandrīz 1 gadu" + other: "gandrīz %{count} gadus" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: " " + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Baits" + other: "Baiti" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + + support: + array: + sentence_connector: "un" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nav iekļauts sarakstā" + exclusion: "ir rezervēts" + invalid: "nederīgs" + confirmation: "apstiprinājums nesakrīt" + accepted: "jābūt akceptētam" + empty: "nevar būt tukšs" + blank: "nevar būt neaizpildīts" + too_long: "ir pārāk gara(š) (maksimālais garums ir %{count} simboli)" + too_short: "ir pārāk īsa(s) (minimālais garums ir %{count} simboli)" + wrong_length: "ir nepareiza garuma (vajadzētu būt %{count} simboli)" + taken: "eksistē" + not_a_number: "nav skaitlis" + not_a_date: "nav derīgs datums" + greater_than: "jābūt lielākam par %{count}" + greater_than_or_equal_to: "jābūt lielākam vai vienādam ar %{count}" + equal_to: "jābūt vienādam ar %{count}" + less_than: "jābūt mazākam kā %{count}" + less_than_or_equal_to: "jābūt mazākam vai vienādam ar %{count}" + odd: "jāatšķirās" + even: "jāsakrīt" + greater_than_start_date: "jābūt vēlākam par sākuma datumu" + not_same_project: "nepieder pie tā paša projekta" + circular_dependency: "Šī relācija radītu ciklisku atkarību" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Izvēlieties + + general_text_No: 'Nē' + general_text_Yes: 'Jā' + general_text_no: 'nē' + general_text_yes: 'jā' + general_lang_name: 'Latvian (Latviešu)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Konts tika atjaunots veiksmīgi. + notice_account_invalid_creditentials: Nepareizs lietotāja vārds vai parole. + notice_account_password_updated: Parole tika veiksmīgi atjaunota. + notice_account_wrong_password: Nepareiza parole + notice_account_register_done: Konts veiksmīgi izveidots. Lai aktivizētu kontu, spiediet uz saites, kas Jums tika nosūtīta. + notice_account_unknown_email: Nezināms lietotājs + notice_can_t_change_password: Šis konts izmanto ārēju pilnvarošanas avotu. Nav iespējams nomainīt paroli. + notice_account_lost_email_sent: Jums tika nosūtīts e-pasts ar instrukcijām, kā izveidot jaunu paroli. + notice_account_activated: Jūsu konts ir aktivizēts. Varat pieslēgties sistēmai. + notice_successful_create: Veiksmīga izveide. + notice_successful_update: Veiksmīga atjaunošana. + notice_successful_delete: Veiksmīga dzēšana. + notice_successful_connection: Veiksmīgs savienojums. + notice_file_not_found: Lapa, ko Jūs mēģināt atvērt, neeksistē vai ir pārvietota. + notice_locking_conflict: Datus ir atjaunojis cits lietotājs. + notice_not_authorized: Jums nav tiesību piekļūt šai lapai. + notice_email_sent: "E-pasts tika nosūtīts uz %{value}" + notice_email_error: "Kļūda sūtot e-pastu (%{value})" + notice_feeds_access_key_reseted: Jūsu RSS pieejas atslēga tika iestatīta sākuma stāvoklī. + notice_api_access_key_reseted: Jūsu API pieejas atslēga tika iestatīta sākuma stāvoklī. + notice_failed_to_save_issues: "Neizdevās saglabāt %{count} uzdevumu(us) no %{total} izvēlēti: %{ids}." + notice_no_issue_selected: "Nav izvēlēts uzdevums! Lūdzu, atzīmējiet uzdevumus, kurus vēlaties rediģēt!" + notice_account_pending: "Jūsu konts tika izveidots un šobrīd gaida administratora apstiprinājumu." + notice_default_data_loaded: Noklusētā konfigurācija tika veiksmīgi ielādēta. + notice_unable_delete_version: Neizdevās dzēst versiju. + notice_issue_done_ratios_updated: Uzdevuma izpildes koeficients atjaunots. + + error_can_t_load_default_data: "Nevar ielādēt noklusētos konfigurācijas datus: %{value}" + error_scm_not_found: "Ieraksts vai versija nebija repozitorijā." + error_scm_command_failed: "Mēģinot piekļūt repozitorijam, notika kļūda: %{value}" + error_scm_annotate: "Ieraksts neeksistē vai tam nevar tikt pievienots paskaidrojums." + error_issue_not_found_in_project: 'Uzdevums netika atrasts vai nepieder šim projektam.' + error_no_tracker_in_project: 'Neviens trakeris nav saistīts ar šo projektu. Pārbaudiet projekta iestatījumus.' + error_no_default_issue_status: 'Nav definēts uzdevuma noklusētais statuss. Pārbaudiet konfigurāciju (Ejat uz: "Administrācija -> Uzdevumu statusi")!' + error_can_not_reopen_issue_on_closed_version: 'Nevar pievienot atsauksmi uzdevumam, kas saistīts ar slēgtu versiju.' + error_can_not_archive_project: Šis projekts nevar tikt arhivēts + error_issue_done_ratios_not_updated: "Uzdevuma izpildes koeficients nav atjaunots." + error_workflow_copy_source: 'Lūdzu izvēlieties avota trakeri vai lomu' + error_workflow_copy_target: 'Lūdzu izvēlēties mērķa trakeri(us) un lomu(as)' + + warning_attachments_not_saved: "%{count} datnes netika saglabātas." + + mail_subject_lost_password: "Jūsu %{value} parole" + mail_body_lost_password: 'Lai mainītu paroli, spiediet uz šīs saites:' + mail_subject_register: "Jūsu %{value} konta aktivizācija" + mail_body_register: 'Lai izveidotu kontu, spiediet uz šīs saites:' + mail_body_account_information_external: "Varat izmantot Jūsu %{value} kontu, lai pieslēgtos." + mail_body_account_information: Jūsu konta informācija + mail_subject_account_activation_request: "%{value} konta aktivizācijas pieprasījums" + mail_body_account_activation_request: "Jauns lietotājs (%{value}) ir reģistrēts. Lietotāja konts gaida Jūsu apstiprinājumu:" + mail_subject_reminder: "%{count} uzdevums(i) sagaidāms(i) tuvākajās %{days} dienās" + mail_body_reminder: "%{count} uzdevums(i), kurš(i) ir nozīmēts(i) Jums, sagaidāms(i) tuvākajās %{days} dienās:" + mail_subject_wiki_content_added: "'%{id}' Wiki lapa pievienota" + mail_body_wiki_content_added: "The '%{id}' Wiki lapu pievienojis %{author}." + mail_subject_wiki_content_updated: "'%{id}' Wiki lapa atjaunota" + mail_body_wiki_content_updated: "The '%{id}' Wiki lapu atjaunojis %{author}." + + gui_validation_error: 1 kļūda + gui_validation_error_plural: "%{count} kļūdas" + + field_name: Nosaukums + field_description: Apraksts + field_summary: Kopsavilkums + field_is_required: Nepieciešams + field_firstname: Vārds + field_lastname: Uzvārds + field_mail: "E-pasts" + field_filename: Datne + field_filesize: Izmērs + field_downloads: Lejupielādes + field_author: Autors + field_created_on: Izveidots + field_updated_on: Atjaunots + field_field_format: Formāts + field_is_for_all: Visiem projektiem + field_possible_values: Iespējamās vērtības + field_regexp: Regulārā izteiksme + field_min_length: Minimālais garums + field_max_length: Maksimālais garums + field_value: Vērtība + field_category: Kategorija + field_title: Nosaukums + field_project: Projekts + field_issue: Uzdevums + field_status: Statuss + field_notes: Piezīmes + field_is_closed: Uzdevums slēgts + field_is_default: Noklusētā vērtība + field_tracker: Trakeris + field_subject: Temats + field_due_date: Sagaidāmais datums + field_assigned_to: Piešķirts + field_priority: Prioritāte + field_fixed_version: Mērķa versija + field_user: Lietotājs + field_role: Loma + field_homepage: Vietne + field_is_public: Publisks + field_parent: Apakšprojekts projektam + field_is_in_roadmap: Ceļvedī parādītie uzdevumi + field_login: Pieslēgties + field_mail_notification: "E-pasta paziņojumi" + field_admin: Administrators + field_last_login_on: Pēdējo reizi pieslēdzies + field_language: Valoda + field_effective_date: Datums + field_password: Parole + field_new_password: Janā parole + field_password_confirmation: Paroles apstiprinājums + field_version: Versija + field_type: Tips + field_host: Hosts + field_port: Ports + field_account: Konts + field_base_dn: Base DN + field_attr_login: Pieslēgšanās atribūts + field_attr_firstname: Vārda atribūts + field_attr_lastname: Uzvārda atribūts + field_attr_mail: "E-pasta atribūts" + field_onthefly: "Lietotāja izveidošana on-the-fly" + field_start_date: Sākuma datums + field_done_ratio: "% padarīti" + field_auth_source: Pilnvarošanas režīms + field_hide_mail: "Paslēpt manu e-pasta adresi" + field_comments: Komentārs + field_url: URL + field_start_page: Sākuma lapa + field_subproject: Apakšprojekts + field_hours: Stundas + field_activity: Aktivitāte + field_spent_on: Datums + field_identifier: Identifikators + field_is_filter: Izmantots kā filtrs + field_issue_to: Saistīts uzdevums + field_delay: Kavējums + field_assignable: Uzdevums var tikt piesaistīts šai lomai + field_redirect_existing_links: Pāradresēt eksistējošās saites + field_estimated_hours: Paredzētais laiks + field_column_names: Kolonnas + field_time_zone: Laika zona + field_searchable: Meklējams + field_default_value: Noklusētā vērtība + field_comments_sorting: Rādīt komentārus + field_parent_title: Vecāka lapa + field_editable: Rediģējams + field_watcher: Vērotājs + field_identity_url: OpenID URL + field_content: Saturs + field_group_by: Grupēt rezultātus pēc + field_sharing: Koplietošana + + setting_app_title: Programmas nosaukums + setting_app_subtitle: Programmas apakš-nosaukums + setting_welcome_text: Sveiciena teksts + setting_default_language: Noklusētā valoda + setting_login_required: Nepieciešama pilnvarošana + setting_self_registration: Pašreģistrēšanās + setting_attachment_max_size: Pielikuma maksimālais izmērs + setting_issues_export_limit: Uzdevumu eksporta ierobežojums + setting_mail_from: "E-pasta adrese informācijas nosūtīšanai" + setting_bcc_recipients: "Saņēmēju adreses neparādīsies citu saņēmēju vēstulēs (bcc)" + setting_plain_text_mail: "Vēstule brīvā tekstā (bez HTML)" + setting_host_name: Hosta nosaukums un piekļuves ceļš + setting_text_formatting: Teksta formatēšana + setting_wiki_compression: Wiki vēstures saspiešana + setting_feeds_limit: Barotnes satura ierobežojums + setting_default_projects_public: Jaunie projekti noklusēti ir publiski pieejami + setting_autofetch_changesets: "Automātiski lietot jaunāko versiju, pieslēdzoties repozitorijam (Autofetch)" + setting_sys_api_enabled: Ieslēgt WS repozitoriju menedžmentam + setting_commit_ref_keywords: Norādes atslēgvārdi + setting_commit_fix_keywords: Fiksējošie atslēgvārdi + setting_autologin: Automātiskā pieslēgšanās + setting_date_format: Datuma formāts + setting_time_format: Laika formāts + setting_cross_project_issue_relations: "Atļaut starp-projektu uzdevumu relācijas" + setting_issue_list_default_columns: Noklusēti rādītās kolonnas uzdevumu sarakstā + setting_emails_footer: "E-pastu kājene" + setting_protocol: Protokols + setting_per_page_options: Objekti vienā lapā + setting_user_format: Lietotāju rādīšanas formāts + setting_activity_days_default: Dienus skaits aktivitāšu rādīšanai aktivitāšu sadaļā + setting_display_subprojects_issues: Rādīt apakšprojekta uzdevumus galvenajā projektā pēc noklusējuma + setting_enabled_scm: Lietot SCM + setting_mail_handler_body_delimiters: "Saīsināt pēc vienas no šim rindām" + setting_mail_handler_api_enabled: "Lietot WS ienākošajiem e-pastiem" + setting_mail_handler_api_key: API atslēga + setting_sequential_project_identifiers: Ģenerēt secīgus projektu identifikatorus + setting_gravatar_enabled: Izmantot Gravatar lietotāju ikonas + setting_gravatar_default: Noklusētais Gravatar attēls + setting_diff_max_lines_displayed: Maksimālais rādīto diff rindu skaits + setting_file_max_size_displayed: Maksimālais izmērs iekļautajiem teksta failiem + setting_repository_log_display_limit: Maksimālais žurnāla datnē rādīto revīziju skaits + setting_openid: Atļaut OpenID pieslēgšanos un reģistrēšanos + setting_password_min_length: Minimālais paroles garums + setting_new_project_user_role_id: Loma, kura tiek piešķirta ne-administratora lietotājam, kurš izveido projektu + setting_default_projects_modules: Noklusētie lietotie moduļi jaunam projektam + setting_issue_done_ratio: Aprēķināt uzdevuma izpildes koeficientu ar + setting_issue_done_ratio_issue_field: uzdevuma lauku + setting_issue_done_ratio_issue_status: uzdevuma statusu + setting_start_of_week: Sākt kalendāru ar + setting_rest_api_enabled: Lietot REST web-servisu + setting_cache_formatted_text: Kešot formatētu tekstu + + permission_add_project: Izveidot projektu + permission_add_subprojects: Izveidot apakšprojektu + permission_edit_project: Rediģēt projektu + permission_select_project_modules: Izvēlēties projekta moduļus + permission_manage_members: Pārvaldīt dalībniekus + permission_manage_project_activities: Pārvaldīt projekta aktivitātes + permission_manage_versions: Pārvaldīt versijas + permission_manage_categories: Pārvaldīt uzdevumu kategorijas + permission_view_issues: Apskatīt uzdevumus + permission_add_issues: Pievienot uzdevumus + permission_edit_issues: Rediģēt uzdevumus + permission_manage_issue_relations: Pārvaldīt uzdevumu relācijas + permission_add_issue_notes: Pievienot piezīmes + permission_edit_issue_notes: Rediģēt piezīmes + permission_edit_own_issue_notes: Rediģēt paša piezīmes + permission_move_issues: Pārvietot uzdevumus + permission_delete_issues: Dzēst uzdevumus + permission_manage_public_queries: Pārvaldīt publiskos pieprasījumus + permission_save_queries: Saglabāt pieprasījumus + permission_view_gantt: Skatīt Ganta diagrammu + permission_view_calendar: Skatīt kalendāru + permission_view_issue_watchers: Skatīt vērotāju sarakstu + permission_add_issue_watchers: Pievienot vērotājus + permission_delete_issue_watchers: Dzēst vērotājus + permission_log_time: Piereģistrēt pavadīto laiku + permission_view_time_entries: Skatīt pavadīto laiku + permission_edit_time_entries: Rdiģēt laika reģistrus + permission_edit_own_time_entries: Rediģēt savus laika reģistrus + permission_manage_news: Pārvaldīt jaunumus + permission_comment_news: Komentēt jaunumus + permission_manage_documents: Pārvaldīt dokumentus + permission_view_documents: Skatīt dokumentus + permission_manage_files: Pārvaldīt failus + permission_view_files: Skatīt failus + permission_manage_wiki: Pārvaldīt wiki + permission_rename_wiki_pages: Pārsaukt wiki lapas + permission_delete_wiki_pages: Dzēst wiki lapas + permission_view_wiki_pages: Skatīt wiki + permission_view_wiki_edits: Skatīt wiki vēsturi + permission_edit_wiki_pages: Rdiģēt wiki lapas + permission_delete_wiki_pages_attachments: Dzēst pielikumus + permission_protect_wiki_pages: Projekta wiki lapas + permission_manage_repository: Pārvaldīt repozitoriju + permission_browse_repository: Pārlūkot repozitoriju + permission_view_changesets: Skatīt izmaiņu kopumus + permission_commit_access: Atļaut piekļuvi + permission_manage_boards: Pārvaldīt ziņojumu dēļus + permission_view_messages: Skatīt ziņas + permission_add_messages: Publicēt ziņas + permission_edit_messages: Rediģēt ziņas + permission_edit_own_messages: Rediģēt savas ziņas + permission_delete_messages: Dzēst ziņas + permission_delete_own_messages: Dzēst savas ziņas + permission_export_wiki_pages: Eksportēt Wiki lapas + + project_module_issue_tracking: Uzdevumu uzskaite + project_module_time_tracking: Laika uzskaite + project_module_news: Jaunumi + project_module_documents: Dokumenti + project_module_files: Datnes + project_module_wiki: Wiki + project_module_repository: Repozitorijs + project_module_boards: Ziņojumu dēļi + + label_user: Lietotājs + label_user_plural: Lietotāji + label_user_new: Jauns lietotājs + label_user_anonymous: Anonīms + label_project: Projekts + label_project_new: Jauns projekts + label_project_plural: Projekti + label_x_projects: + zero: nav projektu + one: 1 projekts + other: "%{count} projekti" + label_project_all: Visi projekti + label_project_latest: Jaunākie projekti + label_issue: Uzdevums + label_issue_new: Jauns uzdevums + label_issue_plural: Uzdevumi + label_issue_view_all: Skatīt visus uzdevumus + label_issues_by: "Kārtot pēc %{value}" + label_issue_added: Uzdevums pievienots + label_issue_updated: Uzdevums atjaunots + label_document: Dokuments + label_document_new: Jauns dokuments + label_document_plural: Dokumenti + label_document_added: Dokuments pievienots + label_role: Loma + label_role_plural: Lomas + label_role_new: Jauna loma + label_role_and_permissions: Lomas un atļaujas + label_member: Dalībnieks + label_member_new: Jauns dalībnieks + label_member_plural: Dalībnieki + label_tracker: Trakeris + label_tracker_plural: Trakeri + label_tracker_new: Jauns trakeris + label_workflow: Darba gaita + label_issue_status: Uzdevuma statuss + label_issue_status_plural: Uzdevumu statusi + label_issue_status_new: Jauns statuss + label_issue_category: Uzdevuma kategorija + label_issue_category_plural: Uzdevumu kategorijas + label_issue_category_new: Jauna kategorija + label_custom_field: Pielāgojams lauks + label_custom_field_plural: Pielāgojami lauki + label_custom_field_new: Jauns pielāgojams lauks + label_enumerations: Uzskaitījumi + label_enumeration_new: Jauna vērtība + label_information: Informācija + label_information_plural: Informācija + label_please_login: Lūdzu pieslēdzieties + label_register: Reģistrēties + label_login_with_open_id_option: vai pieslēgties ar OpenID + label_password_lost: Nozaudēta parole + label_home: Sākums + label_my_page: Mana lapa + label_my_account: Mans konts + label_my_projects: Mani projekti + label_administration: Administrācija + label_login: Pieslēgties + label_logout: Atslēgties + label_help: Palīdzība + label_reported_issues: Ziņotie uzdevumi + label_assigned_to_me_issues: Man piesaistītie uzdevumi + label_last_login: Pēdējā pieslēgšanās + label_registered_on: Reģistrējies + label_activity: Aktivitāte + label_overall_activity: Kopējās aktivitātes + label_user_activity: "Lietotāja %{value} aktivitātes" + label_new: Jauns + label_logged_as: Pieslēdzies kā + label_environment: Vide + label_authentication: Pilnvarošana + label_auth_source: Pilnvarošanas režīms + label_auth_source_new: Jauns pilnvarošanas režīms + label_auth_source_plural: Pilnvarošanas režīmi + label_subproject_plural: Apakšprojekti + label_subproject_new: Jauns apakšprojekts + label_and_its_subprojects: "%{value} un tā apakšprojekti" + label_min_max_length: Minimālais - Maksimālais garums + label_list: Saraksts + label_date: Datums + label_integer: Vesels skaitlis + label_float: Decimālskaitlis + label_boolean: Patiesuma vērtība + label_string: Teksts + label_text: Garš teksts + label_attribute: Atribūts + label_attribute_plural: Atribūti + label_download: "%{count} Lejupielāde" + label_download_plural: "%{count} Lejupielādes" + label_no_data: Nav datu, ko parādīt + label_change_status: Mainīt statusu + label_history: Vēsture + label_attachment: Pielikums + label_attachment_new: Jauns pielikums + label_attachment_delete: Dzēst pielikumu + label_attachment_plural: Pielikumi + label_file_added: Lauks pievienots + label_report: Atskaite + label_report_plural: Atskaites + label_news: Ziņa + label_news_new: Pievienot ziņu + label_news_plural: Ziņas + label_news_latest: Jaunākās ziņas + label_news_view_all: Skatīt visas ziņas + label_news_added: Ziņas pievienotas + label_settings: Iestatījumi + label_overview: Pārskats + label_version: Versija + label_version_new: Jauna versija + label_version_plural: Versijas + label_close_versions: Aizvērt pabeigtās versijas + label_confirmation: Apstiprinājums + label_export_to: 'Pieejams arī:' + label_read: Lasīt... + label_public_projects: Publiskie projekti + label_open_issues: atvērts + label_open_issues_plural: atvērti + label_closed_issues: slēgts + label_closed_issues_plural: slēgti + label_x_open_issues_abbr_on_total: + zero: 0 atvērti / %{total} + one: 1 atvērts / %{total} + other: "%{count} atvērti / %{total}" + label_x_open_issues_abbr: + zero: 0 atvērti + one: 1 atvērts + other: "%{count} atvērti" + label_x_closed_issues_abbr: + zero: 0 slēgti + one: 1 slēgts + other: "%{count} slēgti" + label_total: Kopā + label_permissions: Atļaujas + label_current_status: Pašreizējais statuss + label_new_statuses_allowed: Jauni statusi atļauti + label_all: visi + label_none: neviens + label_nobody: nekas + label_next: Nākošais + label_previous: Iepriekšējais + label_used_by: Izmanto + label_details: Detaļas + label_add_note: Pievienot piezīmi + label_per_page: katrā lapā + label_calendar: Kalendārs + label_months_from: mēneši no + label_gantt: Ganta diagramma + label_internal: Iekšējais + label_last_changes: "pēdējās %{count} izmaiņas" + label_change_view_all: Skatīt visas izmaiņas + label_personalize_page: Pielāgot šo lapu + label_comment: Komentārs + label_comment_plural: Komentāri + label_x_comments: + zero: nav komentāru + one: 1 komentārs + other: "%{count} komentāri" + label_comment_add: Pievienot komentāru + label_comment_added: Komentārs pievienots + label_comment_delete: Dzēst komentārus + label_query: Pielāgots pieprasījums + label_query_plural: Pielāgoti pieprasījumi + label_query_new: Jauns pieprasījums + label_filter_add: Pievienot filtru + label_filter_plural: Filtri + label_equals: ir + label_not_equals: nav + label_in_less_than: ir mazāk kā + label_in_more_than: ir vairāk kā + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: iekš + label_today: šodien + label_all_time: visu laiku + label_yesterday: vakar + label_this_week: šonedēļ + label_last_week: pagājušo šonedēļ + label_last_n_days: "pēdējās %{count} dienas" + label_this_month: šomēnes + label_last_month: pagājušo mēnes + label_this_year: šogad + label_date_range: Datumu apgabals + label_less_than_ago: mazāk kā dienas iepriekš + label_more_than_ago: vairāk kā dienas iepriekš + label_ago: dienas iepriekš + label_contains: satur + label_not_contains: nesatur + label_day_plural: dienas + label_repository: Repozitorijs + label_repository_plural: Repozitoriji + label_browse: Pārlūkot + label_modification: "%{count} izmaiņa" + label_modification_plural: "%{count} izmaiņas" + label_branch: Zars + label_tag: Birka + label_revision: Revīzija + label_revision_plural: Revīzijas + label_revision_id: "Revīzija %{value}" + label_associated_revisions: Saistītās revīzijas + label_added: pievienots + label_modified: modificēts + label_copied: nokopēts + label_renamed: pārsaukts + label_deleted: dzēsts + label_latest_revision: Pēdējā revīzija + label_latest_revision_plural: Pēdējās revīzijas + label_view_revisions: Skatīt revīzijas + label_view_all_revisions: Skatīt visas revīzijas + label_max_size: Maksimālais izmērs + label_sort_highest: Pārvietot uz augšu + label_sort_higher: Pārvietot soli augšup + label_sort_lower: Pārvietot uz leju + label_sort_lowest: Pārvietot vienu soli uz leju + label_roadmap: Ceļvedis + label_roadmap_due_in: "Sagaidāms pēc %{value}" + label_roadmap_overdue: "nokavēts %{value}" + label_roadmap_no_issues: Šai versijai nav uzdevumu + label_search: Meklēt + label_result_plural: Rezultāti + label_all_words: Visi vārdi + label_wiki: Wiki + label_wiki_edit: Wiki labojums + label_wiki_edit_plural: Wiki labojumi + label_wiki_page: Wiki lapa + label_wiki_page_plural: Wiki lapas + label_index_by_title: Indeksēt pēc nosaukuma + label_index_by_date: Indeksēt pēc datuma + label_current_version: Tekošā versija + label_preview: Priekšskatījums + label_feed_plural: Barotnes + label_changes_details: Visu izmaiņu detaļas + label_issue_tracking: Uzdevumu uzskaite + label_spent_time: Pavadītais laiks + label_f_hour: "%{value} stunda" + label_f_hour_plural: "%{value} stundas" + label_time_tracking: Laika uzskaite + label_change_plural: Izmaiņas + label_statistics: Statistika + label_commits_per_month: Nodevumi mēnesī + label_commits_per_author: Nodevumi no autora + label_view_diff: Skatīt atšķirības + label_diff_inline: iekļauts + label_diff_side_by_side: blakus + label_options: Opcijas + label_copy_workflow_from: Kopēt darba plūsmu no + label_permissions_report: Atļauju atskaite + label_watched_issues: Vērotie uzdevumi + label_related_issues: Saistītie uzdevumi + label_applied_status: Piešķirtais statuss + label_loading: Lādējas... + label_relation_new: Jauna relācija + label_relation_delete: Dzēst relāciju + label_relates_to: saistīts ar + label_duplicates: dublikāti + label_duplicated_by: dublējas ar + label_blocks: bloķē + label_blocked_by: nobloķējis + label_precedes: pirms + label_follows: seko + label_end_to_start: no beigām uz sākumu + label_end_to_end: no beigām uz beigām + label_start_to_start: no sākuma uz sākumu + label_start_to_end: no sākuma uz beigām + label_stay_logged_in: Atcerēties mani + label_disabled: izslēgts + label_show_completed_versions: Rādīt pabeigtās versijas + label_me: es + label_board: Forums + label_board_new: Jauns forums + label_board_plural: Forumi + label_board_locked: Slēgts + label_board_sticky: Svarīgs + label_topic_plural: Tēmas + label_message_plural: Ziņas + label_message_last: Pēdējā ziņa + label_message_new: Jauna ziņa + label_message_posted: Ziņa pievienota + label_reply_plural: Atbildes + label_send_information: Sūtīt konta informāciju lietotājam + label_year: Gads + label_month: Mēnesis + label_week: Nedēļa + label_date_from: No + label_date_to: Kam + label_language_based: Izmantot lietotāja valodu + label_sort_by: "Kārtot pēc %{value}" + label_send_test_email: "Sūtīt testa e-pastu" + label_feeds_access_key: RSS piekļuves atslēga + label_missing_feeds_access_key: Trūkst RSS piekļuves atslēgas + label_feeds_access_key_created_on: "RSS piekļuves atslēga izveidota pirms %{value}" + label_module_plural: Moduļi + label_added_time_by: "Pievienojis %{author} pirms %{age}" + label_updated_time_by: "Atjaunojis %{author} pirms %{age}" + label_updated_time: "Atjaunots pirms %{value}" + label_jump_to_a_project: Pāriet uz projektu... + label_file_plural: Datnes + label_changeset_plural: Izmaiņu kopumi + label_default_columns: Noklusētās kolonnas + label_no_change_option: (Nav izmaiņu) + label_bulk_edit_selected_issues: Labot visus izvēlētos uzdevumus + label_theme: Tēma + label_default: Noklusēts + label_search_titles_only: Meklēt tikai nosaukumos + label_user_mail_option_all: "Par visiem notikumiem visos manos projektos" + label_user_mail_option_selected: "Par visiem notikumiem tikai izvēlētajos projektos..." + label_user_mail_no_self_notified: "Neziņot man par izmaiņām, kuras veicu es pats" + label_registration_activation_by_email: "konta aktivizācija caur e-pastu" + label_registration_manual_activation: manuālā konta aktivizācija + label_registration_automatic_activation: automātiskā konta aktivizācija + label_display_per_page: "Rādīt vienā lapā: %{value}" + label_age: Vecums + label_change_properties: Mainīt atribūtus + label_general: Galvenais + label_more: Vēl + label_scm: SCM + label_plugins: Spraudņi + label_ldap_authentication: LDAP pilnvarošana + label_downloads_abbr: L-lād. + label_optional_description: "Apraksts (neobligāts)" + label_add_another_file: Pievienot citu failu + label_preferences: Priekšrocības + label_chronological_order: Hronoloģiskā kārtībā + label_reverse_chronological_order: Apgriezti hronoloģiskā kārtībā + label_planning: Plānošana + label_incoming_emails: "Ienākošie e-pasti" + label_generate_key: Ģenerēt atslēgu + label_issue_watchers: Vērotāji + label_example: Piemērs + label_display: Rādīt + label_sort: Kārtot + label_ascending: Augoši + label_descending: Dilstoši + label_date_from_to: "No %{start} līdz %{end}" + label_wiki_content_added: Wiki lapa pievienota + label_wiki_content_updated: Wiki lapa atjaunota + label_group: Grupa + label_group_plural: Grupas + label_group_new: Jauna grupa + label_time_entry_plural: Pavadītais laiks + label_version_sharing_none: Nav koplietošanai + label_version_sharing_descendants: Ar apakšprojektiem + label_version_sharing_hierarchy: Ar projektu hierarhiju + label_version_sharing_tree: Ar projekta koku + label_version_sharing_system: Ar visiem projektiem + label_update_issue_done_ratios: Atjaunot uzdevuma veikuma attiecību + label_copy_source: Avots + label_copy_target: Mērķis + label_copy_same_as_target: Tāds pats kā mērķis + label_display_used_statuses_only: "Rādīt tikai statusus, ko lieto šis trakeris" + label_api_access_key: API pieejas atslēga + label_missing_api_access_key: Trūkst API pieejas atslēga + label_api_access_key_created_on: "API pieejas atslēga izveidota pirms %{value}" + + button_login: Pieslēgties + button_submit: Nosūtīt + button_save: Saglabāt + button_check_all: Atzīmēt visu + button_uncheck_all: Noņemt visus atzīmējumus + button_delete: Dzēst + button_create: Izveidot + button_create_and_continue: Izveidot un turpināt + button_test: Testēt + button_edit: Labot + button_add: Pievienot + button_change: Mainīt + button_apply: Apstiprināt + button_clear: Notīrīt + button_lock: Slēgt + button_unlock: Atslēgt + button_download: Lejuplādēt + button_list: Saraksts + button_view: Skats + button_move: Pārvietot + button_move_and_follow: Pārvietot un sekot + button_back: Atpakaļ + button_cancel: Atcelt + button_activate: Aktivizēt + button_sort: Kārtot + button_log_time: Ilgs laiks + button_rollback: Atjaunot uz šo versiju + button_watch: Vērot + button_unwatch: Nevērot + button_reply: Atbildēt + button_archive: Arhivēt + button_unarchive: Atarhivēt + button_reset: Atiestatīt + button_rename: Pārsaukt + button_change_password: Mainīt paroli + button_copy: Kopēt + button_copy_and_follow: Kopēt un sekot + button_annotate: Pierakstīt paskaidrojumu + button_update: Atjaunot + button_configure: Konfigurēt + button_quote: Citāts + button_duplicate: Dublēt + button_show: Rādīt + + status_active: aktīvs + status_registered: reģistrēts + status_locked: slēgts + + version_status_open: atvērta + version_status_locked: slēgta + version_status_closed: aizvērta + + field_active: Aktīvs + + text_select_mail_notifications: "Izvēlieties darbības, par kurām vēlaties saņemt ziņojumus e-pastā" + text_regexp_info: "piem. ^[A-Z0-9]+$" + text_min_max_length_info: "0 nozīmē, ka nav ierobežojumu" + text_project_destroy_confirmation: "Vai tiešām vēlaties dzēst šo projektu un ar to saistītos datus?" + text_subprojects_destroy_warning: "Tā apakšprojekts(i): %{value} arī tiks dzēsts(i)." + text_workflow_edit: Lai labotu darba plūsmu, izvēlieties lomu un trakeri + text_are_you_sure: "Vai esat pārliecināts?" + text_journal_changed: "%{label} mainīts no %{old} uz %{new}" + text_journal_set_to: "%{label} iestatīts uz %{value}" + text_journal_deleted: "%{label} dzēsts (%{old})" + text_journal_added: "%{label} %{value} pievienots" + text_tip_issue_begin_day: uzdevums sākas šodien + text_tip_issue_end_day: uzdevums beidzas šodien + text_tip_issue_begin_end_day: uzdevums sākas un beidzas šodien + text_project_identifier_info: 'Tikai mazie burti (a-z), cipari un domuzīmes ir atļauti.
    Kad saglabāts, identifikators nevar tikt mainīts.' + text_caracters_maximum: "%{count} simboli maksimāli." + text_caracters_minimum: "Jābūt vismaz %{count} simbolu garumā." + text_length_between: "Garums starp %{min} un %{max} simboliem." + text_tracker_no_workflow: Šim trakerim nav definēta darba plūsma + text_unallowed_characters: Neatļauti simboli + text_comma_separated: "Atļautas vairākas vērtības (atdalīt ar komatu)." + text_line_separated: "Atļautas vairākas vērtības (rakstīt katru savā rindā)." + text_issues_ref_in_commit_messages: "Izmaiņu salīdzināšana izejot no ziņojumiem" + text_issue_added: "Uzdevumu %{id} pievienojis %{author}." + text_issue_updated: "Uzdevumu %{id} atjaunojis %{author}." + text_wiki_destroy_confirmation: "Vai esat drošs, ka vēlaties dzēst šo wiki un visu tās saturu?" + text_issue_category_destroy_question: "Daži uzdevumi (%{count}) ir nozīmēti šai kategorijai. Ko Jūs vēlaties darīt?" + text_issue_category_destroy_assignments: Dzēst kategoriju nozīmējumus + text_issue_category_reassign_to: Nozīmēt uzdevumus šai kategorijai + text_user_mail_option: "No neizvēlētajiem projektiem Jūs saņemsiet ziņojumus e-pastā tikai par notikumiem, kuriem Jūs sekojat vai kuros esat iesaistīts." + text_no_configuration_data: "Lomas, trakeri, uzdevumu statusi un darba plūsmas vēl nav konfigurētas.\nĻoti ieteicams ielādēt noklusēto konfigurāciju. Pēc ielādēšanas to būs iespējams modificēt." + text_load_default_configuration: Ielādēt noklusēto konfigurāciju + text_status_changed_by_changeset: "Apstiprināts izmaiņu kopumā %{value}." + text_issues_destroy_confirmation: 'Vai tiešām vēlaties dzēst izvēlēto uzdevumu(us)?' + text_select_project_modules: 'Izvēlieties moduļus šim projektam:' + text_default_administrator_account_changed: Noklusētais administratora konts mainīts + text_file_repository_writable: Pielikumu direktorijā atļauts rakstīt + text_plugin_assets_writable: Spraudņu kataloga direktorijā atļauts rakstīt + text_rmagick_available: "RMagick pieejams (neobligāts)" + text_destroy_time_entries_question: "%{hours} stundas tika ziņotas par uzdevumu, ko vēlaties dzēst. Ko darīt?" + text_destroy_time_entries: Dzēst ziņotās stundas + text_assign_time_entries_to_project: Piešķirt ziņotās stundas projektam + text_reassign_time_entries: 'Piešķirt ziņotās stundas uzdevumam:' + text_user_wrote: "%{value} rakstīja:" + text_enumeration_destroy_question: "%{count} objekti ir piešķirti šai vērtībai." + text_enumeration_category_reassign_to: 'Piešķirt tos šai vērtībai:' + text_email_delivery_not_configured: "E-pastu nosūtīšana nav konfigurēta, un ziņojumi ir izslēgti.\nKonfigurējiet savu SMTP serveri datnē config/configuration.yml un pārstartējiet lietotni." + text_repository_usernames_mapping: "Izvēlieties vai atjaunojiet Redmine lietotāju, saistītu ar katru lietotājvārdu, kas atrodams repozitorija žurnālā.\nLietotāji ar to pašu Redmine un repozitorija lietotājvārdu būs saistīti automātiski." + text_diff_truncated: '... Šis diff tika nošķelts, jo tas pārsniedz maksimālo izmēru, ko var parādīt.' + text_custom_field_possible_values_info: 'Katra vērtības savā rindā' + text_wiki_page_destroy_question: "Šij lapai ir %{descendants} apakšlapa(as) un pēcnācēji. Ko darīt?" + text_wiki_page_nullify_children: "Paturēt apakšlapas kā pamatlapas" + text_wiki_page_destroy_children: "Dzēst apakšlapas un visus pēcnācējus" + text_wiki_page_reassign_children: "Piešķirt apakšlapas šai lapai" + text_own_membership_delete_confirmation: "Jūs tūlīt dzēsīsiet dažas vai visas atļaujas, un Jums pēc tam var nebūt atļauja labot šo projektu.\nVai turpināt?" + + default_role_manager: Menedžeris + default_role_developer: Izstrādātājs + default_role_reporter: Ziņotājs + default_tracker_bug: Kļūda + default_tracker_feature: Iezīme + default_tracker_support: Atbalsts + default_issue_status_new: Jauns + default_issue_status_in_progress: Attīstībā + default_issue_status_resolved: Atrisināts + default_issue_status_feedback: Atsauksmes + default_issue_status_closed: Slēgts + default_issue_status_rejected: Noraidīts + default_doc_category_user: Lietotāja dokumentācija + default_doc_category_tech: Tehniskā dokumentācija + default_priority_low: Zema + default_priority_normal: Normāla + default_priority_high: Augsta + default_priority_urgent: Steidzama + default_priority_immediate: Tūlītēja + default_activity_design: Dizains + default_activity_development: Izstrādāšana + + enumeration_issue_priorities: Uzdevumu prioritātes + enumeration_doc_categories: Dokumentu kategorijas + enumeration_activities: Aktivitātes (laika uzskaite) + enumeration_system_activity: Sistēmas aktivitātes + + error_can_not_delete_custom_field: Unable to delete custom field + permission_manage_subtasks: Manage subtasks + label_profile: Profile + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + field_parent_issue: Parent task + error_unable_delete_issue_status: Unable to delete issue status + label_subtask_plural: Subtasks + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + label_project_copy_notifications: Send email notifications during the project copy + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kodēt ziņojumus + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ec/ece7cbef27795c37d973fa2dd96a9568e64db01b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ec/ece7cbef27795c37d973fa2dd96a9568e64db01b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +Copyright (c) 2006 4ssoM LLC + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND +NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ed/ed4445fd5e6feeb3c1741c1359718c8bf54443a6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ed/ed4445fd5e6feeb3c1741c1359718c8bf54443a6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +<%= @news.title %> +<%= @news_url %> +<%= @news.author.name %> + +<%= @news.description %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ed/ed54e17c309435857cb6c6ab5edf8effc7865259.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ed/ed54e17c309435857cb6c6ab5edf8effc7865259.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +

    <%=l(:label_attachment_new)%>

    + +<%= error_messages_for 'attachment' %> +
    +<% form_tag(project_files_path(@project), :multipart => true, :class => "tabular") do %> + +<% if @versions.any? %> +

    +<%= select_tag "version_id", content_tag('option', '') + + options_from_collection_for_select(@versions, "id", "name") %>

    +<% end %> + +

    <%= render :partial => 'attachments/form' %>

    +
    +<%= submit_tag l(:button_add) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ed/ed57efbc247183b288b943a718082419611a4686.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ed/ed57efbc247183b288b943a718082419611a4686.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,88 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class Journal < ActiveRecord::Base + belongs_to :journalized, :polymorphic => true + # added as a quick fix to allow eager loading of the polymorphic association + # since always associated to an issue, for now + belongs_to :issue, :foreign_key => :journalized_id + + belongs_to :user + has_many :details, :class_name => "JournalDetail", :dependent => :delete_all + attr_accessor :indice + + acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" }, + :description => :notes, + :author => :user, + :type => Proc.new {|o| (s = o.new_status) ? (s.is_closed? ? 'issue-closed' : 'issue-edit') : 'issue-note' }, + :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}} + + acts_as_activity_provider :type => 'issues', + :author_key => :user_id, + :find_options => {:include => [{:issue => :project}, :details, :user], + :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" + + " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"} + + named_scope :visible, lambda {|*args| { + :include => {:issue => :project}, + :conditions => Issue.visible_condition(args.shift || User.current, *args) + }} + + def save(*args) + # Do not save an empty journal + (details.empty? && notes.blank?) ? false : super + end + + # Returns the new status if the journal contains a status change, otherwise nil + def new_status + c = details.detect {|detail| detail.prop_key == 'status_id'} + (c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil + end + + def new_value_for(prop) + c = details.detect {|detail| detail.prop_key == prop} + c ? c.value : nil + end + + def editable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project))) + end + + def project + journalized.respond_to?(:project) ? journalized.project : nil + end + + def attachments + journalized.respond_to?(:attachments) ? journalized.attachments : nil + end + + # Returns a string of css classes + def css_classes + s = 'journal' + s << ' has-notes' unless notes.blank? + s << ' has-details' unless details.blank? + s + end + + def notify? + @notify != false + end + + def notify=(arg) + @notify = arg + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ed/edd79c91fb769e74e14d6d0612b40b231334e153.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ed/edd79c91fb769e74e14d6d0612b40b231334e153.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddCustomFieldsEditable < ActiveRecord::Migration + def self.up + add_column :custom_fields, :editable, :boolean, :default => true + end + + def self.down + remove_column :custom_fields, :editable + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ed/ede91cedae4ed5ab7969e06dc653df26e2ee78bf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ed/ede91cedae4ed5ab7969e06dc653df26e2ee78bf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,122 @@ +# RedMine - project management software +# Copyright (C) 2006-2011 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 'zlib' + +class WikiContent < ActiveRecord::Base + set_locking_column :version + belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + validates_presence_of :text + validates_length_of :comments, :maximum => 255, :allow_nil => true + + acts_as_versioned + + def visible?(user=User.current) + page.visible?(user) + end + + def project + page.project + end + + def attachments + page.nil? ? [] : page.attachments + end + + # Returns the mail adresses of users that should be notified + def recipients + notified = project.notified_users + notified.reject! {|user| !visible?(user)} + notified.collect(&:mail) + end + + # Return true if the content is the current page content + def current_version? + true + end + + class Version + belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id' + belongs_to :author, :class_name => '::User', :foreign_key => 'author_id' + attr_protected :data + + acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, + :description => :comments, + :datetime => :updated_on, + :type => 'wiki-page', + :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.page.wiki.project, :id => o.page.title, :version => o.version}} + + acts_as_activity_provider :type => 'wiki_edits', + :timestamp => "#{WikiContent.versioned_table_name}.updated_on", + :author_key => "#{WikiContent.versioned_table_name}.author_id", + :permission => :view_wiki_edits, + :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " + + "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " + + "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " + + "#{WikiContent.versioned_table_name}.id", + :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " + + "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " + + "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"} + + def text=(plain) + case Setting.wiki_compression + when 'gzip' + begin + self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION) + self.compression = 'gzip' + rescue + self.data = plain + self.compression = '' + end + else + self.data = plain + self.compression = '' + end + plain + end + + def text + @text ||= case compression + when 'gzip' + str = Zlib::Inflate.inflate(data) + str.force_encoding("UTF-8") if str.respond_to?(:force_encoding) + str + else + # uncompressed data + data + end + end + + def project + page.project + end + + # Return true if the content is the current page content + def current_version? + page.content.version == self.version + end + + # Returns the previous version or nil + def previous + @previous ||= WikiContent::Version.find(:first, + :order => 'version DESC', + :include => :author, + :conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version]) + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ee/ee581fa8b060e7dedfd4b98698527b98b2c543d6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ee/ee581fa8b060e7dedfd4b98698527b98b2c543d6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1059 @@ +# Vietnamese translation for Ruby on Rails +# by +# Do Hai Bac (dohaibac@gmail.com) +# Dao Thanh Ngoc (ngocdaothanh@gmail.com, http://github.com/ngocdaothanh/rails-i18n/tree/master) + +vi: + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "," + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "." + # Number of decimals, behind the separator (1 with a precision of 2 gives: 1.00) + precision: 3 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%n %u" + unit: "đồng" + # These three are to override number.format and are optional + separator: "," + delimiter: "." + precision: 2 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "30 giây" + less_than_x_seconds: + one: "chưa tới 1 giây" + other: "chưa tới %{count} giây" + x_seconds: + one: "1 giây" + other: "%{count} giây" + less_than_x_minutes: + one: "chưa tới 1 phút" + other: "chưa tới %{count} phút" + x_minutes: + one: "1 phút" + other: "%{count} phút" + about_x_hours: + one: "khoảng 1 giờ" + other: "khoảng %{count} giờ" + x_days: + one: "1 ngày" + other: "%{count} ngày" + about_x_months: + one: "khoảng 1 tháng" + other: "khoảng %{count} tháng" + x_months: + one: "1 tháng" + other: "%{count} tháng" + about_x_years: + one: "khoảng 1 năm" + other: "khoảng %{count} năm" + over_x_years: + one: "hơn 1 năm" + other: "hơn %{count} năm" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + prompts: + year: "Năm" + month: "Tháng" + day: "Ngày" + hour: "Giờ" + minute: "Phút" + second: "Giây" + + activerecord: + errors: + template: + header: + one: "1 lỗi ngăn không cho lưu %{model} này" + other: "%{count} lỗi ngăn không cho lưu %{model} này" + # The variable :count is also available + body: "Có lỗi với các mục sau:" + + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "không có trong danh sách" + exclusion: "đã được giành trước" + invalid: "không hợp lệ" + confirmation: "không khớp với xác nhận" + accepted: "phải được đồng ý" + empty: "không thể rỗng" + blank: "không thể để trắng" + too_long: "quá dài (tối đa %{count} ký tự)" + too_short: "quá ngắn (tối thiểu %{count} ký tự)" + wrong_length: "độ dài không đúng (phải là %{count} ký tự)" + taken: "đã có" + not_a_number: "không phải là số" + greater_than: "phải lớn hơn %{count}" + greater_than_or_equal_to: "phải lớn hơn hoặc bằng %{count}" + equal_to: "phải bằng %{count}" + less_than: "phải nhỏ hơn %{count}" + less_than_or_equal_to: "phải nhỏ hơn hoặc bằng %{count}" + odd: "phải là số chẵn" + even: "phải là số lẻ" + greater_than_start_date: "phải đi sau ngày bắt đầu" + not_same_project: "không thuộc cùng dự án" + circular_dependency: "quan hệ có thể gây ra lặp vô tận" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B, %Y" + + day_names: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"] + abbr_day_names: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, "Tháng một", "Tháng hai", "Tháng ba", "Tháng tư", "Tháng năm", "Tháng sáu", "Tháng bảy", "Tháng tám", "Tháng chín", "Tháng mười", "Tháng mười một", "Tháng mười hai"] + abbr_month_names: [~, "Tháng một", "Tháng hai", "Tháng ba", "Tháng tư", "Tháng năm", "Tháng sáu", "Tháng bảy", "Tháng tám", "Tháng chín", "Tháng mười", "Tháng mười một", "Tháng mười hai"] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "sáng" + pm: "chiều" + + # Used in array.to_sentence. + support: + array: + words_connector: ", " + two_words_connector: " và " + last_word_connector: ", và " + + actionview_instancetag_blank_option: Vui lòng chọn + + general_text_No: 'Không' + general_text_Yes: 'Có' + general_text_no: 'không' + general_text_yes: 'có' + general_lang_name: 'Tiếng Việt' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Cập nhật tài khoản thành công. + notice_account_invalid_creditentials: Tài khoản hoặc mật mã không hợp lệ + notice_account_password_updated: Cập nhật mật mã thành công. + notice_account_wrong_password: Sai mật mã + notice_account_register_done: Tài khoản được tạo thành công. Để kích hoạt vui lòng làm theo hướng dẫn trong email gửi đến bạn. + notice_account_unknown_email: Không rõ tài khoản. + notice_can_t_change_password: Tài khoản được chứng thực từ nguồn bên ngoài. Không thể đổi mật mã cho loại chứng thực này. + notice_account_lost_email_sent: Thông tin để đổi mật mã mới đã gửi đến bạn qua email. + notice_account_activated: Tài khoản vừa được kích hoạt. Bây giờ bạn có thể đăng nhập. + notice_successful_create: Tạo thành công. + notice_successful_update: Cập nhật thành công. + notice_successful_delete: Xóa thành công. + notice_successful_connection: Kết nối thành công. + notice_file_not_found: Trang bạn cố xem không tồn tại hoặc đã chuyển. + notice_locking_conflict: Thông tin đang được cập nhật bởi người khác. Hãy chép nội dung cập nhật của bạn vào clipboard. + notice_not_authorized: Bạn không có quyền xem trang này. + notice_email_sent: "Email đã được gửi tới %{value}" + notice_email_error: "Lỗi xảy ra khi gửi email (%{value})" + notice_feeds_access_key_reseted: Mã số chứng thực RSS đã được tạo lại. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." + notice_account_pending: "Thông tin tài khoản đã được tạo ra và đang chờ chứng thực từ ban quản trị." + notice_default_data_loaded: Đã nạp cấu hình mặc định. + notice_unable_delete_version: Không thể xóa phiên bản. + + error_can_t_load_default_data: "Không thể nạp cấu hình mặc định: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "Lỗi xảy ra khi truy cập vào kho lưu trữ: %{value}" + error_scm_annotate: "The entry does not exist or can not be annotated." + error_issue_not_found_in_project: 'Vấn đề không tồn tại hoặc không thuộc dự án' + + mail_subject_lost_password: "%{value}: mật mã của bạn" + mail_body_lost_password: "Để đổi mật mã, hãy click chuột vào liên kết sau:" + mail_subject_register: "%{value}: kích hoạt tài khoản" + mail_body_register: "Để kích hoạt tài khoản, hãy click chuột vào liên kết sau:" + mail_body_account_information_external: " Bạn có thể dùng tài khoản %{value} để đăng nhập." + mail_body_account_information: Thông tin về tài khoản + mail_subject_account_activation_request: "%{value}: Yêu cầu chứng thực tài khoản" + mail_body_account_activation_request: "Người dùng (%{value}) mới đăng ký và cần bạn xác nhận:" + mail_subject_reminder: "%{count} vấn đề hết hạn trong các %{days} ngày tới" + mail_body_reminder: "%{count} vấn đề gán cho bạn sẽ hết hạn trong %{days} ngày tới:" + + gui_validation_error: 1 lỗi + gui_validation_error_plural: "%{count} lỗi" + + field_name: Tên + field_description: Mô tả + field_summary: Tóm tắt + field_is_required: Bắt buộc + field_firstname: Tên lót + Tên + field_lastname: Họ + field_mail: Email + field_filename: Tập tin + field_filesize: Cỡ + field_downloads: Tải về + field_author: Tác giả + field_created_on: Tạo + field_updated_on: Cập nhật + field_field_format: Định dạng + field_is_for_all: Cho mọi dự án + field_possible_values: Giá trị hợp lệ + field_regexp: Biểu thức chính quy + field_min_length: Chiều dài tối thiểu + field_max_length: Chiều dài tối đa + field_value: Giá trị + field_category: Chủ đề + field_title: Tiêu đề + field_project: Dự án + field_issue: Vấn đề + field_status: Trạng thái + field_notes: Ghi chú + field_is_closed: Vấn đề đóng + field_is_default: Giá trị mặc định + field_tracker: Dòng vấn đề + field_subject: Chủ đề + field_due_date: Hết hạn + field_assigned_to: Gán cho + field_priority: Ưu tiên + field_fixed_version: Phiên bản + field_user: Người dùng + field_role: Quyền + field_homepage: Trang chủ + field_is_public: Công cộng + field_parent: Dự án con của + field_is_in_roadmap: Có thể thấy trong Kế hoạch + field_login: Đăng nhập + field_mail_notification: Thông báo qua email + field_admin: Quản trị + field_last_login_on: Kết nối cuối + field_language: Ngôn ngữ + field_effective_date: Ngày + field_password: Mật mã + field_new_password: Mật mã mới + field_password_confirmation: Khẳng định lại + field_version: Phiên bản + field_type: Kiểu + field_host: Host + field_port: Port + field_account: Tài khoản + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: On-the-fly user creation + field_start_date: Bắt đầu + field_done_ratio: Tiến độ + field_auth_source: Authentication mode + field_hide_mail: Không làm lộ email của bạn + field_comments: Bình luận + field_url: URL + field_start_page: Trang bắt đầu + field_subproject: Dự án con + field_hours: Giờ + field_activity: Hoạt động + field_spent_on: Ngày + field_identifier: Mã nhận dạng + field_is_filter: Dùng như một lọc + field_issue_to: Vấn đền liên quan + field_delay: Độ trễ + field_assignable: Vấn đề có thể gán cho vai trò này + field_redirect_existing_links: Chuyển hướng trang đã có + field_estimated_hours: Thời gian ước đoán + field_column_names: Cột + field_time_zone: Múi giờ + field_searchable: Tìm kiếm được + field_default_value: Giá trị mặc định + field_comments_sorting: Liệt kê bình luận + field_parent_title: Trang mẹ + + setting_app_title: Tựa đề ứng dụng + setting_app_subtitle: Tựa đề nhỏ của ứng dụng + setting_welcome_text: Thông điệp chào mừng + setting_default_language: Ngôn ngữ mặc định + setting_login_required: Cần đăng nhập + setting_self_registration: Tự chứng thực + setting_attachment_max_size: Cỡ tối đa của tập tin đính kèm + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Tạo bản CC bí mật (bcc) + setting_host_name: Tên miền và đường dẫn + setting_text_formatting: Định dạng bài viết + setting_wiki_compression: Wiki history compression + setting_feeds_limit: Giới hạn nội dung của feed + setting_default_projects_public: Dự án mặc định là công cộng + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Từ khóa tham khảo + setting_commit_fix_keywords: Từ khóa chỉ vấn đề đã giải quyết + setting_autologin: Tự động đăng nhập + setting_date_format: Định dạng ngày + setting_time_format: Định dạng giờ + setting_cross_project_issue_relations: Cho phép quan hệ chéo giữa các dự án + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_emails_footer: Chữ ký cuối thư + setting_protocol: Giao thức + setting_per_page_options: Objects per page options + setting_user_format: Định dạng hiển thị người dùng + setting_activity_days_default: Days displayed on project activity + setting_display_subprojects_issues: Display subprojects issues on main projects by default + setting_enabled_scm: Enabled SCM + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: Mã số API + setting_sequential_project_identifiers: Tự sinh chuỗi ID dự án + + project_module_issue_tracking: Theo dõi vấn đề + project_module_time_tracking: Theo dõi thời gian + project_module_news: Tin tức + project_module_documents: Tài liệu + project_module_files: Tập tin + project_module_wiki: Wiki + project_module_repository: Kho lưu trữ + project_module_boards: Diễn đàn + + label_user: Tài khoản + label_user_plural: Tài khoản + label_user_new: Tài khoản mới + label_project: Dự án + label_project_new: Dự án mới + label_project_plural: Dự án + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Mọi dự án + label_project_latest: Dự án mới nhất + label_issue: Vấn đề + label_issue_new: Tạo vấn đề mới + label_issue_plural: Vấn đề + label_issue_view_all: Tất cả vấn đề + label_issues_by: "Vấn đề của %{value}" + label_issue_added: Đã thêm vấn đề + label_issue_updated: Vấn đề được cập nhật + label_document: Tài liệu + label_document_new: Tài liệu mới + label_document_plural: Tài liệu + label_document_added: Đã thêm tài liệu + label_role: Vai trò + label_role_plural: Vai trò + label_role_new: Vai trò mới + label_role_and_permissions: Vai trò và Quyền hạn + label_member: Thành viên + label_member_new: Thành viên mới + label_member_plural: Thành viên + label_tracker: Dòng vấn đề + label_tracker_plural: Dòng vấn đề + label_tracker_new: Tạo dòng vấn đề mới + label_workflow: Workflow + label_issue_status: Issue status + label_issue_status_plural: Issue statuses + label_issue_status_new: New status + label_issue_category: Chủ đề + label_issue_category_plural: Chủ đề + label_issue_category_new: Chủ đề mới + label_custom_field: Custom field + label_custom_field_plural: Custom fields + label_custom_field_new: New custom field + label_enumerations: Enumerations + label_enumeration_new: New value + label_information: Thông tin + label_information_plural: Thông tin + label_please_login: Vui lòng đăng nhập + label_register: Đăng ký + label_password_lost: Phục hồi mật mã + label_home: Trang chính + label_my_page: Trang riêng + label_my_account: Cá nhân + label_my_projects: Dự án của bạn + label_administration: Quản trị + label_login: Đăng nhập + label_logout: Thoát + label_help: Giúp đỡ + label_reported_issues: Vấn đề đã báo cáo + label_assigned_to_me_issues: Vấn đề gán cho bạn + label_last_login: Kết nối cuối + label_registered_on: Ngày tham gia + label_activity: Hoạt động + label_overall_activity: Tất cả hoạt động + label_new: Mới + label_logged_as: Tài khoản » + label_environment: Environment + label_authentication: Authentication + label_auth_source: Authentication mode + label_auth_source_new: New authentication mode + label_auth_source_plural: Authentication modes + label_subproject_plural: Dự án con + label_and_its_subprojects: "%{value} và dự án con" + label_min_max_length: Min - Max length + label_list: List + label_date: Ngày + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Attribute + label_attribute_plural: Attributes + label_download: "%{count} lần tải" + label_download_plural: "%{count} lần tải" + label_no_data: Chưa có thông tin gì + label_change_status: Đổi trạng thái + label_history: Lược sử + label_attachment: Tập tin + label_attachment_new: Thêm tập tin mới + label_attachment_delete: Xóa tập tin + label_attachment_plural: Tập tin + label_file_added: Đã thêm tập tin + label_report: Báo cáo + label_report_plural: Báo cáo + label_news: Tin tức + label_news_new: Thêm tin + label_news_plural: Tin tức + label_news_latest: Tin mới + label_news_view_all: Xem mọi tin + label_news_added: Đã thêm tin + label_settings: Thiết lập + label_overview: Tóm tắt + label_version: Phiên bản + label_version_new: Phiên bản mới + label_version_plural: Phiên bản + label_confirmation: Khẳng định + label_export_to: 'Định dạng khác của trang này:' + label_read: Read... + label_public_projects: Các dự án công cộng + label_open_issues: mở + label_open_issues_plural: mở + label_closed_issues: đóng + label_closed_issues_plural: đóng + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Tổng cộng + label_permissions: Quyền + label_current_status: Trạng thái hiện tại + label_new_statuses_allowed: Trạng thái mới được phép + label_all: tất cả + label_none: không + label_nobody: Chẳng ai + label_next: Sau + label_previous: Trước + label_used_by: Used by + label_details: Chi tiết + label_add_note: Thêm ghi chú + label_per_page: Mỗi trang + label_calendar: Lịch + label_months_from: tháng từ + label_gantt: Biểu đồ sự kiện + label_internal: Nội bộ + label_last_changes: "%{count} thay đổi cuối" + label_change_view_all: Xem mọi thay đổi + label_personalize_page: Điều chỉnh trang này + label_comment: Bình luận + label_comment_plural: Bình luận + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Thêm bình luận + label_comment_added: Đã thêm bình luận + label_comment_delete: Xóa bình luận + label_query: Truy vấn riêng + label_query_plural: Truy vấn riêng + label_query_new: Truy vấn mới + label_filter_add: Thêm lọc + label_filter_plural: Bộ lọc + label_equals: là + label_not_equals: không là + label_in_less_than: ít hơn + label_in_more_than: nhiều hơn + label_in: trong + label_today: hôm nay + label_all_time: mọi thời gian + label_yesterday: hôm qua + label_this_week: tuần này + label_last_week: tuần trước + label_last_n_days: "%{count} ngày cuối" + label_this_month: tháng này + label_last_month: tháng cuối + label_this_year: năm này + label_date_range: Thời gian + label_less_than_ago: cách đây dưới + label_more_than_ago: cách đây hơn + label_ago: cách đây + label_contains: chứa + label_not_contains: không chứa + label_day_plural: ngày + label_repository: Kho lưu trữ + label_repository_plural: Kho lưu trữ + label_browse: Duyệt + label_modification: "%{count} thay đổi" + label_modification_plural: "%{count} thay đổi" + label_revision: Bản điều chỉnh + label_revision_plural: Bản điều chỉnh + label_associated_revisions: Associated revisions + label_added: thêm + label_modified: đổi + label_copied: chép + label_renamed: đổi tên + label_deleted: xóa + label_latest_revision: Bản điều chỉnh cuối cùng + label_latest_revision_plural: Bản điều chỉnh cuối cùng + label_view_revisions: Xem các bản điều chỉnh + label_max_size: Dung lượng tối đa + label_sort_highest: Lên trên cùng + label_sort_higher: Dịch lên + label_sort_lower: Dịch xuống + label_sort_lowest: Xuống dưới cùng + label_roadmap: Kế hoạch + label_roadmap_due_in: "Hết hạn trong %{value}" + label_roadmap_overdue: "Trễ %{value}" + label_roadmap_no_issues: Không có vấn đề cho phiên bản này + label_search: Tìm + label_result_plural: Kết quả + label_all_words: Mọi từ + label_wiki: Wiki + label_wiki_edit: Wiki edit + label_wiki_edit_plural: Thay đổi wiki + label_wiki_page: Trang wiki + label_wiki_page_plural: Trang wiki + label_index_by_title: Danh sách theo tên + label_index_by_date: Danh sách theo ngày + label_current_version: Bản hiện tại + label_preview: Xem trước + label_feed_plural: Feeds + label_changes_details: Chi tiết của mọi thay đổi + label_issue_tracking: Vấn đề + label_spent_time: Thời gian + label_f_hour: "%{value} giờ" + label_f_hour_plural: "%{value} giờ" + label_time_tracking: Theo dõi thời gian + label_change_plural: Thay đổi + label_statistics: Thống kê + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_view_diff: So sánh + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Tùy chọn + label_copy_workflow_from: Copy workflow from + label_permissions_report: Thống kê các quyền + label_watched_issues: Chủ đề đang theo dõi + label_related_issues: Liên quan + label_applied_status: Trạng thái áp dụng + label_loading: Đang xử lý... + label_relation_new: Quan hệ mới + label_relation_delete: Xóa quan hệ + label_relates_to: liên quan + label_duplicates: trùng với + label_duplicated_by: bị trùng bởi + label_blocks: chặn + label_blocked_by: chặn bởi + label_precedes: đi trước + label_follows: đi sau + label_end_to_start: cuối tới đầu + label_end_to_end: cuối tới cuối + label_start_to_start: đầu tớ đầu + label_start_to_end: đầu tới cuối + label_stay_logged_in: Lưu thông tin đăng nhập + label_disabled: bị vô hiệu + label_show_completed_versions: Xem phiên bản đã xong + label_me: tôi + label_board: Diễn đàn + label_board_new: Tạo diễn đàn mới + label_board_plural: Diễn đàn + label_topic_plural: Chủ đề + label_message_plural: Diễn đàn + label_message_last: Bài cuối + label_message_new: Tạo bài mới + label_message_posted: Đã thêm bài viết + label_reply_plural: Hồi âm + label_send_information: Gửi thông tin đến người dùng qua email + label_year: Năm + label_month: Tháng + label_week: Tuần + label_date_from: Từ + label_date_to: Đến + label_language_based: Theo ngôn ngữ người dùng + label_sort_by: "Sắp xếp theo %{value}" + label_send_test_email: Send a test email + label_feeds_access_key_created_on: "Mã chứng thực RSS được tạo ra cách đây %{value}" + label_module_plural: Mô-đun + label_added_time_by: "thêm bởi %{author} cách đây %{age}" + label_updated_time: "Cập nhật cách đây %{value}" + label_jump_to_a_project: Nhảy đến dự án... + label_file_plural: Tập tin + label_changeset_plural: Thay đổi + label_default_columns: Cột mặc định + label_no_change_option: (không đổi) + label_bulk_edit_selected_issues: Sửa nhiều vấn đề + label_theme: Giao diện + label_default: Mặc định + label_search_titles_only: Chỉ tìm trong tựa đề + label_user_mail_option_all: "Mọi sự kiện trên mọi dự án của bạn" + label_user_mail_option_selected: "Mọi sự kiện trên các dự án được chọn..." + label_user_mail_no_self_notified: "Đừng gửi email về các thay đổi do chính bạn thực hiện" + label_registration_activation_by_email: account activation by email + label_registration_manual_activation: manual account activation + label_registration_automatic_activation: automatic account activation + label_display_per_page: "mỗi trang: %{value}" + label_age: Age + label_change_properties: Thay đổi thuộc tính + label_general: Tổng quan + label_more: Chi tiết + label_scm: SCM + label_plugins: Mô-đun + label_ldap_authentication: Chứng thực LDAP + label_downloads_abbr: Tải về + label_optional_description: Mô tả bổ sung + label_add_another_file: Thêm tập tin khác + label_preferences: Cấu hình + label_chronological_order: Bài cũ xếp trước + label_reverse_chronological_order: Bài mới xếp trước + label_planning: Kế hoạch + label_incoming_emails: Nhận mail + label_generate_key: Tạo mã + label_issue_watchers: Theo dõi + + button_login: Đăng nhập + button_submit: Gửi + button_save: Lưu + button_check_all: Đánh dấu tất cả + button_uncheck_all: Bỏ dấu tất cả + button_delete: Xóa + button_create: Tạo + button_test: Kiểm tra + button_edit: Sửa + button_add: Thêm + button_change: Đổi + button_apply: Áp dụng + button_clear: Xóa + button_lock: Khóa + button_unlock: Mở khóa + button_download: Tải về + button_list: Liệt kê + button_view: Xem + button_move: Chuyển + button_back: Quay lại + button_cancel: Bỏ qua + button_activate: Kích hoạt + button_sort: Sắp xếp + button_log_time: Thêm thời gian + button_rollback: Quay trở lại phiên bản này + button_watch: Theo dõi + button_unwatch: Bỏ theo dõi + button_reply: Trả lời + button_archive: Đóng băng + button_unarchive: Xả băng + button_reset: Tạo lại + button_rename: Đổi tên + button_change_password: Đổi mật mã + button_copy: Chép + button_annotate: Chú giải + button_update: Cập nhật + button_configure: Cấu hình + button_quote: Trích dẫn + + status_active: hoạt động + status_registered: đăng ký + status_locked: khóa + + text_select_mail_notifications: Chọn hành động đối với mỗi email thông báo sẽ gửi. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 để chỉ không hạn chế + text_project_destroy_confirmation: Are you sure you want to delete this project and related data ? + text_subprojects_destroy_warning: "Its subproject(s): %{value} will be also deleted." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Bạn chắc chứ? + text_tip_issue_begin_day: ngày bắt đầu + text_tip_issue_end_day: ngày kết thúc + text_tip_issue_begin_end_day: bắt đầu và kết thúc cùng ngày + text_project_identifier_info: 'Chỉ cho phép chữ cái thường (a-z), con số và dấu gạch ngang.
    Sau khi lưu, chỉ số ID không thể thay đổi.' + text_caracters_maximum: "Tối đa %{count} ký tự." + text_caracters_minimum: "Phải gồm ít nhất %{count} ký tự." + text_length_between: "Length between %{min} and %{max} characters." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Ký tự không hợp lệ + text_comma_separated: Multiple values allowed (comma separated). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ? + text_issue_category_destroy_question: "Some issues (%{count}) are assigned to this category. What do you want to do ?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Reassign issues to this category + text_user_mail_option: "Với các dự án không được chọn, bạn chỉ có thể nhận được thông báo về các vấn đề bạn đăng ký theo dõi hoặc có liên quan đến bạn (chẳng hạn, vấn đề được gán cho bạn)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' + text_select_project_modules: 'Chọn các mô-đun cho dự án:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: File repository writable + text_rmagick_available: RMagick available (optional) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do ?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Assign reported hours to the project + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} wrote:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + + default_role_manager: Điều hành + default_role_developer: Phát triển + default_role_reporter: Báo cáo + default_tracker_bug: Lỗi + default_tracker_feature: Tính năng + default_tracker_support: Hỗ trợ + default_issue_status_new: Mới + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Quyết tâm + default_issue_status_feedback: Phản hồi + default_issue_status_closed: Đóng + default_issue_status_rejected: Từ chối + default_doc_category_user: Tài liệu người dùng + default_doc_category_tech: Tài liệu kỹ thuật + default_priority_low: Thấp + default_priority_normal: Bình thường + default_priority_high: Cao + default_priority_urgent: Khẩn cấp + default_priority_immediate: Trung bình + default_activity_design: Thiết kế + default_activity_development: Phát triển + + enumeration_issue_priorities: Mức độ ưu tiên vấn đề + enumeration_doc_categories: Chủ đề tài liệu + enumeration_activities: Hoạt động (theo dõi thời gian) + + setting_plain_text_mail: mail dạng text đơn giản (không dùng HTML) + setting_gravatar_enabled: Dùng biểu tượng Gravatar + permission_edit_project: Chỉnh dự án + permission_select_project_modules: Chọn mô-đun + permission_manage_members: Quản lý thành viên + permission_manage_versions: Quản lý phiên bản + permission_manage_categories: Quản lý chủ đề + permission_add_issues: Thêm vấn đề + permission_edit_issues: Sửa vấn đề + permission_manage_issue_relations: Quản lý quan hệ vấn đề + permission_add_issue_notes: Thêm chú thích + permission_edit_issue_notes: Sửa chú thích + permission_edit_own_issue_notes: Sửa chú thích cá nhân + permission_move_issues: Chuyển vấn đề + permission_delete_issues: Xóa vấn đề + permission_manage_public_queries: Quản lý truy cấn công cộng + permission_save_queries: Lưu truy vấn + permission_view_gantt: Xem biểu đồ sự kiện + permission_view_calendar: Xem lịch + permission_view_issue_watchers: Xem các người theo dõi + permission_add_issue_watchers: Thêm người theo dõi + permission_log_time: Lưu thời gian đã tốn + permission_view_time_entries: Xem thời gian đã tốn + permission_edit_time_entries: Xem nhật ký thời gian + permission_edit_own_time_entries: Sửa thời gian đã lưu + permission_manage_news: Quản lý tin mới + permission_comment_news: Chú thích vào tin mới + permission_manage_documents: Quản lý tài liệu + permission_view_documents: Xem tài liệu + permission_manage_files: Quản lý tập tin + permission_view_files: Xem tập tin + permission_manage_wiki: Quản lý wiki + permission_rename_wiki_pages: Đổi tên trang wiki + permission_delete_wiki_pages: Xóa trang wiki + permission_view_wiki_pages: Xem wiki + permission_view_wiki_edits: Xem lược sử trang wiki + permission_edit_wiki_pages: Sửa trang wiki + permission_delete_wiki_pages_attachments: Xóa tệp đính kèm + permission_protect_wiki_pages: Bảo vệ trang wiki + permission_manage_repository: Quản lý kho lưu trữ + permission_browse_repository: Duyệt kho lưu trữ + permission_view_changesets: Xem các thay đổi + permission_commit_access: Truy cập commit + permission_manage_boards: Quản lý diễn đàn + permission_view_messages: Xem bài viết + permission_add_messages: Gửi bài viết + permission_edit_messages: Sửa bài viết + permission_edit_own_messages: Sửa bài viết cá nhân + permission_delete_messages: Xóa bài viết + permission_delete_own_messages: Xóa bài viết cá nhân + label_example: Ví dụ + text_repository_usernames_mapping: "Chọn hoặc cập nhật ánh xạ người dùng hệ thống với người dùng trong kho lưu trữ.\nNhững trường hợp trùng hợp về tên và email sẽ được tự động ánh xạ." + permission_delete_own_messages: Delete own messages + label_user_activity: "%{value}'s activity" + label_updated_time_by: "Updated by %{author} %{age} ago" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} file(s) could not be saved." + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + label_display: Display + field_editable: Editable + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + text_are_you_sure_with_children: Delete issue and all child issues? + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_emails_header: Emails header + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ee/ee6b6a39234616226f687b8f7fcd84a83a19a1fa.svn-base Binary file .svn/pristine/ee/ee6b6a39234616226f687b8f7fcd84a83a19a1fa.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ee/ee7fe9ed41ae5054b215eb20ccb460e8dc835ca3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ee/ee7fe9ed41ae5054b215eb20ccb460e8dc835ca3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +--- +user_preferences_001: + others: | + --- + :my_page_layout: + left: + - latestnews + - documents + right: + - issuesassignedtome + top: + - calendar + + id: 1 + user_id: 1 + hide_mail: true +user_preferences_002: + others: | + --- + :my_page_layout: + left: + - latestnews + - documents + right: + - issuesassignedtome + top: + - calendar + + id: 2 + user_id: 3 + hide_mail: false \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ee/ee91666670aba00b7f7c1bef0863d52fe4dac26b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ee/ee91666670aba00b7f7c1bef0863d52fe4dac26b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class Board < ActiveRecord::Base + generator_for :name, :start => 'A Forum' + generator_for :description, :start => 'Some description here' + generator_for :project, :method => :generate_project + + def self.generate_project + Project.generate! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ee/eeae244657a9490b90284a25f402eeaf38cbe9f8.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ee/eeae244657a9490b90284a25f402eeaf38cbe9f8.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar МК language +// Author: Ilin Tatabitovski, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("недела", + "понеделник", + "вторник", + "среда", + "четврток", + "петок", + "сабота", + "недела"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("нед", + "пон", + "вто", + "сре", + "чет", + "пет", + "саб", + "нед"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("јануари", + "февруари", + "март", + "април", + "мај", + "јуни", + "јули", + "август", + "септември", + "октомври", + "ноември", + "декември"); + +// short month names +Calendar._SMN = new Array +("јан", + "фев", + "мар", + "апр", + "мај", + "јун", + "јул", + "авг", + "сеп", + "окт", + "ное", + "дек"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "За календарот"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"За последна верзија посети: http://www.dynarch.com/projects/calendar/\n" + +"Дистрибуирано под GNU LGPL. Види http://gnu.org/licenses/lgpl.html за детали." + +"\n\n" + +"Бирање на дата:\n" + +"- Користи ги \xab, \xbb копчињата за да избереш година\n" + +"- Користи ги " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " копчињата за да избере месеци\n" + +"- Држи го притиснато копчето на глувчето на било кое копче за побрзо бирање."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Бирање на време:\n" + +"- Клик на временските делови за да го зголемиш\n" + +"- или Shift-клик да го намалиш\n" + +"- или клик и влечи за побрзо бирање."; + +Calendar._TT["PREV_YEAR"] = "Претходна година (држи за мени)"; +Calendar._TT["PREV_MONTH"] = "Претходен месец (држи за мени)"; +Calendar._TT["GO_TODAY"] = "Go Today"; +Calendar._TT["NEXT_MONTH"] = "Следен месец (држи за мени)"; +Calendar._TT["NEXT_YEAR"] = "Следна година (држи за мени)"; +Calendar._TT["SEL_DATE"] = "Избери дата"; +Calendar._TT["DRAG_TO_MOVE"] = "Влечи да поместиш"; +Calendar._TT["PART_TODAY"] = " (денес)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Прикажи %s прво"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Затвори"; +Calendar._TT["TODAY"] = "Денес"; +Calendar._TT["TIME_PART"] = "(Shift-)Клик или влечи за да промениш вредност"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; + +Calendar._TT["WK"] = "нед"; +Calendar._TT["TIME"] = "Време:"; + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ee/eeb4e06614636c29295cbb5c3157a7ad6e968c68.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ee/eeb4e06614636c29295cbb5c3157a7ad6e968c68.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

    This is a test email sent by Redmine.
    +Redmine URL: <%= auto_link(@url) %>

    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ef/ef0ad884b2ab9390065781b55804cce0528e385a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ef/ef0ad884b2ab9390065781b55804cce0528e385a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +class CreateRepositories < ActiveRecord::Migration + def self.up + create_table :repositories, :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "url", :string, :default => "", :null => false + end + end + + def self.down + drop_table :repositories + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ef/ef19c67700749f66ae99f78b3003842af950afbb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ef/ef19c67700749f66ae99f78b3003842af950afbb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +module <%= class_name %>Helper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ef/ef4c5661c208a7359f12e42ccebb8f0971172087.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ef/ef4c5661c208a7359f12e42ccebb8f0971172087.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,236 @@ +--- +attachments_001: + created_on: 2006-07-19 21:07:27 +02:00 + downloads: 0 + content_type: text/plain + disk_filename: 060719210727_error281.txt + container_id: 3 + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 1 + container_type: Issue + filesize: 28 + filename: error281.txt + author_id: 2 +attachments_002: + created_on: 2007-01-27 15:08:27 +01:00 + downloads: 0 + content_type: text/plain + disk_filename: 060719210727_document.txt + container_id: 1 + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 2 + container_type: Document + filesize: 28 + filename: document.txt + author_id: 2 +attachments_003: + created_on: 2006-07-19 21:07:27 +02:00 + downloads: 0 + content_type: image/gif + disk_filename: 060719210727_logo.gif + container_id: 4 + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 3 + container_type: WikiPage + filesize: 280 + filename: logo.gif + description: This is a logo + author_id: 2 +attachments_004: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 3 + downloads: 0 + disk_filename: 060719210727_source.rb + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 4 + filesize: 153 + filename: source.rb + author_id: 2 + description: This is a Ruby source file + content_type: application/x-ruby +attachments_005: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 3 + downloads: 0 + disk_filename: 060719210727_changeset_iso8859-1.diff + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 5 + filesize: 687 + filename: changeset_iso8859-1.diff + author_id: 2 + content_type: text/x-diff +attachments_006: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 3 + downloads: 0 + disk_filename: 060719210727_archive.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 6 + filesize: 157 + filename: archive.zip + author_id: 2 + content_type: application/octet-stream +attachments_007: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 4 + downloads: 0 + disk_filename: 060719210727_archive.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 7 + filesize: 157 + filename: archive.zip + author_id: 1 + content_type: application/octet-stream +attachments_008: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Project + container_id: 1 + downloads: 0 + disk_filename: 060719210727_project_file.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 8 + filesize: 320 + filename: project_file.zip + author_id: 2 + content_type: application/octet-stream +attachments_009: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Version + container_id: 1 + downloads: 0 + disk_filename: 060719210727_archive.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 9 + filesize: 452 + filename: version_file.zip + author_id: 2 + content_type: application/octet-stream +attachments_010: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 2 + downloads: 0 + disk_filename: 060719210727_picture.jpg + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 10 + filesize: 452 + filename: picture.jpg + author_id: 2 + content_type: image/jpeg +attachments_011: + created_on: 2007-02-12 15:08:27 +01:00 + container_type: Document + container_id: 1 + downloads: 0 + disk_filename: 060719210727_picture.jpg + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 11 + filesize: 452 + filename: picture.jpg + author_id: 2 + content_type: image/jpeg +attachments_012: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Version + container_id: 1 + downloads: 0 + disk_filename: 060719210727_version_file.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 12 + filesize: 452 + filename: version_file.zip + author_id: 2 + content_type: application/octet-stream +attachments_013: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Message + container_id: 1 + downloads: 0 + disk_filename: 060719210727_foo.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 13 + filesize: 452 + filename: foo.zip + author_id: 2 + content_type: application/octet-stream +attachments_014: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 3 + downloads: 0 + disk_filename: 060719210727_changeset_utf8.diff + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 14 + filesize: 687 + filename: changeset_utf8.diff + author_id: 2 + content_type: text/x-diff +attachments_015: + id: 15 + created_on: 2010-07-19 21:07:27 +02:00 + container_type: Issue + container_id: 14 + downloads: 0 + disk_filename: 060719210727_changeset_utf8.diff + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + filesize: 687 + filename: private.diff + author_id: 2 + content_type: text/x-diff + description: attachement of a private issue +attachments_016: + content_type: image/png + downloads: 0 + created_on: 2010-11-23 16:14:50 +09:00 + disk_filename: 101123161450_testfile_1.png + container_id: 14 + digest: 8e0294de2441577c529f170b6fb8f638 + id: 16 + container_type: Issue + description: "" + filename: testfile.png + filesize: 2654 + author_id: 2 +attachments_017: + content_type: image/png + downloads: 0 + created_on: 2010-12-23 16:14:50 +09:00 + disk_filename: 101223161450_testfile_2.png + container_id: 14 + digest: 6bc2963e8d7ea0d3e68d12d1fba3d6ca + id: 17 + container_type: Issue + description: "" + filename: testfile.PNG + filesize: 3582 + author_id: 2 +attachments_018: + content_type: image/png + downloads: 0 + created_on: 2011-01-23 16:14:50 +09:00 + disk_filename: 101123161450_testfile_1.png + container_id: 14 + digest: 8e0294de2441577c529f170b6fb8f638 + id: 18 + container_type: Issue + description: "" + filename: testテスト.png + filesize: 2654 + author_id: 2 +attachments_019: + content_type: image/png + downloads: 0 + created_on: 2011-02-23 16:14:50 +09:00 + disk_filename: 101223161450_testfile_2.png + container_id: 14 + digest: 6bc2963e8d7ea0d3e68d12d1fba3d6ca + id: 19 + container_type: Issue + description: "" + filename: Testテスト.PNG + filesize: 3582 + author_id: 2 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ef/ef517b0f444a2761c3220f0aac6f60bccf22e592.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ef/ef517b0f444a2761c3220f0aac6f60bccf22e592.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,233 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AA afii57636 +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00D7 multiply +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD sfthyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 middot +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00F7 divide +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+05B0 afii57799 +!C1 U+05B1 afii57801 +!C2 U+05B2 afii57800 +!C3 U+05B3 afii57802 +!C4 U+05B4 afii57793 +!C5 U+05B5 afii57794 +!C6 U+05B6 afii57795 +!C7 U+05B7 afii57798 +!C8 U+05B8 afii57797 +!C9 U+05B9 afii57806 +!CB U+05BB afii57796 +!CC U+05BC afii57807 +!CD U+05BD afii57839 +!CE U+05BE afii57645 +!CF U+05BF afii57841 +!D0 U+05C0 afii57842 +!D1 U+05C1 afii57804 +!D2 U+05C2 afii57803 +!D3 U+05C3 afii57658 +!D4 U+05F0 afii57716 +!D5 U+05F1 afii57717 +!D6 U+05F2 afii57718 +!D7 U+05F3 gereshhebrew +!D8 U+05F4 gershayimhebrew +!E0 U+05D0 afii57664 +!E1 U+05D1 afii57665 +!E2 U+05D2 afii57666 +!E3 U+05D3 afii57667 +!E4 U+05D4 afii57668 +!E5 U+05D5 afii57669 +!E6 U+05D6 afii57670 +!E7 U+05D7 afii57671 +!E8 U+05D8 afii57672 +!E9 U+05D9 afii57673 +!EA U+05DA afii57674 +!EB U+05DB afii57675 +!EC U+05DC afii57676 +!ED U+05DD afii57677 +!EE U+05DE afii57678 +!EF U+05DF afii57679 +!F0 U+05E0 afii57680 +!F1 U+05E1 afii57681 +!F2 U+05E2 afii57682 +!F3 U+05E3 afii57683 +!F4 U+05E4 afii57684 +!F5 U+05E5 afii57685 +!F6 U+05E6 afii57686 +!F7 U+05E7 afii57687 +!F8 U+05E8 afii57688 +!F9 U+05E9 afii57689 +!FA U+05EA afii57690 +!FD U+200E afii299 +!FE U+200F afii300 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ef/ef80ce8432516a72f8cb74cf9b450950a64ab182.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ef/ef80ce8432516a72f8cb74cf9b450950a64ab182.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +render_api_attachment(@attachment, api) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ef/efdcfd2d94fd0bcb04b7cf4a72bebfe621b1194f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ef/efdcfd2d94fd0bcb04b7cf4a72bebfe621b1194f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,324 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class TimelogController < ApplicationController + menu_item :issues + before_filter :find_project, :only => [:new, :create] + before_filter :find_time_entry, :only => [:show, :edit, :update] + before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => [:index] + accept_rss_auth :index + accept_api_auth :index, :show, :create, :update, :destroy + + helper :sort + include SortHelper + helper :issues + include TimelogHelper + helper :custom_fields + include CustomFieldsHelper + + def index + sort_init 'spent_on', 'desc' + sort_update 'spent_on' => 'spent_on', + 'user' => 'user_id', + 'activity' => 'activity_id', + 'project' => "#{Project.table_name}.name", + 'issue' => 'issue_id', + 'hours' => 'hours' + + cond = ARCondition.new + if @issue + cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" + elsif @project + cond << @project.project_condition(Setting.display_subprojects_issues?) + end + + retrieve_date_range + cond << ['spent_on BETWEEN ? AND ?', @from, @to] + + respond_to do |format| + format.html { + # Paginate results + @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions) + @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] + @entries = TimeEntry.visible.find(:all, + :include => [:project, :activity, :user, {:issue => :tracker}], + :conditions => cond.conditions, + :order => sort_clause, + :limit => @entry_pages.items_per_page, + :offset => @entry_pages.current.offset) + @total_hours = TimeEntry.visible.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f + + render :layout => !request.xhr? + } + format.api { + @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions) + @offset, @limit = api_offset_and_limit + @entries = TimeEntry.visible.find(:all, + :include => [:project, :activity, :user, {:issue => :tracker}], + :conditions => cond.conditions, + :order => sort_clause, + :limit => @limit, + :offset => @offset) + } + format.atom { + entries = TimeEntry.visible.find(:all, + :include => [:project, :activity, :user, {:issue => :tracker}], + :conditions => cond.conditions, + :order => "#{TimeEntry.table_name}.created_on DESC", + :limit => Setting.feeds_limit.to_i) + render_feed(entries, :title => l(:label_spent_time)) + } + format.csv { + # Export all entries + @entries = TimeEntry.visible.find(:all, + :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], + :conditions => cond.conditions, + :order => sort_clause) + send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv') + } + end + end + + def show + respond_to do |format| + # TODO: Implement html response + format.html { render :nothing => true, :status => 406 } + format.api + end + end + + def new + @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) + @time_entry.attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + render :action => 'edit' + end + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create + @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) + @time_entry.attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + + if @time_entry.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default :action => 'index', :project_id => @time_entry.project + } + format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@time_entry) } + end + end + end + + def edit + @time_entry.attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + end + + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + def update + @time_entry.attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + + if @time_entry.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default :action => 'index', :project_id => @time_entry.project + } + format.api { head :ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@time_entry) } + end + end + end + + def bulk_edit + @available_activities = TimeEntryActivity.shared.active + @custom_fields = TimeEntry.first.available_custom_fields + end + + def bulk_update + attributes = parse_params_for_bulk_time_entry_attributes(params) + + unsaved_time_entry_ids = [] + @time_entries.each do |time_entry| + time_entry.reload + time_entry.attributes = attributes + call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) + unless time_entry.save + # Keep unsaved time_entry ids to display them in flash error + unsaved_time_entry_ids << time_entry.id + end + end + set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids) + redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first}) + end + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } + def destroy + @time_entries.each do |t| + begin + unless t.destroy && t.destroyed? + respond_to do |format| + format.html { + flash[:error] = l(:notice_unable_delete_time_entry) + redirect_to :back + } + format.api { render_validation_errors(t) } + end + return + end + rescue ::ActionController::RedirectBackError + redirect_to :action => 'index', :project_id => @projects.first + return + end + end + + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_delete) + redirect_back_or_default(:action => 'index', :project_id => @projects.first) + } + format.api { head :ok } + end + end + +private + def find_time_entry + @time_entry = TimeEntry.find(params[:id]) + unless @time_entry.editable_by?(User.current) + render_403 + return false + end + @project = @time_entry.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_time_entries + @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @time_entries.empty? + @projects = @time_entries.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + rescue ActiveRecord::RecordNotFound + render_404 + end + + def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids) + if unsaved_time_entry_ids.empty? + flash[:notice] = l(:notice_successful_update) unless time_entries.empty? + else + flash[:error] = l(:notice_failed_to_save_time_entries, + :count => unsaved_time_entry_ids.size, + :total => time_entries.size, + :ids => '#' + unsaved_time_entry_ids.join(', #')) + end + end + + def find_project + if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? + @issue = Issue.find(issue_id) + @project = @issue.project + elsif (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present? + @project = Project.find(project_id) + else + render_404 + return false + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_optional_project + if !params[:issue_id].blank? + @issue = Issue.find(params[:issue_id]) + @project = @issue.project + elsif !params[:project_id].blank? + @project = Project.find(params[:project_id]) + end + deny_access unless User.current.allowed_to?(:view_time_entries, @project, :global => true) + end + + # Retrieves the date range based on predefined ranges or specific from/to param dates + def retrieve_date_range + @free_period = false + @from, @to = nil, nil + + if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?) + case params[:period].to_s + when 'today' + @from = @to = Date.today + when 'yesterday' + @from = @to = Date.today - 1 + when 'current_week' + @from = Date.today - (Date.today.cwday - 1)%7 + @to = @from + 6 + when 'last_week' + @from = Date.today - 7 - (Date.today.cwday - 1)%7 + @to = @from + 6 + when '7_days' + @from = Date.today - 7 + @to = Date.today + when 'current_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) + @to = (@from >> 1) - 1 + when 'last_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) << 1 + @to = (@from >> 1) - 1 + when '30_days' + @from = Date.today - 30 + @to = Date.today + when 'current_year' + @from = Date.civil(Date.today.year, 1, 1) + @to = Date.civil(Date.today.year, 12, 31) + end + elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?)) + begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end + begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end + @free_period = true + else + # default + end + + @from, @to = @to, @from if @from && @to && @from > @to + @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) + @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) + end + + def parse_params_for_bulk_time_entry_attributes(params) + attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] + attributes + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f036a37a46cad981a63df7b8fce61d2e4da796f3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f036a37a46cad981a63df7b8fce61d2e4da796f3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,312 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class BazaarAdapter < AbstractAdapter + + # Bazaar executable name + BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr" + + class << self + def client_command + @@bin ||= BZR_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + !client_version.empty? + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + # Get info about the repository + def info + cmd_args = %w|revno| + cmd_args << bzr_target('') + info = nil + scm_cmd(*cmd_args) do |io| + if io.read =~ %r{^(\d+)\r?$} + info = Info.new({:root_url => url, + :lastrev => Revision.new({ + :identifier => $1 + }) + }) + end + end + info + rescue ScmCommandAborted + return nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + path ||= '' + entries = Entries.new + identifier = -1 unless identifier && identifier.to_i > 0 + cmd_args = %w|ls -v --show-ids| + cmd_args << "-r#{identifier.to_i}" + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + prefix = "#{url}/#{path}".gsub('\\', '/') + logger.debug "PREFIX: #{prefix}" + re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$} + io.each_line do |line| + next unless line =~ re + entries << Entry.new({:name => $3.strip, + :path => ((path.empty? ? "" : "#{path}/") + $3.strip), + :kind => ($4.blank? ? 'file' : 'dir'), + :size => nil, + :lastrev => Revision.new(:revision => $5.strip) + }) + end + end + if logger && logger.debug? + logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") + end + entries.sort_by_name + rescue ScmCommandAborted + return nil + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path ||= '' + identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1' + identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1 + revisions = Revisions.new + cmd_args = %w|log -v --show-ids| + cmd_args << "-r#{identifier_to}..#{identifier_from}" + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + revision = nil + parsing = nil + io.each_line do |line| + if line =~ /^----/ + revisions << revision if revision + revision = Revision.new(:paths => [], :message => '') + parsing = nil + else + next unless revision + if line =~ /^revno: (\d+)($|\s\[merge\]$)/ + revision.identifier = $1.to_i + elsif line =~ /^committer: (.+)$/ + revision.author = $1.strip + elsif line =~ /^revision-id:(.+)$/ + revision.scmid = $1.strip + elsif line =~ /^timestamp: (.+)$/ + revision.time = Time.parse($1).localtime + elsif line =~ /^ -----/ + # partial revisions + parsing = nil unless parsing == 'message' + elsif line =~ /^(message|added|modified|removed|renamed):/ + parsing = $1 + elsif line =~ /^ (.*)$/ + if parsing == 'message' + revision.message << "#{$1}\n" + else + if $1 =~ /^(.*)\s+(\S+)$/ + path = $1.strip + revid = $2 + case parsing + when 'added' + revision.paths << {:action => 'A', :path => "/#{path}", :revision => revid} + when 'modified' + revision.paths << {:action => 'M', :path => "/#{path}", :revision => revid} + when 'removed' + revision.paths << {:action => 'D', :path => "/#{path}", :revision => revid} + when 'renamed' + new_path = path.split('=>').last + revision.paths << {:action => 'M', :path => "/#{new_path.strip}", :revision => revid} if new_path + end + end + end + else + parsing = nil + end + end + end + revisions << revision if revision + end + revisions + rescue ScmCommandAborted + return nil + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + if identifier_to + identifier_to = identifier_to.to_i + else + identifier_to = identifier_from.to_i - 1 + end + if identifier_from + identifier_from = identifier_from.to_i + end + diff = [] + cmd_args = %w|diff| + cmd_args << "-r#{identifier_to}..#{identifier_from}" + cmd_args << bzr_target(path) + scm_cmd_no_raise(*cmd_args) do |io| + io.each_line do |line| + diff << line + end + end + diff + end + + def cat(path, identifier=nil) + cat = nil + cmd_args = %w|cat| + cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0 + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + io.binmode + cat = io.read + end + cat + rescue ScmCommandAborted + return nil + end + + def annotate(path, identifier=nil) + blame = Annotate.new + cmd_args = %w|annotate -q --all| + cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0 + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + author = nil + identifier = nil + io.each_line do |line| + next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$} + rev = $1 + blame.add_line($3.rstrip, + Revision.new( + :identifier => rev, + :revision => rev, + :author => $2.strip + )) + end + end + blame + rescue ScmCommandAborted + return nil + end + + def self.branch_conf_path(path) + bcp = nil + m = path.match(%r{^(.*[/\\])\.bzr.*$}) + if m + bcp = m[1] + else + bcp = path + end + bcp.gsub!(%r{[\/\\]$}, "") + if bcp + bcp = File.join(bcp, ".bzr", "branch", "branch.conf") + end + bcp + end + + def append_revisions_only + return @aro if ! @aro.nil? + @aro = false + bcp = self.class.branch_conf_path(url) + if bcp && File.exist?(bcp) + begin + f = File::open(bcp, "r") + cnt = 0 + f.each_line do |line| + l = line.chomp.to_s + if l =~ /^\s*append_revisions_only\s*=\s*(\w+)\s*$/ + str_aro = $1 + if str_aro.upcase == "TRUE" + @aro = true + cnt += 1 + elsif str_aro.upcase == "FALSE" + @aro = false + cnt += 1 + end + if cnt > 1 + @aro = false + break + end + end + end + ensure + f.close + end + end + @aro + end + + def scm_cmd(*args, &block) + full_args = [] + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "bzr exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd + + def scm_cmd_no_raise(*args, &block) + full_args = [] + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + ret + end + private :scm_cmd_no_raise + + def bzr_target(path) + target(path, false) + end + private :bzr_target + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f06269896f65f1e606b0906f13f624ded16897a7.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f06269896f65f1e606b0906f13f624ded16897a7.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek] + +* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek] + +* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler] + +* Add Timeout protection [Rick] + +* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block. + +* Allow a return_to option to be used instead of the requested url [Josh Peek] + +* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek] + +* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH] + +* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb] + +* Allow -'s in #normalize_url [Rick] + +* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick] + +* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH] + +* Just use the path for the return URL, so extra query parameters don't interfere [DHH] + +* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH] + +* Added normalize_url and applied it to all operations going through the plugin [DHH] + +* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH] + +* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH] + +* Stop relying on root_url being defined, we can just grab the current url instead [DHH] \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f06528e84b5415a40a72b9b0d4c4587fbdcb8aec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f06528e84b5415a40a72b9b0d4c4587fbdcb8aec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,380 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of DotClear. + * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All + * rights reserved. + * + * DotClear 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. + * + * DotClear 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 DotClear; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***** END LICENSE BLOCK ***** +*/ + +/* Modified by JP LANG for textile formatting */ + +function jsToolBar(textarea) { + if (!document.createElement) { return; } + + if (!textarea) { return; } + + if ((typeof(document["selection"]) == "undefined") + && (typeof(textarea["setSelectionRange"]) == "undefined")) { + return; + } + + this.textarea = textarea; + + this.editor = document.createElement('div'); + this.editor.className = 'jstEditor'; + + this.textarea.parentNode.insertBefore(this.editor,this.textarea); + this.editor.appendChild(this.textarea); + + this.toolbar = document.createElement("div"); + this.toolbar.className = 'jstElements'; + this.editor.parentNode.insertBefore(this.toolbar,this.editor); + + // Dragable resizing (only for gecko) + if (this.editor.addEventListener) + { + this.handle = document.createElement('div'); + this.handle.className = 'jstHandle'; + var dragStart = this.resizeDragStart; + var This = this; + this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false); + // fix memory leak in Firefox (bug #241518) + window.addEventListener('unload',function() { + var del = This.handle.parentNode.removeChild(This.handle); + delete(This.handle); + },false); + + this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling); + } + + this.context = null; + this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni + // de raccourcis vers les éléments DOM correspondants aux outils. +} + +function jsButton(title, fn, scope, className) { + if(typeof jsToolBar.strings == 'undefined') { + this.title = title || null; + } else { + this.title = jsToolBar.strings[title] || title || null; + } + this.fn = fn || function(){}; + this.scope = scope || null; + this.className = className || null; +} +jsButton.prototype.draw = function() { + if (!this.scope) return null; + + var button = document.createElement('button'); + button.setAttribute('type','button'); + button.tabIndex = 200; + if (this.className) button.className = this.className; + button.title = this.title; + var span = document.createElement('span'); + span.appendChild(document.createTextNode(this.title)); + button.appendChild(span); + + if (this.icon != undefined) { + button.style.backgroundImage = 'url('+this.icon+')'; + } + if (typeof(this.fn) == 'function') { + var This = this; + button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; }; + } + return button; +} + +function jsSpace(id) { + this.id = id || null; + this.width = null; +} +jsSpace.prototype.draw = function() { + var span = document.createElement('span'); + if (this.id) span.id = this.id; + span.appendChild(document.createTextNode(String.fromCharCode(160))); + span.className = 'jstSpacer'; + if (this.width) span.style.marginRight = this.width+'px'; + + return span; +} + +function jsCombo(title, options, scope, fn, className) { + this.title = title || null; + this.options = options || null; + this.scope = scope || null; + this.fn = fn || function(){}; + this.className = className || null; +} +jsCombo.prototype.draw = function() { + if (!this.scope || !this.options) return null; + + var select = document.createElement('select'); + if (this.className) select.className = className; + select.title = this.title; + + for (var o in this.options) { + //var opt = this.options[o]; + var option = document.createElement('option'); + option.value = o; + option.appendChild(document.createTextNode(this.options[o])); + select.appendChild(option); + } + + var This = this; + select.onchange = function() { + try { + This.fn.call(This.scope, this.value); + } catch (e) { alert(e); } + + return false; + } + + return select; +} + + +jsToolBar.prototype = { + base_url: '', + mode: 'wiki', + elements: {}, + help_link: '', + + getMode: function() { + return this.mode; + }, + + setMode: function(mode) { + this.mode = mode || 'wiki'; + }, + + switchMode: function(mode) { + mode = mode || 'wiki'; + this.draw(mode); + }, + + setHelpLink: function(link) { + this.help_link = link; + }, + + button: function(toolName) { + var tool = this.elements[toolName]; + if (typeof tool.fn[this.mode] != 'function') return null; + var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName); + if (tool.icon != undefined) b.icon = tool.icon; + return b; + }, + space: function(toolName) { + var tool = new jsSpace(toolName) + if (this.elements[toolName].width !== undefined) + tool.width = this.elements[toolName].width; + return tool; + }, + combo: function(toolName) { + var tool = this.elements[toolName]; + var length = tool[this.mode].list.length; + + if (typeof tool[this.mode].fn != 'function' || length == 0) { + return null; + } else { + var options = {}; + for (var i=0; i < length; i++) { + var opt = tool[this.mode].list[i]; + options[opt] = tool.options[opt]; + } + return new jsCombo(tool.title, options, this, tool[this.mode].fn); + } + }, + draw: function(mode) { + this.setMode(mode); + + // Empty toolbar + while (this.toolbar.hasChildNodes()) { + this.toolbar.removeChild(this.toolbar.firstChild) + } + this.toolNodes = {}; // vide les raccourcis DOM/**/ + + var h = document.createElement('div'); + h.className = 'help' + h.innerHTML = this.help_link; + 'Aide'; + this.toolbar.appendChild(h); + + // Draw toolbar elements + var b, tool, newTool; + + for (var i in this.elements) { + b = this.elements[i]; + + var disabled = + b.type == undefined || b.type == '' + || (b.disabled != undefined && b.disabled) + || (b.context != undefined && b.context != null && b.context != this.context); + + if (!disabled && typeof this[b.type] == 'function') { + tool = this[b.type](i); + if (tool) newTool = tool.draw(); + if (newTool) { + this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur + this.toolbar.appendChild(newTool); + } + } + } + }, + + singleTag: function(stag,etag) { + stag = stag || null; + etag = etag || stag; + + if (!stag || !etag) { return; } + + this.encloseSelection(stag,etag); + }, + + encloseLineSelection: function(prefix, suffix, fn) { + this.textarea.focus(); + + prefix = prefix || ''; + suffix = suffix || ''; + + var start, end, sel, scrollPos, subst, res; + + if (typeof(document["selection"]) != "undefined") { + sel = document.selection.createRange().text; + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + start = this.textarea.selectionStart; + end = this.textarea.selectionEnd; + scrollPos = this.textarea.scrollTop; + // go to the start of the line + start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length; + // go to the end of the line + end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length; + sel = this.textarea.value.substring(start, end); + } + + if (sel.match(/ $/)) { // exclude ending space char, if any + sel = sel.substring(0, sel.length - 1); + suffix = suffix + " "; + } + + if (typeof(fn) == 'function') { + res = (sel) ? fn.call(this,sel) : fn(''); + } else { + res = (sel) ? sel : ''; + } + + subst = prefix + res + suffix; + + if (typeof(document["selection"]) != "undefined") { + document.selection.createRange().text = subst; + var range = this.textarea.createTextRange(); + range.collapse(false); + range.move('character', -suffix.length); + range.select(); + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + this.textarea.value = this.textarea.value.substring(0, start) + subst + + this.textarea.value.substring(end); + if (sel) { + this.textarea.setSelectionRange(start + subst.length, start + subst.length); + } else { + this.textarea.setSelectionRange(start + prefix.length, start + prefix.length); + } + this.textarea.scrollTop = scrollPos; + } + }, + + encloseSelection: function(prefix, suffix, fn) { + this.textarea.focus(); + + prefix = prefix || ''; + suffix = suffix || ''; + + var start, end, sel, scrollPos, subst, res; + + if (typeof(document["selection"]) != "undefined") { + sel = document.selection.createRange().text; + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + start = this.textarea.selectionStart; + end = this.textarea.selectionEnd; + scrollPos = this.textarea.scrollTop; + sel = this.textarea.value.substring(start, end); + } + + if (sel.match(/ $/)) { // exclude ending space char, if any + sel = sel.substring(0, sel.length - 1); + suffix = suffix + " "; + } + + if (typeof(fn) == 'function') { + res = (sel) ? fn.call(this,sel) : fn(''); + } else { + res = (sel) ? sel : ''; + } + + subst = prefix + res + suffix; + + if (typeof(document["selection"]) != "undefined") { + document.selection.createRange().text = subst; + var range = this.textarea.createTextRange(); + range.collapse(false); + range.move('character', -suffix.length); + range.select(); +// this.textarea.caretPos -= suffix.length; + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + this.textarea.value = this.textarea.value.substring(0, start) + subst + + this.textarea.value.substring(end); + if (sel) { + this.textarea.setSelectionRange(start + subst.length, start + subst.length); + } else { + this.textarea.setSelectionRange(start + prefix.length, start + prefix.length); + } + this.textarea.scrollTop = scrollPos; + } + }, + + stripBaseURL: function(url) { + if (this.base_url != '') { + var pos = url.indexOf(this.base_url); + if (pos == 0) { + url = url.substr(this.base_url.length); + } + } + + return url; + } +}; + +/** Resizer +-------------------------------------------------------- */ +jsToolBar.prototype.resizeSetStartH = function() { + this.dragStartH = this.textarea.offsetHeight + 0; +}; +jsToolBar.prototype.resizeDragStart = function(event) { + var This = this; + this.dragStartY = event.clientY; + this.resizeSetStartH(); + document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false); + document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false); +}; + +jsToolBar.prototype.resizeDragMove = function(event) { + this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px'; +}; + +jsToolBar.prototype.resizeDragStop = function(event) { + document.removeEventListener('mousemove', this.dragMoveHdlr, false); + document.removeEventListener('mouseup', this.dragStopHdlr, false); +}; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f06f6a1a9c342dff1bcf38adf8c0a9a97805eeed.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f06f6a1a9c342dff1bcf38adf8c0a9a97805eeed.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 EnumerationsHelper +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f073ff08cc2afb6d413c794d740a0e6cb579a02c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f073ff08cc2afb6d413c794d740a0e6cb579a02c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ += <%= file_name %> + +Description goes here diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f0bee1a6f97328341c5f17af5852ef8e9b541a2f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f0bee1a6f97328341c5f17af5852ef8e9b541a2f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +namespace :db do + desc 'Migrates installed plugins.' + task :migrate_plugins => :environment do + if Rails.respond_to?('plugins') + Rails.plugins.each do |plugin| + next unless plugin.respond_to?('migrate') + puts "Migrating #{plugin.name}..." + plugin.migrate + end + else + puts "Undefined method plugins for Rails!" + puts "Make sure engines plugin is installed." + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f0e6829d0324d65e7c9cc71ccb8a30299f34d7e2.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f0e6829d0324d65e7c9cc71ccb8a30299f34d7e2.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class ChangeChangesetsCommitterLimit < ActiveRecord::Migration + def self.up + change_column :changesets, :committer, :string, :limit => nil + end + + def self.down + change_column :changesets, :committer, :string, :limit => 30 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f0ea8798da5044e06000f0cd1c0ce8a2c3a77f32.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f0ea8798da5044e06000f0cd1c0ce8a2c3a77f32.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!8E U+017D Zcaron +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9E U+017E zcaron +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f0/f0fe31ac5f17043ea781f9726c23dec0ad91d555.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f0/f0fe31ac5f17043ea781f9726c23dec0ad91d555.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,68 @@ +/* + calendar-sk.js + language: Slovak + encoding: UTF-8 + author: Stanislav Pach (stano.pach@seznam.cz) +*/ + +// ** I18N +Calendar._DN = new Array('Nedeľa','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota','Nedeľa'); +Calendar._SDN = new Array('Ne','Po','Ut','St','Št','Pi','So','Ne'); +Calendar._MN = new Array('Január','Február','Marec','Apríl','Máj','Jún','Júl','August','September','Október','November','December'); +Calendar._SMN = new Array('Jan','Feb','Mar','Apr','Máj','Jún','Júl','Aug','Sep','Okt','Nov','Dec'); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O komponente kalendár"; +Calendar._TT["TOGGLE"] = "Zmena prvého dňa v týždni"; +Calendar._TT["PREV_YEAR"] = "Predchádzajúci rok (pridrž pre menu)"; +Calendar._TT["PREV_MONTH"] = "Predchádzajúci mesiac (pridrž pre menu)"; +Calendar._TT["GO_TODAY"] = "Dnešný dátum"; +Calendar._TT["NEXT_MONTH"] = "Ďalší mesiac (pridrž pre menu)"; +Calendar._TT["NEXT_YEAR"] = "Ďalší rok (pridrž pre menu)"; +Calendar._TT["SEL_DATE"] = "Zvoľ dátum"; +Calendar._TT["DRAG_TO_MOVE"] = "Chyť a ťahaj pre presun"; +Calendar._TT["PART_TODAY"] = " (dnes)"; +Calendar._TT["MON_FIRST"] = "Ukáž ako prvný Pondelok"; +//Calendar._TT["SUN_FIRST"] = "Ukaž jako první Neděli"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Výber dátumu:\n" + +"- Použijte tlačítka \xab, \xbb pre voľbu roku\n" + +"- Použijte tlačítka " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pre výber mesiaca\n" + +"- Podržte tlačítko myši na akomkoľvek z týchto tlačítok pre rýchlejší výber."; + +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Výber času:\n" + +"- Kliknite na akúkoľvek časť z výberu času pre zvýšenie.\n" + +"- alebo Shift-klick pre zníženie\n" + +"- alebo kliknite a ťahajte pre rýchlejší výber."; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Zobraz %s ako prvý"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zavrieť"; +Calendar._TT["TODAY"] = "Dnes"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikni alebo ťahaj pre zmenu hodnoty"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "d.m.yy"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "týž"; +Calendar._TT["TIME"] = "Čas:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f1/f108ac16dd89fdc6a9b76af157a8c69b5dc81117.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f1/f108ac16dd89fdc6a9b76af157a8c69b5dc81117.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class VersionCustomField < CustomField + def type_name + :label_version_plural + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f1/f16dd552fa837792d60f62dc0c4b19e21584e382.svn-base Binary file .svn/pristine/f1/f16dd552fa837792d60f62dc0c4b19e21584e382.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f1/f1722f2f02a0aad8f0c1c4806750cf6535456366.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f1/f1722f2f02a0aad8f0c1c4806750cf6535456366.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +class AddBoardsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "boards", :action => "new", :description => "button_add", :sort => 2000, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "boards", :action => "edit", :description => "button_edit", :sort => 2005, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "boards", :action => "destroy", :description => "button_delete", :sort => 2010, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action("boards", "new").destroy + Permission.find_by_controller_and_action("boards", "edit").destroy + Permission.find_by_controller_and_action("boards", "destroy").destroy + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f1/f1cdf29a721cc514cb39f1d1983090024969bffe.svn-base Binary file .svn/pristine/f1/f1cdf29a721cc514cb39f1d1983090024969bffe.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f2/f21a5b2225c678b6a423f209390964771a3c8389.svn-base Binary file .svn/pristine/f2/f21a5b2225c678b6a423f209390964771a3c8389.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f2/f22658de649157f0fb513f658c5f97c88aed3de5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f2/f22658de649157f0fb513f658c5f97c88aed3de5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,36 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 GroupsHelper + # Options for the new membership projects combo-box + def options_for_membership_project_select(user, projects) + options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options << project_tree_options_for_select(projects) do |p| + {:disabled => (user.projects.include?(p))} + end + options + end + + def group_settings_tabs + tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general}, + {:name => 'users', :partial => 'groups/users', :label => :label_user_plural}, + {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural} + ] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f2/f2a31393a02ccf87175c51727adbbaca869f6603.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f2/f2a31393a02ccf87175c51727adbbaca869f6603.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddRepositoriesLogEncoding < ActiveRecord::Migration + def self.up + add_column :repositories, :log_encoding, :string, :limit => 64, :default => nil + end + + def self.down + remove_column :repositories, :log_encoding + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f30cc0647876cb77a493a4e5745be36df8d841df.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f30cc0647876cb77a493a4e5745be36df8d841df.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,240 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class UsersController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :show + before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership] + accept_api_auth :index, :show, :create, :update, :destroy + + helper :sort + include SortHelper + helper :custom_fields + include CustomFieldsHelper + + def index + sort_init 'login', 'asc' + sort_update %w(login firstname lastname mail admin created_on last_login_on) + + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + scope = User + scope = scope.in_group(params[:group_id].to_i) if params[:group_id].present? + + @status = params[:status] ? params[:status].to_i : 1 + c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) + + unless params[:name].blank? + name = "%#{params[:name].strip.downcase}%" + c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name] + end + + @user_count = scope.count(:conditions => c.conditions) + @user_pages = Paginator.new self, @user_count, @limit, params['page'] + @offset ||= @user_pages.current.offset + @users = scope.find :all, + :order => sort_clause, + :conditions => c.conditions, + :limit => @limit, + :offset => @offset + + respond_to do |format| + format.html { + @groups = Group.all.sort + render :layout => !request.xhr? + } + format.api + end + end + + def show + # show projects based on current user visibility + @memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current)) + + events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) + @events_by_day = events.group_by(&:event_date) + + unless User.current.admin? + if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?) + render_404 + return + end + end + + respond_to do |format| + format.html { render :layout => 'base' } + format.api + end + end + + def new + @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) + @auth_sources = AuthSource.find(:all) + end + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create + @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) + @user.safe_attributes = params[:user] + @user.admin = params[:user][:admin] || false + @user.login = params[:user][:login] + @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id + + # TODO: Similar to My#account + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + + if @user.save + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + + Mailer.deliver_account_information(@user, params[:user][:password]) if params[:send_information] + + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_create) + redirect_to(params[:continue] ? + {:controller => 'users', :action => 'new'} : + {:controller => 'users', :action => 'edit', :id => @user} + ) + } + format.api { render :action => 'show', :status => :created, :location => user_url(@user) } + end + else + @auth_sources = AuthSource.find(:all) + # Clear password input + @user.password = @user.password_confirmation = nil + + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@user) } + end + end + end + + def edit + @auth_sources = AuthSource.find(:all) + @membership ||= Member.new + end + + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + def update + @user.admin = params[:user][:admin] if params[:user][:admin] + @user.login = params[:user][:login] if params[:user][:login] + if params[:user][:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?) + @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] + end + @user.safe_attributes = params[:user] + # Was the account actived ? (do it before User#save clears the change) + was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE]) + # TODO: Similar to My#account + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + + if @user.save + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + + if was_activated + Mailer.deliver_account_activated(@user) + elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil? + Mailer.deliver_account_information(@user, params[:user][:password]) + end + + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to :back + } + format.api { head :ok } + end + else + @auth_sources = AuthSource.find(:all) + @membership ||= Member.new + # Clear password input + @user.password = @user.password_confirmation = nil + + respond_to do |format| + format.html { render :action => :edit } + format.api { render_validation_errors(@user) } + end + end + rescue ::ActionController::RedirectBackError + redirect_to :controller => 'users', :action => 'edit', :id => @user + end + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } + def destroy + @user.destroy + respond_to do |format| + format.html { redirect_to(users_url) } + format.api { head :ok } + end + end + + def edit_membership + @membership = Member.edit_membership(params[:membership_id], params[:membership], @user) + @membership.save if request.post? + respond_to do |format| + if @membership.valid? + format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' } + format.js { + render(:update) {|page| + page.replace_html "tab-content-memberships", :partial => 'users/memberships' + page.visual_effect(:highlight, "member-#{@membership.id}") + } + } + else + format.js { + render(:update) {|page| + page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', '))) + } + } + end + end + end + + def destroy_membership + @membership = Member.find(params[:membership_id]) + if request.post? && @membership.deletable? + @membership.destroy + end + respond_to do |format| + format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' } + format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} } + end + end + + private + + def find_user + if params[:id] == 'current' + require_login || return + @user = User.current + else + @user = User.find(params[:id]) + end + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f31e0894353284f332a912a2e300b6aa7020e687.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f31e0894353284f332a912a2e300b6aa7020e687.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4641 @@ +This is the status file for DejaVu fonts +($Id: status.txt 1586 2007-02-18 16:07:32Z ben_laenen $) + +original = present in original Bitstream Vera 1.10 + = added in DejaVu fonts + +U+0020 space original +U+0021 exclam original +U+0022 quotedbl original +U+0023 numbersign original +U+0024 dollar original +U+0025 percent original +U+0026 ampersand original +U+0027 quotesingle original +U+0028 parenleft original +U+0029 parenright original +U+002a asterisk original +U+002b plus original +U+002c comma original +U+002d hyphen original +U+002e period original +U+002f slash original +U+0030 zero original +U+0031 one original +U+0032 two original +U+0033 three original +U+0034 four original +U+0035 five original +U+0036 six original +U+0037 seven original +U+0038 eight original +U+0039 nine original +U+003a colon original +U+003b semicolon original +U+003c less original +U+003d equal original +U+003e greater original +U+003f question original +U+0040 at original +U+0041 A original +U+0042 B original +U+0043 C original +U+0044 D original +U+0045 E original +U+0046 F original +U+0047 G original +U+0048 H original +U+0049 I original +U+004a J original +U+004b K original +U+004c L original +U+004d M original +U+004e N original +U+004f O original +U+0050 P original +U+0051 Q original +U+0052 R original +U+0053 S original +U+0054 T original +U+0055 U original +U+0056 V original +U+0057 W original +U+0058 X original +U+0059 Y original +U+005a Z original +U+005b bracketleft original +U+005c backslash original +U+005d bracketright original +U+005e asciicircum original +U+005f underscore original +U+0060 grave original +U+0061 a original +U+0062 b original +U+0063 c original +U+0064 d original +U+0065 e original +U+0066 f original +U+0067 g original +U+0068 h original +U+0069 i original +U+006a j original +U+006b k original +U+006c l original +U+006d m original +U+006e n original +U+006f o original +U+0070 p original +U+0071 q original +U+0072 r original +U+0073 s original +U+0074 t original +U+0075 u original +U+0076 v original +U+0077 w original +U+0078 x original +U+0079 y original +U+007a z original +U+007b braceleft original +U+007c bar original +U+007d braceright original +U+007e asciitilde original +U+00a0 nonbreakingspace original +U+00a1 exclamdown original +U+00a2 cent original +U+00a3 sterling original +U+00a4 currency original +U+00a5 yen original +U+00a6 brokenbar original +U+00a7 section original +U+00a8 dieresis original +U+00a9 copyright original +U+00aa ordfeminine original +U+00ab guillemotleft original +U+00ac logicalnot original +U+00ad sfthyphen original +U+00ae registered original +U+00af macron original +U+00b0 degree original +U+00b1 plusminus original +U+00b2 twosuperior original +U+00b3 threesuperior original +U+00b4 acute original +U+00b5 mu original +U+00b6 paragraph original +U+00b7 periodcentered original +U+00b8 cedilla original +U+00b9 onesuperior original +U+00ba ordmasculine original +U+00bb guillemotright original +U+00bc onequarter original +U+00bd onehalf original +U+00be threequarters original +U+00bf questiondown original +U+00c0 Agrave original +U+00c1 Aacute original +U+00c2 Acircumflex original +U+00c3 Atilde original +U+00c4 Adieresis original +U+00c5 Aring original +U+00c6 AE original +U+00c7 Ccedilla original +U+00c8 Egrave original +U+00c9 Eacute original +U+00ca Ecircumflex original +U+00cb Edieresis original +U+00cc Igrave original +U+00cd Iacute original +U+00ce Icircumflex original +U+00cf Idieresis original +U+00d0 Eth original +U+00d1 Ntilde original +U+00d2 Ograve original +U+00d3 Oacute original +U+00d4 Ocircumflex original +U+00d5 Otilde original +U+00d6 Odieresis original +U+00d7 multiply original +U+00d8 Oslash original +U+00d9 Ugrave original +U+00da Uacute original +U+00db Ucircumflex original +U+00dc Udieresis original +U+00dd Yacute original +U+00de Thorn original +U+00df germandbls original +U+00e0 agrave original +U+00e1 aacute original +U+00e2 acircumflex original +U+00e3 atilde original +U+00e4 adieresis original +U+00e5 aring original +U+00e6 ae original +U+00e7 ccedilla original +U+00e8 egrave original +U+00e9 eacute original +U+00ea ecircumflex original +U+00eb edieresis original +U+00ec igrave original +U+00ed iacute original +U+00ee icircumflex original +U+00ef idieresis original +U+00f0 eth original +U+00f1 ntilde original +U+00f2 ograve original +U+00f3 oacute original +U+00f4 ocircumflex original +U+00f5 otilde original +U+00f6 odieresis original +U+00f7 divide original +U+00f8 oslash original +U+00f9 ugrave original +U+00fa uacute original +U+00fb ucircumflex original +U+00fc udieresis original +U+00fd yacute original +U+00fe thorn original +U+00ff ydieresis original +U+0100 Amacron 1.5 +U+0101 amacron 1.5 +U+0102 Abreve 1.5 +U+0103 abreve 1.5 +U+0104 Aogonek 1.4 +U+0105 aogonek 1.4 +U+0106 Cacute original +U+0107 cacute original +U+0108 Ccircumflex 1.5 +U+0109 ccircumflex 1.5 +U+010a Cdotaccent 1.5 +U+010b cdotaccent 1.5 +U+010c Ccaron original +U+010d ccaron original +U+010e Dcaron 1.0 +U+010f dcaron 1.0 +U+0110 Dcroat 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0111 dcroat original +U+0112 Emacron 1.5 +U+0113 emacron 1.5 +U+0114 Ebreve 1.5 +U+0115 ebreve 1.5 +U+0116 Edotaccent 1.5 +U+0117 edotaccent 1.5 +U+0118 Eogonek 1.4 +U+0119 eogonek 1.4 +U+011a Ecaron 1.0 +U+011b ecaron 1.0 +U+011c Gcircumflex 1.5 +U+011d gcircumflex 1.5 +U+011e Gbreve original +U+011f gbreve original +U+0120 Gdotaccent 1.5 +U+0121 gdotaccent 1.5 +U+0122 Gcommaaccent 1.11 +U+0123 gcommaaccent 1.11 +U+0124 Hcircumflex 1.5 +U+0125 hcircumflex 1.5 +U+0126 Hbar 1.12 +U+0127 hbar 1.12 +U+0128 Itilde 1.5 +U+0129 itilde 1.5 +U+012a Imacron 1.5 +U+012b imacron 1.5 +U+012c Ibreve 1.5 +U+012d ibreve 1.5 +U+012e Iogonek 1.11 +U+012f iogonek 1.11 +U+0130 Idotaccent original +U+0131 dotlessi original +U+0132 IJ 1.11 +U+0133 ij 1.11 +U+0134 Jcircumflex 1.5 +U+0135 jcircumflex 1.5 +U+0136 Kcommaaccent 1.11 +U+0137 kcommaaccent 1.11 +U+0138 kgreenlandic 1.12 +U+0139 Lacute 1.1 +U+013a lacute 1.1 +U+013b Lcommaaccent 1.11 +U+013c lcommaaccent 1.11 +U+013d Lcaron 1.1 +U+013e lcaron 1.1 +U+013f Ldot 1.2 +U+0140 ldot 1.2 +U+0141 Lslash original +U+0142 lslash original +U+0143 Nacute 1.4 +U+0144 nacute 1.4 +U+0145 Ncommaaccent 1.11 +U+0146 ncommaaccent 1.11 +U+0147 Ncaron 1.0 +U+0148 ncaron 1.0 +U+0149 napostrophe 1.12 +U+014a Eng 1.12 +U+014b eng 1.12 +U+014c Omacron 1.5 +U+014d omacron 1.5 +U+014e Obreve 1.5 +U+014f obreve 1.5 +U+0150 Ohungarumlaut 1.5 +U+0151 ohungarumlaut 1.5 +U+0152 OE original +U+0153 oe original +U+0154 Racute 1.1 +U+0155 racute 1.1 +U+0156 Rcommaaccent 1.11 +U+0157 rcommaaccent 1.11 +U+0158 Rcaron 1.0 +U+0159 rcaron 1.0 +U+015a Sacute 1.4 +U+015b sacute 1.4 +U+015c Scircumflex 1.5 +U+015d scircumflex 1.5 +U+015e Scedilla original +U+015f scedilla original +U+0160 Scaron original +U+0161 scaron original +U+0162 Tcommaaccent 1.5 +U+0163 tcommaaccent 1.5 +U+0164 Tcaron 1.0 +U+0165 tcaron 1.0 +U+0166 Tbar 1.12 +U+0167 tbar 1.12 +U+0168 Utilde 1.5 +U+0169 utilde 1.5 +U+016a Umacron 1.5 +U+016b umacron 1.5 +U+016c Ubreve 1.5 +U+016d ubreve 1.5 +U+016e Uring 1.0 +U+016f uring 1.0 +U+0170 Uhungarumlaut 1.5 +U+0171 uhungarumlaut 1.5 +U+0172 Uogonek 1.11 +U+0173 uogonek 1.11 +U+0174 Wcircumflex 1.2 +U+0175 wcircumflex 1.2 +U+0176 Ycircumflex 1.2 +U+0177 ycircumflex 1.2 +U+0178 Ydieresis original +U+0179 Zacute 1.4 +U+017a zacute 1.4 +U+017b Zdotaccent 1.4 +U+017c zdotaccent 1.4 +U+017d Zcaron original +U+017e zcaron original +U+017f longs 1.12 +U+0180 uni0180 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.12 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0181 uni0181 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0182 uni0182 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0183 uni0183 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0184 uni0184 2.3 +U+0185 uni0185 2.3 +U+0186 uni0186 1.15 +U+0187 uni0187 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0188 uni0188 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0189 uni0189 2.1 +U+018a uni018A 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+018b uni018B 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+018c uni018C 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+018d uni018D 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+018e uni018E 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+018f uni018F 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0190 uni0190 1.15 +U+0191 uni0191 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0192 florin original +U+0193 uni0193 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0194 uni0194 1.14 +U+0195 uni0195 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.6 (Sans ExtraLight) +U+0196 uni0196 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0197 uni0197 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0198 uni0198 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+0199 uni0199 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+019a uni019A 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+019b uni019B 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+019c uni019C 2.3 +U+019d uni019D 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+019e uni019E 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+019f uni019F 2.3 +U+01a0 Ohorn 2.3 +U+01a1 ohorn 2.3 +U+01a2 uni01A2 2.3 +U+01a3 uni01A3 2.3 +U+01a4 uni01A4 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01a5 uni01A5 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01a6 uni01A6 2.3 +U+01a7 uni01A7 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01a8 uni01A8 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01a9 uni01A9 2.2 +U+01aa uni01AA 2.3 +U+01ab uni01AB 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01ac uni01AC 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01ad uni01AD 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01ae uni01AE 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01af Uhorn 2.3 +U+01b0 uhorn 2.3 +U+01b1 uni01B1 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01b2 uni01B2 2.3 +U+01b3 uni01B3 2.3 +U+01b4 uni01B4 2.3 +U+01b5 uni01B5 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01b6 uni01B6 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01b7 uni01B7 2.3 +U+01b8 uni01B8 2.3 +U+01b9 uni01B9 2.3 +U+01ba uni01BA 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+01bb uni01BB 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01bc uni01BC 2.3 +U+01bd uni01BD 2.3 +U+01be uni01BE 2.3 +U+01bf uni01BF 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+01c0 uni01C0 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01c1 uni01C1 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01c2 uni01C2 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+01c3 uni01C3 2.2 +U+01c4 uni01C4 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01c5 uni01C5 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01c6 uni01C6 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01c7 uni01C7 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01c8 uni01C8 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01c9 uni01C9 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01ca uni01CA 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01cb uni01CB 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01cc uni01CC 1.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01cd uni01CD 1.15 +U+01ce uni01CE 1.15 +U+01cf uni01CF 1.15 +U+01d0 uni01D0 1.15 +U+01d1 uni01D1 1.15 +U+01d2 uni01D2 1.15 +U+01d3 uni01D3 1.15 +U+01d4 uni01D4 1.15 +U+01d5 uni01D5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01d6 uni01D6 1.13 +U+01d7 uni01D7 2.3 +U+01d8 uni01D8 2.3 +U+01d9 uni01D9 2.3 +U+01da uni01DA 2.3 +U+01db uni01DB 2.3 +U+01dc uni01DC 2.3 +U+01dd uni01DD 2.2 +U+01de uni01DE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01df uni01DF 1.13 +U+01e0 uni01E0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01e1 uni01E1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01e2 uni01E2 1.5 +U+01e3 uni01E3 1.5 +U+01e4 uni01E4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01e5 uni01E5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01e6 Gcaron 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01e7 gcaron 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01e8 uni01E8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01e9 uni01E9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01ea uni01EA 1.9 +U+01eb uni01EB 1.9 +U+01ec uni01EC 1.9 +U+01ed uni01ED 1.9 +U+01ee uni01EE 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01ef uni01EF 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01f0 uni01F0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono) +U+01f1 uni01F1 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01f2 uni01F2 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01f3 uni01F3 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01f4 uni01F4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01f5 uni01F5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01f6 uni01F6 2.3 +U+01f7 uni01F7 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+01f8 uni01F8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01f9 uni01F9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01fa Aringacute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01fb aringacute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+01fc AEacute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01fd aeacute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01fe Oslashacute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+01ff oslashacute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0200 uni0200 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0201 uni0201 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0202 uni0202 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0203 uni0203 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0204 uni0204 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0205 uni0205 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0206 uni0206 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0207 uni0207 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0208 uni0208 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0209 uni0209 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+020a uni020A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+020b uni020B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+020c uni020C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+020d uni020D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+020e uni020E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+020f uni020F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0210 uni0210 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0211 uni0211 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0212 uni0212 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0213 uni0213 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0214 uni0214 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0215 uni0215 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0216 uni0216 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0217 uni0217 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0218 Scommaaccent 1.5 +U+0219 scommaaccent 1.5 +U+021a uni021A 1.5 +U+021b uni021B 1.5 +U+021c uni021C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+021d uni021D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+021e uni021E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+021f uni021F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0220 uni0220 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0221 uni0221 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0222 uni0222 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0223 uni0223 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0224 uni0224 2.3 +U+0225 uni0225 2.3 +U+0226 uni0226 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0227 uni0227 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0228 uni0228 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0229 uni0229 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+022a uni022A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+022b uni022B 1.13 +U+022c uni022C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+022d uni022D 1.13 +U+022e uni022E 1.10 +U+022f uni022F 1.10 +U+0230 uni0230 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+0231 uni0231 1.13 +U+0232 uni0232 1.5 +U+0233 uni0233 1.5 +U+0234 uni0234 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0235 uni0235 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0236 uni0236 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0237 dotlessj 1.5 +U+0238 uni0238 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+0239 uni0239 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+023a uni023A 2.3 +U+023b uni023B 2.3 +U+023c uni023C 2.3 +U+023d uni023D 2.3 +U+023e uni023E 2.3 +U+023f uni023F 2.3 +U+0240 uni0240 2.3 +U+0241 uni0241 2.3 +U+0242 uni0242 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+0243 uni0243 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0244 uni0244 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0245 uni0245 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0246 uni0246 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0247 uni0247 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0248 uni0248 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0249 uni0249 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+024a uni024A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+024b uni024B 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+024c uni024C 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+024d uni024D 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+024e uni024E 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+024f uni024F 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0250 uni0250 1.14 +U+0251 uni0251 1.14 +U+0252 uni0252 1.14 +U+0253 uni0253 1.14 +U+0254 uni0254 1.14 +U+0255 uni0255 1.14 +U+0256 uni0256 1.14 +U+0257 uni0257 1.14 +U+0258 uni0258 1.14 +U+0259 uni0259 1.14 +U+025a uni025A 1.14 +U+025b uni025B 1.14 +U+025c uni025C 1.14 +U+025d uni025D 1.14 +U+025e uni025E 1.14 +U+025f uni025F 1.14 +U+0260 uni0260 1.14 +U+0261 uni0261 1.14 +U+0262 uni0262 1.14 +U+0263 uni0263 1.14 +U+0264 uni0264 1.14 +U+0265 uni0265 1.14 +U+0266 uni0266 1.14 +U+0267 uni0267 1.14 +U+0268 uni0268 1.14 +U+0269 uni0269 1.14 +U+026a uni026A 1.14 +U+026b uni026B 1.14 +U+026c uni026C 1.14 +U+026d uni026D 1.14 +U+026e uni026E 1.14 +U+026f uni026F 1.14 +U+0270 uni0270 1.14 +U+0271 uni0271 1.14 +U+0272 uni0272 1.14 +U+0273 uni0273 1.14 +U+0274 uni0274 1.14 +U+0275 uni0275 1.14 +U+0276 uni0276 1.14 +U+0277 uni0277 1.14 +U+0278 uni0278 1.14 +U+0279 uni0279 1.14 +U+027a uni027A 1.14 +U+027b uni027B 1.14 +U+027c uni027C 1.14 +U+027d uni027D 1.14 +U+027e uni027E 1.14 +U+027f uni027F 1.14 +U+0280 uni0280 1.14 +U+0281 uni0281 1.14 +U+0282 uni0282 1.14 +U+0283 uni0283 1.14 +U+0284 uni0284 1.14 +U+0285 uni0285 1.14 +U+0286 uni0286 1.14 +U+0287 uni0287 1.14 +U+0288 uni0288 1.14 +U+0289 uni0289 1.14 +U+028a uni028A 1.14 +U+028b uni028B 1.14 +U+028c uni028C 1.14 +U+028d uni028D 1.14 +U+028e uni028E 1.14 +U+028f uni028F 1.14 +U+0290 uni0290 1.14 +U+0291 uni0291 1.14 +U+0292 uni0292 1.14 +U+0293 uni0293 1.14 +U+0294 uni0294 1.14 +U+0295 uni0295 1.14 +U+0296 uni0296 1.14 +U+0297 uni0297 1.14 +U+0298 uni0298 1.14 +U+0299 uni0299 1.14 +U+029a uni029A 1.14 +U+029b uni029B 1.14 +U+029c uni029C 1.14 +U+029d uni029D 1.14 +U+029e uni029E 1.14 +U+029f uni029F 1.14 +U+02a0 uni02A0 1.14 +U+02a1 uni02A1 1.14 +U+02a2 uni02A2 1.14 +U+02a3 uni02A3 1.14 +U+02a4 uni02A4 1.14 +U+02a5 uni02A5 1.14 +U+02a6 uni02A6 1.14 +U+02a7 uni02A7 1.14 +U+02a8 uni02A8 1.14 +U+02a9 uni02A9 1.14 +U+02aa uni02AA 1.14 +U+02ab uni02AB 1.14 +U+02ac uni02AC 1.14 +U+02ad uni02AD 1.14 +U+02ae uni02AE 1.14 +U+02af uni02AF 1.14 +U+02b0 uni02B0 1.14 +U+02b1 uni02B1 1.14 +U+02b2 uni02B2 1.14 +U+02b3 uni02B3 1.14 +U+02b4 uni02B4 1.14 +U+02b5 uni02B5 1.14 +U+02b6 uni02B6 1.14 +U+02b7 uni02B7 1.14 +U+02b8 uni02B8 1.14 +U+02b9 uni02B9 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+02ba uni02BA 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02bb uni02BB 1.5 +U+02bc afii57929 1.12 +U+02bd afii64937 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+02be uni02BE 2.2 +U+02bf uni02BF 2.2 +U+02c0 uni02C0 1.14 +U+02c1 uni02C1 1.14 +U+02c2 uni02C2 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02c3 uni02C3 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02c4 uni02C4 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02c5 uni02C5 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02c6 circumflex original +U+02c7 caron original +U+02c8 uni02C8 2.0 +U+02c9 uni02C9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+02ca uni02CA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+02cb uni02CB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+02cc uni02CC 2.0 +U+02cd uni02CD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+02ce uni02CE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+02cf uni02CF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+02d0 uni02D0 1.14 +U+02d1 uni02D1 1.14 +U+02d2 uni02D2 2.0 +U+02d3 uni02D3 2.2 +U+02d4 uni02D4 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02d5 uni02D5 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02d6 uni02D6 2.0 +U+02d7 uni02D7 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02d8 breve original +U+02d9 dotaccent original +U+02da ring original +U+02db ogonek original +U+02dc tilde original +U+02dd hungarumlaut original +U+02de uni02DE 2.0 +U+02df uni02DF 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02e0 uni02E0 1.14 +U+02e1 uni02E1 1.14 +U+02e2 uni02E2 1.14 +U+02e3 uni02E3 1.14 +U+02e4 uni02E4 1.14 +U+02e5 uni02E5 2.0 +U+02e6 uni02E6 2.0 +U+02e7 uni02E7 2.0 +U+02e8 uni02E8 2.0 +U+02e9 uni02E9 2.0 +U+02ec uni02EC 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02ed uni02ED 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+02ee uni02EE 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+02f3 uni02F3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+02f7 uni02F7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+0300 gravecomb 1.15 +U+0301 acutecomb 1.15 +U+0302 uni0302 1.15 +U+0303 tildecomb 1.15 +U+0304 uni0304 1.15 +U+0305 uni0305 2.0 +U+0306 uni0306 1.15 +U+0307 uni0307 1.15 +U+0308 uni0308 1.15 +U+0309 hookabovecomb 2.1 +U+030a uni030A 1.15 +U+030b uni030B 1.15 +U+030c uni030C 1.15 +U+030d uni030D 2.0 +U+030e uni030E 2.0 +U+030f uni030F 2.0 +U+0310 uni0310 2.0 +U+0311 uni0311 2.0 +U+0312 uni0312 1.11 +U+0313 uni0313 2.1 +U+0314 uni0314 2.1 +U+0315 uni0315 2.0 +U+0316 uni0316 2.0 +U+0317 uni0317 2.0 +U+0318 uni0318 2.0 +U+0319 uni0319 2.0 +U+031a uni031A 2.1 +U+031b uni031B 2.1 +U+031c uni031C 2.0 +U+031d uni031D 2.0 +U+031e uni031E 2.0 +U+031f uni031F 2.0 +U+0320 uni0320 2.0 +U+0321 uni0321 1.15 +U+0322 uni0322 1.15 +U+0323 dotbelowcomb 2.1 +U+0324 uni0324 2.0 +U+0325 uni0325 2.0 +U+0326 uni0326 1.5 +U+0327 uni0327 2.1 +U+0328 uni0328 2.1 +U+0329 uni0329 2.0 +U+032a uni032A 2.0 +U+032b uni032B 2.1 +U+032c uni032C 2.0 +U+032d uni032D 2.0 +U+032e uni032E 2.0 +U+032f uni032F 2.0 +U+0330 uni0330 2.0 +U+0331 uni0331 2.0 +U+0332 uni0332 2.0 +U+0333 uni0333 2.1 +U+0334 uni0334 2.3 +U+0335 uni0335 2.3 +U+0336 uni0336 2.3 +U+0337 uni0337 2.3 +U+0338 uni0338 2.3 +U+0339 uni0339 2.0 +U+033a uni033A 2.0 +U+033b uni033B 2.0 +U+033c uni033C 2.1 +U+033d uni033D 2.0 +U+033e uni033E 2.1 +U+033f uni033F 2.1 +U+0340 uni0340 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0341 uni0341 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0342 uni0342 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0343 uni0343 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0344 uni0344 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0345 uni0345 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0346 uni0346 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0347 uni0347 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0348 uni0348 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0349 uni0349 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+034a uni034A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+034b uni034B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+034c uni034C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+034d uni034D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+034e uni034E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+034f uni034F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0351 uni0351 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0352 uni0352 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique) +U+0353 uni0353 2.5 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0357 uni0357 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0358 uni0358 2.3 +U+035c uni035C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+035d uni035D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+035e uni035E 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+035f uni035F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0360 uni0360 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0361 uni0361 2.0 +U+0362 uni0362 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0374 uni0374 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0375 uni0375 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+037a uni037A 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+037b uni037B 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+037c uni037C 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans ExtraLight, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+037d uni037D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans ExtraLight, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+037e uni037E 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0384 tonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0385 dieresistonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0386 Alphatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0387 anoteleia 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0388 Epsilontonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0389 Etatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+038a Iotatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+038c Omicrontonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+038e Upsilontonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+038f Omegatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+0390 iotadieresistonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0391 Alpha 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0392 Beta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0393 Gamma 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0394 uni0394 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0395 Epsilon 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0396 Zeta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0397 Eta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0398 Theta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+0399 Iota 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+039a Kappa 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+039b Lambda 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+039c Mu 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+039d Nu 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+039e Xi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+039f Omicron 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a0 Pi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a1 Rho 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a3 Sigma 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a4 Tau 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a5 Upsilon 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a6 Phi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03a7 Chi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03a8 Psi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03a9 Omega original +U+03aa Iotadieresis 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03ab Upsilondieresis 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.1 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03ac alphatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03ad epsilontonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03ae etatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03af iotatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b0 upsilondieresistonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b1 alpha 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b2 beta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b3 gamma 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b4 delta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b5 epsilon 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03b6 zeta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b7 eta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03b8 theta 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03b9 iota 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03ba kappa 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03bb lambda 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03bc uni03BC 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03bd nu 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03be xi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03bf omicron 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03c0 pi original +U+03c1 rho 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c2 sigma1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c3 sigma 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c4 tau 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c5 upsilon 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c6 phi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c7 chi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c8 psi 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03c9 omega 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03ca iotadieresis 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03cb upsilondieresis 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03cc omicrontonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03cd upsilontonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03ce omegatonos 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 1.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.2 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+03d0 uni03D0 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d1 theta1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d2 Upsilon1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d3 uni03D3 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d4 uni03D4 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d5 phi1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d6 omega1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d7 uni03D7 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d8 uni03D8 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03d9 uni03D9 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03da uni03DA 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03db uni03DB 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03dc uni03DC 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03dd uni03DD 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03de uni03DE 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03df uni03DF 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03e0 uni03E0 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03e1 uni03E1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03e2 uni03E2 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e3 uni03E3 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e4 uni03E4 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e5 uni03E5 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e6 uni03E6 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e7 uni03E7 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e8 uni03E8 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03e9 uni03E9 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03ea uni03EA 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03eb uni03EB 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03ec uni03EC 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03ed uni03ED 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03ee uni03EE 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03ef uni03EF 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+03f0 uni03F0 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03f1 uni03F1 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03f2 uni03F2 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f3 uni03F3 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f4 uni03F4 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f5 uni03F5 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f6 uni03F6 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f7 uni03F7 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f8 uni03F8 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03f9 uni03F9 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03fa uni03FA 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03fb uni03FB 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03fc uni03FC 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+03fd uni03FD 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03fe uni03FE 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+03ff uni03FF 1.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.0 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+0400 uni0400 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0401 afii10023 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0402 afii10051 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0403 afii10052 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0404 afii10053 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0405 afii10054 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0406 afii10055 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0407 afii10056 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0408 afii10057 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0409 afii10058 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+040a afii10059 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+040b afii10060 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+040c afii10061 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+040d uni040D 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+040e afii10062 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+040f afii10145 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0410 afii10017 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0411 afii10018 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0412 afii10019 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0413 afii10020 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0414 afii10021 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0415 afii10022 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0416 afii10024 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0417 afii10025 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0418 afii10026 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0419 afii10027 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+041a afii10028 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+041b afii10029 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+041c afii10030 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+041d afii10031 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+041e afii10032 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+041f afii10033 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0420 afii10034 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0421 afii10035 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0422 afii10036 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0423 afii10037 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0424 afii10038 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0425 afii10039 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0426 afii10040 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0427 afii10041 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0428 afii10042 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0429 afii10043 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+042a afii10044 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+042b afii10045 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+042c afii10046 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+042d afii10047 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+042e afii10048 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+042f afii10049 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0430 afii10065 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0431 afii10066 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0432 afii10067 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0433 afii10068 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0434 afii10069 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0435 afii10070 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0436 afii10072 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0437 afii10073 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0438 afii10074 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0439 afii10075 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+043a afii10076 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+043b afii10077 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+043c afii10078 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+043d afii10079 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+043e afii10080 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+043f afii10081 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0440 afii10082 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0441 afii10083 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0442 afii10084 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0443 afii10085 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0444 afii10086 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0445 afii10087 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0446 afii10088 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0447 afii10089 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0448 afii10090 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0449 afii10091 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+044a afii10092 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+044b afii10093 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+044c afii10094 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+044d afii10095 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+044e afii10096 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+044f afii10097 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0450 uni0450 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0451 afii10071 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0452 afii10099 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0453 afii10100 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0454 afii10101 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0455 afii10102 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0456 afii10103 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0457 afii10104 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0458 afii10105 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+0459 afii10106 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+045a afii10107 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+045b afii10108 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+045c afii10109 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+045d uni045D 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+045e afii10110 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.4 (Sans ExtraLight) +U+045f afii10193 1.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 1.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold) 1.6 (Serif Bold Oblique, Serif Oblique) 1.7 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) 2.5 (Sans ExtraLight) +U+0460 uni0460 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0461 uni0461 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+0462 afii10146 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0463 afii10194 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0464 uni0464 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+0465 uni0465 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+0466 uni0466 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0467 uni0467 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0468 uni0468 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0469 uni0469 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+046a uni046A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+046b uni046B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+046c uni046C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+046d uni046D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+046e uni046E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+046f uni046F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0470 uni0470 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+0471 uni0471 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+0472 afii10147 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+0473 afii10195 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0474 afii10148 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.12 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0475 afii10196 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.12 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0476 uni0476 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0477 uni0477 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0478 uni0478 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0479 uni0479 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+047a uni047A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+047b uni047B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+047c uni047C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+047d uni047D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+047e uni047E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+047f uni047F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0480 uni0480 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0481 uni0481 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0482 uni0482 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0483 uni0483 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0484 uni0484 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0485 uni0485 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0486 uni0486 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0487 uni0487 2.9 (Sans, Sans Condensed) +U+0488 uni0488 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0489 uni0489 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+048a uni048A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+048b uni048B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+048c uni048C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+048d uni048D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+048e uni048E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+048f uni048F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0490 afii10050 1.15 +U+0491 afii10098 1.15 +U+0492 uni0492 1.14 +U+0493 uni0493 1.14 +U+0494 uni0494 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0495 uni0495 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0496 uni0496 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0497 uni0497 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.15 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0498 uni0498 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+0499 uni0499 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+049a uni049A 1.14 +U+049b uni049B 1.14 +U+049c uni049C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+049d uni049D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+049e uni049E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+049f uni049F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a0 uni04A0 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a1 uni04A1 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a2 uni04A2 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a3 uni04A3 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a4 uni04A4 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+04a5 uni04A5 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+04a6 uni04A6 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a7 uni04A7 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04a8 uni04A8 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04a9 uni04A9 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04aa uni04AA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04ab uni04AB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04ac uni04AC 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04ad uni04AD 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04ae uni04AE 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04af uni04AF 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04b0 uni04B0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04b1 uni04B1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04b2 uni04B2 1.14 +U+04b3 uni04B3 1.14 +U+04b4 uni04B4 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+04b5 uni04B5 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+04b6 uni04B6 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04b7 uni04B7 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04b8 uni04B8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04b9 uni04B9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04ba uni04BA 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04bb uni04BB 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04bc uni04BC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04bd uni04BD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04be uni04BE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04bf uni04BF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04c0 uni04C0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04c1 uni04C1 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04c2 uni04C2 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04c3 uni04C3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04c4 uni04C4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04c5 uni04C5 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04c6 uni04C6 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04c7 uni04C7 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04c8 uni04C8 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04c9 uni04C9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04ca uni04CA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04cb uni04CB 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04cc uni04CC 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04cd uni04CD 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04ce uni04CE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04cf uni04CF 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04d0 uni04D0 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d1 uni04D1 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d2 uni04D2 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d3 uni04D3 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d4 uni04D4 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d5 uni04D5 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d6 uni04D6 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d7 uni04D7 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04d8 uni04D8 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04d9 afii10846 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04da uni04DA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04db uni04DB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04dc uni04DC 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04dd uni04DD 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04de uni04DE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04df uni04DF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04e0 uni04E0 2.3 +U+04e1 uni04E1 2.3 +U+04e2 uni04E2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04e3 uni04E3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04e4 uni04E4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04e5 uni04E5 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04e6 uni04E6 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04e7 uni04E7 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.4 (Sans ExtraLight) +U+04e8 uni04E8 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04e9 uni04E9 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04ea uni04EA 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04eb uni04EB 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+04ec uni04EC 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04ed uni04ED 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04ee uni04EE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04ef uni04EF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04f0 uni04F0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04f1 uni04F1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04f2 uni04F2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04f3 uni04F3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04f4 uni04F4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04f5 uni04F5 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04f6 uni04F6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04f7 uni04F7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04f8 uni04F8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+04f9 uni04F9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+04fa uni04FA 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04fb uni04FB 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04fc uni04FC 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04fd uni04FD 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04fe uni04FE 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+04ff uni04FF 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0500 uni0500 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0501 uni0501 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0502 uni0502 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0503 uni0503 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0504 uni0504 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0505 uni0505 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0506 uni0506 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0507 uni0507 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0508 uni0508 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0509 uni0509 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+050a uni050A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+050b uni050B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+050c uni050C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+050d uni050D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+050e uni050E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+050f uni050F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0510 uni0510 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0511 uni0511 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0512 uni0512 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0513 uni0513 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0531 uni0531 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0532 uni0532 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0533 uni0533 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0534 uni0534 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0535 uni0535 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0536 uni0536 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0537 uni0537 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0538 uni0538 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0539 uni0539 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+053a uni053A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+053b uni053B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+053c uni053C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+053d uni053D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+053e uni053E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+053f uni053F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0540 uni0540 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0541 uni0541 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0542 uni0542 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0543 uni0543 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0544 uni0544 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0545 uni0545 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0546 uni0546 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0547 uni0547 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0548 uni0548 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+0549 uni0549 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+054a uni054A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+054b uni054B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+054c uni054C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+054d uni054D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+054e uni054E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+054f uni054F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0550 uni0550 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0551 uni0551 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0552 uni0552 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0553 uni0553 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+0554 uni0554 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0555 uni0555 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0556 uni0556 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0559 uni0559 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+055a uni055A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+055b uni055B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+055c uni055C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+055d uni055D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+055e uni055E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+055f uni055F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0561 uni0561 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+0562 uni0562 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0563 uni0563 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0564 uni0564 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0565 uni0565 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0566 uni0566 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0567 uni0567 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0568 uni0568 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0569 uni0569 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+056a uni056A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+056b uni056B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+056c uni056C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+056d uni056D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+056e uni056E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+056f uni056F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+0570 uni0570 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0571 uni0571 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0572 uni0572 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0573 uni0573 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0574 uni0574 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0575 uni0575 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0576 uni0576 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0577 uni0577 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0578 uni0578 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0579 uni0579 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+057a uni057A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+057b uni057B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+057c uni057C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+057d uni057D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+057e uni057E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+057f uni057F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+0580 uni0580 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0581 uni0581 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0582 uni0582 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0583 uni0583 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+0584 uni0584 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0585 uni0585 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+0586 uni0586 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0587 uni0587 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+0589 uni0589 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+058a uni058A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b0 afii57799 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b1 afii57801 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b2 afii57800 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b3 afii57802 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b4 afii57793 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b5 afii57794 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b6 afii57795 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b7 afii57798 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b8 afii57797 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05b9 afii57806 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05bb afii57796 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05bc afii57807 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05bd afii57839 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05be afii57645 2.9 (Sans Condensed Oblique, Sans Oblique) +U+05bf afii57841 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05c0 afii57842 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05c1 afii57804 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05c2 afii57803 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05c3 afii57658 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05c6 uni05C6 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05c7 uni05C7 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d0 afii57664 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d1 afii57665 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d2 afii57666 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d3 afii57667 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d4 afii57668 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d5 afii57669 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d6 afii57670 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d7 afii57671 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d8 afii57672 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05d9 afii57673 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05da afii57674 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05db afii57675 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05dc afii57676 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05dd afii57677 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05de afii57678 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05df afii57679 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e0 afii57680 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e1 afii57681 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e2 afii57682 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e3 afii57683 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e4 afii57684 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e5 afii57685 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e6 afii57686 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e7 afii57687 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e8 afii57688 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05e9 afii57689 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05ea afii57690 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05f0 afii57716 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05f1 afii57717 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+05f2 afii57718 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+060c afii57388 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0615 uni0615 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+061b afii57403 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+061f afii57407 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0621 afii57409 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0622 afii57410 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0623 afii57411 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0624 afii57412 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0625 afii57413 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0626 afii57414 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0627 afii57415 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0628 afii57416 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0629 afii57417 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+062a afii57418 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+062b afii57419 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+062c afii57420 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+062d afii57421 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+062e afii57422 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+062f afii57423 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0630 afii57424 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0631 afii57425 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0632 afii57426 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0633 afii57427 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0634 afii57428 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0635 afii57429 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0636 afii57430 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0637 afii57431 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0638 afii57432 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0639 afii57433 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+063a afii57434 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0640 afii57440 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0641 afii57441 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0642 afii57442 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0643 afii57443 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0644 afii57444 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0645 afii57445 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0646 afii57446 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0647 afii57470 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0648 afii57448 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0649 afii57449 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+064a afii57450 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+064b afii57451 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+064c afii57452 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+064d afii57453 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+064e afii57454 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+064f afii57455 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0650 afii57456 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0651 afii57457 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0652 afii57458 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0653 uni0653 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0654 uni0654 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0655 uni0655 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+065a uni065A 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0660 afii57392 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0661 afii57393 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0662 afii57394 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0663 afii57395 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0664 afii57396 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0665 afii57397 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0666 afii57398 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0667 afii57399 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0668 afii57400 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0669 afii57401 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+066a afii57381 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+066b uni066B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+066c uni066C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+066d afii63167 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+066e uni066E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+066f uni066F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0674 uni0674 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans ExtraLight) +U+0679 afii57511 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+067a uni067A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+067b uni067B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+067c uni067C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+067d uni067D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+067e afii57506 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+067f uni067F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0680 uni0680 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0681 uni0681 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0682 uni0682 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0683 uni0683 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0684 uni0684 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0685 uni0685 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0686 afii57507 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0687 uni0687 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0691 afii57513 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0692 uni0692 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0695 uni0695 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0698 afii57508 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06a1 uni06A1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06a4 afii57505 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06a6 uni06A6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06a9 uni06A9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06af afii57509 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06b5 uni06B5 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06ba afii57514 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06bf uni06BF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06c6 uni06C6 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06cc uni06CC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06ce uni06CE 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06d5 uni06D5 2.10 (Sans, Sans Bold) 2.11 (Sans Condensed, Sans Condensed Bold) +U+06f0 uni06F0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f1 uni06F1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f2 uni06F2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f3 uni06F3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f4 uni06F4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f5 uni06F5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f6 uni06F6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f7 uni06F7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f8 uni06F8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+06f9 uni06F9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+0e3f uni0E3F 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0e81 uni0E81 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e82 uni0E82 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e84 uni0E84 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e87 uni0E87 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e88 uni0E88 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e8a uni0E8A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e8d uni0E8D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e94 uni0E94 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e95 uni0E95 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e96 uni0E96 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e97 uni0E97 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e99 uni0E99 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e9a uni0E9A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e9b uni0E9B 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e9c uni0E9C 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e9d uni0E9D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e9e uni0E9E 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0e9f uni0E9F 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0ea1 uni0EA1 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0ea2 uni0EA2 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0ea3 uni0EA3 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0ea5 uni0EA5 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0ea7 uni0EA7 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0eaa uni0EAA 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0eab uni0EAB 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0ead uni0EAD 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0eae uni0EAE 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0eaf uni0EAF 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+0eb0 uni0EB0 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb1 uni0EB1 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb2 uni0EB2 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb3 uni0EB3 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb4 uni0EB4 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb5 uni0EB5 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb6 uni0EB6 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb7 uni0EB7 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb8 uni0EB8 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eb9 uni0EB9 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ebb uni0EBB 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ebc uni0EBC 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ebd uni0EBD 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec0 uni0EC0 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec1 uni0EC1 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec2 uni0EC2 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec3 uni0EC3 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec4 uni0EC4 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec6 uni0EC6 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec8 uni0EC8 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ec9 uni0EC9 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0eca uni0ECA 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ecb uni0ECB 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ecc uni0ECC 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0ecd uni0ECD 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0edc uni0EDC 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+0edd uni0EDD 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1401 uni1401 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1402 uni1402 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1403 uni1403 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1404 uni1404 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1405 uni1405 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1406 uni1406 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1407 uni1407 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1409 uni1409 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+140a uni140A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+140b uni140B 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+140c uni140C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+140d uni140D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+140e uni140E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+140f uni140F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1410 uni1410 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1411 uni1411 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1412 uni1412 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1413 uni1413 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1414 uni1414 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1415 uni1415 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1416 uni1416 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1417 uni1417 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1418 uni1418 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1419 uni1419 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+141a uni141A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+141b uni141B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+141d uni141D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+141e uni141E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+141f uni141F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1420 uni1420 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1421 uni1421 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1422 uni1422 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1423 uni1423 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1424 uni1424 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1425 uni1425 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1426 uni1426 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1427 uni1427 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1428 uni1428 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1429 uni1429 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+142a uni142A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+142b uni142B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+142c uni142C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+142d uni142D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+142e uni142E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+142f uni142F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1430 uni1430 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1431 uni1431 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1432 uni1432 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1433 uni1433 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1434 uni1434 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1435 uni1435 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1437 uni1437 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1438 uni1438 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1439 uni1439 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+143a uni143A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+143b uni143B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+143c uni143C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+143d uni143D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+143e uni143E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+143f uni143F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1440 uni1440 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1441 uni1441 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1442 uni1442 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1443 uni1443 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1444 uni1444 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1445 uni1445 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1446 uni1446 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1447 uni1447 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1448 uni1448 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1449 uni1449 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+144a uni144A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+144c uni144C 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+144d uni144D 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+144e uni144E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+144f uni144F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1450 uni1450 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1451 uni1451 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1452 uni1452 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1454 uni1454 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1455 uni1455 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1456 uni1456 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1457 uni1457 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1458 uni1458 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1459 uni1459 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+145a uni145A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+145b uni145B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+145c uni145C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+145d uni145D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+145e uni145E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+145f uni145F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1460 uni1460 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1461 uni1461 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1462 uni1462 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1463 uni1463 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1464 uni1464 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1465 uni1465 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1466 uni1466 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1467 uni1467 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1468 uni1468 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1469 uni1469 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+146a uni146A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+146b uni146B 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+146c uni146C 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+146d uni146D 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+146e uni146E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+146f uni146F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1470 uni1470 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1471 uni1471 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1472 uni1472 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1473 uni1473 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1474 uni1474 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1475 uni1475 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1476 uni1476 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1477 uni1477 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1478 uni1478 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1479 uni1479 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+147a uni147A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+147b uni147B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+147c uni147C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+147d uni147D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+147e uni147E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+147f uni147F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1480 uni1480 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1481 uni1481 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1482 uni1482 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1483 uni1483 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1484 uni1484 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1485 uni1485 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1486 uni1486 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1487 uni1487 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1488 uni1488 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1489 uni1489 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+148a uni148A 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+148b uni148B 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+148c uni148C 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+148d uni148D 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+148e uni148E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+148f uni148F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1490 uni1490 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1491 uni1491 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1492 uni1492 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1493 uni1493 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1494 uni1494 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1495 uni1495 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1496 uni1496 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1497 uni1497 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1498 uni1498 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1499 uni1499 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+149a uni149A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+149b uni149B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+149c uni149C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+149d uni149D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+149e uni149E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+149f uni149F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a0 uni14A0 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a1 uni14A1 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a2 uni14A2 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a3 uni14A3 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a4 uni14A4 2.13 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Oblique) 2.15 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+14a5 uni14A5 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a6 uni14A6 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a7 uni14A7 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a8 uni14A8 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14a9 uni14A9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14aa uni14AA 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ab uni14AB 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ac uni14AC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ad uni14AD 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ae uni14AE 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14af uni14AF 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b0 uni14B0 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b1 uni14B1 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b2 uni14B2 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b3 uni14B3 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b4 uni14B4 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b5 uni14B5 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b6 uni14B6 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b7 uni14B7 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b8 uni14B8 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14b9 uni14B9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ba uni14BA 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14bb uni14BB 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14bc uni14BC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14bd uni14BD 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c0 uni14C0 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c1 uni14C1 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c2 uni14C2 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c3 uni14C3 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c4 uni14C4 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c5 uni14C5 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c6 uni14C6 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c7 uni14C7 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c8 uni14C8 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14c9 uni14C9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ca uni14CA 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14cb uni14CB 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14cc uni14CC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14cd uni14CD 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ce uni14CE 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14cf uni14CF 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d0 uni14D0 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d1 uni14D1 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d2 uni14D2 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d3 uni14D3 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d4 uni14D4 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d5 uni14D5 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d6 uni14D6 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d7 uni14D7 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d8 uni14D8 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14d9 uni14D9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14da uni14DA 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14db uni14DB 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14dc uni14DC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14dd uni14DD 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14de uni14DE 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14df uni14DF 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e0 uni14E0 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e1 uni14E1 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e2 uni14E2 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e3 uni14E3 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e4 uni14E4 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e5 uni14E5 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e6 uni14E6 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e7 uni14E7 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e8 uni14E8 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14e9 uni14E9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ea uni14EA 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ec uni14EC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ed uni14ED 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ee uni14EE 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ef uni14EF 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f0 uni14F0 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f1 uni14F1 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f2 uni14F2 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f3 uni14F3 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f4 uni14F4 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f5 uni14F5 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f6 uni14F6 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f7 uni14F7 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f8 uni14F8 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14f9 uni14F9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14fa uni14FA 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14fb uni14FB 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14fc uni14FC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14fd uni14FD 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14fe uni14FE 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+14ff uni14FF 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1500 uni1500 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1501 uni1501 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1502 uni1502 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1503 uni1503 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1504 uni1504 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1505 uni1505 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1506 uni1506 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1507 uni1507 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1510 uni1510 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1511 uni1511 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1512 uni1512 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1513 uni1513 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1514 uni1514 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1515 uni1515 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1516 uni1516 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1517 uni1517 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1518 uni1518 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1519 uni1519 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+151a uni151A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+151b uni151B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+151c uni151C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+151d uni151D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+151e uni151E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+151f uni151F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1520 uni1520 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1521 uni1521 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1522 uni1522 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1523 uni1523 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1524 uni1524 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1525 uni1525 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1526 uni1526 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1527 uni1527 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1528 uni1528 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1529 uni1529 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+152a uni152A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+152b uni152B 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+152c uni152C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+152d uni152D 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+152e uni152E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+152f uni152F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1530 uni1530 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1531 uni1531 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1532 uni1532 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1533 uni1533 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1534 uni1534 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1535 uni1535 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1536 uni1536 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1537 uni1537 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1538 uni1538 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1539 uni1539 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+153a uni153A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+153b uni153B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+153c uni153C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+153d uni153D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+153e uni153E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1540 uni1540 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1541 uni1541 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1542 uni1542 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1543 uni1543 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1544 uni1544 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1545 uni1545 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1546 uni1546 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1547 uni1547 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1548 uni1548 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1549 uni1549 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+154a uni154A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+154b uni154B 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+154c uni154C 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+154d uni154D 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+154e uni154E 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+154f uni154F 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1550 uni1550 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1552 uni1552 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1553 uni1553 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1554 uni1554 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1555 uni1555 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1556 uni1556 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1557 uni1557 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1558 uni1558 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1559 uni1559 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+155a uni155A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+155b uni155B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+155c uni155C 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+155d uni155D 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+155e uni155E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+155f uni155F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1560 uni1560 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1561 uni1561 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1562 uni1562 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1563 uni1563 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1564 uni1564 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1565 uni1565 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1566 uni1566 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1567 uni1567 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1568 uni1568 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1569 uni1569 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+156a uni156A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1574 uni1574 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1575 uni1575 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1576 uni1576 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1577 uni1577 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1578 uni1578 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1579 uni1579 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+157a uni157A 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+157b uni157B 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+157c uni157C 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+157d uni157D 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+157e uni157E 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+157f uni157F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1580 uni1580 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1581 uni1581 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1582 uni1582 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1583 uni1583 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1584 uni1584 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1585 uni1585 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+158a uni158A 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+158b uni158B 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+158c uni158C 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+158d uni158D 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+158e uni158E 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+158f uni158F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1590 uni1590 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1591 uni1591 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1592 uni1592 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1593 uni1593 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1594 uni1594 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1595 uni1595 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1596 uni1596 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a0 uni15A0 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a1 uni15A1 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a2 uni15A2 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a3 uni15A3 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a4 uni15A4 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a5 uni15A5 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a6 uni15A6 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a7 uni15A7 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a8 uni15A8 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15a9 uni15A9 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15aa uni15AA 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15ab uni15AB 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15ac uni15AC 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15ad uni15AD 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15ae uni15AE 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15af uni15AF 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15de uni15DE 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+15e1 uni15E1 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1646 uni1646 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1647 uni1647 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+166e uni166E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+166f uni166F 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1670 uni1670 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1671 uni1671 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1672 uni1672 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1673 uni1673 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1674 uni1674 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1675 uni1675 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1676 uni1676 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d00 uni1D00 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d01 uni1D01 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d02 uni1D02 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+1d03 uni1D03 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d04 uni1D04 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d05 uni1D05 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d06 uni1D06 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d07 uni1D07 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d08 uni1D08 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1d09 uni1D09 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+1d0a uni1D0A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d0b uni1D0B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d0c uni1D0C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d0d uni1D0D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d0e uni1D0E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d0f uni1D0F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d10 uni1D10 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d11 uni1D11 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d12 uni1D12 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d13 uni1D13 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d14 uni1D14 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+1d16 uni1D16 2.3 +U+1d17 uni1D17 2.3 +U+1d18 uni1D18 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d19 uni1D19 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d1a uni1D1A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d1b uni1D1B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d1c uni1D1C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d1d uni1D1D 2.3 +U+1d1e uni1D1E 2.3 +U+1d1f uni1D1F 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1d20 uni1D20 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d21 uni1D21 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d22 uni1D22 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d23 uni1D23 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d26 uni1D26 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d27 uni1D27 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d28 uni1D28 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+1d29 uni1D29 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d2a uni1D2A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d2b uni1D2B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1d2c uni1D2C 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d2d uni1D2D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d2e uni1D2E 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d30 uni1D30 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d31 uni1D31 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d32 uni1D32 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d33 uni1D33 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d34 uni1D34 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d35 uni1D35 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d36 uni1D36 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d37 uni1D37 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d38 uni1D38 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d39 uni1D39 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d3a uni1D3A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d3b uni1D3B 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d3c uni1D3C 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d3d uni1D3D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d3e uni1D3E 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d3f uni1D3F 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d40 uni1D40 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d41 uni1D41 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d42 uni1D42 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d43 uni1D43 2.3 +U+1d44 uni1D44 2.3 +U+1d45 uni1D45 2.3 +U+1d46 uni1D46 2.3 +U+1d47 uni1D47 2.3 +U+1d48 uni1D48 2.3 +U+1d49 uni1D49 2.3 +U+1d4a uni1D4A 2.3 +U+1d4b uni1D4B 2.3 +U+1d4c uni1D4C 2.3 +U+1d4d uni1D4D 2.3 +U+1d4e uni1D4E 2.3 +U+1d4f uni1D4F 2.3 +U+1d50 uni1D50 2.3 +U+1d51 uni1D51 2.3 +U+1d52 uni1D52 2.3 +U+1d53 uni1D53 2.3 +U+1d54 uni1D54 2.3 +U+1d55 uni1D55 2.3 +U+1d56 uni1D56 2.3 +U+1d57 uni1D57 2.3 +U+1d58 uni1D58 2.3 +U+1d59 uni1D59 2.3 +U+1d5a uni1D5A 2.3 +U+1d5b uni1D5B 2.3 +U+1d5c uni1D5C 2.10 (Sans Oblique) 2.11 (Sans Condensed Oblique) +U+1d5d uni1D5D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d5e uni1D5E 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d5f uni1D5F 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d60 uni1D60 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d61 uni1D61 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d62 uni1D62 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d63 uni1D63 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d64 uni1D64 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d65 uni1D65 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d66 uni1D66 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d67 uni1D67 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d68 uni1D68 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d69 uni1D69 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d6a uni1D6A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d77 uni1D77 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+1d78 uni1D78 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1d7b uni1D7B 2.3 +U+1d85 uni1D85 2.3 +U+1d9b uni1D9B 2.3 +U+1d9c uni1D9C 2.3 +U+1d9d uni1D9D 2.3 +U+1d9e uni1D9E 2.3 +U+1d9f uni1D9F 2.3 +U+1da0 uni1DA0 2.3 +U+1da1 uni1DA1 2.3 +U+1da2 uni1DA2 2.3 +U+1da3 uni1DA3 2.3 +U+1da4 uni1DA4 2.3 +U+1da5 uni1DA5 2.3 +U+1da6 uni1DA6 2.3 +U+1da7 uni1DA7 2.3 +U+1da8 uni1DA8 2.3 +U+1da9 uni1DA9 2.3 +U+1daa uni1DAA 2.3 +U+1dab uni1DAB 2.3 +U+1dac uni1DAC 2.3 +U+1dad uni1DAD 2.3 +U+1dae uni1DAE 2.3 +U+1daf uni1DAF 2.3 +U+1db0 uni1DB0 2.3 +U+1db1 uni1DB1 2.3 +U+1db2 uni1DB2 2.3 +U+1db3 uni1DB3 2.3 +U+1db4 uni1DB4 2.3 +U+1db5 uni1DB5 2.3 +U+1db6 uni1DB6 2.3 +U+1db7 uni1DB7 2.3 +U+1db8 uni1DB8 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+1db9 uni1DB9 2.3 +U+1dba uni1DBA 2.3 +U+1dbb uni1DBB 2.3 +U+1dbc uni1DBC 2.3 +U+1dbd uni1DBD 2.3 +U+1dbe uni1DBE 2.3 +U+1dbf uni1DBF 2.3 +U+1dc4 uni1DC4 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1dc5 uni1DC5 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1dc6 uni1DC6 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1dc7 uni1DC7 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1dc8 uni1DC8 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1dc9 uni1DC9 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+1e00 uni1E00 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e01 uni1E01 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e02 uni1E02 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e03 uni1E03 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e04 uni1E04 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e05 uni1E05 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e06 uni1E06 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e07 uni1E07 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e08 uni1E08 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e09 uni1E09 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e0a uni1E0A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e0b uni1E0B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e0c uni1E0C 2.1 +U+1e0d uni1E0D 2.1 +U+1e0e uni1E0E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e0f uni1E0F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e10 uni1E10 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e11 uni1E11 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e12 uni1E12 1.13 +U+1e13 uni1E13 1.13 +U+1e14 uni1E14 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e15 uni1E15 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e16 uni1E16 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e17 uni1E17 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e18 uni1E18 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e19 uni1E19 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e1a uni1E1A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e1b uni1E1B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e1c uni1E1C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e1d uni1E1D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e1e uni1E1E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e1f uni1E1F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e20 uni1E20 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e21 uni1E21 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e22 uni1E22 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e23 uni1E23 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e24 uni1E24 2.1 +U+1e25 uni1E25 2.1 +U+1e26 uni1E26 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e27 uni1E27 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e28 uni1E28 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e29 uni1E29 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e2a uni1E2A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e2b uni1E2B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e2c uni1E2C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e2d uni1E2D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e2e uni1E2E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e2f uni1E2F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e30 uni1E30 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e31 uni1E31 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e32 uni1E32 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e33 uni1E33 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e34 uni1E34 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e35 uni1E35 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e36 uni1E36 2.1 +U+1e37 uni1E37 2.1 +U+1e38 uni1E38 2.1 +U+1e39 uni1E39 2.1 +U+1e3a uni1E3A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e3b uni1E3B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e3c uni1E3C 1.13 +U+1e3d uni1E3D 1.13 +U+1e3e uni1E3E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e3f uni1E3F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e40 uni1E40 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e41 uni1E41 2.1 +U+1e42 uni1E42 2.1 +U+1e43 uni1E43 2.1 +U+1e44 uni1E44 1.13 +U+1e45 uni1E45 1.13 +U+1e46 uni1E46 2.1 +U+1e47 uni1E47 2.1 +U+1e48 uni1E48 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e49 uni1E49 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e4a uni1E4A 1.13 +U+1e4b uni1E4B 1.13 +U+1e4c uni1E4C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e4d uni1E4D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e4e uni1E4E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e4f uni1E4F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e50 uni1E50 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e51 uni1E51 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e52 uni1E52 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e53 uni1E53 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e54 uni1E54 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e55 uni1E55 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e56 uni1E56 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e57 uni1E57 2.1 +U+1e58 uni1E58 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e59 uni1E59 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e5a uni1E5A 2.1 +U+1e5b uni1E5B 2.1 +U+1e5c uni1E5C 2.1 +U+1e5d uni1E5D 2.1 +U+1e5e uni1E5E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e5f uni1E5F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e60 uni1E60 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e61 uni1E61 2.1 +U+1e62 uni1E62 2.1 +U+1e63 uni1E63 2.1 +U+1e64 uni1E64 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1e65 uni1E65 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1e66 uni1E66 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e67 uni1E67 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1e68 uni1E68 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e69 uni1E69 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e6a uni1E6A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e6b uni1E6B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e6c uni1E6C 2.1 +U+1e6d uni1E6D 2.1 +U+1e6e uni1E6E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e6f uni1E6F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e70 uni1E70 1.13 +U+1e71 uni1E71 1.13 +U+1e72 uni1E72 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e73 uni1E73 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e74 uni1E74 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e75 uni1E75 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e76 uni1E76 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e77 uni1E77 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e78 uni1E78 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e79 uni1E79 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e7a uni1E7A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e7b uni1E7B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1e7c uni1E7C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e7d uni1E7D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e7e uni1E7E 2.1 +U+1e7f uni1E7F 2.1 +U+1e80 Wgrave 1.2 +U+1e81 wgrave 1.2 +U+1e82 Wacute 1.2 +U+1e83 wacute 1.2 +U+1e84 Wdieresis 1.2 +U+1e85 wdieresis 1.2 +U+1e86 uni1E86 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e87 uni1E87 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e88 uni1E88 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e89 uni1E89 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e8a uni1E8A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e8b uni1E8B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e8c uni1E8C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e8d uni1E8D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e8e uni1E8E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e8f uni1E8F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e90 uni1E90 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e91 uni1E91 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e92 uni1E92 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e93 uni1E93 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e94 uni1E94 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e95 uni1E95 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e96 uni1E96 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1e97 uni1E97 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e98 uni1E98 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e99 uni1E99 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1e9a uni1E9A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans ExtraLight) +U+1e9b uni1E9B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ea0 uni1EA0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ea1 uni1EA1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ea2 uni1EA2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ea3 uni1EA3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ea4 uni1EA4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ea5 uni1EA5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ea6 uni1EA6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ea7 uni1EA7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ea8 uni1EA8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ea9 uni1EA9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1eaa uni1EAA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1eab uni1EAB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1eac uni1EAC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1ead uni1EAD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1eae uni1EAE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eaf uni1EAF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb0 uni1EB0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb1 uni1EB1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb2 uni1EB2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb3 uni1EB3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb4 uni1EB4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb5 uni1EB5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eb6 uni1EB6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1eb7 uni1EB7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1eb8 uni1EB8 2.2 +U+1eb9 uni1EB9 2.2 +U+1eba uni1EBA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ebb uni1EBB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ebc uni1EBC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ebd uni1EBD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ebe uni1EBE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ebf uni1EBF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec0 uni1EC0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec1 uni1EC1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec2 uni1EC2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec3 uni1EC3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec4 uni1EC4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec5 uni1EC5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ec6 uni1EC6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1ec7 uni1EC7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1ec8 uni1EC8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ec9 uni1EC9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1eca uni1ECA 2.2 +U+1ecb uni1ECB 2.2 +U+1ecc uni1ECC 2.2 +U+1ecd uni1ECD 2.2 +U+1ece uni1ECE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ecf uni1ECF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ed0 uni1ED0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed1 uni1ED1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed2 uni1ED2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed3 uni1ED3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed4 uni1ED4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed5 uni1ED5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed6 uni1ED6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed7 uni1ED7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ed8 uni1ED8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1ed9 uni1ED9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+1eda uni1EDA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1edb uni1EDB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1edc uni1EDC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1edd uni1EDD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ede uni1EDE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1edf uni1EDF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1ee0 uni1EE0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ee1 uni1EE1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ee2 uni1EE2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ee3 uni1EE3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ee4 uni1EE4 2.2 +U+1ee5 uni1EE5 2.2 +U+1ee6 uni1EE6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ee7 uni1EE7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ee8 uni1EE8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ee9 uni1EE9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1eea uni1EEA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1eeb uni1EEB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1eec uni1EEC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1eed uni1EED 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+1eee uni1EEE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1eef uni1EEF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ef0 uni1EF0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ef1 uni1EF1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+1ef2 Ygrave 1.2 +U+1ef3 ygrave 1.2 +U+1ef4 uni1EF4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ef5 uni1EF5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ef6 uni1EF6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ef7 uni1EF7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans ExtraLight) +U+1ef8 uni1EF8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ef9 uni1EF9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f00 uni1F00 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f01 uni1F01 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f02 uni1F02 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f03 uni1F03 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f04 uni1F04 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f05 uni1F05 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f06 uni1F06 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f07 uni1F07 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f08 uni1F08 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f09 uni1F09 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f0a uni1F0A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f0b uni1F0B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f0c uni1F0C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f0d uni1F0D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f0e uni1F0E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f0f uni1F0F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f10 uni1F10 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f11 uni1F11 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f12 uni1F12 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f13 uni1F13 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f14 uni1F14 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f15 uni1F15 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f18 uni1F18 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f19 uni1F19 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f1a uni1F1A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f1b uni1F1B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f1c uni1F1C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f1d uni1F1D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f20 uni1F20 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f21 uni1F21 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f22 uni1F22 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f23 uni1F23 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f24 uni1F24 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f25 uni1F25 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f26 uni1F26 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f27 uni1F27 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f28 uni1F28 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f29 uni1F29 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f2a uni1F2A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f2b uni1F2B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f2c uni1F2C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f2d uni1F2D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f2e uni1F2E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f2f uni1F2F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f30 uni1F30 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f31 uni1F31 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f32 uni1F32 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f33 uni1F33 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f34 uni1F34 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f35 uni1F35 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f36 uni1F36 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f37 uni1F37 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f38 uni1F38 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f39 uni1F39 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f3a uni1F3A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f3b uni1F3B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f3c uni1F3C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f3d uni1F3D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f3e uni1F3E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f3f uni1F3F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f40 uni1F40 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f41 uni1F41 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f42 uni1F42 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f43 uni1F43 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f44 uni1F44 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f45 uni1F45 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f48 uni1F48 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f49 uni1F49 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f4a uni1F4A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f4b uni1F4B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f4c uni1F4C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f4d uni1F4D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f50 uni1F50 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f51 uni1F51 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f52 uni1F52 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f53 uni1F53 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f54 uni1F54 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f55 uni1F55 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f56 uni1F56 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f57 uni1F57 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f59 uni1F59 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f5b uni1F5B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f5d uni1F5D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f5f uni1F5F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f60 uni1F60 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f61 uni1F61 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f62 uni1F62 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f63 uni1F63 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f64 uni1F64 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f65 uni1F65 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f66 uni1F66 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f67 uni1F67 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f68 uni1F68 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f69 uni1F69 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f6a uni1F6A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f6b uni1F6B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f6c uni1F6C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f6d uni1F6D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f6e uni1F6E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f6f uni1F6F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f70 uni1F70 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f71 uni1F71 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f72 uni1F72 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f73 uni1F73 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f74 uni1F74 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f75 uni1F75 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f76 uni1F76 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f77 uni1F77 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f78 uni1F78 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f79 uni1F79 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1f7a uni1F7A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f7b uni1F7B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f7c uni1F7C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f7d uni1F7D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f80 uni1F80 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f81 uni1F81 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f82 uni1F82 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f83 uni1F83 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f84 uni1F84 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f85 uni1F85 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f86 uni1F86 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f87 uni1F87 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f88 uni1F88 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f89 uni1F89 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f8a uni1F8A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f8b uni1F8B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f8c uni1F8C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f8d uni1F8D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f8e uni1F8E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f8f uni1F8F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f90 uni1F90 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f91 uni1F91 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f92 uni1F92 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f93 uni1F93 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f94 uni1F94 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f95 uni1F95 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f96 uni1F96 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f97 uni1F97 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f98 uni1F98 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f99 uni1F99 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f9a uni1F9A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f9b uni1F9B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f9c uni1F9C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f9d uni1F9D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f9e uni1F9E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1f9f uni1F9F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa0 uni1FA0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa1 uni1FA1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa2 uni1FA2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa3 uni1FA3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa4 uni1FA4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa5 uni1FA5 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa6 uni1FA6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa7 uni1FA7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa8 uni1FA8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fa9 uni1FA9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1faa uni1FAA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fab uni1FAB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fac uni1FAC 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fad uni1FAD 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fae uni1FAE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1faf uni1FAF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb0 uni1FB0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb1 uni1FB1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb2 uni1FB2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb3 uni1FB3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb4 uni1FB4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb6 uni1FB6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb7 uni1FB7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fb8 uni1FB8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fb9 uni1FB9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fba uni1FBA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fbb uni1FBB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fbc uni1FBC 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fbd uni1FBD 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fbe uni1FBE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fbf uni1FBF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fc0 uni1FC0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fc1 uni1FC1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fc2 uni1FC2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fc3 uni1FC3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fc4 uni1FC4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fc6 uni1FC6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fc7 uni1FC7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fc8 uni1FC8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fc9 uni1FC9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fca uni1FCA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fcb uni1FCB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fcc uni1FCC 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.10 (Sans ExtraLight) +U+1fcd uni1FCD 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fce uni1FCE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fcf uni1FCF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd0 uni1FD0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd1 uni1FD1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd2 uni1FD2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd3 uni1FD3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd6 uni1FD6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd7 uni1FD7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fd8 uni1FD8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fd9 uni1FD9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fda uni1FDA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fdb uni1FDB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fdd uni1FDD 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fde uni1FDE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fdf uni1FDF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe0 uni1FE0 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe1 uni1FE1 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe2 uni1FE2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe3 uni1FE3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe4 uni1FE4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe5 uni1FE5 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe6 uni1FE6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe7 uni1FE7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fe8 uni1FE8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fe9 uni1FE9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fea uni1FEA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1feb uni1FEB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fec uni1FEC 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1fed uni1FED 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fee uni1FEE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1fef uni1FEF 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ff2 uni1FF2 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ff3 uni1FF3 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ff4 uni1FF4 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ff6 uni1FF6 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ff7 uni1FF7 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ff8 uni1FF8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ff9 uni1FF9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ffa uni1FFA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ffb uni1FFB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.10 (Sans ExtraLight) +U+1ffc uni1FFC 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+1ffd uni1FFD 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+1ffe uni1FFE 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.5 (Sans ExtraLight) +U+2000 uni2000 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2001 uni2001 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2002 uni2002 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2003 uni2003 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2004 uni2004 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2005 uni2005 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2006 uni2006 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2007 uni2007 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2008 uni2008 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2009 uni2009 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+200a uni200A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+200b uni200B 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.8 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+200c afii61664 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.8 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+200d afii301 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.8 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+200e afii299 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.8 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+200f afii300 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.8 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2010 uni2010 1.5 +U+2011 uni2011 1.5 +U+2012 figuredash 1.5 +U+2013 endash original +U+2014 emdash original +U+2015 afii00208 1.5 +U+2016 uni2016 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2017 underscoredbl 2.3 +U+2018 quoteleft original +U+2019 quoteright original +U+201a quotesinglbase original +U+201b quotereversed 2.3 +U+201c quotedblleft original +U+201d quotedblright original +U+201e quotedblbase original +U+201f uni201F 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.3 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) +U+2020 dagger original +U+2021 daggerdbl original +U+2022 bullet original +U+2023 uni2023 2.2 +U+2024 onedotenleader 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2025 twodotenleader 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2026 ellipsis original +U+2027 uni2027 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+202a uni202A 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+202b uni202B 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+202c afii61573 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+202d afii61574 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+202e afii61575 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+202f uni202F 2.11 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2030 perthousand original +U+2031 uni2031 2.1 +U+2032 minute 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2033 second 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2034 uni2034 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2035 uni2035 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2036 uni2036 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2037 uni2037 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2038 uni2038 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2039 guilsinglleft original +U+203a guilsinglright original +U+203b uni203B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+203c exclamdbl 2.0 +U+203d uni203D 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.11 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.14 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+203e uni203E 2.3 +U+203f uni203F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2040 uni2040 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2041 uni2041 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2042 uni2042 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2043 uni2043 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2044 fraction 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2045 uni2045 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2046 uni2046 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2047 uni2047 2.0 +U+2048 uni2048 2.0 +U+2049 uni2049 2.0 +U+204a uni204A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+204b uni204B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+204c uni204C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+204d uni204D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+204e uni204E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+204f uni204F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2050 uni2050 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2051 uni2051 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2052 uni2052 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2053 uni2053 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2054 uni2054 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2055 uni2055 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2056 uni2056 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2057 uni2057 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2058 uni2058 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2059 uni2059 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+205a uni205A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+205b uni205B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+205c uni205C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+205d uni205D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+205e uni205E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+205f uni205F 2.14 +U+2060 uni2060 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2061 uni2061 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2062 uni2062 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2063 uni2063 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+206a uni206A 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+206b uni206B 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+206c uni206C 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+206d uni206D 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+206e uni206E 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+206f uni206F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2070 uni2070 2.2 +U+2071 uni2071 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2074 uni2074 2.2 +U+2075 uni2075 2.2 +U+2076 uni2076 2.2 +U+2077 uni2077 2.2 +U+2078 uni2078 2.2 +U+2079 uni2079 2.2 +U+207a uni207A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+207b uni207B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+207c uni207C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+207d uni207D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+207e uni207E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+207f uni207F 1.14 +U+2080 uni2080 2.4 +U+2081 uni2081 2.4 +U+2082 uni2082 2.4 +U+2083 uni2083 2.4 +U+2084 uni2084 2.4 +U+2085 uni2085 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2086 uni2086 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2087 uni2087 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2088 uni2088 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2089 uni2089 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+208a uni208A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+208b uni208B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+208c uni208C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+208d uni208D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+208e uni208E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2090 uni2090 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2091 uni2091 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2092 uni2092 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2093 uni2093 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2094 uni2094 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+20a0 uni20A0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a1 colonmonetary 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a2 uni20A2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a3 franc 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a4 lira 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a5 uni20A5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a6 uni20A6 2.3 +U+20a7 peseta 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a8 uni20A8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20a9 uni20A9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20aa afii57636 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20ab dong 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+20ac Euro original +U+20ad uni20AD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20ae uni20AE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20af uni20AF 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+20b0 uni20B0 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+20b1 uni20B1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.14 (Sans ExtraLight, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+20b2 uni20B2 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+20b3 uni20B3 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+20b4 uni20B4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+20b5 uni20B5 2.2 +U+20d0 uni20D0 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+20d1 uni20D1 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+20d6 uni20D6 2.8 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+20d7 uni20D7 2.8 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2100 uni2100 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2101 uni2101 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2102 uni2102 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2103 uni2103 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2104 uni2104 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2105 afii61248 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2106 uni2106 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2107 uni2107 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2108 uni2108 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2109 uni2109 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+210b uni210B 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+210c uni210C 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+210d uni210D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+210e uni210E 2.5 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+210f uni210F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2110 uni2110 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2111 Ifraktur 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2112 uni2112 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2113 afii61289 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2114 uni2114 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2115 uni2115 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2116 afii61352 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2117 uni2117 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2118 weierstrass 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2119 uni2119 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+211a uni211A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+211b uni211B 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+211c Rfraktur 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+211d uni211D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+211e prescription 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+211f uni211F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2120 uni2120 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2121 uni2121 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2122 trademark original +U+2123 uni2123 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2124 uni2124 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2125 uni2125 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2126 uni2126 2.2 +U+2127 uni2127 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2128 uni2128 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2129 uni2129 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+212a uni212A 2.2 +U+212b uni212B 2.2 +U+212c uni212C 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+212d uni212D 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+212e estimated 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+212f uni212F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2130 uni2130 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2131 uni2131 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2132 uni2132 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+2133 uni2133 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2134 uni2134 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2135 aleph 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2136 uni2136 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2137 uni2137 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2138 uni2138 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2139 uni2139 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+213a uni213A 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+213b uni213B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+213c uni213C 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+213d uni213D 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+213e uni213E 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+213f uni213F 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2140 uni2140 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2141 uni2141 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2142 uni2142 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2143 uni2143 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2144 uni2144 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2145 uni2145 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2146 uni2146 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2147 uni2147 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2148 uni2148 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2149 uni2149 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+214b uni214B 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+214e uni214E 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2153 onethird 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2154 twothirds 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2155 uni2155 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2156 uni2156 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2157 uni2157 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2158 uni2158 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2159 uni2159 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+215a uni215A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+215b oneeighth 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+215c threeeighths 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+215d fiveeighths 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+215e seveneighths 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+215f uni215F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.6 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2160 uni2160 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2161 uni2161 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2162 uni2162 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2163 uni2163 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2164 uni2164 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2165 uni2165 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2166 uni2166 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2167 uni2167 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2168 uni2168 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2169 uni2169 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+216a uni216A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+216b uni216B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+216c uni216C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+216d uni216D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+216e uni216E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+216f uni216F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2170 uni2170 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2171 uni2171 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2172 uni2172 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2173 uni2173 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2174 uni2174 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2175 uni2175 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2176 uni2176 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2177 uni2177 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2178 uni2178 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2179 uni2179 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+217a uni217A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+217b uni217B 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+217c uni217C 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+217d uni217D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+217e uni217E 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+217f uni217F 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2180 uni2180 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+2181 uni2181 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2182 uni2182 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2183 uni2183 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) +U+2184 uni2184 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+2190 arrowleft 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2191 arrowup 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2192 arrowright 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2193 arrowdown 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2194 arrowboth 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2195 arrowupdn 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2196 uni2196 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2197 uni2197 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2198 uni2198 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2199 uni2199 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+219a uni219A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+219b uni219B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+219c uni219C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+219d uni219D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+219e uni219E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+219f uni219F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a0 uni21A0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a1 uni21A1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a2 uni21A2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a3 uni21A3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a4 uni21A4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a5 uni21A5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a6 uni21A6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a7 uni21A7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a8 arrowupdnbse 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21a9 uni21A9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21aa uni21AA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ab uni21AB 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ac uni21AC 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ad uni21AD 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ae uni21AE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21af uni21AF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b0 uni21B0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b1 uni21B1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b2 uni21B2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b3 uni21B3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b4 uni21B4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b5 carriagereturn 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b6 uni21B6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b7 uni21B7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b8 uni21B8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21b9 uni21B9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ba uni21BA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21bb uni21BB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21bc uni21BC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21bd uni21BD 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21be uni21BE 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21bf uni21BF 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c0 uni21C0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c1 uni21C1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c2 uni21C2 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c3 uni21C3 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c4 uni21C4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c5 uni21C5 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c6 uni21C6 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c7 uni21C7 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c8 uni21C8 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21c9 uni21C9 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ca uni21CA 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21cb uni21CB 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21cc uni21CC 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21cd uni21CD 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ce uni21CE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21cf uni21CF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d0 arrowdblleft 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d1 arrowdblup 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d2 arrowdblright 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d3 arrowdbldown 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d4 arrowdblboth 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d5 uni21D5 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d6 uni21D6 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d7 uni21D7 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d8 uni21D8 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21d9 uni21D9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21da uni21DA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21db uni21DB 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21dc uni21DC 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21dd uni21DD 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21de uni21DE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21df uni21DF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e0 uni21E0 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e1 uni21E1 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e2 uni21E2 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e3 uni21E3 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e4 uni21E4 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e5 uni21E5 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e6 uni21E6 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e7 uni21E7 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e8 uni21E8 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21e9 uni21E9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ea uni21EA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21eb uni21EB 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ec uni21EC 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ed uni21ED 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ee uni21EE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ef uni21EF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f0 uni21F0 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f1 uni21F1 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f2 uni21F2 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f3 uni21F3 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f4 uni21F4 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f5 uni21F5 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f6 uni21F6 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f7 uni21F7 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f8 uni21F8 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21f9 uni21F9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21fa uni21FA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21fb uni21FB 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21fc uni21FC 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21fd uni21FD 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21fe uni21FE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+21ff uni21FF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2200 universal 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+2201 uni2201 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2202 partialdiff original +U+2203 existential 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans ExtraLight) +U+2204 uni2204 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2205 emptyset 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2206 Delta original +U+2207 gradient 2.1 +U+2208 element 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2209 notelement 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+220a uni220A 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+220b suchthat 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+220c uni220C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+220d uni220D 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+220e uni220E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+220f product original +U+2210 uni2210 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2211 summation original +U+2212 minus original +U+2213 uni2213 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2214 uni2214 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2215 fraction original +U+2216 uni2216 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2217 asteriskmath 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2218 uni2218 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2219 periodcentered original +U+221a radical original +U+221b uni221B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+221c uni221C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+221d proportional 2.1 +U+221e infinity original +U+221f orthogonal 2.1 +U+2220 angle 2.3 +U+2221 uni2221 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2222 uni2222 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2223 uni2223 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2224 uni2224 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2225 uni2225 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2226 uni2226 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2227 logicaland 2.1 +U+2228 logicalor 2.1 +U+2229 intersection 2.1 +U+222a union 2.1 +U+222b integral original +U+222c uni222C 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+222d uni222D 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+222e uni222E 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+222f uni222F 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2230 uni2230 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2231 uni2231 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2232 uni2232 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2233 uni2233 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2234 therefore 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2235 uni2235 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2236 uni2236 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2237 uni2237 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2238 uni2238 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2239 uni2239 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+223a uni223A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+223b uni223B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+223c similar 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+223d uni223D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+223e uni223E 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+223f uni223F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2240 uni2240 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2241 uni2241 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2242 uni2242 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2243 uni2243 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2244 uni2244 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2245 congruent 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2246 uni2246 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2247 uni2247 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2248 approxequal original +U+2249 uni2249 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+224a uni224A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+224b uni224B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+224c uni224C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+224d uni224D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+224e uni224E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+224f uni224F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2250 uni2250 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2251 uni2251 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2252 uni2252 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2253 uni2253 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2254 uni2254 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2255 uni2255 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2256 uni2256 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2257 uni2257 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2258 uni2258 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2259 uni2259 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+225a uni225A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+225b uni225B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+225c uni225C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+225d uni225D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+225e uni225E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+225f uni225F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2260 notequal original +U+2261 equivalence 2.1 +U+2262 uni2262 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2263 uni2263 2.1 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2264 lessequal original +U+2265 greaterequal original +U+2266 uni2266 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2267 uni2267 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2268 uni2268 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2269 uni2269 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+226a uni226A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+226b uni226B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+226c uni226C 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+226d uni226D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+226e uni226E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+226f uni226F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2270 uni2270 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2271 uni2271 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2272 uni2272 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2273 uni2273 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2274 uni2274 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2275 uni2275 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2276 uni2276 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2277 uni2277 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2278 uni2278 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2279 uni2279 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+227a uni227A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+227b uni227B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+227c uni227C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+227d uni227D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+227e uni227E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+227f uni227F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2280 uni2280 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2281 uni2281 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2282 propersubset 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2283 propersuperset 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2284 notsubset 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2285 uni2285 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2286 reflexsubset 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2287 reflexsuperset 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2288 uni2288 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2289 uni2289 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+228a uni228A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+228b uni228B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.6 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+228c uni228C 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+228d uni228D 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+228e uni228E 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+228f uni228F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2290 uni2290 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2291 uni2291 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2292 uni2292 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+2293 uni2293 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2294 uni2294 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2295 circleplus 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2296 uni2296 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2297 circlemultiply 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2298 uni2298 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2299 uni2299 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+229a uni229A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+229b uni229B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+229c uni229C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+229d uni229D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+229e uni229E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+229f uni229F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+22a0 uni22A0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+22a1 uni22A1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+22a2 uni22A2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a3 uni22A3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a4 uni22A4 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a5 perpendicular 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a6 uni22A6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a7 uni22A7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a8 uni22A8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22a9 uni22A9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22aa uni22AA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ab uni22AB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ac uni22AC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ad uni22AD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ae uni22AE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22af uni22AF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b2 uni22B2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b3 uni22B3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b4 uni22B4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b5 uni22B5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b6 uni22B6 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b7 uni22B7 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b8 uni22B8 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22b9 uni22B9 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ba uni22BA 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22bb uni22BB 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22bc uni22BC 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22bd uni22BD 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c0 uni22C0 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c1 uni22C1 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c2 uni22C2 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c3 uni22C3 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c4 uni22C4 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c5 dotmath 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+22c6 uni22C6 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+22c8 uni22C8 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22c9 uni22C9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ca uni22CA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22cb uni22CB 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22cc uni22CC 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22cd uni22CD 2.6 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) 2.7 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+22d6 uni22D6 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22d7 uni22D7 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22d8 uni22D8 2.6 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+22d9 uni22D9 2.6 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+22da uni22DA 2.6 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) 2.7 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+22db uni22DB 2.6 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) 2.7 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+22dc uni22DC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22dd uni22DD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22de uni22DE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22df uni22DF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e0 uni22E0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e1 uni22E1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e2 uni22E2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e3 uni22E3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e4 uni22E4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e5 uni22E5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e6 uni22E6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e7 uni22E7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e8 uni22E8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22e9 uni22E9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+22ea uni22EA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22eb uni22EB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ec uni22EC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ed uni22ED 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ef uni22EF 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+22f2 uni22F2 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f3 uni22F3 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f4 uni22F4 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f5 uni22F5 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f6 uni22F6 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f7 uni22F7 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f8 uni22F8 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22f9 uni22F9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22fa uni22FA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22fb uni22FB 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22fc uni22FC 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22fd uni22FD 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22fe uni22FE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+22ff uni22FF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2300 uni2300 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2301 uni2301 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2302 house 1.14 +U+2303 uni2303 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2304 uni2304 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2305 uni2305 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2306 uni2306 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2308 uni2308 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2309 uni2309 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+230a uni230A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+230b uni230B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+230c uni230C 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+230d uni230D 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+230e uni230E 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+230f uni230F 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2310 revlogicalnot 1.14 +U+2311 uni2311 1.15 +U+2312 uni2312 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2313 uni2313 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2314 uni2314 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2315 uni2315 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2318 uni2318 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2319 uni2319 1.14 +U+231c uni231C 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+231d uni231D 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+231e uni231E 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+231f uni231F 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2320 integraltp 2.3 +U+2321 integralbt 2.3 +U+2325 uni2325 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2326 uni2326 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2327 uni2327 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2328 uni2328 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2329 angleleft 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+232a angleright 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.10 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+232b uni232B 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2335 uni2335 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2337 uni2337 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2338 uni2338 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2339 uni2339 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+233a uni233A 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+233b uni233B 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+233c uni233C 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+233d uni233D 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+233e uni233E 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2341 uni2341 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2342 uni2342 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2343 uni2343 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2344 uni2344 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2347 uni2347 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2348 uni2348 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2349 uni2349 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+234b uni234B 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+234c uni234C 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+234d uni234D 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2350 uni2350 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2352 uni2352 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2353 uni2353 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2354 uni2354 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2357 uni2357 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2358 uni2358 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2359 uni2359 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+235a uni235A 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+235b uni235B 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+235c uni235C 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+235e uni235E 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+235f uni235F 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2360 uni2360 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2363 uni2363 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2364 uni2364 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2365 uni2365 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2368 uni2368 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2369 uni2369 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+236b uni236B 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+236c uni236C 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+236d uni236D 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+236e uni236E 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+236f uni236F 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2370 uni2370 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2373 uni2373 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2374 uni2374 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2375 uni2375 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2376 uni2376 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2377 uni2377 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2378 uni2378 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2379 uni2379 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+237a uni237A 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+237d uni237D 1.15 +U+2380 uni2380 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2381 uni2381 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2382 uni2382 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2383 uni2383 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2388 uni2388 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2389 uni2389 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+238a uni238A 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+238b uni238B 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+2395 uni2395 2.14 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) +U+239b uni239B 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+239c uni239C 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+239d uni239D 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+239e uni239E 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+239f uni239F 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a0 uni23A0 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a1 uni23A1 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a2 uni23A2 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a3 uni23A3 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a4 uni23A4 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a5 uni23A5 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a6 uni23A6 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a7 uni23A7 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a8 uni23A8 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23a9 uni23A9 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23aa uni23AA 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23ab uni23AB 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23ac uni23AC 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23ad uni23AD 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23ae uni23AE 2.3 +U+23ce uni23CE 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique) +U+23cf uni23CF 2.3 +U+2422 uni2422 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2423 uni2423 1.6 +U+2460 uni2460 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2461 uni2461 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2462 uni2462 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2463 uni2463 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2464 uni2464 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2465 uni2465 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2466 uni2466 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2467 uni2467 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2468 uni2468 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2469 uni2469 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2500 SF100000 1.12 (Sans Mono, Sans Mono Oblique) +U+2501 uni2501 1.12 (Sans Mono, Sans Mono Oblique) +U+2502 SF110000 1.12 (Sans Mono, Sans Mono Oblique) +U+2503 uni2503 1.12 (Sans Mono, Sans Mono Oblique) +U+2504 uni2504 1.12 (Sans Mono, Sans Mono Oblique) +U+2505 uni2505 1.12 (Sans Mono, Sans Mono Oblique) +U+2506 uni2506 1.12 (Sans Mono, Sans Mono Oblique) +U+2507 uni2507 1.12 (Sans Mono, Sans Mono Oblique) +U+2508 uni2508 1.12 (Sans Mono, Sans Mono Oblique) +U+2509 uni2509 1.12 (Sans Mono, Sans Mono Oblique) +U+250a uni250A 1.12 (Sans Mono, Sans Mono Oblique) +U+250b uni250B 1.12 (Sans Mono, Sans Mono Oblique) +U+250c SF010000 1.12 (Sans Mono, Sans Mono Oblique) +U+250d uni250D 1.12 (Sans Mono, Sans Mono Oblique) +U+250e uni250E 1.12 (Sans Mono, Sans Mono Oblique) +U+250f uni250F 1.12 (Sans Mono, Sans Mono Oblique) +U+2510 SF030000 1.12 (Sans Mono, Sans Mono Oblique) +U+2511 uni2511 1.12 (Sans Mono, Sans Mono Oblique) +U+2512 uni2512 1.12 (Sans Mono, Sans Mono Oblique) +U+2513 uni2513 1.12 (Sans Mono, Sans Mono Oblique) +U+2514 SF020000 1.12 (Sans Mono, Sans Mono Oblique) +U+2515 uni2515 1.12 (Sans Mono, Sans Mono Oblique) +U+2516 uni2516 1.12 (Sans Mono, Sans Mono Oblique) +U+2517 uni2517 1.12 (Sans Mono, Sans Mono Oblique) +U+2518 SF040000 1.12 (Sans Mono, Sans Mono Oblique) +U+2519 uni2519 1.12 (Sans Mono, Sans Mono Oblique) +U+251a uni251A 1.12 (Sans Mono, Sans Mono Oblique) +U+251b uni251B 1.12 (Sans Mono, Sans Mono Oblique) +U+251c SF080000 1.12 (Sans Mono, Sans Mono Oblique) +U+251d uni251D 1.12 (Sans Mono, Sans Mono Oblique) +U+251e uni251E 1.12 (Sans Mono, Sans Mono Oblique) +U+251f uni251F 1.12 (Sans Mono, Sans Mono Oblique) +U+2520 uni2520 1.12 (Sans Mono, Sans Mono Oblique) +U+2521 uni2521 1.12 (Sans Mono, Sans Mono Oblique) +U+2522 uni2522 1.12 (Sans Mono, Sans Mono Oblique) +U+2523 uni2523 1.12 (Sans Mono, Sans Mono Oblique) +U+2524 SF090000 1.12 (Sans Mono, Sans Mono Oblique) +U+2525 uni2525 1.12 (Sans Mono, Sans Mono Oblique) +U+2526 uni2526 1.12 (Sans Mono, Sans Mono Oblique) +U+2527 uni2527 1.12 (Sans Mono, Sans Mono Oblique) +U+2528 uni2528 1.12 (Sans Mono, Sans Mono Oblique) +U+2529 uni2529 1.12 (Sans Mono, Sans Mono Oblique) +U+252a uni252A 1.12 (Sans Mono, Sans Mono Oblique) +U+252b uni252B 1.12 (Sans Mono, Sans Mono Oblique) +U+252c SF060000 1.12 (Sans Mono, Sans Mono Oblique) +U+252d uni252D 1.12 (Sans Mono, Sans Mono Oblique) +U+252e uni252E 1.12 (Sans Mono, Sans Mono Oblique) +U+252f uni252F 1.12 (Sans Mono, Sans Mono Oblique) +U+2530 uni2530 1.12 (Sans Mono, Sans Mono Oblique) +U+2531 uni2531 1.12 (Sans Mono, Sans Mono Oblique) +U+2532 uni2532 1.12 (Sans Mono, Sans Mono Oblique) +U+2533 uni2533 1.12 (Sans Mono, Sans Mono Oblique) +U+2534 SF070000 1.12 (Sans Mono, Sans Mono Oblique) +U+2535 uni2535 1.12 (Sans Mono, Sans Mono Oblique) +U+2536 uni2536 1.12 (Sans Mono, Sans Mono Oblique) +U+2537 uni2537 1.12 (Sans Mono, Sans Mono Oblique) +U+2538 uni2538 1.12 (Sans Mono, Sans Mono Oblique) +U+2539 uni2539 1.12 (Sans Mono, Sans Mono Oblique) +U+253a uni253A 1.12 (Sans Mono, Sans Mono Oblique) +U+253b uni253B 1.12 (Sans Mono, Sans Mono Oblique) +U+253c SF050000 1.12 (Sans Mono, Sans Mono Oblique) +U+253d uni253D 1.12 (Sans Mono, Sans Mono Oblique) +U+253e uni253E 1.12 (Sans Mono, Sans Mono Oblique) +U+253f uni253F 1.12 (Sans Mono, Sans Mono Oblique) +U+2540 uni2540 1.12 (Sans Mono, Sans Mono Oblique) +U+2541 uni2541 1.12 (Sans Mono, Sans Mono Oblique) +U+2542 uni2542 1.12 (Sans Mono, Sans Mono Oblique) +U+2543 uni2543 1.12 (Sans Mono, Sans Mono Oblique) +U+2544 uni2544 1.12 (Sans Mono, Sans Mono Oblique) +U+2545 uni2545 1.12 (Sans Mono, Sans Mono Oblique) +U+2546 uni2546 1.12 (Sans Mono, Sans Mono Oblique) +U+2547 uni2547 1.12 (Sans Mono, Sans Mono Oblique) +U+2548 uni2548 1.12 (Sans Mono, Sans Mono Oblique) +U+2549 uni2549 1.12 (Sans Mono, Sans Mono Oblique) +U+254a uni254A 1.12 (Sans Mono, Sans Mono Oblique) +U+254b uni254B 1.12 (Sans Mono, Sans Mono Oblique) +U+254c uni254C 1.12 (Sans Mono, Sans Mono Oblique) +U+254d uni254D 1.12 (Sans Mono, Sans Mono Oblique) +U+254e uni254E 1.12 (Sans Mono, Sans Mono Oblique) +U+254f uni254F 1.12 (Sans Mono, Sans Mono Oblique) +U+2550 SF430000 1.12 (Sans Mono, Sans Mono Oblique) +U+2551 SF240000 1.12 (Sans Mono, Sans Mono Oblique) +U+2552 SF510000 1.12 (Sans Mono, Sans Mono Oblique) +U+2553 SF520000 1.12 (Sans Mono, Sans Mono Oblique) +U+2554 SF390000 1.12 (Sans Mono, Sans Mono Oblique) +U+2555 SF220000 1.12 (Sans Mono, Sans Mono Oblique) +U+2556 SF210000 1.12 (Sans Mono, Sans Mono Oblique) +U+2557 SF250000 1.12 (Sans Mono, Sans Mono Oblique) +U+2558 SF500000 1.12 (Sans Mono, Sans Mono Oblique) +U+2559 SF490000 1.12 (Sans Mono, Sans Mono Oblique) +U+255a SF380000 1.12 (Sans Mono, Sans Mono Oblique) +U+255b SF280000 1.12 (Sans Mono, Sans Mono Oblique) +U+255c SF270000 1.12 (Sans Mono, Sans Mono Oblique) +U+255d SF260000 1.12 (Sans Mono, Sans Mono Oblique) +U+255e SF360000 1.12 (Sans Mono, Sans Mono Oblique) +U+255f SF370000 1.12 (Sans Mono, Sans Mono Oblique) +U+2560 SF420000 1.12 (Sans Mono, Sans Mono Oblique) +U+2561 SF190000 1.12 (Sans Mono, Sans Mono Oblique) +U+2562 SF200000 1.12 (Sans Mono, Sans Mono Oblique) +U+2563 SF230000 1.12 (Sans Mono, Sans Mono Oblique) +U+2564 SF470000 1.12 (Sans Mono, Sans Mono Oblique) +U+2565 SF480000 1.12 (Sans Mono, Sans Mono Oblique) +U+2566 SF410000 1.12 (Sans Mono, Sans Mono Oblique) +U+2567 SF450000 1.12 (Sans Mono, Sans Mono Oblique) +U+2568 SF460000 1.12 (Sans Mono, Sans Mono Oblique) +U+2569 SF400000 1.12 (Sans Mono, Sans Mono Oblique) +U+256a SF540000 1.12 (Sans Mono, Sans Mono Oblique) +U+256b SF530000 1.12 (Sans Mono, Sans Mono Oblique) +U+256c SF440000 1.12 (Sans Mono, Sans Mono Oblique) +U+256d uni256D 1.12 (Sans Mono, Sans Mono Oblique) +U+256e uni256E 1.12 (Sans Mono, Sans Mono Oblique) +U+256f uni256F 1.12 (Sans Mono, Sans Mono Oblique) +U+2570 uni2570 1.12 (Sans Mono, Sans Mono Oblique) +U+2571 uni2571 1.12 (Sans Mono, Sans Mono Oblique) +U+2572 uni2572 1.12 (Sans Mono, Sans Mono Oblique) +U+2573 uni2573 1.12 (Sans Mono, Sans Mono Oblique) +U+2574 uni2574 1.12 (Sans Mono, Sans Mono Oblique) +U+2575 uni2575 1.12 (Sans Mono, Sans Mono Oblique) +U+2576 uni2576 1.12 (Sans Mono, Sans Mono Oblique) +U+2577 uni2577 1.12 (Sans Mono, Sans Mono Oblique) +U+2578 uni2578 1.12 (Sans Mono, Sans Mono Oblique) +U+2579 uni2579 1.12 (Sans Mono, Sans Mono Oblique) +U+257a uni257A 1.12 (Sans Mono, Sans Mono Oblique) +U+257b uni257B 1.12 (Sans Mono, Sans Mono Oblique) +U+257c uni257C 1.12 (Sans Mono, Sans Mono Oblique) +U+257d uni257D 1.12 (Sans Mono, Sans Mono Oblique) +U+257e uni257E 1.12 (Sans Mono, Sans Mono Oblique) +U+257f uni257F 1.12 (Sans Mono, Sans Mono Oblique) +U+2580 upblock 1.14 +U+2581 uni2581 1.14 +U+2582 uni2582 1.14 +U+2583 uni2583 1.14 +U+2584 dnblock 1.14 +U+2585 uni2585 1.14 +U+2586 uni2586 1.14 +U+2587 uni2587 1.14 +U+2588 block 1.14 +U+2589 uni2589 1.14 +U+258a uni258A 1.14 +U+258b uni258B 1.14 +U+258c lfblock 1.14 +U+258d uni258D 1.14 +U+258e uni258E 1.14 +U+258f uni258F 1.14 +U+2590 rtblock 1.14 +U+2591 ltshade 1.15 +U+2592 shade 1.15 +U+2593 dkshade 1.15 +U+2594 uni2594 1.14 +U+2595 uni2595 1.14 +U+2596 uni2596 1.14 +U+2597 uni2597 1.14 +U+2598 uni2598 1.14 +U+2599 uni2599 1.14 +U+259a uni259A 1.14 +U+259b uni259B 1.14 +U+259c uni259C 1.14 +U+259d uni259D 1.14 +U+259e uni259E 1.14 +U+259f uni259F 1.14 +U+25a0 filledbox 2.3 +U+25a1 H22073 2.3 +U+25a2 uni25A2 2.3 +U+25a3 uni25A3 2.3 +U+25a4 uni25A4 2.3 +U+25a5 uni25A5 2.3 +U+25a6 uni25A6 2.3 +U+25a7 uni25A7 2.3 +U+25a8 uni25A8 2.3 +U+25a9 uni25A9 2.3 +U+25aa H18543 2.3 +U+25ab H18551 2.3 +U+25ac filledrect 2.3 +U+25ad uni25AD 2.3 +U+25ae uni25AE 2.3 +U+25af uni25AF 2.3 +U+25b0 uni25B0 2.3 +U+25b1 uni25B1 2.3 +U+25b2 triagup 2.3 +U+25b3 uni25B3 2.3 +U+25b4 uni25B4 2.3 +U+25b5 uni25B5 2.3 +U+25b6 uni25B6 2.3 +U+25b7 uni25B7 2.3 +U+25b8 uni25B8 2.3 +U+25b9 uni25B9 2.3 +U+25ba triagrt 2.3 +U+25bb uni25BB 2.3 +U+25bc triagdn 2.3 +U+25bd uni25BD 2.3 +U+25be uni25BE 2.3 +U+25bf uni25BF 2.3 +U+25c0 uni25C0 2.3 +U+25c1 uni25C1 2.3 +U+25c2 uni25C2 2.3 +U+25c3 uni25C3 2.3 +U+25c4 triaglf 2.3 +U+25c5 uni25C5 2.3 +U+25c6 uni25C6 2.3 +U+25c7 uni25C7 2.3 +U+25c8 uni25C8 2.3 +U+25c9 uni25C9 2.3 +U+25ca lozenge original +U+25cb circle 2.3 +U+25cc uni25CC 2.3 +U+25cd uni25CD 2.3 +U+25ce uni25CE 2.3 +U+25cf H18533 2.3 +U+25d0 uni25D0 2.3 +U+25d1 uni25D1 2.3 +U+25d2 uni25D2 2.3 +U+25d3 uni25D3 2.3 +U+25d4 uni25D4 2.3 +U+25d5 uni25D5 2.3 +U+25d6 uni25D6 2.3 +U+25d7 uni25D7 2.3 +U+25d8 invbullet 2.2 +U+25d9 invcircle 2.3 +U+25da uni25DA 2.3 +U+25db uni25DB 2.3 +U+25dc uni25DC 2.3 +U+25dd uni25DD 2.3 +U+25de uni25DE 2.3 +U+25df uni25DF 2.3 +U+25e0 uni25E0 2.3 +U+25e1 uni25E1 2.3 +U+25e2 uni25E2 2.3 +U+25e3 uni25E3 2.3 +U+25e4 uni25E4 2.3 +U+25e5 uni25E5 2.3 +U+25e6 openbullet 2.2 +U+25e7 uni25E7 2.3 +U+25e8 uni25E8 2.3 +U+25e9 uni25E9 2.3 +U+25ea uni25EA 2.3 +U+25eb uni25EB 2.3 +U+25ec uni25EC 2.3 +U+25ed uni25ED 2.3 +U+25ee uni25EE 2.3 +U+25ef uni25EF 2.3 +U+25f0 uni25F0 2.3 +U+25f1 uni25F1 2.3 +U+25f2 uni25F2 2.3 +U+25f3 uni25F3 2.3 +U+25f4 uni25F4 2.3 +U+25f5 uni25F5 2.3 +U+25f6 uni25F6 2.3 +U+25f7 uni25F7 2.3 +U+25f8 uni25F8 2.3 +U+25f9 uni25F9 2.3 +U+25fa uni25FA 2.3 +U+25fb uni25FB 2.3 +U+25fc uni25FC 2.3 +U+25fd uni25FD 2.3 +U+25fe uni25FE 2.3 +U+25ff uni25FF 2.3 +U+2600 uni2600 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2601 uni2601 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2602 uni2602 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2603 uni2603 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2604 uni2604 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2605 uni2605 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2606 uni2606 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2607 uni2607 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2608 uni2608 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2609 uni2609 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+260a uni260A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+260b uni260B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+260c uni260C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+260d uni260D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+260e uni260E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+260f uni260F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2610 uni2610 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2611 uni2611 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2612 uni2612 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2613 uni2613 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2614 uni2614 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2615 uni2615 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2616 uni2616 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2617 uni2617 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2618 uni2618 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2619 uni2619 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+261a uni261A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+261b uni261B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+261c uni261C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+261d uni261D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+261e uni261E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+261f uni261F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2620 uni2620 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2621 uni2621 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2622 uni2622 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2623 uni2623 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2624 uni2624 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2625 uni2625 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2626 uni2626 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2627 uni2627 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2628 uni2628 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2629 uni2629 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+262a uni262A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+262b uni262B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+262c uni262C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+262d uni262D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+262e uni262E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+262f uni262F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2630 uni2630 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2631 uni2631 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2632 uni2632 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2633 uni2633 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2634 uni2634 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2635 uni2635 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2636 uni2636 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2637 uni2637 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2638 uni2638 1.15 +U+2639 uni2639 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+263a smileface 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+263b invsmileface 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+263c sun 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+263d uni263D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+263e uni263E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+263f uni263F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2640 female 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2641 uni2641 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2642 male 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2643 uni2643 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2644 uni2644 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2645 uni2645 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2646 uni2646 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2647 uni2647 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2648 uni2648 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2649 uni2649 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+264a uni264A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+264b uni264B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+264c uni264C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+264d uni264D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+264e uni264E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+264f uni264F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2650 uni2650 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2651 uni2651 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2652 uni2652 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2653 uni2653 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2654 uni2654 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2655 uni2655 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2656 uni2656 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2657 uni2657 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2658 uni2658 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2659 uni2659 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+265a uni265A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+265b uni265B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+265c uni265C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+265d uni265D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+265e uni265E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+265f uni265F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2660 spade 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2661 uni2661 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2662 uni2662 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2663 club 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2664 uni2664 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2665 heart 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2666 diamond 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2667 uni2667 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2668 uni2668 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2669 uni2669 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+266a musicalnote 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+266b musicalnotedbl 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+266c uni266C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+266d uni266D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+266e uni266E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+266f uni266F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2670 uni2670 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2671 uni2671 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2672 uni2672 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2673 uni2673 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2674 uni2674 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2675 uni2675 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2676 uni2676 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2677 uni2677 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2678 uni2678 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2679 uni2679 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+267a uni267A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+267b uni267B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+267c uni267C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+267d uni267D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+267e uni267E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+267f uni267F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2680 uni2680 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold) +U+2681 uni2681 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold) +U+2682 uni2682 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold) +U+2683 uni2683 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold) +U+2684 uni2684 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold) +U+2685 uni2685 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.4 (Sans ExtraLight) 2.7 (Sans Mono, Sans Mono Bold) +U+2686 uni2686 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2687 uni2687 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2688 uni2688 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2689 uni2689 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+268a uni268A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+268b uni268B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+268c uni268C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+268d uni268D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+268e uni268E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+268f uni268F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+2690 uni2690 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2691 uni2691 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2692 uni2692 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2693 uni2693 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2694 uni2694 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2695 uni2695 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2696 uni2696 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2697 uni2697 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2698 uni2698 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2699 uni2699 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+269a uni269A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+269b uni269B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+269c uni269C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+26a0 uni26A0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+26a1 uni26A1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+26a2 uni26A2 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a3 uni26A3 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a4 uni26A4 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a5 uni26A5 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a6 uni26A6 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a7 uni26A7 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a8 uni26A8 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26a9 uni26A9 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26aa uni26AA 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26ab uni26AB 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26ac uni26AC 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26ad uni26AD 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26ae uni26AE 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26af uni26AF 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+26b0 uni26B0 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+26b1 uni26B1 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+26b2 uni26B2 2.12 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2701 uni2701 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2702 uni2702 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2703 uni2703 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2704 uni2704 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2706 uni2706 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2707 uni2707 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2708 uni2708 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2709 uni2709 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+270c uni270C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+270d uni270D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+270e uni270E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+270f uni270F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2710 uni2710 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2711 uni2711 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2712 uni2712 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2713 uni2713 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2714 uni2714 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2715 uni2715 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2716 uni2716 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2717 uni2717 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2718 uni2718 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2719 uni2719 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+271a uni271A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+271b uni271B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+271c uni271C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+271d uni271D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+271e uni271E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+271f uni271F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2720 uni2720 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2721 uni2721 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2722 uni2722 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2723 uni2723 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2724 uni2724 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2725 uni2725 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2726 uni2726 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2727 uni2727 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2729 uni2729 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+272a uni272A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+272b uni272B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+272c uni272C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+272d uni272D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+272e uni272E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+272f uni272F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2730 uni2730 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2731 uni2731 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2732 uni2732 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2733 uni2733 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2734 uni2734 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2735 uni2735 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2736 uni2736 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2737 uni2737 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2738 uni2738 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2739 uni2739 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+273a uni273A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+273b uni273B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+273c uni273C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+273d uni273D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+273e uni273E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+273f uni273F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2740 uni2740 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2741 uni2741 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2742 uni2742 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2743 uni2743 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2744 uni2744 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2745 uni2745 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2746 uni2746 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2747 uni2747 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2748 uni2748 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2749 uni2749 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+274a uni274A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+274b uni274B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+274d uni274D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+274f uni274F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2750 uni2750 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2751 uni2751 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2752 uni2752 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2756 uni2756 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2758 uni2758 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2759 uni2759 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+275a uni275A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+275b uni275B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+275c uni275C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+275d uni275D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+275e uni275E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2761 uni2761 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2762 uni2762 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2763 uni2763 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2764 uni2764 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2765 uni2765 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2766 uni2766 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2767 uni2767 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2768 uni2768 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2769 uni2769 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+276a uni276A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+276b uni276B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+276c uni276C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+276d uni276D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+276e uni276E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+276f uni276F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2770 uni2770 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2771 uni2771 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2772 uni2772 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2773 uni2773 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2774 uni2774 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2775 uni2775 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Sans Mono, Sans Mono Bold) +U+2776 uni2776 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2777 uni2777 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2778 uni2778 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2779 uni2779 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+277a uni277A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+277b uni277B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+277c uni277C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+277d uni277D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+277e uni277E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+277f uni277F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2780 uni2780 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2781 uni2781 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2782 uni2782 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2783 uni2783 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2784 uni2784 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2785 uni2785 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2786 uni2786 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2787 uni2787 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2788 uni2788 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2789 uni2789 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+278a uni278A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+278b uni278B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+278c uni278C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+278d uni278D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+278e uni278E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+278f uni278F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2790 uni2790 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2791 uni2791 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2792 uni2792 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2793 uni2793 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2794 uni2794 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2798 uni2798 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+2799 uni2799 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+279a uni279A 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+279b uni279B 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+279c uni279C 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+279d uni279D 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+279e uni279E 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+279f uni279F 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a0 uni27A0 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a1 uni27A1 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a2 uni27A2 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a3 uni27A3 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a4 uni27A4 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a5 uni27A5 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a6 uni27A6 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a7 uni27A7 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a8 uni27A8 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27a9 uni27A9 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27aa uni27AA 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27ab uni27AB 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27ac uni27AC 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27ad uni27AD 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27ae uni27AE 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27af uni27AF 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b1 uni27B1 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b2 uni27B2 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b3 uni27B3 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b4 uni27B4 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b5 uni27B5 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b6 uni27B6 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b7 uni27B7 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b8 uni27B8 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27b9 uni27B9 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27ba uni27BA 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27bb uni27BB 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27bc uni27BC 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27bd uni27BD 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27be uni27BE 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.7 (Sans Mono, Sans Mono Bold) +U+27bf uni27BF 2.7 (Sans Mono Bold) +U+27e0 uni27E0 2.3 +U+27e6 uni27E6 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27e7 uni27E7 2.15 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27e8 uni27E8 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+27e9 uni27E9 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.13 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+27ea uni27EA 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27eb uni27EB 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f0 uni27F0 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f1 uni27F1 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f2 uni27F2 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f3 uni27F3 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f4 uni27F4 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f5 uni27F5 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f6 uni27F6 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f7 uni27F7 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f8 uni27F8 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27f9 uni27F9 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27fa uni27FA 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27fb uni27FB 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27fc uni27FC 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27fd uni27FD 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27fe uni27FE 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+27ff uni27FF 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2800 uni2800 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2801 uni2801 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2802 uni2802 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2803 uni2803 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2804 uni2804 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2805 uni2805 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2806 uni2806 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2807 uni2807 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2808 uni2808 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2809 uni2809 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+280a uni280A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+280b uni280B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+280c uni280C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+280d uni280D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+280e uni280E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+280f uni280F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2810 uni2810 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2811 uni2811 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2812 uni2812 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2813 uni2813 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2814 uni2814 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2815 uni2815 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2816 uni2816 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2817 uni2817 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2818 uni2818 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2819 uni2819 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+281a uni281A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+281b uni281B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+281c uni281C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+281d uni281D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+281e uni281E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+281f uni281F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2820 uni2820 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2821 uni2821 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2822 uni2822 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2823 uni2823 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2824 uni2824 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2825 uni2825 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2826 uni2826 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2827 uni2827 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2828 uni2828 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2829 uni2829 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+282a uni282A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+282b uni282B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+282c uni282C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+282d uni282D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+282e uni282E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+282f uni282F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2830 uni2830 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2831 uni2831 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2832 uni2832 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2833 uni2833 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2834 uni2834 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2835 uni2835 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2836 uni2836 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2837 uni2837 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2838 uni2838 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2839 uni2839 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+283a uni283A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+283b uni283B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+283c uni283C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+283d uni283D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+283e uni283E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+283f uni283F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2840 uni2840 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2841 uni2841 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2842 uni2842 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2843 uni2843 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2844 uni2844 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2845 uni2845 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2846 uni2846 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2847 uni2847 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2848 uni2848 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2849 uni2849 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+284a uni284A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+284b uni284B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+284c uni284C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+284d uni284D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+284e uni284E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+284f uni284F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2850 uni2850 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2851 uni2851 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2852 uni2852 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2853 uni2853 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2854 uni2854 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2855 uni2855 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2856 uni2856 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2857 uni2857 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2858 uni2858 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2859 uni2859 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+285a uni285A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+285b uni285B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+285c uni285C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+285d uni285D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+285e uni285E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+285f uni285F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2860 uni2860 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2861 uni2861 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2862 uni2862 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2863 uni2863 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2864 uni2864 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2865 uni2865 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2866 uni2866 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2867 uni2867 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2868 uni2868 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2869 uni2869 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+286a uni286A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+286b uni286B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+286c uni286C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+286d uni286D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+286e uni286E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+286f uni286F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2870 uni2870 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2871 uni2871 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2872 uni2872 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2873 uni2873 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2874 uni2874 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2875 uni2875 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2876 uni2876 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2877 uni2877 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2878 uni2878 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2879 uni2879 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+287a uni287A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+287b uni287B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+287c uni287C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+287d uni287D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+287e uni287E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+287f uni287F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2880 uni2880 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2881 uni2881 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2882 uni2882 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2883 uni2883 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2884 uni2884 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2885 uni2885 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2886 uni2886 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2887 uni2887 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2888 uni2888 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2889 uni2889 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+288a uni288A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+288b uni288B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+288c uni288C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+288d uni288D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+288e uni288E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+288f uni288F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2890 uni2890 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2891 uni2891 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2892 uni2892 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2893 uni2893 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2894 uni2894 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2895 uni2895 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2896 uni2896 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2897 uni2897 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2898 uni2898 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2899 uni2899 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+289a uni289A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+289b uni289B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+289c uni289C 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+289d uni289D 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+289e uni289E 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+289f uni289F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a0 uni28A0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a1 uni28A1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a2 uni28A2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a3 uni28A3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a4 uni28A4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a5 uni28A5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a6 uni28A6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a7 uni28A7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a8 uni28A8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28a9 uni28A9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28aa uni28AA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ab uni28AB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ac uni28AC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ad uni28AD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ae uni28AE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28af uni28AF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b0 uni28B0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b1 uni28B1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b2 uni28B2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b3 uni28B3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b4 uni28B4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b5 uni28B5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b6 uni28B6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b7 uni28B7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b8 uni28B8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28b9 uni28B9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ba uni28BA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28bb uni28BB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28bc uni28BC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28bd uni28BD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28be uni28BE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28bf uni28BF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c0 uni28C0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c1 uni28C1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c2 uni28C2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c3 uni28C3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c4 uni28C4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c5 uni28C5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c6 uni28C6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c7 uni28C7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c8 uni28C8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28c9 uni28C9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ca uni28CA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28cb uni28CB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28cc uni28CC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28cd uni28CD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ce uni28CE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28cf uni28CF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d0 uni28D0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d1 uni28D1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d2 uni28D2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d3 uni28D3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d4 uni28D4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d5 uni28D5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d6 uni28D6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d7 uni28D7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d8 uni28D8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28d9 uni28D9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28da uni28DA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28db uni28DB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28dc uni28DC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28dd uni28DD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28de uni28DE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28df uni28DF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e0 uni28E0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e1 uni28E1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e2 uni28E2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e3 uni28E3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e4 uni28E4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e5 uni28E5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e6 uni28E6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e7 uni28E7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e8 uni28E8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28e9 uni28E9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ea uni28EA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28eb uni28EB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ec uni28EC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ed uni28ED 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ee uni28EE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ef uni28EF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f0 uni28F0 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f1 uni28F1 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f2 uni28F2 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f3 uni28F3 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f4 uni28F4 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f5 uni28F5 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f6 uni28F6 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f7 uni28F7 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f8 uni28F8 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28f9 uni28F9 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28fa uni28FA 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28fb uni28FB 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28fc uni28FC 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28fd uni28FD 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28fe uni28FE 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+28ff uni28FF 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2906 uni2906 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2907 uni2907 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+290a uni290A 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+290b uni290B 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2940 uni2940 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2941 uni2941 2.13 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29ce uni29CE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29cf uni29CF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29d0 uni29D0 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29d1 uni29D1 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29d2 uni29D2 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29d3 uni29D3 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29d4 uni29D4 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29d5 uni29D5 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+29eb uni29EB 2.2 +U+2a00 uni2A00 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a01 uni2A01 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a02 uni2A02 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a0c uni2A0C 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2a0d uni2A0D 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2a0e uni2A0E 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.9 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+2a0f uni2A0F 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a10 uni2A10 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a11 uni2A11 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a12 uni2A12 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a13 uni2A13 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a14 uni2A14 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a15 uni2A15 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a16 uni2A16 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a17 uni2A17 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a18 uni2A18 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a19 uni2A19 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a1a uni2A1A 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a1b uni2A1B 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a1c uni2A1C 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a7d uni2A7D 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a7e uni2A7E 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a7f uni2A7F 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a80 uni2A80 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a81 uni2A81 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a82 uni2A82 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a83 uni2A83 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a84 uni2A84 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a85 uni2A85 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a86 uni2A86 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a87 uni2A87 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a88 uni2A88 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a89 uni2A89 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a8a uni2A8A 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a8b uni2A8B 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a8c uni2A8C 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a8d uni2A8D 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a8e uni2A8E 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a8f uni2A8F 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a90 uni2A90 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a91 uni2A91 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a92 uni2A92 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a93 uni2A93 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a94 uni2A94 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a95 uni2A95 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a96 uni2A96 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a97 uni2A97 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a98 uni2A98 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a99 uni2A99 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a9a uni2A9A 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a9b uni2A9B 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a9c uni2A9C 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a9d uni2A9D 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a9e uni2A9E 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2a9f uni2A9F 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2aa0 uni2AA0 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2aae uni2AAE 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2aaf uni2AAF 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab0 uni2AB0 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab1 uni2AB1 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab2 uni2AB2 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab3 uni2AB3 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab4 uni2AB4 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab5 uni2AB5 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab6 uni2AB6 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab7 uni2AB7 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab8 uni2AB8 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2ab9 uni2AB9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2aba uni2ABA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2af9 uni2AF9 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2afa uni2AFA 2.7 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b00 uni2B00 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b01 uni2B01 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b02 uni2B02 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b03 uni2B03 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b04 uni2B04 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b05 uni2B05 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b06 uni2B06 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b07 uni2B07 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b08 uni2B08 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b09 uni2B09 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b0a uni2B0A 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b0b uni2B0B 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b0c uni2B0C 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b0d uni2B0D 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b0e uni2B0E 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b0f uni2B0F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b10 uni2B10 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b11 uni2B11 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b12 uni2B12 2.3 +U+2b13 uni2B13 2.3 +U+2b14 uni2B14 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b15 uni2B15 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b16 uni2B16 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b17 uni2B17 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b18 uni2B18 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b19 uni2B19 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b1a uni2B1A 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+2b20 uni2B20 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b21 uni2B21 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b22 uni2B22 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2b23 uni2B23 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c60 uni2C60 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c61 uni2C61 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c62 uni2C62 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c63 uni2C63 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c64 uni2C64 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c65 uni2C65 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c66 uni2C66 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c67 uni2C67 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c68 uni2C68 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c69 uni2C69 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c6a uni2C6A 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c6b uni2C6B 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c6c uni2C6C 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c74 uni2C74 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+2c75 uni2C75 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c76 uni2C76 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+2c77 uni2C77 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e000 uniE000 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e001 uniE001 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e002 uniE002 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e003 uniE003 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e004 uniE004 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e005 uniE005 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e006 uniE006 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e007 uniE007 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e008 uniE008 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique) +U+e009 uniE009 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e00a uniE00A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e00b uniE00B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e00c uniE00C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e00d uniE00D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e00e uniE00E 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e00f uniE00F 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e010 uniE010 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e011 uniE011 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e012 uniE012 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e013 uniE013 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e014 uniE014 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) +U+e015 uniE015 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e016 uniE016 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e017 uniE017 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e018 uniE018 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e019 uniE019 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e01a uniE01A 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e01b uniE01B 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e01c uniE01C 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+e01d uniE01D 2.4 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f000 uniF000 2.10 (Sans) 2.11 (Sans Condensed) +U+f001 uniF001 2.10 (Sans) 2.11 (Sans Condensed) +U+f208 uniF208 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f20a uniF20A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f215 uniF215 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f216 uniF216 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f217 uniF217 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f21a uniF21A 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f21b uniF21B 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f25f uniF25F 2.6 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+f5c5 afii10064 2.9 (Sans Bold Oblique, Sans Condensed Bold Oblique) +U+f6c4 afii10063 2.10 (Serif Bold Oblique, Serif Oblique) 2.11 (Serif Condensed Bold Oblique, Serif Condensed Oblique) +U+f6c5 afii10064 2.5 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) 2.7 (Sans Mono, Sans Mono Bold, Sans Mono Bold Oblique, Sans Mono Oblique) 2.9 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold, Sans Condensed Oblique, Sans Oblique) +U+f6c6 afii10192 2.5 (Serif Bold Oblique, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+f6c7 afii10831 2.11 (Serif Bold Oblique, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+f6c8 afii10832 2.11 (Serif Bold Oblique, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+f6d1 cyrBreve 2.5 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+f6d4 cyrbreve 2.5 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fb00 uniFB00 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) 2.8 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fb01 fi original +U+fb02 fl original +U+fb03 uniFB03 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) 2.8 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fb04 uniFB04 2.2 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.5 (Sans ExtraLight) 2.8 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fb05 uniFB05 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fb06 uniFB06 2.5 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) 2.8 (Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fb13 uniFB13 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb14 uniFB14 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb15 uniFB15 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb16 uniFB16 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb17 uniFB17 2.3 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb1d uniFB1D 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb1f uniFB1F 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb20 uniFB20 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb29 uniFB29 2.10 (Sans, Sans Bold, Sans Bold Oblique, Sans ExtraLight, Sans Oblique) 2.11 (Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique) +U+fb2a uniFB2A 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb2b uniFB2B 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb2c uniFB2C 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb2d uniFB2D 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb2e uniFB2E 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb2f uniFB2F 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb30 uniFB30 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb31 uniFB31 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb32 uniFB32 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb33 uniFB33 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb34 uniFB34 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb35 uniFB35 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb36 uniFB36 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb37 uniFB37 2.11 (Sans Condensed Oblique, Sans Oblique) +U+fb38 uniFB38 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb39 uniFB39 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb3a uniFB3A 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb3b uniFB3B 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb3c uniFB3C 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb3e uniFB3E 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb40 uniFB40 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb41 uniFB41 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb43 uniFB43 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb44 uniFB44 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb46 uniFB46 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb47 uniFB47 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb48 uniFB48 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb49 uniFB49 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb4a uniFB4A 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb4b uniFB4B 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb4c uniFB4C 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb4d uniFB4D 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb4e uniFB4E 2.9 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans Oblique) +U+fb52 uniFB52 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb53 uniFB53 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb54 uniFB54 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb55 uniFB55 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb56 uniFB56 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb57 uniFB57 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb58 uniFB58 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb59 uniFB59 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb5a uniFB5A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb5b uniFB5B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb5c uniFB5C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb5d uniFB5D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb5e uniFB5E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb5f uniFB5F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb60 uniFB60 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb61 uniFB61 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb62 uniFB62 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb63 uniFB63 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb64 uniFB64 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb65 uniFB65 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb66 uniFB66 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb67 uniFB67 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb68 uniFB68 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb69 uniFB69 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb6a uniFB6A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb6b uniFB6B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb6c uniFB6C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb6d uniFB6D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb6e uniFB6E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb6f uniFB6F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb70 uniFB70 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb71 uniFB71 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb72 uniFB72 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb73 uniFB73 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb74 uniFB74 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb75 uniFB75 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb76 uniFB76 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb77 uniFB77 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb78 uniFB78 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb79 uniFB79 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb7a uniFB7A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb7b uniFB7B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb7c uniFB7C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb7d uniFB7D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb7e uniFB7E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb7f uniFB7F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb80 uniFB80 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb81 uniFB81 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb8a uniFB8A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb8b uniFB8B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb8c uniFB8C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb8d uniFB8D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb8e uniFB8E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb8f uniFB8F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb90 uniFB90 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb91 uniFB91 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb92 uniFB92 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb93 uniFB93 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb94 uniFB94 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb95 uniFB95 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb9e uniFB9E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fb9f uniFB9F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbd9 uniFBD9 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbda uniFBDA 2.7 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbe8 uniFBE8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbe9 uniFBE9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbfc uniFBFC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbfd uniFBFD 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbfe uniFBFE 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fbff uniFBFF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe00 uniFE00 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe01 uniFE01 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe02 uniFE02 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe03 uniFE03 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe04 uniFE04 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe05 uniFE05 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe06 uniFE06 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe07 uniFE07 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe08 uniFE08 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe09 uniFE09 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe0a uniFE0A 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe0b uniFE0B 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe0c uniFE0C 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe0d uniFE0D 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe0e uniFE0E 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe0f uniFE0F 2.14 (Sans, Sans Bold, Sans Bold Oblique, Sans Condensed, Sans Condensed Bold, Sans Condensed Bold Oblique, Sans Condensed Oblique, Sans ExtraLight, Sans Oblique, Serif, Serif Bold, Serif Bold Oblique, Serif Condensed, Serif Condensed Bold, Serif Condensed Bold Oblique, Serif Condensed Oblique, Serif Oblique) +U+fe70 uniFE70 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe71 uniFE71 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe72 uniFE72 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe73 uniFE73 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe74 uniFE74 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe76 uniFE76 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe77 uniFE77 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe78 uniFE78 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe79 uniFE79 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe7a uniFE7A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe7b uniFE7B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe7c uniFE7C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe7d uniFE7D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe7e uniFE7E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe7f uniFE7F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe80 uniFE80 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe81 uniFE81 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe82 uniFE82 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe83 uniFE83 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe84 uniFE84 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe85 uniFE85 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe86 uniFE86 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe87 uniFE87 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe88 uniFE88 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe89 uniFE89 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe8a uniFE8A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe8b uniFE8B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe8c uniFE8C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe8d uniFE8D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe8e uniFE8E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe8f uniFE8F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe90 uniFE90 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe91 uniFE91 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe92 uniFE92 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe93 uniFE93 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe94 uniFE94 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe95 uniFE95 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe96 uniFE96 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe97 uniFE97 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe98 uniFE98 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe99 uniFE99 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe9a uniFE9A 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe9b uniFE9B 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe9c uniFE9C 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe9d uniFE9D 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe9e uniFE9E 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fe9f uniFE9F 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea0 uniFEA0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea1 uniFEA1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea2 uniFEA2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea3 uniFEA3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea4 uniFEA4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea5 uniFEA5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea6 uniFEA6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea7 uniFEA7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea8 uniFEA8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fea9 uniFEA9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feaa uniFEAA 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feab uniFEAB 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feac uniFEAC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fead uniFEAD 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feae uniFEAE 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feaf uniFEAF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb0 uniFEB0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb1 uniFEB1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb2 uniFEB2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb3 uniFEB3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb4 uniFEB4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb5 uniFEB5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb6 uniFEB6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb7 uniFEB7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb8 uniFEB8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feb9 uniFEB9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feba uniFEBA 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+febb uniFEBB 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+febc uniFEBC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+febd uniFEBD 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+febe uniFEBE 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+febf uniFEBF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec0 uniFEC0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec1 uniFEC1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec2 uniFEC2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec3 uniFEC3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec4 uniFEC4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec5 uniFEC5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec6 uniFEC6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec7 uniFEC7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec8 uniFEC8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fec9 uniFEC9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feca uniFECA 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fecb uniFECB 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fecc uniFECC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fecd uniFECD 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fece uniFECE 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fecf uniFECF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed0 uniFED0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed1 uniFED1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed2 uniFED2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed3 uniFED3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed4 uniFED4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed5 uniFED5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed6 uniFED6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed7 uniFED7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed8 uniFED8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fed9 uniFED9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feda uniFEDA 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fedb uniFEDB 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fedc uniFEDC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fedd uniFEDD 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fede uniFEDE 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fedf uniFEDF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee0 uniFEE0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee1 uniFEE1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee2 uniFEE2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee3 uniFEE3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee4 uniFEE4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee5 uniFEE5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee6 uniFEE6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee7 uniFEE7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee8 uniFEE8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fee9 uniFEE9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feea uniFEEA 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feeb uniFEEB 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feec uniFEEC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feed uniFEED 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feee uniFEEE 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feef uniFEEF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef0 uniFEF0 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef1 uniFEF1 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef2 uniFEF2 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef3 uniFEF3 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef4 uniFEF4 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef5 uniFEF5 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef6 uniFEF6 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef7 uniFEF7 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef8 uniFEF8 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fef9 uniFEF9 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fefa uniFEFA 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fefb uniFEFB 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fefc uniFEFC 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+feff uniFEFF 2.4 (Sans, Sans Bold, Sans Condensed, Sans Condensed Bold) +U+fffd uniFFFD 1.12 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f33c6880e8251726611101bca6cb50a4896db55f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f33c6880e8251726611101bca6cb50a4896db55f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,91 @@ +### From http://svn.geekdaily.org/public/rails/plugins/generally_useful/tasks/coverage_via_rcov.rake + +namespace :test do + desc 'Measures test coverage' + task :coverage do + rm_f "coverage" + rm_f "coverage.data" + rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib --html --exclude gems/" + files = Dir.glob("test/**/*_test.rb").join(" ") + system("#{rcov} #{files}") + system("open coverage/index.html") if PLATFORM['darwin'] + end + + desc 'Run unit and functional scm tests' + task :scm do + errors = %w(test:scm:units test:scm:functionals).collect do |task| + begin + Rake::Task[task].invoke + nil + rescue => e + task + end + end.compact + abort "Errors running #{errors.to_sentence(:locale => :en)}!" if errors.any? + end + + namespace :scm do + namespace :setup do + desc "Creates directory for test repositories" + task :create_dir do + FileUtils.mkdir_p Rails.root + '/tmp/test' + end + + supported_scms = [:subversion, :cvs, :bazaar, :mercurial, :git, :darcs, :filesystem] + + desc "Creates a test subversion repository" + task :subversion => :create_dir do + repo_path = "tmp/test/subversion_repository" + system "svnadmin create #{repo_path}" + system "gunzip < test/fixtures/repositories/subversion_repository.dump.gz | svnadmin load #{repo_path}" + end + + desc "Creates a test mercurial repository" + task :mercurial => :create_dir do + repo_path = "tmp/test/mercurial_repository" + bundle_path = "test/fixtures/repositories/mercurial_repository.hg" + system "hg init #{repo_path}" + system "hg -R #{repo_path} pull #{bundle_path}" + end + + (supported_scms - [:subversion, :mercurial]).each do |scm| + desc "Creates a test #{scm} repository" + task scm => :create_dir do + # system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test" + system "tar -xvz -C tmp/test -f test/fixtures/repositories/#{scm}_repository.tar.gz" + end + end + + desc "Creates all test repositories" + task :all => supported_scms + end + + desc "Updates installed test repositories" + task :update do + require 'fileutils' + Dir.glob("tmp/test/*_repository").each do |dir| + next unless File.basename(dir) =~ %r{^(.+)_repository$} && File.directory?(dir) + scm = $1 + next unless fixture = Dir.glob("test/fixtures/repositories/#{scm}_repository.*").first + next if File.stat(dir).ctime > File.stat(fixture).mtime + + FileUtils.rm_rf dir + Rake::Task["test:scm:setup:#{scm}"].execute + end + end + + Rake::TestTask.new(:units => "db:test:prepare") do |t| + t.libs << "test" + t.verbose = true + t.test_files = FileList['test/unit/repository*_test.rb'] + FileList['test/unit/lib/redmine/scm/**/*_test.rb'] + end + Rake::Task['test:scm:units'].comment = "Run the scm unit tests" + + Rake::TestTask.new(:functionals => "db:test:prepare") do |t| + t.libs << "test" + t.verbose = true + t.test_files = FileList['test/functional/repositories*_test.rb'] + end + Rake::Task['test:scm:functionals'].comment = "Run the scm functional tests" + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f34034b519f43ca5e6a5472f282e7c5860581332.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f34034b519f43ca5e6a5472f282e7c5860581332.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +TCPDFFontDescriptor.define('helveticabi') do |font| + font[:cw]={ + 0.chr=>278,1.chr=>278,2.chr=>278,3.chr=>278,4.chr=>278,5.chr=>278,6.chr=>278,7.chr=>278,8.chr=>278,9.chr=>278,10.chr=>278,11.chr=>278,12.chr=>278,13.chr=>278,14.chr=>278,15.chr=>278,16.chr=>278,17.chr=>278,18.chr=>278,19.chr=>278,20.chr=>278,21.chr=>278, + 22.chr=>278,23.chr=>278,24.chr=>278,25.chr=>278,26.chr=>278,27.chr=>278,28.chr=>278,29.chr=>278,30.chr=>278,31.chr=>278,' '=>278,'!'=>333,'"'=>474,'#'=>556,'$'=>556,'%'=>889,'&'=>722,'\''=>238,'('=>333,')'=>333,'*'=>389,'+'=>584, + ','=>278,'-'=>333,'.'=>278,'/'=>278,'0'=>556,'1'=>556,'2'=>556,'3'=>556,'4'=>556,'5'=>556,'6'=>556,'7'=>556,'8'=>556,'9'=>556,':'=>333,';'=>333,'<'=>584,'='=>584,'>'=>584,'?'=>611,'@'=>975,'A'=>722, + 'B'=>722,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>722,'I'=>278,'J'=>556,'K'=>722,'L'=>611,'M'=>833,'N'=>722,'O'=>778,'P'=>667,'Q'=>778,'R'=>722,'S'=>667,'T'=>611,'U'=>722,'V'=>667,'W'=>944, + 'X'=>667,'Y'=>667,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>584,'_'=>556,'`'=>333,'a'=>556,'b'=>611,'c'=>556,'d'=>611,'e'=>556,'f'=>333,'g'=>611,'h'=>611,'i'=>278,'j'=>278,'k'=>556,'l'=>278,'m'=>889, + 'n'=>611,'o'=>611,'p'=>611,'q'=>611,'r'=>389,'s'=>556,'t'=>333,'u'=>611,'v'=>556,'w'=>778,'x'=>556,'y'=>556,'z'=>500,'{'=>389,'|'=>280,'}'=>389,'~'=>584,127.chr=>350,128.chr=>556,129.chr=>350,130.chr=>278,131.chr=>556, + 132.chr=>500,133.chr=>1000,134.chr=>556,135.chr=>556,136.chr=>333,137.chr=>1000,138.chr=>667,139.chr=>333,140.chr=>1000,141.chr=>350,142.chr=>611,143.chr=>350,144.chr=>350,145.chr=>278,146.chr=>278,147.chr=>500,148.chr=>500,149.chr=>350,150.chr=>556,151.chr=>1000,152.chr=>333,153.chr=>1000, + 154.chr=>556,155.chr=>333,156.chr=>944,157.chr=>350,158.chr=>500,159.chr=>667,160.chr=>278,161.chr=>333,162.chr=>556,163.chr=>556,164.chr=>556,165.chr=>556,166.chr=>280,167.chr=>556,168.chr=>333,169.chr=>737,170.chr=>370,171.chr=>556,172.chr=>584,173.chr=>333,174.chr=>737,175.chr=>333, + 176.chr=>400,177.chr=>584,178.chr=>333,179.chr=>333,180.chr=>333,181.chr=>611,182.chr=>556,183.chr=>278,184.chr=>333,185.chr=>333,186.chr=>365,187.chr=>556,188.chr=>834,189.chr=>834,190.chr=>834,191.chr=>611,192.chr=>722,193.chr=>722,194.chr=>722,195.chr=>722,196.chr=>722,197.chr=>722, + 198.chr=>1000,199.chr=>722,200.chr=>667,201.chr=>667,202.chr=>667,203.chr=>667,204.chr=>278,205.chr=>278,206.chr=>278,207.chr=>278,208.chr=>722,209.chr=>722,210.chr=>778,211.chr=>778,212.chr=>778,213.chr=>778,214.chr=>778,215.chr=>584,216.chr=>778,217.chr=>722,218.chr=>722,219.chr=>722, + 220.chr=>722,221.chr=>667,222.chr=>667,223.chr=>611,224.chr=>556,225.chr=>556,226.chr=>556,227.chr=>556,228.chr=>556,229.chr=>556,230.chr=>889,231.chr=>556,232.chr=>556,233.chr=>556,234.chr=>556,235.chr=>556,236.chr=>278,237.chr=>278,238.chr=>278,239.chr=>278,240.chr=>611,241.chr=>611, + 242.chr=>611,243.chr=>611,244.chr=>611,245.chr=>611,246.chr=>611,247.chr=>584,248.chr=>611,249.chr=>611,250.chr=>611,251.chr=>611,252.chr=>611,253.chr=>556,254.chr=>611,255.chr=>556} +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f34e33a2a42b339063ea92067802d190a2825630.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f34e33a2a42b339063ea92067802d190a2825630.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class UserPreferenceTest < ActiveSupport::TestCase + fixtures :users, :user_preferences + + def test_create + user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo") + user.login = "newuser" + user.password, user.password_confirmation = "password", "password" + assert user.save + + assert_kind_of UserPreference, user.pref + assert_kind_of Hash, user.pref.others + assert user.pref.save + end + + def test_update + user = User.find(1) + assert_equal true, user.pref.hide_mail + user.pref['preftest'] = 'value' + assert user.pref.save + + user.reload + assert_equal 'value', user.pref['preftest'] + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f35847d445152b5406b2138b825010b073653b9f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f35847d445152b5406b2138b825010b073653b9f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +# Sample OpenLDAP configuration file for Redmine LDAP test server +# +ucdata-path ./ucdata +include ./schema/core.schema +include ./schema/cosine.schema +include ./schema/inetorgperson.schema +include ./schema/openldap.schema +include ./schema/nis.schema + +pidfile ./run/slapd.pid +argsfile ./run/slapd.args + +database bdb +suffix "dc=redmine,dc=org" +rootdn "cn=Manager,dc=redmine,dc=org" +rootpw secret +directory ./redmine +# Indices to maintain +index objectClass eq diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f3620e1d272f7f0206e16d61dc2fdc4a8da59a95.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f3620e1d272f7f0206e16d61dc2fdc4a8da59a95.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%=l(:label_auth_source_new)%> (<%= h(@auth_source.auth_method_name) %>)

    + +<% form_tag({:action => 'create'}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f36627f1ceebd181333d428d96386397035bb171.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f36627f1ceebd181333d428d96386397035bb171.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,68 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 SearchHelper + def highlight_tokens(text, tokens) + return text unless text && tokens && !tokens.empty? + re_tokens = tokens.collect {|t| Regexp.escape(t)} + regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE + result = '' + text.split(regexp).each_with_index do |words, i| + if result.length > 1200 + # maximum length of the preview reached + result << '...' + break + end + words = words.mb_chars + if i.even? + result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words) + else + t = (tokens.index(words.downcase) || 0) % 4 + result << content_tag('span', h(words), :class => "highlight token-#{t}") + end + end + result + end + + def type_label(t) + l("label_#{t.singularize}_plural", :default => t.to_s.humanize) + end + + def project_select_tag + options = [[l(:label_project_all), 'all']] + options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? + options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? + options << [@project.name, ''] unless @project.nil? + label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") + + select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 + end + + def render_results_by_type(results_by_type) + links = [] + # Sorts types by results count + results_by_type.keys.sort {|a, b| results_by_type[b] <=> results_by_type[a]}.each do |t| + c = results_by_type[t] + next if c == 0 + text = "#{type_label(t)} (#{c})" + links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only], + :all_words => params[:all_words], :scope => params[:scope], t => 1) + end + ('
      ' + links.map {|link| content_tag('li', link)}.join(' ') + '
    ') unless links.empty? + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f388a468f7bcce147f8cf82b4b0549106c8cc56a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f388a468f7bcce147f8cf82b4b0549106c8cc56a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,100 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) +require 'documents_controller' + +# Re-raise errors caught by the controller. +class DocumentsController; def rescue_action(e) raise e end; end + +class DocumentsControllerTest < ActionController::TestCase + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :documents, :enumerations + + def setup + @controller = DocumentsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_index + # Sets a default category + e = Enumeration.find_by_name('Technical documentation') + e.update_attributes(:is_default => true) + + get :index, :project_id => 'ecookbook' + assert_response :success + assert_template 'index' + assert_not_nil assigns(:grouped) + + # Default category selected in the new document form + assert_tag :select, :attributes => {:name => 'document[category_id]'}, + :child => {:tag => 'option', :attributes => {:selected => 'selected'}, + :content => 'Technical documentation'} + + assert ! DocumentCategory.find(16).active? + assert_no_tag :option, :attributes => {:value => '16'}, + :parent => {:tag => 'select', :attributes => {:id => 'document_category_id'} } + end + + def test_index_with_long_description + # adds a long description to the first document + doc = documents(:documents_001) + doc.update_attributes(:description => < 'ecookbook' + assert_response :success + assert_template 'index' + + # should only truncate on new lines to avoid breaking wiki formatting + assert_select '.wiki p', :text => (doc.description.split("\n").first + '...') + assert_select '.wiki p', :text => Regexp.new(Regexp.escape("EndOfLineHere...")) + end + + def test_new_with_one_attachment + ActionMailer::Base.deliveries.clear + Setting.notified_events << 'document_added' + @request.session[:user_id] = 2 + set_tmp_attachments_directory + + post :new, :project_id => 'ecookbook', + :document => { :title => 'DocumentsControllerTest#test_post_new', + :description => 'This is a new document', + :category_id => 2}, + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} + + assert_redirected_to '/projects/ecookbook/documents' + + document = Document.find_by_title('DocumentsControllerTest#test_post_new') + assert_not_nil document + assert_equal Enumeration.find(2), document.category + assert_equal 1, document.attachments.size + assert_equal 'testfile.txt', document.attachments.first.filename + assert_equal 1, ActionMailer::Base.deliveries.size + end + + def test_destroy + @request.session[:user_id] = 2 + post :destroy, :id => 1 + assert_redirected_to '/projects/ecookbook/documents' + assert_nil Document.find_by_id(1) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f3c118af336d1f061b825e2d660d96a9847739fa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f3c118af336d1f061b825e2d660d96a9847739fa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +require File.expand_path('../../../../../../test_helper', __FILE__) +begin + require 'mocha' + + class DarcsAdapterTest < ActiveSupport::TestCase + REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s + + if File.directory?(REPOSITORY_PATH) + def setup + @adapter = Redmine::Scm::Adapters::DarcsAdapter.new(REPOSITORY_PATH) + end + + def test_darcsversion + to_test = { "1.0.9 (release)\n" => [1,0,9] , + "2.2.0 (release)\n" => [2,2,0] } + to_test.each do |s, v| + test_darcsversion_for(s, v) + end + end + + def test_revisions + id1 = '20080308225258-98289-761f654d669045eabee90b91b53a21ce5593cadf.gz' + revs = @adapter.revisions('', nil, nil, {:with_path => true}) + assert_equal 6, revs.size + assert_equal id1, revs[5].scmid + paths = revs[5].paths + assert_equal 5, paths.size + assert_equal 'A', paths[0][:action] + assert_equal '/README', paths[0][:path] + assert_equal 'A', paths[1][:action] + assert_equal '/images', paths[1][:path] + end + + private + + def test_darcsversion_for(darcsversion, version) + @adapter.class.expects(:darcs_binary_version_from_command_line).returns(darcsversion) + assert_equal version, @adapter.class.darcs_binary_version + end + + else + puts "Darcs test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end + end + +rescue LoadError + class DarcsMochaFake < ActiveSupport::TestCase + def test_fake; assert(false, "Requires mocha to run those tests") end + end +end + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f3/f3e5e994ff2f624af7f4980e43ec0d7f29545774.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f3/f3e5e994ff2f624af7f4980e43ec0d7f29545774.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,978 @@ +begin + require 'zlib' + @@__have_zlib = true +rescue + @@__have_zlib = false +end + +require 'rexml/document' + +module SVG + module Graph + VERSION = '@ANT_VERSION@' + + # === Base object for generating SVG Graphs + # + # == Synopsis + # + # This class is only used as a superclass of specialized charts. Do not + # attempt to use this class directly, unless creating a new chart type. + # + # For examples of how to subclass this class, see the existing specific + # subclasses, such as SVG::Graph::Pie. + # + # == Examples + # + # For examples of how to use this package, see either the test files, or + # the documentation for the specific class you want to use. + # + # * file:test/plot.rb + # * file:test/single.rb + # * file:test/test.rb + # * file:test/timeseries.rb + # + # == Description + # + # This package should be used as a base for creating SVG graphs. + # + # == Acknowledgements + # + # Leo Lapworth for creating the SVG::TT::Graph package which this Ruby + # port is based on. + # + # Stephen Morgan for creating the TT template and SVG. + # + # == See + # + # * SVG::Graph::BarHorizontal + # * SVG::Graph::Bar + # * SVG::Graph::Line + # * SVG::Graph::Pie + # * SVG::Graph::Plot + # * SVG::Graph::TimeSeries + # + # == Author + # + # Sean E. Russell + # + # Copyright 2004 Sean E. Russell + # This software is available under the Ruby license[LICENSE.txt] + # + class Graph + include REXML + + # Initialize the graph object with the graph settings. You won't + # instantiate this class directly; see the subclass for options. + # [width] 500 + # [height] 300 + # [show_x_guidelines] false + # [show_y_guidelines] true + # [show_data_values] true + # [min_scale_value] 0 + # [show_x_labels] true + # [stagger_x_labels] false + # [rotate_x_labels] false + # [step_x_labels] 1 + # [step_include_first_x_label] true + # [show_y_labels] true + # [rotate_y_labels] false + # [scale_integers] false + # [show_x_title] false + # [x_title] 'X Field names' + # [show_y_title] false + # [y_title_text_direction] :bt + # [y_title] 'Y Scale' + # [show_graph_title] false + # [graph_title] 'Graph Title' + # [show_graph_subtitle] false + # [graph_subtitle] 'Graph Sub Title' + # [key] true, + # [key_position] :right, # bottom or righ + # [font_size] 12 + # [title_font_size] 16 + # [subtitle_font_size] 14 + # [x_label_font_size] 12 + # [x_title_font_size] 14 + # [y_label_font_size] 12 + # [y_title_font_size] 14 + # [key_font_size] 10 + # [no_css] false + # [add_popups] false + def initialize( config ) + @config = config + + self.top_align = self.top_font = self.right_align = self.right_font = 0 + + init_with({ + :width => 500, + :height => 300, + :show_x_guidelines => false, + :show_y_guidelines => true, + :show_data_values => true, + +# :min_scale_value => 0, + + :show_x_labels => true, + :stagger_x_labels => false, + :rotate_x_labels => false, + :step_x_labels => 1, + :step_include_first_x_label => true, + + :show_y_labels => true, + :rotate_y_labels => false, + :stagger_y_labels => false, + :scale_integers => false, + + :show_x_title => false, + :x_title => 'X Field names', + + :show_y_title => false, + :y_title_text_direction => :bt, + :y_title => 'Y Scale', + + :show_graph_title => false, + :graph_title => 'Graph Title', + :show_graph_subtitle => false, + :graph_subtitle => 'Graph Sub Title', + :key => true, + :key_position => :right, # bottom or right + + :font_size =>12, + :title_font_size =>16, + :subtitle_font_size =>14, + :x_label_font_size =>12, + :x_title_font_size =>14, + :y_label_font_size =>12, + :y_title_font_size =>14, + :key_font_size =>10, + + :no_css =>false, + :add_popups =>false, + }) + + set_defaults if respond_to? :set_defaults + + init_with config + end + + + # This method allows you do add data to the graph object. + # It can be called several times to add more data sets in. + # + # data_sales_02 = [12, 45, 21]; + # + # graph.add_data({ + # :data => data_sales_02, + # :title => 'Sales 2002' + # }) + def add_data conf + @data = [] unless defined? @data + + if conf[:data] and conf[:data].kind_of? Array + @data << conf + else + raise "No data provided by #{conf.inspect}" + end + end + + + # This method removes all data from the object so that you can + # reuse it to create a new graph but with the same config options. + # + # graph.clear_data + def clear_data + @data = [] + end + + + # This method processes the template with the data and + # config which has been set and returns the resulting SVG. + # + # This method will croak unless at least one data set has + # been added to the graph object. + # + # print graph.burn + def burn + raise "No data available" unless @data.size > 0 + + calculations if respond_to? :calculations + + start_svg + calculate_graph_dimensions + @foreground = Element.new( "g" ) + draw_graph + draw_titles + draw_legend + draw_data + @graph.add_element( @foreground ) + style + + data = "" + @doc.write( data, 0 ) + + if @config[:compress] + if @@__have_zlib + inp, out = IO.pipe + gz = Zlib::GzipWriter.new( out ) + gz.write data + gz.close + data = inp.read + else + data << ""; + end + end + + return data + end + + + # Set the height of the graph box, this is the total height + # of the SVG box created - not the graph it self which auto + # scales to fix the space. + attr_accessor :height + # Set the width of the graph box, this is the total width + # of the SVG box created - not the graph it self which auto + # scales to fix the space. + attr_accessor :width + # Set the path to an external stylesheet, set to '' if + # you want to revert back to using the defaut internal version. + # + # To create an external stylesheet create a graph using the + # default internal version and copy the stylesheet section to + # an external file and edit from there. + attr_accessor :style_sheet + # (Bool) Show the value of each element of data on the graph + attr_accessor :show_data_values + # The point at which the Y axis starts, defaults to '0', + # if set to nil it will default to the minimum data value. + attr_accessor :min_scale_value + # Whether to show labels on the X axis or not, defaults + # to true, set to false if you want to turn them off. + attr_accessor :show_x_labels + # This puts the X labels at alternative levels so if they + # are long field names they will not overlap so easily. + # Default it false, to turn on set to true. + attr_accessor :stagger_x_labels + # This puts the Y labels at alternative levels so if they + # are long field names they will not overlap so easily. + # Default it false, to turn on set to true. + attr_accessor :stagger_y_labels + # This turns the X axis labels by 90 degrees. + # Default it false, to turn on set to true. + attr_accessor :rotate_x_labels + # This turns the Y axis labels by 90 degrees. + # Default it false, to turn on set to true. + attr_accessor :rotate_y_labels + # How many "steps" to use between displayed X axis labels, + # a step of one means display every label, a step of two results + # in every other label being displayed (label label label), + # a step of three results in every third label being displayed + # (label label label) and so on. + attr_accessor :step_x_labels + # Whether to (when taking "steps" between X axis labels) step from + # the first label (i.e. always include the first label) or step from + # the X axis origin (i.e. start with a gap if step_x_labels is greater + # than one). + attr_accessor :step_include_first_x_label + # Whether to show labels on the Y axis or not, defaults + # to true, set to false if you want to turn them off. + attr_accessor :show_y_labels + # Ensures only whole numbers are used as the scale divisions. + # Default it false, to turn on set to true. This has no effect if + # scale divisions are less than 1. + attr_accessor :scale_integers + # This defines the gap between markers on the Y axis, + # default is a 10th of the max_value, e.g. you will have + # 10 markers on the Y axis. NOTE: do not set this too + # low - you are limited to 999 markers, after that the + # graph won't generate. + attr_accessor :scale_divisions + # Whether to show the title under the X axis labels, + # default is false, set to true to show. + attr_accessor :show_x_title + # What the title under X axis should be, e.g. 'Months'. + attr_accessor :x_title + # Whether to show the title under the Y axis labels, + # default is false, set to true to show. + attr_accessor :show_y_title + # Aligns writing mode for Y axis label. + # Defaults to :bt (Bottom to Top). + # Change to :tb (Top to Bottom) to reverse. + attr_accessor :y_title_text_direction + # What the title under Y axis should be, e.g. 'Sales in thousands'. + attr_accessor :y_title + # Whether to show a title on the graph, defaults + # to false, set to true to show. + attr_accessor :show_graph_title + # What the title on the graph should be. + attr_accessor :graph_title + # Whether to show a subtitle on the graph, defaults + # to false, set to true to show. + attr_accessor :show_graph_subtitle + # What the subtitle on the graph should be. + attr_accessor :graph_subtitle + # Whether to show a key, defaults to false, set to + # true if you want to show it. + attr_accessor :key + # Where the key should be positioned, defaults to + # :right, set to :bottom if you want to move it. + attr_accessor :key_position + # Set the font size (in points) of the data point labels + attr_accessor :font_size + # Set the font size of the X axis labels + attr_accessor :x_label_font_size + # Set the font size of the X axis title + attr_accessor :x_title_font_size + # Set the font size of the Y axis labels + attr_accessor :y_label_font_size + # Set the font size of the Y axis title + attr_accessor :y_title_font_size + # Set the title font size + attr_accessor :title_font_size + # Set the subtitle font size + attr_accessor :subtitle_font_size + # Set the key font size + attr_accessor :key_font_size + # Show guidelines for the X axis + attr_accessor :show_x_guidelines + # Show guidelines for the Y axis + attr_accessor :show_y_guidelines + # Do not use CSS if set to true. Many SVG viewers do not support CSS, but + # not using CSS can result in larger SVGs as well as making it impossible to + # change colors after the chart is generated. Defaults to false. + attr_accessor :no_css + # Add popups for the data points on some graphs + attr_accessor :add_popups + + + protected + + def sort( *arrys ) + sort_multiple( arrys ) + end + + # Overwrite configuration options with supplied options. Used + # by subclasses. + def init_with config + config.each { |key, value| + self.send((key.to_s+"=").to_sym, value ) if respond_to? key.to_sym + } + end + + attr_accessor :top_align, :top_font, :right_align, :right_font + + KEY_BOX_SIZE = 12 + + # Override this (and call super) to change the margin to the left + # of the plot area. Results in @border_left being set. + def calculate_left_margin + @border_left = 7 + # Check for Y labels + max_y_label_height_px = rotate_y_labels ? + y_label_font_size : + get_y_labels.max{|a,b| + a.to_s.length<=>b.to_s.length + }.to_s.length * y_label_font_size * 0.6 + @border_left += max_y_label_height_px if show_y_labels + @border_left += max_y_label_height_px + 10 if stagger_y_labels + @border_left += y_title_font_size + 5 if show_y_title + end + + + # Calculates the width of the widest Y label. This will be the + # character height if the Y labels are rotated + def max_y_label_width_px + return font_size if rotate_y_labels + end + + + # Override this (and call super) to change the margin to the right + # of the plot area. Results in @border_right being set. + def calculate_right_margin + @border_right = 7 + if key and key_position == :right + val = keys.max { |a,b| a.length <=> b.length } + @border_right += val.length * key_font_size * 0.6 + @border_right += KEY_BOX_SIZE + @border_right += 10 # Some padding around the box + end + end + + + # Override this (and call super) to change the margin to the top + # of the plot area. Results in @border_top being set. + def calculate_top_margin + @border_top = 5 + @border_top += title_font_size if show_graph_title + @border_top += 5 + @border_top += subtitle_font_size if show_graph_subtitle + end + + + # Adds pop-up point information to a graph. + def add_popup( x, y, label ) + txt_width = label.length * font_size * 0.6 + 10 + tx = (x+txt_width > width ? x-5 : x+5) + t = @foreground.add_element( "text", { + "x" => tx.to_s, + "y" => (y - font_size).to_s, + "visibility" => "hidden", + }) + t.attributes["style"] = "fill: #000; "+ + (x+txt_width > width ? "text-anchor: end;" : "text-anchor: start;") + t.text = label.to_s + t.attributes["id"] = t.object_id.to_s + + @foreground.add_element( "circle", { + "cx" => x.to_s, + "cy" => y.to_s, + "r" => "10", + "style" => "opacity: 0", + "onmouseover" => + "document.getElementById(#{t.object_id}).setAttribute('visibility', 'visible' )", + "onmouseout" => + "document.getElementById(#{t.object_id}).setAttribute('visibility', 'hidden' )", + }) + + end + + + # Override this (and call super) to change the margin to the bottom + # of the plot area. Results in @border_bottom being set. + def calculate_bottom_margin + @border_bottom = 7 + if key and key_position == :bottom + @border_bottom += @data.size * (font_size + 5) + @border_bottom += 10 + end + if show_x_labels + max_x_label_height_px = (not rotate_x_labels) ? + x_label_font_size : + get_x_labels.max{|a,b| + a.to_s.length<=>b.to_s.length + }.to_s.length * x_label_font_size * 0.6 + @border_bottom += max_x_label_height_px + @border_bottom += max_x_label_height_px + 10 if stagger_x_labels + end + @border_bottom += x_title_font_size + 5 if show_x_title + end + + + # Draws the background, axis, and labels. + def draw_graph + @graph = @root.add_element( "g", { + "transform" => "translate( #@border_left #@border_top )" + }) + + # Background + @graph.add_element( "rect", { + "x" => "0", + "y" => "0", + "width" => @graph_width.to_s, + "height" => @graph_height.to_s, + "class" => "graphBackground" + }) + + # Axis + @graph.add_element( "path", { + "d" => "M 0 0 v#@graph_height", + "class" => "axis", + "id" => "xAxis" + }) + @graph.add_element( "path", { + "d" => "M 0 #@graph_height h#@graph_width", + "class" => "axis", + "id" => "yAxis" + }) + + draw_x_labels + draw_y_labels + end + + + # Where in the X area the label is drawn + # Centered in the field, should be width/2. Start, 0. + def x_label_offset( width ) + 0 + end + + def make_datapoint_text( x, y, value, style="" ) + if show_data_values + @foreground.add_element( "text", { + "x" => x.to_s, + "y" => y.to_s, + "class" => "dataPointLabel", + "style" => "#{style} stroke: #fff; stroke-width: 2;" + }).text = value.to_s + text = @foreground.add_element( "text", { + "x" => x.to_s, + "y" => y.to_s, + "class" => "dataPointLabel" + }) + text.text = value.to_s + text.attributes["style"] = style if style.length > 0 + end + end + + + # Draws the X axis labels + def draw_x_labels + stagger = x_label_font_size + 5 + if show_x_labels + label_width = field_width + + count = 0 + for label in get_x_labels + if step_include_first_x_label == true then + step = count % step_x_labels + else + step = (count + 1) % step_x_labels + end + + if step == 0 then + text = @graph.add_element( "text" ) + text.attributes["class"] = "xAxisLabels" + text.text = label.to_s + + x = count * label_width + x_label_offset( label_width ) + y = @graph_height + x_label_font_size + 3 + t = 0 - (font_size / 2) + + if stagger_x_labels and count % 2 == 1 + y += stagger + @graph.add_element( "path", { + "d" => "M#{x} #@graph_height v#{stagger}", + "class" => "staggerGuideLine" + }) + end + + text.attributes["x"] = x.to_s + text.attributes["y"] = y.to_s + if rotate_x_labels + text.attributes["transform"] = + "rotate( 90 #{x} #{y-x_label_font_size} )"+ + " translate( 0 -#{x_label_font_size/4} )" + text.attributes["style"] = "text-anchor: start" + else + text.attributes["style"] = "text-anchor: middle" + end + end + + draw_x_guidelines( label_width, count ) if show_x_guidelines + count += 1 + end + end + end + + + # Where in the Y area the label is drawn + # Centered in the field, should be width/2. Start, 0. + def y_label_offset( height ) + 0 + end + + + def field_width + (@graph_width.to_f - font_size*2*right_font) / + (get_x_labels.length - right_align) + end + + + def field_height + (@graph_height.to_f - font_size*2*top_font) / + (get_y_labels.length - top_align) + end + + + # Draws the Y axis labels + def draw_y_labels + stagger = y_label_font_size + 5 + if show_y_labels + label_height = field_height + + count = 0 + y_offset = @graph_height + y_label_offset( label_height ) + y_offset += font_size/1.2 unless rotate_y_labels + for label in get_y_labels + y = y_offset - (label_height * count) + x = rotate_y_labels ? 0 : -3 + + if stagger_y_labels and count % 2 == 1 + x -= stagger + @graph.add_element( "path", { + "d" => "M#{x} #{y} h#{stagger}", + "class" => "staggerGuideLine" + }) + end + + text = @graph.add_element( "text", { + "x" => x.to_s, + "y" => y.to_s, + "class" => "yAxisLabels" + }) + text.text = label.to_s + if rotate_y_labels + text.attributes["transform"] = "translate( -#{font_size} 0 ) "+ + "rotate( 90 #{x} #{y} ) " + text.attributes["style"] = "text-anchor: middle" + else + text.attributes["y"] = (y - (y_label_font_size/2)).to_s + text.attributes["style"] = "text-anchor: end" + end + draw_y_guidelines( label_height, count ) if show_y_guidelines + count += 1 + end + end + end + + + # Draws the X axis guidelines + def draw_x_guidelines( label_height, count ) + if count != 0 + @graph.add_element( "path", { + "d" => "M#{label_height*count} 0 v#@graph_height", + "class" => "guideLines" + }) + end + end + + + # Draws the Y axis guidelines + def draw_y_guidelines( label_height, count ) + if count != 0 + @graph.add_element( "path", { + "d" => "M0 #{@graph_height-(label_height*count)} h#@graph_width", + "class" => "guideLines" + }) + end + end + + + # Draws the graph title and subtitle + def draw_titles + if show_graph_title + @root.add_element( "text", { + "x" => (width / 2).to_s, + "y" => (title_font_size).to_s, + "class" => "mainTitle" + }).text = graph_title.to_s + end + + if show_graph_subtitle + y_subtitle = show_graph_title ? + title_font_size + 10 : + subtitle_font_size + @root.add_element("text", { + "x" => (width / 2).to_s, + "y" => (y_subtitle).to_s, + "class" => "subTitle" + }).text = graph_subtitle.to_s + end + + if show_x_title + y = @graph_height + @border_top + x_title_font_size + if show_x_labels + y += x_label_font_size + 5 if stagger_x_labels + y += x_label_font_size + 5 + end + x = width / 2 + + @root.add_element("text", { + "x" => x.to_s, + "y" => y.to_s, + "class" => "xAxisTitle", + }).text = x_title.to_s + end + + if show_y_title + x = y_title_font_size + (y_title_text_direction==:bt ? 3 : -3) + y = height / 2 + + text = @root.add_element("text", { + "x" => x.to_s, + "y" => y.to_s, + "class" => "yAxisTitle", + }) + text.text = y_title.to_s + if y_title_text_direction == :bt + text.attributes["transform"] = "rotate( -90, #{x}, #{y} )" + else + text.attributes["transform"] = "rotate( 90, #{x}, #{y} )" + end + end + end + + def keys + return @data.collect{ |d| d[:title] } + end + + # Draws the legend on the graph + def draw_legend + if key + group = @root.add_element( "g" ) + + key_count = 0 + for key_name in keys + y_offset = (KEY_BOX_SIZE * key_count) + (key_count * 5) + group.add_element( "rect", { + "x" => 0.to_s, + "y" => y_offset.to_s, + "width" => KEY_BOX_SIZE.to_s, + "height" => KEY_BOX_SIZE.to_s, + "class" => "key#{key_count+1}" + }) + group.add_element( "text", { + "x" => (KEY_BOX_SIZE + 5).to_s, + "y" => (y_offset + KEY_BOX_SIZE).to_s, + "class" => "keyText" + }).text = key_name.to_s + key_count += 1 + end + + case key_position + when :right + x_offset = @graph_width + @border_left + 10 + y_offset = @border_top + 20 + when :bottom + x_offset = @border_left + 20 + y_offset = @border_top + @graph_height + 5 + if show_x_labels + max_x_label_height_px = (not rotate_x_labels) ? + x_label_font_size : + get_x_labels.max{|a,b| + a.to_s.length<=>b.to_s.length + }.to_s.length * x_label_font_size * 0.6 + x_label_font_size + y_offset += max_x_label_height_px + y_offset += max_x_label_height_px + 5 if stagger_x_labels + end + y_offset += x_title_font_size + 5 if show_x_title + end + group.attributes["transform"] = "translate(#{x_offset} #{y_offset})" + end + end + + + private + + def sort_multiple( arrys, lo=0, hi=arrys[0].length-1 ) + if lo < hi + p = partition(arrys,lo,hi) + sort_multiple(arrys, lo, p-1) + sort_multiple(arrys, p+1, hi) + end + arrys + end + + def partition( arrys, lo, hi ) + p = arrys[0][lo] + l = lo + z = lo+1 + while z <= hi + if arrys[0][z] < p + l += 1 + arrys.each { |arry| arry[z], arry[l] = arry[l], arry[z] } + end + z += 1 + end + arrys.each { |arry| arry[lo], arry[l] = arry[l], arry[lo] } + l + end + + def style + if no_css + styles = parse_css + @root.elements.each("//*[@class]") { |el| + cl = el.attributes["class"] + style = styles[cl] + style += el.attributes["style"] if el.attributes["style"] + el.attributes["style"] = style + } + end + end + + def parse_css + css = get_style + rv = {} + while css =~ /^(\.(\w+)(?:\s*,\s*\.\w+)*)\s*\{/m + names_orig = names = $1 + css = $' + css =~ /([^}]+)\}/m + content = $1 + css = $' + + nms = [] + while names =~ /^\s*,?\s*\.(\w+)/ + nms << $1 + names = $' + end + + content = content.tr( "\n\t", " ") + for name in nms + current = rv[name] + current = current ? current+"; "+content : content + rv[name] = current.strip.squeeze(" ") + end + end + return rv + end + + + # Override and place code to add defs here + def add_defs defs + end + + + def start_svg + # Base document + @doc = Document.new + @doc << XMLDecl.new + @doc << DocType.new( %q{svg PUBLIC "-//W3C//DTD SVG 1.0//EN" } + + %q{"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"} ) + if style_sheet && style_sheet != '' + @doc << Instruction.new( "xml-stylesheet", + %Q{href="#{style_sheet}" type="text/css"} ) + end + @root = @doc.add_element( "svg", { + "width" => width.to_s, + "height" => height.to_s, + "viewBox" => "0 0 #{width} #{height}", + "xmlns" => "http://www.w3.org/2000/svg", + "xmlns:xlink" => "http://www.w3.org/1999/xlink", + "xmlns:a3" => "http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/", + "a3:scriptImplementation" => "Adobe" + }) + @root << Comment.new( " "+"\\"*66 ) + @root << Comment.new( " Created with SVG::Graph " ) + @root << Comment.new( " SVG::Graph by Sean E. Russell " ) + @root << Comment.new( " Losely based on SVG::TT::Graph for Perl by"+ + " Leo Lapworth & Stephan Morgan " ) + @root << Comment.new( " "+"/"*66 ) + + defs = @root.add_element( "defs" ) + add_defs defs + if not(style_sheet && style_sheet != '') and !no_css + @root << Comment.new(" include default stylesheet if none specified ") + style = defs.add_element( "style", {"type"=>"text/css"} ) + style << CData.new( get_style ) + end + + @root << Comment.new( "SVG Background" ) + @root.add_element( "rect", { + "width" => width.to_s, + "height" => height.to_s, + "x" => "0", + "y" => "0", + "class" => "svgBackground" + }) + end + + + def calculate_graph_dimensions + calculate_left_margin + calculate_right_margin + calculate_bottom_margin + calculate_top_margin + @graph_width = width - @border_left - @border_right + @graph_height = height - @border_top - @border_bottom + end + + def get_style + return < :generate_user + + def self.generate_user + User.generate_with_protected! + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f4/f467515460b9eb22b10f740b88d1c4243cdd2fcb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f4/f467515460b9eb22b10f740b88d1c4243cdd2fcb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class BackwardsCompatibilityTest < Test::Unit::TestCase + def test_rails_module_plugin_method_should_delegate_to_engines_plugins + assert_nothing_raised { Rails.plugins } + assert_equal Engines.plugins, Rails.plugins + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f4/f47a66cebd26305b3781a467013843ce34b75932.svn-base Binary file .svn/pristine/f4/f47a66cebd26305b3781a467013843ce34b75932.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f4/f4ed187be5049fc813de7d8b059a08d27d7db5b6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f4/f4ed187be5049fc813de7d8b059a08d27d7db5b6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddChangesRevision < ActiveRecord::Migration + def self.up + add_column :changes, :revision, :string + end + + def self.down + remove_column :changes, :revision + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f5/f58a566574c2a05cde87f16c23c2fc9af55a3297.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f5/f58a566574c2a05cde87f16c23c2fc9af55a3297.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class WorkflowTest < ActiveSupport::TestCase + fixtures :roles, :trackers, :issue_statuses + + def test_copy + Workflow.delete_all + Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :new_status_id => 2) + Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :new_status_id => 3, :assignee => true) + Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :new_status_id => 4, :author => true) + + assert_difference 'Workflow.count', 3 do + Workflow.copy(Tracker.find(2), Role.find(1), Tracker.find(3), Role.find(2)) + end + + assert Workflow.first(:conditions => {:role_id => 2, :tracker_id => 3, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false}) + assert Workflow.first(:conditions => {:role_id => 2, :tracker_id => 3, :old_status_id => 1, :new_status_id => 3, :author => false, :assignee => true}) + assert Workflow.first(:conditions => {:role_id => 2, :tracker_id => 3, :old_status_id => 1, :new_status_id => 4, :author => true, :assignee => false}) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f5/f5ab1d07c740e8d415c8b82041e81fc8bd2e6f97.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f5/f5ab1d07c740e8d415c8b82041e81fc8bd2e6f97.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1088 @@ +# Chinese (Taiwan) translations for Ruby on Rails +# by tsechingho (http://github.com/tsechingho) +# See http://github.com/svenfuchs/rails-i18n/ for details. + +"zh-TW": + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b%d日" + long: "%Y年%b%d日" + + day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六] + abbr_day_names: [日, 一, 二, 三, 四, 五, 六] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月] + abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + # 使用於 date_select 與 datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y年%b%d日 %A %H:%M:%S %Z" + time: "%H:%M" + short: "%b%d日 %H:%M" + long: "%Y年%b%d日 %H:%M" + am: "AM" + pm: "PM" + +# 使用於 array.to_sentence. + support: + array: + words_connector: ", " + two_words_connector: " 和 " + last_word_connector: ", 和 " + sentence_connector: "且" + skip_last_comma: false + + number: + # 使用於 number_with_delimiter() + # 同時也是 'currency', 'percentage', 'precision', 與 'human' 的預設值 + format: + # 設定小數點分隔字元,以使用更高的準確度 (例如: 1.0 / 2.0 == 0.5) + separator: "." + # 千分位符號 (例如:一百萬是 1,000,000) (均以三個位數來分組) + delimiter: "," + # 小數點分隔字元後之精確位數 (數字 1 搭配 2 位精確位數為: 1.00) + precision: 3 + + # 使用於 number_to_currency() + currency: + format: + # 貨幣符號的位置? %u 是貨幣符號, %n 是數值 (預設值: $5.00) + format: "%u%n" + unit: "NT$" + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + separator: "." + delimiter: "," + precision: 2 + + # 使用於 number_to_percentage() + percentage: + format: + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + # separator: + delimiter: "" + # precision: + + # 使用於 number_to_precision() + precision: + format: + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + # separator: + delimiter: "" + # precision: + + # 使用於 number_to_human_size() + human: + format: + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + # separator: + delimiter: "" + precision: 1 + # 儲存單位輸出格式. + # %u 是儲存單位, %n 是數值 (預設值: 2 MB) + storage_units: + format: "%n %u" + units: + byte: + one: "位元組 (B)" + other: "位元組 (B)" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # 使用於 distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "半分鐘" + less_than_x_seconds: + one: "小於 1 秒" + other: "小於 %{count} 秒" + x_seconds: + one: "1 秒" + other: "%{count} 秒" + less_than_x_minutes: + one: "小於 1 分鐘" + other: "小於 %{count} 分鐘" + x_minutes: + one: "1 分鐘" + other: "%{count} 分鐘" + about_x_hours: + one: "約 1 小時" + other: "約 %{count} 小時" + x_days: + one: "1 天" + other: "%{count} 天" + about_x_months: + one: "約 1 個月" + other: "約 %{count} 個月" + x_months: + one: "1 個月" + other: "%{count} 個月" + about_x_years: + one: "約 1 年" + other: "約 %{count} 年" + over_x_years: + one: "超過 1 年" + other: "超過 %{count} 年" + almost_x_years: + one: "將近 1 年" + other: "將近 %{count} 年" + prompts: + year: "年" + month: "月" + day: "日" + hour: "時" + minute: "分" + second: "秒" + + activerecord: + errors: + template: + header: + one: "有 1 個錯誤發生使得「%{model}」無法被儲存。" + other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。" + # The variable :count is also available + body: "下面所列欄位有問題:" + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "沒有包含在列表中" + exclusion: "是被保留的" + invalid: "是無效的" + confirmation: "不符合確認值" + accepted: "必须是可被接受的" + empty: "不能留空" + blank: "不能是空白字元" + too_long: "過長(最長是 %{count} 個字)" + too_short: "過短(最短是 %{count} 個字)" + wrong_length: "字數錯誤(必須是 %{count} 個字)" + taken: "已經被使用" + not_a_number: "不是數字" + greater_than: "必須大於 %{count}" + greater_than_or_equal_to: "必須大於或等於 %{count}" + equal_to: "必須等於 %{count}" + less_than: "必須小於 %{count}" + less_than_or_equal_to: "必須小於或等於 %{count}" + odd: "必須是奇數" + even: "必須是偶數" + # Append your own errors here or at the model/attributes scope. + greater_than_start_date: "必須在開始日期之後" + not_same_project: "不屬於同一個專案" + circular_dependency: "這個關聯會導致環狀相依" + cant_link_an_issue_with_a_descendant: "問題無法被連結至自己的子任務" + + # You can define own errors for models or model attributes. + # The values :model, :attribute and :value are always available for interpolation. + # + # For example, + # models: + # user: + # blank: "This is a custom blank message for %{model}: %{attribute}" + # attributes: + # login: + # blank: "This is a custom blank message for User login" + # Will define custom blank validation message for User model and + # custom blank validation message for login attribute of User model. + #models: + + # Translate model names. Used in Model.human_name(). + #models: + # For example, + # user: "Dude" + # will translate User model name to "Dude" + + # Translate model attribute names. Used in Model.human_attribute_name(attribute). + #attributes: + # For example, + # user: + # login: "Handle" + # will translate User attribute "login" as "Handle" + + actionview_instancetag_blank_option: 請選擇 + + general_text_No: '否' + general_text_Yes: '是' + general_text_no: '否' + general_text_yes: '是' + general_lang_name: 'Traditional Chinese (繁體中文)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: Big5 + general_pdf_encoding: Big5 + general_first_day_of_week: '7' + + notice_account_updated: 帳戶更新資訊已儲存 + notice_account_invalid_creditentials: 帳戶或密碼不正確 + notice_account_password_updated: 帳戶新密碼已儲存 + notice_account_wrong_password: 密碼不正確 + notice_account_register_done: 帳號已建立成功。欲啟用您的帳號,請點擊系統確認信函中的啟用連結。 + notice_account_unknown_email: 未知的使用者 + notice_can_t_change_password: 這個帳號使用外部認證方式,無法變更其密碼。 + notice_account_lost_email_sent: 包含選擇新密碼指示的電子郵件,已經寄出給您。 + notice_account_activated: 您的帳號已經啟用,可用它登入系統。 + notice_successful_create: 建立成功 + notice_successful_update: 更新成功 + notice_successful_delete: 刪除成功 + notice_successful_connection: 連線成功 + notice_file_not_found: 您想要存取的頁面已經不存在或被搬移至其他位置。 + notice_locking_conflict: 資料已被其他使用者更新。 + notice_not_authorized: 你未被授權存取此頁面。 + notice_not_authorized_archived_project: 您欲存取的專案已經被歸檔封存。 + notice_email_sent: "郵件已經成功寄送至以下收件者: %{value}" + notice_email_error: "寄送郵件的過程中發生錯誤 (%{value})" + notice_feeds_access_key_reseted: 您的 RSS 存取金鑰已被重新設定。 + notice_api_access_key_reseted: 您的 API 存取金鑰已被重新設定。 + notice_failed_to_save_issues: " %{count} 個問題儲存失敗(總共選取 %{total} 個問題): %{ids} 。" + notice_failed_to_save_members: "成員儲存失敗: %{errors}." + notice_no_issue_selected: "未選擇任何問題!請勾選您想要編輯的問題。" + notice_account_pending: "您的帳號已經建立,正在等待管理員的審核。" + notice_default_data_loaded: 預設組態已載入成功。 + notice_unable_delete_version: 無法刪除版本。 + notice_unable_delete_time_entry: 無法刪除工時記錄項目。 + notice_issue_done_ratios_updated: 問題完成百分比已更新。 + notice_gantt_chart_truncated: "由於項目數量超過可顯示數量的最大值 (%{max}),故此甘特圖尾部已被截斷" + notice_issue_successful_create: "問題 %{id} 已建立。" + + error_can_t_load_default_data: "無法載入預設組態: %{value}" + error_scm_not_found: "在儲存機制中找不到這個項目或修訂版。" + error_scm_command_failed: "嘗試存取儲存機制時發生錯誤: %{value}" + error_scm_annotate: "項目不存在或項目無法被加上附註。" + error_scm_annotate_big_text_file: 此項目無法被標註,因為它已經超過最大的文字檔大小。 + error_issue_not_found_in_project: '該問題不存在或不屬於此專案' + error_no_tracker_in_project: '此專案尚未指定追蹤標籤。請檢查專案的設定資訊。' + error_no_default_issue_status: '尚未定義問題狀態的預設值。請您前往「網站管理」->「問題狀態清單」頁面,檢查相關組態設定。' + error_can_not_delete_custom_field: 無法刪除自訂欄位 + error_can_not_delete_tracker: "此追蹤標籤已包含問題,無法被刪除。" + error_can_not_remove_role: "此角色已被使用,無法將其刪除。" + error_can_not_reopen_issue_on_closed_version: '指派給「已結束」版本的問題,無法再將其狀態變更為「進行中」' + error_can_not_archive_project: 此專案無法被歸檔 + error_issue_done_ratios_not_updated: "問題完成百分比未更新。" + error_workflow_copy_source: '請選擇一個來源問題追蹤標籤或角色' + error_workflow_copy_target: '請選擇一個(或多個)目的問題追蹤標籤或角色' + error_unable_delete_issue_status: '無法刪除問題狀態' + error_unable_to_connect: "無法連線至(%{value})" + error_attachment_too_big: "這個檔案無法被上傳,因為它已經超過最大的檔案大小 (%{max_size})" + warning_attachments_not_saved: "%{count} 個附加檔案無法被儲存。" + + mail_subject_lost_password: 您的 Redmine 網站密碼 + mail_body_lost_password: '欲變更您的 Redmine 網站密碼, 請點選以下鏈結:' + mail_subject_register: 啟用您的 Redmine 帳號 + mail_body_register: '欲啟用您的 Redmine 帳號, 請點選以下鏈結:' + mail_body_account_information_external: "您可以使用 %{value} 帳號登入 Redmine 網站。" + mail_body_account_information: 您的 Redmine 帳號資訊 + mail_subject_account_activation_request: Redmine 帳號啟用需求通知 + mail_body_account_activation_request: "有位新用戶 (%{value}) 已經完成註冊,正等候您的審核:" + mail_subject_reminder: "您有 %{count} 個問題即將到期 (%{days})" + mail_body_reminder: "%{count} 個指派給您的問題,將於 %{days} 天之內到期:" + mail_subject_wiki_content_added: "'%{id}' wiki 頁面已被新增" + mail_body_wiki_content_added: "此 '%{id}' wiki 頁面已被 %{author} 新增。" + mail_subject_wiki_content_updated: "'%{id}' wiki 頁面已被更新" + mail_body_wiki_content_updated: "此 '%{id}' wiki 頁面已被 %{author} 更新。" + + gui_validation_error: 1 個錯誤 + gui_validation_error_plural: "%{count} 個錯誤" + + field_name: 名稱 + field_description: 概述 + field_summary: 摘要 + field_is_required: 必填 + field_firstname: 名字 + field_lastname: 姓氏 + field_mail: 電子郵件 + field_filename: 檔案名稱 + field_filesize: 大小 + field_downloads: 下載次數 + field_author: 作者 + field_created_on: 建立日期 + field_updated_on: 更新 + field_field_format: 格式 + field_is_for_all: 給全部的專案 + field_possible_values: 可能值 + field_regexp: 正規表示式 + field_min_length: 最小長度 + field_max_length: 最大長度 + field_value: 值 + field_category: 分類 + field_title: 標題 + field_project: 專案 + field_issue: 問題 + field_status: 狀態 + field_notes: 筆記 + field_is_closed: 問題已結束 + field_is_default: 預設值 + field_tracker: 追蹤標籤 + field_subject: 主旨 + field_due_date: 完成日期 + field_assigned_to: 分派給 + field_priority: 優先權 + field_fixed_version: 版本 + field_user: 用戶 + field_principal: 原則 + field_role: 角色 + field_homepage: 網站首頁 + field_is_public: 公開 + field_parent: 父專案 + field_is_in_roadmap: 問題顯示於版本藍圖中 + field_login: 帳戶名稱 + field_mail_notification: 電子郵件提醒選項 + field_admin: 管理者 + field_last_login_on: 最近連線日期 + field_language: 語系 + field_effective_date: 日期 + field_password: 目前密碼 + field_new_password: 新密碼 + field_password_confirmation: 確認新密碼 + field_version: 版本 + field_type: Type + field_host: Host + field_port: 連接埠 + field_account: 帳戶 + field_base_dn: Base DN + field_attr_login: 登入屬性 + field_attr_firstname: 名字屬性 + field_attr_lastname: 姓氏屬性 + field_attr_mail: 電子郵件信箱屬性 + field_onthefly: 即時建立使用者 + field_start_date: 開始日期 + field_done_ratio: 完成百分比 + field_auth_source: 認證模式 + field_hide_mail: 隱藏我的電子郵件 + field_comments: 回應 + field_url: 網址 + field_start_page: 首頁 + field_subproject: 子專案 + field_hours: 小時 + field_activity: 活動 + field_spent_on: 日期 + field_identifier: 代碼 + field_is_filter: 用來作為過濾器 + field_issue_to: 相關問題 + field_delay: 逾期 + field_assignable: 問題可被分派至此角色 + field_redirect_existing_links: 重新導向現有連結 + field_estimated_hours: 預估工時 + field_column_names: 欄位 + field_time_entries: 耗用工時 + field_time_zone: 時區 + field_searchable: 可用做搜尋條件 + field_default_value: 預設值 + field_comments_sorting: 回應排序 + field_parent_title: 父頁面 + field_editable: 可編輯 + field_watcher: 觀察者 + field_identity_url: OpenID 網址 + field_content: 內容 + field_group_by: 結果分組方式 + field_sharing: 共用 + field_parent_issue: 父任務 + field_member_of_group: "被指派者的群組" + field_assigned_to_role: "被指派者的角色" + field_text: 內容文字 + field_visible: 可被看見 + field_warn_on_leaving_unsaved: "提醒我將要離開的頁面中尚有未儲存的資料" + field_issues_visibility: 問題可見度 + field_is_private: 私人 + field_commit_logs_encoding: 認可訊息編碼 + field_scm_path_encoding: 路徑編碼 + field_path_to_repository: 儲存機制路徑 + field_root_directory: 根資料夾 + field_cvsroot: CVSROOT + field_cvs_module: 模組 + + setting_app_title: 標題 + setting_app_subtitle: 副標題 + setting_welcome_text: 歡迎詞 + setting_default_language: 預設語系 + setting_login_required: 需要驗證 + setting_self_registration: 註冊選項 + setting_attachment_max_size: 附件大小限制 + setting_issues_export_limit: 問題匯出限制 + setting_mail_from: 寄件者電子郵件 + setting_bcc_recipients: 使用密件副本 (BCC) + setting_plain_text_mail: 純文字郵件 (不含 HTML) + setting_host_name: 主機名稱 + setting_text_formatting: 文字格式 + setting_wiki_compression: 壓縮 Wiki 歷史文章 + setting_feeds_limit: RSS 新聞限制 + setting_autofetch_changesets: 自動擷取認可 + setting_default_projects_public: 新建立之專案預設為「公開」 + setting_sys_api_enabled: 啟用管理儲存機制的網頁服務 (Web Service) + setting_commit_ref_keywords: 認可用於參照之關鍵字 + setting_commit_fix_keywords: 認可用於修正之關鍵字 + setting_autologin: 自動登入 + setting_date_format: 日期格式 + setting_time_format: 時間格式 + setting_cross_project_issue_relations: 允許關聯至其它專案的問題 + setting_issue_list_default_columns: 預設顯示於問題清單的欄位 + setting_repositories_encodings: 附加檔案與儲存機制的編碼 + setting_emails_header: 電子郵件前頭說明 + setting_emails_footer: 電子郵件附帶說明 + setting_protocol: 協定 + setting_per_page_options: 每頁顯示個數選項 + setting_user_format: 使用者顯示格式 + setting_activity_days_default: 專案活動顯示天數 + setting_display_subprojects_issues: 預設於父專案中顯示子專案的問題 + setting_enabled_scm: 啟用的 SCM + setting_mail_handler_body_delimiters: "截去郵件中包含下列值之後的內容" + setting_mail_handler_api_enabled: 啟用處理傳入電子郵件的服務 + setting_mail_handler_api_key: API 金鑰 + setting_sequential_project_identifiers: 循序產生專案識別碼 + setting_gravatar_enabled: 啟用 Gravatar 全球認證大頭像 + setting_gravatar_default: 預設全球認證大頭像圖片 + setting_diff_max_lines_displayed: 差異顯示行數之最大值 + setting_file_max_size_displayed: 檔案內容顯示大小之最大值 + setting_repository_log_display_limit: 修訂版顯示數目之最大值 + setting_openid: 允許使用 OpenID 登入與註冊 + setting_password_min_length: 密碼最小長度 + setting_new_project_user_role_id: 管理者以外之用戶建立新專案時,將被指派的角色 + setting_default_projects_modules: 新專案預設啟用的模組 + setting_issue_done_ratio: 計算問題完成百分比之方式 + setting_issue_done_ratio_issue_field: 依據問題完成百分比欄位 + setting_issue_done_ratio_issue_status: 依據問題狀態 + setting_start_of_week: 週的第一天 + setting_rest_api_enabled: 啟用 REST 網路服務技術(Web Service) + setting_cache_formatted_text: 快取已格式化文字 + setting_default_notification_option: 預設通知選項 + setting_commit_logtime_enabled: 啟用認可中的時間記錄 + setting_commit_logtime_activity_id: 時間記錄對應的活動 + setting_gantt_items_limit: 甘特圖中項目顯示數量的最大值 + setting_issue_group_assignment: 允許問題被指派至群組 + setting_default_issue_start_date_to_creation_date: 設定新問題的起始日期為今天的日期 + + permission_add_project: 建立專案 + permission_add_subprojects: 建立子專案 + permission_edit_project: 編輯專案 + permission_select_project_modules: 選擇專案模組 + permission_manage_members: 管理成員 + permission_manage_project_activities: 管理專案活動 + permission_manage_versions: 管理版本 + permission_manage_categories: 管理問題分類 + permission_view_issues: 檢視問題 + permission_add_issues: 新增問題 + permission_edit_issues: 編輯問題 + permission_manage_issue_relations: 管理問題關聯 + permission_set_issues_private: 設定問題為公開或私人 + permission_set_own_issues_private: 設定自己的問題為公開或私人 + permission_add_issue_notes: 新增筆記 + permission_edit_issue_notes: 編輯筆記 + permission_edit_own_issue_notes: 編輯自己的筆記 + permission_move_issues: 搬移問題 + permission_delete_issues: 刪除問題 + permission_manage_public_queries: 管理公開查詢 + permission_save_queries: 儲存查詢 + permission_view_gantt: 檢視甘特圖 + permission_view_calendar: 檢視日曆 + permission_view_issue_watchers: 檢視監看者清單 + permission_add_issue_watchers: 新增監看者 + permission_delete_issue_watchers: 刪除監看者 + permission_log_time: 紀錄耗用工時 + permission_view_time_entries: 檢視耗用工時 + permission_edit_time_entries: 編輯工時紀錄 + permission_edit_own_time_entries: 編輯自己的工時記錄 + permission_manage_news: 管理新聞 + permission_comment_news: 回應新聞 + permission_manage_documents: 管理文件 + permission_view_documents: 檢視文件 + permission_manage_files: 管理檔案 + permission_view_files: 檢視檔案 + permission_manage_wiki: 管理 wiki + permission_rename_wiki_pages: 重新命名 wiki 頁面 + permission_delete_wiki_pages: 刪除 wiki 頁面 + permission_view_wiki_pages: 檢視 wiki + permission_view_wiki_edits: 檢視 wiki 歷史 + permission_edit_wiki_pages: 編輯 wiki 頁面 + permission_delete_wiki_pages_attachments: 刪除附件 + permission_protect_wiki_pages: 專案 wiki 頁面 + permission_manage_repository: 管理儲存機制 + permission_browse_repository: 瀏覽儲存機制 + permission_view_changesets: 檢視變更集 + permission_commit_access: 存取認可 + permission_manage_boards: 管理討論版 + permission_view_messages: 檢視訊息 + permission_add_messages: 新增訊息 + permission_edit_messages: 編輯訊息 + permission_edit_own_messages: 編輯自己的訊息 + permission_delete_messages: 刪除訊息 + permission_delete_own_messages: 刪除自己的訊息 + permission_export_wiki_pages: 匯出 wiki 頁面 + permission_manage_subtasks: 管理子任務 + + project_module_issue_tracking: 問題追蹤 + project_module_time_tracking: 工時追蹤 + project_module_news: 新聞 + project_module_documents: 文件 + project_module_files: 檔案 + project_module_wiki: Wiki + project_module_repository: 版本控管 + project_module_boards: 討論區 + project_module_calendar: 日曆 + project_module_gantt: 甘特圖 + + label_user: 用戶 + label_user_plural: 用戶清單 + label_user_new: 建立新用戶 + label_user_anonymous: 匿名用戶 + label_project: 專案 + label_project_new: 建立新專案 + label_project_plural: 專案清單 + label_x_projects: + zero: 無專案 + one: 1 個專案 + other: "%{count} 個專案" + label_project_all: 全部的專案 + label_project_latest: 最近的專案 + label_issue: 問題 + label_issue_new: 建立新問題 + label_issue_plural: 問題清單 + label_issue_view_all: 檢視所有問題 + label_issues_by: "問題按 %{value} 分組顯示" + label_issue_added: 問題已新增 + label_issue_updated: 問題已更新 + label_issue_note_added: 筆記已新增 + label_issue_status_updated: 狀態已更新 + label_issue_priority_updated: 優先權已更新 + label_document: 文件 + label_document_new: 建立新文件 + label_document_plural: 文件 + label_document_added: 文件已新增 + label_role: 角色 + label_role_plural: 角色 + label_role_new: 建立新角色 + label_role_and_permissions: 角色與權限 + label_role_anonymous: 匿名者 + label_role_non_member: 非會員 + label_member: 成員 + label_member_new: 建立新成員 + label_member_plural: 成員 + label_tracker: 追蹤標籤 + label_tracker_plural: 追蹤標籤清單 + label_tracker_new: 建立新的追蹤標籤 + label_workflow: 流程 + label_issue_status: 問題狀態 + label_issue_status_plural: 問題狀態清單 + label_issue_status_new: 建立新狀態 + label_issue_category: 問題分類 + label_issue_category_plural: 問題分類清單 + label_issue_category_new: 建立新分類 + label_custom_field: 自訂欄位 + label_custom_field_plural: 自訂欄位清單 + label_custom_field_new: 建立新自訂欄位 + label_enumerations: 列舉值清單 + label_enumeration_new: 建立新列舉值 + label_information: 資訊 + label_information_plural: 資訊 + label_please_login: 請先登入 + label_register: 註冊 + label_login_with_open_id_option: 或使用 OpenID 登入 + label_password_lost: 遺失密碼 + label_home: 網站首頁 + label_my_page: 帳戶首頁 + label_my_account: 我的帳戶 + label_my_projects: 我的專案 + label_my_page_block: 帳戶首頁區塊 + label_administration: 網站管理 + label_login: 登入 + label_logout: 登出 + label_help: 說明 + label_reported_issues: 我通報的問題 + label_assigned_to_me_issues: 分派給我的問題 + label_last_login: 最近一次連線 + label_registered_on: 註冊於 + label_activity: 活動 + label_overall_activity: 整體活動 + label_user_activity: "%{value} 的活動" + label_new: 建立新的... + label_logged_as: 目前登入 + label_environment: 環境 + label_authentication: 認證 + label_auth_source: 認證模式 + label_auth_source_new: 建立新認證模式 + label_auth_source_plural: 認證模式清單 + label_subproject_plural: 子專案 + label_subproject_new: 建立子專案 + label_and_its_subprojects: "%{value} 與其子專案" + label_min_max_length: 最小 - 最大 長度 + label_list: 清單 + label_date: 日期 + label_integer: 整數 + label_float: 浮點數 + label_boolean: 布林 + label_string: 文字 + label_text: 長文字 + label_attribute: 屬性 + label_attribute_plural: 屬性 + label_download: "%{count} 個下載" + label_download_plural: "%{count} 個下載" + label_no_data: 沒有任何資料可供顯示 + label_change_status: 變更狀態 + label_history: 歷史 + label_attachment: 檔案 + label_attachment_new: 建立新檔案 + label_attachment_delete: 刪除檔案 + label_attachment_plural: 檔案 + label_file_added: 檔案已新增 + label_report: 報告 + label_report_plural: 報告 + label_news: 新聞 + label_news_new: 建立新聞 + label_news_plural: 新聞 + label_news_latest: 最近新聞 + label_news_view_all: 檢視全部的新聞 + label_news_added: 新聞已新增 + label_news_comment_added: 回應已加入新聞 + label_settings: 設定 + label_overview: 概觀 + label_version: 版本 + label_version_new: 建立新版本 + label_version_plural: 版本 + label_close_versions: 結束已完成的版本 + label_confirmation: 確認 + label_export_to: 匯出至 + label_read: 讀取... + label_public_projects: 公開專案 + label_open_issues: 進行中 + label_open_issues_plural: 進行中 + label_closed_issues: 已結束 + label_closed_issues_plural: 已結束 + label_x_open_issues_abbr_on_total: + zero: 0 進行中 / 共 %{total} + one: 1 進行中 / 共 %{total} + other: "%{count} 進行中 / 共 %{total}" + label_x_open_issues_abbr: + zero: 0 進行中 + one: 1 進行中 + other: "%{count} 進行中" + label_x_closed_issues_abbr: + zero: 0 已結束 + one: 1 已結束 + other: "%{count} 已結束" + label_total: 總計 + label_permissions: 權限 + label_current_status: 目前狀態 + label_new_statuses_allowed: 可變更至以下狀態 + label_all: 全部 + label_none: 空值 + label_nobody: 無名 + label_next: 下一頁 + label_previous: 上一頁 + label_used_by: Used by + label_details: 明細 + label_add_note: 加入一個新筆記 + label_per_page: 每頁 + label_calendar: 日曆 + label_months_from: 個月, 開始月份 + label_gantt: 甘特圖 + label_internal: 內部 + label_last_changes: "最近 %{count} 個變更" + label_change_view_all: 檢視全部的變更 + label_personalize_page: 自訂版面 + label_comment: 回應 + label_comment_plural: 回應 + label_x_comments: + zero: 無回應 + one: 1 個回應 + other: "%{count} 個回應" + label_comment_add: 加入新回應 + label_comment_added: 新回應已加入 + label_comment_delete: 刪除回應 + label_query: 自訂查詢 + label_query_plural: 自訂查詢 + label_query_new: 建立新查詢 + label_my_queries: 我的自訂查詢 + label_filter_add: 加入新篩選條件 + label_filter_plural: 篩選條件 + label_equals: 等於 + label_not_equals: 不等於 + label_in_less_than: 在小於 + label_in_more_than: 在大於 + label_greater_or_equal: "大於等於 (>=)" + label_less_or_equal: "小於等於 (<=)" + label_between: 區間 + label_in: 在 + label_today: 今天 + label_all_time: 全部 + label_yesterday: 昨天 + label_this_week: 本週 + label_last_week: 上週 + label_last_n_days: "過去 %{count} 天" + label_this_month: 這個月 + label_last_month: 上個月 + label_this_year: 今年 + label_date_range: 日期區間 + label_less_than_ago: 小於幾天之前 + label_more_than_ago: 大於幾天之前 + label_ago: 天以前 + label_contains: 包含 + label_not_contains: 不包含 + label_day_plural: 天 + label_repository: 儲存機制 + label_repository_plural: 儲存機制清單 + label_browse: 瀏覽 + label_modification: "%{count} 變更" + label_modification_plural: "%{count} 變更" + label_branch: 分支 + label_tag: 標籤 + label_revision: 修訂版 + label_revision_plural: 修訂版清單 + label_revision_id: "修訂版 %{value}" + label_associated_revisions: 關聯的修訂版 + label_added: 已新增 + label_modified: 已修改 + label_copied: 已複製 + label_renamed: 已重新命名 + label_deleted: 已刪除 + label_latest_revision: 最新的修訂版 + label_latest_revision_plural: 最新的修訂版清單 + label_view_revisions: 檢視修訂版清單 + label_view_all_revisions: 檢視所有的的修訂版清單 + label_max_size: 最大長度 + label_sort_highest: 移動至開頭 + label_sort_higher: 往上移動 + label_sort_lower: 往下移動 + label_sort_lowest: 移動至結尾 + label_roadmap: 版本藍圖 + label_roadmap_due_in: "剩餘 %{value}" + label_roadmap_overdue: "逾期 %{value}" + label_roadmap_no_issues: 此版本尚未包含任何問題 + label_search: 搜尋 + label_result_plural: 結果 + label_all_words: 包含全部的字詞 + label_wiki: Wiki + label_wiki_edit: Wiki 編輯 + label_wiki_edit_plural: Wiki 編輯 + label_wiki_page: Wiki 網頁 + label_wiki_page_plural: Wiki 網頁 + label_index_by_title: 依標題索引 + label_index_by_date: 依日期索引 + label_current_version: 現行版本 + label_preview: 預覽 + label_feed_plural: Feeds + label_changes_details: 所有變更的明細 + label_issue_tracking: 問題追蹤 + label_spent_time: 耗用工時 + label_overall_spent_time: 整體耗用工時 + label_f_hour: "%{value} 小時" + label_f_hour_plural: "%{value} 小時" + label_time_tracking: 工時追蹤 + label_change_plural: 變更 + label_statistics: 統計資訊 + label_commits_per_month: 依月份統計認可 + label_commits_per_author: 依作者統計認可 + label_view_diff: 檢視差異 + label_diff: 差異 + label_diff_inline: 直列 + label_diff_side_by_side: 並排 + label_options: 選項清單 + label_copy_workflow_from: 從以下追蹤標籤複製工作流程 + label_permissions_report: 權限報表 + label_watched_issues: 監看中的問題清單 + label_related_issues: 相關的問題清單 + label_applied_status: 已套用狀態 + label_loading: 載入中... + label_relation_new: 建立新關聯 + label_relation_delete: 刪除關聯 + label_relates_to: 關聯至 + label_duplicates: 已重複 + label_duplicated_by: 與後面所列問題重複 + label_blocks: 阻擋 + label_blocked_by: 被阻擋 + label_precedes: 優先於 + label_follows: 跟隨於 + label_end_to_start: 結束─開始 + label_end_to_end: 結束─結束 + label_start_to_start: 開始─開始 + label_start_to_end: 開始─結束 + label_stay_logged_in: 維持已登入狀態 + label_disabled: 關閉 + label_show_completed_versions: 顯示已完成的版本 + label_me: 我自己 + label_board: 論壇 + label_board_new: 建立新論壇 + label_board_plural: 論壇 + label_board_locked: 鎖定 + label_board_sticky: 置頂 + label_topic_plural: 討論主題 + label_message_plural: 訊息 + label_message_last: 上一封訊息 + label_message_new: 建立新訊息 + label_message_posted: 訊息已新增 + label_reply_plural: 回應 + label_send_information: 寄送帳戶資訊電子郵件給用戶 + label_year: 年 + label_month: 月 + label_week: 週 + label_date_from: 開始 + label_date_to: 結束 + label_language_based: 依用戶之語系決定 + label_sort_by: "按 %{value} 排序" + label_send_test_email: 寄送測試郵件 + label_feeds_access_key: RSS 存取金鑰 + label_missing_feeds_access_key: 找不到 RSS 存取金鑰 + label_feeds_access_key_created_on: "RSS 存取鍵建立於 %{value} 之前" + label_module_plural: 模組 + label_added_time_by: "是由 %{author} 於 %{age} 前加入" + label_updated_time_by: "是由 %{author} 於 %{age} 前更新" + label_updated_time: "於 %{value} 前更新" + label_jump_to_a_project: 選擇欲前往的專案... + label_file_plural: 檔案清單 + label_changeset_plural: 變更集清單 + label_default_columns: 預設欄位清單 + label_no_change_option: (維持不變) + label_bulk_edit_selected_issues: 大量編輯選取的問題 + label_bulk_edit_selected_time_entries: 大量編輯選取的工時項目 + label_theme: 畫面主題 + label_default: 預設 + label_search_titles_only: 僅搜尋標題 + label_user_mail_option_all: "提醒與我的專案有關的全部事件" + label_user_mail_option_selected: "只提醒我所選擇專案中的事件..." + label_user_mail_option_none: "取消提醒" + label_user_mail_option_only_my_events: "只提醒我觀察中或參與中的事物" + label_user_mail_option_only_assigned: "只提醒我被指派的事物" + label_user_mail_option_only_owner: "只提醒我作為擁有者的事物" + label_user_mail_no_self_notified: "不提醒我自己所做的變更" + label_registration_activation_by_email: 透過電子郵件啟用帳戶 + label_registration_manual_activation: 手動啟用帳戶 + label_registration_automatic_activation: 自動啟用帳戶 + label_display_per_page: "每頁顯示: %{value} 個" + label_age: 年齡 + label_change_properties: 變更屬性 + label_general: 一般 + label_more: 更多 » + label_scm: 版本控管 + label_plugins: 附加元件 + label_ldap_authentication: LDAP 認證 + label_downloads_abbr: 下載 + label_optional_description: 額外的說明 + label_add_another_file: 增加其他檔案 + label_preferences: 偏好選項 + label_chronological_order: 以時間由遠至近排序 + label_reverse_chronological_order: 以時間由近至遠排序 + label_planning: 計劃表 + label_incoming_emails: 傳入的電子郵件 + label_generate_key: 產生金鑰 + label_issue_watchers: 監看者 + label_example: 範例 + label_display: 顯示 + label_sort: 排序 + label_ascending: 遞增排序 + label_descending: 遞減排序 + label_date_from_to: 起 %{start} 迄 %{end} + label_wiki_content_added: Wiki 頁面已新增 + label_wiki_content_updated: Wiki 頁面已更新 + label_group: 群組 + label_group_plural: 群組清單 + label_group_new: 建立新群組 + label_time_entry_plural: 耗用工時 + label_version_sharing_none: 不共用 + label_version_sharing_descendants: 與子專案共用 + label_version_sharing_hierarchy: 與專案階層架構共用 + label_version_sharing_tree: 與專案樹共用 + label_version_sharing_system: 與全部的專案共用 + label_update_issue_done_ratios: 更新問題完成百分比 + label_copy_source: 來源 + label_copy_target: 目的地 + label_copy_same_as_target: 與目的地相同 + label_display_used_statuses_only: 僅顯示此追蹤標籤所使用之狀態 + label_api_access_key: API 存取金鑰 + label_missing_api_access_key: 找不到 API 存取金鑰 + label_api_access_key_created_on: "API 存取金鑰建立於 %{value} 之前" + label_profile: 配置概況 + label_subtask_plural: 子任務 + label_project_copy_notifications: 在複製專案的過程中,傳送通知郵件 + label_principal_search: "搜尋用戶或群組:" + label_user_search: "搜尋用戶:" + label_additional_workflow_transitions_for_author: 用戶為作者時額外允許的流程轉換 + label_additional_workflow_transitions_for_assignee: 用戶為被指定者時額外允許的流程轉換 + label_issues_visibility_all: 所有問題 + label_issues_visibility_public: 所有非私人問題 + label_issues_visibility_own: 使用者所建立的或被指派的問題 + label_git_report_last_commit: 報告最後認可的文件和目錄 + label_parent_revision: 父項 + label_child_revision: 子項 + label_export_options: %{export_format} 匯出選項 + + button_login: 登入 + button_submit: 送出 + button_save: 儲存 + button_check_all: 全選 + button_uncheck_all: 全不選 + button_collapse_all: 全部摺疊 + button_expand_all: 全部展開 + button_delete: 刪除 + button_create: 建立 + button_create_and_continue: 繼續建立 + button_test: 測試 + button_edit: 編輯 + button_edit_associated_wikipage: "編輯相關 Wiki 頁面: %{page_title}" + button_add: 新增 + button_change: 修改 + button_apply: 套用 + button_clear: 清除 + button_lock: 鎖定 + button_unlock: 解除鎖定 + button_download: 下載 + button_list: 清單 + button_view: 檢視 + button_move: 移動 + button_move_and_follow: 移動後跟隨 + button_back: 返回 + button_cancel: 取消 + button_activate: 啟用 + button_sort: 排序 + button_log_time: 記錄時間 + button_rollback: 還原至此版本 + button_watch: 觀察 + button_unwatch: 取消觀察 + button_reply: 回應 + button_archive: 歸檔 + button_unarchive: 取消歸檔 + button_reset: 回復 + button_rename: 重新命名 + button_change_password: 變更密碼 + button_copy: 複製 + button_copy_and_follow: 複製後跟隨 + button_annotate: 註解 + button_update: 更新 + button_configure: 設定 + button_quote: 引用 + button_duplicate: 重製 + button_show: 顯示 + button_edit_section: 編輯此區塊 + button_export: 匯出 + + status_active: 活動中 + status_registered: 註冊完成 + status_locked: 鎖定中 + + version_status_open: 進行中 + version_status_locked: 已鎖定 + version_status_closed: 已結束 + + field_active: 活動中 + + text_select_mail_notifications: 選擇欲寄送提醒通知郵件之動作 + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 代表「不限制」 + text_project_destroy_confirmation: 您確定要刪除這個專案和其他相關資料? + text_subprojects_destroy_warning: "下列子專案: %{value} 將一併被刪除。" + text_workflow_edit: 選擇角色與追蹤標籤以設定其工作流程 + text_are_you_sure: 確定執行? + text_are_you_sure_with_children: "確定刪除此問題及其子問題?" + text_journal_changed: "%{label} 從 %{old} 變更為 %{new}" + text_journal_changed_no_detail: "%{label} 已更新" + text_journal_set_to: "%{label} 設定為 %{value}" + text_journal_deleted: "%{label} 已刪除 (%{old})" + text_journal_added: "%{label} %{value} 已新增" + text_tip_issue_begin_day: 今天起始的問題 + text_tip_issue_end_day: 今天截止的的問題 + text_tip_issue_begin_end_day: 今天起始與截止的問題 + text_project_identifier_info: '只允許小寫英文字母(a-z)、阿拉伯數字與連字符號(-)。
    儲存後,代碼不可再被更改。' + text_caracters_maximum: "最多 %{count} 個字元." + text_caracters_minimum: "長度必須大於 %{count} 個字元." + text_length_between: "長度必須介於 %{min} 至 %{max} 個字元之間." + text_tracker_no_workflow: 此追蹤標籤尚未定義工作流程 + text_unallowed_characters: 不允許的字元 + text_comma_separated: 可輸入多個值(須以逗號分隔)。 + text_line_separated: 可輸入多個值(須以換行符號分隔,即每列只能輸入一個值)。 + text_issues_ref_in_commit_messages: 認可訊息中參照(或修正)問題之關鍵字 + text_issue_added: "問題 %{id} 已被 %{author} 通報。" + text_issue_updated: "問題 %{id} 已被 %{author} 更新。" + text_wiki_destroy_confirmation: 您確定要刪除這個 wiki 和其中的所有內容? + text_issue_category_destroy_question: "有 (%{count}) 個問題被指派到此分類. 請選擇您想要的動作?" + text_issue_category_destroy_assignments: 移除這些問題的分類 + text_issue_category_reassign_to: 重新指派這些問題至其它分類 + text_user_mail_option: "對於那些未被選擇的專案,將只會接收到您正在觀察中,或是參與中的問題通知。(「參與中的問題」包含您建立的或是指派給您的問題)" + text_no_configuration_data: "角色、追蹤標籤、問題狀態與流程尚未被設定完成。\n強烈建議您先載入預設的組態。將預設組態載入之後,您可再變更其中之值。" + text_load_default_configuration: 載入預設組態 + text_status_changed_by_changeset: "已套用至變更集 %{value}." + text_time_logged_by_changeset: "紀錄於變更集 %{value}." + text_issues_destroy_confirmation: '確定刪除已選擇的問題?' + text_issues_destroy_descendants_confirmation: "這麼做將會一併刪除 %{count} 子任務。" + text_time_entries_destroy_confirmation: 您確定要刪除所選擇的工時紀錄? + text_select_project_modules: '選擇此專案可使用之模組:' + text_default_administrator_account_changed: 已變更預設管理員帳號內容 + text_file_repository_writable: 可寫入附加檔案目錄 + text_plugin_assets_writable: 可寫入附加元件目錄 + text_rmagick_available: 可使用 RMagick (選配) + text_destroy_time_entries_question: 您即將刪除的問題已報工 %{hours} 小時. 您的選擇是? + text_destroy_time_entries: 刪除已報工的時數 + text_assign_time_entries_to_project: 指定已報工的時數至專案中 + text_reassign_time_entries: '重新指定已報工的時數至此問題:' + text_user_wrote: "%{value} 先前提到:" + text_enumeration_destroy_question: "目前有 %{count} 個物件使用此列舉值。" + text_enumeration_category_reassign_to: '重新設定其列舉值為:' + text_email_delivery_not_configured: "您尚未設定電子郵件傳送方式,因此提醒選項已被停用。\n請在 config/configuration.yml 中設定 SMTP 之後,重新啟動 Redmine,以啟用電子郵件提醒選項。" + text_repository_usernames_mapping: "選擇或更新 Redmine 使用者與儲存機制紀錄使用者之對應關係。\n儲存機制中之使用者帳號或電子郵件信箱,與 Redmine 設定相同者,將自動產生對應關係。" + text_diff_truncated: '... 這份差異已被截短以符合顯示行數之最大值' + text_custom_field_possible_values_info: '一列輸入一個值' + text_wiki_page_destroy_question: "此頁面包含 %{descendants} 個子頁面及延伸頁面。 請選擇您想要的動作?" + text_wiki_page_nullify_children: "保留所有子頁面當作根頁面" + text_wiki_page_destroy_children: "刪除所有子頁面及其延伸頁面" + text_wiki_page_reassign_children: "重新指定所有的子頁面之父頁面至此頁面" + text_own_membership_delete_confirmation: "您在專案中,所擁有的部分或全部權限即將被移除,在這之後可能無法再次編輯此專案。\n您確定要繼續執行這個動作?" + text_zoom_in: 放大 + text_zoom_out: 縮小 + text_warn_on_leaving_unsaved: "若您離開這個頁面,此頁面所包含的未儲存資料將會遺失。" + text_scm_path_encoding_note: "預設: UTF-8" + text_git_repository_note: 儲存機制是本機的空(bare)目錄 (即: /gitrepo, c:\gitrepo) + text_mercurial_repository_note: 本機儲存機制 (即: /hgrepo, c:\hgrepo) + text_scm_command: 命令 + text_scm_command_version: 版本 + text_scm_config: 您可以在 config/configuration.yml 中設定 SCM 命令。請在編輯該檔案之後重新啟動 Redmine 應用程式。 + text_scm_command_not_available: SCM 命令無法使用。請檢查管理面板中的設定。 + + default_role_manager: 管理人員 + default_role_developer: 開發人員 + default_role_reporter: 報告人員 + default_tracker_bug: 臭蟲 + default_tracker_feature: 功能 + default_tracker_support: 支援 + default_issue_status_new: 新建立 + default_issue_status_in_progress: 實作中 + default_issue_status_resolved: 已解決 + default_issue_status_feedback: 已回應 + default_issue_status_closed: 已結束 + default_issue_status_rejected: 已拒絕 + default_doc_category_user: 使用手冊 + default_doc_category_tech: 技術文件 + default_priority_low: 低 + default_priority_normal: 正常 + default_priority_high: 高 + default_priority_urgent: 速 + default_priority_immediate: 急 + default_activity_design: 設計 + default_activity_development: 開發 + + enumeration_issue_priorities: 問題優先權 + enumeration_doc_categories: 文件分類 + enumeration_activities: 活動 (時間追蹤) + enumeration_system_activity: 系統活動 + description_filter: 篩選條件 + description_search: 搜尋欄位 + description_choose_project: 專案清單 + description_project_scope: 搜尋範圍 + description_notes: 筆記 + description_message_content: 訊息內容 + description_query_sort_criteria_attribute: 排序屬性 + description_query_sort_criteria_direction: 排列順序 + description_user_mail_notification: 郵件通知設定 + description_available_columns: 可用欄位 + description_selected_columns: 已選取的欄位 + description_all_columns: 所有欄位 + description_issue_category_reassign: 選擇問題分類 + description_wiki_subpages_reassign: 選擇新的父頁面 + description_date_range_list: 從清單中選取範圍 + description_date_range_interval: 選擇起始與結束日期以設定範圍區間 + description_date_from: 輸入起始日期 + description_date_to: 輸入結束日期 diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f5/f5ada035c7d5ce2734e191045efdfc2d9fd551ae.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f5/f5ada035c7d5ce2734e191045efdfc2d9fd551ae.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,291 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'redmine/scm/adapters/abstract_adapter' +require 'uri' + +module Redmine + module Scm + module Adapters + class SubversionAdapter < AbstractAdapter + + # SVN executable name + SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn" + + class << self + def client_command + @@bin ||= SVN_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (svn_binary_version || []) + end + + def client_available + # --xml options are introduced in 1.3. + # http://subversion.apache.org/docs/release-notes/1.3.html + client_version_above?([1, 3]) + end + + def svn_binary_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + # Get info about the svn repository + def info + cmd = "#{self.class.sq_bin} info --xml #{target}" + cmd << credentials_string + info = nil + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = ActiveSupport::XmlMini.parse(output) + # root_url = doc.elements["info/entry/repository/root"].text + info = Info.new({:root_url => doc['info']['entry']['repository']['root']['__content__'], + :lastrev => Revision.new({ + :identifier => doc['info']['entry']['commit']['revision'], + :time => Time.parse(doc['info']['entry']['commit']['date']['__content__']).localtime, + :author => (doc['info']['entry']['commit']['author'] ? doc['info']['entry']['commit']['author']['__content__'] : "") + }) + }) + rescue + end + end + return nil if $? && $?.exitstatus != 0 + info + rescue CommandFailed + return nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + path ||= '' + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + entries = Entries.new + cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}" + cmd << credentials_string + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = ActiveSupport::XmlMini.parse(output) + each_xml_element(doc['lists']['list'], 'entry') do |entry| + commit = entry['commit'] + commit_date = commit['date'] + # Skip directory if there is no commit date (usually that + # means that we don't have read access to it) + next if entry['kind'] == 'dir' && commit_date.nil? + name = entry['name']['__content__'] + entries << Entry.new({:name => URI.unescape(name), + :path => ((path.empty? ? "" : "#{path}/") + name), + :kind => entry['kind'], + :size => ((s = entry['size']) ? s['__content__'].to_i : nil), + :lastrev => Revision.new({ + :identifier => commit['revision'], + :time => Time.parse(commit_date['__content__'].to_s).localtime, + :author => ((a = commit['author']) ? a['__content__'] : nil) + }) + }) + end + rescue Exception => e + logger.error("Error parsing svn output: #{e.message}") + logger.error("Output was:\n #{output}") + end + end + return nil if $? && $?.exitstatus != 0 + logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug? + entries.sort_by_name + end + + def properties(path, identifier=nil) + # proplist xml output supported in svn 1.5.0 and higher + return nil unless self.class.client_version_above?([1, 5, 0]) + + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "#{self.class.sq_bin} proplist --verbose --xml #{target(path)}@#{identifier}" + cmd << credentials_string + properties = {} + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = ActiveSupport::XmlMini.parse(output) + each_xml_element(doc['properties']['target'], 'property') do |property| + properties[ property['name'] ] = property['__content__'].to_s + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + properties + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path ||= '' + identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD" + identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1 + revisions = Revisions.new + cmd = "#{self.class.sq_bin} log --xml -r #{identifier_from}:#{identifier_to}" + cmd << credentials_string + cmd << " --verbose " if options[:with_paths] + cmd << " --limit #{options[:limit].to_i}" if options[:limit] + cmd << ' ' + target(path) + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = ActiveSupport::XmlMini.parse(output) + each_xml_element(doc['log'], 'logentry') do |logentry| + paths = [] + each_xml_element(logentry['paths'], 'path') do |path| + paths << {:action => path['action'], + :path => path['__content__'], + :from_path => path['copyfrom-path'], + :from_revision => path['copyfrom-rev'] + } + end if logentry['paths'] && logentry['paths']['path'] + paths.sort! { |x,y| x[:path] <=> y[:path] } + + revisions << Revision.new({:identifier => logentry['revision'], + :author => (logentry['author'] ? logentry['author']['__content__'] : ""), + :time => Time.parse(logentry['date']['__content__'].to_s).localtime, + :message => logentry['msg']['__content__'], + :paths => paths + }) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + revisions + end + + def diff(path, identifier_from, identifier_to=nil, type="inline") + path ||= '' + identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : '' + + identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1) + + cmd = "#{self.class.sq_bin} diff -r " + cmd << "#{identifier_to}:" + cmd << "#{identifier_from}" + cmd << " #{target(path)}@#{identifier_from}" + cmd << credentials_string + diff = [] + shellout(cmd) do |io| + io.each_line do |line| + diff << line + end + end + return nil if $? && $?.exitstatus != 0 + diff + end + + def cat(path, identifier=nil) + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "#{self.class.sq_bin} cat #{target(path)}@#{identifier}" + cmd << credentials_string + cat = nil + shellout(cmd) do |io| + io.binmode + cat = io.read + end + return nil if $? && $?.exitstatus != 0 + cat + end + + def annotate(path, identifier=nil) + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "#{self.class.sq_bin} blame #{target(path)}@#{identifier}" + cmd << credentials_string + blame = Annotate.new + shellout(cmd) do |io| + io.each_line do |line| + next unless line =~ %r{^\s*(\d+)\s*(\S+)\s(.*)$} + rev = $1 + blame.add_line($3.rstrip, + Revision.new( + :identifier => rev, + :revision => rev, + :author => $2.strip + )) + end + end + return nil if $? && $?.exitstatus != 0 + blame + end + + private + + def credentials_string + str = '' + str << " --username #{shell_quote(@login)}" unless @login.blank? + str << " --password #{shell_quote(@password)}" unless @login.blank? || @password.blank? + str << " --no-auth-cache --non-interactive" + str + end + + # Helper that iterates over the child elements of a xml node + # MiniXml returns a hash when a single child is found + # or an array of hashes for multiple children + def each_xml_element(node, name) + if node && node[name] + if node[name].is_a?(Hash) + yield node[name] + else + node[name].each do |element| + yield element + end + end + end + end + + def target(path = '') + base = path.match(/^\//) ? root_url : url + uri = "#{base}/#{path}" + uri = URI.escape(URI.escape(uri), '[]') + shell_quote(uri.gsub(/[?<>\*]/, '')) + end + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f6/f62006a748496bdfe8f98a95967ea18642e17172.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f6/f62006a748496bdfe8f98a95967ea18642e17172.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Pazar", + "Pazartesi", + "Salı", + "Çarşamba", + "Perşembe", + "Cuma", + "Cumartesi", + "Pazar"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Paz", + "Pzt", + "Sal", + "Çar", + "Per", + "Cum", + "Cmt", + "Paz"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Ocak", + "Şubat", + "Mart", + "Nisan", + "Mayıs", + "Haziran", + "Temmuz", + "Ağustos", + "Eylül", + "Ekim", + "Kasım", + "Aralık"); + +// short month names +Calendar._SMN = new Array +("Oca", + "Şub", + "Mar", + "Nis", + "May", + "Haz", + "Tem", + "Ağu", + "Eyl", + "Eki", + "Kas", + "Ara"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Takvim hakkında"; + +Calendar._TT["ABOUT"] = +"DHTML Tarih/Zaman Seçici\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Tarih Seçimi:\n" + +"- Yıl seçmek için \xab, \xbb tuşlarını kullanın\n" + +"- Ayı seçmek için " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " tuşlarını kullanın\n" + +"- Hızlı seçim için yukardaki butonların üzerinde farenin tuşuna basılı tutun."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Zaman Seçimi:\n" + +"- Arttırmak için herhangi bir zaman bölümüne tıklayın\n" + +"- ya da azaltmak için Shift+tıkla yapın\n" + +"- ya da daha hızlı bir seçim için tıklayın ve sürükleyin."; + +Calendar._TT["PREV_YEAR"] = "Öncki yıl (Menu için basılı tutun)"; +Calendar._TT["PREV_MONTH"] = "Önceki ay (Menu için basılı tutun)"; +Calendar._TT["GO_TODAY"] = "Bugüne Git"; +Calendar._TT["NEXT_MONTH"] = "Sonraki Ay (Menu için basılı tutun)"; +Calendar._TT["NEXT_YEAR"] = "Next year (Menu için basılı tutun)"; +Calendar._TT["SEL_DATE"] = "Tarih seçin"; +Calendar._TT["DRAG_TO_MOVE"] = "Taşımak için sürükleyin"; +Calendar._TT["PART_TODAY"] = " (bugün)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s : önce göster"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "1,0"; + +Calendar._TT["CLOSE"] = "Kapat"; +Calendar._TT["TODAY"] = "Bugün"; +Calendar._TT["TIME_PART"] = "Değeri değiştirmek için (Shift-)tıkla veya sürükle"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "Hafta"; +Calendar._TT["TIME"] = "Saat:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f6/f6a4adfc427b33de65e5a0e28b7897458d9a2b7f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f6/f6a4adfc427b33de65e5a0e28b7897458d9a2b7f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,287 @@ +TCPDFFontDescriptor.define('dejavusansb') do |font| + font[:type]='TrueTypeUnicode'; + font[:name]='DejaVuSans-Bold'; + font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-1069 -388 1975 1123]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>600}; + font[:up]=-42; + font[:ut]=44; + font[:cw]={ + 0=>600, 32=>348, 33=>456, 34=>521, 35=>838, 36=>696, 37=>1002, 38=>872, 39=>306, 40=>457, 41=>457, 42=>523, 43=>838, 44=>380, 45=>415, 46=>380, + 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>400, 59=>400, 60=>838, 61=>838, 62=>838, + 63=>580, 64=>1000, 65=>774, 66=>762, 67=>734, 68=>830, 69=>683, 70=>683, 71=>821, 72=>837, 73=>372, 74=>372, 75=>775, 76=>637, 77=>995, 78=>837, + 79=>850, 80=>733, 81=>850, 82=>770, 83=>720, 84=>682, 85=>812, 86=>774, 87=>1103, 88=>771, 89=>724, 90=>725, 91=>457, 92=>365, 93=>457, 94=>838, + 95=>500, 96=>500, 97=>675, 98=>716, 99=>593, 100=>716, 101=>678, 102=>435, 103=>716, 104=>712, 105=>343, 106=>343, 107=>665, 108=>343, 109=>1042, 110=>712, + 111=>687, 112=>716, 113=>716, 114=>493, 115=>595, 116=>478, 117=>712, 118=>652, 119=>924, 120=>645, 121=>652, 122=>582, 123=>712, 124=>365, 125=>712, 126=>838, + 8364=>696, 1027=>637, 8218=>380, 402=>435, 8222=>657, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1440, 352=>720, 8249=>412, 338=>1167, 1036=>817, 381=>725, 1039=>837, + 8216=>380, 8217=>380, 8220=>657, 8221=>657, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>595, 8250=>412, 339=>1094, 1116=>679, 382=>582, 376=>724, 160=>348, + 161=>456, 162=>696, 163=>696, 164=>636, 165=>696, 166=>365, 167=>500, 168=>500, 169=>1000, 170=>564, 171=>646, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, + 177=>838, 178=>438, 179=>438, 180=>500, 181=>736, 182=>636, 183=>380, 184=>500, 185=>438, 186=>564, 187=>646, 188=>1035, 189=>1035, 190=>1035, 191=>580, 192=>774, + 193=>774, 194=>774, 195=>774, 196=>774, 197=>774, 198=>1085, 199=>734, 200=>683, 201=>683, 202=>683, 203=>683, 204=>372, 205=>372, 206=>372, 207=>372, 208=>838, + 209=>837, 210=>850, 211=>850, 212=>850, 213=>850, 214=>850, 215=>838, 216=>850, 217=>812, 218=>812, 219=>812, 220=>812, 221=>724, 222=>738, 223=>719, 224=>675, + 225=>675, 226=>675, 227=>675, 228=>675, 229=>675, 230=>1048, 231=>593, 232=>678, 233=>678, 234=>678, 235=>678, 236=>343, 237=>343, 238=>343, 239=>343, 240=>687, + 241=>712, 242=>687, 243=>687, 244=>687, 245=>687, 246=>687, 247=>838, 248=>687, 249=>712, 250=>712, 251=>712, 252=>712, 253=>652, 254=>716, 255=>652, 256=>774, + 257=>675, 258=>774, 259=>675, 260=>774, 261=>675, 262=>734, 263=>593, 264=>734, 265=>593, 266=>734, 267=>593, 268=>734, 269=>593, 270=>830, 271=>716, 272=>838, + 273=>716, 274=>683, 275=>678, 276=>683, 277=>678, 278=>683, 279=>678, 280=>683, 281=>678, 282=>683, 283=>678, 284=>821, 285=>716, 286=>821, 287=>716, 288=>821, + 289=>716, 290=>821, 291=>716, 292=>837, 293=>712, 294=>974, 295=>790, 296=>372, 297=>343, 298=>372, 299=>343, 300=>372, 301=>343, 302=>372, 303=>343, 304=>372, + 305=>343, 306=>744, 307=>686, 308=>372, 309=>343, 310=>775, 311=>665, 312=>665, 313=>637, 314=>343, 315=>637, 316=>343, 317=>637, 318=>479, 319=>637, 320=>557, + 321=>642, 322=>371, 323=>837, 324=>712, 325=>837, 326=>712, 327=>837, 328=>712, 329=>983, 330=>837, 331=>712, 332=>850, 333=>687, 334=>850, 335=>687, 336=>850, + 337=>687, 340=>770, 341=>493, 342=>770, 343=>493, 344=>770, 345=>493, 346=>720, 347=>595, 348=>720, 349=>595, 350=>720, 351=>595, 354=>682, 355=>478, 356=>682, + 357=>478, 358=>682, 359=>478, 360=>812, 361=>712, 362=>812, 363=>712, 364=>812, 365=>712, 366=>812, 367=>712, 368=>812, 369=>712, 370=>812, 371=>712, 372=>1103, + 373=>924, 374=>724, 375=>652, 377=>725, 378=>582, 379=>725, 380=>582, 383=>435, 384=>716, 385=>811, 386=>762, 387=>716, 388=>762, 389=>716, 390=>734, 391=>734, + 392=>593, 393=>838, 394=>879, 395=>757, 396=>716, 397=>688, 398=>683, 399=>849, 400=>696, 401=>683, 403=>821, 404=>793, 405=>1045, 406=>436, 407=>389, 408=>775, + 409=>665, 410=>360, 411=>592, 412=>1042, 413=>837, 414=>712, 415=>850, 416=>874, 417=>687, 418=>1114, 419=>962, 420=>782, 421=>716, 422=>770, 423=>720, 424=>595, + 425=>683, 426=>552, 427=>478, 428=>707, 429=>478, 430=>682, 431=>835, 432=>712, 433=>769, 434=>813, 435=>797, 436=>778, 437=>725, 438=>582, 439=>772, 440=>772, + 441=>641, 442=>582, 443=>696, 444=>772, 445=>641, 446=>573, 447=>716, 448=>372, 449=>659, 450=>544, 451=>372, 452=>1555, 453=>1412, 454=>1298, 455=>1009, 456=>980, + 457=>686, 458=>1209, 459=>1180, 460=>1055, 461=>774, 462=>675, 463=>372, 464=>343, 465=>850, 466=>687, 467=>812, 468=>712, 469=>812, 470=>712, 471=>812, 472=>712, + 473=>812, 474=>712, 475=>812, 476=>712, 477=>678, 478=>774, 479=>675, 480=>774, 481=>675, 482=>1085, 483=>1048, 484=>821, 485=>716, 486=>821, 487=>716, 488=>775, + 489=>665, 490=>850, 491=>687, 492=>850, 493=>687, 494=>772, 495=>582, 496=>343, 497=>1555, 498=>1412, 499=>1298, 500=>821, 501=>716, 502=>1289, 503=>787, 504=>837, + 505=>712, 506=>774, 507=>675, 508=>1085, 509=>1048, 510=>850, 511=>687, 512=>774, 513=>675, 514=>774, 515=>675, 516=>683, 517=>678, 518=>683, 519=>678, 520=>372, + 521=>343, 522=>372, 523=>343, 524=>850, 525=>687, 526=>850, 527=>687, 528=>770, 529=>493, 530=>770, 531=>493, 532=>812, 533=>712, 534=>812, 535=>712, 536=>720, + 537=>595, 538=>682, 539=>478, 540=>690, 541=>607, 542=>837, 543=>712, 544=>837, 545=>865, 546=>809, 547=>659, 548=>725, 549=>582, 550=>774, 551=>675, 552=>683, + 553=>678, 554=>850, 555=>687, 556=>850, 557=>687, 558=>850, 559=>687, 560=>850, 561=>687, 562=>724, 563=>652, 564=>492, 565=>867, 566=>512, 567=>343, 568=>1088, + 569=>1088, 570=>774, 571=>734, 572=>593, 573=>637, 574=>682, 575=>595, 576=>582, 577=>782, 578=>614, 579=>762, 580=>812, 581=>774, 582=>683, 583=>678, 584=>372, + 585=>343, 586=>860, 587=>791, 588=>770, 589=>493, 590=>724, 591=>652, 592=>675, 593=>716, 594=>716, 595=>716, 596=>593, 597=>593, 598=>717, 599=>792, 600=>678, + 601=>678, 602=>876, 603=>557, 604=>545, 605=>815, 606=>731, 607=>343, 608=>792, 609=>716, 610=>627, 611=>735, 612=>635, 613=>712, 614=>712, 615=>712, 616=>545, + 617=>440, 618=>545, 619=>559, 620=>693, 621=>343, 622=>841, 623=>1042, 624=>1042, 625=>1042, 626=>712, 627=>793, 628=>642, 629=>687, 630=>909, 631=>681, 632=>796, + 633=>538, 634=>538, 635=>650, 636=>493, 637=>493, 638=>596, 639=>596, 640=>642, 641=>642, 642=>595, 643=>415, 644=>435, 645=>605, 646=>552, 647=>478, 648=>478, + 649=>920, 650=>769, 651=>670, 652=>652, 653=>924, 654=>652, 655=>724, 656=>694, 657=>684, 658=>641, 659=>641, 660=>573, 661=>573, 662=>573, 663=>573, 664=>850, + 665=>633, 666=>731, 667=>685, 668=>691, 669=>343, 670=>732, 671=>539, 672=>792, 673=>573, 674=>573, 675=>1156, 676=>1214, 677=>1155, 678=>974, 679=>769, 680=>929, + 681=>1026, 682=>792, 683=>780, 684=>591, 685=>415, 686=>677, 687=>789, 688=>456, 689=>456, 690=>219, 691=>315, 692=>315, 693=>315, 694=>411, 695=>591, 696=>417, + 697=>302, 698=>521, 699=>380, 700=>380, 701=>380, 702=>366, 703=>366, 704=>326, 705=>326, 706=>500, 707=>500, 708=>500, 709=>500, 711=>500, 712=>306, 713=>500, + 714=>500, 715=>500, 716=>306, 717=>500, 718=>500, 719=>500, 720=>337, 721=>337, 722=>366, 723=>366, 724=>500, 725=>500, 726=>500, 727=>500, 728=>500, 729=>500, + 730=>500, 731=>500, 733=>500, 734=>351, 735=>500, 736=>412, 737=>219, 738=>381, 739=>413, 740=>326, 741=>500, 742=>500, 743=>500, 744=>500, 745=>500, 748=>500, + 749=>500, 750=>500, 755=>500, 759=>500, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, + 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, + 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, + 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, + 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, + 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 850=>0, 851=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, + 884=>302, 885=>302, 890=>500, 891=>593, 892=>550, 893=>549, 894=>337, 900=>441, 901=>500, 902=>797, 903=>380, 904=>846, 905=>1009, 906=>563, 908=>891, 910=>980, + 911=>894, 912=>390, 913=>774, 914=>762, 915=>637, 916=>774, 917=>683, 918=>725, 919=>837, 920=>850, 921=>372, 922=>775, 923=>774, 924=>995, 925=>837, 926=>632, + 927=>850, 928=>837, 929=>733, 931=>683, 932=>682, 933=>724, 934=>850, 935=>771, 936=>850, 937=>850, 938=>372, 939=>724, 940=>687, 941=>557, 942=>712, 943=>390, + 944=>675, 945=>687, 946=>716, 947=>681, 948=>687, 949=>557, 950=>591, 951=>712, 952=>687, 953=>390, 954=>710, 955=>633, 956=>736, 957=>681, 958=>591, 959=>687, + 960=>791, 961=>716, 962=>593, 963=>779, 964=>638, 965=>675, 966=>782, 967=>645, 968=>794, 969=>869, 970=>390, 971=>675, 972=>687, 973=>675, 974=>869, 976=>651, + 977=>661, 978=>746, 979=>981, 980=>746, 981=>796, 982=>869, 983=>744, 984=>850, 985=>687, 986=>734, 987=>593, 988=>683, 989=>494, 990=>702, 991=>660, 992=>919, + 993=>627, 994=>1093, 995=>837, 996=>832, 997=>716, 998=>928, 999=>744, 1000=>733, 1001=>650, 1002=>789, 1003=>671, 1004=>752, 1005=>716, 1006=>682, 1007=>590, 1008=>744, + 1009=>716, 1010=>593, 1011=>343, 1012=>850, 1013=>645, 1014=>644, 1015=>738, 1016=>716, 1017=>734, 1018=>995, 1019=>732, 1020=>716, 1021=>698, 1022=>734, 1023=>698, 1024=>683, + 1025=>683, 1026=>878, 1028=>734, 1029=>720, 1030=>372, 1031=>372, 1032=>372, 1033=>1154, 1034=>1130, 1035=>878, 1037=>837, 1038=>771, 1040=>774, 1041=>762, 1042=>762, 1043=>637, + 1044=>891, 1045=>683, 1046=>1224, 1047=>710, 1048=>837, 1049=>837, 1050=>817, 1051=>831, 1052=>995, 1053=>837, 1054=>850, 1055=>837, 1056=>733, 1057=>734, 1058=>682, 1059=>771, + 1060=>992, 1061=>771, 1062=>928, 1063=>808, 1064=>1235, 1065=>1326, 1066=>939, 1067=>1036, 1068=>762, 1069=>734, 1070=>1174, 1071=>770, 1072=>675, 1073=>698, 1074=>633, 1075=>522, + 1076=>808, 1077=>678, 1078=>995, 1079=>581, 1080=>701, 1081=>701, 1082=>679, 1083=>732, 1084=>817, 1085=>691, 1086=>687, 1087=>691, 1088=>716, 1089=>593, 1090=>580, 1091=>652, + 1092=>992, 1093=>645, 1094=>741, 1095=>687, 1096=>1062, 1097=>1105, 1098=>751, 1099=>904, 1100=>632, 1101=>593, 1102=>972, 1103=>642, 1104=>678, 1105=>678, 1106=>714, 1107=>522, + 1108=>593, 1109=>595, 1110=>343, 1111=>343, 1112=>343, 1113=>991, 1114=>956, 1115=>734, 1117=>701, 1118=>652, 1119=>691, 1120=>1093, 1121=>869, 1122=>840, 1123=>736, 1124=>1012, + 1125=>839, 1126=>992, 1127=>832, 1128=>1358, 1129=>1121, 1130=>850, 1131=>687, 1132=>1236, 1133=>1007, 1134=>696, 1135=>557, 1136=>1075, 1137=>1061, 1138=>850, 1139=>667, 1140=>850, + 1141=>695, 1142=>850, 1143=>695, 1144=>1148, 1145=>1043, 1146=>1074, 1147=>863, 1148=>1405, 1149=>1173, 1150=>1093, 1151=>869, 1152=>734, 1153=>593, 1154=>652, 1155=>0, 1156=>0, + 1157=>0, 1158=>0, 1160=>418, 1161=>418, 1162=>957, 1163=>807, 1164=>762, 1165=>611, 1166=>733, 1167=>716, 1168=>637, 1169=>522, 1170=>666, 1171=>543, 1172=>808, 1173=>669, + 1174=>1224, 1175=>995, 1176=>710, 1177=>581, 1178=>775, 1179=>679, 1180=>817, 1181=>679, 1182=>817, 1183=>679, 1184=>1015, 1185=>826, 1186=>956, 1187=>808, 1188=>1103, 1189=>874, + 1190=>1273, 1191=>1017, 1192=>875, 1193=>710, 1194=>734, 1195=>593, 1196=>682, 1197=>580, 1198=>724, 1199=>652, 1200=>724, 1201=>652, 1202=>771, 1203=>645, 1204=>1112, 1205=>1000, + 1206=>808, 1207=>687, 1208=>808, 1209=>687, 1210=>808, 1211=>712, 1212=>1026, 1213=>810, 1214=>1026, 1215=>810, 1216=>372, 1217=>1224, 1218=>995, 1219=>775, 1220=>630, 1221=>951, + 1222=>805, 1223=>837, 1224=>691, 1225=>957, 1226=>807, 1227=>808, 1228=>687, 1229=>1115, 1230=>933, 1231=>343, 1232=>774, 1233=>675, 1234=>774, 1235=>675, 1236=>1085, 1237=>1048, + 1238=>683, 1239=>678, 1240=>849, 1241=>678, 1242=>849, 1243=>678, 1244=>1224, 1245=>995, 1246=>710, 1247=>581, 1248=>772, 1249=>641, 1250=>837, 1251=>701, 1252=>837, 1253=>701, + 1254=>850, 1255=>687, 1256=>850, 1257=>687, 1258=>850, 1259=>687, 1260=>734, 1261=>593, 1262=>771, 1263=>652, 1264=>771, 1265=>652, 1266=>771, 1267=>652, 1268=>808, 1269=>687, + 1270=>637, 1271=>522, 1272=>1036, 1273=>904, 1274=>666, 1275=>543, 1276=>771, 1277=>645, 1278=>771, 1279=>645, 1280=>762, 1281=>608, 1282=>1159, 1283=>893, 1284=>1119, 1285=>920, + 1286=>828, 1287=>693, 1288=>1242, 1289=>1017, 1290=>1248, 1291=>1013, 1292=>839, 1293=>638, 1294=>938, 1295=>803, 1296=>696, 1297=>557, 1298=>831, 1299=>732, 1329=>984, 1330=>812, + 1331=>984, 1332=>984, 1333=>812, 1334=>777, 1335=>812, 1336=>812, 1337=>975, 1338=>984, 1339=>812, 1340=>710, 1341=>1078, 1342=>1136, 1343=>812, 1344=>710, 1345=>757, 1346=>984, + 1347=>876, 1348=>984, 1349=>793, 1350=>984, 1351=>812, 1352=>812, 1353=>812, 1354=>958, 1355=>777, 1356=>984, 1357=>812, 1358=>984, 1359=>720, 1360=>812, 1361=>793, 1362=>895, + 1363=>850, 1364=>936, 1365=>850, 1366=>720, 1369=>366, 1370=>380, 1371=>550, 1372=>550, 1373=>380, 1374=>546, 1375=>521, 1377=>1042, 1378=>712, 1379=>866, 1380=>868, 1381=>712, + 1382=>817, 1383=>653, 1384=>712, 1385=>811, 1386=>817, 1387=>712, 1388=>498, 1389=>1018, 1390=>716, 1391=>712, 1392=>712, 1393=>716, 1394=>819, 1395=>712, 1396=>751, 1397=>343, + 1398=>882, 1399=>559, 1400=>712, 1401=>559, 1402=>1042, 1403=>559, 1404=>863, 1405=>712, 1406=>813, 1407=>1042, 1408=>712, 1409=>716, 1410=>571, 1411=>1042, 1412=>778, 1413=>687, + 1414=>720, 1415=>862, 1417=>400, 1418=>487, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, + 1469=>0, 1471=>0, 1472=>372, 1473=>0, 1474=>0, 1475=>372, 1478=>532, 1479=>0, 1488=>751, 1489=>731, 1490=>537, 1491=>684, 1492=>778, 1493=>372, 1494=>521, 1495=>778, + 1496=>770, 1497=>372, 1498=>778, 1499=>750, 1500=>718, 1501=>778, 1502=>856, 1503=>372, 1504=>532, 1505=>855, 1506=>720, 1507=>802, 1508=>777, 1509=>628, 1510=>751, 1511=>803, + 1512=>778, 1513=>963, 1514=>822, 1520=>692, 1521=>692, 1522=>692, 1548=>380, 1557=>0, 1563=>400, 1567=>580, 1569=>511, 1570=>343, 1571=>343, 1572=>622, 1573=>343, 1574=>917, + 1575=>343, 1576=>1005, 1577=>590, 1578=>1005, 1579=>1005, 1580=>721, 1581=>721, 1582=>721, 1583=>513, 1584=>513, 1585=>576, 1586=>576, 1587=>1380, 1588=>1380, 1589=>1345, 1590=>1345, + 1591=>1039, 1592=>1039, 1593=>683, 1594=>683, 1600=>342, 1601=>1162, 1602=>894, 1603=>917, 1604=>868, 1605=>733, 1606=>854, 1607=>590, 1608=>622, 1609=>917, 1610=>917, 1611=>0, + 1612=>0, 1613=>0, 1614=>0, 1615=>0, 1616=>0, 1617=>0, 1618=>0, 1619=>0, 1620=>0, 1621=>0, 1626=>500, 1632=>610, 1633=>610, 1634=>610, 1635=>610, 1636=>610, + 1637=>610, 1638=>610, 1639=>610, 1640=>610, 1641=>610, 1642=>610, 1643=>374, 1644=>380, 1645=>545, 1646=>1005, 1647=>894, 1652=>292, 1657=>1005, 1658=>1005, 1659=>1005, 1660=>1005, + 1661=>1005, 1662=>1005, 1663=>1005, 1664=>1005, 1665=>721, 1666=>721, 1667=>721, 1668=>721, 1669=>721, 1670=>721, 1671=>721, 1681=>576, 1682=>576, 1685=>681, 1688=>576, 1697=>1162, + 1700=>1162, 1702=>1162, 1705=>1024, 1711=>1024, 1717=>868, 1722=>854, 1727=>721, 1734=>622, 1740=>917, 1742=>917, 1749=>590, 1776=>610, 1777=>610, 1778=>610, 1779=>610, 1780=>610, + 1781=>610, 1782=>610, 1783=>610, 1784=>610, 1785=>610, 3647=>743, 3713=>790, 3714=>748, 3716=>749, 3719=>569, 3720=>742, 3722=>744, 3725=>761, 3732=>706, 3733=>704, 3734=>747, + 3735=>819, 3737=>730, 3738=>727, 3739=>727, 3740=>922, 3741=>827, 3742=>866, 3743=>866, 3745=>836, 3746=>761, 3747=>770, 3749=>769, 3751=>713, 3754=>827, 3755=>1031, 3757=>724, + 3758=>784, 3759=>934, 3760=>688, 3761=>0, 3762=>610, 3763=>610, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>670, 3776=>516, + 3777=>860, 3778=>516, 3779=>650, 3780=>632, 3782=>759, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>1363, 3805=>1363, 5121=>774, 5122=>774, 5123=>774, + 5124=>774, 5125=>905, 5126=>905, 5127=>905, 5129=>905, 5130=>905, 5131=>905, 5132=>1018, 5133=>1009, 5134=>1018, 5135=>1009, 5136=>1018, 5137=>1009, 5138=>1149, 5139=>1140, 5140=>1149, + 5141=>1140, 5142=>905, 5143=>1149, 5144=>1142, 5145=>1149, 5146=>1142, 5147=>905, 5149=>310, 5150=>529, 5151=>425, 5152=>425, 5153=>395, 5154=>395, 5155=>395, 5156=>395, 5157=>564, + 5158=>470, 5159=>310, 5160=>395, 5161=>395, 5162=>395, 5163=>1213, 5164=>986, 5165=>1216, 5166=>1297, 5167=>774, 5168=>774, 5169=>774, 5170=>774, 5171=>886, 5172=>886, 5173=>886, + 5175=>886, 5176=>886, 5177=>886, 5178=>1018, 5179=>1009, 5180=>1018, 5181=>1009, 5182=>1018, 5183=>1009, 5184=>1149, 5185=>1140, 5186=>1149, 5187=>1140, 5188=>1149, 5189=>1142, 5190=>1149, + 5191=>1142, 5192=>886, 5193=>576, 5194=>229, 5196=>812, 5197=>812, 5198=>812, 5199=>812, 5200=>815, 5201=>815, 5202=>815, 5204=>815, 5205=>815, 5206=>815, 5207=>1056, 5208=>1048, + 5209=>1056, 5210=>1048, 5211=>1056, 5212=>1048, 5213=>1060, 5214=>1054, 5215=>1060, 5216=>1054, 5217=>1060, 5218=>1052, 5219=>1060, 5220=>1052, 5221=>1060, 5222=>483, 5223=>1005, 5224=>1005, + 5225=>1023, 5226=>1017, 5227=>743, 5228=>743, 5229=>743, 5230=>743, 5231=>743, 5232=>755, 5233=>743, 5234=>743, 5235=>743, 5236=>1029, 5237=>975, 5238=>980, 5239=>975, 5240=>980, + 5241=>975, 5242=>1029, 5243=>975, 5244=>1029, 5245=>975, 5246=>980, 5247=>975, 5248=>980, 5249=>975, 5250=>980, 5251=>501, 5252=>501, 5253=>938, 5254=>938, 5255=>938, 5256=>938, + 5257=>743, 5258=>743, 5259=>743, 5260=>743, 5261=>743, 5262=>755, 5263=>743, 5264=>743, 5265=>743, 5266=>1029, 5267=>975, 5268=>1029, 5269=>975, 5270=>1029, 5271=>975, 5272=>1029, + 5273=>975, 5274=>1029, 5275=>975, 5276=>1029, 5277=>975, 5278=>1029, 5279=>975, 5280=>1029, 5281=>501, 5282=>501, 5283=>626, 5284=>626, 5285=>626, 5286=>626, 5287=>626, 5288=>667, + 5289=>626, 5290=>626, 5291=>626, 5292=>881, 5293=>854, 5294=>863, 5295=>874, 5296=>863, 5297=>874, 5298=>881, 5299=>874, 5300=>881, 5301=>874, 5302=>863, 5303=>874, 5304=>863, + 5305=>874, 5306=>863, 5307=>436, 5308=>548, 5309=>436, 5312=>988, 5313=>988, 5314=>988, 5315=>988, 5316=>931, 5317=>931, 5318=>931, 5319=>931, 5320=>931, 5321=>1238, 5322=>1247, + 5323=>1200, 5324=>1228, 5325=>1200, 5326=>1228, 5327=>931, 5328=>660, 5329=>497, 5330=>660, 5331=>988, 5332=>988, 5333=>988, 5334=>988, 5335=>931, 5336=>931, 5337=>931, 5338=>931, + 5339=>931, 5340=>1231, 5341=>1247, 5342=>1283, 5343=>1228, 5344=>1283, 5345=>1228, 5346=>1228, 5347=>1214, 5348=>1228, 5349=>1214, 5350=>1283, 5351=>1228, 5352=>1283, 5353=>1228, 5354=>660, + 5356=>886, 5357=>730, 5358=>730, 5359=>730, 5360=>730, 5361=>730, 5362=>755, 5363=>730, 5364=>730, 5365=>730, 5366=>998, 5367=>958, 5368=>967, 5369=>989, 5370=>967, 5371=>989, + 5372=>998, 5373=>958, 5374=>998, 5375=>958, 5376=>967, 5377=>989, 5378=>967, 5379=>989, 5380=>967, 5381=>493, 5382=>460, 5383=>493, 5392=>923, 5393=>923, 5394=>923, 5395=>1136, + 5396=>1136, 5397=>1136, 5398=>1136, 5399=>1209, 5400=>1202, 5401=>1209, 5402=>1202, 5403=>1209, 5404=>1202, 5405=>1431, 5406=>1420, 5407=>1431, 5408=>1420, 5409=>1431, 5410=>1420, 5411=>1431, + 5412=>1420, 5413=>746, 5414=>776, 5415=>776, 5416=>776, 5417=>776, 5418=>776, 5419=>776, 5420=>776, 5421=>776, 5422=>776, 5423=>1003, 5424=>1003, 5425=>1013, 5426=>996, 5427=>1013, + 5428=>996, 5429=>1003, 5430=>1003, 5431=>1003, 5432=>1003, 5433=>1013, 5434=>996, 5435=>1013, 5436=>996, 5437=>1013, 5438=>495, 5440=>395, 5441=>510, 5442=>1033, 5443=>1033, 5444=>976, + 5445=>976, 5446=>976, 5447=>976, 5448=>733, 5449=>733, 5450=>733, 5451=>733, 5452=>733, 5453=>733, 5454=>1003, 5455=>959, 5456=>495, 5458=>886, 5459=>774, 5460=>774, 5461=>774, + 5462=>774, 5463=>928, 5464=>928, 5465=>928, 5466=>928, 5467=>1172, 5468=>1142, 5469=>602, 5470=>812, 5471=>812, 5472=>812, 5473=>812, 5474=>812, 5475=>812, 5476=>815, 5477=>815, + 5478=>815, 5479=>815, 5480=>1060, 5481=>1052, 5482=>548, 5492=>977, 5493=>977, 5494=>977, 5495=>977, 5496=>977, 5497=>977, 5498=>977, 5499=>618, 5500=>837, 5501=>510, 5502=>1238, + 5503=>1238, 5504=>1238, 5505=>1238, 5506=>1238, 5507=>1238, 5508=>1238, 5509=>989, 5514=>977, 5515=>977, 5516=>977, 5517=>977, 5518=>1591, 5519=>1591, 5520=>1591, 5521=>1295, 5522=>1295, + 5523=>1591, 5524=>1591, 5525=>848, 5526=>1273, 5536=>988, 5537=>988, 5538=>931, 5539=>931, 5540=>931, 5541=>931, 5542=>660, 5543=>776, 5544=>776, 5545=>776, 5546=>776, 5547=>776, + 5548=>776, 5549=>776, 5550=>495, 5551=>743, 5598=>830, 5601=>830, 5702=>496, 5703=>496, 5742=>413, 5743=>1238, 5744=>1591, 5745=>2016, 5746=>2016, 5747=>1720, 5748=>1678, 5749=>2016, + 5750=>2016, 7424=>652, 7425=>833, 7426=>1048, 7427=>608, 7428=>593, 7429=>676, 7430=>676, 7431=>559, 7432=>557, 7433=>343, 7434=>494, 7435=>665, 7436=>539, 7437=>817, 7438=>701, + 7439=>687, 7440=>593, 7441=>660, 7442=>660, 7443=>660, 7444=>1094, 7446=>687, 7447=>687, 7448=>556, 7449=>642, 7450=>642, 7451=>580, 7452=>634, 7453=>737, 7454=>948, 7455=>695, + 7456=>652, 7457=>924, 7458=>582, 7459=>646, 7462=>539, 7463=>652, 7464=>691, 7465=>556, 7466=>781, 7467=>732, 7468=>487, 7469=>683, 7470=>480, 7472=>523, 7473=>430, 7474=>430, + 7475=>517, 7476=>527, 7477=>234, 7478=>234, 7479=>488, 7480=>401, 7481=>626, 7482=>527, 7483=>527, 7484=>535, 7485=>509, 7486=>461, 7487=>485, 7488=>430, 7489=>511, 7490=>695, + 7491=>458, 7492=>458, 7493=>479, 7494=>712, 7495=>479, 7496=>479, 7497=>479, 7498=>479, 7499=>386, 7500=>386, 7501=>479, 7502=>219, 7503=>487, 7504=>664, 7505=>456, 7506=>488, + 7507=>414, 7508=>488, 7509=>488, 7510=>479, 7511=>388, 7512=>456, 7513=>462, 7514=>664, 7515=>501, 7517=>451, 7518=>429, 7519=>433, 7520=>493, 7521=>406, 7522=>219, 7523=>315, + 7524=>456, 7525=>501, 7526=>451, 7527=>429, 7528=>433, 7529=>493, 7530=>406, 7543=>716, 7544=>527, 7547=>545, 7557=>514, 7579=>479, 7580=>414, 7581=>414, 7582=>488, 7583=>386, + 7584=>377, 7585=>348, 7586=>479, 7587=>456, 7588=>347, 7589=>281, 7590=>347, 7591=>347, 7592=>431, 7593=>326, 7594=>330, 7595=>370, 7596=>664, 7597=>664, 7598=>562, 7599=>562, + 7600=>448, 7601=>488, 7602=>542, 7603=>422, 7604=>396, 7605=>388, 7606=>583, 7607=>494, 7608=>399, 7609=>451, 7610=>501, 7611=>417, 7612=>523, 7613=>470, 7614=>455, 7615=>425, + 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>774, 7681=>675, 7682=>762, 7683=>716, 7684=>762, 7685=>716, 7686=>762, 7687=>716, 7688=>734, 7689=>593, + 7690=>830, 7691=>716, 7692=>830, 7693=>716, 7694=>830, 7695=>716, 7696=>830, 7697=>716, 7698=>830, 7699=>716, 7700=>683, 7701=>678, 7702=>683, 7703=>678, 7704=>683, 7705=>678, + 7706=>683, 7707=>678, 7708=>683, 7709=>678, 7710=>683, 7711=>435, 7712=>821, 7713=>716, 7714=>837, 7715=>712, 7716=>837, 7717=>712, 7718=>837, 7719=>712, 7720=>837, 7721=>712, + 7722=>837, 7723=>712, 7724=>372, 7725=>343, 7726=>372, 7727=>343, 7728=>775, 7729=>665, 7730=>775, 7731=>665, 7732=>775, 7733=>665, 7734=>637, 7735=>343, 7736=>637, 7737=>343, + 7738=>637, 7739=>343, 7740=>637, 7741=>343, 7742=>995, 7743=>1042, 7744=>995, 7745=>1042, 7746=>995, 7747=>1042, 7748=>837, 7749=>712, 7750=>837, 7751=>712, 7752=>837, 7753=>712, + 7754=>837, 7755=>712, 7756=>850, 7757=>687, 7758=>850, 7759=>687, 7760=>850, 7761=>687, 7762=>850, 7763=>687, 7764=>733, 7765=>716, 7766=>733, 7767=>716, 7768=>770, 7769=>493, + 7770=>770, 7771=>493, 7772=>770, 7773=>493, 7774=>770, 7775=>493, 7776=>720, 7777=>595, 7778=>720, 7779=>595, 7780=>720, 7781=>595, 7782=>720, 7783=>595, 7784=>720, 7785=>595, + 7786=>682, 7787=>478, 7788=>682, 7789=>478, 7790=>682, 7791=>478, 7792=>682, 7793=>478, 7794=>812, 7795=>712, 7796=>812, 7797=>712, 7798=>812, 7799=>712, 7800=>812, 7801=>712, + 7802=>812, 7803=>712, 7804=>774, 7805=>652, 7806=>774, 7807=>652, 7808=>1103, 7809=>924, 7810=>1103, 7811=>924, 7812=>1103, 7813=>924, 7814=>1103, 7815=>924, 7816=>1103, 7817=>924, + 7818=>771, 7819=>645, 7820=>771, 7821=>645, 7822=>724, 7823=>652, 7824=>725, 7825=>582, 7826=>725, 7827=>582, 7828=>725, 7829=>582, 7830=>712, 7831=>478, 7832=>924, 7833=>652, + 7834=>675, 7835=>435, 7840=>774, 7841=>675, 7842=>774, 7843=>675, 7844=>774, 7845=>675, 7846=>774, 7847=>675, 7848=>774, 7849=>675, 7850=>774, 7851=>675, 7852=>774, 7853=>675, + 7854=>774, 7855=>675, 7856=>774, 7857=>675, 7858=>774, 7859=>675, 7860=>774, 7861=>675, 7862=>774, 7863=>675, 7864=>683, 7865=>678, 7866=>683, 7867=>678, 7868=>683, 7869=>678, + 7870=>683, 7871=>678, 7872=>683, 7873=>678, 7874=>683, 7875=>678, 7876=>683, 7877=>678, 7878=>683, 7879=>678, 7880=>372, 7881=>343, 7882=>372, 7883=>343, 7884=>850, 7885=>687, + 7886=>850, 7887=>687, 7888=>850, 7889=>687, 7890=>850, 7891=>687, 7892=>850, 7893=>687, 7894=>850, 7895=>687, 7896=>850, 7897=>687, 7898=>874, 7899=>687, 7900=>874, 7901=>687, + 7902=>874, 7903=>687, 7904=>874, 7905=>687, 7906=>874, 7907=>687, 7908=>812, 7909=>712, 7910=>812, 7911=>712, 7912=>835, 7913=>712, 7914=>835, 7915=>712, 7916=>835, 7917=>712, + 7918=>835, 7919=>712, 7920=>835, 7921=>712, 7922=>724, 7923=>652, 7924=>724, 7925=>652, 7926=>724, 7927=>652, 7928=>724, 7929=>652, 7936=>687, 7937=>687, 7938=>687, 7939=>687, + 7940=>687, 7941=>687, 7942=>687, 7943=>687, 7944=>774, 7945=>774, 7946=>1041, 7947=>1043, 7948=>935, 7949=>963, 7950=>835, 7951=>859, 7952=>557, 7953=>557, 7954=>557, 7955=>557, + 7956=>557, 7957=>557, 7960=>792, 7961=>794, 7962=>1100, 7963=>1096, 7964=>1023, 7965=>1052, 7968=>712, 7969=>712, 7970=>712, 7971=>712, 7972=>712, 7973=>712, 7974=>712, 7975=>712, + 7976=>945, 7977=>951, 7978=>1250, 7979=>1250, 7980=>1180, 7981=>1206, 7982=>1054, 7983=>1063, 7984=>390, 7985=>390, 7986=>390, 7987=>390, 7988=>390, 7989=>390, 7990=>390, 7991=>390, + 7992=>483, 7993=>489, 7994=>777, 7995=>785, 7996=>712, 7997=>738, 7998=>604, 7999=>604, 8000=>687, 8001=>687, 8002=>687, 8003=>687, 8004=>687, 8005=>687, 8008=>892, 8009=>933, + 8010=>1221, 8011=>1224, 8012=>1053, 8013=>1082, 8016=>675, 8017=>675, 8018=>675, 8019=>675, 8020=>675, 8021=>675, 8022=>675, 8023=>675, 8025=>930, 8027=>1184, 8029=>1199, 8031=>1049, + 8032=>869, 8033=>869, 8034=>869, 8035=>869, 8036=>869, 8037=>869, 8038=>869, 8039=>869, 8040=>909, 8041=>958, 8042=>1246, 8043=>1251, 8044=>1076, 8045=>1105, 8046=>1028, 8047=>1076, + 8048=>687, 8049=>687, 8050=>557, 8051=>557, 8052=>712, 8053=>712, 8054=>390, 8055=>390, 8056=>687, 8057=>687, 8058=>675, 8059=>675, 8060=>869, 8061=>869, 8064=>687, 8065=>687, + 8066=>687, 8067=>687, 8068=>687, 8069=>687, 8070=>687, 8071=>687, 8072=>774, 8073=>774, 8074=>1041, 8075=>1043, 8076=>935, 8077=>963, 8078=>835, 8079=>859, 8080=>712, 8081=>712, + 8082=>712, 8083=>712, 8084=>712, 8085=>712, 8086=>712, 8087=>712, 8088=>945, 8089=>951, 8090=>1250, 8091=>1250, 8092=>1180, 8093=>1206, 8094=>1054, 8095=>1063, 8096=>869, 8097=>869, + 8098=>869, 8099=>869, 8100=>869, 8101=>869, 8102=>869, 8103=>869, 8104=>909, 8105=>958, 8106=>1246, 8107=>1251, 8108=>1076, 8109=>1105, 8110=>1028, 8111=>1076, 8112=>687, 8113=>687, + 8114=>687, 8115=>687, 8116=>687, 8118=>687, 8119=>687, 8120=>774, 8121=>774, 8122=>876, 8123=>797, 8124=>774, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>712, + 8131=>712, 8132=>712, 8134=>712, 8135=>712, 8136=>929, 8137=>846, 8138=>1080, 8139=>1009, 8140=>837, 8141=>500, 8142=>500, 8143=>500, 8144=>390, 8145=>390, 8146=>390, 8147=>390, + 8150=>390, 8151=>390, 8152=>372, 8153=>372, 8154=>621, 8155=>563, 8157=>500, 8158=>500, 8159=>500, 8160=>675, 8161=>675, 8162=>675, 8163=>675, 8164=>716, 8165=>716, 8166=>675, + 8167=>675, 8168=>724, 8169=>724, 8170=>1020, 8171=>980, 8172=>838, 8173=>500, 8174=>500, 8175=>500, 8178=>869, 8179=>869, 8180=>869, 8182=>869, 8183=>869, 8184=>1065, 8185=>891, + 8186=>1084, 8187=>894, 8188=>850, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, 8196=>330, 8197=>250, 8198=>167, 8199=>696, 8200=>380, 8201=>200, 8202=>100, + 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>415, 8209=>415, 8210=>696, 8213=>1000, 8214=>500, 8215=>500, 8219=>380, 8223=>657, 8227=>639, 8228=>333, 8229=>667, + 8231=>348, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1887, 8242=>264, 8243=>447, 8244=>630, 8245=>264, 8246=>447, 8247=>630, 8248=>733, 8251=>972, + 8252=>627, 8253=>580, 8254=>500, 8255=>828, 8256=>828, 8257=>329, 8258=>1023, 8259=>500, 8260=>456, 8261=>457, 8262=>457, 8263=>1030, 8264=>829, 8265=>829, 8266=>513, 8267=>636, + 8268=>500, 8269=>500, 8270=>523, 8271=>400, 8272=>828, 8273=>523, 8274=>556, 8275=>838, 8276=>828, 8277=>838, 8278=>684, 8279=>813, 8280=>838, 8281=>838, 8282=>380, 8283=>872, + 8284=>838, 8285=>380, 8286=>380, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>438, 8305=>219, + 8308=>438, 8309=>438, 8310=>438, 8311=>438, 8312=>438, 8313=>438, 8314=>528, 8315=>528, 8316=>528, 8317=>288, 8318=>288, 8319=>456, 8320=>438, 8321=>438, 8322=>438, 8323=>438, + 8324=>438, 8325=>438, 8326=>438, 8327=>438, 8328=>438, 8329=>438, 8330=>528, 8331=>528, 8332=>528, 8333=>288, 8334=>288, 8336=>458, 8337=>479, 8338=>488, 8339=>413, 8340=>479, + 8352=>929, 8353=>696, 8354=>696, 8355=>696, 8356=>696, 8357=>1042, 8358=>837, 8359=>1518, 8360=>1205, 8361=>1103, 8362=>904, 8363=>696, 8365=>696, 8366=>682, 8367=>1392, 8368=>696, + 8369=>696, 8370=>696, 8371=>696, 8372=>859, 8373=>696, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>1120, 8449=>1170, 8450=>734, 8451=>1211, 8452=>896, 8453=>1091, 8454=>1144, + 8455=>614, 8456=>698, 8457=>1086, 8459=>1073, 8460=>913, 8461=>850, 8462=>712, 8463=>712, 8464=>604, 8465=>694, 8466=>868, 8467=>472, 8468=>974, 8469=>837, 8470=>1203, 8471=>1000, + 8472=>697, 8473=>702, 8474=>850, 8475=>876, 8476=>814, 8477=>792, 8478=>896, 8479=>710, 8480=>1020, 8481=>1281, 8483=>755, 8484=>725, 8485=>578, 8486=>850, 8487=>769, 8488=>763, + 8489=>338, 8490=>775, 8491=>774, 8492=>928, 8493=>776, 8494=>854, 8495=>636, 8496=>738, 8497=>811, 8498=>683, 8499=>1193, 8500=>465, 8501=>794, 8502=>736, 8503=>503, 8504=>695, + 8505=>380, 8506=>945, 8507=>1348, 8508=>790, 8509=>737, 8510=>652, 8511=>845, 8512=>840, 8513=>775, 8514=>557, 8515=>637, 8516=>760, 8517=>830, 8518=>716, 8519=>678, 8520=>343, + 8521=>343, 8523=>872, 8526=>547, 8531=>1035, 8532=>1035, 8533=>1035, 8534=>1035, 8535=>1035, 8536=>1035, 8537=>1035, 8538=>1035, 8539=>1035, 8540=>1035, 8541=>1035, 8542=>1035, 8543=>615, + 8544=>372, 8545=>659, 8546=>945, 8547=>1099, 8548=>774, 8549=>1099, 8550=>1386, 8551=>1672, 8552=>1121, 8553=>771, 8554=>1120, 8555=>1407, 8556=>637, 8557=>734, 8558=>830, 8559=>995, + 8560=>343, 8561=>607, 8562=>872, 8563=>984, 8564=>652, 8565=>962, 8566=>1227, 8567=>1491, 8568=>969, 8569=>645, 8570=>969, 8571=>1233, 8572=>343, 8573=>593, 8574=>716, 8575=>1042, + 8576=>1289, 8577=>830, 8578=>1289, 8579=>734, 8580=>593, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8596=>838, 8597=>838, 8598=>838, 8599=>838, 8600=>838, 8601=>838, 8602=>838, + 8603=>838, 8604=>838, 8605=>838, 8606=>838, 8607=>838, 8608=>838, 8609=>838, 8610=>838, 8611=>838, 8612=>838, 8613=>838, 8614=>838, 8615=>838, 8616=>838, 8617=>838, 8618=>838, + 8619=>838, 8620=>838, 8621=>838, 8622=>838, 8623=>838, 8624=>838, 8625=>838, 8626=>838, 8627=>838, 8628=>838, 8629=>838, 8630=>838, 8631=>838, 8632=>838, 8633=>838, 8634=>838, + 8635=>838, 8636=>838, 8637=>838, 8638=>838, 8639=>838, 8640=>838, 8641=>838, 8642=>838, 8643=>838, 8644=>838, 8645=>838, 8646=>838, 8647=>838, 8648=>838, 8649=>838, 8650=>838, + 8651=>838, 8652=>838, 8653=>838, 8654=>838, 8655=>838, 8656=>838, 8657=>838, 8658=>838, 8659=>838, 8660=>838, 8661=>838, 8662=>838, 8663=>838, 8664=>838, 8665=>838, 8666=>838, + 8667=>838, 8668=>838, 8669=>838, 8670=>838, 8671=>838, 8672=>838, 8673=>838, 8674=>838, 8675=>838, 8676=>838, 8677=>838, 8678=>838, 8679=>838, 8680=>838, 8681=>838, 8682=>838, + 8683=>838, 8684=>838, 8685=>838, 8686=>838, 8687=>838, 8688=>838, 8689=>838, 8690=>838, 8691=>838, 8692=>838, 8693=>838, 8694=>838, 8695=>838, 8696=>838, 8697=>838, 8698=>838, + 8699=>838, 8700=>838, 8701=>838, 8702=>838, 8703=>838, 8704=>774, 8705=>696, 8706=>544, 8707=>683, 8708=>683, 8709=>856, 8710=>697, 8711=>697, 8712=>896, 8713=>896, 8714=>750, + 8715=>896, 8716=>896, 8717=>750, 8718=>636, 8719=>787, 8720=>787, 8721=>718, 8722=>838, 8723=>838, 8724=>696, 8725=>167, 8726=>696, 8727=>838, 8728=>626, 8729=>380, 8730=>667, + 8731=>667, 8732=>667, 8733=>669, 8734=>833, 8735=>838, 8736=>896, 8737=>896, 8738=>838, 8739=>500, 8740=>500, 8741=>500, 8742=>500, 8743=>812, 8744=>812, 8745=>812, 8746=>812, + 8747=>610, 8748=>929, 8749=>1295, 8750=>563, 8751=>977, 8752=>1313, 8753=>563, 8754=>563, 8755=>563, 8756=>696, 8757=>696, 8758=>294, 8759=>696, 8760=>838, 8761=>838, 8762=>838, + 8763=>838, 8764=>838, 8765=>838, 8766=>838, 8767=>838, 8768=>375, 8769=>838, 8770=>838, 8771=>838, 8772=>838, 8773=>838, 8774=>838, 8775=>838, 8776=>838, 8777=>838, 8778=>838, + 8779=>838, 8780=>838, 8781=>838, 8782=>838, 8783=>838, 8784=>838, 8785=>838, 8786=>838, 8787=>838, 8788=>1063, 8789=>1063, 8790=>838, 8791=>838, 8792=>838, 8793=>838, 8794=>838, + 8795=>838, 8796=>838, 8797=>838, 8798=>838, 8799=>838, 8800=>838, 8801=>838, 8802=>838, 8803=>838, 8804=>838, 8805=>838, 8806=>838, 8807=>838, 8808=>841, 8809=>841, 8810=>1047, + 8811=>1047, 8812=>500, 8813=>838, 8814=>838, 8815=>838, 8816=>838, 8817=>838, 8818=>838, 8819=>838, 8820=>838, 8821=>838, 8822=>838, 8823=>838, 8824=>838, 8825=>838, 8826=>838, + 8827=>838, 8828=>838, 8829=>838, 8830=>838, 8831=>838, 8832=>838, 8833=>838, 8834=>838, 8835=>838, 8836=>838, 8837=>838, 8838=>838, 8839=>838, 8840=>838, 8841=>838, 8842=>838, + 8843=>838, 8844=>812, 8845=>812, 8846=>812, 8847=>838, 8848=>838, 8849=>838, 8850=>838, 8851=>754, 8852=>754, 8853=>838, 8854=>838, 8855=>838, 8856=>838, 8857=>838, 8858=>838, + 8859=>838, 8860=>838, 8861=>838, 8862=>838, 8863=>838, 8864=>838, 8865=>838, 8866=>914, 8867=>914, 8868=>914, 8869=>914, 8870=>542, 8871=>542, 8872=>914, 8873=>914, 8874=>914, + 8875=>914, 8876=>914, 8877=>914, 8878=>914, 8879=>914, 8882=>838, 8883=>838, 8884=>838, 8885=>838, 8886=>1000, 8887=>1000, 8888=>838, 8889=>838, 8890=>542, 8891=>812, 8892=>812, + 8893=>812, 8896=>843, 8897=>843, 8898=>843, 8899=>843, 8900=>494, 8901=>380, 8902=>626, 8904=>1000, 8905=>1000, 8906=>1000, 8907=>1000, 8908=>1000, 8909=>838, 8918=>838, 8919=>838, + 8920=>1422, 8921=>1422, 8922=>838, 8923=>838, 8924=>838, 8925=>838, 8926=>838, 8927=>838, 8928=>838, 8929=>838, 8930=>838, 8931=>838, 8932=>838, 8933=>838, 8934=>838, 8935=>838, + 8936=>838, 8937=>838, 8938=>838, 8939=>838, 8940=>838, 8941=>838, 8946=>1158, 8947=>896, 8948=>750, 8949=>896, 8950=>896, 8951=>750, 8952=>896, 8953=>896, 8954=>1158, 8955=>896, + 8956=>750, 8957=>896, 8958=>750, 8959=>896, 8962=>716, 8966=>917, 8968=>457, 8969=>457, 8970=>457, 8971=>457, 8976=>838, 8977=>539, 8984=>928, 8985=>838, 8992=>610, 8993=>610, + 8997=>1000, 9000=>1443, 9085=>863, 9115=>500, 9116=>500, 9117=>500, 9118=>500, 9119=>500, 9120=>500, 9121=>500, 9122=>500, 9123=>500, 9124=>500, 9125=>500, 9126=>500, 9127=>750, + 9128=>750, 9129=>750, 9130=>750, 9131=>750, 9132=>750, 9133=>750, 9134=>610, 9166=>838, 9167=>945, 9250=>716, 9251=>716, 9312=>847, 9313=>847, 9314=>847, 9315=>847, 9316=>847, + 9317=>847, 9318=>847, 9319=>847, 9320=>847, 9321=>847, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, 9609=>769, 9610=>769, + 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, 9625=>769, 9626=>769, + 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, 9641=>945, 9642=>678, + 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, 9657=>502, 9658=>769, + 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, 9673=>873, 9674=>494, + 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>840, 9689=>970, 9690=>970, + 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>769, 9697=>769, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>639, 9703=>945, 9704=>945, 9705=>945, 9706=>945, + 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, 9721=>769, 9722=>769, + 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9729=>1000, 9730=>896, 9731=>896, 9732=>896, 9733=>896, 9734=>896, 9735=>573, 9736=>896, 9737=>896, 9738=>888, + 9739=>888, 9740=>671, 9741=>1013, 9742=>1246, 9743=>1250, 9744=>896, 9745=>896, 9746=>896, 9747=>532, 9748=>896, 9749=>896, 9750=>896, 9751=>896, 9752=>896, 9753=>896, 9754=>896, + 9755=>896, 9756=>896, 9757=>609, 9758=>896, 9759=>609, 9760=>896, 9761=>896, 9762=>896, 9763=>896, 9764=>669, 9765=>746, 9766=>649, 9767=>784, 9768=>545, 9769=>896, 9770=>896, + 9771=>896, 9772=>710, 9773=>896, 9774=>896, 9775=>896, 9776=>896, 9777=>896, 9778=>896, 9779=>896, 9780=>896, 9781=>896, 9782=>896, 9783=>896, 9784=>896, 9785=>896, 9786=>896, + 9787=>896, 9788=>896, 9789=>896, 9790=>896, 9791=>614, 9792=>731, 9793=>731, 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9800=>896, 9801=>896, 9802=>896, + 9803=>896, 9804=>896, 9805=>896, 9806=>896, 9807=>896, 9808=>896, 9809=>896, 9810=>896, 9811=>896, 9812=>896, 9813=>896, 9814=>896, 9815=>896, 9816=>896, 9817=>896, 9818=>896, + 9819=>896, 9820=>896, 9821=>896, 9822=>896, 9823=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9832=>896, 9833=>472, 9834=>638, + 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 9840=>748, 9841=>766, 9842=>896, 9843=>896, 9844=>896, 9845=>896, 9846=>896, 9847=>896, 9848=>896, 9849=>896, 9850=>896, + 9851=>896, 9852=>896, 9853=>896, 9854=>896, 9855=>896, 9856=>869, 9857=>869, 9858=>869, 9859=>869, 9860=>869, 9861=>869, 9862=>896, 9863=>896, 9864=>896, 9865=>896, 9866=>896, + 9867=>896, 9868=>896, 9869=>896, 9870=>896, 9871=>896, 9872=>896, 9873=>896, 9874=>896, 9875=>896, 9876=>896, 9877=>541, 9878=>896, 9879=>896, 9880=>896, 9881=>896, 9882=>896, + 9883=>896, 9884=>896, 9888=>896, 9889=>702, 9890=>838, 9891=>838, 9892=>838, 9893=>838, 9894=>838, 9895=>838, 9896=>838, 9897=>838, 9898=>838, 9899=>838, 9900=>838, 9901=>838, + 9902=>838, 9903=>838, 9904=>844, 9905=>838, 9906=>731, 9985=>838, 9986=>838, 9987=>838, 9988=>838, 9990=>838, 9991=>838, 9992=>838, 9993=>838, 9996=>838, 9997=>838, 9998=>838, + 9999=>838, 10000=>838, 10001=>838, 10002=>838, 10003=>838, 10004=>838, 10005=>838, 10006=>838, 10007=>838, 10008=>838, 10009=>838, 10010=>838, 10011=>838, 10012=>838, 10013=>838, 10014=>838, + 10015=>838, 10016=>838, 10017=>838, 10018=>838, 10019=>838, 10020=>838, 10021=>838, 10022=>838, 10023=>838, 10025=>838, 10026=>838, 10027=>838, 10028=>838, 10029=>838, 10030=>838, 10031=>838, + 10032=>838, 10033=>838, 10034=>838, 10035=>838, 10036=>838, 10037=>838, 10038=>838, 10039=>838, 10040=>838, 10041=>838, 10042=>838, 10043=>838, 10044=>838, 10045=>838, 10046=>838, 10047=>838, + 10048=>838, 10049=>838, 10050=>838, 10051=>838, 10052=>838, 10053=>838, 10054=>838, 10055=>838, 10056=>838, 10057=>838, 10058=>838, 10059=>838, 10061=>896, 10063=>896, 10064=>896, 10065=>896, + 10066=>896, 10070=>896, 10072=>838, 10073=>838, 10074=>838, 10075=>347, 10076=>347, 10077=>587, 10078=>587, 10081=>838, 10082=>838, 10083=>838, 10084=>838, 10085=>838, 10086=>838, 10087=>838, + 10088=>838, 10089=>838, 10090=>838, 10091=>838, 10092=>838, 10093=>838, 10094=>838, 10095=>838, 10096=>838, 10097=>838, 10098=>838, 10099=>838, 10100=>838, 10101=>838, 10102=>847, 10103=>847, + 10104=>847, 10105=>847, 10106=>847, 10107=>847, 10108=>847, 10109=>847, 10110=>847, 10111=>847, 10112=>838, 10113=>838, 10114=>838, 10115=>838, 10116=>838, 10117=>838, 10118=>838, 10119=>838, + 10120=>838, 10121=>838, 10122=>838, 10123=>838, 10124=>838, 10125=>838, 10126=>838, 10127=>838, 10128=>838, 10129=>838, 10130=>838, 10131=>838, 10132=>838, 10136=>838, 10137=>838, 10138=>838, + 10139=>838, 10140=>838, 10141=>838, 10142=>838, 10143=>838, 10144=>838, 10145=>838, 10146=>838, 10147=>838, 10148=>838, 10149=>838, 10150=>838, 10151=>838, 10152=>838, 10153=>838, 10154=>838, + 10155=>838, 10156=>838, 10157=>838, 10158=>838, 10159=>838, 10161=>838, 10162=>838, 10163=>838, 10164=>838, 10165=>838, 10166=>838, 10167=>838, 10168=>838, 10169=>838, 10170=>838, 10171=>838, + 10172=>838, 10173=>838, 10174=>838, 10208=>494, 10214=>487, 10215=>487, 10216=>457, 10217=>457, 10218=>721, 10219=>721, 10224=>838, 10225=>838, 10226=>838, 10227=>838, 10228=>1157, 10229=>1434, + 10230=>1434, 10231=>1434, 10232=>1434, 10233=>1434, 10234=>1434, 10235=>1434, 10236=>1434, 10237=>1434, 10238=>1434, 10239=>1434, 10240=>781, 10241=>781, 10242=>781, 10243=>781, 10244=>781, 10245=>781, + 10246=>781, 10247=>781, 10248=>781, 10249=>781, 10250=>781, 10251=>781, 10252=>781, 10253=>781, 10254=>781, 10255=>781, 10256=>781, 10257=>781, 10258=>781, 10259=>781, 10260=>781, 10261=>781, + 10262=>781, 10263=>781, 10264=>781, 10265=>781, 10266=>781, 10267=>781, 10268=>781, 10269=>781, 10270=>781, 10271=>781, 10272=>781, 10273=>781, 10274=>781, 10275=>781, 10276=>781, 10277=>781, + 10278=>781, 10279=>781, 10280=>781, 10281=>781, 10282=>781, 10283=>781, 10284=>781, 10285=>781, 10286=>781, 10287=>781, 10288=>781, 10289=>781, 10290=>781, 10291=>781, 10292=>781, 10293=>781, + 10294=>781, 10295=>781, 10296=>781, 10297=>781, 10298=>781, 10299=>781, 10300=>781, 10301=>781, 10302=>781, 10303=>781, 10304=>781, 10305=>781, 10306=>781, 10307=>781, 10308=>781, 10309=>781, + 10310=>781, 10311=>781, 10312=>781, 10313=>781, 10314=>781, 10315=>781, 10316=>781, 10317=>781, 10318=>781, 10319=>781, 10320=>781, 10321=>781, 10322=>781, 10323=>781, 10324=>781, 10325=>781, + 10326=>781, 10327=>781, 10328=>781, 10329=>781, 10330=>781, 10331=>781, 10332=>781, 10333=>781, 10334=>781, 10335=>781, 10336=>781, 10337=>781, 10338=>781, 10339=>781, 10340=>781, 10341=>781, + 10342=>781, 10343=>781, 10344=>781, 10345=>781, 10346=>781, 10347=>781, 10348=>781, 10349=>781, 10350=>781, 10351=>781, 10352=>781, 10353=>781, 10354=>781, 10355=>781, 10356=>781, 10357=>781, + 10358=>781, 10359=>781, 10360=>781, 10361=>781, 10362=>781, 10363=>781, 10364=>781, 10365=>781, 10366=>781, 10367=>781, 10368=>781, 10369=>781, 10370=>781, 10371=>781, 10372=>781, 10373=>781, + 10374=>781, 10375=>781, 10376=>781, 10377=>781, 10378=>781, 10379=>781, 10380=>781, 10381=>781, 10382=>781, 10383=>781, 10384=>781, 10385=>781, 10386=>781, 10387=>781, 10388=>781, 10389=>781, + 10390=>781, 10391=>781, 10392=>781, 10393=>781, 10394=>781, 10395=>781, 10396=>781, 10397=>781, 10398=>781, 10399=>781, 10400=>781, 10401=>781, 10402=>781, 10403=>781, 10404=>781, 10405=>781, + 10406=>781, 10407=>781, 10408=>781, 10409=>781, 10410=>781, 10411=>781, 10412=>781, 10413=>781, 10414=>781, 10415=>781, 10416=>781, 10417=>781, 10418=>781, 10419=>781, 10420=>781, 10421=>781, + 10422=>781, 10423=>781, 10424=>781, 10425=>781, 10426=>781, 10427=>781, 10428=>781, 10429=>781, 10430=>781, 10431=>781, 10432=>781, 10433=>781, 10434=>781, 10435=>781, 10436=>781, 10437=>781, + 10438=>781, 10439=>781, 10440=>781, 10441=>781, 10442=>781, 10443=>781, 10444=>781, 10445=>781, 10446=>781, 10447=>781, 10448=>781, 10449=>781, 10450=>781, 10451=>781, 10452=>781, 10453=>781, + 10454=>781, 10455=>781, 10456=>781, 10457=>781, 10458=>781, 10459=>781, 10460=>781, 10461=>781, 10462=>781, 10463=>781, 10464=>781, 10465=>781, 10466=>781, 10467=>781, 10468=>781, 10469=>781, + 10470=>781, 10471=>781, 10472=>781, 10473=>781, 10474=>781, 10475=>781, 10476=>781, 10477=>781, 10478=>781, 10479=>781, 10480=>781, 10481=>781, 10482=>781, 10483=>781, 10484=>781, 10485=>781, + 10486=>781, 10487=>781, 10488=>781, 10489=>781, 10490=>781, 10491=>781, 10492=>781, 10493=>781, 10494=>781, 10495=>781, 10502=>838, 10503=>838, 10506=>838, 10507=>838, 10560=>838, 10561=>838, + 10702=>838, 10703=>1046, 10704=>1046, 10705=>1000, 10706=>1000, 10707=>1000, 10708=>1000, 10709=>1000, 10731=>494, 10752=>1000, 10753=>1000, 10754=>1000, 10764=>1661, 10765=>563, 10766=>563, 10767=>563, + 10768=>563, 10769=>563, 10770=>563, 10771=>563, 10772=>563, 10773=>563, 10774=>563, 10775=>563, 10776=>563, 10777=>563, 10778=>563, 10779=>563, 10780=>563, 10877=>838, 10878=>838, 10879=>838, + 10880=>838, 10881=>838, 10882=>838, 10883=>838, 10884=>838, 10885=>838, 10886=>838, 10887=>838, 10888=>838, 10889=>838, 10890=>838, 10891=>838, 10892=>838, 10893=>838, 10894=>838, 10895=>838, + 10896=>838, 10897=>838, 10898=>838, 10899=>838, 10900=>838, 10901=>838, 10902=>838, 10903=>838, 10904=>838, 10905=>838, 10906=>838, 10907=>838, 10908=>838, 10909=>838, 10910=>838, 10911=>838, + 10912=>838, 10926=>838, 10927=>838, 10928=>838, 10929=>838, 10930=>838, 10931=>838, 10932=>838, 10933=>838, 10934=>838, 10935=>838, 10936=>838, 10937=>838, 10938=>838, 11001=>838, 11002=>838, + 11008=>838, 11009=>838, 11010=>838, 11011=>838, 11012=>838, 11013=>838, 11014=>838, 11015=>838, 11016=>838, 11017=>838, 11018=>838, 11019=>838, 11020=>838, 11021=>838, 11022=>838, 11023=>838, + 11024=>838, 11025=>838, 11026=>945, 11027=>945, 11028=>945, 11029=>945, 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 11040=>869, 11041=>873, 11042=>873, 11043=>873, 11360=>637, + 11361=>360, 11362=>637, 11363=>733, 11364=>770, 11365=>675, 11366=>478, 11367=>956, 11368=>712, 11369=>775, 11370=>665, 11371=>725, 11372=>582, 11380=>652, 11381=>649, 11382=>516, 11383=>782, + 61960=>860, 62047=>720, 63173=>687, 64256=>810, 64257=>741, 64258=>741, 64259=>1115, 64260=>1116, 64261=>808, 64262=>1020, 64275=>1388, 64276=>1384, 64277=>1378, 64278=>1384, 64279=>1713, 64285=>372, + 64287=>692, 64288=>720, 64297=>838, 64298=>963, 64299=>963, 64300=>963, 64301=>963, 64302=>751, 64303=>751, 64304=>751, 64305=>731, 64306=>537, 64307=>684, 64308=>778, 64309=>467, 64310=>521, + 64312=>770, 64313=>467, 64314=>778, 64315=>750, 64316=>718, 64318=>856, 64320=>532, 64321=>855, 64323=>802, 64324=>777, 64326=>751, 64327=>803, 64328=>778, 64329=>963, 64330=>822, 64331=>372, + 64332=>731, 64333=>754, 64334=>777, 64338=>1005, 64339=>1059, 64340=>375, 64341=>408, 64342=>1005, 64343=>1059, 64344=>375, 64345=>408, 64346=>1005, 64347=>1059, 64348=>375, 64349=>408, 64350=>1005, + 64351=>1059, 64352=>375, 64353=>408, 64354=>1005, 64355=>1059, 64356=>375, 64357=>408, 64358=>1005, 64359=>1059, 64360=>375, 64361=>408, 64362=>1162, 64363=>1191, 64364=>655, 64365=>720, 64366=>1162, + 64367=>1191, 64368=>655, 64369=>720, 64370=>721, 64371=>721, 64372=>721, 64373=>721, 64374=>721, 64375=>721, 64376=>721, 64377=>721, 64378=>721, 64379=>721, 64380=>721, 64381=>721, 64382=>721, + 64383=>721, 64384=>721, 64385=>721, 64394=>576, 64395=>622, 64396=>576, 64397=>622, 64398=>1024, 64399=>1024, 64400=>582, 64401=>582, 64402=>1024, 64403=>1024, 64404=>582, 64405=>582, 64414=>854, + 64415=>900, 64473=>622, 64474=>627, 64488=>375, 64489=>408, 64508=>917, 64509=>1012, 64510=>375, 64511=>408, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, + 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65136=>342, 65137=>342, 65138=>342, 65139=>346, 65140=>342, 65142=>342, 65143=>342, + 65144=>342, 65145=>342, 65146=>342, 65147=>342, 65148=>342, 65149=>342, 65150=>342, 65151=>342, 65152=>511, 65153=>343, 65154=>375, 65155=>343, 65156=>375, 65157=>622, 65158=>627, 65159=>343, + 65160=>375, 65161=>917, 65162=>917, 65163=>375, 65164=>408, 65165=>343, 65166=>375, 65167=>1005, 65168=>1059, 65169=>375, 65170=>408, 65171=>590, 65172=>606, 65173=>1005, 65174=>1059, 65175=>375, + 65176=>408, 65177=>1005, 65178=>1059, 65179=>375, 65180=>408, 65181=>721, 65182=>721, 65183=>721, 65184=>721, 65185=>721, 65186=>721, 65187=>721, 65188=>721, 65189=>721, 65190=>721, 65191=>721, + 65192=>721, 65193=>513, 65194=>578, 65195=>513, 65196=>578, 65197=>576, 65198=>622, 65199=>576, 65200=>622, 65201=>1380, 65202=>1414, 65203=>983, 65204=>1018, 65205=>1380, 65206=>1414, 65207=>983, + 65208=>1018, 65209=>1345, 65210=>1364, 65211=>966, 65212=>985, 65213=>1345, 65214=>1364, 65215=>966, 65216=>985, 65217=>1039, 65218=>1071, 65219=>942, 65220=>974, 65221=>1039, 65222=>1071, 65223=>942, + 65224=>974, 65225=>683, 65226=>683, 65227=>683, 65228=>564, 65229=>683, 65230=>683, 65231=>683, 65232=>564, 65233=>1162, 65234=>1191, 65235=>655, 65236=>720, 65237=>894, 65238=>901, 65239=>655, + 65240=>720, 65241=>917, 65242=>931, 65243=>582, 65244=>582, 65245=>868, 65246=>893, 65247=>375, 65248=>408, 65249=>733, 65250=>784, 65251=>619, 65252=>670, 65253=>854, 65254=>900, 65255=>375, + 65256=>408, 65257=>590, 65258=>606, 65259=>693, 65260=>660, 65261=>622, 65262=>627, 65263=>917, 65264=>1012, 65265=>917, 65266=>1012, 65267=>375, 65268=>408, 65269=>745, 65270=>759, 65271=>745, + 65272=>759, 65273=>745, 65274=>759, 65275=>745, 65276=>759, 65279=>0, 65533=>1113}; + font[:enc]=''; + font[:diff]=''; + font[:file]='DejaVuSans-Bold.z'; + font[:ctg]='DejaVuSans-Bold.ctg.z'; + font[:originalsize]=494260; +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f6/f6a6bc2e8f1885b3b41f16525e91388bb373165f.svn-base Binary file .svn/pristine/f6/f6a6bc2e8f1885b3b41f16525e91388bb373165f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f6/f6ad9cdc54a3eca24ddf31db675e5edcd3cde504.svn-base Binary file .svn/pristine/f6/f6ad9cdc54a3eca24ddf31db675e5edcd3cde504.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f6/f6adde640ee0f6699f4137e3cbfb95a7427fe4fa.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f6/f6adde640ee0f6699f4137e3cbfb95a7427fe4fa.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +/.project +/.loadpath +/config/additional_environment.rb +/config/configuration.yml +/config/database.yml +/config/email.yml +/config/initializers/session_store.rb +/coverage +/db/*.db +/db/*.sqlite3 +/db/schema.rb +/files/* +/lib/redmine/scm/adapters/mercurial/redminehelper.pyc +/lib/redmine/scm/adapters/mercurial/redminehelper.pyo +/log/*.log* +/log/mongrel_debug +/public/dispatch.* +/public/plugin_assets +/tmp/* +/tmp/cache/* +/tmp/sessions/* +/tmp/sockets/* +/tmp/test/* +/vendor/rails +*.rbc + +/.bundle +/Gemfile.lock +/Gemfile.local + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f71915a7023c35e460772e471f889ad3127c400c.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f71915a7023c35e460772e471f889ad3127c400c.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar LT language +// Author: Gediminas Muižis, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. +// Ver: 0.2 + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sekmadienis", + "Pirmadienis", + "Antradienis", + "Trečiadienis", + "Ketvirtadienis", + "Penktadienis", + "Šeštadienis", + "Sekmadienis"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Sek", + "Pir", + "Ant", + "Tre", + "Ket", + "Pen", + "Šeš", + "Sek"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Sausis", + "Vasaris", + "Kovas", + "Balandis", + "Gegužė", + "Birželis", + "Liepa", + "Rudpjūtis", + "Rugsėjis", + "Spalis", + "Lapkritis", + "Gruodis"); + +// short month names +Calendar._SMN = new Array +("Sau", + "Vas", + "Kov", + "Bal", + "Geg", + "Brž", + "Lie", + "Rgp", + "Rgs", + "Spl", + "Lap", + "Grd"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Apie kalendorių"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Datos pasirinkimas:\n" + +"- Naudoti \xab, \xbb mygtukus norint pasirinkti metus\n" + +"- Naudoti " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " mygtukus norint pasirinkti mėnesį\n" + +"- PAlaikykite nuspaudę bet kurį nygtuką norėdami iškviesti greitąjį meniu."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Datos pasirinkimas:\n" + +"- Paspaudus ant valandos ar minutės, jų reikšmės padidėja\n" + +"- arba Shift-paspaudimas norint sumažinti reikšmę\n" + +"- arba paspauskite ir tempkite norint greičiau keisti reikšmę."; + +Calendar._TT["PREV_YEAR"] = "Ankst. metai (laikyti, norint iškviesti meniu)"; +Calendar._TT["PREV_MONTH"] = "Ankst. mėnuo (laikyti, norint iškviesti meniu)"; +Calendar._TT["GO_TODAY"] = "Šiandien"; +Calendar._TT["NEXT_MONTH"] = "Kitas mėnuo (laikyti, norint iškviesti meniu)"; +Calendar._TT["NEXT_YEAR"] = "Kiti metai (laikyti, norint iškviesti meniu)"; +Calendar._TT["SEL_DATE"] = "Pasirinkti datą"; +Calendar._TT["DRAG_TO_MOVE"] = "Perkelkite pėlyte"; +Calendar._TT["PART_TODAY"] = " (šiandien)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Rodyti %s pirmiau"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Uždaryti"; +Calendar._TT["TODAY"] = "Šiandien"; +Calendar._TT["TIME_PART"] = "(Shift-)Spausti ar tempti, norint pakeisti reikšmę"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "sav"; +Calendar._TT["TIME"] = "Laikas:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f7233d462d007f750b5083ef4fae8c0ec45087b3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f7233d462d007f750b5083ef4fae8c0ec45087b3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class UpgradeOpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase + def initialize(runtime_args, runtime_options = {}) + super + end + + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate' + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f724e18f2ef00c8b0bb5023a4b21743356c7755b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f724e18f2ef00c8b0bb5023a4b21743356c7755b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,82 @@ +dn: dc=redmine,dc=org +objectClass: top +objectClass: dcObject +objectClass: organization +o: redmine.org +dc: redmine +structuralObjectClass: organization +entryUUID: 886f5fca-0a87-102e-8d06-67c361d9bd2d +creatorsName: +createTimestamp: 20090721211642Z +entryCSN: 20090721211642.955188Z#000000#000#000000 +modifiersName: +modifyTimestamp: 20090721211642Z + +dn: cn=admin,dc=redmine,dc=org +objectClass: simpleSecurityObject +objectClass: organizationalRole +cn: admin +description: LDAP administrator +userPassword:: e2NyeXB0fWlWTU9DcUt6WWxXRDI= +structuralObjectClass: organizationalRole +entryUUID: 88704e44-0a87-102e-8d07-67c361d9bd2d +creatorsName: +createTimestamp: 20090721211642Z +entryCSN: 20090721211642.961418Z#000000#000#000000 +modifiersName: +modifyTimestamp: 20090721211642Z + +dn: ou=Person,dc=redmine,dc=org +ou: Person +objectClass: top +objectClass: organizationalUnit +structuralObjectClass: organizationalUnit +entryUUID: d39dd388-0c84-102e-82fa-dff86c63a7d6 +creatorsName: cn=admin,dc=redmine,dc=org +createTimestamp: 20090724100222Z +entryCSN: 20090724100222.924226Z#000000#000#000000 +modifiersName: cn=admin,dc=redmine,dc=org +modifyTimestamp: 20090724100222Z + +dn: uid=example1,ou=Person,dc=redmine,dc=org +objectClass: posixAccount +objectClass: top +objectClass: inetOrgPerson +gidNumber: 0 +givenName: Example +sn: One +uid: example1 +homeDirectory: /home/example1 +cn: Example One +structuralObjectClass: inetOrgPerson +entryUUID: 285d304e-0c8a-102e-82fc-dff86c63a7d6 +creatorsName: cn=admin,dc=redmine,dc=org +createTimestamp: 20090724104032Z +uidNumber: 0 +mail: example1@redmine.org +userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9 +entryCSN: 20090724105945.375801Z#000000#000#000000 +modifiersName: cn=admin,dc=redmine,dc=org +modifyTimestamp: 20090724105945Z + +dn: uid=edavis,ou=Person,dc=redmine,dc=org +objectClass: posixAccount +objectClass: top +objectClass: inetOrgPerson +gidNumber: 0 +givenName: Eric +sn: Davis +uid: edavis +mail: edavis@littlestreamsoftware.com +structuralObjectClass: inetOrgPerson +entryUUID: 9c5f0502-0c8b-102e-82fe-dff86c63a7d6 +creatorsName: cn=admin,dc=redmine,dc=org +createTimestamp: 20090724105056Z +homeDirectory: /home/edavis +cn: Eric Davis +uidNumber: 0 +userPassword:: e1NIQX1mRXFOQ2NvM1lxOWg1WlVnbEQzQ1pKVDRsQnM9 +entryCSN: 20090724105937.734480Z#000000#000#000000 +modifiersName: cn=admin,dc=redmine,dc=org +modifyTimestamp: 20090724105937Z + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f72d15e7793c4539e89571293a216e4135d03c64.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f72d15e7793c4539e89571293a216e4135d03c64.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +module CodeRay +module Encoders + + load :html + + # Wraps HTML output into a DIV element, using inline styles by default. + # + # See Encoders::HTML for available options. + class Div < HTML + + FILE_EXTENSION = 'div.html' + + register_for :div + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :style, + :wrap => :div, + :line_numbers => false + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f758fe470e3cc5243a9e779c6dc8af90264614da.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f758fe470e3cc5243a9e779c6dc8af90264614da.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,64 @@ += AwesomeNestedSet + +Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer. + +== What makes this so awesome? + +This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support. + +== Installation + +If you are on Rails 2.1 or later: + + script/plugin install git://github.com/collectiveidea/awesome_nested_set.git + +== Usage + +To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id: + + class CreateCategories < ActiveRecord::Migration + def self.up + create_table :categories do |t| + t.string :name + t.integer :parent_id + t.integer :lft + t.integer :rgt + end + end + + def self.down + drop_table :categories + end + end + +Enable the nested set functionality by declaring acts_as_nested_set on your model + + class Category < ActiveRecord::Base + acts_as_nested_set + end + +Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info. + +== View Helper + +The view helper is called #nested_set_options. + +Example usage: + + <%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %> + + <%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{i.name}" } ) %> + +See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers. + +== References + +You can learn more about nested sets at: + + http://www.dbmsmag.com/9603d06.html + http://threebit.net/tutorials/nestedset/tutorial1.html + http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html + http://opensource.symetrie.com/trac/better_nested_set/ + + +Copyright (c) 2008 Collective Idea, released under the MIT license \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f767b8d14c7249c0fabe9ba271f45b37cfcab811.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f767b8d14c7249c0fabe9ba271f45b37cfcab811.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,60 @@ +# Tests in this file ensure that: +# +# * plugin views are found +# * views in the application take precedence over those in plugins +# * views in subsequently loaded plugins take precendence over those in previously loaded plugins +# * this works for namespaced views accordingly + +require File.dirname(__FILE__) + '/../test_helper' + +class ViewLoadingTest < ActionController::TestCase + def setup + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + # plugin views should be found + + def test_WITH_a_view_defined_only_in_a_plugin_IT_should_find_the_view + get_action_on_controller :a_view, :alpha_plugin + assert_response_body 'alpha_plugin/a_view' + end + + def test_WITH_a_namespaced_view_defined_only_in_a_plugin_IT_should_find_the_view + get_action_on_controller :a_view, :alpha_plugin, :namespace + assert_response_body 'namespace/alpha_plugin/a_view' + end + + # app takes precedence over plugins + + def test_WITH_a_view_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app + get_action_on_controller :a_view, :app_and_plugin + assert_response_body 'app_and_plugin/a_view (from app)' + end + + def test_WITH_a_namespaced_view_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app + get_action_on_controller :a_view, :app_and_plugin, :namespace + assert_response_body 'namespace/app_and_plugin/a_view (from app)' + end + + # subsequently loaded plugins take precendence over previously loaded plugins + + def test_WITH_a_view_defined_in_two_plugins_IT_should_find_the_latter_of_both + get_action_on_controller :a_view, :shared_plugin + assert_response_body 'shared_plugin/a_view (from beta_plugin)' + end + + def test_WITH_a_namespaced_view_defined_in_two_plugins_IT_should_find_the_latter_of_both + get_action_on_controller :a_view, :shared_plugin, :namespace + assert_response_body 'namespace/shared_plugin/a_view (from beta_plugin)' + end + + # layouts loaded from plugins + + def test_should_be_able_to_load_a_layout_from_a_plugin + get_action_on_controller :action_with_layout, :alpha_plugin + assert_response_body 'rendered in AlphaPluginController#action_with_layout (with plugin layout)' + end + +end + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f76e3147fad4f4e3e2afc96fea2ef9812deb2e0a.svn-base Binary file .svn/pristine/f7/f76e3147fad4f4e3e2afc96fea2ef9812deb2e0a.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f78e5d10fa36c8cdc9c486adcff944bf87c87548.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f78e5d10fa36c8cdc9c486adcff944bf87c87548.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +require File.join(File.dirname(__FILE__), 'abstract_unit') + +if ActiveRecord::Base.connection.supports_migrations? + class Thing < ActiveRecord::Base + attr_accessor :version + acts_as_versioned + end + + class MigrationTest < Test::Unit::TestCase + self.use_transactional_fixtures = false + def teardown + if ActiveRecord::Base.connection.respond_to?(:initialize_schema_information) + ActiveRecord::Base.connection.initialize_schema_information + ActiveRecord::Base.connection.update "UPDATE schema_info SET version = 0" + else + ActiveRecord::Base.connection.initialize_schema_migrations_table + ActiveRecord::Base.connection.assume_migrated_upto_version(0) + end + + Thing.connection.drop_table "things" rescue nil + Thing.connection.drop_table "thing_versions" rescue nil + Thing.reset_column_information + end + + def test_versioned_migration + assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' } + # take 'er up + ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/') + t = Thing.create :title => 'blah blah', :price => 123.45, :type => 'Thing' + assert_equal 1, t.versions.size + + # check that the price column has remembered its value correctly + assert_equal t.price, t.versions.first.price + assert_equal t.title, t.versions.first.title + assert_equal t[:type], t.versions.first[:type] + + # make sure that the precision of the price column has been preserved + assert_equal 7, Thing::Version.columns.find{|c| c.name == "price"}.precision + assert_equal 2, Thing::Version.columns.find{|c| c.name == "price"}.scale + + # now lets take 'er back down + ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/') + assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' } + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f7b73feba9d5d70f6a5a719c5fa3f02097ad51ee.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f7b73feba9d5d70f6a5a719c5fa3f02097ad51ee.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +
    + <%= textilizable content, :text, :attachments => content.page.attachments, + :edit_section_links => (@sections_editable && {:controller => 'wiki', :action => 'edit', :project_id => @page.project, :id => @page.title}) %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f7be25d9006f221b78f8f48800739b3ad4190d60.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f7be25d9006f221b78f8f48800739b3ad4190d60.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddTrackerIsInRoadmap < ActiveRecord::Migration + def self.up + add_column :trackers, :is_in_roadmap, :boolean, :default => true, :null => false + end + + def self.down + remove_column :trackers, :is_in_roadmap + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f7d49732b9c4387f067e29bcd9d719f802bacd6a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f7d49732b9c4387f067e29bcd9d719f802bacd6a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,302 @@ +require 'set' + +module CodeRay +module Encoders + + # = HTML Encoder + # + # This is CodeRay's most important highlighter: + # It provides save, fast XHTML generation and CSS support. + # + # == Usage + # + # require 'coderay' + # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page + # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) + # #-> Some /code/ + # puts CodeRay.scan('Some /code/', :ruby).span #-> the same + # + # puts CodeRay.scan('Some code', :ruby).html( + # :wrap => nil, + # :line_numbers => :inline, + # :css => :style + # ) + # + # == Options + # + # === :tab_width + # Convert \t characters to +n+ spaces (a number.) + # + # Default: 8 + # + # === :css + # How to include the styles; can be :class or :style. + # + # Default: :class + # + # === :wrap + # Wrap in :page, :div, :span or nil. + # + # You can also use Encoders::Div and Encoders::Span. + # + # Default: nil + # + # === :title + # + # The title of the HTML page (works only when :wrap is set to :page.) + # + # Default: 'CodeRay output' + # + # === :line_numbers + # Include line numbers in :table, :inline, or nil (no line numbers) + # + # Default: nil + # + # === :line_number_anchors + # Adds anchors and links to the line numbers. Can be false (off), true (on), + # or a prefix string that will be prepended to the anchor name. + # + # The prefix must consist only of letters, digits, and underscores. + # + # Default: true, default prefix name: "line" + # + # === :line_number_start + # Where to start with line number counting. + # + # Default: 1 + # + # === :bold_every + # Make every +n+-th number appear bold. + # + # Default: 10 + # + # === :highlight_lines + # + # Highlights certain line numbers. + # Can be any Enumerable, typically just an Array or Range, of numbers. + # + # Bolding is deactivated when :highlight_lines is set. It only makes sense + # in combination with :line_numbers. + # + # Default: nil + # + # === :hint + # Include some information into the output using the title attribute. + # Can be :info (show token kind on mouse-over), :info_long (with full path) + # or :debug (via inspect). + # + # Default: false + class HTML < Encoder + + register_for :html + + FILE_EXTENSION = 'snippet.html' + + DEFAULT_OPTIONS = { + :tab_width => 8, + + :css => :class, + :style => :alpha, + :wrap => nil, + :title => 'CodeRay output', + + :line_numbers => nil, + :line_number_anchors => 'n', + :line_number_start => 1, + :bold_every => 10, + :highlight_lines => nil, + + :hint => false, + } + + autoload :Output, 'coderay/encoders/html/output' + autoload :CSS, 'coderay/encoders/html/css' + autoload :Numbering, 'coderay/encoders/html/numbering' + + attr_reader :css + + protected + + HTML_ESCAPE = { #:nodoc: + '&' => '&', + '"' => '"', + '>' => '>', + '<' => '<', + } + + # This was to prevent illegal HTML. + # Strange chars should still be avoided in codes. + evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s] + evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' } + #ansi_chars = Array(0x7f..0xff) + #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i } + # \x9 (\t) and \xA (\n) not included + #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/ + HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/ + + TOKEN_KIND_TO_INFO = Hash.new do |h, kind| + h[kind] = kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } + end + + TRANSPARENT_TOKEN_KINDS = Set[ + :delimiter, :modifier, :content, :escape, :inline_delimiter, + ] + + # Generate a hint about the given +kinds+ in a +hint+ style. + # + # +hint+ may be :info, :info_long or :debug. + def self.token_path_to_hint hint, kinds + kinds = Array kinds + title = + case hint + when :info + kinds = kinds[1..-1] if TRANSPARENT_TOKEN_KINDS.include? kinds.first + TOKEN_KIND_TO_INFO[kinds.first] + when :info_long + kinds.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') + when :debug + kinds.inspect + end + title ? " title=\"#{title}\"" : '' + end + + def setup options + super + + if options[:wrap] || options[:line_numbers] + @real_out = @out + @out = '' + end + + @HTML_ESCAPE = HTML_ESCAPE.dup + @HTML_ESCAPE["\t"] = ' ' * options[:tab_width] + + @opened = [] + @last_opened = nil + @css = CSS.new options[:style] + + hint = options[:hint] + if hint && ![:debug, :info, :info_long].include?(hint) + raise ArgumentError, "Unknown value %p for :hint; \ + expected :info, :info_long, :debug, false, or nil." % hint + end + + css_classes = TokenKinds + case options[:css] + when :class + @span_for_kind = Hash.new do |h, k| + if k.is_a? ::Symbol + kind = k_dup = k + else + kind = k.first + k_dup = k.dup + end + if kind != :space && (hint || css_class = css_classes[kind]) + title = HTML.token_path_to_hint hint, k if hint + css_class ||= css_classes[kind] + h[k_dup] = "" + else + h[k_dup] = nil + end + end + when :style + @span_for_kind = Hash.new do |h, k| + kind = k.is_a?(Symbol) ? k : k.first + h[k.is_a?(Symbol) ? k : k.dup] = + if kind != :space && (hint || css_classes[kind]) + title = HTML.token_path_to_hint hint, k if hint + style = @css.get_style Array(k).map { |c| css_classes[c] } + "" + end + end + else + raise ArgumentError, "Unknown value %p for :css." % options[:css] + end + + @set_last_opened = options[:hint] || options[:css] == :style + end + + def finish options + unless @opened.empty? + warn '%d tokens still open: %p' % [@opened.size, @opened] if $CODERAY_DEBUG + @out << '' while @opened.pop + @last_opened = nil + end + + @out.extend Output + @out.css = @css + if options[:line_numbers] + Numbering.number! @out, options[:line_numbers], options + end + @out.wrap! options[:wrap] + @out.apply_title! options[:title] + + if defined?(@real_out) && @real_out + @real_out << @out + @out = @real_out + end + + super + end + + public + + def text_token text, kind + if text =~ /#{HTML_ESCAPE_PATTERN}/o + text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } + end + if style = @span_for_kind[@last_opened ? [kind, *@opened] : kind] + @out << style << text << '' + else + @out << text + end + end + + # token groups, eg. strings + def begin_group kind + @out << (@span_for_kind[@last_opened ? [kind, *@opened] : kind] || '') + @opened << kind + @last_opened = kind if @set_last_opened + end + + def end_group kind + if $CODERAY_DEBUG && (@opened.empty? || @opened.last != kind) + warn 'Malformed token stream: Trying to close a token (%p) ' \ + 'that is not open. Open are: %p.' % [kind, @opened[1..-1]] + end + if @opened.pop + @out << '' + @last_opened = @opened.last if @last_opened + end + end + + # whole lines to be highlighted, eg. a deleted line in a diff + def begin_line kind + if style = @span_for_kind[@last_opened ? [kind, *@opened] : kind] + if style['class="'] + @out << style.sub('class="', 'class="line ') + else + @out << style.sub('>', ' class="line">') + end + else + @out << '' + end + @opened << kind + @last_opened = kind if @options[:css] == :style + end + + def end_line kind + if $CODERAY_DEBUG && (@opened.empty? || @opened.last != kind) + warn 'Malformed token stream: Trying to close a line (%p) ' \ + 'that is not open. Open are: %p.' % [kind, @opened[1..-1]] + end + if @opened.pop + @out << '' + @last_opened = @opened.last if @last_opened + end + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f7/f7dd5a21e5b6b1fa4c68720d5809c8a2999e974e.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f7/f7dd5a21e5b6b1fa4c68720d5809c8a2999e974e.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +class AddAttachmentsDescription < ActiveRecord::Migration + def self.up + add_column :attachments, :description, :string + end + + def self.down + remove_column :attachments, :description + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f8050e00c99f743c3802900a880f819adbedf13f.svn-base Binary file .svn/pristine/f8/f8050e00c99f743c3802900a880f819adbedf13f.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f8143c93fa1582a0422fb7d8b83ff1b7610b8c1d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f8/f8143c93fa1582a0422fb7d8b83ff1b7610b8c1d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +require File.expand_path('../../../test_helper', __FILE__) + +class ApiTest::HttpBasicLoginTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + def setup + Setting.rest_api_enabled = '1' + Setting.login_required = '1' + end + + def teardown + Setting.rest_api_enabled = '0' + Setting.login_required = '0' + end + + # Using the NewsController because it's a simple API. + context "get /news" do + setup do + project = Project.find('onlinestore') + EnabledModule.create(:project => project, :name => 'news') + end + + context "in :xml format" do + should_allow_http_basic_auth_with_username_and_password(:get, "/projects/onlinestore/news.xml") + end + + context "in :json format" do + should_allow_http_basic_auth_with_username_and_password(:get, "/projects/onlinestore/news.json") + end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f814f68d4495c2a93724f5907a7e7cbb5ab780d2.svn-base Binary file .svn/pristine/f8/f814f68d4495c2a93724f5907a7e7cbb5ab780d2.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f85a0a8308f568f41116e7ba4ea3c465193b95f6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f8/f85a0a8308f568f41116e7ba4ea3c465193b95f6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class TimelogHelperTest < ActionView::TestCase + include TimelogHelper + include ActionView::Helpers::TextHelper + include ActionView::Helpers::DateHelper + + fixtures :projects, :roles, :enabled_modules, :users, + :repositories, :changesets, + :trackers, :issue_statuses, :issues, :versions, :documents, + :wikis, :wiki_pages, :wiki_contents, + :boards, :messages, + :attachments, + :enumerations + + def setup + super + end + + def test_activities_collection_for_select_options_should_return_array_of_activity_names_and_ids + activities = activity_collection_for_select_options + assert activities.include?(["Design", 9]) + assert activities.include?(["Development", 10]) + end + + def test_activities_collection_for_select_options_should_not_include_inactive_activities + activities = activity_collection_for_select_options + assert !activities.include?(["Inactive Activity", 14]) + end + + def test_activities_collection_for_select_options_should_use_the_projects_override + project = Project.find(1) + override_activity = TimeEntryActivity.create!({:name => "Design override", :parent => TimeEntryActivity.find_by_name("Design"), :project => project}) + + activities = activity_collection_for_select_options(nil, project) + assert !activities.include?(["Design", 9]), "System activity found in: " + activities.inspect + assert activities.include?(["Design override", override_activity.id]), "Override activity not found in: " + activities.inspect + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f870c3ba20ea2ddf0ff2322592df44a3f659e500.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f8/f870c3ba20ea2ddf0ff2322592df44a3f659e500.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,43 @@ +class Page < ActiveRecord::Base + belongs_to :author + has_many :authors, :through => :versions, :order => 'name' + belongs_to :revisor, :class_name => 'Author' + has_many :revisors, :class_name => 'Author', :through => :versions, :order => 'name' + acts_as_versioned :if => :feeling_good? do + def self.included(base) + base.cattr_accessor :feeling_good + base.feeling_good = true + base.belongs_to :author + base.belongs_to :revisor, :class_name => 'Author' + end + + def feeling_good? + @@feeling_good == true + end + end +end + +module LockedPageExtension + def hello_world + 'hello_world' + end +end + +class LockedPage < ActiveRecord::Base + acts_as_versioned \ + :inheritance_column => :version_type, + :foreign_key => :page_id, + :table_name => :locked_pages_revisions, + :class_name => 'LockedPageRevision', + :version_column => :lock_version, + :limit => 2, + :if_changed => :title, + :extend => LockedPageExtension +end + +class SpecialLockedPage < LockedPage +end + +class Author < ActiveRecord::Base + has_many :pages +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f897bedafc089b1fd8d90f9d7c464aac7a4e2491.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f8/f897bedafc089b1fd8d90f9d7c464aac7a4e2491.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +begin + require('htmlentities') +rescue LoadError + # This gem is not required - just nice to have. +end +require('cgi') +require 'rfpdf' + +# Mime::Type.register "application/pdf", :pdf +ActionView::Template::register_template_handler 'rfpdf', RFPDF::TemplateHandlers::Base + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f8/f8dc8b2a006317a75e69425034f4d279286333a1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f8/f8dc8b2a006317a75e69425034f4d279286333a1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,152 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::TimeEntriesTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :time_entries + + def setup + Setting.rest_api_enabled = '1' + end + + context "GET /time_entries.xml" do + should "return time entries" do + get '/time_entries.xml', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'time_entries', + :child => {:tag => 'time_entry', :child => {:tag => 'id', :content => '2'}} + end + + context "with limit" do + should "return limited results" do + get '/time_entries.xml?limit=2', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'time_entries', + :children => {:count => 2} + end + end + end + + context "GET /time_entries/2.xml" do + should "return requested time entry" do + get '/time_entries/2.xml', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'time_entry', + :child => {:tag => 'id', :content => '2'} + end + end + + context "POST /time_entries.xml" do + context "with issue_id" do + should "return create time entry" do + assert_difference 'TimeEntry.count' do + post '/time_entries.xml', {:time_entry => {:issue_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11'}}, :authorization => credentials('jsmith') + end + assert_response :created + assert_equal 'application/xml', @response.content_type + + entry = TimeEntry.first(:order => 'id DESC') + assert_equal 'jsmith', entry.user.login + assert_equal Issue.find(1), entry.issue + assert_equal Project.find(1), entry.project + assert_equal Date.parse('2010-12-02'), entry.spent_on + assert_equal 3.5, entry.hours + assert_equal TimeEntryActivity.find(11), entry.activity + end + end + + context "with project_id" do + should "return create time entry" do + assert_difference 'TimeEntry.count' do + post '/time_entries.xml', {:time_entry => {:project_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11'}}, :authorization => credentials('jsmith') + end + assert_response :created + assert_equal 'application/xml', @response.content_type + + entry = TimeEntry.first(:order => 'id DESC') + assert_equal 'jsmith', entry.user.login + assert_nil entry.issue + assert_equal Project.find(1), entry.project + assert_equal Date.parse('2010-12-02'), entry.spent_on + assert_equal 3.5, entry.hours + assert_equal TimeEntryActivity.find(11), entry.activity + end + end + + context "with invalid parameters" do + should "return errors" do + assert_no_difference 'TimeEntry.count' do + post '/time_entries.xml', {:time_entry => {:project_id => '1', :spent_on => '2010-12-02', :activity_id => '11'}}, :authorization => credentials('jsmith') + end + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + + assert_tag 'errors', :child => {:tag => 'error', :content => "Hours can't be blank"} + end + end + end + + context "PUT /time_entries/2.xml" do + context "with valid parameters" do + should "update time entry" do + assert_no_difference 'TimeEntry.count' do + put '/time_entries/2.xml', {:time_entry => {:comments => 'API Update'}}, :authorization => credentials('jsmith') + end + assert_response :ok + assert_equal 'API Update', TimeEntry.find(2).comments + end + end + + context "with invalid parameters" do + should "return errors" do + assert_no_difference 'TimeEntry.count' do + put '/time_entries/2.xml', {:time_entry => {:hours => '', :comments => 'API Update'}}, :authorization => credentials('jsmith') + end + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + + assert_tag 'errors', :child => {:tag => 'error', :content => "Hours can't be blank"} + end + end + end + + context "DELETE /time_entries/2.xml" do + should "destroy time entry" do + assert_difference 'TimeEntry.count', -1 do + delete '/time_entries/2.xml', {}, :authorization => credentials('jsmith') + end + assert_response :ok + assert_nil TimeEntry.find_by_id(2) + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f9/f9aeb8c692c8cedd603babe04b14a070c2aa1c72.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f9/f9aeb8c692c8cedd603babe04b14a070c2aa1c72.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +--- +changes_001: + id: 1 + changeset_id: 100 + action: A + path: /test/some/path/in/the/repo + from_path: + from_revision: +changes_002: + id: 2 + changeset_id: 100 + action: A + path: /test/some/path/elsewhere/in/the/repo + from_path: + from_revision: +changes_003: + id: 3 + changeset_id: 101 + action: M + path: /test/some/path/in/the/repo + from_path: + from_revision: + \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f9/f9b97c28f8a6947541c1dc27fc6092ed1a18cddb.svn-base Binary file .svn/pristine/f9/f9b97c28f8a6947541c1dc27fc6092ed1a18cddb.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f9/f9c3d3f8b1d544ebc83678b8531d0a867aef2179.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/f9/f9c3d3f8b1d544ebc83678b8531d0a867aef2179.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +api.relation do + api.id @relation.id + api.issue_id @relation.issue_from_id + api.issue_to_id @relation.issue_to_id + api.relation_type @relation.relation_type + api.delay @relation.delay +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/f9/f9cd20d82fbf300776d4caacbaf8cb4ca08eb45b.svn-base Binary file .svn/pristine/f9/f9cd20d82fbf300776d4caacbaf8cb4ca08eb45b.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fa/fa3b4d93c72c3ec159cca814b171bb7f0448ff0f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fa/fa3b4d93c72c3ec159cca814b171bb7f0448ff0f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +class Topic < ActiveRecord::Base + has_many :replies, :include => [:user], :dependent => :destroy +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fa/fafc777bb67f933889320268007fe8033f0b89cb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fa/fafc777bb67f933889320268007fe8033f0b89cb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,225 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 'diff' +require 'enumerator' + +class WikiPage < ActiveRecord::Base + belongs_to :wiki + has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy + acts_as_attachable :delete_permission => :delete_wiki_pages_attachments + acts_as_tree :dependent => :nullify, :order => 'title' + + acts_as_watchable + acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"}, + :description => :text, + :datetime => :created_on, + :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}} + + acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"], + :include => [{:wiki => :project}, :content], + :permission => :view_wiki_pages, + :project_key => "#{Wiki.table_name}.project_id" + + attr_accessor :redirect_existing_links + + validates_presence_of :title + validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/ + validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false + validates_associated :content + + validate :validate_parent_title + before_destroy :remove_redirects + before_save :handle_redirects + + # eager load information about last updates, without loading text + named_scope :with_updated_on, { + :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on", + :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id" + } + + # Wiki pages that are protected by default + DEFAULT_PROTECTED_PAGES = %w(sidebar) + + def after_initialize + if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase) + self.protected = true + end + end + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_wiki_pages, project) + end + + def title=(value) + value = Wiki.titleize(value) + @previous_title = read_attribute(:title) if @previous_title.blank? + write_attribute(:title, value) + end + + def handle_redirects + self.title = Wiki.titleize(title) + # Manage redirects if the title has changed + if !@previous_title.blank? && (@previous_title != title) && !new_record? + # Update redirects that point to the old title + wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r| + r.redirects_to = title + r.title == r.redirects_to ? r.destroy : r.save + end + # Remove redirects for the new title + wiki.redirects.find_all_by_title(title).each(&:destroy) + # Create a redirect to the new title + wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0" + @previous_title = nil + end + end + + def remove_redirects + # Remove redirects to this page + wiki.redirects.find_all_by_redirects_to(title).each(&:destroy) + end + + def pretty_title + WikiPage.pretty_title(title) + end + + def content_for_version(version=nil) + result = content.versions.find_by_version(version.to_i) if version + result ||= content + result + end + + def diff(version_to=nil, version_from=nil) + version_to = version_to ? version_to.to_i : self.content.version + version_from = version_from ? version_from.to_i : version_to - 1 + version_to, version_from = version_from, version_to unless version_from < version_to + + content_to = content.versions.find_by_version(version_to) + content_from = content.versions.find_by_version(version_from) + + (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil + end + + def annotate(version=nil) + version = version ? version.to_i : self.content.version + c = content.versions.find_by_version(version) + c ? WikiAnnotate.new(c) : nil + end + + def self.pretty_title(str) + (str && str.is_a?(String)) ? str.tr('_', ' ') : str + end + + def project + wiki.project + end + + def text + content.text if content + end + + def updated_on + unless @updated_on + if time = read_attribute(:updated_on) + # content updated_on was eager loaded with the page + @updated_on = Time.parse(time) rescue nil + else + @updated_on = content && content.updated_on + end + end + @updated_on + end + + # Returns true if usr is allowed to edit the page, otherwise false + def editable_by?(usr) + !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project) + end + + def attachments_deletable?(usr=User.current) + editable_by?(usr) && super(usr) + end + + def parent_title + @parent_title || (self.parent && self.parent.pretty_title) + end + + def parent_title=(t) + @parent_title = t + parent_page = t.blank? ? nil : self.wiki.find_page(t) + self.parent = parent_page + end + + protected + + def validate_parent_title + errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil? + errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self)) + errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id) + end +end + +class WikiDiff < Redmine::Helpers::Diff + attr_reader :content_to, :content_from + + def initialize(content_to, content_from) + @content_to = content_to + @content_from = content_from + super(content_to.text, content_from.text) + end +end + +class WikiAnnotate + attr_reader :lines, :content + + def initialize(content) + @content = content + current = content + current_lines = current.text.split(/\r?\n/) + @lines = current_lines.collect {|t| [nil, nil, t]} + positions = [] + current_lines.size.times {|i| positions << i} + while (current.previous) + d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten + d.each_slice(3) do |s| + sign, line = s[0], s[1] + if sign == '+' && positions[line] && positions[line] != -1 + if @lines[positions[line]][0].nil? + @lines[positions[line]][0] = current.version + @lines[positions[line]][1] = current.author + end + end + end + d.each_slice(3) do |s| + sign, line = s[0], s[1] + if sign == '-' + positions.insert(line, -1) + else + positions[line] = nil + end + end + positions.compact! + # Stop if every line is annotated + break unless @lines.detect { |line| line[0].nil? } + current = current.previous + end + @lines.each { |line| + line[0] ||= current.version + # if the last known version is > 1 (eg. history was cleared), we don't know the author + line[1] ||= current.author if current.version == 1 + } + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fb/fb7ef041bbcc8eadd98d7fb619e196b16fec91c6.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fb/fb7ef041bbcc8eadd98d7fb619e196b16fec91c6.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +require File.expand_path('../../test_helper', __FILE__) + +class LayoutTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + + test "browsing to a missing page should render the base layout" do + get "/users/100000000" + + assert_response :not_found + + # UsersController uses the admin layout by default + assert_select "#admin-menu", :count => 0 + end + + test "browsing to an unauthorized page should render the base layout" do + change_user_password('miscuser9', 'test') + + log_user('miscuser9','test') + + get "/admin" + assert_response :forbidden + assert_select "#admin-menu", :count => 0 + end + + def test_top_menu_and_search_not_visible_when_login_required + with_settings :login_required => '1' do + get '/' + assert_select "#top-menu > ul", 0 + assert_select "#quick-search", 0 + end + end + + def test_top_menu_and_search_visible_when_login_not_required + with_settings :login_required => '0' do + get '/' + assert_select "#top-menu > ul" + assert_select "#quick-search" + end + end + + def test_wiki_formatter_header_tags + Role.anonymous.add_permission! :add_issues + + get '/projects/ecookbook/issues/new' + assert_tag :script, + :attributes => {:src => %r{^/javascripts/jstoolbar/textile.js}}, + :parent => {:tag => 'head'} + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fb/fb9d18ab27c8a24a4ea968203d6a7cfafe3bd575.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fb/fb9d18ab27c8a24a4ea968203d6a7cfafe3bd575.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,137 @@ +<%= render :partial => 'action_menu' %> + +

    <%= issue_heading(@issue) %>

    + +
    + <%= avatar(@issue.author, :size => "50") %> + +
    +<%= render_issue_subject_with_tree(@issue) %> +
    +

    + <%= authoring @issue.created_on, @issue.author %>. + <% if @issue.created_on != @issue.updated_on %> + <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>. + <% end %> +

    + + + + + + + + + + + + + + + + + <% if User.current.allowed_to?(:view_time_entries, @project) %> + + + <% end %> + + + + <% if @issue.estimated_hours %> + + <% end %> + +<%= render_custom_fields_rows(@issue) %> +<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> +
    <%=l(:field_status)%>:<%= h(@issue.status.name) %><%=l(:field_start_date)%>:<%= format_date(@issue.start_date) %>
    <%=l(:field_priority)%>:<%= h(@issue.priority.name) %><%=l(:field_due_date)%>:<%= format_date(@issue.due_date) %>
    <%=l(:field_assigned_to)%>:<%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %><%=l(:field_done_ratio)%>:<%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %>
    <%=l(:field_category)%>:<%=h(@issue.category ? @issue.category.name : "-") %><%=l(:label_spent_time)%>:<%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %>
    <%=l(:field_fixed_version)%>:<%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %><%=l(:field_estimated_hours)%>:<%= l_hours(@issue.estimated_hours) %>
    + +<% if @issue.description? || @issue.attachments.any? -%> +
    +<% if @issue.description? %> +
    + <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %> +
    + +

    <%=l(:field_description)%>

    +
    + <%= textilizable @issue, :description, :attachments => @issue.attachments %> +
    +<% end %> +<%= link_to_attachments @issue %> +<% end -%> + +<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> + +<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> +
    +
    +
    + <%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %> +
    +

    <%=l(:label_subtask_plural)%>

    +<%= render_descendants_tree(@issue) unless @issue.leaf? %> +
    +<% end %> + +<% if @relations.present? || User.current.allowed_to?(:manage_issue_relations, @project) %> +
    +
    +<%= render :partial => 'relations' %> +
    +<% end %> + +
    + +<% if @changesets.present? %> +
    +

    <%=l(:label_associated_revisions)%>

    +<%= render :partial => 'changesets', :locals => { :changesets => @changesets} %> +
    +<% end %> + +<% if @journals.present? %> +
    +

    <%=l(:label_history)%>

    +<%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %> +
    +<% end %> + + +
    +<%= render :partial => 'action_menu' %> + +
    +<% if authorize_for('issues', 'edit') %> + +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> + <%= f.link_to 'PDF' %> +<% end %> + +<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> + + <% if User.current.allowed_to?(:add_issue_watchers, @project) || + (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %> +
    + <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %> +
    + <% end %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> + <%= stylesheet_link_tag 'scm' %> + <%= javascript_include_tag 'context_menu' %> + <%= stylesheet_link_tag 'context_menu' %> + <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %> +<% end %> + +<%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fb/fbf038fb26f312343fb26d2a73a682ce24193c01.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fb/fbf038fb26f312343fb26d2a73a682ce24193c01.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +
    <%= l(:label_preview) %> +<%= textilizable @text, :attachments => @attachements, :object => @previewed %> +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fc2507eb1a52514c446bec6339656a06784ed796.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fc2507eb1a52514c446bec6339656a06784ed796.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +$:.unshift File.dirname(__FILE__) unless $:.include? '.' + +ROOT = '.' +LIB_ROOT = File.join ROOT, 'lib' + +task :default => :test + +if File.directory? 'rake_tasks' + + # load rake tasks from subfolder + for task_file in Dir['rake_tasks/*.rake'].sort + load task_file + end + +else + + # fallback tasks when rake_tasks folder is not present (eg. in the distribution package) + desc 'Run CodeRay tests (basic)' + task :test do + ruby './test/functional/suite.rb' + ruby './test/functional/for_redcloth.rb' + end + + gem 'rdoc' if defined? gem + require 'rdoc/task' + desc 'Generate documentation for CodeRay' + Rake::RDocTask.new :doc do |rd| + rd.title = 'CodeRay Documentation' + rd.main = 'README_INDEX.rdoc' + rd.rdoc_files.add Dir['lib'] + rd.rdoc_files.add rd.main + rd.rdoc_dir = 'doc' + end + +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fc2c0768f87efe63d12db5d2349aa64af0e78721.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fc2c0768f87efe63d12db5d2349aa64af0e78721.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +

    <%= link_to(h(@news.title), @news_url) %>

    +<%=h @news.author.name %> + +<%= textilizable(@news, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fc555949e682fe2780b0d574c835d1ef48063ebb.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fc555949e682fe2780b0d574c835d1ef48063ebb.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar BS language +// Autor: Ernad Husremović +// +// Preuzeto od Dragan Matic, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Nedjelja", + "Ponedeljak", + "Utorak", + "Srijeda", + "Četvrtak", + "Petak", + "Subota", + "Nedelja"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ned", + "Pon", + "Uto", + "Sri", + "Čet", + "Pet", + "Sub", + "Ned"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Mart", + "April", + "Maj", + "Jun", + "Jul", + "Avgust", + "Septembar", + "Oktobar", + "Novembar", + "Decembar"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Maj", + "Jun", + "Jul", + "Avg", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O kalendaru"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Preth. godina (drži pritisnuto za meni)"; +Calendar._TT["PREV_MONTH"] = "Preth. mjesec (drži pritisnuto za meni)"; +Calendar._TT["GO_TODAY"] = "Na današnji dan"; +Calendar._TT["NEXT_MONTH"] = "Naredni mjesec (drži pritisnuto za meni)"; +Calendar._TT["NEXT_YEAR"] = "Naredna godina (drži prisnuto za meni)"; +Calendar._TT["SEL_DATE"] = "Izbor datuma"; +Calendar._TT["DRAG_TO_MOVE"] = "Prevucite za izmjenu"; +Calendar._TT["PART_TODAY"] = " (danas)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Prikaži %s prvo"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zatvori"; +Calendar._TT["TODAY"] = "Danas"; +Calendar._TT["TIME_PART"] = "(Shift-)Klik ili prevlačenje za izmjenu vrijednosti"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Vrijeme:"; diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fc6f47b58bfa56e7e03288bcdf7475367e1fb37d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fc6f47b58bfa56e7e03288bcdf7475367e1fb37d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +
    +<%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_project_plural)%>

    + +<% form_tag({}, :method => :get) do %> +
    <%= l(:label_filter_plural) %> + +<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %> +<%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %> +
    +<% end %> +  + +
    + + + + + + + + +<% project_tree(@projects) do |project, level| %> + <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> + + + + + +<% end %> + +
    <%=l(:label_project)%><%=l(:field_is_public)%><%=l(:field_created_on)%>
    <%= link_to_project(project, {:action => 'settings'}, :title => project.short_description) %><%= checked_image project.is_public? %><%= format_date(project.created_on) %> + <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %> + <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %> + <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %> + <%= link_to(l(:button_delete), project_destroy_confirm_path(project), :class => 'icon icon-del') %> +
    +
    + +<% html_title(l(:label_project_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fc76a054eee69ed8d40059f29968dde646077194.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fc76a054eee69ed8d40059f29968dde646077194.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +<% form_tag(project_project_enumerations_path(@project), :method => :put, :class => "tabular") do %> + + + + + + <% TimeEntryActivity.new.available_custom_fields.each do |value| %> + + <% end %> + + + + <% @project.activities(true).each do |enumeration| %> + <% fields_for "enumerations[#{enumeration.id}]", enumeration do |ff| %> + + + + <% enumeration.custom_field_values.each do |value| %> + + <% end %> + + + <% end %> + <% end %> +
    <%= l(:field_name) %><%= l(:enumeration_system_activity) %><%= h value.name %><%= l(:field_active) %>
    + <%= ff.hidden_field :parent_id, :value => enumeration.id unless enumeration.project %> + <%= h(enumeration) %> + <%= checked_image !enumeration.project %> + <%= custom_field_tag "enumerations[#{enumeration.id}]", value %> + + <%= ff.check_box :active %> +
    + +
    +<%= link_to(l(:button_reset), project_project_enumerations_path(@project), + :method => :delete, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fcdff04c6de4b2e2832edf1ac8e1080f0bd88be1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fcdff04c6de4b2e2832edf1ac8e1080f0bd88be1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,49 @@ +

    <%= l(:label_bulk_edit_selected_time_entries) %>

    + +
      <%= @time_entries.collect {|i| content_tag('li', link_to(h("#{i.spent_on.strftime("%Y-%m-%d")} -- #{i.project}: #{l(:label_f_hour_plural, :value => i.hours)}"), { :action => 'edit', :id => i }))} %>
    + +<% form_tag(:action => 'bulk_update') do %> +<%= @time_entries.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> +
    +
    + <%= l(:label_change_properties) %> +
    +

    + + <%= text_field :time_entry, :issue_id, :size => 6 %> +

    + +

    + + <%= text_field :time_entry, :spent_on, :size => 10 %><%= calendar_for('time_entry_spent_on') %> +

    + +

    + + <%= text_field :time_entry, :hours, :size => 6 %> +

    + + <% if @available_activities.any? %> +

    + + <%= select_tag('time_entry[activity_id]', "" + options_from_collection_for_select(@available_activities, :id, :name)) %> +

    + <% end %> + +

    + + <%= text_field(:time_entry, :comments, :size => 100) %> +

    + + <% @custom_fields.each do |custom_field| %> +

    <%= custom_field_tag_for_bulk_edit('time_entry', custom_field, @projects) %>

    + <% end %> + + <%= call_hook(:view_time_entries_bulk_edit_details_bottom, { :time_entries => @time_entries }) %> +
    + +
    +
    + +

    <%= submit_tag l(:button_submit) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fce0d89d5b88d079f5970994503e60b140fbf5f1.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fce0d89d5b88d079f5970994503e60b140fbf5f1.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %> + +
    +
      + <% tabs.each do |tab| -%> +
    • <%= link_to l(tab[:label]), { :tab => tab[:name] }, + :id => "tab-#{tab[:name]}", + :class => (tab[:name] != selected_tab ? nil : 'selected'), + :onclick => "showTab('#{tab[:name]}'); this.blur(); return false;" %>
    • + <% end -%> +
    + +
    + + + +<% tabs.each do |tab| -%> + <%= content_tag('div', render(:partial => tab[:partial], :locals => {:tab => tab} ), + :id => "tab-content-#{tab[:name]}", + :style => (tab[:name] != selected_tab ? 'display:none' : nil), + :class => 'tab-content') %> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fcea6055312718c79b19d49925ca680df3e4895d.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fcea6055312718c79b19d49925ca680df3e4895d.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +witty_retort: + id: 1 + topic_id: 1 + content: Birdman is better! + created_at: <%= 6.hours.ago.to_s(:db) %> + updated_at: nil + +another: + id: 2 + topic_id: 2 + content: Nuh uh! + created_at: <%= 1.hour.ago.to_s(:db) %> + updated_at: nil \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fc/fcf69ce1c47164fbec9c6f967900d8f3c2edcd92.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fc/fcf69ce1c47164fbec9c6f967900d8f3c2edcd92.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +class CreateChangesetsIssues < ActiveRecord::Migration + def self.up + create_table :changesets_issues, :id => false do |t| + t.column :changeset_id, :integer, :null => false + t.column :issue_id, :integer, :null => false + end + add_index :changesets_issues, [:changeset_id, :issue_id], :unique => true, :name => :changesets_issues_ids + end + + def self.down + drop_table :changesets_issues + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd17adbe8ddb5fa8d4ce1ceca6975396fcf0109b.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd17adbe8ddb5fa8d4ce1ceca6975396fcf0109b.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,152 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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 Hook + include ActionController::UrlWriter + + @@listener_classes = [] + @@listeners = nil + @@hook_listeners = {} + + class << self + # Adds a listener class. + # Automatically called when a class inherits from Redmine::Hook::Listener. + def add_listener(klass) + raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton) + @@listener_classes << klass + clear_listeners_instances + end + + # Returns all the listerners instances. + def listeners + @@listeners ||= @@listener_classes.collect {|listener| listener.instance} + end + + # Returns the listeners instances for the given hook. + def hook_listeners(hook) + @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)} + end + + # Clears all the listeners. + def clear_listeners + @@listener_classes = [] + clear_listeners_instances + end + + # Clears all the listeners instances. + def clear_listeners_instances + @@listeners = nil + @@hook_listeners = {} + end + + # Calls a hook. + # Returns the listeners response. + def call_hook(hook, context={}) + [].tap do |response| + hls = hook_listeners(hook) + if hls.any? + hls.each {|listener| response << listener.send(hook, context)} + end + end + end + end + + # Base class for hook listeners. + class Listener + include Singleton + include Redmine::I18n + + # Registers the listener + def self.inherited(child) + Redmine::Hook.add_listener(child) + super + end + + end + + # Listener class used for views hooks. + # Listeners that inherit this class will include various helpers by default. + class ViewListener < Listener + include ERB::Util + include ActionView::Helpers::TagHelper + include ActionView::Helpers::FormHelper + include ActionView::Helpers::FormTagHelper + include ActionView::Helpers::FormOptionsHelper + include ActionView::Helpers::JavaScriptHelper + include ActionView::Helpers::PrototypeHelper + include ActionView::Helpers::NumberHelper + include ActionView::Helpers::UrlHelper + include ActionView::Helpers::AssetTagHelper + include ActionView::Helpers::TextHelper + include ActionController::UrlWriter + include ApplicationHelper + + # Default to creating links using only the path. Subclasses can + # change this default as needed + def self.default_url_options + {:only_path => true } + end + + # Helper method to directly render a partial using the context: + # + # class MyHook < Redmine::Hook::ViewListener + # render_on :view_issues_show_details_bottom, :partial => "show_more_data" + # end + # + def self.render_on(hook, options={}) + define_method hook do |context| + context[:controller].send(:render_to_string, {:locals => context}.merge(options)) + end + end + end + + # Helper module included in ApplicationHelper and ActionController so that + # hooks can be called in views like this: + # + # <%= call_hook(:some_hook) %> + # <%= call_hook(:another_hook, :foo => 'bar') %> + # + # Or in controllers like: + # call_hook(:some_hook) + # call_hook(:another_hook, :foo => 'bar') + # + # Hooks added to views will be concatenated into a string. Hooks added to + # controllers will return an array of results. + # + # Several objects are automatically added to the call context: + # + # * project => current project + # * request => Request instance + # * controller => current Controller instance + # + module Helper + def call_hook(hook, context={}) + if is_a?(ActionController::Base) + default_context = {:controller => self, :project => @project, :request => request} + Redmine::Hook.call_hook(hook, default_context.merge(context)) + else + default_context = {:controller => controller, :project => @project, :request => request} + Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ') + end + end + end + end +end + +ApplicationHelper.send(:include, Redmine::Hook::Helper) +ActionController::Base.send(:include, Redmine::Hook::Helper) diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd3783c6b45fc6689032dd3ff2fb71c9e008341a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd3783c6b45fc6689032dd3ff2fb71c9e008341a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_board) %>

    + +<% labelled_tabular_form_for :board, @board, :url => {:action => 'edit', :id => @board} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd3cf4d6d773d3c54f6502ba7ca3721b3e053fbc.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd3cf4d6d773d3c54f6502ba7ca3721b3e053fbc.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,446 @@ +# encoding: utf-8 + +# This file includes UTF-8 "Felix Schäfer". +# We need to consider Ruby 1.9 compatibility. + +require File.expand_path('../../../../../../test_helper', __FILE__) +begin + require 'mocha' + + class GitAdapterTest < ActiveSupport::TestCase + REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s + + FELIX_UTF8 = "Felix Schäfer" + FELIX_HEX = "Felix Sch\xC3\xA4fer" + CHAR_1_HEX = "\xc3\x9c" + + ## Ruby uses ANSI api to fork a process on Windows. + ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem + ## and these are incompatible with ASCII. + # WINDOWS_PASS = Redmine::Platform.mswin? + WINDOWS_PASS = false + + ## Git, Mercurial and CVS path encodings are binary. + ## Subversion supports URL encoding for path. + ## Redmine Mercurial adapter and extension use URL encoding. + ## Git accepts only binary path in command line parameter. + ## So, there is no way to use binary command line parameter in JRuby. + JRUBY_SKIP = (RUBY_PLATFORM == 'java') + JRUBY_SKIP_STR = "TODO: This test fails in JRuby" + + if File.directory?(REPOSITORY_PATH) + def setup + adapter_class = Redmine::Scm::Adapters::GitAdapter + assert adapter_class + assert adapter_class.client_command + assert_equal true, adapter_class.client_available + assert_equal true, adapter_class.client_version_above?([1]) + assert_equal true, adapter_class.client_version_above?([1, 0]) + + @adapter = Redmine::Scm::Adapters::GitAdapter.new( + REPOSITORY_PATH, + nil, + nil, + nil, + 'ISO-8859-1' + ) + assert @adapter + @char_1 = CHAR_1_HEX.dup + if @char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + end + end + + def test_scm_version + to_test = { "git version 1.7.3.4\n" => [1,7,3,4], + "1.6.1\n1.7\n1.8" => [1,6,1], + "1.6.2\r\n1.8.1\r\n1.9.1" => [1,6,2]} + to_test.each do |s, v| + test_scm_version_for(s, v) + end + end + + def test_branches + brs = [] + @adapter.branches.each do |b| + brs << b + end + assert_equal 4, brs.length + assert_equal 'latin-1-path-encoding', brs[0].to_s + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', brs[0].revision + assert_equal brs[0].scmid, brs[0].revision + assert_equal 'master', brs[1].to_s + assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', brs[1].revision + assert_equal brs[1].scmid, brs[1].revision + assert_equal 'test-latin-1', brs[2].to_s + assert_equal '67e7792ce20ccae2e4bb73eed09bb397819c8834', brs[2].revision + assert_equal brs[2].scmid, brs[2].revision + assert_equal 'test_branch', brs[3].to_s + assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', brs[3].revision + assert_equal brs[3].scmid, brs[3].revision + end + + def test_tags + assert_equal [ + "tag00.lightweight", + "tag01.annotated", + ], @adapter.tags + end + + def test_getting_all_revisions + assert_equal 21, @adapter.revisions('',nil,nil,:all => true).length + end + + def test_getting_certain_revisions + assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length + end + + def test_revisions_reverse + revs1 = @adapter.revisions('',nil,nil,{:all => true, :reverse => true }) + assert_equal 21, revs1.length + assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[0].identifier + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[20].identifier + end + + def test_revisions_reverse_with_time + since2 = Time.gm(2010, 9, 30, 0, 0, 0) + revs2 = @adapter.revisions('', nil, nil, + {:all => true, :since => since2, :reverse => true}) + assert_equal 6, revs2.length + assert_equal '67e7792ce20ccae2e4bb73eed09bb397819c8834', revs2[0].identifier + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[5].identifier + end + + def test_revisions_master_all + revs1 = [] + @adapter.revisions('', nil, "master",{}) do |rev| + revs1 << rev + end + assert_equal 15, revs1.length + assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[ 0].identifier + assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier + + revs2 = [] + @adapter.revisions('', nil, "master", + {:reverse => true}) do |rev| + revs2 << rev + end + assert_equal 15, revs2.length + assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier + assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier + end + + def test_revisions_master_merged_rev + revs1 = [] + @adapter.revisions('', + "713f4944648826f558cf548222f813dabe7cbb04", + "master", + {:reverse => true}) do |rev| + revs1 << rev + end + assert_equal 8, revs1.length + assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', revs1[ 0].identifier + assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs1[ 1].identifier + # 4a07fe31b is not a child of 713f49446 + assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs1[ 2].identifier + # Merged revision + assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs1[ 3].identifier + assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs1[-1].identifier + + revs2 = [] + @adapter.revisions('', + "fba357b886984ee71185ad2065e65fc0417d9b92", + "master", + {:reverse => true}) do |rev| + revs2 << rev + end + assert_equal 7, revs2.length + assert_equal '7e61ac704deecde634b51e59daa8110435dcb3da', revs2[ 0].identifier + # 4a07fe31b is not a child of fba357b8869 + assert_equal '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', revs2[ 1].identifier + # Merged revision + assert_equal '32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', revs2[ 2].identifier + assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', revs2[-1].identifier + end + + def test_revisions_branch_latin_1_path_encoding_all + revs1 = [] + @adapter.revisions('', nil, "latin-1-path-encoding",{}) do |rev| + revs1 << rev + end + assert_equal 8, revs1.length + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[ 0].identifier + assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs1[-1].identifier + + revs2 = [] + @adapter.revisions('', nil, "latin-1-path-encoding", + {:reverse => true}) do |rev| + revs2 << rev + end + assert_equal 8, revs2.length + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier + assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', revs2[ 0].identifier + end + + def test_revisions_branch_latin_1_path_encoding_with_rev + revs1 = [] + @adapter.revisions('', + '7234cb2750b63f47bff735edc50a1c0a433c2518', + "latin-1-path-encoding", + {:reverse => true}) do |rev| + revs1 << rev + end + assert_equal 7, revs1.length + assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', revs1[ 0].identifier + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs1[-1].identifier + + revs2 = [] + @adapter.revisions('', + '57ca437c0acbbcb749821fdf3726a1367056d364', + "latin-1-path-encoding", + {:reverse => true}) do |rev| + revs2 << rev + end + assert_equal 3, revs2.length + assert_equal '4fc55c43bf3d3dc2efb66145365ddc17639ce81e', revs2[ 0].identifier + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', revs2[-1].identifier + end + + def test_revisions_invalid_rev + revs1 = [] + @adapter.revisions('', + '1234abcd', + "master", + {:reverse => true}) do |rev| + revs1 << rev + end + assert_equal [], revs1 + end + + def test_getting_revisions_with_spaces_in_filename + assert_equal 1, @adapter.revisions("filemane with spaces.txt", + nil, nil, :all => true).length + end + + def test_parents + revs1 = [] + @adapter.revisions('', + nil, + "master", + {:reverse => true}) do |rev| + revs1 << rev + end + assert_equal 15, revs1.length + assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", + revs1[0].identifier + assert_equal nil, revs1[0].parents + assert_equal "899a15dba03a3b350b89c3f537e4bbe02a03cdc9", + revs1[1].identifier + assert_equal 1, revs1[1].parents.length + assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", + revs1[1].parents[0] + assert_equal "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf", + revs1[10].identifier + assert_equal 2, revs1[10].parents.length + assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", + revs1[10].parents[0] + assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", + revs1[10].parents[1] + end + + def test_getting_revisions_with_leading_and_trailing_spaces_in_filename + assert_equal " filename with a leading space.txt ", + @adapter.revisions(" filename with a leading space.txt ", + nil, nil, :all => true)[0].paths[0][:path] + end + + def test_getting_entries_with_leading_and_trailing_spaces_in_filename + assert_equal " filename with a leading space.txt ", + @adapter.entries('', + '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c')[3].name + end + + def test_annotate + annotate = @adapter.annotate('sources/watchers_controller.rb') + assert_kind_of Redmine::Scm::Adapters::Annotate, annotate + assert_equal 41, annotate.lines.size + assert_equal "# This program is free software; you can redistribute it and/or", + annotate.lines[4].strip + assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", + annotate.revisions[4].identifier + assert_equal "jsmith", annotate.revisions[4].author + end + + def test_annotate_moved_file + annotate = @adapter.annotate('renamed_test.txt') + assert_kind_of Redmine::Scm::Adapters::Annotate, annotate + assert_equal 2, annotate.lines.size + end + + def test_last_rev + last_rev = @adapter.lastrev("README", + "4f26664364207fa8b1af9f8722647ab2d4ac5d43") + assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.scmid + assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", last_rev.identifier + assert_equal "Adam Soltys ", last_rev.author + assert_equal "2009-06-24 05:27:38".to_time, last_rev.time + end + + def test_last_rev_with_spaces_in_filename + last_rev = @adapter.lastrev("filemane with spaces.txt", + "ed5bb786bbda2dee66a2d50faf51429dbc043a7b") + str_felix_utf8 = FELIX_UTF8.dup + str_felix_hex = FELIX_HEX.dup + last_rev_author = last_rev.author + if last_rev_author.respond_to?(:force_encoding) + last_rev_author.force_encoding('UTF-8') + end + assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.scmid + assert_equal "ed5bb786bbda2dee66a2d50faf51429dbc043a7b", last_rev.identifier + assert_equal "#{str_felix_utf8} ", + last_rev.author + assert_equal "#{str_felix_hex} ", + last_rev.author + assert_equal "2010-09-18 19:59:46".to_time, last_rev.time + end + + def test_latin_1_path + if WINDOWS_PASS + # + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR + else + p2 = "latin-1-dir/test-#{@char_1}-2.txt" + ['4fc55c43bf3d3dc2efb66145365ddc17639ce81e', '4fc55c43bf3'].each do |r1| + assert @adapter.diff(p2, r1) + assert @adapter.cat(p2, r1) + assert_equal 1, @adapter.annotate(p2, r1).lines.length + ['64f1f3e89ad1cb57976ff0ad99a107012ba3481d', '64f1f3e89ad1cb5797'].each do |r2| + assert @adapter.diff(p2, r1, r2) + end + end + end + end + + def test_entries_tag + entries1 = @adapter.entries(nil, 'tag01.annotated', + options = {:report_last_commit => true}) + assert entries1 + assert_equal 3, entries1.size + assert_equal 'sources', entries1[1].name + assert_equal 'sources', entries1[1].path + assert_equal 'dir', entries1[1].kind + readme = entries1[2] + assert_equal 'README', readme.name + assert_equal 'README', readme.path + assert_equal 'file', readme.kind + assert_equal 27, readme.size + assert_equal '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', readme.lastrev.identifier + assert_equal Time.gm(2007, 12, 14, 9, 24, 1), readme.lastrev.time + end + + def test_entries_branch + entries1 = @adapter.entries(nil, 'test_branch', + options = {:report_last_commit => true}) + assert entries1 + assert_equal 4, entries1.size + assert_equal 'sources', entries1[1].name + assert_equal 'sources', entries1[1].path + assert_equal 'dir', entries1[1].kind + readme = entries1[2] + assert_equal 'README', readme.name + assert_equal 'README', readme.path + assert_equal 'file', readme.kind + assert_equal 159, readme.size + assert_equal '713f4944648826f558cf548222f813dabe7cbb04', readme.lastrev.identifier + assert_equal Time.gm(2009, 6, 19, 4, 37, 23), readme.lastrev.time + end + + def test_entries_latin_1_files + entries1 = @adapter.entries('latin-1-dir', '64f1f3e8') + assert entries1 + assert_equal 3, entries1.size + f1 = entries1[1] + assert_equal "test-#{@char_1}-2.txt", f1.name + assert_equal "latin-1-dir/test-#{@char_1}-2.txt", f1.path + assert_equal 'file', f1.kind + end + + def test_entries_latin_1_dir + if WINDOWS_PASS + # + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR + else + entries1 = @adapter.entries("latin-1-dir/test-#{@char_1}-subdir", + '1ca7f5ed') + assert entries1 + assert_equal 3, entries1.size + f1 = entries1[1] + assert_equal "test-#{@char_1}-2.txt", f1.name + assert_equal "latin-1-dir/test-#{@char_1}-subdir/test-#{@char_1}-2.txt", f1.path + assert_equal 'file', f1.kind + end + end + + def test_path_encoding_default_utf8 + adpt1 = Redmine::Scm::Adapters::GitAdapter.new( + REPOSITORY_PATH + ) + assert_equal "UTF-8", adpt1.path_encoding + adpt2 = Redmine::Scm::Adapters::GitAdapter.new( + REPOSITORY_PATH, + nil, + nil, + nil, + "" + ) + assert_equal "UTF-8", adpt2.path_encoding + end + + def test_cat_path_invalid + assert_nil @adapter.cat('invalid') + end + + def test_cat_revision_invalid + assert @adapter.cat('README') + assert_nil @adapter.cat('README', 'abcd1234efgh') + end + + def test_diff_path_invalid + assert_equal [], @adapter.diff('invalid', '713f4944648826f5') + end + + def test_diff_revision_invalid + assert_nil @adapter.diff(nil, 'abcd1234efgh') + assert_nil @adapter.diff(nil, '713f4944648826f5', 'abcd1234efgh') + assert_nil @adapter.diff(nil, 'abcd1234efgh', '713f4944648826f5') + end + + def test_annotate_path_invalid + assert_nil @adapter.annotate('invalid') + end + + def test_annotate_revision_invalid + assert @adapter.annotate('README') + assert_nil @adapter.annotate('README', 'abcd1234efgh') + end + + private + + def test_scm_version_for(scm_command_version, version) + @adapter.class.expects(:scm_version_from_command_line).returns(scm_command_version) + assert_equal version, @adapter.class.scm_command_version + end + + else + puts "Git test repository NOT FOUND. Skipping unit tests !!!" + def test_fake; assert true end + end + end + +rescue LoadError + class GitMochaFake < ActiveSupport::TestCase + def test_fake; assert(false, "Requires mocha to run those tests") end + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd4c8c5c34ecdf4437056903541cdc2e7af5c1a9.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd4c8c5c34ecdf4437056903541cdc2e7af5c1a9.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 ReportsHelper + + def aggregate(data, criteria) + a = 0 + data.each { |row| + match = 1 + criteria.each { |k, v| + match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? "f" : "t")) + } unless criteria.nil? + a = a + row["total"].to_i if match == 1 + } unless data.nil? + a + end + + def aggregate_link(data, criteria, *args) + a = aggregate data, criteria + a > 0 ? link_to(h(a), *args) : '-' + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd67b936cb5a4fcd00d856837e6795e5d9c87b69.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd67b936cb5a4fcd00d856837e6795e5d9c87b69.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,119 @@ +# The engines plugin makes it trivial to share public assets using plugins. +# To do this, include an assets directory within your plugin, and put +# your javascripts, stylesheets and images in subdirectories of that folder: +# +# my_plugin +# |- init.rb +# |- lib/ +# |- assets/ +# |- javascripts/ +# | |- my_functions.js +# | +# |- stylesheets/ +# | |- my_styles.css +# | +# |- images/ +# |- my_face.jpg +# +# Files within the asset structure are automatically mirrored into +# a publicly-accessible folder each time your application starts (see +# Engines::Assets#mirror_assets). +# +# +# == Using plugin assets in views +# +# It's also simple to use Rails' helpers in your views to use plugin assets. +# The default helper methods have been enhanced by the engines plugin to accept +# a :plugin option, indicating the plugin containing the desired asset. +# +# For example, it's easy to use plugin assets in your layouts: +# +# <%= stylesheet_link_tag "my_styles", :plugin => "my_plugin", :media => "screen" %> +# <%= javascript_include_tag "my_functions", :plugin => "my_plugin" %> +# +# ... and similarly in views and partials, it's easy to use plugin images: +# +# <%= image_tag "my_face", :plugin => "my_plugin" %> +# +# <%= image_path "my_face", :plugin => "my_plugin" %> +# +# Where the default helpers allow the specification of more than one file (i.e. the +# javascript and stylesheet helpers), you can do similarly for multiple assets from +# within a single plugin. +# +# --- +# +# This module enhances four of the methods from ActionView::Helpers::AssetTagHelper: +# +# * stylesheet_link_tag +# * javascript_include_tag +# * image_path +# * image_tag +# +# Each one of these methods now accepts the key/value pair :plugin => "plugin_name", +# which can be used to specify the originating plugin for any assets. +# +module Engines::RailsExtensions::AssetHelpers + def self.included(base) #:nodoc: + base.class_eval do + [:stylesheet_link_tag, :javascript_include_tag, :image_path, :image_tag].each do |m| + alias_method_chain m, :engine_additions + end + end + end + + # Adds plugin functionality to Rails' default stylesheet_link_tag method. + def stylesheet_link_tag_with_engine_additions(*sources) + stylesheet_link_tag_without_engine_additions(*Engines::RailsExtensions::AssetHelpers.pluginify_sources("stylesheets", *sources)) + end + + # Adds plugin functionality to Rails' default javascript_include_tag method. + def javascript_include_tag_with_engine_additions(*sources) + javascript_include_tag_without_engine_additions(*Engines::RailsExtensions::AssetHelpers.pluginify_sources("javascripts", *sources)) + end + + #-- + # Our modified image_path now takes a 'plugin' option, though it doesn't require it + #++ + + # Adds plugin functionality to Rails' default image_path method. + def image_path_with_engine_additions(source, options={}) + options.stringify_keys! + source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options["plugin"], "images", source) if options["plugin"] + image_path_without_engine_additions(source) + end + + # Adds plugin functionality to Rails' default image_tag method. + def image_tag_with_engine_additions(source, options={}) + options.stringify_keys! + if options["plugin"] + source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options["plugin"], "images", source) + options.delete("plugin") + end + image_tag_without_engine_additions(source, options) + end + + #-- + # The following are methods on this module directly because of the weird-freaky way + # Rails creates the helper instance that views actually get + #++ + + # Convert sources to the paths for the given plugin, if any plugin option is given + def self.pluginify_sources(type, *sources) + options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { } + sources.map! { |s| plugin_asset_path(options["plugin"], type, s) } if options["plugin"] + options.delete("plugin") # we don't want it appearing in the HTML + sources << options # re-add options + end + + # Returns the publicly-addressable relative URI for the given asset, type and plugin + def self.plugin_asset_path(plugin_name, type, asset) + raise "No plugin called '#{plugin_name}' - please use the full name of a loaded plugin." if Engines.plugins[plugin_name].nil? + "#{ActionController::Base.relative_url_root}/#{Engines.plugins[plugin_name].public_asset_directory}/#{type}/#{asset}" + end + +end + +module ::ActionView::Helpers::AssetTagHelper #:nodoc: + include Engines::RailsExtensions::AssetHelpers +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd6af42c319d60bd62015ecb66209b14f70f4eec.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd6af42c319d60bd62015ecb66209b14f70f4eec.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddProjectsLftAndRgt < ActiveRecord::Migration + def self.up + add_column :projects, :lft, :integer + add_column :projects, :rgt, :integer + end + + def self.down + remove_column :projects, :lft + remove_column :projects, :rgt + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fd76a59a0d1f9bf708a40119765343dabf8db11a.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fd76a59a0d1f9bf708a40119765343dabf8db11a.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +class AddMissingIndexesToQueries < ActiveRecord::Migration + def self.up + add_index :queries, :project_id + add_index :queries, :user_id + end + + def self.down + remove_index :queries, :project_id + remove_index :queries, :user_id + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fdc1344d7f646f61fa7506b2b2b25effb91b6273.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fdc1344d7f646f61fa7506b2b2b25effb91b6273.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + +class PreviewsController < ApplicationController + before_filter :find_project + + def issue + @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? + if @issue + @attachements = @issue.attachments + @description = params[:issue] && params[:issue][:description] + if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") + @description = nil + end + @notes = params[:notes] + else + @description = (params[:issue] ? params[:issue][:description] : nil) + end + render :layout => false + end + + def news + @text = (params[:news] ? params[:news][:description] : nil) + render :partial => 'common/preview' + end + + private + + def find_project + project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fdc51e770f73afd80741292baab412f8bbb3e897.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fdc51e770f73afd80741292baab412f8bbb3e897.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +api.project do + api.id @project.id + api.name @project.name + api.identifier @project.identifier + api.description @project.description + api.homepage @project.homepage + api.parent(:id => @project.parent.id, :name => @project.parent.name) if @project.parent && @project.parent.visible? + + render_api_custom_values @project.visible_custom_field_values, api + + api.created_on @project.created_on + api.updated_on @project.updated_on + + api.array :trackers do + @project.trackers.each do |tracker| + api.tracker(:id => tracker.id, :name => tracker.name) + end + end if include_in_api_response?('trackers') + + api.array :issue_categories do + @project.issue_categories.each do |category| + api.issue_category(:id => category.id, :name => category.name) + end + end if include_in_api_response?('issue_categories') +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fd/fdfe5659f8fae8662194ea302cbaaa172aeab193.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fd/fdfe5659f8fae8662194ea302cbaaa172aeab193.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,168 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class AttachmentTest < ActiveSupport::TestCase + fixtures :users, :projects, :roles, :members, :member_roles, + :enabled_modules, :issues, :trackers, :attachments + + class MockFile + attr_reader :original_filename, :content_type, :content, :size + + def initialize(attributes) + @original_filename = attributes[:original_filename] + @content_type = attributes[:content_type] + @content = attributes[:content] || "Content" + @size = content.size + end + end + + def setup + set_tmp_attachments_directory + end + + def test_create + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("testfile.txt", "text/plain"), + :author => User.find(1)) + assert a.save + assert_equal 'testfile.txt', a.filename + assert_equal 59, a.filesize + assert_equal 'text/plain', a.content_type + assert_equal 0, a.downloads + assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest + assert File.exist?(a.diskfile) + assert_equal 59, File.size(a.diskfile) + end + + def test_destroy + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("testfile.txt", "text/plain"), + :author => User.find(1)) + assert a.save + assert_equal 'testfile.txt', a.filename + assert_equal 59, a.filesize + assert_equal 'text/plain', a.content_type + assert_equal 0, a.downloads + assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest + diskfile = a.diskfile + assert File.exist?(diskfile) + assert_equal 59, File.size(a.diskfile) + assert a.destroy + assert !File.exist?(diskfile) + end + + def test_create_should_auto_assign_content_type + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("testfile.txt", ""), + :author => User.find(1)) + assert a.save + assert_equal 'text/plain', a.content_type + end + + def test_identical_attachments_at_the_same_time_should_not_overwrite + a1 = Attachment.create!(:container => Issue.find(1), + :file => uploaded_test_file("testfile.txt", ""), + :author => User.find(1)) + a2 = Attachment.create!(:container => Issue.find(1), + :file => uploaded_test_file("testfile.txt", ""), + :author => User.find(1)) + assert a1.disk_filename != a2.disk_filename + end + + def test_filename_should_be_basenamed + a = Attachment.new(:file => MockFile.new(:original_filename => "path/to/the/file")) + assert_equal 'file', a.filename + end + + def test_filename_should_be_sanitized + a = Attachment.new(:file => MockFile.new(:original_filename => "valid:[] invalid:?%*|\"'<>chars")) + assert_equal 'valid_[] invalid_chars', a.filename + end + + def test_diskfilename + assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/ + assert_equal 'test_file.txt', Attachment.disk_filename("test_file.txt")[13..-1] + assert_equal '770c509475505f37c2b8fb6030434d6b.txt', Attachment.disk_filename("test_accentué.txt")[13..-1] + assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentué")[13..-1] + assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentué.ça")[13..-1] + end + + context "Attachmnet.attach_files" do + should "attach the file" do + issue = Issue.first + assert_difference 'Attachment.count' do + Attachment.attach_files(issue, + '1' => { + 'file' => uploaded_test_file('testfile.txt', 'text/plain'), + 'description' => 'test' + }) + end + + attachment = Attachment.first(:order => 'id DESC') + assert_equal issue, attachment.container + assert_equal 'testfile.txt', attachment.filename + assert_equal 59, attachment.filesize + assert_equal 'test', attachment.description + assert_equal 'text/plain', attachment.content_type + assert File.exists?(attachment.diskfile) + assert_equal 59, File.size(attachment.diskfile) + end + + should "add unsaved files to the object as unsaved attachments" do + # Max size of 0 to force Attachment creation failures + with_settings(:attachment_max_size => 0) do + @project = Project.generate! + response = Attachment.attach_files(@project, { + '1' => {'file' => mock_file, 'description' => 'test'}, + '2' => {'file' => mock_file, 'description' => 'test'} + }) + + assert response[:unsaved].present? + assert_equal 2, response[:unsaved].length + assert response[:unsaved].first.new_record? + assert response[:unsaved].second.new_record? + assert_equal response[:unsaved], @project.unsaved_attachments + end + end + end + + def test_latest_attach + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + a1 = Attachment.find(16) + assert_equal "testfile.png", a1.filename + assert a1.readable? + assert (! a1.visible?(User.anonymous)) + assert a1.visible?(User.find(2)) + a2 = Attachment.find(17) + assert_equal "testfile.PNG", a2.filename + assert a2.readable? + assert (! a2.visible?(User.anonymous)) + assert a2.visible?(User.find(2)) + assert a1.created_on < a2.created_on + + la1 = Attachment.latest_attach([a1, a2], "testfile.png") + assert_equal 17, la1.id + la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG") + assert_equal 17, la2.id + + set_tmp_attachments_directory + end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fe/fe0465ebb05e92c484a2edd16cfdf129d7d41205.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fe/fe0465ebb05e92c484a2edd16cfdf129d7d41205.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,81 @@ +module CodeRay +module Scanners + + load :html + load :ruby + + # Scanner for HTML ERB templates. + class ERB < Scanner + + register_for :erb + title 'HTML ERB Template' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + ERB_RUBY_BLOCK = / + (<%(?!%)[-=\#]?) + ((?> + [^\-%]* # normal* + (?> # special + (?: %(?!>) | -(?!%>) ) + [^\-%]* # normal* + )* + )) + ((?: -?%> )?) + /x # :nodoc: + + START_OF_ERB = / + <%(?!%) + /x # :nodoc: + + protected + + def setup + @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true + end + + def reset_instance + super + @html_scanner.reset + end + + def scan_tokens encoder, options + + until eos? + + if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_rest) and not match.empty? + @html_scanner.tokenize match, :tokens => encoder + + elsif match = scan(/#{ERB_RUBY_BLOCK}/o) + start_tag = self[1] + code = self[2] + end_tag = self[3] + + encoder.begin_group :inline + encoder.text_token start_tag, :inline_delimiter + + if start_tag == '<%#' + encoder.text_token code, :comment + else + @ruby_scanner.tokenize code, :tokens => encoder + end unless code.empty? + + encoder.text_token end_tag, :inline_delimiter unless end_tag.empty? + encoder.end_group :inline + + else + raise_inspect 'else-case reached!', encoder + + end + + end + + encoder + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fe/fe997d32c1edf27724d928d7c7e9f42ba101c58f.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/fe/fe997d32c1edf27724d928d7c7e9f42ba101c58f.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fe/feeee980ac9a0f2f3e3981936b394d300cca7b64.svn-base Binary file .svn/pristine/fe/feeee980ac9a0f2f3e3981936b394d300cca7b64.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/fe/fefd73cd9ecdd313f2212e84087533a0649291de.svn-base Binary file .svn/pristine/fe/fefd73cd9ecdd313f2212e84087533a0649291de.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ff/ff068acc0413b56f4b540c721950411f34fdcce5.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ff/ff068acc0413b56f4b540c721950411f34fdcce5.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +

    <%=l(:label_issue_new)%>

    + +<% labelled_tabular_form_for :issue, @issue, :url => {:controller => 'issues', :action => 'create', :project_id => @project}, + :html => {:multipart => true, :id => 'issue-form', :class => 'tabular new-issue-form'} do |f| %> + <%= error_messages_for 'issue' %> +
    + <%= render :partial => 'issues/form', :locals => {:f => f} %> +
    + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> + <%= link_to_remote l(:label_preview), + { :url => preview_issue_path(:project_id => @project), + :method => 'post', + :update => 'preview', + :with => "Form.serialize('issue-form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> + + <%= javascript_tag "Form.Element.focus('issue_subject');" %> +<% end %> + +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> + <%= robot_exclusion_tag %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ff/ff62b4bdd41363f9cdc9bf0c3cbe24d3f90f2713.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ff/ff62b4bdd41363f9cdc9bf0c3cbe24d3f90f2713.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +
    + + +<% line_num = 1 %> +<% syntax_highlight(filename, Redmine::CodesetUtil.to_utf8_by_setting(content)).each_line do |line| %> + + + + + <% line_num += 1 %> +<% end %> + +
    + <%= line_num %> + +
    <%= line %>
    +
    +
    diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ff/ff7c7a78022ec834d13d1e81c3b7d935dfcd48bf.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ff/ff7c7a78022ec834d13d1e81c3b7d935dfcd48bf.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +module CodeRay +module Encoders + + load :token_kind_filter + + # A simple Filter that removes all tokens of the :comment kind. + # + # Alias: +remove_comments+ + # + # Usage: + # CodeRay.scan('print # foo', :ruby).comment_filter.text + # #-> "print " + # + # See also: TokenKindFilter, LinesOfCode + class CommentFilter < TokenKindFilter + + register_for :comment_filter + + DEFAULT_OPTIONS = superclass::DEFAULT_OPTIONS.merge \ + :exclude => [:comment, :docstring] + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ff/ff97db36631f807ab9d4ecf2b564480b822d64f3.svn-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.svn/pristine/ff/ff97db36631f807ab9d4ecf2b564480b822d64f3.svn-base Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,124 @@ +Bitstream Vera Fonts Copyright + +The fonts have a generous copyright, allowing derivative works (as +long as "Bitstream" or "Vera" are not in the names), and full +redistribution (so long as they are not#sold# by themselves). They +can be be bundled, redistributed and sold with any software. + +The fonts are distributed under the following copyright: + +Copyright +========= + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream +Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute +the Font Software, including without limitation the rights to use, +copy, merge, publish, distribute, and/or sell copies of the Font +Software, and to permit persons to whom the Font Software is furnished +to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font +Software without prior written authorization from the Gnome Foundation +or Bitstream Inc., respectively. For further information, contact: +fonts at gnome dot org. + +Copyright FAQ +============= + + 1. I don't understand the resale restriction... What gives? + + Bitstream is giving away these fonts, but wishes to ensure its + competitors can't just drop the fonts as is into a font sale system + and sell them as is. It seems fair that if Bitstream can't make money + from the Bitstream Vera fonts, their competitors should not be able to + do so either. You can sell the fonts as part of any software package, + however. + + 2. I want to package these fonts separately for distribution and + sale as part of a larger software package or system. Can I do so? + + Yes. A RPM or Debian package is a "larger software package" to begin + with, and you aren't selling them independently by themselves. + See 1. above. + + 3. Are derivative works allowed? + Yes! + + 4. Can I change or add to the font(s)? + Yes, but you must change the name(s) of the font(s). + + 5. Under what terms are derivative works allowed? + + You must change the name(s) of the fonts. This is to ensure the + quality of the fonts, both to protect Bitstream and Gnome. We want to + ensure that if an application has opened a font specifically of these + names, it gets what it expects (though of course, using fontconfig, + substitutions could still could have occurred during font + opening). You must include the Bitstream copyright. Additional + copyrights can be added, as per copyright law. Happy Font Hacking! + + 6. If I have improvements for Bitstream Vera, is it possible they might get + adopted in future versions? + + Yes. The contract between the Gnome Foundation and Bitstream has + provisions for working with Bitstream to ensure quality additions to + the Bitstream Vera font family. Please contact us if you have such + additions. Note, that in general, we will want such additions for the + entire family, not just a single font, and that you'll have to keep + both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add + glyphs to the font, they must be stylistically in keeping with Vera's + design. Vera cannot become a "ransom note" font. Jim Lyles will be + providing a document describing the design elements used in Vera, as a + guide and aid for people interested in contributing to Vera. + + 7. I want to sell a software package that uses these fonts: Can I do so? + + Sure. Bundle the fonts with your software and sell your software + with the fonts. That is the intent of the copyright. + + 8. If applications have built the names "Bitstream Vera" into them, + can I override this somehow to use fonts of my choosing? + + This depends on exact details of the software. Most open source + systems and software (e.g., Gnome, KDE, etc.) are now converting to + use fontconfig (see www.fontconfig.org) to handle font configuration, + selection and substitution; it has provisions for overriding font + names and subsituting alternatives. An example is provided by the + supplied local.conf file, which chooses the family Bitstream Vera for + "sans", "serif" and "monospace". Other software (e.g., the XFree86 + core server) has other mechanisms for font substitution. + diff -r 487d96eac004 -r 5e80956cc792 .svn/pristine/ff/fffffac237c4fea0abe945894e0eaa5870f5e77d.svn-base Binary file .svn/pristine/ff/fffffac237c4fea0abe945894e0eaa5870f5e77d.svn-base has changed diff -r 487d96eac004 -r 5e80956cc792 .svn/text-base/.gitignore.svn-base --- a/.svn/text-base/.gitignore.svn-base Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/.project -/.loadpath -/config/additional_environment.rb -/config/configuration.yml -/config/database.yml -/config/email.yml -/config/initializers/session_store.rb -/coverage -/db/*.db -/db/*.sqlite3 -/db/schema.rb -/files/* -/lib/redmine/scm/adapters/mercurial/redminehelper.pyc -/lib/redmine/scm/adapters/mercurial/redminehelper.pyo -/log/*.log* -/log/mongrel_debug -/public/dispatch.* -/public/plugin_assets -/tmp/* -/tmp/cache/* -/tmp/sessions/* -/tmp/sockets/* -/tmp/test/* -/vendor/rails -*.rbc diff -r 487d96eac004 -r 5e80956cc792 .svn/text-base/README.rdoc.svn-base --- a/.svn/text-base/README.rdoc.svn-base Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -= Redmine - -Redmine is a flexible project management web application written using Ruby on Rails framework. - -More details can be found at in the doc directory or on the official website http://www.redmine.org diff -r 487d96eac004 -r 5e80956cc792 .svn/text-base/Rakefile.svn-base --- a/.svn/text-base/Rakefile.svn-base Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -# Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake. - -require(File.join(File.dirname(__FILE__), 'config', 'boot')) - -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -require 'tasks/rails' \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 .svn/wc.db Binary file .svn/wc.db has changed diff -r 487d96eac004 -r 5e80956cc792 README.rdoc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.rdoc Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ += Redmine + +Redmine is a flexible project management web application written using Ruby on Rails framework. + +More details can be found in the doc directory or on the official website http://www.redmine.org diff -r 487d96eac004 -r 5e80956cc792 Rakefile --- a/Rakefile Fri Feb 24 20:18:25 2012 +0000 +++ b/Rakefile Mon Feb 27 13:53:18 2012 +0000 @@ -5,6 +5,11 @@ require 'rake' require 'rake/testtask' -require 'rake/rdoctask' -require 'tasks/rails' \ No newline at end of file +begin + require 'rdoc/task' +rescue LoadError + # RDoc is not available +end + +require 'tasks/rails' diff -r 487d96eac004 -r 5e80956cc792 app/controllers/account_controller.rb --- a/app/controllers/account_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/account_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,24 +1,24 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class AccountController < ApplicationController helper :custom_fields - include CustomFieldsHelper - + include CustomFieldsHelper + # prevents login action to be filtered by check_if_login_required application scope filter skip_before_filter :check_if_login_required @@ -36,7 +36,7 @@ logout_user redirect_to home_url end - + # Enable user to choose a new password def lost_password redirect_to(home_url) && return unless Setting.lost_password? @@ -51,7 +51,7 @@ flash[:notice] = l(:notice_account_password_updated) redirect_to :action => 'login' return - end + end end render :template => "account/password_recovery" return @@ -73,7 +73,7 @@ end end end - + # User self-registration def register redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration] @@ -122,7 +122,7 @@ end end end - + # Token based account activation def activate redirect_to(home_url) && return unless Setting.self_registration? && params[:token] @@ -137,9 +137,9 @@ end redirect_to :action => 'login' end - + private - + def logout_user if User.current.logged? cookies.delete :autologin @@ -147,7 +147,7 @@ self.logged_user = nil end end - + def authenticate_user if Setting.openid? && using_open_id? open_id_authenticate(params[:openid_url]) @@ -169,7 +169,6 @@ end end - def open_id_authenticate(openid_url) authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration| if result.successful? @@ -198,7 +197,7 @@ register_manually_by_administrator(user) do onthefly_creation_failed(user) end - end + end else # Existing record if user.active? @@ -210,7 +209,7 @@ end end end - + def successful_authentication(user) # Valid user self.logged_user = user @@ -221,7 +220,7 @@ call_hook(:controller_account_success_authentication_after, {:user => user }) redirect_back_or_default :controller => 'my', :action => 'page' end - + def set_autologin_cookie(user) token = Token.create(:user => user, :action => 'autologin') cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin' @@ -260,7 +259,7 @@ yield if block_given? end end - + # Automatically register a user # # Pass a block for behavior when a user fails to save @@ -276,7 +275,7 @@ yield if block_given? end end - + # Manual activation by the administrator # # Pass a block for behavior when a user fails to save diff -r 487d96eac004 -r 5e80956cc792 app/controllers/admin_controller.rb --- a/app/controllers/admin_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/admin_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/controllers/application_controller.rb --- a/app/controllers/application_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/application_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -26,6 +26,11 @@ layout 'base' exempt_from_layout 'builder', 'rsb' + protect_from_forgery + def handle_unverified_request + super + cookies.delete(:autologin) + end # Remove broken cookie after upgrade from 0.8.x (#4292) # See https://rails.lighthouseapp.com/projects/8994/tickets/3360 # TODO: remove it when Rails is fixed @@ -40,7 +45,6 @@ before_filter :user_setup, :check_if_login_required, :set_localization filter_parameter_logging :password - protect_from_forgery rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token rescue_from ::Unauthorized, :with => :deny_access @@ -202,8 +206,6 @@ render_404 unless @object.present? @project = @object.project - rescue ActiveRecord::RecordNotFound - render_404 end def find_model_object @@ -250,7 +252,7 @@ if @project.is_public? || User.current.member_of?(@project) || User.current.admin? true else - User.current.logged? ? render_403 : require_login + deny_access end else @project = nil @@ -325,6 +327,19 @@ format.json { head @status } end end + + # Filter for actions that provide an API response + # but have no HTML representation for non admin users + def require_admin_or_api_request + return true if api_request? + if User.current.admin? + true + elsif User.current.logged? + render_error(:status => 406) + else + deny_access + end + end # Picks which layout to use based on the request # @@ -345,9 +360,10 @@ @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items = @items.slice(0, Setting.feeds_limit.to_i) @title = options[:title] || Setting.app_title - render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml' + render :template => "common/feed.atom", :layout => false, + :content_type => 'application/atom+xml' end - + # TODO: remove in Redmine 1.4 def self.accept_key_auth(*actions) ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead." @@ -359,7 +375,7 @@ ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth_actions is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead." self.class.accept_rss_auth end - + def self.accept_rss_auth(*actions) if actions.any? write_inheritable_attribute('accept_rss_auth_actions', actions) @@ -367,11 +383,11 @@ read_inheritable_attribute('accept_rss_auth_actions') || [] end end - + def accept_rss_auth?(action=action_name) self.class.accept_rss_auth.include?(action.to_sym) end - + def self.accept_api_auth(*actions) if actions.any? write_inheritable_attribute('accept_api_auth_actions', actions) @@ -379,7 +395,7 @@ read_inheritable_attribute('accept_api_auth_actions') || [] end end - + def accept_api_auth?(action=action_name) self.class.accept_api_auth.include?(action.to_sym) end @@ -490,13 +506,6 @@ render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." end - # Converts the errors on an ActiveRecord object into a common JSON format - def object_errors_to_json(object) - object.errors.collect do |attribute, error| - { attribute => error } - end.to_json - end - # Renders API response on validation failure def render_validation_errors(object) options = { :status => :unprocessable_entity, :layout => false } diff -r 487d96eac004 -r 5e80956cc792 app/controllers/attachments_controller.rb --- a/app/controllers/attachments_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/attachments_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,17 +22,29 @@ before_filter :delete_authorize, :only => :destroy before_filter :active_authorize, :only => :toggle_active - verify :method => :post, :only => :destroy + accept_api_auth :show, :download def show - if @attachment.is_diff? - @diff = File.new(@attachment.diskfile, "rb").read - render :action => 'diff' - elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte - @content = File.new(@attachment.diskfile, "rb").read - render :action => 'file' - else - download + respond_to do |format| + format.html { + if @attachment.is_diff? + @diff = File.new(@attachment.diskfile, "rb").read + @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' + @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) + # Save diff type as user preference + if User.current.logged? && @diff_type != User.current.pref[:diff_type] + User.current.pref[:diff_type] = @diff_type + User.current.preference.save + end + render :action => 'diff' + elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte + @content = File.new(@attachment.diskfile, "rb").read + render :action => 'file' + else + download + end + } + format.api end end @@ -48,6 +60,7 @@ end + verify :method => :delete, :only => :destroy def destroy # Make sure association callbacks are called @attachment.container.attachments.delete(@attachment) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/auth_sources_controller.rb --- a/app/controllers/auth_sources_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/auth_sources_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,23 +1,23 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class AuthSourcesController < ApplicationController layout 'admin' - + before_filter :require_admin # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) @@ -58,7 +58,7 @@ render 'auth_sources/edit' end end - + def test_connection @auth_method = AuthSource.find(params[:id]) begin diff -r 487d96eac004 -r 5e80956cc792 app/controllers/auto_completes_controller.rb --- a/app/controllers/auto_completes_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/auto_completes_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,6 @@ class AutoCompletesController < ApplicationController before_filter :find_project - + def issues @issues = [] q = params[:q].to_s diff -r 487d96eac004 -r 5e80956cc792 app/controllers/boards_controller.rb --- a/app/controllers/boards_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/boards_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -26,7 +26,7 @@ include SortHelper helper :watchers include WatchersHelper - + def index @boards = @project.boards # show the board if there is only one @@ -43,7 +43,7 @@ sort_update 'created_on' => "#{Message.table_name}.created_on", 'replies' => "#{Message.table_name}.replies_count", 'updated_on' => "#{Message.table_name}.updated_on" - + @topic_count = @board.topics.count @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page'] @topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '), @@ -61,7 +61,7 @@ } end end - + verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index } def new @@ -83,7 +83,7 @@ @board.destroy redirect_to_settings_in_projects end - + private def redirect_to_settings_in_projects redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards' diff -r 487d96eac004 -r 5e80956cc792 app/controllers/calendars_controller.rb --- a/app/controllers/calendars_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/calendars_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -33,11 +33,11 @@ @year = params[:year].to_i if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 @month = params[:month].to_i - end + end end @year ||= Date.today.year @month ||= Date.today.month - + @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) retrieve_query @query.group_by = nil @@ -47,10 +47,10 @@ :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] ) events += @query.versions(:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) - + @calendar.events = events end - + render :action => 'show', :layout => false if request.xhr? end end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/comments_controller.rb --- a/app/controllers/comments_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/comments_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -12,7 +12,7 @@ if @news.comments << @comment flash[:notice] = l(:label_comment_added) end - + redirect_to :controller => 'news', :action => 'show', :id => @news end @@ -32,5 +32,5 @@ @comment = nil @news end - + end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/context_menus_controller.rb --- a/app/controllers/context_menus_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/context_menus_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,10 @@ class ContextMenusController < ApplicationController helper :watchers helper :issues - + def issues @issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project) - + if (@issues.size == 1) @issue = @issues.first @allowed_statuses = @issue.new_statuses_allowed_to(User.current) @@ -26,19 +26,22 @@ :delete => User.current.allowed_to?(:delete_issues, @projects) } if @project - @assignables = @project.assignable_users - @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to) + if @issue + @assignables = @issue.assignable_users + else + @assignables = @project.assignable_users + end @trackers = @project.trackers else #when multiple projects, we only keep the intersection of each set @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a} @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t} end - - @priorities = IssuePriority.all.reverse + + @priorities = IssuePriority.active.reverse @statuses = IssueStatus.find(:all, :order => 'position') @back = back_url - + render :layout => false end @@ -48,11 +51,10 @@ @projects = @time_entries.collect(&:project).compact.uniq @project = @projects.first if @projects.size == 1 @activities = TimeEntryActivity.shared.active - @can = {:edit => User.current.allowed_to?(:log_time, @projects), - :update => User.current.allowed_to?(:log_time, @projects), - :delete => User.current.allowed_to?(:log_time, @projects) + @can = {:edit => User.current.allowed_to?(:edit_time_entries, @projects), + :delete => User.current.allowed_to?(:edit_time_entries, @projects) } @back = back_url render :layout => false - end + end end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/custom_fields_controller.rb --- a/app/controllers/custom_fields_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/custom_fields_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,30 +1,30 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class CustomFieldsController < ApplicationController layout 'admin' - + before_filter :require_admin def index @custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name } @tab = params[:tab] || 'IssueCustomField' end - + def new @custom_field = begin if params[:type].to_s.match(/.+CustomField$/) @@ -33,7 +33,7 @@ rescue end (redirect_to(:action => 'index'); return) unless @custom_field.is_a?(CustomField) - + if request.post? and @custom_field.save flash[:notice] = l(:notice_successful_create) call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field) @@ -53,7 +53,7 @@ @trackers = Tracker.find(:all, :order => 'position') end end - + def destroy @custom_field = CustomField.find(params[:id]).destroy redirect_to :action => 'index', :tab => @custom_field.class.name diff -r 487d96eac004 -r 5e80956cc792 app/controllers/documents_controller.rb --- a/app/controllers/documents_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/documents_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -22,9 +22,9 @@ before_filter :find_model_object, :except => [:index, :new] before_filter :find_project_from_association, :except => [:index, :new] before_filter :authorize - + helper :attachments - + def index @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' documents = @project.documents.find :all, :include => [:attachments, :category] @@ -41,13 +41,13 @@ @document = @project.documents.build render :layout => false if request.xhr? end - + def show @attachments = @document.attachments.find(:all, :order => "created_on DESC") end def new - @document = @project.documents.build(params[:document]) + @document = @project.documents.build(params[:document]) if request.post? and @document.save attachments = Attachment.attach_files(@document, params[:attachments]) render_attachment_warning_if_needed(@document) @@ -55,20 +55,20 @@ redirect_to :action => 'index', :project_id => @project end end - + def edit - @categories = DocumentCategory.all + @categories = DocumentCategory.active #TODO: use it in the views if request.post? and @document.update_attributes(params[:document]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'show', :id => @document end - end + end def destroy @document.destroy redirect_to :controller => 'documents', :action => 'index', :project_id => @project end - + def add_attachment attachments = Attachment.attach_files(@document, params[:attachments]) render_attachment_warning_if_needed(@document) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/enumerations_controller.rb --- a/app/controllers/enumerations_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/enumerations_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,45 +1,39 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class EnumerationsController < ApplicationController layout 'admin' - + before_filter :require_admin helper :custom_fields include CustomFieldsHelper - + def index - list - render :action => 'list' end - # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) verify :method => :post, :only => [ :destroy, :create, :update ], - :redirect_to => { :action => :list } - - def list - end + :redirect_to => { :action => :index } def new begin @enumeration = params[:type].constantize.new rescue NameError - @enumeration = Enumeration.new + @enumeration = Enumeration.new end end @@ -48,7 +42,7 @@ @enumeration.type = params[:enumeration][:type] if @enumeration.save flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list', :type => @enumeration.type + redirect_to :action => 'index', :type => @enumeration.type else render :action => 'new' end @@ -63,12 +57,12 @@ @enumeration.type = params[:enumeration][:type] if params[:enumeration][:type] if @enumeration.update_attributes(params[:enumeration]) flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list', :type => @enumeration.type + redirect_to :action => 'index', :type => @enumeration.type else render :action => 'edit' end end - + def destroy @enumeration = Enumeration.find(params[:id]) if !@enumeration.in_use? diff -r 487d96eac004 -r 5e80956cc792 app/controllers/gantts_controller.rb --- a/app/controllers/gantts_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/gantts_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -29,16 +29,16 @@ helper :sort include SortHelper include Redmine::Export::PDF - + def show @gantt = Redmine::Helpers::Gantt.new(params) @gantt.project = @project retrieve_query @query.group_by = nil @gantt.query = @query if @query.valid? - + basename = (@project ? "#{@project.identifier}-" : '') + 'gantt' - + respond_to do |format| format.html { render :action => "show", :layout => !request.xhr? } format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image') diff -r 487d96eac004 -r 5e80956cc792 app/controllers/groups_controller.rb --- a/app/controllers/groups_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/groups_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,27 +1,27 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class GroupsController < ApplicationController layout 'admin' - + before_filter :require_admin - + helper :custom_fields - + # GET /groups # GET /groups.xml def index @@ -48,7 +48,7 @@ # GET /groups/new.xml def new @group = Group.new - + respond_to do |format| format.html # new.html.erb format.xml { render :xml => @group } @@ -67,8 +67,10 @@ respond_to do |format| if @group.save - flash[:notice] = l(:notice_successful_create) - format.html { redirect_to(groups_path) } + format.html { + flash[:notice] = l(:notice_successful_create) + redirect_to(params[:continue] ? new_group_path : groups_path) + } format.xml { render :xml => @group, :status => :created, :location => @group } else format.html { render :action => "new" } @@ -105,37 +107,37 @@ format.xml { head :ok } end end - + def add_users @group = Group.find(params[:id]) users = User.find_all_by_id(params[:user_ids]) @group.users << users if request.post? respond_to do |format| format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } - format.js { - render(:update) {|page| + format.js { + render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users' users.each {|user| page.visual_effect(:highlight, "user-#{user.id}") } } } end end - + def remove_user @group = Group.find(params[:id]) - @group.users.delete(User.find(params[:user_id])) if request.post? + @group.users.delete(User.find(params[:user_id])) if request.delete? respond_to do |format| format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} } end end - + def autocomplete_for_user @group = Group.find(params[:id]) @users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100) render :layout => false end - + def edit_membership @group = Group.find(params[:id]) @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) @@ -158,7 +160,7 @@ end end end - + def destroy_membership @group = Group.find(params[:id]) Member.find(params[:membership_id]).destroy if request.post? diff -r 487d96eac004 -r 5e80956cc792 app/controllers/issue_categories_controller.rb --- a/app/controllers/issue_categories_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/issue_categories_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,58 +18,92 @@ class IssueCategoriesController < ApplicationController menu_item :settings model_object IssueCategory - before_filter :find_model_object, :except => :new - before_filter :find_project_from_association, :except => :new - before_filter :find_project, :only => :new + before_filter :find_model_object, :except => [:index, :new, :create] + before_filter :find_project_from_association, :except => [:index, :new, :create] + before_filter :find_project, :only => [:index, :new, :create] before_filter :authorize + accept_api_auth :index, :show, :create, :update, :destroy - verify :method => :post, :only => :destroy + def index + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project } + format.api { @categories = @project.issue_categories.all } + end + end + + def show + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project } + format.api + end + end def new - @category = @project.issue_categories.build(params[:category]) - if request.post? - if @category.save - respond_to do |format| - format.html do - flash[:notice] = l(:notice_successful_create) - redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project - end - format.js do - # IE doesn't support the replace_html rjs method for select box options - render(:update) {|page| page.replace "issue_category_id", - content_tag('select', '' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') - } - end + @category = @project.issue_categories.build(params[:issue_category]) + end + + verify :method => :post, :only => :create + def create + @category = @project.issue_categories.build(params[:issue_category]) + if @category.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project end - else - respond_to do |format| - format.html - format.js do - render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) } - end + format.js do + # IE doesn't support the replace_html rjs method for select box options + render(:update) {|page| page.replace "issue_category_id", + content_tag('select', '' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') + } end + format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) } + end + else + respond_to do |format| + format.html { render :action => 'new'} + format.js do + render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) } + end + format.api { render_validation_errors(@category) } end end end - + def edit - if request.post? and @category.update_attributes(params[:category]) - flash[:notice] = l(:notice_successful_update) - redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project + end + + verify :method => :put, :only => :update + def update + if @category.update_attributes(params[:issue_category]) + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project + } + format.api { head :ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@category) } + end end end + verify :method => :delete, :only => :destroy def destroy @issue_count = @category.issues.size - if @issue_count == 0 - # No issue assigned to this category - @category.destroy - redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' - return - elsif params[:todo] - reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign' + if @issue_count == 0 || params[:todo] || api_request? + reassign_to = nil + if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?) + reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) + end @category.destroy(reassign_to) - redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' + respond_to do |format| + format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' } + format.api { head :ok } + end return end @categories = @project.issue_categories - [@category] @@ -81,8 +115,8 @@ def find_model_object super @category = @object - end - + end + def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound diff -r 487d96eac004 -r 5e80956cc792 app/controllers/issue_moves_controller.rb --- a/app/controllers/issue_moves_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/issue_moves_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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. + class IssueMovesController < ApplicationController + menu_item :issues + default_search_scope :issues before_filter :find_issues, :check_project_uniqueness before_filter :authorize diff -r 487d96eac004 -r 5e80956cc792 app/controllers/issue_relations_controller.rb --- a/app/controllers/issue_relations_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/issue_relations_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,30 +1,53 @@ # Redmine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class IssueRelationsController < ApplicationController - before_filter :find_issue, :find_project_from_association, :authorize - - def new + before_filter :find_issue, :find_project_from_association, :authorize, :only => [:index, :create] + before_filter :find_relation, :except => [:index, :create] + + accept_api_auth :index, :show, :create, :destroy + + def index + @relations = @issue.relations + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + def show + raise Unauthorized unless @relation.visible? + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create @relation = IssueRelation.new(params[:relation]) @relation.issue_from = @issue if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/) @relation.issue_to = Issue.visible.find_by_id(m[1].to_i) end - @relation.save if request.post? + saved = @relation.save + respond_to do |format| format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } format.js do @@ -37,28 +60,38 @@ end end end - end - end - - def destroy - relation = IssueRelation.find(params[:id]) - if request.post? && @issue.relations.include?(relation) - relation.destroy - @issue.reload - end - respond_to do |format| - format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } - format.js { - @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } - render(:update) {|page| page.replace_html "relations", :partial => 'issues/relations'} + format.api { + if saved + render :action => 'show', :status => :created, :location => relation_url(@relation) + else + render_validation_errors(@relation) + end } end end - + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } + def destroy + raise Unauthorized unless @relation.deletable? + @relation.destroy + + respond_to do |format| + format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } + format.js { render(:update) {|page| page.remove "relation-#{@relation.id}"} } + format.api { head :ok } + end + end + private def find_issue @issue = @object = Issue.find(params[:issue_id]) rescue ActiveRecord::RecordNotFound render_404 end + + def find_relation + @relation = IssueRelation.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/issue_statuses_controller.rb --- a/app/controllers/issue_statuses_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/issue_statuses_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,31 +1,37 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class IssueStatusesController < ApplicationController layout 'admin' - - before_filter :require_admin - verify :method => :post, :only => [ :destroy, :create, :update, :move, :update_issue_done_ratio ], - :redirect_to => { :action => :index } - + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + def index - @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position" - render :action => "index", :layout => false if request.xhr? + respond_to do |format| + format.html { + @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position" + render :action => "index", :layout => false if request.xhr? + } + format.api { + @issue_statuses = IssueStatus.all(:order => 'position') + } + end end def new @@ -34,7 +40,7 @@ def create @issue_status = IssueStatus.new(params[:issue_status]) - if @issue_status.save + if request.post? && @issue_status.save flash[:notice] = l(:notice_successful_create) redirect_to :action => 'index' else @@ -48,7 +54,7 @@ def update @issue_status = IssueStatus.find(params[:id]) - if @issue_status.update_attributes(params[:issue_status]) + if request.put? && @issue_status.update_attributes(params[:issue_status]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' else @@ -56,6 +62,7 @@ end end + verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index } def destroy IssueStatus.find(params[:id]).destroy redirect_to :action => 'index' @@ -63,9 +70,9 @@ flash[:error] = l(:error_unable_delete_issue_status) redirect_to :action => 'index' end - + def update_issue_done_ratio - if IssueStatus.update_issue_done_ratios + if request.post? && IssueStatus.update_issue_done_ratios flash[:notice] = l(:notice_issue_done_ratios_updated) else flash[:error] = l(:error_issue_done_ratios_not_updated) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/issues_controller.rb --- a/app/controllers/issues_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/issues_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -89,15 +89,20 @@ @issue_count_by_group = @query.issue_count_by_group respond_to do |format| - format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? } - format.api + format.html { render :template => 'issues/index', :layout => !request.xhr? } + format.api { + Issue.load_relations(@issues) if include_in_api_response?('relations') + } format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } - format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') } + format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') } format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') } end else - # Send html if the query is not valid - render(:template => 'issues/index.rhtml', :layout => !request.xhr?) + respond_to do |format| + format.html { render(:template => 'issues/index', :layout => !request.xhr?) } + format.any(:atom, :csv, :pdf) { render(:nothing => true) } + format.api { render_validation_errors(@query) } + end end rescue ActiveRecord::RecordNotFound render_404 @@ -116,10 +121,10 @@ @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } @allowed_statuses = @issue.new_statuses_allowed_to(User.current) @edit_allowed = User.current.allowed_to?(:edit_issues, @project) - @priorities = IssuePriority.all + @priorities = IssuePriority.active @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) respond_to do |format| - format.html { render :template => 'issues/show.rhtml' } + format.html { render :template => 'issues/show' } format.api format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' } format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } @@ -139,8 +144,6 @@ call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) if @issue.save attachments = Attachment.attach_files(@issue, params[:attachments]) - render_attachment_warning_if_needed(@issue) - flash[:notice] = l(:notice_successful_create) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) @@ -153,6 +156,8 @@ respond_to do |format| format.html { + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_issue_successful_create, :id => "##{@issue.id}") redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : { :action => 'show', :id => @issue }) } @@ -289,7 +294,7 @@ # TODO: Refactor, not everything in here is needed by #edit def update_issue_from_params @allowed_statuses = @issue.new_statuses_allowed_to(User.current) - @priorities = IssuePriority.all + @priorities = IssuePriority.active @edit_allowed = User.current.allowed_to?(:edit_issues, @project) @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) @time_entry.attributes = params[:time_entry] @@ -330,14 +335,14 @@ render_error l(:error_no_tracker_in_project) return false end - @issue.start_date ||= Date.today + @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date? if params[:issue].is_a?(Hash) @issue.safe_attributes = params[:issue] if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record? @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] end end - @priorities = IssuePriority.all + @priorities = IssuePriority.active @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/journals_controller.rb --- a/app/controllers/journals_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/journals_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -22,7 +22,7 @@ before_filter :authorize, :only => [:new, :edit, :diff] accept_rss_auth :index menu_item :issues - + helper :issues helper :custom_fields helper :queries @@ -34,9 +34,9 @@ retrieve_query sort_init 'id', 'desc' sort_update(@query.sortable_columns) - + if @query.valid? - @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", + @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", :limit => 25) end @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) @@ -44,7 +44,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def diff @issue = @journal.issue if params[:detail_id].present? @@ -55,7 +55,7 @@ (render_404; return false) unless @issue && @detail @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value) end - + def new journal = Journal.find(params[:journal_id]) if params[:journal_id] if journal @@ -69,7 +69,7 @@ text = text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]') content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - + render(:update) { |page| page.<< "$('notes').value = \"#{escape_javascript content}\";" page.show 'update' @@ -78,7 +78,7 @@ page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" } end - + def edit (render_403; return false) unless @journal.editable_by?(User.current) if request.post? @@ -93,15 +93,15 @@ respond_to do |format| format.html { # TODO: implement non-JS journal update - render :nothing => true + render :nothing => true } format.js end end end - + private - + def find_journal @journal = Journal.find(params[:id]) @project = @journal.journalized.project diff -r 487d96eac004 -r 5e80956cc792 app/controllers/ldap_auth_sources_controller.rb --- a/app/controllers/ldap_auth_sources_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/ldap_auth_sources_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ class LdapAuthSourcesController < AuthSourcesController protected - + def auth_source_class AuthSourceLdap end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/members_controller.rb --- a/app/controllers/members_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/members_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -63,8 +63,8 @@ format.html { redirect_to :action => 'index', :project_id => @project } - format.js { - render(:update) {|page| + format.js { + render(:update) {|page| page.replace_html "memberlist", :partial => 'editlist' page << 'hideOnLoad()' members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") } @@ -81,17 +81,17 @@ # page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', '))) } } - + end end end - + def edit if request.post? and @member.update_attributes(params[:member]) respond_to do |format| format.html { redirect_to :action => 'index', :project_id => @project } - format.js { - render(:update) {|page| + format.js { + render(:update) {|page| page.replace_html "memberlist", :partial => 'editlist' page << 'hideOnLoad()' page.visual_effect(:highlight, "member-#{@member.id}") @@ -114,7 +114,7 @@ } end end - + def autocomplete_for_member @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals logger.debug "Query for #{params[:q]} returned #{@principals.size} results" diff -r 487d96eac004 -r 5e80956cc792 app/controllers/messages_controller.rb --- a/app/controllers/messages_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/messages_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -27,10 +27,10 @@ helper :watchers helper :attachments - include AttachmentsHelper + include AttachmentsHelper REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE) - + # Show a topic and its replies def show page = params[:page] @@ -39,18 +39,18 @@ offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i]) page = 1 + offset / REPLIES_PER_PAGE end - + @reply_count = @topic.children.count @reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}], :order => "#{Message.table_name}.created_on ASC", :limit => @reply_pages.items_per_page, :offset => @reply_pages.current.offset) - + @reply = Message.new(:subject => "RE: #{@message.subject}") render :action => "show", :layout => false if request.xhr? end - + # Create a new topic def new @message = Message.new(params[:message]) @@ -97,7 +97,7 @@ redirect_to :action => 'show', :board_id => @message.board, :id => @message.root, :r => (@message.parent_id && @message.id) end end - + # Delete a messages def destroy (render_403; return false) unless @message.destroyable_by?(User.current) @@ -106,7 +106,7 @@ { :controller => 'boards', :action => 'show', :project_id => @project, :id => @board } : { :action => 'show', :id => @message.parent, :r => @message } end - + def quote user = @message.author text = @message.content @@ -115,7 +115,7 @@ content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> " content << text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n" render(:update) { |page| - page << "$('reply_subject').value = \"#{subject}\";" + page << "$('message_subject').value = \"#{subject}\";" page.<< "$('message_content').value = \"#{content}\";" page.show 'reply' page << "Form.Element.focus('message_content');" @@ -123,14 +123,14 @@ page << "$('message_content').scrollTop = $('message_content').scrollHeight - $('message_content').clientHeight;" } end - + def preview message = @board.messages.find_by_id(params[:id]) @attachements = message.attachments if message @text = (params[:message] || params[:reply])[:content] render :partial => 'common/preview' end - + private def find_message find_board @@ -139,7 +139,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def find_board @board = Board.find(params[:board_id], :include => :project) @project = @board.project diff -r 487d96eac004 -r 5e80956cc792 app/controllers/my_controller.rb --- a/app/controllers/my_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/my_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -119,7 +119,7 @@ end end end - + # Create a new feeds key def reset_rss_key if request.post? @@ -153,7 +153,7 @@ @block_options = [] BLOCKS.each {|k, v| @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize]} end - + # Add a block to user's page # The block is added on top of the page # params[:block] : id of the block to add @@ -167,10 +167,10 @@ # add it on top layout['top'].unshift block @user.pref[:my_page_layout] = layout - @user.pref.save + @user.pref.save render :partial => "block", :locals => {:user => @user, :block_name => block} end - + # Remove a block to user's page # params[:block] : id of the block to remove def remove_block @@ -180,7 +180,7 @@ layout = @user.pref[:my_page_layout] || {} %w(top left right).each {|f| (layout[f] ||= []).delete block } @user.pref[:my_page_layout] = layout - @user.pref.save + @user.pref.save render :nothing => true end @@ -200,7 +200,7 @@ } layout[group] = group_items @user.pref[:my_page_layout] = layout - @user.pref.save + @user.pref.save end end render :nothing => true diff -r 487d96eac004 -r 5e80956cc792 app/controllers/news_controller.rb --- a/app/controllers/news_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/news_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -25,9 +25,9 @@ before_filter :find_optional_project, :only => :index accept_rss_auth :index accept_api_auth :index - + helper :watchers - + def index case params[:format] when 'xml', 'json' @@ -35,9 +35,9 @@ else @limit = 10 end - + scope = @project ? @project.news.visible : News.visible - + @news_count = scope.count @news_pages = Paginator.new self, @news_count, @limit, params['page'] @offset ||= @news_pages.current.offset @@ -45,14 +45,17 @@ :order => "#{News.table_name}.created_on DESC", :offset => @offset, :limit => @limit) - + respond_to do |format| - format.html { render :layout => false if request.xhr? } + format.html { + @news = News.new # for adding news inline + render :layout => false if request.xhr? + } format.api format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") } end end - + def show @comments = @news.comments @comments.reverse! if User.current.wants_comments_in_reverse_order? @@ -77,7 +80,7 @@ def edit end - + def update if request.put? and @news.update_attributes(params[:news]) flash[:notice] = l(:notice_successful_update) @@ -91,14 +94,14 @@ @news.destroy redirect_to :action => 'index', :project_id => @project end - + private def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end - + def find_optional_project return true unless params[:project_id] @project = Project.find(params[:project_id]) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/previews_controller.rb --- a/app/controllers/previews_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/previews_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -39,12 +39,12 @@ end private - + def find_project project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] @project = Project.find(project_id) rescue ActiveRecord::RecordNotFound render_404 end - + end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/project_enumerations_controller.rb --- a/app/controllers/project_enumerations_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/project_enumerations_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,7 @@ class ProjectEnumerationsController < ApplicationController before_filter :find_project_by_project_id before_filter :authorize - + def update if request.put? && params[:enumerations] Project.transaction do @@ -11,7 +11,7 @@ end flash[:notice] = l(:notice_successful_update) end - + redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/projects_controller.rb --- a/app/controllers/projects_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/projects_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,7 +19,7 @@ menu_item :overview menu_item :roadmap, :only => :roadmap menu_item :settings, :only => :settings - + before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ] before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy] before_filter :authorize_global, :only => [:new, :create] @@ -36,7 +36,7 @@ helper :sort include SortHelper helper :custom_fields - include CustomFieldsHelper + include CustomFieldsHelper helper :issues helper :queries include QueriesHelper @@ -48,7 +48,7 @@ # (subprojects belong to them) def index respond_to do |format| - format.html { + format.html { sort_init 'name' sort_update %w(name lft created_on updated_on) @limit = per_page_option @@ -75,7 +75,7 @@ } end end - + def new @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all @@ -108,9 +108,12 @@ @project.members << m end respond_to do |format| - format.html { + format.html { flash[:notice] = l(:notice_successful_create) - redirect_to :controller => 'projects', :action => 'settings', :id => @project + redirect_to(params[:continue] ? + {:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} : + {:controller => 'projects', :action => 'settings', :id => @project} + ) } format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) } end @@ -120,9 +123,9 @@ format.api { render_validation_errors(@project) } end end - + end - + def copy @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all @@ -136,7 +139,7 @@ @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers? else redirect_to :controller => 'admin', :action => 'projects' - end + end else Mailer.with_deliveries(params[:notifications] == '1') do @project = Project.new @@ -164,27 +167,27 @@ # try to redirect to the requested menu item redirect_to_project_menu_item(@project, params[:jump]) && return end - + @users_by_role = @project.users_by_role @subprojects = @project.children.visible.all @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") @trackers = @project.rolled_up_trackers - + cond = @project.project_condition(Setting.display_subprojects_issues?) - + @open_issues_by_tracker = Issue.visible.count(:group => :tracker, :include => [:project, :status, :tracker], :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false]) @total_issues_by_tracker = Issue.visible.count(:group => :tracker, :include => [:project, :status, :tracker], :conditions => cond) - + if User.current.allowed_to?(:view_time_entries, @project) @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f end - + @key = User.current.rss_key - + respond_to do |format| format.html format.api @@ -199,7 +202,7 @@ @repository ||= @project.repository @wiki ||= @project.wiki end - + def edit end @@ -210,7 +213,7 @@ if validate_parent_id && @project.save @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') respond_to do |format| - format.html { + format.html { flash[:notice] = l(:notice_successful_update) redirect_to :action => 'settings', :id => @project } @@ -218,7 +221,7 @@ end else respond_to do |format| - format.html { + format.html { settings render :action => 'settings' } @@ -251,12 +254,12 @@ end redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status])) end - + def unarchive @project.unarchive if request.post? && !@project.active? redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status])) end - + # Delete @project def destroy @project_to_destroy = @project diff -r 487d96eac004 -r 5e80956cc792 app/controllers/queries_controller.rb --- a/app/controllers/queries_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/queries_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,67 +1,97 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class QueriesController < ApplicationController menu_item :issues - before_filter :find_query, :except => :new - before_filter :find_optional_project, :only => :new - - def new - @query = Query.new(params[:query]) - @query.project = params[:query_is_for_all] ? nil : @project - @query.user = User.current - @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? - - @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) if params[:fields] || params[:f] - @query.group_by ||= params[:group_by] - @query.column_names = params[:c] if params[:c] - @query.column_names = nil if params[:default_columns] - - if request.post? && params[:confirm] && @query.save - flash[:notice] = l(:notice_successful_create) - redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query - return + before_filter :find_query, :except => [:new, :create, :index] + before_filter :find_optional_project, :only => [:new, :create] + + accept_api_auth :index + + include QueriesHelper + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option end - render :layout => false if request.xhr? - end - - def edit - if request.post? - @query.filters = {} - @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) if params[:fields] || params[:f] - @query.attributes = params[:query] - @query.project = nil if params[:query_is_for_all] - @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? - @query.group_by ||= params[:group_by] - @query.column_names = params[:c] if params[:c] - @query.column_names = nil if params[:default_columns] - - if @query.save - flash[:notice] = l(:notice_successful_update) - redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query - end + + @query_count = Query.visible.count + @query_pages = Paginator.new self, @query_count, @limit, params['page'] + @queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name") + + respond_to do |format| + format.html { render :nothing => true } + format.api end end + def new + @query = Query.new + @query.user = User.current + @query.project = @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + build_query_from_params + end + + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } + def create + @query = Query.new(params[:query]) + @query.user = User.current + @query.project = params[:query_is_for_all] ? nil : @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + build_query_from_params + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query + else + render :action => 'new', :layout => !request.xhr? + end + end + + def edit + end + + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + def update + @query.attributes = params[:query] + @query.project = nil if params[:query_is_for_all] + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + build_query_from_params + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query + else + render :action => 'edit' + end + end + + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } def destroy - @query.destroy if request.post? + @query.destroy redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 end - + private def find_query @query = Query.find(params[:id]) @@ -70,7 +100,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def find_optional_project @project = Project.find(params[:project_id]) if params[:project_id] render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/reports_controller.rb --- a/app/controllers/reports_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/reports_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -24,8 +24,8 @@ @versions = @project.shared_versions.sort @priorities = IssuePriority.all @categories = @project.issue_categories - @assignees = @project.members.collect { |m| m.user }.sort - @authors = @project.members.collect { |m| m.user }.sort + @assignees = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort + @authors = @project.users.sort @subprojects = @project.descendants.visible @issues_by_tracker = Issue.by_tracker(@project) @@ -37,7 +37,7 @@ @issues_by_subproject = Issue.by_subproject(@project) || [] render :template => "reports/issue_report" - end + end def issue_report_details case params[:detail] @@ -63,12 +63,12 @@ @report_title = l(:field_category) when "assigned_to" @field = "assigned_to_id" - @rows = @project.members.collect { |m| m.user }.sort + @rows = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort @data = Issue.by_assigned_to(@project) @report_title = l(:field_assigned_to) when "author" @field = "author_id" - @rows = @project.members.collect { |m| m.user }.sort + @rows = @project.users.sort @data = Issue.by_author(@project) @report_title = l(:field_author) when "subproject" diff -r 487d96eac004 -r 5e80956cc792 app/controllers/repositories_controller.rb --- a/app/controllers/repositories_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/repositories_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -126,7 +126,7 @@ @changesets = @repository.changesets.find(:all, :limit => @changeset_pages.items_per_page, :offset => @changeset_pages.current.offset, - :include => [:user, :repository]) + :include => [:user, :repository, :parents]) respond_to do |format| format.html { render :layout => false if request.xhr? } @@ -177,7 +177,16 @@ (show_error_not_found; return) unless @entry @annotate = @repository.scm.annotate(@path, @rev) - (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty? + if @annotate.nil? || @annotate.empty? + (render_error l(:error_scm_annotate); return) + end + ann_buf_size = 0 + @annotate.lines.each do |buf| + ann_buf_size += buf.size + end + if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte + (render_error l(:error_scm_annotate_big_text_file); return) + end @changeset = @repository.find_changeset_by_name(@rev) end @@ -212,7 +221,7 @@ User.current.pref[:diff_type] = @diff_type User.current.preference.save end - @cache_key = "repositories/diff/#{@repository.id}/" + + @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}") unless read_fragment(@cache_key) @diff = @repository.diff(@path, @rev, @rev_to) @@ -254,7 +263,7 @@ (render_404; return false) unless @repository @path = params[:path].join('/') unless params[:path].nil? @path ||= '' - @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip + @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip @rev_to = params[:rev_to] unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/roles_controller.rb --- a/app/controllers/roles_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/roles_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,26 +1,26 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class RolesController < ApplicationController layout 'admin' - + before_filter :require_admin - verify :method => :post, :only => [ :destroy, :move ], + verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index } def index @@ -50,7 +50,7 @@ flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' else - @permissions = @role.setable_permissions + @permissions = @role.setable_permissions end end @@ -62,8 +62,8 @@ flash[:error] = l(:error_can_not_remove_role) redirect_to :action => 'index' end - - def report + + def report @roles = Role.find(:all, :order => 'builtin, position') @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } if request.post? diff -r 487d96eac004 -r 5e80956cc792 app/controllers/search_controller.rb --- a/app/controllers/search_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/search_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -26,7 +26,7 @@ @question.strip! @all_words = params[:all_words] ? params[:all_words].present? : true @titles_only = params[:titles_only] ? params[:titles_only].present? : false - + projects_to_search = case params[:scope] when 'all' @@ -38,16 +38,16 @@ else @project end - + offset = nil begin; offset = params[:offset].to_time if params[:offset]; rescue; end - + # quick jump to an issue if @question.match(/^#?(\d+)$/) && Issue.visible.find_by_id($1.to_i) redirect_to :controller => "issues", :action => "show", :id => $1 return end - + @object_types = Redmine::Search.available_search_types.dup if projects_to_search.is_a? Project # don't search projects @@ -55,24 +55,24 @@ # only show what the user is allowed to view @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)} end - + @scope = @object_types.select {|t| params[t]} @scope = @object_types if @scope.empty? - + # extract tokens from the question # eg. hello "bye bye" => ["hello", "bye bye"] @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')} # tokens must be at least 2 characters long @tokens = @tokens.uniq.select {|w| w.length > 1 } - + if !@tokens.empty? # no more than 5 tokens to search for - @tokens.slice! 5..-1 if @tokens.size > 5 - + @tokens.slice! 5..-1 if @tokens.size > 5 + @project_matches = [] @results = [] @results_by_type = Hash.new {|h,k| h[k] = 0} - + limit = 10 @scope.each do |s| r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search, @@ -94,13 +94,13 @@ if params[:previous].nil? @pagination_previous_date = @results[0].event_datetime if offset && @results[0] if @results.size > limit - @pagination_next_date = @results[limit-1].event_datetime + @pagination_next_date = @results[limit-1].event_datetime @results = @results[0, limit] end else @pagination_next_date = @results[-1].event_datetime if offset && @results[-1] if @results.size > limit - @pagination_previous_date = @results[-(limit)].event_datetime + @pagination_previous_date = @results[-(limit)].event_datetime @results = @results[-(limit), limit] end end @@ -110,7 +110,7 @@ render :layout => false if request.xhr? end -private +private def find_optional_project return true unless params[:id] @project = Project.find(params[:id]) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/sys_controller.rb --- a/app/controllers/sys_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/sys_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,28 +1,29 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class SysController < ActionController::Base before_filter :check_enabled - + def projects p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') - render :xml => p.to_xml(:include => :repository) + # extra_info attribute from repository breaks activeresource client + render :xml => p.to_xml(:only => [:id, :identifier, :name, :is_public, :status], :include => {:repository => {:only => [:id, :url]}}) end - + def create_project_repository project = Project.find(params[:id]) if project.repository @@ -31,13 +32,13 @@ logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." project.repository = Repository.factory(params[:vendor], params[:repository]) if project.repository && project.repository.save - render :xml => project.repository, :status => 201 + render :xml => project.repository.to_xml(:only => [:id, :url]), :status => 201 else render :nothing => true, :status => 422 end end end - + def fetch_changesets projects = [] if params[:id] diff -r 487d96eac004 -r 5e80956cc792 app/controllers/time_entry_reports_controller.rb --- a/app/controllers/time_entry_reports_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/time_entry_reports_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -16,16 +16,16 @@ @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria} @criterias.uniq! @criterias = @criterias[0,3] - + @columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month' - + retrieve_date_range - + unless @criterias.empty? sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ') sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ') sql_condition = '' - + if @project.nil? sql_condition = Project.allowed_to_condition(User.current, :view_time_entries) elsif @issue.nil? @@ -41,9 +41,9 @@ sql << " (%s) AND" % sql_condition sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from), ActiveRecord::Base.connection.quoted_date(@to)] sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on" - + @hours = ActiveRecord::Base.connection.select_all(sql) - + @hours.each do |row| case @columns when 'year' @@ -56,9 +56,9 @@ row['day'] = "#{row['spent_on']}" end end - + @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} - + @periods = [] # Date#at_beginning_of_ not supported in Rails 1.2.x date_from = @from.to_time @@ -80,13 +80,13 @@ end end end - + respond_to do |format| format.html { render :layout => !request.xhr? } format.csv { send_data(report_to_csv(@criterias, @periods, @hours), :type => 'text/csv; header=present', :filename => 'timelog.csv') } end end - + private # TODO: duplicated in TimelogController @@ -141,7 +141,7 @@ else # default end - + @from, @to = @to, @from if @from && @to && @from > @to @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) @@ -170,7 +170,7 @@ :klass => Issue, :label => :label_issue} } - + # Add list and boolean custom fields as available criterias custom_fields = (@project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields) custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf| @@ -178,7 +178,7 @@ :format => cf.field_format, :label => cf.name} end if @project - + # Add list and boolean time entry custom fields TimeEntryCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id)", diff -r 487d96eac004 -r 5e80956cc792 app/controllers/timelog_controller.rb --- a/app/controllers/timelog_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/timelog_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -24,14 +24,14 @@ before_filter :find_optional_project, :only => [:index] accept_rss_auth :index accept_api_auth :index, :show, :create, :update, :destroy - + helper :sort include SortHelper helper :issues include TimelogHelper helper :custom_fields include CustomFieldsHelper - + def index sort_init 'spent_on', 'desc' sort_update 'spent_on' => 'spent_on', @@ -40,14 +40,14 @@ 'project' => "#{Project.table_name}.name", 'issue' => 'issue_id', 'hours' => 'hours' - + cond = ARCondition.new if @issue cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" elsif @project cond << @project.project_condition(Setting.display_subprojects_issues?) end - + retrieve_date_range cond << ['spent_on BETWEEN ? AND ?', @from, @to] @@ -56,7 +56,7 @@ # Paginate results @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions) @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] - @entries = TimeEntry.visible.find(:all, + @entries = TimeEntry.visible.find(:all, :include => [:project, :activity, :user, {:issue => :tracker}], :conditions => cond.conditions, :order => sort_clause, @@ -69,7 +69,7 @@ format.api { @entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions) @offset, @limit = api_offset_and_limit - @entries = TimeEntry.visible.find(:all, + @entries = TimeEntry.visible.find(:all, :include => [:project, :activity, :user, {:issue => :tracker}], :conditions => cond.conditions, :order => sort_clause, @@ -86,7 +86,7 @@ } format.csv { # Export all entries - @entries = TimeEntry.visible.find(:all, + @entries = TimeEntry.visible.find(:all, :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :conditions => cond.conditions, :order => sort_clause) @@ -94,7 +94,7 @@ } end end - + def show respond_to do |format| # TODO: Implement html response @@ -106,7 +106,7 @@ def new @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry.attributes = params[:time_entry] - + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) render :action => 'edit' end @@ -115,9 +115,9 @@ def create @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry.attributes = params[:time_entry] - + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) - + if @time_entry.save respond_to do |format| format.html { @@ -131,21 +131,21 @@ format.html { render :action => 'edit' } format.api { render_validation_errors(@time_entry) } end - end + end end - + def edit @time_entry.attributes = params[:time_entry] - + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) end verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } def update @time_entry.attributes = params[:time_entry] - + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) - + if @time_entry.save respond_to do |format| format.html { @@ -159,7 +159,7 @@ format.html { render :action => 'edit' } format.api { render_validation_errors(@time_entry) } end - end + end end def bulk_edit @@ -186,7 +186,7 @@ verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } def destroy - @time_entries.each do |t| + @time_entries.each do |t| begin unless t.destroy && t.destroyed? respond_to do |format| @@ -258,7 +258,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def find_optional_project if !params[:issue_id].blank? @issue = Issue.find(params[:issue_id]) @@ -268,7 +268,7 @@ end deny_access unless User.current.allowed_to?(:view_time_entries, @project, :global => true) end - + # Retrieves the date range based on predefined ranges or specific from/to param dates def retrieve_date_range @free_period = false @@ -309,7 +309,7 @@ else # default end - + @from, @to = @to, @from if @from && @to && @from > @to @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) diff -r 487d96eac004 -r 5e80956cc792 app/controllers/trackers_controller.rb --- a/app/controllers/trackers_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/trackers_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,33 +1,46 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class TrackersController < ApplicationController layout 'admin' - - before_filter :require_admin - verify :method => :post, :only => :destroy, :redirect_to => { :action => :index } + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index def index - @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position' - render :action => "index", :layout => false if request.xhr? + respond_to do |format| + format.html { + @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position' + render :action => "index", :layout => false if request.xhr? + } + format.api { + @trackers = Tracker.all + } + end end def new + @tracker ||= Tracker.new(params[:tracker]) + @trackers = Tracker.find :all, :order => 'position' + @projects = Project.find(:all) + end + + def create @tracker = Tracker.new(params[:tracker]) if request.post? and @tracker.save # workflow copy @@ -38,20 +51,27 @@ redirect_to :action => 'index' return end - @trackers = Tracker.find :all, :order => 'position' - @projects = Project.find(:all) + new + render :action => 'new' end def edit + @tracker ||= Tracker.find(params[:id]) + @projects = Project.find(:all) + end + + def update @tracker = Tracker.find(params[:id]) - if request.post? and @tracker.update_attributes(params[:tracker]) + if request.put? and @tracker.update_attributes(params[:tracker]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' return end - @projects = Project.find(:all) + edit + render :action => 'edit' end - + + verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index } def destroy @tracker = Tracker.find(params[:id]) unless @tracker.issues.empty? @@ -60,5 +80,5 @@ @tracker.destroy end redirect_to :action => 'index' - end + end end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/users_controller.rb --- a/app/controllers/users_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/users_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,19 +5,19 @@ # 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. class UsersController < ApplicationController layout 'admin' - + before_filter :require_admin, :except => :show before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership] accept_api_auth :index, :show, :create, :update, :destroy @@ -25,22 +25,22 @@ helper :sort include SortHelper helper :custom_fields - include CustomFieldsHelper + include CustomFieldsHelper def index sort_init 'login', 'asc' sort_update %w(login firstname lastname mail admin created_on last_login_on) - + case params[:format] when 'xml', 'json' @offset, @limit = api_offset_and_limit else @limit = per_page_option end - + scope = User scope = scope.in_group(params[:group_id].to_i) if params[:group_id].present? - + @status = params[:status] ? params[:status].to_i : 1 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) @@ -48,7 +48,7 @@ name = "%#{params[:name].strip.downcase}%" c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name] end - + @user_count = scope.count(:conditions => c.conditions) @user_pages = Paginator.new self, @user_count, @limit, params['page'] @offset ||= @user_pages.current.offset @@ -66,7 +66,7 @@ format.api end end - + def show if @user.ssamr_user_detail != nil @@ -84,17 +84,17 @@ # show projects based on current user visibility @memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current)) - + events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) @events_by_day = events.group_by(&:event_date) - + unless User.current.admin? if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?) render_404 return end end - + respond_to do |format| format.html { render :layout => 'base' } format.api @@ -107,7 +107,7 @@ @ssamr_user_details = SsamrUserDetail.new end - + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) @@ -133,12 +133,12 @@ Mailer.deliver_account_information(@user, params[:user][:password]) if params[:send_information] - + respond_to do |format| format.html { flash[:notice] = l(:notice_successful_create) - redirect_to(params[:continue] ? - {:controller => 'users', :action => 'new'} : + redirect_to(params[:continue] ? + {:controller => 'users', :action => 'new'} : {:controller => 'users', :action => 'edit', :id => @user} ) } @@ -169,7 +169,7 @@ @auth_sources = AuthSource.find(:all) @membership ||= Member.new end - + verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } def update @user.admin = params[:user][:admin] if params[:user][:admin] @@ -213,7 +213,7 @@ elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil? Mailer.deliver_account_information(@user, params[:user][:password]) end - + respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) @@ -266,7 +266,7 @@ end end end - + def destroy_membership @membership = Member.find(params[:membership_id]) if request.post? && @membership.deletable? @@ -277,9 +277,9 @@ format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} } end end - + private - + def find_user if params[:id] == 'current' require_login || return diff -r 487d96eac004 -r 5e80956cc792 app/controllers/versions_controller.rb --- a/app/controllers/versions_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/versions_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,39 +23,53 @@ before_filter :find_project, :only => [:index, :new, :create, :close_completed] before_filter :authorize + accept_api_auth :index, :create, :update, :destroy + helper :custom_fields helper :projects def index - @trackers = @project.trackers.find(:all, :order => 'position') - retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) - @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') - project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] - - @versions = @project.shared_versions || [] - @versions += @project.rolled_up_versions.visible if @with_subprojects - @versions = @versions.uniq.sort - @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed] - - @issues_by_version = {} - unless @selected_tracker_ids.empty? - @versions.each do |version| - issues = version.fixed_issues.visible.find(:all, - :include => [:project, :status, :tracker, :priority], - :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids}, - :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") - @issues_by_version[version] = issues - end + respond_to do |format| + format.html { + @trackers = @project.trackers.find(:all, :order => 'position') + retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) + @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] + + @versions = @project.shared_versions || [] + @versions += @project.rolled_up_versions.visible if @with_subprojects + @versions = @versions.uniq.sort + @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed] + + @issues_by_version = {} + unless @selected_tracker_ids.empty? + @versions.each do |version| + issues = version.fixed_issues.visible.find(:all, + :include => [:project, :status, :tracker, :priority], + :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids}, + :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") + @issues_by_version[version] = issues + end + end + @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} + } + format.api { + @versions = @project.shared_versions.all + } end - @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} end - + def show - @issues = @version.fixed_issues.visible.find(:all, - :include => [:status, :tracker, :priority], - :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") + respond_to do |format| + format.html { + @issues = @version.fixed_issues.visible.find(:all, + :include => [:status, :tracker, :priority], + :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") + } + format.api + end end - + def new @version = @project.versions.build if params[:version] @@ -79,7 +93,7 @@ respond_to do |format| format.html do flash[:notice] = l(:notice_successful_create) - redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project end format.js do # IE doesn't support the replace_html rjs method for select box options @@ -87,6 +101,9 @@ content_tag('select', '' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]') } end + format.api do + render :action => 'show', :status => :created, :location => version_url(@version) + end end else respond_to do |format| @@ -94,6 +111,7 @@ format.js do render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) } end + format.api { render_validation_errors(@version) } end end end @@ -101,22 +119,28 @@ def edit end - + def update if request.put? && params[:version] attributes = params[:version].dup attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) if @version.update_attributes(attributes) - flash[:notice] = l(:notice_successful_update) - redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + } + format.api { head :ok } + end else respond_to do |format| format.html { render :action => 'edit' } + format.api { render_validation_errors(@version) } end end end end - + def close_completed if request.put? @project.close_completed_versions @@ -124,16 +148,25 @@ redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project end + verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } def destroy if @version.fixed_issues.empty? @version.destroy - redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + respond_to do |format| + format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project } + format.api { head :ok } + end else - flash[:error] = l(:notice_unable_delete_version) - redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + respond_to do |format| + format.html { + flash[:error] = l(:notice_unable_delete_version) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project + } + format.api { head :unprocessable_entity } + end end end - + def status_by respond_to do |format| format.html { render :action => 'show' } diff -r 487d96eac004 -r 5e80956cc792 app/controllers/watchers_controller.rb --- a/app/controllers/watchers_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/watchers_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,11 +19,11 @@ before_filter :find_project before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch] before_filter :authorize, :only => [:new, :destroy] - + verify :method => :post, :only => [ :watch, :unwatch ], :render => { :nothing => true, :status => :method_not_allowed } - + def watch if @watched.respond_to?(:visible?) && !@watched.visible?(User.current) render_403 @@ -31,11 +31,11 @@ set_watcher(User.current, true) end end - + def unwatch set_watcher(User.current, false) end - + def new @watcher = Watcher.new(params[:watcher]) @watcher.watchable = @watched @@ -51,7 +51,7 @@ rescue ::ActionController::RedirectBackError render :text => 'Watcher added.', :layout => true end - + def destroy @watched.set_watcher(User.find(params[:user_id]), false) if request.post? respond_to do |format| @@ -63,7 +63,7 @@ end end end - + private def find_project klass = Object.const_get(params[:object_type].camelcase) @@ -73,7 +73,7 @@ rescue render_404 end - + def set_watcher(user, watching) @watched.set_watcher(user, watching) respond_to do |format| diff -r 487d96eac004 -r 5e80956cc792 app/controllers/welcome_controller.rb --- a/app/controllers/welcome_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/welcome_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -35,7 +35,7 @@ end end - + def robots @projects = Project.all_public.active render :layout => false, :content_type => 'text/plain' diff -r 487d96eac004 -r 5e80956cc792 app/controllers/wiki_controller.rb --- a/app/controllers/wiki_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/wiki_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -40,6 +40,7 @@ helper :attachments include AttachmentsHelper helper :watchers + include Redmine::Export::PDF # List of pages, sorted alphabetically and by parent (hierarchy) def index @@ -71,7 +72,10 @@ end @content = @page.content_for_version(params[:version]) if User.current.allowed_to?(:export_wiki_pages, @project) - if params[:format] == 'html' + if params[:format] == 'pdf' + send_data(wiki_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf") + return + elsif params[:format] == 'html' export = render_to_string :action => 'export', :layout => false send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") return @@ -81,6 +85,10 @@ end end @editable = editable? + @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) && + @content.current_version? && + Redmine::WikiFormatting.supports_section_edit? + render :action => 'show' end @@ -96,6 +104,13 @@ # To prevent StaleObjectError exception when reverting to a previous version @content.version = @page.content.version + + @text = @content.text + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section) + render_404 if @text.blank? + end end verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } @@ -116,7 +131,17 @@ redirect_to :action => 'show', :project_id => @project, :id => @page.title return end - @content.attributes = params[:content] + + @content.comments = params[:content][:comments] + @text = params[:content][:text] + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @section_hash = params[:section_hash] + @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) + else + @content.version = params[:content][:version] + @content.text = @text + end @content.author = User.current # if page is new @page.save will also save content, but not if page isn't a new record if (@page.new_record? ? @page.save : @content.save) @@ -128,7 +153,7 @@ render :action => 'edit' end - rescue ActiveRecord::StaleObjectError + rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError # Optimistic locking exception flash.now[:error] = l(:notice_locking_conflict) render :action => 'edit' diff -r 487d96eac004 -r 5e80956cc792 app/controllers/wikis_controller.rb --- a/app/controllers/wikis_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/wikis_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ class WikisController < ApplicationController menu_item :settings before_filter :find_project, :authorize - + # Create or update a project's wiki def edit @wiki = @project.wiki || Wiki.new(:project => @project) @@ -32,6 +32,6 @@ if request.post? && params[:confirm] && @project.wiki @project.wiki.destroy redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'wiki' - end + end end end diff -r 487d96eac004 -r 5e80956cc792 app/controllers/workflows_controller.rb --- a/app/controllers/workflows_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/controllers/workflows_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,42 +1,42 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. class WorkflowsController < ApplicationController layout 'admin' - + before_filter :require_admin before_filter :find_roles before_filter :find_trackers - + def index @workflow_counts = Workflow.count_by_tracker_and_role end - + def edit @role = Role.find_by_id(params[:role_id]) - @tracker = Tracker.find_by_id(params[:tracker_id]) - + @tracker = Tracker.find_by_id(params[:tracker_id]) + if request.post? Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) (params[:issue_status] || []).each { |status_id, transitions| transitions.each { |new_status_id, options| author = options.is_a?(Array) && options.include?('author') && !options.include?('always') assignee = options.is_a?(Array) && options.include?('assignee') && !options.include?('always') - @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee) + @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee) } } if @role.save @@ -45,13 +45,13 @@ return end end - + @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) if @tracker && @used_statuses_only && @tracker.issue_statuses.any? @statuses = @tracker.issue_statuses end @statuses ||= IssueStatus.find(:all, :order => 'position') - + if @tracker && @role && @statuses.any? workflows = Workflow.all(:conditions => {:role_id => @role.id, :tracker_id => @tracker.id}) @workflows = {} @@ -60,9 +60,9 @@ @workflows['assignee'] = workflows.select {|w| w.assignee} end end - + def copy - + if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' @source_tracker = nil else @@ -73,10 +73,10 @@ else @source_role = Role.find_by_id(params[:source_role_id].to_i) end - + @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids]) @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids]) - + if request.post? if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) flash.now[:error] = l(:error_workflow_copy_source) @@ -95,7 +95,7 @@ def find_roles @roles = Role.find(:all, :order => 'builtin, position') end - + def find_trackers @trackers = Tracker.find(:all, :order => 'position') end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/account_helper.rb --- a/app/helpers/account_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/account_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/admin_helper.rb --- a/app/helpers/admin_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/admin_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,23 +1,25 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 AdminHelper def project_status_options_for_select(selected) - options_for_select([[l(:label_all), ''], + options_for_select([[l(:label_all), ''], [l(:status_active), 1]], selected) end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/application_helper.rb --- a/app/helpers/application_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/application_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -80,7 +82,7 @@ subject = truncate(subject, :length => options[:truncate]) end end - s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, + s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, :class => issue.css_classes, :title => title s << ": #{h subject}" if subject @@ -95,8 +97,10 @@ def link_to_attachment(attachment, options={}) text = options.delete(:text) || attachment.filename action = options.delete(:download) ? 'download' : 'show' - - link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options) + link_to(h(text), + {:controller => 'attachments', :action => action, + :id => attachment, :filename => attachment.filename }, + options) end # Generates a link to a SCM revision @@ -106,7 +110,7 @@ text = options.delete(:text) || format_revision(revision) rev = revision.respond_to?(:identifier) ? revision.identifier : revision - link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev}, + link_to(h(text), {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev}, :title => l(:label_revision_id, format_revision(revision))) end @@ -200,7 +204,7 @@ end content << "\n" end - content + content.html_safe end # Renders flash messages @@ -209,7 +213,7 @@ flash.each do |k,v| s << content_tag('div', v, :class => "flash #{k}") end - s + s.html_safe end # Renders tabs and their content @@ -233,7 +237,7 @@ { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) } end s << '' - s + s.html_safe end end @@ -250,7 +254,7 @@ tag_options.merge!(yield(project)) if block_given? s << content_tag('option', name_prefix + h(project), tag_options) end - s + s.html_safe end # Yields the given block for each project with its level in the tree @@ -281,7 +285,7 @@ end s << ("\n" * ancestors.size) end - s + s.html_safe end def principals_check_box_tags(name, principals) @@ -289,6 +293,20 @@ principals.sort.each do |principal| s << "\n" end + s.html_safe + end + + # Returns a string for users/groups option tags + def principals_options_for_select(collection, selected=nil) + s = '' + groups = '' + collection.sort.each do |element| + selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) + (element.is_a?(Group) ? groups : s) << %() + end + unless groups.empty? + s << %(#{groups}) + end s end @@ -308,11 +326,11 @@ end def html_hours(text) - text.gsub(%r{(\d+)\.(\d+)}, '\1.\2') + text.gsub(%r{(\d+)\.(\d+)}, '\1.\2').html_safe end def authoring(created, author, options={}) - l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)) + l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe end def time_tag(time) @@ -339,7 +357,10 @@ html = '' if paginator.current.previous - html << link_to_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' ' + # \xc2\xab(utf-8) = « + html << link_to_content_update( + "\xc2\xab " + l(:label_previous), + url_param.merge(page_param => paginator.current.previous)) + ' ' end html << (pagination_links_each(paginator, options) do |n| @@ -347,7 +368,10 @@ end || '') if paginator.current.next - html << ' ' + link_to_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next)) + # \xc2\xbb(utf-8) = » + html << ' ' + link_to_content_update( + (l(:label_next) + " \xc2\xbb"), + url_param.merge(page_param => paginator.current.next)) end unless count.nil? @@ -357,7 +381,7 @@ end end - html + html.html_safe end def per_page_links(selected=nil) @@ -367,22 +391,30 @@ links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil end - def reorder_links(name, url) - link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) + - link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) + - link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) + - link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest)) + def reorder_links(name, url, method = :post) + link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), + url.merge({"#{name}[move_to]" => 'highest'}), + :method => method, :title => l(:label_sort_highest)) + + link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), + url.merge({"#{name}[move_to]" => 'higher'}), + :method => method, :title => l(:label_sort_higher)) + + link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), + url.merge({"#{name}[move_to]" => 'lower'}), + :method => method, :title => l(:label_sort_lower)) + + link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), + url.merge({"#{name}[move_to]" => 'lowest'}), + :method => method, :title => l(:label_sort_lowest)) end def breadcrumb(*args) elements = args.flatten - elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil + elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil end def other_formats_links(&block) - concat('

    ' + l(:label_export_to)) + concat('

    '.html_safe + l(:label_export_to)) yield Redmine::Views::OtherFormatsBuilder.new(self) - concat('

    ') + concat('

    '.html_safe) end def page_header_title @@ -414,10 +446,9 @@ def html_title(*args) if args.empty? - title = [] + title = @html_title || [] title << @project.name if @project - title += @html_title if @html_title - title << Setting.app_title + title << Setting.app_title unless Setting.app_title == title.last title.select {|t| !t.blank? }.join(' - ') else @html_title ||= [] @@ -463,11 +494,12 @@ project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) only_path = options.delete(:only_path) == false ? false : true - text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) @parsed_headings = [] + @current_section = 0 if options[:edit_section_links] text = parse_non_pre_blocks(text) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| + [:parse_sections, :parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros, :parse_headings].each do |method_name| send method_name, text, project, obj, attr, only_path, options end end @@ -505,26 +537,26 @@ while tag = tags.pop parsed << "" end - parsed + parsed.html_safe end def parse_inline_attachments(text, project, obj, attr, only_path, options) # when using an image link, try to use an attachment, if possible if options[:attachments] || (obj && obj.respond_to?(:attachments)) - attachments = nil - text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| + attachments = options[:attachments] || obj.attachments + text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| filename, ext, alt, alttext = $1.downcase, $2, $3, $4 - attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse # search for the picture in attachments - if found = attachments.detect { |att| att.filename.downcase == filename } - image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found + if found = Attachment.latest_attach(attachments, filename) + image_url = url_for :only_path => only_path, :controller => 'attachments', + :action => 'download', :id => found desc = found.description.to_s.gsub('"', '') if !desc.blank? && alttext.blank? alt = " title=\"#{desc}\" alt=\"#{desc}\"" end - "src=\"#{image_url}\"#{alt}" + "src=\"#{image_url}\"#{alt}".html_safe else - m + m.html_safe end end end @@ -557,22 +589,27 @@ if page =~ /^(.+?)\#(.+)$/ page, anchor = $1, $2 end + anchor = sanitize_anchor_name(anchor) if anchor.present? # check if page exists wiki_page = link_project.wiki.find_page(page) - url = case options[:wiki_links] - when :local; "#{title}.html" - when :anchor; "##{title}" # used for single-file wiki export + url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page + "##{anchor}" + else + case options[:wiki_links] + when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') + when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export else wiki_page_id = page.present? ? Wiki.titleize(page) : nil url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor) end - link_to((title || page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) + end + link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) else # project or wiki doesn't exist - all + all.html_safe end else - all + all.html_safe end end end @@ -610,7 +647,7 @@ # identifier:version:1.0.0 # identifier:source:some/file def parse_redmine_links(text, project, obj, attr, only_path, options) - text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m| + text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m| leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10 link = nil if project_identifier @@ -620,7 +657,7 @@ if prefix.nil? && sep == 'r' # project.changesets.visible raises an SQL error because of a double join on repositories if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier)) - link = link_to("#{project_prefix}r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, + link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, :class => 'changeset', :title => truncate_single_line(changeset.comments, :length => 100)) end @@ -647,6 +684,16 @@ if message = Message.visible.find_by_id(oid, :include => :parent) link = link_to_message(message, {:only_path => only_path}, :class => 'message') end + when 'forum' + if board = Board.visible.find_by_id(oid) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if news = News.visible.find_by_id(oid) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end when 'project' if p = Project.visible.find_by_id(oid) link = link_to_project(p, {:only_path => only_path}, :class => 'project') @@ -666,11 +713,21 @@ link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, :class => 'version' end + when 'forum' + if project && board = project.boards.visible.find_by_name(name) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if project && news = project.news.visible.find_by_title(name) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end when 'commit' if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"])) link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier}, :class => 'changeset', - :title => truncate_single_line(changeset.comments, :length => 100) + :title => truncate_single_line(h(changeset.comments), :length => 100) end when 'source', 'export' if project && project.repository && User.current.allowed_to?(:browse_repository, project) @@ -696,11 +753,26 @@ end end end - leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}") + (leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe end end - HEADING_RE = /]+)?>(.+?)<\/h(1|2|3|4)>/i unless const_defined?(:HEADING_RE) + HEADING_RE = /(]+)?>(.+?)<\/h(1|2|3|4)>)/i unless const_defined?(:HEADING_RE) + + def parse_sections(text, project, obj, attr, only_path, options) + return unless options[:edit_section_links] + text.gsub!(HEADING_RE) do + @current_section += 1 + if @current_section > 1 + content_tag('div', + link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)), + :class => 'contextual', + :title => l(:button_edit_section)) + $1 + else + $1 + end + end + end # Headings and TOC # Adds ids and links to headings unless options[:headings] is set to false @@ -708,14 +780,43 @@ return if options[:headings] == false text.gsub!(HEADING_RE) do - level, attrs, content = $1.to_i, $2, $3 + level, attrs, content = $2.to_i, $3, $4 item = strip_tags(content).strip - anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + anchor = sanitize_anchor_name(item) + # used for single-file wiki export + anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) @parsed_headings << [level, anchor, item] "\n#{content}" end end + MACROS_RE = / + (!)? # escaping + ( + \{\{ # opening tag + ([\w]+) # macro name + (\(([^\}]*)\))? # optional arguments + \}\} # closing tag + ) + /x unless const_defined?(:MACROS_RE) + + # Macros substitution + def parse_macros(text, project, obj, attr, only_path, options) + text.gsub!(MACROS_RE) do + esc, all, macro = $1, $2, $3.downcase + args = ($5 || '').split(',').each(&:strip) + if esc.nil? + begin + exec_macro(macro, obj, args) + rescue => e + "
    Error executing the #{macro} macro (#{e})
    " + end || all + else + all + end + end + end + TOC_RE = /

    \{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) # Renders the TOC with given headings @@ -754,7 +855,8 @@ text.to_s. gsub(/\r\n?/, "\n"). # \r\n and \r -> \n gsub(/\n\n+/, "

    "). # 2+ newline -> 2 br - gsub(/([^\n]\n)(?=[^\n])/, '\1
    ') # 1 newline -> br + gsub(/([^\n]\n)(?=[^\n])/, '\1
    '). # 1 newline -> br + html_safe end def lang_options_for_select(blank=true) @@ -767,10 +869,20 @@ content_tag("label", label_text) end - def labelled_tabular_form_for(name, object, options, &proc) + def labelled_tabular_form_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last options[:html] ||= {} options[:html][:class] = 'tabular' unless options[:html].has_key?(:class) - form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc) + options.merge!({:builder => TabularFormBuilder}) + form_for(*args, &proc) + end + + def labelled_form_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + options.merge!({:builder => TabularFormBuilder}) + form_for(*args, &proc) end def back_url_hidden_field_tag @@ -781,7 +893,7 @@ def check_all_links(form_name) link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + - " | " + + " | ".html_safe + link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") end @@ -794,11 +906,11 @@ legend = options[:legend] || '' content_tag('table', content_tag('tr', - (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : '') + - (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : '') + - (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : '') - ), :class => 'progress', :style => "width: #{width};") + - content_tag('p', legend, :class => 'pourcent') + (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + + (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + + (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) + ), :class => 'progress', :style => "width: #{width};").html_safe + + content_tag('p', legend, :class => 'pourcent').html_safe end def checked_image(checked=true) @@ -836,7 +948,7 @@ options[:class] << ' disabled' url = '#' end - link_to name, url, options + link_to h(name), url, options end def calendar_for(field_id) @@ -879,6 +991,10 @@ (@has_content && @has_content[name]) || false end + def email_delivery_enabled? + !!ActionMailer::Base.perform_deliveries + end + # Returns the avatar image tag for the given +user+ if avatars are enabled # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe ') def avatar(user, options = { }) @@ -896,21 +1012,25 @@ end end + def sanitize_anchor_name(anchor) + anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + end + # Returns the javascript tags that are included in the html layout head def javascript_heads tags = javascript_include_tag(:defaults) unless User.current.pref.warn_on_leaving_unsaved == '0' - tags << "\n" + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });") + tags << "\n".html_safe + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });") end tags end def favicon - "" + "".html_safe end def robot_exclusion_tag - '' + ''.html_safe end def stylesheet_platform_font_tag diff -r 487d96eac004 -r 5e80956cc792 app/helpers/attachments_helper.rb --- a/app/helpers/attachments_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/attachments_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -28,19 +30,16 @@ end end - def to_utf8(str) - if str.respond_to?(:force_encoding) - str.force_encoding('UTF-8') - return str if str.valid_encoding? - else - return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii - end - - begin - Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3] - rescue Iconv::InvalidEncoding - # "UTF-8//IGNORE" is not supported on some OS - str + def render_api_attachment(attachment, api) + api.attachment do + api.id attachment.id + api.filename attachment.filename + api.filesize attachment.filesize + api.content_type attachment.content_type + api.description attachment.description + api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) + api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author + api.created_on attachment.created_on end end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/auth_sources_helper.rb --- a/app/helpers/auth_sources_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/auth_sources_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/boards_helper.rb --- a/app/helpers/boards_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/boards_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/calendars_helper.rb --- a/app/helpers/calendars_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/calendars_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,22 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 CalendarsHelper def link_to_previous_month(year, month, options={}) target_year, target_month = if month == 1 @@ -5,14 +24,15 @@ else [year, month - 1] end - + name = if target_month == 12 "#{month_name(target_month)} #{target_year}" else "#{month_name(target_month)}" end - link_to_month(('« ' + name), target_year, target_month, options) + # \xc2\xab(utf-8) = « + link_to_month(("\xc2\xab " + name), target_year, target_month, options) end def link_to_next_month(year, month, options={}) @@ -28,10 +48,11 @@ "#{month_name(target_month)}" end - link_to_month((name + ' »'), target_year, target_month, options) + # \xc2\xbb(utf-8) = » + link_to_month((name + " \xc2\xbb"), target_year, target_month, options) end def link_to_month(link_name, year, month, options={}) - link_to_content_update(link_name, params.merge(:year => year, :month => month)) + link_to_content_update(h(link_name), params.merge(:year => year, :month => month)) end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/custom_fields_helper.rb --- a/app/helpers/custom_fields_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/custom_fields_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,12 +7,12 @@ # 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. @@ -29,7 +31,7 @@ {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName} ] end - + # Return custom field html tag corresponding to its format def custom_field_tag(name, custom_value) custom_field = custom_value.custom_field @@ -39,7 +41,7 @@ field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) case field_format.try(:edit_as) when "date" - text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) + + text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) + calendar_for(field_id) when "text" text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%') @@ -47,34 +49,34 @@ hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id) when "list" blank_option = custom_field.is_required? ? - (custom_field.default_value.blank? ? "" : '') : + (custom_field.default_value.blank? ? "" : '') : '' select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id) else text_field_tag(field_name, custom_value.value, :id => field_id) end end - + # Return custom field label tag def custom_field_label_tag(name, custom_value) - content_tag "label", custom_value.custom_field.name + - (custom_value.custom_field.is_required? ? " *" : ""), + content_tag "label", h(custom_value.custom_field.name) + + (custom_value.custom_field.is_required? ? " *".html_safe : ""), :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}", :class => (custom_value.errors.empty? ? nil : "error" ) end - + # Return custom field tag with its label tag def custom_field_tag_with_label(name, custom_value) custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) end - + def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil) field_name = "#{name}[custom_field_values][#{custom_field.id}]" field_id = "#{name}_custom_field_values_#{custom_field.id}" field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) case field_format.try(:edit_as) when "date" - text_field_tag(field_name, '', :id => field_id, :size => 10) + + text_field_tag(field_name, '', :id => field_id, :size => 10) + calendar_for(field_id) when "text" text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%') @@ -94,7 +96,7 @@ return "" unless custom_value format_value(custom_value.value, custom_value.custom_field.field_format) end - + # Return a string used to display a custom value def format_value(value, field_format) Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy @@ -104,7 +106,7 @@ def custom_field_formats_for_select(custom_field) Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name) end - + # Renders the custom_values in api views def render_api_custom_values(custom_values, api) api.array :custom_fields do diff -r 487d96eac004 -r 5e80956cc792 app/helpers/documents_helper.rb --- a/app/helpers/documents_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/documents_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/enumerations_helper.rb --- a/app/helpers/enumerations_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/enumerations_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/gantt_helper.rb --- a/app/helpers/gantt_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/gantt_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,12 +7,12 @@ # 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. @@ -25,16 +27,16 @@ params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), :class => 'icon icon-zoom-in' else - content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in') + content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe end - + when :out if gantt.zoom > 1 link_to_content_update l(:text_zoom_out), params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), :class => 'icon icon-zoom-out' else - content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out') + content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe end end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/groups_helper.rb --- a/app/helpers/groups_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/groups_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ +# encoding: utf-8 +# # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -24,7 +26,7 @@ end options end - + def group_settings_tabs tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general}, {:name => 'users', :partial => 'groups/users', :label => :label_user_plural}, diff -r 487d96eac004 -r 5e80956cc792 app/helpers/issue_categories_helper.rb --- a/app/helpers/issue_categories_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/issue_categories_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/issue_moves_helper.rb --- a/app/helpers/issue_moves_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/issue_moves_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,2 +1,4 @@ +# encoding: utf-8 +# module IssueMovesHelper end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/issue_relations_helper.rb --- a/app/helpers/issue_relations_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/issue_relations_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/issue_statuses_helper.rb --- a/app/helpers/issue_statuses_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/issue_statuses_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/issues_helper.rb --- a/app/helpers/issues_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/issues_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -46,13 +48,13 @@ @cached_label_priority ||= l(:field_priority) @cached_label_project ||= l(:field_project) - link_to_issue(issue) + "

    " + + (link_to_issue(issue) + "

    " + "#{@cached_label_project}: #{link_to_project(issue.project)}
    " + - "#{@cached_label_status}: #{issue.status.name}
    " + + "#{@cached_label_status}: #{h(issue.status.name)}
    " + "#{@cached_label_start_date}: #{format_date(issue.start_date)}
    " + "#{@cached_label_due_date}: #{format_date(issue.due_date)}
    " + - "#{@cached_label_assigned_to}: #{issue.assigned_to}
    " + - "#{@cached_label_priority}: #{issue.priority.name}" + "#{@cached_label_assigned_to}: #{h(issue.assigned_to)}
    " + + "#{@cached_label_priority}: #{h(issue.priority.name)}").html_safe end def issue_heading(issue) @@ -72,7 +74,7 @@ end s << content_tag('h3', subject) s << '' * (ancestors.size + 1) - s + s.html_safe end def render_descendants_tree(issue) @@ -87,7 +89,7 @@ :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}") end s << '' - s + s.html_safe end def render_custom_fields_rows(issue) @@ -106,7 +108,7 @@ n += 1 end s << "\n" - s + s.html_safe end def issues_destroy_confirmation_message(issues) @@ -145,7 +147,7 @@ # links to #index on issues/show url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params - content_tag('h3', title) + + content_tag('h3', h(title)) + queries.collect {|query| link_to(h(query.name), url_params.merge(:query_id => query)) }.join('
    ') @@ -206,7 +208,7 @@ unless no_html label = content_tag('strong', label) old_value = content_tag("i", h(old_value)) if detail.old_value - old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?) + old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank? if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key) # Link to the attachment if it has not been removed value = link_to_attachment(a) @@ -263,59 +265,38 @@ end end - def issues_to_csv(issues, project = nil) - ic = Iconv.new(l(:general_csv_encoding), 'UTF-8') + def issues_to_csv(issues, project, query, options={}) decimal_separator = l(:general_csv_decimal_separator) + encoding = l(:general_csv_encoding) + columns = (options[:columns] == 'all' ? query.available_columns : query.columns) + export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| # csv header fields - headers = [ "#", - l(:field_status), - l(:field_project), - l(:field_tracker), - l(:field_priority), - l(:field_subject), - l(:field_assigned_to), - l(:field_category), - l(:field_fixed_version), - l(:field_author), - l(:field_start_date), - l(:field_due_date), - l(:field_done_ratio), - l(:field_estimated_hours), - l(:field_parent_issue), - l(:field_created_on), - l(:field_updated_on) - ] - # Export project custom fields if project is given - # otherwise export custom fields marked as "For all projects" - custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields - custom_fields.each {|f| headers << f.name} - # Description in the last column - headers << l(:field_description) - csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } + csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + + (options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : []) + # csv lines issues.each do |issue| - fields = [issue.id, - issue.status.name, - issue.project.name, - issue.tracker.name, - issue.priority.name, - issue.subject, - issue.assigned_to, - issue.category, - issue.fixed_version, - issue.author.name, - format_date(issue.start_date), - format_date(issue.due_date), - issue.done_ratio, - issue.estimated_hours.to_s.gsub('.', decimal_separator), - issue.parent_id, - format_time(issue.created_on), - format_time(issue.updated_on) - ] - custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) } - fields << issue.description - csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } + col_values = columns.collect do |column| + s = if column.is_a?(QueryCustomFieldColumn) + cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} + show_value(cv) + else + value = issue.send(column.name) + if value.is_a?(Date) + format_date(value) + elsif value.is_a?(Time) + format_time(value) + elsif value.is_a?(Float) + value.to_s.gsub('.', decimal_separator) + else + value + end + end + s.to_s + end + csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } + + (options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : []) end end export diff -r 487d96eac004 -r 5e80956cc792 app/helpers/journals_helper.rb --- a/app/helpers/journals_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/journals_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -24,7 +26,7 @@ links << link_to_remote(image_tag('comment.png'), { :url => {:controller => 'journals', :action => 'new', :id => issue, :journal_id => journal} }, :title => l(:button_quote)) if options[:reply_links] - links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", + links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", { :controller => 'journals', :action => 'edit', :id => journal }, :title => l(:button_edit)) if editable end @@ -34,7 +36,7 @@ css_classes << " editable" if editable content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes) end - + def link_to_in_place_notes_editor(text, field_id, url, options={}) onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;" link_to text, '#', options.merge(:onclick => onclick) diff -r 487d96eac004 -r 5e80956cc792 app/helpers/mail_handler_helper.rb --- a/app/helpers/mail_handler_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/mail_handler_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/members_helper.rb --- a/app/helpers/members_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/members_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/messages_helper.rb --- a/app/helpers/messages_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/messages_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/my_helper.rb --- a/app/helpers/my_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/my_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/news_helper.rb --- a/app/helpers/news_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/news_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/projects_helper.rb --- a/app/helpers/projects_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/projects_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -46,7 +48,7 @@ options = '' options << "" if project.allowed_parents.include?(nil) options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) - content_tag('select', options, :name => 'project[parent_id]', :id => 'project_parent_id') + content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') end def render_project_short_description(project) @@ -90,7 +92,7 @@ s << ("\n" * ancestors.size) @project = original_project end - s + s.html_safe end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/queries_helper.rb --- a/app/helpers/queries_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/queries_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,31 +7,31 @@ # 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 QueriesHelper - + def operators_for_select(filter_type) Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]} end - + def column_header(column) column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, - :default_order => column.default_order) : - content_tag('th', column.caption) + :default_order => column.default_order) : + content_tag('th', h(column.caption)) end - + def column_content(column, issue) value = column.value(issue) - + case value.class.name when 'String' if column.name == :subject @@ -45,7 +47,7 @@ if column.name == :done_ratio progress_bar(value, :width => '80px') else - value.to_s + h(value.to_s) end when 'User' link_to_user value @@ -74,27 +76,30 @@ @query.project = @project session[:query] = {:id => @query.id, :project_id => @query.project_id} sort_clear + elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) + # Give it a name, required to be valid + @query = Query.new(:name => "_") + @query.project = @project + build_query_from_params + session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} else - if api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) - # Give it a name, required to be valid - @query = Query.new(:name => "_") - @query.project = @project - if params[:fields] || params[:f] - @query.filters = {} - @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) - else - @query.available_filters.keys.each do |field| - @query.add_short_filter(field, params[field]) if params[field] - end - end - @query.group_by = params[:group_by] - @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) - session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} - else - @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] - @query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) - @query.project = @project + # retrieve from session + @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] + @query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) + @query.project = @project + end + end + + def build_query_from_params + if params[:fields] || params[:f] + @query.filters = {} + @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) + else + @query.available_filters.keys.each do |field| + @query.add_short_filter(field, params[field]) if params[field] end end + @query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) + @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/reports_helper.rb --- a/app/helpers/reports_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/reports_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -31,6 +33,6 @@ def aggregate_link(data, criteria, *args) a = aggregate data, criteria - a > 0 ? link_to(a, *args) : '-' + a > 0 ? link_to(h(a), *args) : '-' end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/repositories_helper.rb --- a/app/helpers/repositories_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/repositories_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -37,9 +39,9 @@ unless properties.nil? || properties.empty? content = '' properties.keys.sort.each do |property| - content << content_tag('li', "#{h property}: #{h properties[property]}") + content << content_tag('li', "#{h property}: #{h properties[property]}".html_safe) end - content_tag('ul', content, :class => 'properties') + content_tag('ul', content.html_safe, :class => 'properties') end end @@ -87,7 +89,7 @@ if s = tree[file][:s] style << ' folder' path_param = to_path_param(@repository.relative_path(file)) - text = link_to(text, :controller => 'repositories', + text = link_to(h(text), :controller => 'repositories', :action => 'show', :id => @project, :path => path_param, @@ -97,56 +99,25 @@ elsif c = tree[file][:c] style << " change-#{c.action}" path_param = to_path_param(@repository.relative_path(c.path)) - text = link_to(text, :controller => 'repositories', + text = link_to(h(text), :controller => 'repositories', :action => 'entry', :id => @project, :path => path_param, :rev => @changeset.identifier) unless c.action == 'D' - text << " - #{c.revision}" unless c.revision.blank? - text << ' (' + link_to('diff', :controller => 'repositories', + text << " - #{h(c.revision)}" unless c.revision.blank? + text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories', :action => 'diff', :id => @project, :path => path_param, - :rev => @changeset.identifier) + ') ' if c.action == 'M' - text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank? + :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M' + text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank? output << "

  • #{text}
  • " end end output << '' - output + output.html_safe end - def to_utf8(str) - return str if str.nil? - str = to_utf8_internal(str) - if str.respond_to?(:force_encoding) - str.force_encoding('UTF-8') - end - str - end - - def to_utf8_internal(str) - return str if str.nil? - if str.respond_to?(:force_encoding) - str.force_encoding('ASCII-8BIT') - end - return str if str.empty? - return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii - if str.respond_to?(:force_encoding) - str.force_encoding('UTF-8') - end - @encodings ||= Setting.repositories_encodings.split(',').collect(&:strip) - @encodings.each do |encoding| - begin - return Iconv.conv('UTF-8', encoding, str) - rescue Iconv::Failure - # do nothing here and try the next encoding - end - end - str = Redmine::CodesetUtil.replace_invalid_utf8(str) - end - private :to_utf8_internal - def repository_field_tags(form, repository) method = repository.class.name.demodulize.underscore + "_field_tags" if repository.is_a?(Repository) && @@ -188,7 +159,8 @@ def subversion_field_tags(form, repository) content_tag('p', form.text_field(:url, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + - '
    (file:///, http://, https://, svn://, svn+[tunnelscheme]://)') + + '
    '.html_safe + + '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') + content_tag('p', form.text_field(:login, :size => 30)) + content_tag('p', form.password_field( :password, :size => 30, :name => 'ignore', @@ -213,12 +185,12 @@ :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?) ) + - '
    ' + l(:text_mercurial_repository_note)) + + '
    '.html_safe + l(:text_mercurial_repository_note)) + content_tag('p', form.select( :path_encoding, [nil] + Setting::ENCODINGS, :label => l(:field_scm_path_encoding) ) + - '
    ' + l(:text_scm_path_encoding_note)) + '
    '.html_safe + l(:text_scm_path_encoding_note)) end def git_field_tags(form, repository) @@ -227,12 +199,13 @@ :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?) ) + - '
    ' + l(:text_git_repository_note)) + + '
    '.html_safe + + l(:text_git_repository_note)) + content_tag('p', form.select( :path_encoding, [nil] + Setting::ENCODINGS, :label => l(:field_scm_path_encoding) ) + - '
    ' + l(:text_scm_path_encoding_note)) + + '
    '.html_safe + l(:text_scm_path_encoding_note)) + content_tag('p', form.check_box( :extra_report_last_commit, :label => l(:label_git_report_last_commit) @@ -257,7 +230,7 @@ :path_encoding, [nil] + Setting::ENCODINGS, :label => l(:field_scm_path_encoding) ) + - '
    ' + l(:text_scm_path_encoding_note)) + '
    '.html_safe + l(:text_scm_path_encoding_note)) end def bazaar_field_tags(form, repository) @@ -279,7 +252,63 @@ :path_encoding, [nil] + Setting::ENCODINGS, :label => l(:field_scm_path_encoding) ) + - '
    ' + l(:text_scm_path_encoding_note)) + '
    '.html_safe + l(:text_scm_path_encoding_note)) + end + + def index_commits(commits, heads, href_proc = nil) + return nil if commits.nil? or commits.first.parents.nil? + map = {} + commit_hashes = [] + refs_map = {} + href_proc ||= Proc.new {|x|x} + heads.each{|r| refs_map[r.scmid] ||= []; refs_map[r.scmid] << r} + commits.reverse.each_with_index do |c, i| + h = {} + h[:parents] = c.parents.collect do |p| + [p.scmid, 0, 0] + end + h[:rdmid] = i + h[:space] = 0 + h[:refs] = refs_map[c.scmid].join(" ") if refs_map.include? c.scmid + h[:scmid] = c.scmid + h[:href] = href_proc.call(c.scmid) + commit_hashes << h + map[c.scmid] = h + end + heads.sort! do |a,b| + a.to_s <=> b.to_s + end + j = 0 + heads.each do |h| + if map.include? h.scmid then + j = mark_chain(j += 1, map[h.scmid], map) + end + end + # when no head matched anything use first commit + if j == 0 then + mark_chain(j += 1, map.values.first, map) + end + map + end + + def mark_chain(mark, commit, map) + stack = [[mark, commit]] + markmax = mark + until stack.empty? + current = stack.pop + m, commit = current + commit[:space] = m if commit[:space] == 0 + m1 = m - 1 + commit[:parents].each_with_index do |p, i| + psha = p[0] + if map.include? psha and map[psha][:space] == 0 then + stack << [m1 += 1, map[psha]] if i == 0 + stack = [[m1 += 1, map[psha]]] + stack if i > 0 + end + end + markmax = m1 if markmax < m1 + end + markmax end # Generates a link to a downloadable archive for a revision diff -r 487d96eac004 -r 5e80956cc792 app/helpers/repositories_helper.rb.rej --- a/app/helpers/repositories_helper.rb.rej Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ ---- app/helpers/repositories_helper.rb -+++ app/helpers/repositories_helper.rb -@@ -52,17 +52,19 @@ - else - change - end -- end.compact -+ end.compact - - tree = { } - changes.each do |change| - p = tree - dirs = change.path.to_s.split('/').select {|d| !d.blank?} -+ path = '' - dirs.each do |dir| -+ path += '/' + dir - p[:s] ||= {} - p = p[:s] -- p[dir] ||= {} -- p = p[dir] -+ p[path] ||= {} -+ p = p[path] - end - p[:c] = change - end -@@ -76,21 +78,26 @@ - output = '' - output << '
      ' - tree.keys.sort.each do |file| -- s = !tree[file][:s].nil? -- c = tree[file][:c] -- - style = 'change' -- style << ' folder' if s -- style << " change-#{c.action}" if c -- -- text = h(file) -- unless c.nil? -+ text = File.basename(h(file)) -+ if s = tree[file][:s] -+ style << ' folder' -+ path_param = to_path_param(@repository.relative_path(file)) -+ text = link_to(text, :controller => 'repositories', -+ :action => 'show', -+ :id => @project, -+ :path => path_param, -+ :rev => @changeset.revision) -+ output << "
    • #{text}
    • " -+ output << render_changes_tree(s) -+ elsif c = tree[file][:c] -+ style << " change-#{c.action}" - path_param = to_path_param(@repository.relative_path(c.path)) - text = link_to(text, :controller => 'repositories', - :action => 'entry', - :id => @project, - :path => path_param, -- :rev => @changeset.revision) unless s || c.action == 'D' -+ :rev => @changeset.revision) unless c.action == 'D' - text << " - #{c.revision}" unless c.revision.blank? - text << ' (' + link_to('diff', :controller => 'repositories', - :action => 'diff', -@@ -98,9 +105,8 @@ - :path => path_param, - :rev => @changeset.revision) + ') ' if c.action == 'M' - text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank? -+ output << "
    • #{text}
    • " - end -- output << "
    • #{text}
    • " -- output << render_changes_tree(tree[file][:s]) if s - end - output << '
    ' - output diff -r 487d96eac004 -r 5e80956cc792 app/helpers/roles_helper.rb --- a/app/helpers/roles_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/roles_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/search_helper.rb --- a/app/helpers/search_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/search_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,12 +7,12 @@ # 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. @@ -19,7 +21,7 @@ def highlight_tokens(text, tokens) return text unless text && tokens && !tokens.empty? re_tokens = tokens.collect {|t| Regexp.escape(t)} - regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE + regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE result = '' text.split(regexp).each_with_index do |words, i| if result.length > 1200 @@ -37,19 +39,20 @@ end result end - + def type_label(t) l("label_#{t.singularize}_plural", :default => t.to_s.humanize) end - + def project_select_tag options = [[l(:label_project_all), 'all']] options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? options << [@project.name, ''] unless @project.nil? + label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") + select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 end - + def render_results_by_type(results_by_type) links = [] # Sorts types by results count @@ -57,7 +60,8 @@ c = results_by_type[t] next if c == 0 text = "#{type_label(t)} (#{c})" - links << link_to(text, :q => params[:q], :titles_only => params[:titles_only], :all_words => params[:all_words], :scope => params[:scope], t => 1) + links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only], + :all_words => params[:all_words], :scope => params[:scope], t => 1) end ('
      ' + links.map {|link| content_tag('li', link)}.join(' ') + '
    ') unless links.empty? end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/settings_helper.rb --- a/app/helpers/settings_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/settings_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -32,18 +34,18 @@ if blank_text = options.delete(:blank) choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices end - setting_label(setting, options) + + setting_label(setting, options).html_safe + select_tag("settings[#{setting}]", options_for_select(choices, Setting.send(setting).to_s), - options) + options).html_safe end def setting_multiselect(setting, choices, options={}) setting_values = Setting.send(setting) setting_values = [] unless setting_values.is_a?(Array) - setting_label(setting, options) + - hidden_field_tag("settings[#{setting}][]", '') + + setting_label(setting, options).html_safe + + hidden_field_tag("settings[#{setting}][]", '').html_safe + choices.collect do |choice| text, value = (choice.is_a?(Array) ? choice : [choice, choice]) content_tag( @@ -55,28 +57,28 @@ ) + text.to_s, :class => 'block' ) - end.join + end.join.html_safe end def setting_text_field(setting, options={}) - setting_label(setting, options) + - text_field_tag("settings[#{setting}]", Setting.send(setting), options) + setting_label(setting, options).html_safe + + text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe end def setting_text_area(setting, options={}) - setting_label(setting, options) + - text_area_tag("settings[#{setting}]", Setting.send(setting), options) + setting_label(setting, options).html_safe + + text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe end def setting_check_box(setting, options={}) - setting_label(setting, options) + - hidden_field_tag("settings[#{setting}]", 0) + - check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options) + setting_label(setting, options).html_safe + + hidden_field_tag("settings[#{setting}]", 0).html_safe + + check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe end def setting_label(setting, options={}) label = options.delete(:label) - label != false ? content_tag("label", l(label || "setting_#{setting}")) : '' + label != false ? content_tag("label", l(label || "setting_#{setting}")).html_safe : '' end # Renders a notification field for a Redmine::Notifiable option @@ -84,8 +86,8 @@ return content_tag(:label, check_box_tag('settings[notified_events][]', notifiable.name, - Setting.notified_events.include?(notifiable.name)) + - l_or_humanize(notifiable.name, :prefix => 'label_'), - :class => notifiable.parent.present? ? "parent" : '') + Setting.notified_events.include?(notifiable.name)).html_safe + + l_or_humanize(notifiable.name, :prefix => 'label_').html_safe, + :class => notifiable.parent.present? ? "parent" : '').html_safe end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/sort_helper.rb --- a/app/helpers/sort_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/sort_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Helpers to sort tables using clickable column headers. # # Author: Stuart Rackham , March 2005. @@ -15,18 +17,18 @@ # # helper :sort # include SortHelper -# +# # def list # sort_init 'last_name' # sort_update %w(first_name last_name) # @items = Contact.find_all nil, sort_clause # end -# +# # Controller (using Pagination module): # # helper :sort # include SortHelper -# +# # def list # sort_init 'last_name' # sort_update %w(first_name last_name) @@ -34,9 +36,9 @@ # :order_by => sort_clause, # :per_page => 10 # end -# +# # View (table header in list.rhtml): -# +# # # # <%= sort_header_tag('id', :title => 'Sort by contact ID') %> @@ -52,32 +54,32 @@ module SortHelper class SortCriteria - + def initialize @criteria = [] end - + def available_criteria=(criteria) unless criteria.is_a?(Hash) criteria = criteria.inject({}) {|h,k| h[k] = k; h} end @available_criteria = criteria end - + def from_param(param) @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]} normalize! end - + def criteria=(arg) @criteria = arg normalize! end - + def to_param @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',') end - + def to_sql sql = @criteria.collect do |k,o| if s = @available_criteria[k] @@ -86,33 +88,33 @@ end.compact.join(', ') sql.blank? ? nil : sql end - + def add!(key, asc) @criteria.delete_if {|k,o| k == key} @criteria = [[key, asc]] + @criteria normalize! end - + def add(*args) r = self.class.new.from_param(to_param) r.add!(*args) r end - + def first_key @criteria.first && @criteria.first.first end - + def first_asc? @criteria.first && @criteria.first.last end - + def empty? @criteria.empty? end - + private - + def normalize! @criteria ||= [] @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]} @@ -120,7 +122,7 @@ @criteria.slice!(3) self end - + # Appends DESC to the sort criterion unless it has a fixed order def append_desc(criterion) if criterion =~ / (asc|desc)$/i @@ -130,14 +132,14 @@ end end end - + def sort_name controller_name + '_' + action_name + '_sort' end # Initializes the default sort. # Examples: - # + # # sort_init 'name' # sort_init 'id', 'desc' # sort_init ['name', ['id', 'desc']] @@ -165,7 +167,7 @@ @sort_criteria.criteria = @sort_default if @sort_criteria.empty? session[sort_name] = @sort_criteria.to_param end - + # Clears the sort criteria session data # def sort_clear @@ -187,7 +189,7 @@ # def sort_link(column, caption, default_order) css, order = nil, default_order - + if column.to_s == @sort_criteria.first_key if @sort_criteria.first_asc? css = 'sort asc' @@ -198,14 +200,14 @@ end end caption = column.to_s.humanize unless caption - + sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param } url_options = params.merge(sort_options) - + # Add project_id to url_options url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) - link_to_content_update(caption, url_options, :class => css) + link_to_content_update(h(caption), url_options, :class => css) end # Returns a table header tag with a sort link for the named column diff -r 487d96eac004 -r 5e80956cc792 app/helpers/timelog_helper.rb --- a/app/helpers/timelog_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/timelog_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,23 +1,25 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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 TimelogHelper include ApplicationHelper - + def render_timelog_breadcrumb links = [] links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) @@ -52,15 +54,15 @@ activities.each { |a| collection << [a.name, a.id] } collection end - + def select_hours(data, criteria, value) if value.to_s.empty? data.select {|row| row[criteria].blank? } - else + else data.select {|row| row[criteria].to_s == value.to_s} end end - + def sum_hours(data) sum = 0 data.each do |row| @@ -68,7 +70,7 @@ end sum end - + def options_for_period_select(value) options_for_select([[l(:label_all_time), 'all'], [l(:label_today), 'today'], @@ -82,9 +84,8 @@ [l(:label_this_year), 'current_year']], value) end - + def entries_to_csv(entries) - ic = Iconv.new(l(:general_csv_encoding), 'UTF-8') decimal_separator = l(:general_csv_decimal_separator) custom_fields = TimeEntryCustomField.find(:all) export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| @@ -101,8 +102,10 @@ ] # Export custom fields headers += custom_fields.collect(&:name) - - csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } + + csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } # csv lines entries.each do |entry| fields = [format_date(entry.spent_on), @@ -116,13 +119,15 @@ entry.comments ] fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } - - csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } + + csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } end end export end - + def format_criteria_value(criteria, value) if value.blank? l(:label_none) @@ -137,54 +142,55 @@ format_value(value, @available_criterias[criteria][:format]) end end - + def report_to_csv(criterias, periods, hours) + decimal_separator = l(:general_csv_decimal_separator) export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| # Column headers headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } headers += periods headers << l(:label_total) - csv << headers.collect {|c| to_utf8(c) } + csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } # Content report_criteria_to_csv(csv, criterias, periods, hours) # Total row - row = [ l(:label_total) ] + [''] * (criterias.size - 1) + str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding)) + row = [ str_total ] + [''] * (criterias.size - 1) total = 0 periods.each do |period| sum = sum_hours(select_hours(hours, @columns, period.to_s)) total += sum - row << (sum > 0 ? "%.2f" % sum : '') + row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') end - row << "%.2f" %total + row << ("%.2f" % total).gsub('.',decimal_separator) csv << row end export end - + def report_criteria_to_csv(csv, criterias, periods, hours, level=0) + decimal_separator = l(:general_csv_decimal_separator) hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| hours_for_value = select_hours(hours, criterias[level], value) next if hours_for_value.empty? row = [''] * level - row << to_utf8(format_criteria_value(criterias[level], value)) + row << Redmine::CodesetUtil.from_utf8( + format_criteria_value(criterias[level], value).to_s, + l(:general_csv_encoding) ) row += [''] * (criterias.length - level - 1) total = 0 periods.each do |period| sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) total += sum - row << (sum > 0 ? "%.2f" % sum : '') + row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') end - row << "%.2f" %total + row << ("%.2f" % total).gsub('.',decimal_separator) csv << row - if criterias.length > level + 1 report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) end end end - - def to_utf8(s) - @ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8') - begin; @ic.iconv(s.to_s); rescue; s.to_s; end - end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/trackers_helper.rb --- a/app/helpers/trackers_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/trackers_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/users_helper.rb --- a/app/helpers/users_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/users_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,12 +20,12 @@ module UsersHelper def users_status_options_for_select(selected) user_count_by_status = User.count(:group => 'status').to_hash - options_for_select([[l(:label_all), ''], + options_for_select([[l(:label_all), ''], ["#{l(:status_active)} (#{user_count_by_status[1].to_i})", 1], ["#{l(:status_registered)} (#{user_count_by_status[2].to_i})", 2], ["#{l(:status_locked)} (#{user_count_by_status[3].to_i})", 3]], selected) end - + # Options for the new membership projects combo-box def options_for_membership_project_select(user, projects) options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") @@ -32,14 +34,14 @@ end options end - + def user_mail_notification_options(user) user.valid_notification_options.collect {|o| [l(o.last), o.first]} end - + def change_status_link(user) url = {:controller => 'users', :action => 'update', :id => user, :page => params[:page], :status => params[:status], :tab => nil} - + if user.locked? link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' elsif user.registered? @@ -48,7 +50,7 @@ link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock' end end - + def user_settings_tabs tabs = [{:name => 'general', :partial => 'users/general', :label => :label_general}, {:name => 'memberships', :partial => 'users/memberships', :label => :label_project_plural} diff -r 487d96eac004 -r 5e80956cc792 app/helpers/versions_helper.rb --- a/app/helpers/versions_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/versions_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,12 +7,12 @@ # 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. @@ -18,10 +20,10 @@ module VersionsHelper STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to) - + def render_issue_status_by(version, criteria) criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria) - + h = Hash.new {|k,v| k[v] = [0, 0]} begin # Total issue count @@ -36,10 +38,10 @@ end counts = h.keys.compact.sort.collect {|k| {:group => k, :total => h[k][0], :open => h[k][1], :closed => (h[k][0] - h[k][1])}} max = counts.collect {|c| c[:total]}.max - + render :partial => 'issue_counts', :locals => {:version => version, :criteria => criteria, :counts => counts, :max => max} end - + def status_by_options_for_select(value) options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value) end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/watchers_helper.rb --- a/app/helpers/watchers_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/watchers_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,22 +7,22 @@ # 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 WatchersHelper - + def watcher_tag(object, user, options={}) content_tag("span", watcher_link(object, user), :class => watcher_css(object)) end - + def watcher_link(object, user) return '' unless user && user.logged? && object.respond_to?('watched_by?') watched = object.watched_by?(user) @@ -32,14 +34,14 @@ {:url => url}, :href => url_for(url), :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off')) - + end - + # Returns the css class used to identify watch links for a given +object+ def watcher_css(object) "#{object.class.to_s.underscore}-#{object.id}-watcher" end - + # Returns a comma separated list of users watching the given object def watchers_list(object) remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project) diff -r 487d96eac004 -r 5e80956cc792 app/helpers/welcome_helper.rb --- a/app/helpers/welcome_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/welcome_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/helpers/wiki_helper.rb --- a/app/helpers/wiki_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/wiki_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2011 Jean-Philippe Lang # @@ -5,18 +7,18 @@ # 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 WikiHelper - + def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0) pages = pages.group_by(&:parent) unless pages.is_a?(Hash) s = '' @@ -25,11 +27,17 @@ attrs = "value='#{page.id}'" attrs << " selected='selected'" if selected == page indent = (level > 0) ? (' ' * level * 2 + '» ') : nil - - s << "\n" + + + s << "\n" + wiki_page_options_for_select(pages, selected, page, level + 1) end end s end + + def wiki_page_breadcrumb(page) + breadcrumb(page.ancestors.reverse.collect {|parent| + link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project}) + }) + end end diff -r 487d96eac004 -r 5e80956cc792 app/helpers/workflows_helper.rb --- a/app/helpers/workflows_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/helpers/workflows_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,18 @@ +# encoding: utf-8 +# # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/attachment.rb --- a/app/models/attachment.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/attachment.rb Mon Feb 27 13:53:18 2012 +0000 @@ -24,6 +24,7 @@ validates_presence_of :container, :filename, :author validates_length_of :filename, :maximum => 255 validates_length_of :disk_filename, :maximum => 255 + validate :validate_max_file_size acts_as_event :title => :filename, :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} @@ -43,9 +44,12 @@ "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} cattr_accessor :storage_path - @@storage_path = Redmine::Configuration['attachments_storage_path'] || "#{RAILS_ROOT}/files" + @@storage_path = Redmine::Configuration['attachments_storage_path'] || "#{Rails.root}/files" - def validate + before_save :files_to_final_location + after_destroy :delete_from_disk + + def validate_max_file_size if self.filesize > Setting.attachment_max_size.to_i.kilobytes errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes) end @@ -72,9 +76,9 @@ # Copies the temporary file to its final location # and computes its MD5 hash - def before_save + def files_to_final_location if @temp_file && (@temp_file.size > 0) - logger.debug("saving '#{self.diskfile}'") + logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") md5 = Digest::MD5.new File.open(diskfile, "wb") do |f| buffer = "" @@ -85,6 +89,7 @@ end self.digest = md5.hexdigest end + @temp_file = nil # Don't save the content type if it's longer than the authorized length if self.content_type && self.content_type.length > 255 self.content_type = nil @@ -92,7 +97,7 @@ end # Deletes file on the disk - def after_destroy + def delete_from_disk File.delete(diskfile) if !filename.blank? && File.exist?(diskfile) end @@ -118,7 +123,7 @@ end def image? - self.filename =~ /\.(jpe?g|gif|png)$/i + self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i end def is_text? @@ -149,6 +154,7 @@ :file => file, :description => attachment['description'].to_s.strip, :author => User.current) + obj.attachments << a if a.new_record? obj.unsaved_attachments ||= [] @@ -161,15 +167,19 @@ {:files => attached, :unsaved => obj.unsaved_attachments} end + def self.latest_attach(attachments, filename) + attachments.sort_by(&:created_on).reverse.detect { + |att| att.filename.downcase == filename.downcase + } + end + private def sanitize_filename(value) # get only the filename, not the whole path just_filename = value.gsub(/^.*(\\|\/)/, '') - # NOTE: File.basename doesn't work right with Windows paths on Unix - # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/')) - # Finally, replace all non alphanumeric, hyphens or periods with underscore - @filename = just_filename.gsub(/[^\w\.\-]/,'_') + # Finally, replace invalid characters with underscore + @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') end # Returns an ASCII or hashed filename diff -r 487d96eac004 -r 5e80956cc792 app/models/auth_source.rb --- a/app/models/auth_source.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/auth_source.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,43 +1,43 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class AuthSource < ActiveRecord::Base include Redmine::Ciphering - + has_many :users - + validates_presence_of :name validates_uniqueness_of :name validates_length_of :name, :maximum => 60 def authenticate(login, password) end - + def test_connection end - + def auth_method_name "Abstract" end - + def account_password read_ciphered_attribute(:account_password) end - + def account_password=(arg) write_ciphered_attribute(:account_password, arg) end diff -r 487d96eac004 -r 5e80956cc792 app/models/auth_source_ldap.rb --- a/app/models/auth_source_ldap.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/auth_source_ldap.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,23 +18,23 @@ require 'net/ldap' require 'iconv' -class AuthSourceLdap < AuthSource +class AuthSourceLdap < AuthSource validates_presence_of :host, :port, :attr_login validates_length_of :name, :host, :maximum => 60, :allow_nil => true validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true validates_numericality_of :port, :only_integer => true - + before_validation :strip_ldap_attributes - + def after_initialize self.port = 389 if self.port == 0 end - + def authenticate(login, password) return nil if login.blank? || password.blank? attrs = get_user_dn(login) - + if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password) logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? return attrs.except(:dn) @@ -50,19 +50,19 @@ rescue Net::LDAP::LdapError => text raise "LdapError: " + text end - + def auth_method_name "LDAP" end - + private - + def strip_ldap_attributes [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr| write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil? end end - + def initialize_ldap_con(ldap_user, ldap_password) options = { :host => self.host, :port => self.port, @@ -102,12 +102,12 @@ # Get the user's dn and any attributes for them, given their login def get_user_dn(login) ldap_con = initialize_ldap_con(self.account, self.account_password) - login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) - object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) + login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) + object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) attrs = {} - - ldap_con.search( :base => self.base_dn, - :filter => object_filter & login_filter, + + ldap_con.search( :base => self.base_dn, + :filter => object_filter & login_filter, :attributes=> search_attributes) do |entry| if onthefly_register? @@ -121,7 +121,7 @@ attrs end - + def self.get_attr(entry, attr_name) if !attr_name.blank? entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] diff -r 487d96eac004 -r 5e80956cc792 app/models/board.rb --- a/app/models/board.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/board.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -22,23 +22,26 @@ belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id acts_as_list :scope => :project_id acts_as_watchable - + validates_presence_of :name, :description validates_length_of :name, :maximum => 30 validates_length_of :description, :maximum => 255 - + + named_scope :visible, lambda {|*args| { :include => :project, + :conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } } + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_messages, project) end - + def to_s name end - + def reset_counters! self.class.reset_counters!(id) end - + # Updates topics_count, messages_count and last_message_id attributes for +board_id+ def self.reset_counters!(board_id) board_id = board_id.to_i diff -r 487d96eac004 -r 5e80956cc792 app/models/change.rb --- a/app/models/change.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/change.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,12 +20,13 @@ validates_presence_of :changeset_id, :action, :path before_save :init_path + before_validation :replace_invalid_utf8_of_path def relative_path changeset.repository.relative_path(path) end - def before_validation + def replace_invalid_utf8_of_path self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path) self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path) end diff -r 487d96eac004 -r 5e80956cc792 app/models/changeset.rb --- a/app/models/changeset.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/changeset.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,6 +22,14 @@ belongs_to :user has_many :changes, :dependent => :delete_all has_and_belongs_to_many :issues + has_and_belongs_to_many :parents, + :class_name => "Changeset", + :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", + :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id' + has_and_belongs_to_many :children, + :class_name => "Changeset", + :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", + :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id' acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))}, :description => :long_comments, @@ -44,6 +52,9 @@ named_scope :visible, lambda {|*args| { :include => {:repository => :project}, :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } } + after_create :scan_for_issues + before_create :before_create_cs + def revision=(r) write_attribute :revision, (r.nil? ? nil : r.to_s) end @@ -79,14 +90,14 @@ user || committer.to_s.split('<').first end - def before_create + def before_create_cs self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding) self.comments = self.class.normalize_comments( self.comments, repository.repo_log_encoding) self.user = repository.find_committer_user(self.committer) end - def after_create + def scan_for_issues scan_comment_for_issue_ids end @@ -193,7 +204,7 @@ def fix_issue(issue) status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) if status.nil? - logger.warn("No status macthes commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger + logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger return issue end @@ -253,39 +264,6 @@ end def self.to_utf8(str, encoding) - return str if str.nil? - str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding) - if str.empty? - str.force_encoding("UTF-8") if str.respond_to?(:force_encoding) - return str - end - enc = encoding.blank? ? "UTF-8" : encoding - if str.respond_to?(:force_encoding) - if enc.upcase != "UTF-8" - str.force_encoding(enc) - str = str.encode("UTF-8", :invalid => :replace, - :undef => :replace, :replace => '?') - else - str.force_encoding("UTF-8") - if ! str.valid_encoding? - str = str.encode("US-ASCII", :invalid => :replace, - :undef => :replace, :replace => '?').encode("UTF-8") - end - end - else - ic = Iconv.new('UTF-8', enc) - txtar = "" - begin - txtar += ic.iconv(str) - rescue Iconv::IllegalSequence - txtar += $!.success - str = '?' + $!.failed[1,$!.failed.length] - retry - rescue - txtar += $!.success - end - str = txtar - end - str + Redmine::CodesetUtil.to_utf8(str, encoding) end end diff -r 487d96eac004 -r 5e80956cc792 app/models/changeset.rb.rej --- a/app/models/changeset.rb.rej Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ ---- app/models/changeset.rb -+++ app/models/changeset.rb -@@ -152,6 +152,15 @@ - def self.normalize_comments(str) - to_utf8(str.to_s.strip) - end -+ -+ # Creates a new Change from it's common parameters -+ def create_change(change) -+ Change.create(:changeset => self, -+ :action => change[:action], -+ :path => change[:path], -+ :from_path => change[:from_path], -+ :from_revision => change[:from_revision]) -+ end - - private - diff -r 487d96eac004 -r 5e80956cc792 app/models/comment.rb --- a/app/models/comment.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/comment.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/comment_observer.rb --- a/app/models/comment_observer.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/comment_observer.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/custom_field.rb --- a/app/models/custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,35 +19,45 @@ has_many :custom_values, :dependent => :delete_all acts_as_list :scope => 'type = \'#{self.class}\'' serialize :possible_values - + validates_presence_of :name, :field_format validates_uniqueness_of :name, :scope => :type validates_length_of :name, :maximum => 30 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats + validate :validate_values + def initialize(attributes = nil) super self.possible_values ||= [] end - + def before_validation # make sure these fields are not searchable self.searchable = false if %w(int float date bool).include?(field_format) true end - - def validate + + def validate_values if self.field_format == "list" errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty? errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array end - + + if regexp.present? + begin + Regexp.new(regexp) + rescue + errors.add(:regexp, :invalid) + end + end + # validate default value v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil) v.custom_field.is_required = false errors.add(:default_value, :invalid) unless v.valid? end - + def possible_values_options(obj=nil) case field_format when 'user', 'version' @@ -56,7 +66,7 @@ when 'user' obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]} when 'version' - obj.project.versions.sort.collect {|u| [u.to_s, u.id.to_s]} + obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]} end elsif obj.is_a?(Array) obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v} @@ -67,7 +77,7 @@ read_attribute :possible_values end end - + def possible_values(obj=nil) case field_format when 'user', 'version' @@ -76,7 +86,7 @@ read_attribute :possible_values end end - + # Makes possible_values accept a multiline string def possible_values=(arg) if arg.is_a?(Array) @@ -85,7 +95,7 @@ self.possible_values = arg.to_s.split(/[\n\r]+/) end end - + def cast_value(value) casted = nil unless value.blank? @@ -106,7 +116,7 @@ end casted end - + # Returns a ORDER BY clause that can used to sort customized # objects by their value of the custom field. # Returns false, if the custom field can not be used for sorting. @@ -114,7 +124,7 @@ case field_format when 'string', 'text', 'list', 'date', 'bool' # COALESCE is here to make sure that blank and NULL values are sorted equally - "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + + "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" @@ -122,7 +132,7 @@ # Make the database cast values into numeric # Postgresql will raise an error if a value can not be casted! # CustomValue validations should ensure that it doesn't occur - "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" + + "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" + " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" @@ -134,17 +144,17 @@ def <=>(field) position <=> field.position end - + def self.customized_class self.name =~ /^(.+)CustomField$/ begin; $1.constantize; rescue nil; end end - + # to move in project_custom_field def self.for_all find(:all, :conditions => ["is_for_all=?", true], :order => 'position') end - + def type_name nil end diff -r 487d96eac004 -r 5e80956cc792 app/models/custom_value.rb --- a/app/models/custom_value.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/custom_value.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,42 +19,44 @@ belongs_to :custom_field belongs_to :customized, :polymorphic => true + validate :validate_custom_value + def after_initialize if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?)) self.value ||= custom_field.default_value end end - + # Returns true if the boolean custom value is true def true? self.value == '1' end - + def editable? custom_field.editable? end - + def visible? custom_field.visible? end - + def required? custom_field.is_required? end - + def to_s value.to_s end - + protected - def validate + def validate_custom_value if value.blank? - errors.add(:value, :blank) if custom_field.is_required? and value.blank? + errors.add(:value, :blank) if custom_field.is_required? and value.blank? else errors.add(:value, :invalid) unless custom_field.regexp.blank? or value =~ Regexp.new(custom_field.regexp) errors.add(:value, :too_short, :count => custom_field.min_length) if custom_field.min_length > 0 and value.length < custom_field.min_length errors.add(:value, :too_long, :count => custom_field.max_length) if custom_field.max_length > 0 and value.length > custom_field.max_length - + # Format specific validations case custom_field.field_format when 'int' @@ -62,7 +64,7 @@ when 'float' begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end when 'date' - errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ + errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end when 'list' errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value) end diff -r 487d96eac004 -r 5e80956cc792 app/models/enumeration.rb --- a/app/models/enumeration.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/enumeration.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,31 +1,32 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class Enumeration < ActiveRecord::Base default_scope :order => "#{Enumeration.table_name}.position ASC" - + belongs_to :project - + acts_as_list :scope => 'type = \'#{type}\'' acts_as_customizable acts_as_tree :order => 'position ASC' before_destroy :check_integrity - + before_save :check_default + validates_presence_of :name validates_uniqueness_of :name, :scope => [:type, :project_id] validates_length_of :name, :maximum => 30 @@ -45,23 +46,23 @@ find(:first, :conditions => { :is_default => true }) end end - + # Overloaded on concrete classes def option_name nil end - def before_save + def check_default if is_default? && is_default_changed? Enumeration.update_all("is_default = #{connection.quoted_false}", {:type => type}) end end - + # Overloaded on concrete classes def objects_count 0 end - + def in_use? self.objects_count != 0 end @@ -70,9 +71,9 @@ def is_override? !self.parent.nil? end - + alias :destroy_without_reassign :destroy - + # Destroy the enumeration # If a enumeration is specified, objects are reassigned def destroy(reassign_to = nil) @@ -81,11 +82,11 @@ end destroy_without_reassign end - + def <=>(enumeration) position <=> enumeration.position end - + def to_s; name end # Returns the Subclasses of Enumeration. Each Subclass needs to be @@ -115,13 +116,13 @@ return true end - + # Are the new and previous fields equal? def self.same_active_state?(new, previous) new = (new == "1" ? true : false) return new == previous end - + private def check_integrity raise "Can't delete enumeration" if self.in_use? diff -r 487d96eac004 -r 5e80956cc792 app/models/group.rb --- a/app/models/group.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/group.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,17 +18,21 @@ class Group < Principal has_and_belongs_to_many :users, :after_add => :user_added, :after_remove => :user_removed - + acts_as_customizable - + validates_presence_of :lastname validates_uniqueness_of :lastname, :case_sensitive => false validates_length_of :lastname, :maximum => 30 - + + before_destroy :remove_references_before_destroy + def to_s lastname.to_s end - + + alias :name :to_s + def user_added(user) members.each do |member| next if member.project.nil? @@ -39,11 +43,28 @@ user_member.save! end end - + def user_removed(user) members.each do |member| MemberRole.find(:all, :include => :member, :conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy) end end + + def self.human_attribute_name(attribute_key_name) + attr_name = attribute_key_name + if attr_name == 'lastname' + attr_name = "name" + end + super(attr_name) + end + + private + + # Removes references that are not handled by associations + def remove_references_before_destroy + return if self.id.nil? + + Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id] + end end diff -r 487d96eac004 -r 5e80956cc792 app/models/group_custom_field.rb --- a/app/models/group_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/group_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/issue.rb --- a/app/models/issue.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,7 +22,7 @@ belongs_to :tracker belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' - belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id' belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' @@ -35,7 +35,7 @@ has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all acts_as_nested_set :scope => 'root_id', :dependent => :destroy - acts_as_attachable :after_remove => :attachment_removed + acts_as_attachable :after_add => :attachment_added, :after_remove => :attachment_removed acts_as_customizable acts_as_watchable acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], @@ -58,6 +58,7 @@ validates_length_of :subject, :maximum => 255 validates_inclusion_of :done_ratio, :in => 0..100 validates_numericality_of :estimated_hours, :allow_nil => true + validate :validate_issue named_scope :visible, lambda {|*args| { :include => :project, :conditions => Issue.visible_condition(args.shift || User.current, *args) } } @@ -93,9 +94,11 @@ when 'all' nil when 'default' - "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})" + user_ids = [user.id] + user.groups.map(&:id) + "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" when 'own' - "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})" + user_ids = [user.id] + user.groups.map(&:id) + "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" else '1=0' end @@ -109,9 +112,9 @@ when 'all' true when 'default' - !self.is_private? || self.author == user || self.assigned_to == user + !self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to) when 'own' - self.author == user || self.assigned_to == user + self.author == user || user.is_or_belongs_to?(assigned_to) else false end @@ -227,7 +230,7 @@ @custom_field_values = nil result end - + def description=(arg) if arg.is_a?(String) arg = arg.gsub(/(\r\n|\n|\r)/, "\r\n") @@ -335,7 +338,7 @@ Setting.issue_done_ratio == 'issue_field' end - def validate + def validate_issue if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? errors.add :due_date, :not_a_date end @@ -352,7 +355,7 @@ if !assignable_versions.include?(fixed_version) errors.add :fixed_version_id, :inclusion elsif reopened? && fixed_version.closed? - errors.add_to_base I18n.t(:error_can_not_reopen_issue_on_closed_version) + errors.add :base, I18n.t(:error_can_not_reopen_issue_on_closed_version) end end @@ -449,6 +452,7 @@ def assignable_users users = project.assignable_users users << author if author + users << assigned_to if assigned_to users.uniq.sort end @@ -482,7 +486,13 @@ # Author and assignee are always notified unless they have been # locked or don't want to be notified notified << author if author && author.active? && author.notify_about?(self) - notified << assigned_to if assigned_to && assigned_to.active? && assigned_to.notify_about?(self) + if assigned_to + if assigned_to.is_a?(Group) + notified += assigned_to.users.select {|u| u.active? && u.notify_about?(self)} + else + notified << assigned_to if assigned_to.active? && assigned_to.notify_about?(self) + end + end notified.uniq! # Remove users that can not view the issue notified.reject! {|user| !visible?(user)} @@ -499,7 +509,22 @@ end def relations - (relations_from + relations_to).sort + @relations ||= (relations_from + relations_to).sort + end + + # Preloads relations for a collection of issues + def self.load_relations(issues) + if issues.any? + relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}]) + issues.each do |issue| + issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id} + end + end + end + + # Finds an issue relation given its id. + def find_relation(relation_id) + IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id]) end def all_dependent_issues(except=[]) @@ -592,15 +617,13 @@ @time_entry.project = project @time_entry.issue = self @time_entry.user = User.current - @time_entry.spent_on = Date.today + @time_entry.spent_on = User.current.today @time_entry.attributes = params[:time_entry] self.time_entries << @time_entry end if valid? attachments = Attachment.attach_files(self, params[:attachments]) - - attachments[:files].each {|a| @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)} # TODO: Rename hook Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) begin @@ -612,7 +635,7 @@ end rescue ActiveRecord::StaleObjectError attachments[:files].each(&:destroy) - errors.add_to_base l(:notice_locking_conflict) + errors.add :base, l(:notice_locking_conflict) raise ActiveRecord::Rollback end end @@ -831,6 +854,13 @@ end # Callback on attachment deletion + def attachment_added(obj) + if @current_journal && !obj.new_record? + @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename) + end + end + + # Callback on attachment deletion def attachment_removed(obj) journal = init_journal(User.current) journal.details << JournalDetail.new(:property => 'attachment', diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_category.rb --- a/app/models/issue_category.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_category.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,29 +5,31 @@ # 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. class IssueCategory < ActiveRecord::Base belongs_to :project - belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' has_many :issues, :foreign_key => 'category_id', :dependent => :nullify - + validates_presence_of :name validates_uniqueness_of :name, :scope => [:project_id] validates_length_of :name, :maximum => 30 + attr_protected :project_id + named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} - + alias :destroy_without_reassign :destroy - + # Destroy the category # If a category is specified, issues are reassigned to this category def destroy(reassign_to = nil) @@ -36,10 +38,10 @@ end destroy_without_reassign end - + def <=>(category) name <=> category.name end - + def to_s; name end end diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_custom_field.rb --- a/app/models/issue_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,7 +19,7 @@ has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id" has_and_belongs_to_many :trackers, :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :foreign_key => "custom_field_id" has_many :issues, :through => :issue_custom_values - + def type_name :label_issue_plural end diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_observer.rb --- a/app/models/issue_observer.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_observer.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_priority.rb --- a/app/models/issue_priority.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_priority.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_priority_custom_field.rb --- a/app/models/issue_priority_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_priority_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_relation.rb --- a/app/models/issue_relation.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_relation.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ class IssueRelation < ActiveRecord::Base belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id' belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id' - + TYPE_RELATES = "relates" TYPE_DUPLICATES = "duplicates" TYPE_DUPLICATED = "duplicated" @@ -26,7 +26,7 @@ TYPE_BLOCKED = "blocked" TYPE_PRECEDES = "precedes" TYPE_FOLLOWS = "follows" - + TYPES = { TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1, :sym => TYPE_RELATES }, TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2, :sym => TYPE_DUPLICATED }, TYPE_DUPLICATED => { :name => :label_duplicated_by, :sym_name => :label_duplicates, :order => 3, :sym => TYPE_DUPLICATES, :reverse => TYPE_DUPLICATES }, @@ -35,32 +35,54 @@ TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, :order => 6, :sym => TYPE_FOLLOWS }, TYPE_FOLLOWS => { :name => :label_follows, :sym_name => :label_precedes, :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES } }.freeze - + validates_presence_of :issue_from, :issue_to, :relation_type validates_inclusion_of :relation_type, :in => TYPES.keys validates_numericality_of :delay, :allow_nil => true validates_uniqueness_of :issue_to_id, :scope => :issue_from_id - + + validate :validate_issue_relation + attr_protected :issue_from_id, :issue_to_id - - def validate + + before_save :handle_issue_order + + def visible?(user=User.current) + (issue_from.nil? || issue_from.visible?(user)) && (issue_to.nil? || issue_to.visible?(user)) + end + + def deletable?(user=User.current) + visible?(user) && + ((issue_from.nil? || user.allowed_to?(:manage_issue_relations, issue_from.project)) || + (issue_to.nil? || user.allowed_to?(:manage_issue_relations, issue_to.project))) + end + + def after_initialize + if new_record? + if relation_type.blank? + self.relation_type = IssueRelation::TYPE_RELATES + end + end + end + + def validate_issue_relation if issue_from && issue_to errors.add :issue_to_id, :invalid if issue_from_id == issue_to_id errors.add :issue_to_id, :not_same_project unless issue_from.project_id == issue_to.project_id || Setting.cross_project_issue_relations? #detect circular dependencies depending wether the relation should be reversed if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] - errors.add_to_base :circular_dependency if issue_from.all_dependent_issues.include? issue_to + errors.add :base, :circular_dependency if issue_from.all_dependent_issues.include? issue_to else - errors.add_to_base :circular_dependency if issue_to.all_dependent_issues.include? issue_from + errors.add :base, :circular_dependency if issue_to.all_dependent_issues.include? issue_from end - errors.add_to_base :cant_link_an_issue_with_a_descendant if issue_from.is_descendant_of?(issue_to) || issue_from.is_ancestor_of?(issue_to) + errors.add :base, :cant_link_an_issue_with_a_descendant if issue_from.is_descendant_of?(issue_to) || issue_from.is_ancestor_of?(issue_to) end end - + def other_issue(issue) (self.issue_from_id == issue.id) ? issue_to : issue_from end - + # Returns the relation type for +issue+ def relation_type_for(issue) if TYPES[relation_type] @@ -71,14 +93,14 @@ end end end - + def label_for(issue) TYPES[relation_type] ? TYPES[relation_type][(self.issue_from_id == issue.id) ? :name : :sym_name] : :unknow end - - def before_save + + def handle_issue_order reverse_if_needed - + if TYPE_PRECEDES == relation_type self.delay ||= 0 else @@ -86,27 +108,29 @@ end set_issue_to_dates end - + def set_issue_to_dates soonest_start = self.successor_soonest_start if soonest_start && issue_to issue_to.reschedule_after(soonest_start) end end - + def successor_soonest_start if (TYPE_PRECEDES == self.relation_type) && delay && issue_from && (issue_from.start_date || issue_from.due_date) (issue_from.due_date || issue_from.start_date) + 1 + delay end end - + def <=>(relation) TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order] end - + private - + # Reverses the relation if needed so that it gets stored in the proper way + # Should not be reversed before validation so that it can be displayed back + # as entered on new relation form def reverse_if_needed if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] issue_tmp = issue_to diff -r 487d96eac004 -r 5e80956cc792 app/models/issue_status.rb --- a/app/models/issue_status.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/issue_status.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,43 +1,44 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class IssueStatus < ActiveRecord::Base - before_destroy :check_integrity + before_destroy :check_integrity has_many :workflows, :foreign_key => "old_status_id" acts_as_list - + before_destroy :delete_workflows + after_save :update_default validates_presence_of :name validates_uniqueness_of :name validates_length_of :name, :maximum => 30 validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true - + named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} - def after_save + def update_default IssueStatus.update_all("is_default=#{connection.quoted_false}", ['id <> ?', id]) if self.is_default? - end - + end + # Returns the default status for new issues def self.default find(:first, :conditions =>["is_default=?", true]) end - + # Update all the +Issues+ setting their done_ratio to the value of their +IssueStatus+ def self.update_issue_done_ratios if Issue.use_status_for_done_ratio? @@ -57,27 +58,29 @@ role_ids = roles.collect(&:id) transitions = workflows.select do |w| role_ids.include?(w.role_id) && - w.tracker_id == tracker.id && - (author || !w.author) && - (assignee || !w.assignee) + w.tracker_id == tracker.id && + ((!w.author && !w.assignee) || (author && w.author) || (assignee && w.assignee)) end transitions.collect{|w| w.new_status}.compact.sort else [] end end - + # Same thing as above but uses a database query # More efficient than the previous method if called just once def find_new_statuses_allowed_to(roles, tracker, author=false, assignee=false) - if roles && tracker - conditions = {:role_id => roles.collect(&:id), :tracker_id => tracker.id} - conditions[:author] = false unless author - conditions[:assignee] = false unless assignee - + if roles.present? && tracker + conditions = "(author = :false AND assignee = :false)" + conditions << " OR author = :true" if author + conditions << " OR assignee = :true" if assignee + workflows.find(:all, - :include => :new_status, - :conditions => conditions).collect{|w| w.new_status}.compact.sort + :include => :new_status, + :conditions => ["role_id IN (:role_ids) AND tracker_id = :tracker_id AND (#{conditions})", + {:role_ids => roles.collect(&:id), :tracker_id => tracker.id, :true => true, :false => false} + ] + ).collect{|w| w.new_status}.compact.sort else [] end @@ -86,14 +89,14 @@ def <=>(status) position <=> status.position end - + def to_s; name end private def check_integrity raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id]) end - + # Deletes associated workflows def delete_workflows Workflow.delete_all(["old_status_id = :id OR new_status_id = :id", {:id => id}]) diff -r 487d96eac004 -r 5e80956cc792 app/models/journal.rb --- a/app/models/journal.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/journal.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -20,11 +20,11 @@ # added as a quick fix to allow eager loading of the polymorphic association # since always associated to an issue, for now belongs_to :issue, :foreign_key => :journalized_id - + belongs_to :user has_many :details, :class_name => "JournalDetail", :dependent => :delete_all attr_accessor :indice - + acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" }, :description => :notes, :author => :user, @@ -36,36 +36,36 @@ :find_options => {:include => [{:issue => :project}, :details, :user], :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" + " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"} - + named_scope :visible, lambda {|*args| { :include => {:issue => :project}, :conditions => Issue.visible_condition(args.shift || User.current, *args) }} - + def save(*args) # Do not save an empty journal (details.empty? && notes.blank?) ? false : super end - + # Returns the new status if the journal contains a status change, otherwise nil def new_status c = details.detect {|detail| detail.prop_key == 'status_id'} (c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil end - + def new_value_for(prop) c = details.detect {|detail| detail.prop_key == prop} c ? c.value : nil end - + def editable_by?(usr) usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project))) end - + def project journalized.respond_to?(:project) ? journalized.project : nil end - + def attachments journalized.respond_to?(:attachments) ? journalized.attachments : nil end @@ -77,11 +77,11 @@ s << ' has-details' unless details.blank? s end - + def notify? @notify != false end - + def notify=(arg) @notify = arg end diff -r 487d96eac004 -r 5e80956cc792 app/models/journal_detail.rb --- a/app/models/journal_detail.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/journal_detail.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,14 +18,14 @@ class JournalDetail < ActiveRecord::Base belongs_to :journal before_save :normalize_values - + private - + def normalize_values self.value = normalize(value) self.old_value = normalize(old_value) end - + def normalize(v) if v == true "1" diff -r 487d96eac004 -r 5e80956cc792 app/models/journal_observer.rb --- a/app/models/journal_observer.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/journal_observer.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/mail_handler.rb --- a/app/models/mail_handler.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/mail_handler.rb Mon Feb 27 13:53:18 2012 +0000 @@ -61,7 +61,7 @@ when 'accept' @user = User.anonymous when 'create' - @user = MailHandler.create_user_from_email(email) + @user = create_user_from_email(email) if @user logger.info "MailHandler: [#{@user.login}] account created" if logger && logger.info Mailer.deliver_account_information(@user, @user.password) @@ -198,9 +198,9 @@ end def add_attachments(obj) - if email.has_attachments? + if email.attachments && email.attachments.any? email.attachments.each do |attachment| - Attachment.create(:container => obj, + obj.attachments << Attachment.create(:container => obj, :file => attachment, :author => user, :content_type => attachment.content_type) @@ -261,8 +261,7 @@ # Returns a Hash of issue attributes extracted from keywords in the email body def issue_attributes_from_keywords(issue) - assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_user_from_keyword(k) - assigned_to = nil if assigned_to && !issue.assignable_users.include?(assigned_to) + assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_assignee_from_keyword(k, issue) attrs = { 'tracker_id' => (k = get_keyword(:tracker)) && issue.project.trackers.named(k).first.try(:id), @@ -323,22 +322,53 @@ @full_sanitizer ||= HTML::FullSanitizer.new end - # Creates a user account for the +email+ sender - def self.create_user_from_email(email) + def self.assign_string_attribute_with_limit(object, attribute, value) + limit = object.class.columns_hash[attribute.to_s].limit || 255 + value = value.to_s.slice(0, limit) + object.send("#{attribute}=", value) + end + + # Returns a User from an email address and a full name + def self.new_user_from_attributes(email_address, fullname=nil) + user = User.new + + # Truncating the email address would result in an invalid format + user.mail = email_address + assign_string_attribute_with_limit(user, 'login', email_address) + + names = fullname.blank? ? email_address.gsub(/@.*$/, '').split('.') : fullname.split + assign_string_attribute_with_limit(user, 'firstname', names.shift) + assign_string_attribute_with_limit(user, 'lastname', names.join(' ')) + user.lastname = '-' if user.lastname.blank? + + password_length = [Setting.password_min_length.to_i, 10].max + user.password = ActiveSupport::SecureRandom.hex(password_length / 2 + 1) + user.language = Setting.default_language + + unless user.valid? + user.login = "user#{ActiveSupport::SecureRandom.hex(6)}" if user.errors.on(:login) + user.firstname = "-" if user.errors.on(:firstname) + user.lastname = "-" if user.errors.on(:lastname) + end + + user + end + + # Creates a User for the +email+ sender + # Returns the user or nil if it could not be created + def create_user_from_email(email) addr = email.from_addrs.to_a.first if addr && !addr.spec.blank? - user = User.new - user.mail = addr.spec - - names = addr.name.blank? ? addr.spec.gsub(/@.*$/, '').split('.') : addr.name.split - user.firstname = names.shift - user.lastname = names.join(' ') - user.lastname = '-' if user.lastname.blank? - - user.login = user.mail - user.password = ActiveSupport::SecureRandom.hex(5) - user.language = Setting.default_language - user.save ? user : nil + user = self.class.new_user_from_attributes(addr.spec, addr.name) + if user.save + user + else + logger.error "MailHandler: failed to create User: #{user.errors.full_messages}" if logger + nil + end + else + logger.error "MailHandler: failed to create User: no FROM address found" if logger + nil end end @@ -354,13 +384,18 @@ body.strip end - def find_user_from_keyword(keyword) - user ||= User.find_by_mail(keyword) - user ||= User.find_by_login(keyword) - if user.nil? && keyword.match(/ /) + def find_assignee_from_keyword(keyword, issue) + keyword = keyword.to_s.downcase + assignable = issue.assignable_users + assignee = nil + assignee ||= assignable.detect {|a| a.mail.to_s.downcase == keyword || a.login.to_s.downcase == keyword} + if assignee.nil? && keyword.match(/ /) firstname, lastname = *(keyword.split) # "First Last Throwaway" - user ||= User.find_by_firstname_and_lastname(firstname, lastname) + assignee ||= assignable.detect {|a| a.is_a?(User) && a.firstname.to_s.downcase == firstname && a.lastname.to_s.downcase == lastname} end - user + if assignee.nil? + assignee ||= assignable.detect {|a| a.is_a?(Group) && a.name.downcase == keyword} + end + assignee end end diff -r 487d96eac004 -r 5e80956cc792 app/models/mailer.rb --- a/app/models/mailer.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/mailer.rb Mon Feb 27 13:53:18 2012 +0000 @@ -95,7 +95,7 @@ subject s body :issue => issue, :journal => journal, - :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) + :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}") render_multipart('issue_edit', body) end @@ -106,7 +106,9 @@ subject l(:mail_subject_reminder, :count => issues.size, :days => days) body :issues => issues, :days => days, - :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort => 'due_date:asc') + :issues_url => url_for(:controller => 'issues', :action => 'index', + :set_filter => 1, :assigned_to_id => user.id, + :sort => 'due_date:asc') render_multipart('reminder', body) end @@ -219,7 +221,9 @@ cc(wiki_content.page.wiki.watcher_recipients - recipients) subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}" body :wiki_content => wiki_content, - :wiki_content_url => url_for(:controller => 'wiki', :action => 'show', :project_id => wiki_content.project, :id => wiki_content.page.title) + :wiki_content_url => url_for(:controller => 'wiki', :action => 'show', + :project_id => wiki_content.project, + :id => wiki_content.page.title) render_multipart('wiki_content_added', body) end @@ -236,8 +240,12 @@ cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients) subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}" body :wiki_content => wiki_content, - :wiki_content_url => url_for(:controller => 'wiki', :action => 'show', :project_id => wiki_content.project, :id => wiki_content.page.title), - :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff', :project_id => wiki_content.project, :id => wiki_content.page.title, :version => wiki_content.version) + :wiki_content_url => url_for(:controller => 'wiki', :action => 'show', + :project_id => wiki_content.project, + :id => wiki_content.page.title), + :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff', + :project_id => wiki_content.project, :id => wiki_content.page.title, + :version => wiki_content.version) render_multipart('wiki_content_updated', body) end @@ -266,7 +274,9 @@ recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact subject l(:mail_subject_account_activation_request, Setting.app_title) body :user => user, - :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc') + :url => url_for(:controller => 'users', :action => 'index', + :status => User::STATUS_REGISTERED, + :sort_key => 'created_on', :sort_order => 'desc') render_multipart('account_activation_request', body) end @@ -389,7 +399,7 @@ headers 'X-Mailer' => 'Redmine', 'X-Redmine-Host' => Setting.host_name, 'X-Redmine-Site' => Setting.app_title, - 'Precedence' => 'bulk', + 'X-Auto-Response-Suppress' => 'OOF', 'Auto-Submitted' => 'auto-generated' end @@ -431,11 +441,16 @@ def render_multipart(method_name, body) if Setting.plain_text_mail? content_type "text/plain" - body render(:file => "#{method_name}.text.plain.rhtml", :body => body, :layout => 'mailer.text.plain.erb') + body render(:file => "#{method_name}.text.erb", + :body => body, + :layout => 'mailer.text.erb') else content_type "multipart/alternative" - part :content_type => "text/plain", :body => render(:file => "#{method_name}.text.plain.rhtml", :body => body, :layout => 'mailer.text.plain.erb') - part :content_type => "text/html", :body => render_message("#{method_name}.text.html.rhtml", body) + part :content_type => "text/plain", + :body => render(:file => "#{method_name}.text.erb", + :body => body, :layout => 'mailer.text.erb') + part :content_type => "text/html", + :body => render_message("#{method_name}.html.erb", body) end end @@ -467,7 +482,7 @@ end def mylogger - RAILS_DEFAULT_LOGGER + Rails.logger end end diff -r 487d96eac004 -r 5e80956cc792 app/models/member.rb --- a/app/models/member.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/member.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -26,17 +26,17 @@ validates_uniqueness_of :user_id, :scope => :project_id after_destroy :unwatch_from_permission_change - + def name self.user.name end - + alias :base_role_ids= :role_ids= def role_ids=(arg) ids = (arg || []).collect(&:to_i) - [0] # Keep inherited roles ids += member_roles.select {|mr| !mr.inherited_from.nil?}.collect(&:role_id) - + new_role_ids = ids - role_ids # Add new roles new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id) } @@ -47,16 +47,16 @@ unwatch_from_permission_change end end - + def <=>(member) a, b = roles.sort.first, member.roles.sort.first a == b ? (principal <=> member.principal) : (a <=> b) end - + def deletable? member_roles.detect {|mr| mr.inherited_from}.nil? end - + def include?(user) if principal.is_a?(Group) !user.nil? && user.groups.include?(principal) @@ -64,7 +64,7 @@ self.user == user end end - + def before_destroy if user # remove category based auto assignments for this member @@ -78,15 +78,15 @@ @membership.attributes = new_attributes @membership end - + protected - + def validate errors.add_on_empty :role if member_roles.empty? && roles.empty? end - + private - + # Unwatch things that the user is no longer allowed to view inside project def unwatch_from_permission_change if user diff -r 487d96eac004 -r 5e80956cc792 app/models/member_role.rb --- a/app/models/member_role.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/member_role.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,30 +18,30 @@ class MemberRole < ActiveRecord::Base belongs_to :member belongs_to :role - + after_destroy :remove_member_if_empty after_create :add_role_to_group_users after_destroy :remove_role_from_group_users - + validates_presence_of :role - + def validate errors.add :role_id, :invalid if role && !role.member? end - + def inherited? !inherited_from.nil? end - + private - + def remove_member_if_empty if member.roles.empty? member.destroy end end - + def add_role_to_group_users if member.principal.is_a?(Group) member.principal.users.each do |user| @@ -51,7 +51,7 @@ end end end - + def remove_role_from_group_users MemberRole.find(:all, :conditions => { :inherited_from => id }).group_by(&:member).each do |member, member_roles| member_roles.each(&:destroy) diff -r 487d96eac004 -r 5e80956cc792 app/models/message.rb --- a/app/models/message.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/message.rb Mon Feb 27 13:53:18 2012 +0000 @@ -29,7 +29,7 @@ acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, :description => :content, :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'}, - :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} : + :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} : {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})} acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}, @@ -39,8 +39,11 @@ attr_protected :locked, :sticky validates_presence_of :board, :subject, :content validates_length_of :subject, :maximum => 255 + validate :cannot_reply_to_locked_topic, :on => :create - after_create :add_author_as_watcher + after_create :add_author_as_watcher, :update_parent_last_reply + after_update :update_messages_board + after_destroy :reset_board_counters named_scope :visible, lambda {|*args| { :include => {:board => :project}, :conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } } @@ -49,19 +52,19 @@ !user.nil? && user.allowed_to?(:view_messages, project) end - def validate_on_create + def cannot_reply_to_locked_topic # Can not reply to a locked topic - errors.add_to_base 'Topic is locked' if root.locked? && self != root + errors.add :base, 'Topic is locked' if root.locked? && self != root end - def after_create + def update_parent_last_reply if parent parent.reload.update_attribute(:last_reply_id, self.id) end board.reset_counters! end - def after_update + def update_messages_board if board_id_changed? Message.update_all("board_id = #{board_id}", ["id = ? OR parent_id = ?", root.id, root.id]) Board.reset_counters!(board_id_was) @@ -69,7 +72,7 @@ end end - def after_destroy + def reset_board_counters board.reset_counters! end diff -r 487d96eac004 -r 5e80956cc792 app/models/news_observer.rb --- a/app/models/news_observer.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/news_observer.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/principal.rb --- a/app/models/principal.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/principal.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -21,17 +21,18 @@ has_many :members, :foreign_key => 'user_id', :dependent => :destroy has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name" has_many :projects, :through => :memberships + has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify # Groups and active users named_scope :active, :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status = 1)" - - named_scope :like, lambda {|q| + + named_scope :like, lambda {|q| s = "%#{q.to_s.strip.downcase}%" {:conditions => ["LOWER(login) LIKE :s OR LOWER(firstname) LIKE :s OR LOWER(lastname) LIKE :s OR LOWER(mail) LIKE :s", {:s => s}], :order => 'type, login, lastname, firstname, mail' } } - + before_create :set_default_empty_values def name(formatter = nil) @@ -46,9 +47,9 @@ principal.class.name <=> self.class.name end end - + protected - + # Make sure we don't try to insert NULL values (see #4632) def set_default_empty_values self.login ||= '' diff -r 487d96eac004 -r 5e80956cc792 app/models/project.rb --- a/app/models/project.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/project.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,36 +5,36 @@ # 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. class Project < ActiveRecord::Base include Redmine::SafeAttributes - + # Project statuses STATUS_ACTIVE = 1 STATUS_ARCHIVED = 9 - + # Maximum length for project identifiers IDENTIFIER_MAX_LENGTH = 100 - + # Specific overidden Activities has_many :time_entry_activities has_many :members, :include => [:user, :roles], :conditions => "#{User.table_name}.type='User' AND #{User.table_name}.status=#{User::STATUS_ACTIVE}" has_many :memberships, :class_name => 'Member' - has_many :member_principals, :class_name => 'Member', + has_many :member_principals, :class_name => 'Member', :include => :principal, :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{User::STATUS_ACTIVE})" has_many :users, :through => :members has_many :principals, :through => :member_principals, :source => :principal - + has_many :enabled_modules, :dependent => :delete_all has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker] @@ -50,12 +50,12 @@ has_many :changesets, :through => :repository has_one :wiki, :dependent => :destroy # Custom field for the project issues - has_and_belongs_to_many :issue_custom_fields, + has_and_belongs_to_many :issue_custom_fields, :class_name => 'IssueCustomField', :order => "#{CustomField.table_name}.position", :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id' - + acts_as_nested_set :order => 'name', :dependent => :destroy acts_as_attachable :view_permission => :view_files, :delete_permission => :manage_files @@ -67,7 +67,7 @@ :author => nil attr_protected :status - + validates_presence_of :name, :identifier validates_uniqueness_of :identifier validates_associated :repository, :wiki @@ -86,12 +86,12 @@ named_scope :all_public, { :conditions => { :is_public => true } } named_scope :visible, lambda {|*args| {:conditions => Project.visible_condition(args.shift || User.current, *args) }} named_scope :visible_roots, lambda { { :conditions => Project.root_visible_by(User.current) } } - + def initialize(attributes = nil) super - + initialized = (attributes || {}).stringify_keys - if !initialized.key?('identifier') && Setting.sequential_project_identifiers? + if !initialized.key?('identifier') && Setting.sequential_project_identifiers? self.identifier = Project.next_identifier end if !initialized.key?('is_public') @@ -104,11 +104,11 @@ self.trackers = Tracker.all end end - + def identifier=(identifier) super unless identifier_frozen? end - + def identifier_frozen? errors[:identifier].nil? && !(new_record? || identifier.blank?) end @@ -123,12 +123,7 @@ def visible?(user=User.current) user.allowed_to?(:view_project, self) end - - def self.visible_by(user=nil) - ActiveSupport::Deprecation.warn "Project.visible_by is deprecated and will be removed in Redmine 1.3.0. Use Project.visible_condition instead." - visible_condition(user || User.current) - end - + # Returns a SQL conditions string used to find all projects visible by the specified user. # # Examples: @@ -138,7 +133,7 @@ def self.visible_condition(user, options={}) allowed_to_condition(user, :view_project, options) end - + def self.root_visible_by(user=nil) return "#{Project.table_name}.parent_id IS NULL AND " + visible_by(user) end @@ -162,7 +157,7 @@ project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects] base_statement = "(#{project_statement}) AND (#{base_statement})" end - + if user.admin? base_statement else @@ -216,14 +211,14 @@ activity.update_attributes(activity_hash) if activity end end - + # Create a new TimeEntryActivity if it overrides a system TimeEntryActivity # # This will raise a ActiveRecord::Rollback if the TimeEntryActivity # does not successfully save. def create_time_entry_activity_if_needed(activity) if activity['parent_id'] - + parent_activity = TimeEntryActivity.find(activity['parent_id']) activity['name'] = parent_activity.name activity['position'] = parent_activity.position @@ -250,7 +245,7 @@ cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects cond end - + def self.find(*args) if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/) project = find_by_identifier(*args) @@ -260,20 +255,20 @@ super end end - + def to_param # id is used for projects with a numeric identifier (compatibility) @to_param ||= (identifier.to_s =~ %r{^\d*$} ? id : identifier) end - + def active? self.status == STATUS_ACTIVE end - + def archived? self.status == STATUS_ARCHIVED end - + # Archives the project and its descendants def archive # Check that there is no issue of a non descendant project that is assigned @@ -289,14 +284,14 @@ end true end - + # Unarchives the project # All its ancestors must be active def unarchive return false if ancestors.detect {|a| !a.active?} update_attribute :status, STATUS_ACTIVE end - + # Returns an array of projects the project can be moved to # by the current user def allowed_parents @@ -311,7 +306,7 @@ end @allowed_parents end - + # Sets the parent of the project with authorization check def set_allowed_parent!(p) unless p.nil? || p.is_a?(Project) @@ -331,7 +326,7 @@ end set_parent!(p) end - + # Sets the parent of the project # Argument can be either a Project, a String, a Fixnum or nil def set_parent!(p) @@ -370,7 +365,7 @@ false end end - + # Returns an array of the trackers used by the project and its active sub projects def rolled_up_trackers @rolled_up_trackers ||= @@ -379,7 +374,7 @@ :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt], :order => "#{Tracker.table_name}.position") end - + # Closes open and locked project versions that are completed def close_completed_versions Version.transaction do @@ -397,7 +392,7 @@ Version.scoped(:include => :project, :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt]) end - + # Returns a scope of the Versions used by the project def shared_versions @shared_versions ||= begin @@ -423,30 +418,31 @@ h end end - + # Deletes all project's members def delete_all_members me, mr = Member.table_name, MemberRole.table_name connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})") Member.delete_all(['project_id = ?', id]) end - - # Users issues can be assigned to + + # Users/groups issues can be assigned to def assignable_users - members.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.user}.sort + assignable = Setting.issue_group_assignment? ? member_principals : members + assignable.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.principal}.sort end - + # Returns the mail adresses of users that should be always notified on project events def recipients notified_users.collect {|user| user.mail} end - + # Returns the users that should be notified on project events def notified_users # TODO: User part should be extracted to User#notify_about? members.select {|m| m.mail_notification? || m.user.mail_notification == 'all'}.collect {|m| m.user} end - + # Returns an array of all custom fields enabled for project issues # (explictly associated custom fields and custom fields enabled for all projects) def all_issue_custom_fields @@ -458,19 +454,19 @@ def all_time_entry_custom_fields @all_time_entry_custom_fields ||= (TimeEntryCustomField.for_all + time_entry_custom_fields).uniq.sort end - + def project self end - + def <=>(project) name.downcase <=> project.name.downcase end - + def to_s name end - + # Returns a short description of the projects (first lines) def short_description(length = 255) @@ -537,7 +533,7 @@ end end end - + # Return true if this project is allowed to do the specified action. # action can be: # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') @@ -549,12 +545,12 @@ allowed_permissions.include? action end end - + def module_enabled?(module_name) module_name = module_name.to_s enabled_modules.detect {|m| m.name == module_name} end - + def enabled_module_names=(module_names) if module_names && module_names.is_a?(Array) module_names = module_names.collect(&:to_s).reject(&:blank?) @@ -563,7 +559,7 @@ enabled_modules.clear end end - + # Returns an array of the enabled modules names def enabled_module_names enabled_modules.collect(&:name) @@ -602,7 +598,7 @@ safe_attributes 'enabled_module_names', :if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) } - + # Returns an array of projects that are in this project's hierarchy # # Example: parents, children, siblings @@ -611,7 +607,7 @@ descendants = project.descendants || [] project_hierarchy = parents | descendants # Set union end - + # Returns an auto-generated project identifier based on the last identifier used def self.next_identifier p = Project.find(:first, :order => 'created_on DESC') @@ -635,10 +631,10 @@ # project.copy(1, :only => ['members', 'versions']) # => copies members and versions def copy(project, options={}) project = project.is_a?(Project) ? project : Project.find(project) - + to_be_copied = %w(wiki versions issue_categories issues members queries boards) to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil? - + Project.transaction do if save reload @@ -651,7 +647,7 @@ end end - + # Copies +project+ and returns the new instance. This will not save # the copy def self.copy_from(project) @@ -678,16 +674,16 @@ def self.project_tree(projects, &block) ancestors = [] projects.sort_by(&:lft).each do |project| - while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) ancestors.pop end yield project, ancestors.size ancestors << project end end - + private - + # Copies wiki from +project+ def copy_wiki(project) # Check that the source project has a wiki first @@ -732,14 +728,14 @@ self.issue_categories << new_issue_category end end - + # Copies issues from +project+ # Note: issues assigned to a closed version won't be copied due to validation rules def copy_issues(project) # Stores the source issue id as a key and the copied issues as the # value. Used to map the two togeather for issue relations. issues_map = {} - + # Get issues sorted by root_id, lft so that parent issues # get copied before their children project.issues.find(:all, :order => 'root_id, lft').each do |issue| @@ -762,7 +758,7 @@ new_issue.parent_issue_id = copied_parent.id end end - + self.issues << new_issue if new_issue.new_record? logger.info "Project#copy_issues: issue ##{issue.id} could not be copied: #{new_issue.errors.full_messages}" if logger && logger.info @@ -778,7 +774,7 @@ # Issue was not copied next end - + # Relations issue.relations_from.each do |source_relation| new_issue_relation = IssueRelation.new @@ -789,7 +785,7 @@ end new_issue.relations_from << new_issue_relation end - + issue.relations_to.each do |source_relation| new_issue_relation = IssueRelation.new new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id") @@ -808,7 +804,7 @@ members_to_copy = [] members_to_copy += project.memberships.select {|m| m.principal.is_a?(User)} members_to_copy += project.memberships.select {|m| !m.principal.is_a?(User)} - + members_to_copy.each do |member| new_member = Member.new new_member.attributes = member.attributes.dup.except("id", "project_id", "created_on") @@ -829,6 +825,7 @@ new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria") new_query.sort_criteria = query.sort_criteria if query.sort_criteria new_query.project = self + new_query.user_id = query.user_id self.queries << new_query end end @@ -842,7 +839,7 @@ self.boards << new_board end end - + def allowed_permissions @allowed_permissions ||= begin module_names = enabled_modules.all(:select => :name).collect {|m| m.name} @@ -857,7 +854,7 @@ # Returns all the active Systemwide and project specific activities def active_activities overridden_activity_ids = self.time_entry_activities.collect(&:parent_id) - + if overridden_activity_ids.empty? return TimeEntryActivity.shared.active else @@ -891,7 +888,7 @@ self.time_entry_activities.active end end - + # Archives subprojects recursively def archive! children.each do |subproject| diff -r 487d96eac004 -r 5e80956cc792 app/models/project_custom_field.rb --- a/app/models/project_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/project_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/query.rb --- a/app/models/query.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/query.rb Mon Feb 27 13:53:18 2012 +0000 @@ -36,7 +36,11 @@ # Returns true if the column is sortable, otherwise false def sortable? - !sortable.nil? + !@sortable.nil? + end + + def sortable + @sortable.is_a?(Proc) ? @sortable.call : @sortable end def value(issue) @@ -92,6 +96,7 @@ validates_presence_of :name, :on => :save validates_length_of :name, :maximum => 255 + validate :validate_query_filters @@operators = { "=" => :label_equals, "!" => :label_not_equals, @@ -101,6 +106,7 @@ "*" => :label_all, ">=" => :label_greater_or_equal, "<=" => :label_less_or_equal, + "><" => :label_between, " :label_in_less_than, ">t+" => :label_in_more_than, "t+" => :label_in, @@ -118,11 +124,12 @@ :list_status => [ "o", "=", "!", "c", "*" ], :list_optional => [ "=", "!", "!*", "*" ], :list_subprojects => [ "*", "!*", "=" ], - :date => [ "t+", "t+", "t", "w", ">t-", " [ ">t-", " [ "=", ">=", "<=", "><", "t+", "t+", "t", "w", ">t-", " [ "=", ">=", "<=", "><", ">t-", " [ "=", "~", "!", "!~" ], :text => [ "~", "!~" ], - :integer => [ "=", ">=", "<=", "!*", "*" ] } + :integer => [ "=", ">=", "<=", "><", "!*", "*" ], + :float => [ "=", ">=", "<=", "><", "!*", "*" ] } cattr_reader :operators_by_filter_type @@ -133,8 +140,8 @@ QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true), QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true), QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), - QueryColumn.new(:author), - QueryColumn.new(:assigned_to, :sortable => ["#{User.table_name}.lastname", "#{User.table_name}.firstname", "#{User.table_name}.id"], :groupable => true), + QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true), + QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true), QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc', :groupable => true), @@ -146,6 +153,16 @@ ] cattr_reader :available_columns + named_scope :visible, lambda {|*args| + user = args.shift || User.current + base = Project.allowed_to_condition(user, :view_issues, *args) + user_id = user.logged? ? user.id : 0 + { + :conditions => ["(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id], + :include => :project + } + } + def initialize(attributes = nil) super attributes self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } @@ -156,8 +173,24 @@ @is_for_all = project.nil? end - def validate + def validate_query_filters filters.each_key do |field| + if values_for(field) + case type_for(field) + when :integer + errors.add(label_for(field), :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) } + when :float + errors.add(label_for(field), :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+(\.\d*)?$/) } + when :date, :date_past + case operator_for(field) + when "=", ">=", "<=", "><" + errors.add(label_for(field), :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) } + when ">t-", " { :type => :date_past, :order => 10 }, "start_date" => { :type => :date, :order => 11 }, "due_date" => { :type => :date, :order => 12 }, - "estimated_hours" => { :type => :integer, :order => 13 }, + "estimated_hours" => { :type => :float, :order => 13 }, "done_ratio" => { :type => :integer, :order => 14 }} - user_values = [] - user_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + principals = [] if project - user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] } + principals += project.principals.sort else all_projects = Project.visible.all if all_projects.any? # members of visible projects - user_values += User.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", all_projects.collect(&:id)]).sort.collect{|s| [s.name, s.id.to_s] } + principals += Principal.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", all_projects.collect(&:id)]).sort # project filter project_values = [] @@ -214,8 +246,17 @@ @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} unless project_values.empty? end end - @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty? - @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty? + users = principals.select {|p| p.is_a?(User)} + + assigned_to_values = [] + assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] } + @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => assigned_to_values } unless assigned_to_values.empty? + + author_values = [] + author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + author_values += users.collect{|s| [s.name, s.id.to_s] } + @available_filters["author_id"] = { :type => :list, :order => 5, :values => author_values } unless author_values.empty? group_values = Group.all.collect {|g| [g.name, g.id.to_s] } @available_filters["member_of_group"] = { :type => :list_optional, :order => 6, :values => group_values } unless group_values.empty? @@ -229,21 +270,21 @@ if project # project specific filters - categories = @project.issue_categories.all + categories = project.issue_categories.all unless categories.empty? @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => categories.collect{|s| [s.name, s.id.to_s] } } end - versions = @project.shared_versions.all + versions = project.shared_versions.all unless versions.empty? @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } end - unless @project.leaf? - subprojects = @project.descendants.visible.all + unless project.leaf? + subprojects = project.descendants.visible.all unless subprojects.empty? @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => subprojects.collect{|s| [s.name, s.id.to_s] } } end end - add_custom_fields_filters(@project.all_issue_custom_fields) + add_custom_fields_filters(project.all_issue_custom_fields) else # global filters for cross project issue list system_shared_versions = Version.visible.find_all_by_sharing('system') @@ -257,7 +298,7 @@ def add_filter(field, operator, values) # values must be an array - return unless values and values.is_a? Array # and !values.first.empty? + return unless values.nil? || values.is_a?(Array) # check if field is defined as an available filter if available_filters.has_key? field filter_options = available_filters[field] @@ -266,21 +307,24 @@ # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]}) # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator #end - filters[field] = {:operator => operator, :values => values } + filters[field] = {:operator => operator, :values => (values || [''])} end end def add_short_filter(field, expression) - return unless expression - parms = expression.scan(/^(o|c|!\*|!|\*)?(.*)$/).first - add_filter field, (parms[0] || "="), [parms[1] || ""] + return unless expression && available_filters.has_key?(field) + field_type = available_filters[field][:type] + @@operators_by_filter_type[field_type].sort.reverse.detect do |operator| + next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ + add_filter field, operator, $1.present? ? $1.split('|') : [''] + end || add_filter(field, '=', expression.split('|')) end # Add multiple filters using +add_filter+ def add_filters(fields, operators, values) - if fields.is_a?(Array) && operators.is_a?(Hash) && values.is_a?(Hash) + if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash)) fields.each do |field| - add_filter(field, operators[field], values[field]) + add_filter(field, operators[field], values && values[field]) end end end @@ -289,6 +333,10 @@ filters and filters[field] end + def type_for(field) + available_filters[field][:type] if available_filters.has_key?(field) + end + def operator_for(field) has_filter?(field) ? filters[field][:operator] : nil end @@ -297,6 +345,10 @@ has_filter?(field) ? filters[field][:values] : nil end + def value_for(field, index=0) + (values_for(field) || [])[index] + end + def label_for(field) label = available_filters[field][:name] if available_filters.has_key?(field) label ||= field.gsub(/\_id$/, "") @@ -304,8 +356,8 @@ def available_columns return @available_columns if @available_columns - @available_columns = Query.available_columns - @available_columns += (project ? + @available_columns = ::Query.available_columns + @available_columns += (project ? project.all_issue_custom_fields : IssueCustomField.find(:all) ).collect {|cf| QueryCustomFieldColumn.new(cf) } @@ -333,14 +385,17 @@ end def columns - if has_default_columns? - available_columns.select do |c| - # Adds the project column by default for cross-project lists - Setting.issue_list_default_columns.include?(c.name.to_s) || (c.name == :project && project.nil?) - end - else - # preserve the column_names order - column_names.collect {|name| available_columns.find {|col| col.name == name}}.compact + # preserve the column_names order + (has_default_columns? ? default_columns_names : column_names).collect do |name| + available_columns.find { |col| col.name == name } + end.compact + end + + def default_columns_names + @default_columns_names ||= begin + default_columns = Setting.issue_list_default_columns.map(&:to_sym) + + project.present? ? default_columns : [:project] | default_columns end end @@ -349,7 +404,7 @@ names = names.select {|n| n.is_a?(Symbol) || !n.blank? } names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym } # Set column_names to nil if default columns - if names.map(&:to_s) == Setting.issue_list_default_columns + if names == default_columns_names names = nil end end @@ -409,7 +464,7 @@ def project_statement project_clauses = [] - if project && !@project.descendants.active.empty? + if project && !project.descendants.active.empty? ids = [project.id] if has_filter?("subproject_id") case operator_for("subproject_id") @@ -443,71 +498,26 @@ # "me" value subsitution if %w(assigned_to_id author_id watcher_id).include?(field) - v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me") + if v.delete("me") + if User.current.logged? + v.push(User.current.id.to_s) + v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id' + else + v.push("0") + end + end end - sql = '' if field =~ /^cf_(\d+)$/ # custom field - db_table = CustomValue.table_name - db_field = 'value' - is_custom_filter = true - sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE " - sql << sql_for_field(field, operator, v, db_table, db_field, true) + ')' - elsif field == 'watcher_id' - db_table = Watcher.table_name - db_field = 'user_id' - sql << "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " - sql << sql_for_field(field, '=', v, db_table, db_field) + ')' - elsif field == "member_of_group" # named field - if operator == '*' # Any group - groups = Group.all - operator = '=' # Override the operator since we want to find by assigned_to - elsif operator == "!*" - groups = Group.all - operator = '!' # Override the operator since we want to find by assigned_to - else - groups = Group.find_all_by_id(v) - end - groups ||= [] - - members_of_groups = groups.inject([]) {|user_ids, group| - if group && group.user_ids.present? - user_ids << group.user_ids - end - user_ids.flatten.uniq.compact - }.sort.collect(&:to_s) - - sql << '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')' - - elsif field == "assigned_to_role" # named field - if operator == "*" # Any Role - roles = Role.givable - operator = '=' # Override the operator since we want to find by assigned_to - elsif operator == "!*" # No role - roles = Role.givable - operator = '!' # Override the operator since we want to find by assigned_to - else - roles = Role.givable.find_all_by_id(v) - end - roles ||= [] - - members_of_roles = roles.inject([]) {|user_ids, role| - if role && role.members - user_ids << role.members.collect(&:user_id) - end - user_ids.flatten.uniq.compact - }.sort.collect(&:to_s) - - sql << '(' + sql_for_field("assigned_to_id", operator, members_of_roles, Issue.table_name, "assigned_to_id", false) + ')' + filters_clauses << sql_for_custom_field(field, operator, v, $1) + elsif respond_to?("sql_for_#{field}_field") + # specific statement + filters_clauses << send("sql_for_#{field}_field", field, operator, v) else # regular field - db_table = Issue.table_name - db_field = field - sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')' + filters_clauses << '(' + sql_for_field(field, operator, v, Issue.table_name, field) + ')' end - filters_clauses << sql - end if filters and valid? filters_clauses << project_statement @@ -518,7 +528,7 @@ # Returns the issue count def issue_count - Issue.count(:include => [:status, :project], :conditions => statement) + Issue.visible.count(:include => [:status, :project], :conditions => statement) rescue ::ActiveRecord::StatementInvalid => e raise StatementInvalid.new(e.message) end @@ -548,10 +558,13 @@ def issues(options={}) order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') order_option = nil if order_option.blank? + + joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil - Issue.visible.find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, - :conditions => Query.merge_conditions(statement, options[:conditions]), + Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, + :conditions => statement, :order => order_option, + :joins => joins, :limit => options[:limit], :offset => options[:offset] rescue ::ActiveRecord::StatementInvalid => e @@ -573,21 +586,83 @@ # Returns the versions # Valid options are :conditions def versions(options={}) - Version.visible.find :all, :include => :project, - :conditions => Query.merge_conditions(project_statement, options[:conditions]) + Version.visible.scoped(:conditions => options[:conditions]).find :all, :include => :project, :conditions => project_statement rescue ::ActiveRecord::StatementInvalid => e raise StatementInvalid.new(e.message) end + def sql_for_watcher_id_field(field, operator, value) + db_table = Watcher.table_name + "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " + + sql_for_field(field, '=', value, db_table, 'user_id') + ')' + end + + def sql_for_member_of_group_field(field, operator, value) + if operator == '*' # Any group + groups = Group.all + operator = '=' # Override the operator since we want to find by assigned_to + elsif operator == "!*" + groups = Group.all + operator = '!' # Override the operator since we want to find by assigned_to + else + groups = Group.find_all_by_id(value) + end + groups ||= [] + + members_of_groups = groups.inject([]) {|user_ids, group| + if group && group.user_ids.present? + user_ids << group.user_ids + end + user_ids.flatten.uniq.compact + }.sort.collect(&:to_s) + + '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')' + end + + def sql_for_assigned_to_role_field(field, operator, value) + case operator + when "*", "!*" # Member / Not member + sw = operator == "!*" ? 'NOT' : '' + nl = operator == "!*" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' + "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}" + + " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))" + when "=", "!" + role_cond = value.any? ? + "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" : + "1=0" + + sw = operator == "!" ? 'NOT' : '' + nl = operator == "!" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' + "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}, #{MemberRole.table_name}" + + " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id AND #{Member.table_name}.id = #{MemberRole.table_name}.member_id AND #{role_cond}))" + end + end + private + def sql_for_custom_field(field, operator, value, custom_field_id) + db_table = CustomValue.table_name + db_field = 'value' + "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " + + sql_for_field(field, operator, value, db_table, db_field, true) + ')' + end + # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+ def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false) sql = '' case operator when "=" if value.any? - sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" + case type_for(field) + when :date, :date_past + sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil)) + when :integer + sql = "#{db_table}.#{db_field} = #{value.first.to_i}" + when :float + sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}" + else + sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" + end else # IN an empty set sql = "1=0" @@ -606,36 +681,64 @@ sql = "#{db_table}.#{db_field} IS NOT NULL" sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter when ">=" - sql = "#{db_table}.#{db_field} >= #{value.first.to_i}" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil) + else + if is_custom_filter + sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_f}" + else + sql = "#{db_table}.#{db_field} >= #{value.first.to_f}" + end + end when "<=" - sql = "#{db_table}.#{db_field} <= #{value.first.to_i}" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil)) + else + if is_custom_filter + sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_f}" + else + sql = "#{db_table}.#{db_field} <= #{value.first.to_f}" + end + end + when "><" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil)) + else + if is_custom_filter + sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f}" + else + sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}" + end + end when "o" sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id" when "c" sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id" when ">t-" - sql = date_range_clause(db_table, db_field, - value.first.to_i, 0) + sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0) when "t+" - sql = date_range_clause(db_table, db_field, value.first.to_i, nil) + sql = relative_date_clause(db_table, db_field, value.first.to_i, nil) when "= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) - sql = date_range_clause(db_table, db_field, - days_ago, - days_ago + 6) + sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) when "~" sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" when "!~" sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" + else + raise "Unknown query operator #{operator}" end return sql @@ -654,6 +757,10 @@ options = { :type => :date, :order => 20 } when "bool" options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 } + when "int" + options = { :type => :integer, :order => 20 } + when "float" + options = { :type => :float, :order => 20 } when "user", "version" next unless project options = { :type => :list_optional, :values => field.possible_values_options(project), :order => 20} @@ -665,14 +772,22 @@ end # Returns a SQL clause for a date or datetime field. - def date_range_clause(table, field, from, to) + def date_clause(table, field, from, to) s = [] if from - s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)]) + from_yesterday = from - 1 + from_yesterday_utc = Time.gm(from_yesterday.year, from_yesterday.month, from_yesterday.day) + s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_utc.end_of_day)]) end if to - s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date((Date.today + to).to_time.end_of_day)]) + to_utc = Time.gm(to.year, to.month, to.day) + s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_utc.end_of_day)]) end s.join(' AND ') end + + # Returns a SQL clause for a date or datetime field using relative dates. + def relative_date_clause(table, field, days_from, days_to) + date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) + end end diff -r 487d96eac004 -r 5e80956cc792 app/models/repository.rb --- a/app/models/repository.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/repository.rb Mon Feb 27 13:53:18 2012 +0000 @@ -15,6 +15,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +class ScmFetchError < Exception; end + class Repository < ActiveRecord::Base include Redmine::Ciphering @@ -30,7 +32,13 @@ validates_length_of :password, :maximum => 255, :allow_nil => true # Checks if the SCM is enabled when creating a repository - validate_on_create { |r| r.errors.add(:type, :invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) } + validate :repo_create_validation, :on => :create + + def repo_create_validation + unless Setting.enabled_scm.include?(self.class.name.demodulize) + errors.add(:type, :invalid) + end + end def self.human_attribute_name(attribute_key_name) attr_name = attribute_key_name @@ -100,6 +108,10 @@ false end + def supports_revision_graph? + false + end + def entry(path=nil, identifier=nil) scm.entry(path, identifier) end @@ -308,13 +320,6 @@ private - def before_save - # Strips url and root_url - url.strip! - root_url.strip! - true - end - def clear_changesets cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}" connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") diff -r 487d96eac004 -r 5e80956cc792 app/models/repository/darcs.rb.rej --- a/app/models/repository/darcs.rb.rej Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ ---- app/models/repository/darcs.rb -+++ app/models/repository/darcs.rb -@@ -85,11 +85,7 @@ - :comments => revision.message) - - revision.paths.each do |change| -- Change.create(:changeset => changeset, -- :action => change[:action], -- :path => change[:path], -- :from_path => change[:from_path], -- :from_revision => change[:from_revision]) -+ changeset.create_change(change) - end - next_rev += 1 - end if revisions diff -r 487d96eac004 -r 5e80956cc792 app/models/repository/git.rb --- a/app/models/repository/git.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/repository/git.rb Mon Feb 27 13:53:18 2012 +0000 @@ -53,6 +53,10 @@ true end + def supports_revision_graph? + true + end + def repo_log_encoding 'UTF-8' end @@ -77,6 +81,9 @@ def default_branch scm.default_branch + rescue Exception => e + logger.error "git: error during get default branch: #{e.message}" + nil end def find_changeset_by_name(name) @@ -92,6 +99,17 @@ options = {:report_last_commit => extra_report_last_commit}) end + # With SCMs that have a sequential commit numbering, + # such as Subversion and Mercurial, + # Redmine is able to be clever and only fetch changesets + # going forward from the most recent one it knows about. + # + # However, Git does not have a sequential commit numbering. + # + # In order to fetch only new adding revisions, + # Redmine needs to parse revisions per branch. + # Branch "last_scmid" is for this requirement. + # # In Git and Mercurial, revisions are not in date order. # Redmine Mercurial fixed issues. # * Redmine Takes Too Long On Large Mercurial Repository @@ -126,7 +144,8 @@ merge_extra_info(h) self.save end - scm_brs.each do |br| + scm_brs.each do |br1| + br = br1.to_s from_scmid = nil from_scmid = h["branches"][br]["last_scmid"] if h["branches"][br] h["branches"][br] ||= {} @@ -134,7 +153,12 @@ db_rev = find_changeset_by_name(rev.revision) transaction do if db_rev.nil? - save_revision(rev) + db_saved_rev = save_revision(rev) + parents = {} + parents[db_saved_rev] = rev.parents unless rev.parents.nil? + parents.each do |ch, chparents| + ch.parents = chparents.collect{|rp| find_changeset_by_name(rp)}.compact + end end h["branches"][br]["last_scmid"] = rev.scmid merge_extra_info(h) @@ -161,6 +185,7 @@ :path => file[:path]) end end + changeset end private :save_revision diff -r 487d96eac004 -r 5e80956cc792 app/models/repository/mercurial.rb --- a/app/models/repository/mercurial.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/repository/mercurial.rb Mon Feb 27 13:53:18 2012 +0000 @@ -19,12 +19,15 @@ class Repository::Mercurial < Repository # sort changesets by revision number - has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id' + has_many :changesets, + :order => "#{Changeset.table_name}.id DESC", + :foreign_key => 'repository_id' - attr_protected :root_url + attr_protected :root_url # validates_presence_of :url - FETCH_AT_ONCE = 100 # number of changesets to fetch at once + # number of changesets to fetch at once + FETCH_AT_ONCE = 100 def self.human_attribute_name(attribute_key_name) attr_name = attribute_key_name @@ -46,6 +49,10 @@ true end + def supports_revision_graph? + true + end + def repo_log_encoding 'UTF-8' end @@ -84,9 +91,11 @@ # Sqlite3 and PostgreSQL pass. # Is this MySQL bug? def latest_changesets(path, rev, limit=10) - changesets.find(:all, :include => :user, + changesets.find(:all, + :include => :user, :conditions => latest_changesets_cond(path, rev, limit), - :limit => limit, :order => "#{Changeset.table_name}.id DESC") + :limit => limit, + :order => "#{Changeset.table_name}.id DESC") end def latest_changesets_cond(path, rev, limit) @@ -108,16 +117,14 @@ cond << "#{Changeset.table_name}.id <= ?" args << last.id end - unless path.blank? cond << "EXISTS (SELECT * FROM #{Change.table_name} WHERE #{Change.table_name}.changeset_id = #{Changeset.table_name}.id AND (#{Change.table_name}.path = ? OR #{Change.table_name}.path LIKE ? ESCAPE ?))" args << path.with_leading_slash - args << "#{path.with_leading_slash.gsub(/[%_\\]/) { |s| "\\#{s}" }}/%" << '\\' + args << "#{path.with_leading_slash.gsub(%r{[%_\\]}) { |s| "\\#{s}" }}/%" << '\\' end - [cond.join(' AND '), *args] unless cond.empty? end private :latest_changesets_cond @@ -125,23 +132,27 @@ def fetch_changesets return if scm.info.nil? scm_rev = scm.info.lastrev.revision.to_i - db_rev = latest_changeset ? latest_changeset.revision.to_i : -1 + db_rev = latest_changeset ? latest_changeset.revision.to_i : -1 return unless db_rev < scm_rev # already up-to-date logger.debug "Fetching changesets for repository #{url}" if logger (db_rev + 1).step(scm_rev, FETCH_AT_ONCE) do |i| transaction do scm.each_revision('', i, [i + FETCH_AT_ONCE - 1, scm_rev].min) do |re| - cs = Changeset.create(:repository => self, - :revision => re.revision, - :scmid => re.scmid, - :committer => re.author, + cs = Changeset.create(:repository => self, + :revision => re.revision, + :scmid => re.scmid, + :committer => re.author, :committed_on => re.time, - :comments => re.message) + :comments => re.message) re.paths.each { |e| cs.create_change(e) } + parents = {} + parents[cs] = re.parents unless re.parents.nil? + parents.each do |ch, chparents| + ch.parents = chparents.collect{|rp| find_changeset_by_name(rp)}.compact + end end end end - self end end diff -r 487d96eac004 -r 5e80956cc792 app/models/repository/mercurial.rb.rej --- a/app/models/repository/mercurial.rb.rej Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ ---- app/models/repository/mercurial.rb -+++ app/models/repository/mercurial.rb -@@ -78,11 +78,7 @@ - :comments => revision.message) - - revision.paths.each do |change| -- Change.create(:changeset => changeset, -- :action => change[:action], -- :path => change[:path], -- :from_path => change[:from_path], -- :from_revision => change[:from_revision]) -+ changeset.create_change(change) - end - end - end unless revisions.nil? diff -r 487d96eac004 -r 5e80956cc792 app/models/repository/subversion.rb.rej --- a/app/models/repository/subversion.rb.rej Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ ---- app/models/repository/subversion.rb -+++ app/models/repository/subversion.rb -@@ -63,11 +63,7 @@ - :comments => revision.message) - - revision.paths.each do |change| -- Change.create(:changeset => changeset, -- :action => change[:action], -- :path => change[:path], -- :from_path => change[:from_path], -- :from_revision => change[:from_revision]) -+ changeset.create_change(change) - end unless changeset.new_record? - end - end unless revisions.nil? diff -r 487d96eac004 -r 5e80956cc792 app/models/role.rb --- a/app/models/role.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/role.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,7 +19,7 @@ # Built-in roles BUILTIN_NON_MEMBER = 1 BUILTIN_ANONYMOUS = 2 - + ISSUES_VISIBILITY_OPTIONS = [ ['all', :label_issues_visibility_all], ['default', :label_issues_visibility_public], @@ -31,18 +31,18 @@ compare = 'not' if args.first == true { :conditions => "#{compare} builtin = 0" } } - + before_destroy :check_deletable has_many :workflows, :dependent => :delete_all do def copy(source_role) Workflow.copy(nil, source_role, nil, proxy_owner) end end - + has_many :member_roles, :dependent => :destroy has_many :members, :through => :member_roles acts_as_list - + serialize :permissions, Array attr_protected :builtin @@ -52,11 +52,11 @@ validates_inclusion_of :issues_visibility, :in => ISSUES_VISIBILITY_OPTIONS.collect(&:first), :if => lambda {|role| role.respond_to?(:issues_visibility)} - + def permissions read_attribute(:permissions) || [] end - + def permissions=(perms) perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms write_attribute(:permissions, perms) @@ -79,20 +79,20 @@ perms.each { |p| permissions.delete(p.to_sym) } save! end - + # Returns true if the role has the given permission def has_permission?(perm) !permissions.nil? && permissions.include?(perm.to_sym) end - + def <=>(role) role ? position <=> role.position : -1 end - + def to_s name end - + def name case builtin when 1; l(:label_role_non_member, :default => read_attribute(:name)) @@ -100,17 +100,17 @@ else; read_attribute(:name) end end - + # Return true if the role is a builtin role def builtin? self.builtin != 0 end - + # Return true if the role is a project member role def member? !self.builtin? end - + # Return true if role is allowed to do the specified action # action can be: # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') @@ -122,7 +122,7 @@ allowed_permissions.include? action end end - + # Return all the permissions that can be given to the role def setable_permissions setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions @@ -139,31 +139,17 @@ # Return the builtin 'non member' role. If the role doesn't exist, # it will be created on the fly. def self.non_member - non_member_role = find(:first, :conditions => {:builtin => BUILTIN_NON_MEMBER}) - if non_member_role.nil? - non_member_role = create(:name => 'Non member', :position => 0) do |role| - role.builtin = BUILTIN_NON_MEMBER - end - raise 'Unable to create the non-member role.' if non_member_role.new_record? - end - non_member_role + find_or_create_system_role(BUILTIN_NON_MEMBER, 'Non member') end # Return the builtin 'anonymous' role. If the role doesn't exist, # it will be created on the fly. def self.anonymous - anonymous_role = find(:first, :conditions => {:builtin => BUILTIN_ANONYMOUS}) - if anonymous_role.nil? - anonymous_role = create(:name => 'Anonymous', :position => 0) do |role| - role.builtin = BUILTIN_ANONYMOUS - end - raise 'Unable to create the anonymous role.' if anonymous_role.new_record? - end - anonymous_role + find_or_create_system_role(BUILTIN_ANONYMOUS, 'Anonymous') end - private + def allowed_permissions @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name} end @@ -171,9 +157,20 @@ def allowed_actions @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten end - + def check_deletable raise "Can't delete role" if members.any? raise "Can't delete builtin role" if builtin? end + + def self.find_or_create_system_role(builtin, name) + role = first(:conditions => {:builtin => builtin}) + if role.nil? + role = create(:name => name, :position => 0) do |r| + r.builtin = builtin + end + raise "Unable to create the #{name} role." if role.new_record? + end + role + end end diff -r 487d96eac004 -r 5e80956cc792 app/models/setting.rb --- a/app/models/setting.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/setting.rb Mon Feb 27 13:53:18 2012 +0000 @@ -75,7 +75,7 @@ TIS-620) cattr_accessor :available_settings - @@available_settings = YAML::load(File.open("#{RAILS_ROOT}/config/settings.yml")) + @@available_settings = YAML::load(File.open("#{Rails.root}/config/settings.yml")) Redmine::Plugin.all.each do |plugin| next unless plugin.settings @@available_settings["plugin_#{plugin.id}"] = {'default' => plugin.settings[:default], 'serialized' => true} @@ -151,11 +151,16 @@ def self.check_cache settings_updated_on = Setting.maximum(:updated_on) if settings_updated_on && @cached_cleared_on <= settings_updated_on - @cached_settings.clear - @cached_cleared_on = Time.now - logger.info "Settings cache cleared." if logger + clear_cache end end + + # Clears the settings cache + def self.clear_cache + @cached_settings.clear + @cached_cleared_on = Time.now + logger.info "Settings cache cleared." if logger + end private # Returns the Setting instance for the setting named name @@ -164,6 +169,10 @@ name = name.to_s raise "There's no setting named #{name}" unless @@available_settings.has_key?(name) setting = find_by_name(name) - setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name + unless setting + setting = new(:name => name) + setting.value = @@available_settings[name]['default'] + end + setting end end diff -r 487d96eac004 -r 5e80956cc792 app/models/time_entry.rb --- a/app/models/time_entry.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/time_entry.rb Mon Feb 27 13:53:18 2012 +0000 @@ -38,6 +38,8 @@ validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on validates_numericality_of :hours, :allow_nil => true, :message => :invalid validates_length_of :comments, :maximum => 255, :allow_nil => true + before_validation :set_project_if_nil + validate :validate_time_entry named_scope :visible, lambda {|*args| { :include => :project, @@ -53,11 +55,11 @@ end end - def before_validation + def set_project_if_nil self.project = issue.project if issue && project.nil? end - def validate + def validate_time_entry errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000) errors.add :project_id, :invalid if project.nil? errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) @@ -84,14 +86,6 @@ (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project) end - # TODO: remove this method in 1.3.0 - def self.visible_by(usr) - ActiveSupport::Deprecation.warn "TimeEntry.visible_by is deprecated and will be removed in Redmine 1.3.0. Use the visible scope instead." - with_scope(:find => { :conditions => Project.allowed_to_condition(usr, :view_time_entries) }) do - yield - end - end - def self.earilest_date_for_project(project=nil) finder_conditions = ARCondition.new(Project.allowed_to_condition(User.current, :view_time_entries)) if project diff -r 487d96eac004 -r 5e80956cc792 app/models/time_entry_activity.rb --- a/app/models/time_entry_activity.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/time_entry_activity.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,7 +19,7 @@ has_many :time_entries, :foreign_key => 'activity_id' OptionName = :enumeration_activities - + def option_name OptionName end diff -r 487d96eac004 -r 5e80956cc792 app/models/time_entry_activity_custom_field.rb --- a/app/models/time_entry_activity_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/time_entry_activity_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -20,4 +20,3 @@ :enumeration_activities end end - diff -r 487d96eac004 -r 5e80956cc792 app/models/time_entry_custom_field.rb --- a/app/models/time_entry_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/time_entry_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/token.rb --- a/app/models/token.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/token.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,30 +18,30 @@ class Token < ActiveRecord::Base belongs_to :user validates_uniqueness_of :value - - before_create :delete_previous_tokens - + + before_create :delete_previous_tokens, :generate_new_token + @@validity_time = 1.day - - def before_create + + def generate_new_token self.value = Token.generate_token_value end - # Return true if token has expired + # Return true if token has expired def expired? return Time.now > self.created_on + @@validity_time end - + # Delete all expired tokens def self.destroy_expired Token.delete_all ["action <> 'feeds' AND created_on < ?", Time.now - @@validity_time] end - + private def self.generate_token_value ActiveSupport::SecureRandom.hex(20) end - + # Removes obsolete tokens (same user and action) def delete_previous_tokens if user diff -r 487d96eac004 -r 5e80956cc792 app/models/tracker.rb --- a/app/models/tracker.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/tracker.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,29 +1,29 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class Tracker < ActiveRecord::Base - before_destroy :check_integrity + before_destroy :check_integrity has_many :issues has_many :workflows, :dependent => :delete_all do def copy(source_tracker) Workflow.copy(source_tracker, nil, proxy_owner, nil) end end - + has_and_belongs_to_many :projects has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id' acts_as_list @@ -33,9 +33,9 @@ validates_length_of :name, :maximum => 30 named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} - + def to_s; name end - + def <=>(tracker) name <=> tracker.name end @@ -43,24 +43,24 @@ def self.all find(:all, :order => 'position') end - + # Returns an array of IssueStatus that are used # in the tracker's workflows def issue_statuses if @issue_statuses - return @issue_statuses + return @issue_statuses elsif new_record? return [] end - + ids = Workflow. connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{Workflow.table_name} WHERE tracker_id = #{id}"). flatten. uniq - + @issue_statuses = IssueStatus.find_all_by_id(ids).sort end - + private def check_integrity raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id]) diff -r 487d96eac004 -r 5e80956cc792 app/models/user.rb --- a/app/models/user.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/user.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,19 +19,20 @@ class User < Principal include Redmine::SafeAttributes - + # Account statuses STATUS_ANONYMOUS = 0 STATUS_ACTIVE = 1 STATUS_REGISTERED = 2 STATUS_LOCKED = 3 - + + # Different ways of displaying/sorting users USER_FORMATS = { - :firstname_lastname => '#{firstname} #{lastname}', - :firstname => '#{firstname}', - :lastname_firstname => '#{lastname} #{firstname}', - :lastname_coma_firstname => '#{lastname}, #{firstname}', - :username => '#{login}' + :firstname_lastname => {:string => '#{firstname} #{lastname}', :order => %w(firstname lastname id)}, + :firstname => {:string => '#{firstname}', :order => %w(firstname id)}, + :lastname_firstname => {:string => '#{lastname} #{firstname}', :order => %w(lastname firstname id)}, + :lastname_coma_firstname => {:string => '#{lastname}, #{firstname}', :order => %w(lastname firstname id)}, + :username => {:string => '#{login}', :order => %w(login id)}, } MAIL_NOTIFICATION_OPTIONS = [ @@ -45,13 +46,12 @@ has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)}, :after_remove => Proc.new {|user, group| group.user_removed(user)} - has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify has_many :changesets, :dependent => :nullify has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'" has_one :api_token, :class_name => 'Token', :conditions => "action='api'" belongs_to :auth_source - + has_one :ssamr_user_detail, :dependent => :destroy, :class_name => 'SsamrUserDetail' accepts_nested_attributes_for :ssamr_user_detail @@ -59,9 +59,9 @@ # Active non-anonymous users scope named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}" - + acts_as_customizable - + attr_accessor :password, :password_confirmation attr_accessor :last_before_login_on # Prevents unauthorized assignments @@ -77,13 +77,16 @@ validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i validates_length_of :login, :maximum => 30 validates_length_of :firstname, :lastname, :maximum => 30 - validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true + validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_blank => true validates_length_of :mail, :maximum => 60, :allow_nil => true validates_confirmation_of :password, :allow_nil => true validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true + validate :validate_password_length + before_create :set_mail_notification + before_save :update_hashed_password before_destroy :remove_references_before_destroy - + validates_acceptance_of :terms_and_conditions, :on => :create, :message => :must_accept_terms_and_conditions named_scope :in_group, lambda {|group| @@ -94,29 +97,29 @@ group_id = group.is_a?(Group) ? group.id : group.to_i { :conditions => ["#{User.table_name}.id NOT IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id] } } - - def before_create + + def set_mail_notification self.mail_notification = Setting.default_notification_option if self.mail_notification.blank? true end - - def before_save + + def update_hashed_password # update hashed_password if password was set if self.password && self.auth_source_id.blank? salt_password(password) end end - + def reload(*args) @name = nil @projects_by_role = nil super end - + def mail=(arg) write_attribute(:mail, arg.to_s.strip) end - + def description=(arg) write_attribute(:description, arg.to_s.strip) end @@ -133,7 +136,7 @@ end self.read_attribute(:identity_url) end - + # Returns the user that matches provided login and password, or nil def self.try_to_login(login, password) # Make sure no one can sign in with an empty password @@ -161,13 +164,13 @@ logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source end end - end + end user.update_attribute(:last_login_on, Time.now) if user && !user.new_record? user rescue => text raise text end - + # Returns the user who matches the given autologin +key+ or nil def self.try_to_autologin(key) tokens = Token.find_all_by_action_and_value('autologin', key) @@ -180,16 +183,32 @@ end end end - + + def self.name_formatter(formatter = nil) + USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname] + end + + # Returns an array of fields names than can be used to make an order statement for users + # according to how user names are displayed + # Examples: + # + # User.fields_for_order_statement => ['users.login', 'users.id'] + # User.fields_for_order_statement('authors') => ['authors.login', 'authors.id'] + def self.fields_for_order_statement(table=nil) + table ||= table_name + name_formatter[:order].map {|field| "#{table}.#{field}"} + end + # Return user's full name for display def name(formatter = nil) + f = self.class.name_formatter(formatter) if formatter - eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"') + eval('"' + f[:string] + '"') else - @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"') + @name ||= eval('"' + f[:string] + '"') end end - + def active? self.status == STATUS_ACTIVE end @@ -197,7 +216,7 @@ def registered? self.status == STATUS_REGISTERED end - + def locked? self.status == STATUS_LOCKED end @@ -234,7 +253,7 @@ User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password end end - + # Generates a random salt and computes hashed_password for +clear_password+ # The hashed password is stored in the following form: SHA1(salt + SHA1(password)) def salt_password(clear_password) @@ -259,19 +278,19 @@ self.password_confirmation = password self end - + def pref self.preference ||= UserPreference.new(:user => self) end - + def time_zone @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone]) end - + def wants_comments_in_reverse_order? self.pref[:comments_sorting] == 'desc' end - + # Return user's RSS key (a 40 chars long string), used to access feeds def rss_key token = self.rss_token || Token.create(:user => self, :action => 'feeds') @@ -283,12 +302,12 @@ token = self.api_token || self.create_api_token(:action => 'api') token.value end - + # Return an array of project ids for which the user has explicitly turned mail notifications on def notified_projects_ids @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id) end - + def notified_project_ids=(ids) Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id]) Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty? @@ -316,7 +335,7 @@ def self.find_by_login(login) # force string comparison to be case sensitive on MySQL type_cast = (ActiveRecord::Base.connection.adapter_name == 'MySQL') ? 'BINARY' : '' - + # First look for an exact match user = first(:conditions => ["#{type_cast} login = ?", login]) # Fail over to case-insensitive if none was found @@ -327,21 +346,21 @@ token = Token.find_by_value(key) token && token.user.active? ? token.user : nil end - + def self.find_by_api_key(key) token = Token.find_by_action_and_value('api', key) token && token.user.active? ? token.user : nil end - + # Makes find_by_mail case-insensitive def self.find_by_mail(mail) find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase]) end - + def to_s name end - + # Returns the current day according to user's time zone def today if time_zone.nil? @@ -350,15 +369,15 @@ Time.now.in_time_zone(time_zone).to_date end end - + def logged? true end - + def anonymous? !logged? end - + # Return user's roles for project def roles_for_project(project) roles = [] @@ -379,16 +398,16 @@ end roles end - + # Return true if the user is a member of project def member_of?(project) !roles_for_project(project).detect {|role| role.member?}.nil? end - + # Returns a hash of user's projects grouped by roles def projects_by_role return @projects_by_role if @projects_by_role - + @projects_by_role = Hash.new {|h,k| h[k]=[]} memberships.each do |membership| membership.roles.each do |role| @@ -398,10 +417,21 @@ @projects_by_role.each do |role, projects| projects.uniq! end - + @projects_by_role end - + + # Returns true if user is arg or belongs to arg + def is_or_belongs_to?(arg) + if arg.is_a?(User) + self == arg + elsif arg.is_a?(Group) + arg.users.include?(self) + else + false + end + end + # Return true if the user is allowed to do the specified action on a specific context # Action can be: # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') @@ -409,7 +439,7 @@ # Context can be: # * a project : returns true if user is allowed to do the specified action on this project # * an array of projects : returns true if user is allowed on every project - # * nil with options[:global] set : check if user has at least one role allowed for this action, + # * nil with options[:global] set : check if user has at least one role allowed for this action, # or falls back to Non Member / Anonymous permissions depending if the user is logged def allowed_to?(action, context, options={}, &block) if context && context.is_a?(Project) @@ -419,7 +449,7 @@ return false unless context.allows_to?(action) # Admin users are authorized for anything else return true if admin? - + roles = roles_for_project(context) return false unless roles roles.detect {|role| @@ -437,7 +467,7 @@ elsif options[:global] # Admin users are always authorized return true if admin? - + # authorize if user has at least one role that has this permission roles = memberships.collect {|m| m.roles}.flatten.uniq roles << (self.logged? ? Role.non_member : Role.anonymous) @@ -465,14 +495,14 @@ 'custom_field_values', 'custom_fields', 'identity_url' - + safe_attributes 'status', 'auth_source_id', :if => lambda {|user, current_user| current_user.admin?} - + safe_attributes 'group_ids', :if => lambda {|user, current_user| current_user.admin? && !user.new_record?} - + # Utility method to help check if a user should be notified about an # event. # @@ -483,7 +513,7 @@ true when 'selected' # user receives notifications for created/assigned issues on unselected projects - if object.is_a?(Issue) && (object.author == self || object.assigned_to == self) + if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to)) true else false @@ -491,13 +521,13 @@ when 'none' false when 'only_my_events' - if object.is_a?(Issue) && (object.author == self || object.assigned_to == self) + if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to)) true else false end when 'only_assigned' - if object.is_a?(Issue) && object.assigned_to == self + if object.is_a?(Issue) && is_or_belongs_to?(object.assigned_to) true else false @@ -512,15 +542,15 @@ false end end - + def self.current=(user) @current_user = user end - + def self.current @current_user ||= User.anonymous end - + # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only # one anonymous user per database. def self.anonymous @@ -545,23 +575,23 @@ end end end - + protected - - def validate + + def validate_password_length # Password length validation based on setting if !password.nil? && password.size < Setting.password_min_length.to_i errors.add(:password, :too_short, :count => Setting.password_min_length.to_i) end end - + private - + # Removes references that are not handled by associations # Things that are not deleted are reassociated with the anonymous user def remove_references_before_destroy return if self.id.nil? - + substitute = User.anonymous Attachment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] Comment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] @@ -581,30 +611,30 @@ WikiContent.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] WikiContent::Version.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] end - + # Return password digest def self.hash_password(clear_password) Digest::SHA1.hexdigest(clear_password || "") end - + # Returns a 128bits random salt as a hex string (32 chars long) def self.generate_salt ActiveSupport::SecureRandom.hex(16) end - + end class AnonymousUser < User - + def validate_on_create # There should be only one AnonymousUser in the database - errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first) + errors.add :base, 'An anonymous user already exists.' if AnonymousUser.find(:first) end - + def available_custom_fields [] end - + # Overrides a few properties def logged?; false end def admin; false end @@ -612,7 +642,7 @@ def mail; nil end def time_zone; nil end def rss_key; nil end - + # Anonymous user can not be destroyed def destroy false diff -r 487d96eac004 -r 5e80956cc792 app/models/user_custom_field.rb --- a/app/models/user_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/user_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/user_preference.rb --- a/app/models/user_preference.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/user_preference.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,18 +18,18 @@ class UserPreference < ActiveRecord::Base belongs_to :user serialize :others - + attr_protected :others - + def initialize(attributes = nil) super self.others ||= {} end - + def before_save self.others ||= {} end - + def [](attr_name) if attribute_present? attr_name super @@ -37,7 +37,7 @@ others ? others[attr_name] : nil end end - + def []=(attr_name, value) if attribute_present? attr_name super @@ -48,10 +48,10 @@ value end end - + def comments_sorting; self[:comments_sorting] end def comments_sorting=(order); self[:comments_sorting]=order end - + def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end end diff -r 487d96eac004 -r 5e80956cc792 app/models/version.rb --- a/app/models/version.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/version.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -25,7 +25,7 @@ VERSION_STATUSES = %w(open locked closed) VERSION_SHARINGS = %w(none descendants hierarchy tree system) - + validates_presence_of :name validates_uniqueness_of :name, :scope => [:project_id] validates_length_of :name, :maximum => 60 @@ -42,26 +42,35 @@ def visible?(user=User.current) user.allowed_to?(:view_issues, self.project) end - + + # Version files have same visibility as project files + def attachments_visible?(*args) + project.present? && project.attachments_visible?(*args) + end + def start_date @start_date ||= fixed_issues.minimum('start_date') end - + def due_date effective_date end - + + def due_date=(arg) + self.effective_date=(arg) + end + # Returns the total estimated time for this version # (sum of leaves estimated_hours) def estimated_hours @estimated_hours ||= fixed_issues.leaves.sum(:estimated_hours).to_f end - + # Returns the total reported time for this version def spent_hours @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ?", id]).to_f end - + def closed? status == 'closed' end @@ -69,7 +78,7 @@ def open? status == 'open' end - + # Returns true if the version is completed: due date reached and no open issues def completed? effective_date && (effective_date <= Date.today) && (open_issues_count == 0) @@ -85,7 +94,7 @@ false # No issues so it's not late end end - + # Returns the completion percentage of this version based on the amount of open/closed issues # and the time spent on the open issues. def completed_pourcent @@ -97,7 +106,7 @@ issues_progress(false) + issues_progress(true) end end - + # Returns the percentage of issues that have been marked as 'closed'. def closed_pourcent if issues_count == 0 @@ -106,17 +115,17 @@ issues_progress(false) end end - + # Returns true if the version is overdue: due date reached and some open issues def overdue? effective_date && (effective_date < Date.today) && (open_issues_count > 0) end - + # Returns assigned issues count def issues_count @issue_count ||= fixed_issues.count end - + # Returns the total amount of open issues for this version. def open_issues_count @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) @@ -126,20 +135,20 @@ def closed_issues_count @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status) end - + def wiki_page if project.wiki && !wiki_page_title.blank? @wiki_page ||= project.wiki.find_page(wiki_page_title) end @wiki_page end - + def to_s; name end def to_s_with_project "#{project} - #{name}" end - + # Versions are sorted by effective_date and "Project Name - Version name" # Those with no effective_date are at the end, sorted by "Project Name - Version name" def <=>(version) @@ -161,7 +170,7 @@ end end end - + # Returns the sharings that +user+ can set the version to def allowed_sharings(user = User.current) VERSION_SHARINGS.select do |s| @@ -182,7 +191,7 @@ end end end - + private # Update the issue's fixed versions. Used if a version's sharing changes. @@ -195,7 +204,7 @@ end end end - + # Returns the average estimated time of assigned issues # or 1 if no issue has an estimated time # Used to weigth unestimated issues in progress calculation @@ -209,7 +218,7 @@ end @estimated_average end - + # Returns the total progress of open or closed issues. The returned percentage takes into account # the amount of estimated time set for this version. # @@ -222,7 +231,7 @@ progress = 0 if issues_count > 0 ratio = open ? 'done_ratio' : 100 - + done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", :include => :status, :conditions => ["is_closed = ?", !open]).to_f diff -r 487d96eac004 -r 5e80956cc792 app/models/version_custom_field.rb --- a/app/models/version_custom_field.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/version_custom_field.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 app/models/watcher.rb --- a/app/models/watcher.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/watcher.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ class Watcher < ActiveRecord::Base belongs_to :watchable, :polymorphic => true belongs_to :user - + validates_presence_of :user validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id] @@ -34,25 +34,25 @@ pruned end end - + protected - + def validate errors.add :user_id, :invalid unless user.nil? || user.active? end - + private - + def self.prune_single_user(user, options={}) return unless user.is_a?(User) pruned = 0 find(:all, :conditions => {:user_id => user.id}).each do |watcher| next if watcher.watchable.nil? - + if options.has_key?(:project) next unless watcher.watchable.respond_to?(:project) && watcher.watchable.project == options[:project] end - + if watcher.watchable.respond_to?(:visible?) unless watcher.watchable.visible?(user) watcher.destroy diff -r 487d96eac004 -r 5e80956cc792 app/models/wiki.rb --- a/app/models/wiki.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/wiki.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -19,29 +19,29 @@ belongs_to :project has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title' has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all - + acts_as_watchable - + validates_presence_of :start_page validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/ - + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_wiki_pages, project) end - + # Returns the wiki page that acts as the sidebar content # or nil if no such page exists def sidebar @sidebar ||= find_page('Sidebar', :with_redirect => false) end - + # find the page with the given title # if page doesn't exist, return a new page def find_or_new_page(title) title = start_page if title.blank? find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title)) end - + # find the page with the given title def find_page(title, options = {}) @page_found_with_redirect = false @@ -58,7 +58,7 @@ end page end - + # Returns true if the last page was found with a redirect def page_found_with_redirect? @page_found_with_redirect @@ -82,7 +82,7 @@ end end end - + # turn a string into a valid page title def self.titleize(title) # replace spaces with _ and remove unwanted caracters @@ -90,5 +90,5 @@ # upcase the first letter title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title title - end + end end diff -r 487d96eac004 -r 5e80956cc792 app/models/wiki_content.rb --- a/app/models/wiki_content.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/wiki_content.rb Mon Feb 27 13:53:18 2012 +0000 @@ -45,6 +45,11 @@ notified.collect(&:mail) end + # Return true if the content is the current page content + def current_version? + true + end + class Version belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id' belongs_to :author, :class_name => '::User', :foreign_key => 'author_id' @@ -88,7 +93,9 @@ def text @text ||= case compression when 'gzip' - Zlib::Inflate.inflate(data) + str = Zlib::Inflate.inflate(data) + str.force_encoding("UTF-8") if str.respond_to?(:force_encoding) + str else # uncompressed data data @@ -99,6 +106,11 @@ page.project end + # Return true if the content is the current page content + def current_version? + page.content.version == self.version + end + # Returns the previous version or nil def previous @previous ||= WikiContent::Version.find(:first, diff -r 487d96eac004 -r 5e80956cc792 app/models/wiki_content_observer.rb --- a/app/models/wiki_content_observer.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/wiki_content_observer.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -19,7 +19,7 @@ def after_create(wiki_content) Mailer.deliver_wiki_content_added(wiki_content) if Setting.notified_events.include?('wiki_content_added') end - + def after_update(wiki_content) if wiki_content.text_changed? Mailer.deliver_wiki_content_updated(wiki_content) if Setting.notified_events.include?('wiki_content_updated') diff -r 487d96eac004 -r 5e80956cc792 app/models/wiki_page.rb --- a/app/models/wiki_page.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/wiki_page.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -30,33 +30,37 @@ :datetime => :created_on, :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}} - acts_as_searchable :columns => ['title', 'text'], + acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"], :include => [{:wiki => :project}, :content], :permission => :view_wiki_pages, :project_key => "#{Wiki.table_name}.project_id" attr_accessor :redirect_existing_links - + validates_presence_of :title validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/ validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false validates_associated :content - + + validate :validate_parent_title + before_destroy :remove_redirects + before_save :handle_redirects + # eager load information about last updates, without loading text named_scope :with_updated_on, { :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on", :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id" } - + # Wiki pages that are protected by default DEFAULT_PROTECTED_PAGES = %w(sidebar) - + def after_initialize if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase) self.protected = true end end - + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_wiki_pages, project) end @@ -67,8 +71,8 @@ write_attribute(:title, value) end - def before_save - self.title = Wiki.titleize(title) + def handle_redirects + self.title = Wiki.titleize(title) # Manage redirects if the title has changed if !@previous_title.blank? && (@previous_title != title) && !new_record? # Update redirects that point to the old title @@ -83,51 +87,51 @@ @previous_title = nil end end - - def before_destroy + + def remove_redirects # Remove redirects to this page wiki.redirects.find_all_by_redirects_to(title).each(&:destroy) end - + def pretty_title WikiPage.pretty_title(title) end - + def content_for_version(version=nil) result = content.versions.find_by_version(version.to_i) if version result ||= content result end - + def diff(version_to=nil, version_from=nil) version_to = version_to ? version_to.to_i : self.content.version version_from = version_from ? version_from.to_i : version_to - 1 version_to, version_from = version_from, version_to unless version_from < version_to - + content_to = content.versions.find_by_version(version_to) content_from = content.versions.find_by_version(version_from) - + (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil end - + def annotate(version=nil) version = version ? version.to_i : self.content.version c = content.versions.find_by_version(version) c ? WikiAnnotate.new(c) : nil end - + def self.pretty_title(str) (str && str.is_a?(String)) ? str.tr('_', ' ') : str end - + def project wiki.project end - + def text content.text if content end - + def updated_on unless @updated_on if time = read_attribute(:updated_on) @@ -139,20 +143,20 @@ end @updated_on end - + # Returns true if usr is allowed to edit the page, otherwise false def editable_by?(usr) !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project) end - + def attachments_deletable?(usr=User.current) editable_by?(usr) && super(usr) end - + def parent_title @parent_title || (self.parent && self.parent.pretty_title) end - + def parent_title=(t) @parent_title = t parent_page = t.blank? ? nil : self.wiki.find_page(t) @@ -160,8 +164,8 @@ end protected - - def validate + + def validate_parent_title errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil? errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self)) errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id) @@ -170,7 +174,7 @@ class WikiDiff < Redmine::Helpers::Diff attr_reader :content_to, :content_from - + def initialize(content_to, content_from) @content_to = content_to @content_from = content_from @@ -180,7 +184,7 @@ class WikiAnnotate attr_reader :lines, :content - + def initialize(content) @content = content current = content @@ -212,7 +216,7 @@ break unless @lines.detect { |line| line[0].nil? } current = current.previous end - @lines.each { |line| + @lines.each { |line| line[0] ||= current.version # if the last known version is > 1 (eg. history was cleared), we don't know the author line[1] ||= current.author if current.version == 1 diff -r 487d96eac004 -r 5e80956cc792 app/models/wiki_redirect.rb --- a/app/models/wiki_redirect.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/wiki_redirect.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,23 +1,23 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class WikiRedirect < ActiveRecord::Base belongs_to :wiki - + validates_presence_of :title, :redirects_to validates_length_of :title, :redirects_to, :maximum => 255 end diff -r 487d96eac004 -r 5e80956cc792 app/models/workflow.rb --- a/app/models/workflow.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/models/workflow.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -21,13 +21,13 @@ belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' validates_presence_of :role, :old_status, :new_status - + # Returns workflow transitions count by tracker and role def self.count_by_tracker_and_role counts = connection.select_all("SELECT role_id, tracker_id, count(id) AS c FROM #{Workflow.table_name} GROUP BY role_id, tracker_id") roles = Role.find(:all, :order => 'builtin, position') trackers = Tracker.find(:all, :order => 'position') - + result = [] trackers.each do |tracker| t = [] @@ -37,7 +37,7 @@ end result << [tracker, t] end - + result end @@ -51,19 +51,19 @@ uniq. sort end - + # Copies workflows from source to targets def self.copy(source_tracker, source_role, target_trackers, target_roles) unless source_tracker.is_a?(Tracker) || source_role.is_a?(Role) raise ArgumentError.new("source_tracker or source_role must be specified") end - + target_trackers = [target_trackers].flatten.compact target_roles = [target_roles].flatten.compact - + target_trackers = Tracker.all if target_trackers.empty? target_roles = Role.all if target_roles.empty? - + target_trackers.each do |target_tracker| target_roles.each do |target_role| copy_one(source_tracker || target_tracker, @@ -73,17 +73,17 @@ end end end - + # Copies a single set of workflows from source to target def self.copy_one(source_tracker, source_role, target_tracker, target_role) unless source_tracker.is_a?(Tracker) && !source_tracker.new_record? && source_role.is_a?(Role) && !source_role.new_record? && target_tracker.is_a?(Tracker) && !target_tracker.new_record? && target_role.is_a?(Role) && !target_role.new_record? - + raise ArgumentError.new("arguments can not be nil or unsaved objects") end - + if source_tracker == target_tracker && source_role == target_role false else diff -r 487d96eac004 -r 5e80956cc792 app/views/account/login.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/account/login.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +<%= call_hook :view_account_login_top %> +
    +<% form_tag({:action=> "login"}) do %> +<%= back_url_hidden_field_tag %> + + + + + + + + + +<% if Setting.openid? %> + + + + +<% end %> + + + + + + + + +
    <%= text_field_tag 'username', nil, :tabindex => '1' %>
    <%= password_field_tag 'password', nil, :tabindex => '2' %>
    <%= text_field_tag "openid_url", nil, :tabindex => '3' %>
    + <% if Setting.autologin? %> + + <% end %> +
    + <% if Setting.lost_password? %> + <%= link_to l(:label_password_lost), :controller => 'account', :action => 'lost_password' %> + <% end %> + + +
    +<%= javascript_tag "Form.Element.focus('username');" %> +<% end %> +
    +<%= call_hook :view_account_login_bottom %> diff -r 487d96eac004 -r 5e80956cc792 app/views/account/login.rhtml --- a/app/views/account/login.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -<%= call_hook :view_account_login_top %> -
    -<% form_tag({:action=> "login"}) do %> -<%= back_url_hidden_field_tag %> - - - - - - - - - -<% if Setting.openid? %> - - - - -<% end %> - - - - - - - - -
    <%= text_field_tag 'username', nil, :tabindex => '1' %>
    <%= password_field_tag 'password', nil, :tabindex => '2' %>
    <%= text_field_tag "openid_url", nil, :tabindex => '3' %>
    - <% if Setting.autologin? %> - - <% end %> -
    - <% if Setting.lost_password? %> - <%= link_to l(:label_password_lost), :controller => 'account', :action => 'lost_password' %> - <% end %> - - -
    -<%= javascript_tag "Form.Element.focus('username');" %> -<% end %> -
    -<%= call_hook :view_account_login_bottom %> diff -r 487d96eac004 -r 5e80956cc792 app/views/account/lost_password.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/account/lost_password.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +

    <%=l(:label_password_lost)%>

    + +
    +<% form_tag({:action=> "lost_password"}, :class => "tabular") do %> + +

    +<%= text_field_tag 'mail', nil, :size => 40 %> +<%= submit_tag l(:button_submit) %>

    + +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/account/lost_password.rhtml --- a/app/views/account/lost_password.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -

    <%=l(:label_password_lost)%>

    - -
    -<% form_tag({:action=> "lost_password"}, :class => "tabular") do %> - -

    -<%= text_field_tag 'mail', nil, :size => 40 %> -<%= submit_tag l(:button_submit) %>

    - -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/account/password_recovery.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/account/password_recovery.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%=l(:label_password_lost)%>

    + +<%= error_messages_for 'user' %> + +<% form_tag({:token => @token.value}) do %> +
    +

    +<%= password_field_tag 'new_password', nil, :size => 25 %>
    +<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    + +

    +<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    +
    +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/account/password_recovery.rhtml --- a/app/views/account/password_recovery.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -

    <%=l(:label_password_lost)%>

    - -<%= error_messages_for 'user' %> - -<% form_tag({:token => @token.value}) do %> -
    -

    -<%= password_field_tag 'new_password', nil, :size => 25 %>
    -<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    - -

    -<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    -
    -

    <%= submit_tag l(:button_save) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/account/register.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/account/register.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +<%= javascript_include_tag "ssamr_institutions" %> +<%= javascript_include_tag "ssamr_registration" %> + +

    <%=l(:label_register)%> <%=link_to l(:label_login_with_open_id_option), signin_url if Setting.openid? %>

    + +<% form_tag({:action => 'register'}, :class => "tabular") do %> +<%= error_messages_for 'user' %> + +
    + +<% if @user.auth_source_id.nil? %> +

    +<%= text_field 'user', 'login', :size => 25 %>

    + +

    +<%= password_field_tag 'password', nil, :size => 25 %>
    +<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    + +

    +<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

    +<% end %> + +

    +<%= text_field 'user', 'firstname' %>

    + +

    +<%= text_field 'user', 'lastname' %>

    + +

    +<%= text_field 'user', 'mail' %>

    + + + +

    <%=l(:label_ssamr_details)%>

    + + <% fields_for :ssamr_user_details, :builder => TabularFormBuilder, :lang => current_language do |ssamr_user_detail| %> +

    + <%= ssamr_user_detail.text_area :description, :rows => 3, :cols => 40, :required => true, :class => 'wiki-edit' %> + <%=l(:text_user_ssamr_description_info)%> +

    + +

    + <%= ssamr_user_detail.radio_button :institution_type, true %> + <%= ssamr_user_detail.collection_select(:institution_id, Institution.find(:all, :order => "institutions.order"), :id, :name, {:selected => @selected_institution_id, :prompt => true}).gsub('&', '&') %> +

    + +

    + <%= ssamr_user_detail.radio_button :institution_type, false %> Other: + <%= ssamr_user_detail.text_field(:other_institution) %> +

    + <% end %> + +<% if Setting.openid? %> +

    +<%= text_field 'user', 'identity_url' %>

    +<% end %> + +<% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %> +

    <%= custom_field_tag_with_label :user, value %>

    +<% end %> + +
    + +<%= check_box :user, :terms_and_conditions %> <%= l(:accept_terms_and_conditions) %> <%= link_to("Terms and Conditions", "https://code.soundsoftware.ac.uk/projects/soundsoftware-site/wiki/TandCs", {:target => "_blank"}) %>. +
    +
    + +<%= submit_tag l(:button_submit) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/account/register.rhtml --- a/app/views/account/register.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -<%= javascript_include_tag "ssamr_institutions" %> -<%= javascript_include_tag "ssamr_registration" %> - -

    <%=l(:label_register)%> <%=link_to l(:label_login_with_open_id_option), signin_url if Setting.openid? %>

    - -<% form_tag({:action => 'register'}, :class => "tabular") do %> -<%= error_messages_for 'user' %> - -
    - -<% if @user.auth_source_id.nil? %> -

    -<%= text_field 'user', 'login', :size => 25 %>

    - -

    -<%= password_field_tag 'password', nil, :size => 25 %>
    -<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    - -

    -<%= password_field_tag 'password_confirmation', nil, :size => 25 %>

    -<% end %> - -

    -<%= text_field 'user', 'firstname' %>

    - -

    -<%= text_field 'user', 'lastname' %>

    - -

    -<%= text_field 'user', 'mail' %>

    - - - -

    <%=l(:label_ssamr_details)%>

    - - <% fields_for :ssamr_user_details, :builder => TabularFormBuilder, :lang => current_language do |ssamr_user_detail| %> -

    - <%= ssamr_user_detail.text_area :description, :rows => 3, :cols => 40, :required => true, :class => 'wiki-edit' %> - <%=l(:text_user_ssamr_description_info)%> -

    - -

    - <%= ssamr_user_detail.radio_button :institution_type, true %> - <%= ssamr_user_detail.collection_select(:institution_id, Institution.find(:all, :order => "institutions.order"), :id, :name, {:selected => @selected_institution_id, :prompt => true}).gsub('&', '&') %> -

    - -

    - <%= ssamr_user_detail.radio_button :institution_type, false %> Other: - <%= ssamr_user_detail.text_field(:other_institution) %> -

    - <% end %> - -<% if Setting.openid? %> -

    -<%= text_field 'user', 'identity_url' %>

    -<% end %> - -<% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %> -

    <%= custom_field_tag_with_label :user, value %>

    -<% end %> - -
    - -<%= check_box :user, :terms_and_conditions %> <%= l(:accept_terms_and_conditions) %> <%= link_to("Terms and Conditions", "https://code.soundsoftware.ac.uk/projects/soundsoftware-site/wiki/TandCs", {:target => "_blank"}) %>. -
    -
    - -<%= submit_tag l(:button_submit) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/activities/index.html.erb --- a/app/views/activities/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/activities/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -7,12 +7,12 @@
    <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
    - <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %> + <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %> <%= format_time(e.event_datetime, false) %> <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= link_to format_activity_title(e.event_title), e.event_url %>
    <%= format_activity_description(e.event_description) %> - <%= e.event_author if e.respond_to?(:event_author) %>
    + <%= link_to_user(e.event_author) if e.respond_to?(:event_author) %> <% end -%>
    <% end -%> @@ -21,18 +21,18 @@ <%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %>
    -<%= link_to_content_update('« ' + l(:label_previous), +<%= link_to_content_update("\xc2\xab " + l(:label_previous), params.merge(:from => @date_to - @days - 1), :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))) %>
    -<%= link_to_content_update(l(:label_next) + ' »', +<%= link_to_content_update(l(:label_next) + " \xc2\xbb", params.merge(:from => @date_to + @days - 1), :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))) unless @date_to >= Date.today %>
      <% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> + <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> <% end %> <% content_for :header_tags do %> @@ -44,11 +44,11 @@

    <%= l(:label_activity) %>

    <% @activity.event_types.each do |t| %> <%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> -<%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id]})%> +
    <% end %>

    <% if @project && @project.descendants.active.any? %> - <%= hidden_field_tag 'with_subprojects', 0 %> + <%= hidden_field_tag 'with_subprojects', 0 %>

    <% end %> <%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/_menu.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/admin/_menu.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +
    +
      + <%= render_menu :admin_menu %> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/_menu.rhtml --- a/app/views/admin/_menu.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -
    -
      - <%= render_menu :admin_menu %> -
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/_no_data.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/admin/_no_data.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +
    +<% form_tag({:action => 'default_configuration'}) do %> + <%= simple_format(l(:text_no_configuration_data)) %> +

    <%= l(:field_language) %>: + <%= select_tag 'lang', options_for_select(lang_options_for_select(false), current_language.to_s) %> + <%= submit_tag l(:text_load_default_configuration) %>

    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/_no_data.rhtml --- a/app/views/admin/_no_data.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -
    -<% form_tag({:action => 'default_configuration'}) do %> - <%= simple_format(l(:text_no_configuration_data)) %> -

    <%= l(:field_language) %>: - <%= select_tag 'lang', options_for_select(lang_options_for_select(false), current_language.to_s) %> - <%= submit_tag l(:text_load_default_configuration) %>

    -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/admin/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%=l(:label_administration)%>

    + +
    + <%= render :partial => 'no_data' if @no_configuration_data %> + <%= render :partial => 'menu' %> +
    + +<% html_title(l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/index.rhtml --- a/app/views/admin/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -

    <%=l(:label_administration)%>

    - -
    - <%= render :partial => 'no_data' if @no_configuration_data %> - <%= render :partial => 'menu' %> -
    - -<% html_title(l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/info.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/admin/info.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%=l(:label_information_plural)%>

    + +

    <%= Redmine::Info.versioned_name %> (<%= @db_adapter_name %>)

    + + +<% @checklist.each do |label, result| %> + + + + +<% end %> +
    <%= l(label) %><%= image_tag((result ? 'true.png' : 'exclamation.png'), + :style => "vertical-align:bottom;") %>
    + +<% html_title(l(:label_information_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/info.rhtml --- a/app/views/admin/info.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -

    <%=l(:label_information_plural)%>

    - -

    <%= Redmine::Info.versioned_name %> (<%= @db_adapter_name %>)

    - - -<% @checklist.each do |label, result| %> - - - - -<% end %> -
    <%= l(label) %><%= image_tag((result ? 'true.png' : 'exclamation.png'), - :style => "vertical-align:bottom;") %>
    - -<% html_title(l(:label_information_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/plugins.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/admin/plugins.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +

    <%= l(:label_plugins) %>

    + +<% if @plugins.any? %> + + <% @plugins.each do |plugin| %> + + + + + + + <% end %> +
    <%=h plugin.name %> + <%= content_tag('span', h(plugin.description), :class => 'description') unless plugin.description.blank? %> + <%= content_tag('span', link_to(h(plugin.url), plugin.url), :class => 'url') unless plugin.url.blank? %> + <%= plugin.author_url.blank? ? h(plugin.author) : link_to(h(plugin.author), plugin.author_url) %><%=h plugin.version %><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.id) if plugin.configurable? %>
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/plugins.rhtml --- a/app/views/admin/plugins.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -

    <%= l(:label_plugins) %>

    - -<% if @plugins.any? %> - - <% @plugins.each do |plugin| %> - - - - - - - <% end %> -
    <%=h plugin.name %> - <%= content_tag('span', h(plugin.description), :class => 'description') unless plugin.description.blank? %> - <%= content_tag('span', link_to(h(plugin.url), plugin.url), :class => 'url') unless plugin.url.blank? %> - <%= plugin.author_url.blank? ? h(plugin.author) : link_to(h(plugin.author), plugin.author_url) %><%=h plugin.version %><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.id) if plugin.configurable? %>
    -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/projects.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/admin/projects.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +
    +<%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_project_plural)%>

    + +<% form_tag({}, :method => :get) do %> +
    <%= l(:label_filter_plural) %> + +<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %> +<%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %> +
    +<% end %> +  + +
    + + + + + + + + +<% project_tree(@projects) do |project, level| %> + <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> + + + + + +<% end %> + +
    <%=l(:label_project)%><%=l(:field_is_public)%><%=l(:field_created_on)%>
    <%= link_to_project(project, {:action => 'settings'}, :title => project.short_description) %><%= checked_image project.is_public? %><%= format_date(project.created_on) %> + <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %> + <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %> + <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %> + <%= link_to(l(:button_delete), project_destroy_confirm_path(project), :class => 'icon icon-del') %> +
    +
    + +<% html_title(l(:label_project_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/admin/projects.rhtml --- a/app/views/admin/projects.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -
    -<%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %> -
    - -

    <%=l(:label_project_plural)%>

    - -<% form_tag({}, :method => :get) do %> -
    <%= l(:label_filter_plural) %> - -<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> - -<%= text_field_tag 'name', params[:name], :size => 30 %> -<%= submit_tag l(:button_apply), :class => "small", :name => nil %> -<%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %> -
    -<% end %> -  - -
    - - - - - - - - -<% project_tree(@projects) do |project, level| %> - <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> - - - - - -<% end %> - -
    <%=l(:label_project)%><%=l(:field_is_public)%><%=l(:field_created_on)%>
    <%= link_to_project(project, {:action => 'settings'}, :title => project.short_description) %><%= checked_image project.is_public? %><%= format_date(project.created_on) %> - <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %> - <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %> - <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %> - <%= link_to(l(:button_delete), project_destroy_confirm_path(project), :class => 'icon icon-del') %> -
    -
    - -<% html_title(l(:label_project_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/attachments/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ + + + <%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil, :class => 'file', + :onchange => "checkFileSize(this, #{Setting.attachment_max_size.to_i.kilobytes}, '#{escape_javascript(l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)))}');" -%> + + <%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %> + + +<%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %> +(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) + diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/_form.rhtml --- a/app/views/attachments/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ - -<%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil -%> - -
    -<%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %> -(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) - diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/_links.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/attachments/_links.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +
    +<% for attachment in attachments %> +

    <%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> +<%= h(" - #{attachment.description}") unless attachment.description.blank? %> + (<%= number_to_human_size attachment.filesize %>) + <% if options[:deletable] %> + <%= link_to image_tag('delete.png'), attachment_path(attachment), + :confirm => l(:text_are_you_sure), + :method => :delete, + :class => 'delete', + :title => l(:button_delete) %> + <% end %> + <% if options[:author] %> + <%= h(attachment.author) %>, <%= format_time(attachment.created_on) %> + <% end %> +

    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/_links.rhtml --- a/app/views/attachments/_links.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -
    -<% for attachment in attachments %> -

    <%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> -<%= h(" - #{attachment.description}") unless attachment.description.blank? %> - (<%= number_to_human_size attachment.filesize %>) - <% if options[:deletable] %> - <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment}, - :confirm => l(:text_are_you_sure), - :method => :post, - :class => 'delete', - :title => l(:button_delete) %> - <% end %> - <% if options[:author] %> - <%= attachment.author %>, <%= format_time(attachment.created_on) %> - <% end %> -

    -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/diff.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/attachments/diff.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +

    <%=h @attachment.filename %>

    + +
    +

    <%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> + <%= link_to_user(@attachment.author) %>, <%= format_time(@attachment.created_on) %>

    +

    <%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> + (<%= number_to_human_size @attachment.filesize %>)

    +
    +

    +<% form_tag({}, :method => 'get') do %> + + <%= select_tag 'type', + options_for_select( + [[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), + :onchange => "if (this.value != '') {this.form.submit()}" %> +<% end %> +

    +<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %> + +<% html_title @attachment.filename %> + +<% content_for :header_tags do -%> + <%= stylesheet_link_tag "scm" -%> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/diff.rhtml --- a/app/views/attachments/diff.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -

    <%=h @attachment.filename %>

    - -
    -

    <%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> - <%= @attachment.author %>, <%= format_time(@attachment.created_on) %>

    -

    <%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> - (<%= number_to_human_size @attachment.filesize %>)

    - -
    -  -<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %> - -<% html_title @attachment.filename %> - -<% content_for :header_tags do -%> - <%= stylesheet_link_tag "scm" -%> -<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/file.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/attachments/file.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +

    <%=h @attachment.filename %>

    + +
    +

    <%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> + <%= link_to_user(@attachment.author) %>, <%= format_time(@attachment.created_on) %>

    +

    <%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> + (<%= number_to_human_size @attachment.filesize %>)

    + +
    +  +<%= render :partial => 'common/file', :locals => {:content => @content, :filename => @attachment.filename} %> + +<% html_title @attachment.filename %> + +<% content_for :header_tags do -%> + <%= stylesheet_link_tag "scm" -%> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/file.rhtml --- a/app/views/attachments/file.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -

    <%=h @attachment.filename %>

    - -
    -

    <%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> - <%= @attachment.author %>, <%= format_time(@attachment.created_on) %>

    -

    <%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> - (<%= number_to_human_size @attachment.filesize %>)

    - -
    -  -<%= render :partial => 'common/file', :locals => {:content => @content, :filename => @attachment.filename} %> - -<% html_title @attachment.filename %> - -<% content_for :header_tags do -%> - <%= stylesheet_link_tag "scm" -%> -<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/attachments/show.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/attachments/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +render_api_attachment(@attachment, api) diff -r 487d96eac004 -r 5e80956cc792 app/views/auth_sources/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/auth_sources/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +

    <%=l(:label_auth_source)%> (<%= h(@auth_source.auth_method_name) %>)

    + +<% form_tag({:action => 'update', :id => @auth_source}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<% end %> + diff -r 487d96eac004 -r 5e80956cc792 app/views/auth_sources/edit.rhtml --- a/app/views/auth_sources/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -

    <%=l(:label_auth_source)%> (<%= @auth_source.auth_method_name %>)

    - -<% form_tag({:action => 'update', :id => @auth_source}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<% end %> - diff -r 487d96eac004 -r 5e80956cc792 app/views/auth_sources/index.html.erb --- a/app/views/auth_sources/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/auth_sources/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -6,23 +6,23 @@ - - - - - + + + + + <% for source in @auth_sources %> - "> + "> <% have_file = false %> -<% @containers.each do |container| %> +<% @containers.each do |container| %> <% next if container.attachments.empty? -%> - <% if container.is_a?(Version) -%> + <% if container.is_a?(Version) -%> - - <% end -%> - <% container.attachments.each do |file| %> + <%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %> + + + <% end -%> + <% container.attachments.each do |file| %> <%= "active" if file.active? %>"> - + <% end reset_cycle %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/files/new.html.erb --- a/app/views/files/new.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/files/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -7,10 +7,10 @@ <% if @versions.any? %>

    <%= select_tag "version_id", content_tag('option', '') + - options_from_collection_for_select(@versions, "id", "name") %>

    + options_from_collection_for_select(@versions, "id", "name") %>

    <% end %>

    <%= render :partial => 'attachments/form' %>

    <%= submit_tag l(:button_add) %> -<% end %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/gantts/show.html.erb --- a/app/views/gantts/show.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/gantts/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -5,7 +5,7 @@ <%= hidden_field_tag 'set_filter', '1' %>
    "> <%= l(:label_filter_plural) %> -
    "> +
    "> <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
    @@ -48,7 +48,7 @@ end end -# Width of the entire chart +# Width of the entire chart g_width = (@gantt.date_to - @gantt.date_from + 1)*zoom @gantt.render(:top => headers_height + 8, :zoom => zoom, :g_width => g_width, :subject_width => subject_width) @@ -60,7 +60,7 @@ %> <% if @gantt.truncated %> -

    <%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %>

    +

    <%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %>

    <% end %>
    <%=l(:field_name)%><%=l(:field_type)%><%=l(:field_host)%><%=l(:label_user_plural)%><%=l(:field_name)%><%=l(:field_type)%><%=l(:field_host)%><%=l(:label_user_plural)%>
    <%= link_to(h(source.name), :action => 'edit', :id => source)%> <%= h source.auth_method_name %> <%= h source.host %> <%= h source.users.count %> - <%= link_to l(:button_test), :action => 'test_connection', :id => source %> - <%= link_to l(:button_delete), { :action => 'destroy', :id => source }, - :method => :post, + <%= link_to l(:button_test), :action => 'test_connection', :id => source %> + <%= link_to l(:button_delete), { :action => 'destroy', :id => source }, + :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del', :disabled => source.users.any? %> diff -r 487d96eac004 -r 5e80956cc792 app/views/auth_sources/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/auth_sources/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%=l(:label_auth_source_new)%> (<%= h(@auth_source.auth_method_name) %>)

    + +<% form_tag({:action => 'create'}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/auth_sources/new.rhtml --- a/app/views/auth_sources/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)

    - -<% form_tag({:action => 'create'}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/boards/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<%= error_messages_for 'board' %> + + +
    +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.text_field :description, :required => true, :size => 80 %>

    +
    + diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/_form.rhtml --- a/app/views/boards/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -<%= error_messages_for 'board' %> - - -
    -

    <%= f.text_field :name, :required => true %>

    -

    <%= f.text_field :description, :required => true, :size => 80 %>

    -
    - diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/boards/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_board) %>

    + +<% labelled_tabular_form_for :board, @board, :url => {:action => 'edit', :id => @board} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/edit.rhtml --- a/app/views/boards/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= l(:label_board) %>

    - -<% labelled_tabular_form_for :board, @board, :url => {:action => 'edit', :id => @board} do |f| %> - <%= render :partial => 'form', :locals => {:f => f} %> - <%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/boards/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +

    <%= l(:label_board_plural) %>

    + + + + + + + + + +<% for board in @boards %> + + + + + + +<% end %> + +
    <%= l(:label_board) %><%= l(:label_topic_plural) %><%= l(:label_message_plural) %><%= l(:label_message_last) %>
    + <%= link_to h(board.name), {:action => 'show', :id => board}, :class => "board" %>
    + <%=h board.description %> +
    <%= board.topics_count %><%= board.messages_count %> + + <% if board.last_message %> + <%= authoring board.last_message.created_on, board.last_message.author %>
    + <%= link_to_message board.last_message %> + <% end %> +
    +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_messages => 1, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %> +<% end %> + +<% html_title l(:label_board_plural) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/index.rhtml --- a/app/views/boards/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -

    <%= l(:label_board_plural) %>

    - - - - - - - - - -<% for board in @boards %> - - - - - - -<% end %> - -
    <%= l(:label_board) %><%= l(:label_topic_plural) %><%= l(:label_message_plural) %><%= l(:label_message_last) %>
    - <%= link_to h(board.name), {:action => 'show', :id => board}, :class => "board" %>
    - <%=h board.description %> -
    <%= board.topics_count %><%= board.messages_count %> - - <% if board.last_message %> - <%= authoring board.last_message.created_on, board.last_message.author %>
    - <%= link_to_message board.last_message %> - <% end %> -
    -
    - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_messages => 1, :key => User.current.rss_key} %> -<% end %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %> -<% end %> - -<% html_title l(:label_board_plural) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/boards/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_board_new) %>

    + +<% labelled_tabular_form_for :board, @board, :url => {:action => 'new'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/new.rhtml --- a/app/views/boards/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= l(:label_board_new) %>

    - -<% labelled_tabular_form_for :board, @board, :url => {:action => 'new'} do |f| %> - <%= render :partial => 'form', :locals => {:f => f} %> - <%= submit_tag l(:button_create) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/boards/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,73 @@ +<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}) %> + +
    +<%= link_to_if_authorized l(:label_message_new), + {:controller => 'messages', :action => 'new', :board_id => @board}, + :class => 'icon icon-add', + :onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %> +<%= watcher_tag(@board, User.current) %> +
    + + + +

    <%=h @board.name %>

    +

    <%=h @board.description %>

    + +<% if @topics.any? %> + + + + + <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> + <%= sort_header_tag('replies', :caption => l(:label_reply_plural)) %> + <%= sort_header_tag('updated_on', :caption => l(:label_message_last)) %> + + + <% @topics.each do |topic| %> + + + + + + + + <% end %> + +
    <%= l(:field_subject) %><%= l(:field_author) %>
    <%= link_to h(topic.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => topic } %><%= link_to_user(topic.author) %><%= format_time(topic.created_on) %><%= topic.replies_count %> + <% if topic.last_reply %> + <%= authoring topic.last_reply.created_on, topic.last_reply.author %>
    + <%= link_to_message topic.last_reply %> + <% end %> +
    +

    <%= pagination_links_full @topic_pages, @topic_count %>

    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title @board.name %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@project}: #{@board}") %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/boards/show.rhtml --- a/app/views/boards/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}) %> - -
    -<%= link_to_if_authorized l(:label_message_new), - {:controller => 'messages', :action => 'new', :board_id => @board}, - :class => 'icon icon-add', - :onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %> -<%= watcher_tag(@board, User.current) %> -
    - - - -

    <%=h @board.name %>

    -

    <%=h @board.description %>

    - -<% if @topics.any? %> - - - - - <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> - <%= sort_header_tag('replies', :caption => l(:label_reply_plural)) %> - <%= sort_header_tag('updated_on', :caption => l(:label_message_last)) %> - - - <% @topics.each do |topic| %> - - - - - - - - <% end %> - -
    <%= l(:field_subject) %><%= l(:field_author) %>
    <%= link_to h(topic.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => topic } %><%= topic.author %><%= format_time(topic.created_on) %><%= topic.replies_count %> - <% if topic.last_reply %> - <%= authoring topic.last_reply.created_on, topic.last_reply.author %>
    - <%= link_to_message topic.last_reply %> - <% end %> -
    -

    <%= pagination_links_full @topic_pages, @topic_count %>

    -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> -<% end %> - -<% html_title h(@board.name) %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@project}: #{@board}") %> - <%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/calendars/show.html.erb --- a/app/views/calendars/show.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/calendars/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -29,9 +29,9 @@ <%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %>

    - <%= l(:text_tip_issue_begin_day) %> - <%= l(:text_tip_issue_end_day) %> - <%= l(:text_tip_issue_begin_end_day) %> + <%= l(:text_tip_issue_begin_day) %> + <%= l(:text_tip_issue_end_day) %> + <%= l(:text_tip_issue_begin_end_day) %>

    <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_calendar.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/common/_calendar.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ + + +<% 7.times do |i| %><% end %> + + + +<% day = calendar.startdt +while day <= calendar.enddt %> +<%= "" if day.cwday == calendar.first_wday %> + +<%= '' if day.cwday==calendar.last_wday and day!=calendar.enddt %> +<% day = day + 1 +end %> + + +
    <%= day_name( (calendar.first_wday+i)%7 ) %>
    #{(day+(11-day.cwday)%7).cweek} +

    <%= day.day %>

    +<% calendar.events_on(day).each do |i| %> + <% if i.is_a? Issue %> +
    + <%= h("#{i.project} -") unless @project && @project == i.project %> + <%= link_to_issue i, :truncate => 30 %> + <%= render_issue_tooltip i %> +
    + <% else %> + + <%= h("#{i.project} -") unless @project && @project == i.project %> + <%= link_to_version i%> + + <% end %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_calendar.rhtml --- a/app/views/common/_calendar.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ - - -<% 7.times do |i| %><% end %> - - - -<% day = calendar.startdt -while day <= calendar.enddt %> -<%= "" if day.cwday == calendar.first_wday %> - -<%= '' if day.cwday==calendar.last_wday and day!=calendar.enddt %> -<% day = day + 1 -end %> - - -
    <%= day_name( (calendar.first_wday+i)%7 ) %>
    #{(day+(11-day.cwday)%7).cweek} -

    <%= day.day %>

    -<% calendar.events_on(day).each do |i| %> - <% if i.is_a? Issue %> -
    - <%= h("#{i.project} -") unless @project && @project == i.project %> - <%= link_to_issue i, :truncate => 30 %> - <%= render_issue_tooltip i %> -
    - <% else %> - - <%= h("#{i.project} -") unless @project && @project == i.project %> - <%= link_to_version i%> - - <% end %> -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_diff.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/common/_diff.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,67 @@ +<% diff = Redmine::UnifiedDiff.new( + diff, :type => diff_type, + :max_lines => Setting.diff_max_lines_displayed.to_i) -%> + +<% diff.each do |table_file| -%> +
    +<% if diff.diff_type == 'sbs' -%> + + + + + + + +<% table_file.each_line do |spacing, line| -%> +<% if spacing -%> + + + +<% end -%> + + + + + + +<% end -%> + +
    + <%= h(Redmine::CodesetUtil.to_utf8_by_setting(table_file.file_name)) %> +
    ......
    <%= line.nb_line_left %> +
    <%= Redmine::CodesetUtil.to_utf8_by_setting(line.html_line_left) %>
    +
    <%= line.nb_line_right %> +
    <%= Redmine::CodesetUtil.to_utf8_by_setting(line.html_line_right) %>
    +
    + +<% else -%> + + + + + + + +<% table_file.each_line do |spacing, line| %> +<% if spacing -%> + + + +<% end -%> + + + + + +<% end -%> + +
    + <%= h(Redmine::CodesetUtil.to_utf8_by_setting(table_file.file_name)) %> +
    ......
    <%= line.nb_line_left %><%= line.nb_line_right %> +
    <%= Redmine::CodesetUtil.to_utf8_by_setting(line.html_line) %>
    +
    +<% end -%> +
    +<% end -%> + +<%= l(:text_diff_truncated) if diff.truncated? %> diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_diff.rhtml --- a/app/views/common/_diff.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -<% diff = Redmine::UnifiedDiff.new(diff, :type => diff_type, :max_lines => Setting.diff_max_lines_displayed.to_i) -%> - -<% diff.each do |table_file| -%> -
    -<% if diff.diff_type == 'sbs' -%> - - - - - -<% table_file.each_line do |spacing, line| -%> -<% if spacing -%> - - - -<% end -%> - - - - - - -<% end -%> - -
    <%=to_utf8 table_file.file_name %>
    ......
    <%= line.nb_line_left %> -
    <%=to_utf8 line.html_line_left %>
    -
    <%= line.nb_line_right %> -
    <%=to_utf8 line.html_line_right %>
    -
    - -<% else -%> - - - - - -<% table_file.each_line do |spacing, line| %> -<% if spacing -%> - - - -<% end -%> - - - - - -<% end -%> - -
    <%=to_utf8 table_file.file_name %>
    ......
    <%= line.nb_line_left %><%= line.nb_line_right %> -
    <%=to_utf8 line.html_line %>
    -
    -<% end -%> -
    -<% end -%> - -<%= l(:text_diff_truncated) if diff.truncated? %> diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_file.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/common/_file.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +
    + + +<% line_num = 1 %> +<% syntax_highlight(filename, Redmine::CodesetUtil.to_utf8_by_setting(content)).each_line do |line| %> + + + + + <% line_num += 1 %> +<% end %> + +
    + <%= line_num %> + +
    <%= line %>
    +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_file.rhtml --- a/app/views/common/_file.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -
    - - -<% line_num = 1 %> -<% syntax_highlight(filename, to_utf8(content)).each_line do |line| %> - -<% line_num += 1 %> -<% end %> - -
    <%= line_num %>
    <%= line %>
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_preview.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/common/_preview.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +
    <%= l(:label_preview) %> +<%= textilizable @text, :attachments => @attachements, :object => @previewed %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_preview.rhtml --- a/app/views/common/_preview.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -
    <%= l(:label_preview) %> -<%= textilizable @text, :attachments => @attachements, :object => @previewed %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_tabs.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/common/_tabs.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %> + +
    +
      + <% tabs.each do |tab| -%> +
    • <%= link_to l(tab[:label]), { :tab => tab[:name] }, + :id => "tab-#{tab[:name]}", + :class => (tab[:name] != selected_tab ? nil : 'selected'), + :onclick => "showTab('#{tab[:name]}'); this.blur(); return false;" %>
    • + <% end -%> +
    + +
    + + + +<% tabs.each do |tab| -%> + <%= content_tag('div', render(:partial => tab[:partial], :locals => {:tab => tab} ), + :id => "tab-content-#{tab[:name]}", + :style => (tab[:name] != selected_tab ? 'display:none' : nil), + :class => 'tab-content') %> +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/common/_tabs.rhtml --- a/app/views/common/_tabs.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %> - -
    -
      - <% tabs.each do |tab| -%> -
    • <%= link_to l(tab[:label]), { :tab => tab[:name] }, - :id => "tab-#{tab[:name]}", - :class => (tab[:name] != selected_tab ? nil : 'selected'), - :onclick => "showTab('#{tab[:name]}'); this.blur(); return false;" %>
    • - <% end -%> -
    - -
    - - - -<% tabs.each do |tab| -%> - <%= content_tag('div', render(:partial => tab[:partial], :locals => {:tab => tab} ), - :id => "tab-content-#{tab[:name]}", - :style => (tab[:name] != selected_tab ? 'display:none' : nil), - :class => 'tab-content') %> -<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/common/error.html.erb --- a/app/views/common/error.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/common/error.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,8 @@

    <%=h @status %>

    -

    <%=h @message %>

    +<% if @message.present? %> +

    <%=h @message %>

    +<% end %>

    Back

    <% html_title @status %> diff -r 487d96eac004 -r 5e80956cc792 app/views/common/feed.atom.builder --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/common/feed.atom.builder Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,31 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do + xml.title truncate_single_line(@title, :length => 100) + xml.link "rel" => "self", "href" => url_for(params.merge(:only_path => false)) + xml.link "rel" => "alternate", "href" => url_for(params.merge(:only_path => false, :format => nil, :key => nil)) + xml.id url_for(:controller => 'welcome', :only_path => false) + xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema) + xml.author { xml.name "#{Setting.app_title}" } + xml.generator(:uri => Redmine::Info.url) { xml.text! Redmine::Info.app_name; } + @items.each do |item| + xml.entry do + url = url_for(item.event_url(:only_path => false)) + if @project + xml.title truncate_single_line(item.event_title, :length => 100) + else + xml.title truncate_single_line("#{item.project} - #{item.event_title}", :length => 100) + end + xml.link "rel" => "alternate", "href" => url + xml.id url + xml.updated item.event_datetime.xmlschema + author = item.event_author if item.respond_to?(:event_author) + xml.author do + xml.name(author) + xml.email(author.mail) if author.is_a?(User) && !author.mail.blank? && !author.pref.hide_mail + end if author + xml.content "type" => "html" do + xml.text! textilizable(item, :event_description, :only_path => false) + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/common/feed.atom.rxml --- a/app/views/common/feed.atom.rxml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -xml.instruct! -xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do - xml.title truncate_single_line(@title, :length => 100) - xml.link "rel" => "self", "href" => url_for(params.merge(:only_path => false)) - xml.link "rel" => "alternate", "href" => url_for(params.merge(:only_path => false, :format => nil, :key => nil)) - xml.id url_for(:controller => 'welcome', :only_path => false) - xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema) - xml.author { xml.name "#{Setting.app_title}" } - xml.generator(:uri => Redmine::Info.url) { xml.text! Redmine::Info.app_name; } - @items.each do |item| - xml.entry do - url = url_for(item.event_url(:only_path => false)) - if @project - xml.title truncate_single_line(item.event_title, :length => 100) - else - xml.title truncate_single_line("#{item.project} - #{item.event_title}", :length => 100) - end - xml.link "rel" => "alternate", "href" => url - xml.id url - xml.updated item.event_datetime.xmlschema - author = item.event_author if item.respond_to?(:event_author) - xml.author do - xml.name(author) - xml.email(author.mail) if author.is_a?(User) && !author.mail.blank? && !author.pref.hide_mail - end if author - xml.content "type" => "html" do - xml.text! textilizable(item, :event_description, :only_path => false) - end - end - end -end diff -r 487d96eac004 -r 5e80956cc792 app/views/context_menus/issues.html.erb --- a/app/views/context_menus/issues.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/context_menus/issues.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -2,118 +2,118 @@ <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %> <% if !@issue.nil? -%> -
  • <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, - :class => 'icon-edit', :disabled => !@can[:edit] %>
  • +
  • <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
  • <% else %> -
  • <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)}, - :class => 'icon-edit', :disabled => !@can[:edit] %>
  • +
  • <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
  • <% end %> <% if @allowed_statuses.present? %> -
  • - <%= l(:field_status) %> -
      - <% @statuses.each do |s| -%> -
    • <%= context_menu_link s.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post, - :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %>
    • - <% end -%> -
    -
  • +
  • + <%= l(:field_status) %> +
      + <% @statuses.each do |s| -%> +
    • <%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post, + :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %>
    • + <% end -%> +
    +
  • <% end %> - <% unless @trackers.nil? %> -
  • - <%= l(:field_tracker) %> -
      - <% @trackers.each do |t| -%> -
    • <%= context_menu_link t.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post, - :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %>
    • - <% end -%> -
    -
  • - <% end %> + <% unless @trackers.nil? %> +
  • + <%= l(:field_tracker) %> +
      + <% @trackers.each do |t| -%> +
    • <%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post, + :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %>
    • + <% end -%> +
    +
  • + <% end %> -
  • - <%= l(:field_priority) %> -
      - <% @priorities.each do |p| -%> -
    • <%= context_menu_link p.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post, - :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
    • - <% end -%> -
    -
  • +
  • + <%= l(:field_priority) %> +
      + <% @priorities.each do |p| -%> +
    • <%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post, + :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
    • + <% end -%> +
    +
  • <% #TODO: allow editing versions when multiple projects %> - <% unless @project.nil? || @project.shared_versions.open.empty? -%> -
  • - <%= l(:field_fixed_version) %> -
      - <% @project.shared_versions.open.sort.each do |v| -%> -
    • <%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post, - :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %>
    • - <% end -%> -
    • <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post, - :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %>
    • -
    -
  • - <% end %> - <% if @assignables.present? -%> -
  • - <%= l(:field_assigned_to) %> -
      - <% @assignables.each do |u| -%> -
    • <%= context_menu_link u.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post, - :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %>
    • - <% end -%> -
    • <%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post, - :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %>
    • -
    -
  • - <% end %> - <% unless @project.nil? || @project.issue_categories.empty? -%> -
  • - <%= l(:field_category) %> -
      - <% @project.issue_categories.each do |u| -%> -
    • <%= context_menu_link u.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post, - :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %>
    • - <% end -%> -
    • <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post, - :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %>
    • -
    -
  • - <% end -%> + <% unless @project.nil? || @project.shared_versions.open.empty? -%> +
  • + <%= l(:field_fixed_version) %> +
      + <% @project.shared_versions.open.sort.each do |v| -%> +
    • <%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post, + :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %>
    • +
    +
  • + <% end %> + <% if @assignables.present? -%> +
  • + <%= l(:field_assigned_to) %> +
      + <% @assignables.each do |u| -%> +
    • <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post, + :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %>
    • +
    +
  • + <% end %> + <% unless @project.nil? || @project.issue_categories.empty? -%> +
  • + <%= l(:field_category) %> +
      + <% @project.issue_categories.each do |u| -%> +
    • <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post, + :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %>
    • +
    +
  • + <% end -%> <% if Issue.use_field_for_done_ratio? %> -
  • - <%= l(:field_done_ratio) %> -
      - <% (0..10).map{|x|x*10}.each do |p| -%> -
    • <%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post, - :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
    • - <% end -%> -
    -
  • +
  • + <%= l(:field_done_ratio) %> +
      + <% (0..10).map{|x|x*10}.each do |p| -%> +
    • <%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post, + :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
    • + <% end -%> +
    +
  • <% end %> <% if !@issue.nil? %> - <% if @can[:log_time] -%> -
  • <%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, - :class => 'icon-time-add' %>
  • - <% end %> - <% if User.current.logged? %> -
  • <%= watcher_link(@issue, User.current) %>
  • - <% end %> + <% if @can[:log_time] -%> +
  • <%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, + :class => 'icon-time-add' %>
  • + <% end %> + <% if User.current.logged? %> +
  • <%= watcher_link(@issue, User.current) %>
  • + <% end %> <% end %> <% if @issue.present? %>
  • <%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, - :class => 'icon-duplicate', :disabled => !@can[:copy] %>
  • + :class => 'icon-duplicate', :disabled => !@can[:copy] %> <% end %>
  • <%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}), - :class => 'icon-copy', :disabled => !@can[:move] %>
  • + :class => 'icon-copy', :disabled => !@can[:move] %>
  • <%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)), - :class => 'icon-move', :disabled => !@can[:move] %>
  • + :class => 'icon-move', :disabled => !@can[:move] %>
  • <%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id), :back_url => @back}, :method => :post, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %>
  • diff -r 487d96eac004 -r 5e80956cc792 app/views/context_menus/time_entries.html.erb --- a/app/views/context_menus/time_entries.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/context_menus/time_entries.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -9,24 +9,24 @@ <%= call_hook(:view_time_entries_context_menu_start, {:time_entries => @time_entries, :can => @can, :back => @back }) %> - <% if @activities.present? -%> -
  • - <%= l(:field_activity) %> -
      - <% @activities.each do |u| -%> -
    • <%= context_menu_link u.name, {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post, - :selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:update] %>
    • - <% end -%> -
    • <%= context_menu_link l(:label_nobody), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post, - :selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:update] %>
    • -
    -
  • - <% end %> + <% if @activities.present? -%> +
  • + <%= l(:field_activity) %> +
      + <% @activities.each do |u| -%> +
    • <%= context_menu_link h(u.name), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post, + :selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:edit] %>
    • + <% end -%> +
    • <%= context_menu_link l(:label_none), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:edit] %>
    • +
    +
  • + <% end %> <%= call_hook(:view_time_entries_context_menu_end, {:time_entries => @time_entries, :can => @can, :back => @back }) %>
  • - <%= context_menu_link l(:button_delete), + <%= context_menu_link l(:button_delete), {:controller => 'timelog', :action => 'destroy', :ids => @time_entries.collect(&:id), :back_url => @back}, :method => :delete, :confirm => l(:text_time_entries_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %>
  • diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/custom_fields/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,120 @@ +<%= error_messages_for 'custom_field' %> + + + +
    +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :onchange => "toggle_custom_field_format();", + :disabled => !@custom_field.new_record? %>

    +

    + <%= f.text_field :min_length, :size => 5, :no_label => true %> - + <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

    +

    <%= f.text_field :regexp, :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    +

    + <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %> +
    <%= l(:text_custom_field_possible_values_info) %> +

    +

    <%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>

    +<%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %> +
    + +
    +<% case @custom_field.class.name +when "IssueCustomField" %> + +
    <%=l(:label_tracker_plural)%> + <% for tracker in @trackers %> + <%= check_box_tag "custom_field[tracker_ids][]", + tracker.id, + (@custom_field.trackers.include? tracker), + :id => "custom_field_tracker_ids_#{tracker.id}" %> + + <% end %> + <%= hidden_field_tag "custom_field[tracker_ids][]", '' %> +
    +   +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :is_for_all %>

    +

    <%= f.check_box :is_filter %>

    +

    <%= f.check_box :searchable %>

    + +<% when "UserCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :visible %>

    +

    <%= f.check_box :editable %>

    + +<% when "ProjectCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :visible %>

    +

    <%= f.check_box :searchable %>

    + +<% when "TimeEntryCustomField" %> +

    <%= f.check_box :is_required %>

    + +<% else %> +

    <%= f.check_box :is_required %>

    + +<% end %> +<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %> +
    +<%= javascript_tag "toggle_custom_field_format();" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/_form.rhtml --- a/app/views/custom_fields/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -<%= error_messages_for 'custom_field' %> - - - -
    -

    <%= f.text_field :name, :required => true %>

    -

    <%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :onchange => "toggle_custom_field_format();", - :disabled => !@custom_field.new_record? %>

    -

    - <%= f.text_field :min_length, :size => 5, :no_label => true %> - - <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

    -

    <%= f.text_field :regexp, :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    -

    - <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %> -
    <%= l(:text_custom_field_possible_values_info) %> -

    -

    <%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>

    -<%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %> -
    - -
    -<% case @custom_field.class.name -when "IssueCustomField" %> - -
    <%=l(:label_tracker_plural)%> - <% for tracker in @trackers %> - <%= check_box_tag "custom_field[tracker_ids][]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %> - <% end %> - <%= hidden_field_tag "custom_field[tracker_ids][]", '' %> -
    -   -

    <%= f.check_box :is_required %>

    -

    <%= f.check_box :is_for_all %>

    -

    <%= f.check_box :is_filter %>

    -

    <%= f.check_box :searchable %>

    - -<% when "UserCustomField" %> -

    <%= f.check_box :is_required %>

    -

    <%= f.check_box :visible %>

    -

    <%= f.check_box :editable %>

    - -<% when "ProjectCustomField" %> -

    <%= f.check_box :is_required %>

    -

    <%= f.check_box :visible %>

    -

    <%= f.check_box :searchable %>

    - -<% when "TimeEntryCustomField" %> -

    <%= f.check_box :is_required %>

    - -<% else %> -

    <%= f.check_box :is_required %>

    - -<% end %> -<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %> -
    -<%= javascript_tag "toggle_custom_field_format();" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/_index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/custom_fields/_index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ + + + + + + <% if tab[:name] == 'IssueCustomField' %> + + + <% end %> + + + + + <% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%> + "> + + + + <% if tab[:name] == 'IssueCustomField' %> + + + <% end %> + + + + <% end; reset_cycle %> + +
    <%=l(:field_name)%><%=l(:field_field_format)%><%=l(:field_is_required)%><%=l(:field_is_for_all)%><%=l(:label_used_by)%><%=l(:button_sort)%>
    <%= link_to h(custom_field.name), :action => 'edit', :id => custom_field %><%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %><%= checked_image custom_field.is_required? %><%= checked_image custom_field.is_for_all? %><%= l(:label_x_projects, :count => custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %><%= reorder_links('custom_field', {:action => 'edit', :id => custom_field}) %> + <%= link_to(l(:button_delete), { :action => 'destroy', :id => custom_field }, + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + +

    <%= link_to l(:label_custom_field_new), {:action => 'new', :type => tab[:name]}, :class => 'icon icon-add' %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/_index.rhtml --- a/app/views/custom_fields/_index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ - - - - - - <% if tab[:name] == 'IssueCustomField' %> - - - <% end %> - - - - - <% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%> - "> - - - - <% if tab[:name] == 'IssueCustomField' %> - - - <% end %> - - - - <% end; reset_cycle %> - -
    <%=l(:field_name)%><%=l(:field_field_format)%><%=l(:field_is_required)%><%=l(:field_is_for_all)%><%=l(:label_used_by)%><%=l(:button_sort)%>
    <%= link_to custom_field.name, :action => 'edit', :id => custom_field %><%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %><%= checked_image custom_field.is_required? %><%= checked_image custom_field.is_for_all? %><%= l(:label_x_projects, :count => custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %><%= reorder_links('custom_field', {:action => 'edit', :id => custom_field}) %> - <%= link_to(l(:button_delete), { :action => 'destroy', :id => custom_field }, - :method => :post, - :confirm => l(:text_are_you_sure), - :class => 'icon icon-del') %> -
    - -

    <%= link_to l(:label_custom_field_new), {:action => 'new', :type => tab[:name]}, :class => 'icon icon-add' %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/custom_fields/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> + » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %> + » <%=h @custom_field.name %>

    + +<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "edit", :id => @custom_field } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/edit.rhtml --- a/app/views/custom_fields/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> - » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.type %> - » <%=h @custom_field.name %>

    - -<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "edit", :id => @custom_field } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/custom_fields/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%=l(:label_custom_field_plural)%>

    + +<%= render_tabs custom_fields_tabs %> + +<% html_title(l(:label_custom_field_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/index.rhtml --- a/app/views/custom_fields/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -

    <%=l(:label_custom_field_plural)%>

    - -<%= render_tabs custom_fields_tabs %> - -<% html_title(l(:label_custom_field_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/custom_fields/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> + » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %> + » <%= l(:label_custom_field_new) %>

    + +<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "new" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= hidden_field_tag 'type', @custom_field.type %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/custom_fields/new.rhtml --- a/app/views/custom_fields/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> - » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.type %> - » <%= l(:label_custom_field_new) %>

    - -<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "new" } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= hidden_field_tag 'type', @custom_field.type %> -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/_document.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/documents/_document.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %>

    +

    <%= format_time(document.updated_on) %>

    + +
    + <%= textilizable(truncate_lines(document.description), :object => document) %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/_document.rhtml --- a/app/views/documents/_document.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %>

    -

    <%= format_time(document.updated_on) %>

    - -
    - <%= textilizable(truncate_lines(document.description)) %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/documents/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +<%= error_messages_for 'document' %> +
    + +

    +<%= select('document', 'category_id', DocumentCategory.active.collect {|c| [c.name, c.id]}) %>

    + +

    +<%= text_field 'document', 'title', :size => 60 %>

    + +

    +<%= text_area 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    + +
    + +<%= wikitoolbar_for 'document_description' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/_form.rhtml --- a/app/views/documents/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -<%= error_messages_for 'document' %> -
    - -

    -<%= select('document', 'category_id', DocumentCategory.all.collect {|c| [c.name, c.id]}) %>

    - -

    -<%= text_field 'document', 'title', :size => 60 %>

    - -

    -<%= text_area 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    - -
    - -<%= wikitoolbar_for 'document_description' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/documents/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%=l(:label_document)%>

    + +<% form_tag({:action => 'edit', :id => @document}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<% end %> + + diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/edit.rhtml --- a/app/views/documents/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -

    <%=l(:label_document)%>

    - -<% form_tag({:action => 'edit', :id => @document}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<% end %> - - diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/documents/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +
    +<%= link_to_if_authorized l(:label_document_new), + {:controller => 'documents', :action => 'new', :project_id => @project}, + :class => 'icon icon-add', + :onclick => 'Element.show("add-document"); Form.Element.focus("document_title"); return false;' %> +
    + + + +

    <%=l(:label_document_plural)%>

    + +<% if @grouped.empty? %>

    <%= l(:label_no_data) %>

    <% end %> + +<% @grouped.keys.sort.each do |group| %> +

    <%= group %>

    + <%= render :partial => 'documents/document', :collection => @grouped[group] %> +<% end %> + +<% content_for :sidebar do %> +

    <%= l(:label_sort_by, '') %>

    + <% form_tag({}, :method => :get) do %> +
    +
    +
    + + <% end %> +<% end %> + +<% html_title(l(:label_document_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/index.rhtml --- a/app/views/documents/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -
    -<%= link_to_if_authorized l(:label_document_new), - {:controller => 'documents', :action => 'new', :project_id => @project}, - :class => 'icon icon-add', - :onclick => 'Element.show("add-document"); Form.Element.focus("document_title"); return false;' %> -
    - - - -

    <%=l(:label_document_plural)%>

    - -<% if @grouped.empty? %>

    <%= l(:label_no_data) %>

    <% end %> - -<% @grouped.keys.sort.each do |group| %> -

    <%= group %>

    - <%= render :partial => 'documents/document', :collection => @grouped[group] %> -<% end %> - -<% content_for :sidebar do %> -

    <%= l(:label_sort_by, '') %>

    - <% form_tag({}, :method => :get) do %> -
    -
    -
    - - <% end %> -<% end %> - -<% html_title(l(:label_document_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/documents/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +

    <%=l(:label_document_new)%>

    + +<% form_tag({:controller => 'documents', :action => 'new', :project_id => @project}, :class => "tabular", :multipart => true) do %> +<%= render :partial => 'documents/form' %> + +
    +

    <%= render :partial => 'attachments/form' %>

    +
    + +<%= submit_tag l(:button_create) %> +<% end %> + + diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/new.rhtml --- a/app/views/documents/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -

    <%=l(:label_document_new)%>

    - -<% form_tag({:controller => 'documents', :action => 'new', :project_id => @project}, :class => "tabular", :multipart => true) do %> -<%= render :partial => 'documents/form' %> - -
    -

    <%= render :partial => 'attachments/form' %>

    -
    - -<%= submit_tag l(:button_create) %> -<% end %> - - diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/documents/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ +
    +<%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %> +<%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> +
    + +

    <%=h @document.title %>

    + +

    <%=h @document.category.name %>
    +<%= format_date @document.created_on %>

    +
    +<%= textilizable @document.description, :attachments => @document.attachments %> +
    + +

    <%= l(:label_attachment_plural) %>

    +<%= link_to_attachments @document %> + +<% if authorize_for('documents', 'add_attachment') %> +

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", + :id => 'attach_files_link' %>

    + <% form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> +
    +

    <%= render :partial => 'attachments/form' %>

    +
    + <%= submit_tag l(:button_add) %> + <% end %> +<% end %> + +<% html_title @document.title -%> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/documents/show.rhtml --- a/app/views/documents/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -
    -<%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %> -<%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> -
    - -

    <%=h @document.title %>

    - -

    <%=h @document.category.name %>
    -<%= format_date @document.created_on %>

    -
    -<%= textilizable @document.description, :attachments => @document.attachments %> -
    - -

    <%= l(:label_attachment_plural) %>

    -<%= link_to_attachments @document %> - -<% if authorize_for('documents', 'add_attachment') %> -

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", - :id => 'attach_files_link' %>

    - <% form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> -
    -

    <%= render :partial => 'attachments/form' %>

    -
    - <%= submit_tag l(:button_add) %> - <% end %> -<% end %> - -<% html_title @document.title -%> - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/enumerations/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +<%= error_messages_for 'enumeration' %> +
    + +<%= hidden_field 'enumeration', 'type' %> + +

    +<%= text_field 'enumeration', 'name' %>

    + +

    +<%= check_box 'enumeration', 'active' %>

    + +

    +<%= check_box 'enumeration', 'is_default' %>

    + + +<% @enumeration.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :enumeration, value %>

    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/_form.rhtml --- a/app/views/enumerations/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -<%= error_messages_for 'enumeration' %> -
    - -<%= hidden_field 'enumeration', 'type' %> - -

    -<%= text_field 'enumeration', 'name' %>

    - -

    -<%= check_box 'enumeration', 'active' %>

    - -

    -<%= check_box 'enumeration', 'is_default' %>

    - - -<% @enumeration.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :enumeration, value %>

    -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/destroy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/enumerations/destroy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +

    <%= l(@enumeration.option_name) %>: <%=h @enumeration %>

    + +<% form_tag({}) do %> +
    +

    <%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %>

    +

    +<%= select_tag 'reassign_to_id', ("" + options_from_collection_for_select(@enumerations, 'id', 'name')) %>

    +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'enumerations', :action => 'index' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/destroy.rhtml --- a/app/views/enumerations/destroy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -

    <%= l(@enumeration.option_name) %>: <%=h @enumeration %>

    - -<% form_tag({}) do %> -
    -

    <%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %>

    -

    <%= l(:text_enumeration_category_reassign_to) %> -<%= select_tag 'reassign_to_id', ("" + options_from_collection_for_select(@enumerations, 'id', 'name')) %>

    -
    - -<%= submit_tag l(:button_apply) %> -<%= link_to l(:button_cancel), :controller => 'enumerations', :action => 'index' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/enumerations/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=h @enumeration %>

    + +<% form_tag({:action => 'update', :id => @enumeration}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/edit.rhtml --- a/app/views/enumerations/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -

    <%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=h @enumeration %>

    - -<% form_tag({:action => 'update', :id => @enumeration}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<% end %> - -<% form_tag({:action => 'destroy', :id => @enumeration}) do %> - <%= submit_tag l(:button_delete) %> -<% end %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/enumerations/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +

    <%=l(:label_enumerations)%>

    + +<% Enumeration.get_subclasses.each do |klass| %> +

    <%= l(klass::OptionName) %>

    + +<% enumerations = klass.shared %> +<% if enumerations.any? %> + + + + + + + + +<% enumerations.each do |enumeration| %> + + + + + + + +<% end %> +
    <%= l(:field_name) %><%= l(:field_is_default) %><%= l(:field_active) %>
    <%= link_to h(enumeration), :action => 'edit', :id => enumeration %><%= checked_image enumeration.is_default? %><%= checked_image enumeration.active? %><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}) %> + <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration }, + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del' %> +
    +<% reset_cycle %> +<% end %> + +

    <%= link_to l(:label_enumeration_new), { :action => 'new', :type => klass.name } %>

    +<% end %> + +<% html_title(l(:label_enumerations)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/list.rhtml --- a/app/views/enumerations/list.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -

    <%=l(:label_enumerations)%>

    - -<% Enumeration.get_subclasses.each do |klass| %> -

    <%= l(klass::OptionName) %>

    - -<% enumerations = klass.shared %> -<% if enumerations.any? %> - - - - - - - - -<% enumerations.each do |enumeration| %> - - - - - - - -<% end %> -
    <%= l(:field_name) %><%= l(:field_is_default) %><%= l(:field_active) %>
    <%= link_to h(enumeration), :action => 'edit', :id => enumeration %><%= checked_image enumeration.is_default? %><%= checked_image enumeration.active? %><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}) %> - <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration }, - :method => :post, - :confirm => l(:text_are_you_sure), - :class => 'icon icon-del' %> -
    -<% reset_cycle %> -<% end %> - -

    <%= link_to l(:label_enumeration_new), { :action => 'new', :type => klass.name } %>

    -<% end %> - -<% html_title(l(:label_enumerations)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/enumerations/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=l(:label_enumeration_new)%>

    + +<% form_tag({:action => 'create'}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/enumerations/new.rhtml --- a/app/views/enumerations/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=l(:label_enumeration_new)%>

    - -<% form_tag({:action => 'create'}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/files/index.html.erb --- a/app/views/files/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/files/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -19,16 +19,16 @@
    - <%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %> -
    <% have_file = true %> @@ -55,10 +55,10 @@ <%= file.downloads %> <%= file.digest %> - <%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file}, - :confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %> + <%= link_to(image_tag('delete.png'), attachment_path(file), + :confirm => l(:text_are_you_sure), :method => :delete) if delete_allowed %>
    @@ -72,7 +72,7 @@
    -<%= @gantt.subjects %> +<%= @gantt.subjects.html_safe %>
    @@ -81,78 +81,78 @@
     
    -<% +<% # # Months headers # month_f = @gantt.date_from left = 0 height = (show_weeks ? header_heigth : header_heigth + g_height) -@gantt.months.times do - width = ((month_f >> 1) - month_f) * zoom - 1 - %> -
    - <%= link_to "#{month_f.year}-#{month_f.month}", @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%> -
    - <% - left = left + width + 1 - month_f = month_f >> 1 +@gantt.months.times do + width = ((month_f >> 1) - month_f) * zoom - 1 + %> +
    + <%= link_to h("#{month_f.year}-#{month_f.month}"), @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%> +
    + <% + left = left + width + 1 + month_f = month_f >> 1 end %> -<% +<% # # Weeks headers # if show_weeks - left = 0 - height = (show_days ? header_heigth-1 : header_heigth-1 + g_height) - if @gantt.date_from.cwday == 1 - # @date_from is monday + left = 0 + height = (show_days ? header_heigth-1 : header_heigth-1 + g_height) + if @gantt.date_from.cwday == 1 + # @date_from is monday week_f = @gantt.date_from - else - # find next monday after @date_from - week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1) - width = (7 - @gantt.date_from.cwday + 1) * zoom-1 - %> -
     
    - <% - left = left + width+1 - end %> - <% - while week_f <= @gantt.date_to - width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom -1 : (@gantt.date_to - week_f + 1) * zoom-1 - %> -
    - <%= week_f.cweek if width >= 16 %> -
    - <% - left = left + width+1 - week_f = week_f+7 - end + else + # find next monday after @date_from + week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1) + width = (7 - @gantt.date_from.cwday + 1) * zoom-1 + %> +
     
    + <% + left = left + width+1 + end %> + <% + while week_f <= @gantt.date_to + width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom -1 : (@gantt.date_to - week_f + 1) * zoom-1 + %> +
    + <%= week_f.cweek if width >= 16 %> +
    + <% + left = left + width+1 + week_f = week_f+7 + end end %> -<% +<% # # Days headers # if show_days - left = 0 - height = g_height + header_heigth - 1 - wday = @gantt.date_from.cwday - (@gantt.date_to - @gantt.date_from + 1).to_i.times do - width = zoom - 1 - %> -
    5 %>" class="gantt_hdr"> - <%= day_name(wday).first %> -
    - <% - left = left + width+1 - wday = wday + 1 - wday = 1 if wday > 7 - end + left = 0 + height = g_height + header_heigth - 1 + wday = @gantt.date_from.cwday + (@gantt.date_to - @gantt.date_from + 1).to_i.times do + width = zoom - 1 + %> +
    5 %>" class="gantt_hdr"> + <%= day_name(wday).first %> +
    + <% + left = left + width+1 + wday = wday + 1 + wday = 1 if wday > 7 + end end %> -<%= @gantt.lines %> +<%= @gantt.lines.html_safe %> <% # @@ -169,14 +169,14 @@
    - - + +
    <%= link_to_content_update('« ' + l(:label_previous), params.merge(@gantt.params_previous)) %><%= link_to_content_update(l(:label_next) + ' »', params.merge(@gantt.params_next)) %><%= link_to_content_update("\xc2\xab " + l(:label_previous), params.merge(@gantt.params_previous)) %><%= link_to_content_update(l(:label_next) + " \xc2\xbb", params.merge(@gantt.params_next)) %>
    <% other_formats_links do |f| %> - <%= f.link_to 'PDF', :url => params.merge(@gantt.params) %> - <%= f.link_to('PNG', :url => params.merge(@gantt.params)) if @gantt.respond_to?('to_image') %> + <%= f.link_to 'PDF', :url => params.merge(@gantt.params) %> + <%= f.link_to('PNG', :url => params.merge(@gantt.params)) if @gantt.respond_to?('to_image') %> <% end %> <% end # query.valid? %> diff -r 487d96eac004 -r 5e80956cc792 app/views/groups/_form.html.erb --- a/app/views/groups/_form.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/groups/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,8 +1,8 @@ -<%= error_messages_for :group %> +<%= f.error_messages %>
    -

    <%= f.text_field :lastname, :label => :field_name %>

    - <% @group.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :group, value %>

    +

    <%= f.text_field :lastname, :label => :field_name %>

    + <% @group.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :group, value %>

    <% end %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/groups/_general.html.erb --- a/app/views/groups/_general.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/groups/_general.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -<% labelled_tabular_form_for :group, @group, :url => group_path(@group), :html => {:method => :put} do |f| %> +<% labelled_form_for @group do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> <%= submit_tag l(:button_save) %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/groups/_memberships.html.erb --- a/app/views/groups/_memberships.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/groups/_memberships.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -4,21 +4,21 @@
    <% if @group.memberships.any? %> - - - - - - - <% @group.memberships.each do |membership| %> - <% next if membership.new_record? %> - - + + + + + + + <% @group.memberships.each do |membership| %> + <% next if membership.new_record? %> + + - - + <% end; reset_cycle %> +
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    <%=h membership.project %>
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    <%=h membership.project %> <%=h membership.roles.sort.collect(&:to_s).join(', ') %> <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @group, :membership_id => membership }, - :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %> -

    <% roles.each do |role| %> + :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %> +

    <% roles.each do |role| %>
    <% end %>

    <%= submit_tag l(:button_change) %> @@ -28,12 +28,12 @@

    <%= link_to_function l(:button_edit), "$('member-#{membership.id}-roles').hide(); $('member-#{membership.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %> <%= link_to_remote l(:button_delete), { :url => { :controller => 'groups', :action => 'destroy_membership', :id => @group, :membership_id => membership }, - :method => :post }, - :class => 'icon icon-del' %> + :method => :post }, + :class => 'icon icon-del' %>
    <% else %>

    <%= l(:label_no_data) %>

    @@ -44,6 +44,7 @@ <% if projects.any? %>
    <%=l(:label_project_new)%> <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @group }) do %> +<%= label_tag "membership_project_id", l(:description_choose_project), :class => "hidden-for-sighted" %> <%= select_tag 'membership[project_id]', options_for_membership_project_select(@group, projects) %>

    <%= l(:label_role_plural) %>: <% roles.each do |role| %> diff -r 487d96eac004 -r 5e80956cc792 app/views/groups/_users.html.erb --- a/app/views/groups/_users.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/groups/_users.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,48 +1,47 @@

    <% if @group.users.any? %> - - - - - - - <% @group.users.sort.each do |user| %> - - - - - <% end %> - -
    <%= l(:label_user) %>
    <%= link_to_user user %> - <%= link_to_remote l(:button_delete), { :url => { :controller => 'groups', :action => 'remove_user', :id => @group, :user_id => user }, - :method => :post }, - :class => 'icon icon-del' %> -
    + + + + + + + <% @group.users.sort.each do |user| %> + + + + + <% end %> + +
    <%= l(:label_user) %>
    <%= link_to_user user %> + <%= link_to_remote l(:button_delete), { :url => group_user_path(@group, :user_id => user), :method => :delete }, :class => 'icon icon-del' %> +
    <% else %> -

    <%= l(:label_no_data) %>

    +

    <%= l(:label_no_data) %>

    <% end %>
    <% users = User.active.not_in_group(@group).all(:limit => 100) %> <% if users.any? %> - <% remote_form_for(:group, @group, :url => {:controller => 'groups', :action => 'add_users', :id => @group}, :method => :post) do |f| %> + <% remote_form_for(@group, :url => group_users_path(@group), :html => {:method => :post}) do |f| %>
    <%=l(:label_user_new)%> - -

    <%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

    - <%= observe_field(:user_search, + +

    <%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

    + <%= observe_field(:user_search, :frequency => 0.5, :update => :users, - :url => { :controller => 'groups', :action => 'autocomplete_for_user', :id => @group }, + :url => autocomplete_for_user_group_path(@group), + :method => :get, :with => 'q') %> - -
    - <%= principals_check_box_tags 'user_ids[]', users %> -
    - + +
    + <%= principals_check_box_tags 'user_ids[]', users %> +
    +

    <%= submit_tag l(:button_add) %>

    -
    +
    <% end %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/groups/index.html.erb --- a/app/views/groups/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/groups/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -14,7 +14,7 @@ <% @groups.each do |group| %> - <%= link_to h(group), :action => 'edit', :id => group %> + <%= link_to h(group), edit_group_path(group) %> <%= group.users.size %> <%= link_to l(:button_delete), group, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/groups/new.html.erb --- a/app/views/groups/new.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/groups/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,9 @@

    <%= link_to l(:label_group_plural), groups_path %> » <%= l(:label_group_new) %>

    -<% form_for(@group, :builder => TabularFormBuilder, :lang => current_language) do |f| %> +<% labelled_form_for @group do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> -

    <%= f.submit l(:button_create) %>

    +

    + <%= f.submit l(:button_create) %> + <%= f.submit l(:button_create_and_continue), :name => 'continue' %> +

    <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_categories/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +<%= error_messages_for 'category' %> + +
    +

    <%= f.text_field :name, :size => 30, :required => true %>

    +

    <%= f.select :assigned_to_id, principals_options_for_select(@project.assignable_users, @category.assigned_to), :include_blank => true %>

    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/_form.rhtml --- a/app/views/issue_categories/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -<%= error_messages_for 'category' %> - -
    -

    <%= f.text_field :name, :size => 30, :required => true %>

    -

    <%= f.select :assigned_to_id, @project.users.sort.collect{|u| [u.name, u.id]}, :include_blank => true %>

    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/destroy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_categories/destroy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +

    <%=l(:label_issue_category)%>: <%=h @category.name %>

    + +<% form_tag(issue_category_path(@category), :method => :delete) do %> +
    +

    <%= l(:text_issue_category_destroy_question, @issue_count) %>

    +


    +<% if @categories.size > 0 %> +: +<%= label_tag "reassign_to_id", l(:description_issue_category_reassign), :class => "hidden-for-sighted" %> +<%= select_tag 'reassign_to_id', options_from_collection_for_select(@categories, 'id', 'name') %>

    +<% end %> +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/destroy.rhtml --- a/app/views/issue_categories/destroy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -

    <%=l(:label_issue_category)%>: <%=h @category.name %>

    - -<% form_tag({}) do %> -
    -

    <%= l(:text_issue_category_destroy_question, @issue_count) %>

    -


    -<% if @categories.size > 0 %> -: -<%= select_tag 'reassign_to_id', options_from_collection_for_select(@categories, 'id', 'name') %>

    -<% end %> -
    - -<%= submit_tag l(:button_apply) %> -<%= link_to l(:button_cancel), :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_categories/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%=l(:label_issue_category)%>

    + +<% labelled_tabular_form_for :issue_category, @category, :url => issue_category_path(@category), :html => {:method => :put} do |f| %> +<%= render :partial => 'issue_categories/form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/edit.rhtml --- a/app/views/issue_categories/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%=l(:label_issue_category)%>

    - -<% labelled_tabular_form_for :category, @category, :url => { :action => 'edit', :id => @category } do |f| %> -<%= render :partial => 'issue_categories/form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/index.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_categories/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +api.array :issue_categories, api_meta(:total_count => @categories.size) do + @categories.each do |category| + api.issue_category do + api.id category.id + api.project(:id => category.project_id, :name => category.project.name) unless category.project.nil? + api.name category.name + api.assigned_to(:id => category.assigned_to_id, :name => category.assigned_to.name) unless category.assigned_to.nil? + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/new.html.erb --- a/app/views/issue_categories/new.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/issue_categories/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,6 @@

    <%=l(:label_issue_category_new)%>

    -<% labelled_tabular_form_for :category, @category, :url => { :action => 'new' } do |f| %> +<% labelled_tabular_form_for :issue_category, @category, :url => project_issue_categories_path(@project) do |f| %> <%= render :partial => 'issue_categories/form', :locals => { :f => f } %> <%= submit_tag l(:button_create) %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_categories/show.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_categories/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +api.issue_category do + api.id @category.id + api.project(:id => @category.project_id, :name => @category.project.name) unless @category.project.nil? + api.name @category.name + api.assigned_to(:id => @category.assigned_to_id, :name => @category.assigned_to.name) unless @category.assigned_to.nil? +end diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_moves/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_moves/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,79 @@ +

    <%= @copy ? l(:button_copy) : l(:button_move) %>

    + +
      +<% @issues.each do |issue| -%> +
    • <%= link_to_issue issue %>
    • +<% end -%> +
    + +<% form_tag({:action => 'create'}, :id => 'move_form') do %> +<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> + +
    +
    +<%= l(:label_change_properties) %> + +
    +

    +<%= select_tag "new_project_id", + project_tree_options_for_select(@allowed_projects, :selected => @target_project), + :onchange => remote_function(:url => { :action => 'new' }, + :method => :get, + :update => 'content', + :with => "Form.serialize('move_form')") %>

    + +

    +<%= select_tag "new_tracker_id", "" + options_from_collection_for_select(@trackers, "id", "name") %>

    + +

    + + <%= select_tag('status_id', "" + options_from_collection_for_select(@available_statuses, :id, :name)) %> +

    + +

    + + <%= select_tag('priority_id', "" + options_from_collection_for_select(IssuePriority.active, :id, :name)) %> +

    + +

    + + <%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_nobody), :value => 'none') + + principals_options_for_select(@target_project.assignable_users)) %> +

    +
    + +
    +

    + + <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %> +

    + +

    + + <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %> +

    +
    + +
    + +
    <%= l(:field_notes) %> +<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> +<%= wikitoolbar_for 'notes' %> +
    + +<%= call_hook(:view_issues_move_bottom, :issues => @issues, :target_project => @target_project, :copy => !!@copy) %> +
    + +<% if @copy %> + <%= hidden_field_tag("copy_options[copy]", "1") %> + <%= submit_tag l(:button_copy) %> + <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %> +<% else %> + <%= submit_tag l(:button_move) %> + <%= submit_tag l(:button_move_and_follow), :name => 'follow' %> +<% end %> +<% end %> +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_moves/new.rhtml --- a/app/views/issue_moves/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -

    <%= @copy ? l(:button_copy) : l(:button_move) %>

    - -
      -<% @issues.each do |issue| -%> -
    • <%= link_to_issue issue %>
    • -<% end -%> -
    - -<% form_tag({:action => 'create'}, :id => 'move_form') do %> -<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> - -
    -
    -<%= l(:label_change_properties) %> - -
    -

    -<%= select_tag "new_project_id", - project_tree_options_for_select(@allowed_projects, :selected => @target_project), - :onchange => remote_function(:url => { :action => 'new' }, - :method => :get, - :update => 'content', - :with => "Form.serialize('move_form')") %>

    - -

    -<%= select_tag "new_tracker_id", "" + options_from_collection_for_select(@trackers, "id", "name") %>

    - -

    - - <%= select_tag('status_id', "" + options_from_collection_for_select(@available_statuses, :id, :name)) %> -

    - -

    - - <%= select_tag('priority_id', "" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %> -

    - -

    - - <%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') + - content_tag('option', l(:label_nobody), :value => 'none') + - options_from_collection_for_select(@target_project.assignable_users, :id, :name)) %> -

    -
    - -
    -

    - - <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %> -

    - -

    - - <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %> -

    -
    - -
    - -
    <%= l(:field_notes) %> -<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> -<%= wikitoolbar_for 'notes' %> -
    - -<%= call_hook(:view_issues_move_bottom, :issues => @issues, :target_project => @target_project, :copy => !!@copy) %> -
    - -<% if @copy %> - <%= hidden_field_tag("copy_options[copy]", "1") %> - <%= submit_tag l(:button_copy) %> - <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %> -<% else %> - <%= submit_tag l(:button_move) %> - <%= submit_tag l(:button_move_and_follow), :name => 'follow' %> -<% end %> -<% end %> -<% content_for :header_tags do %> - <%= robot_exclusion_tag %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_relations/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_relations/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +<%= error_messages_for 'relation' %> + +

    <%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %> +<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 10 %> +

    +<%= javascript_tag "observeRelatedIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> + +<%= submit_tag l(:button_add) %> +<%= toggle_link l(:button_cancel), 'new-relation-form'%> +

    + +<%= javascript_tag "setPredecessorFieldsVisibility();" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_relations/_form.rhtml --- a/app/views/issue_relations/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -<%= error_messages_for 'relation' %> - -

    <%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %> -<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 10 %> -

    -<%= javascript_tag "observeRelatedIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> - -<%= submit_tag l(:button_add) %> -<%= toggle_link l(:button_cancel), 'new-relation-form'%> -

    - -<%= javascript_tag "setPredecessorFieldsVisibility();" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_relations/index.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_relations/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +api.array :relations do + @relations.each do |relation| + api.relation do + api.id relation.id + api.issue_id relation.issue_from_id + api.issue_to_id relation.issue_to_id + api.relation_type relation.relation_type + api.delay relation.delay + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_relations/show.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_relations/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +api.relation do + api.id @relation.id + api.issue_id @relation.issue_from_id + api.issue_to_id @relation.issue_to_id + api.relation_type @relation.relation_type + api.delay @relation.delay +end diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_statuses/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +<%= error_messages_for 'issue_status' %> + +
    +

    <%= f.text_field :name, :required => true %>

    +<% if Issue.use_status_for_done_ratio? %> +

    <%= f.select :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true, :label => :field_done_ratio %>

    +<% end %> +

    <%= f.check_box :is_closed %>

    +

    <%= f.check_box :is_default %>

    + +<%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/_form.rhtml --- a/app/views/issue_statuses/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -<%= error_messages_for 'issue_status' %> - -
    - -

    -<%= text_field 'issue_status', 'name' %>

    - -<% if Issue.use_status_for_done_ratio? %> -

    -<%= select 'issue_status', :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true %>

    -<% end %> - -

    -<%= check_box 'issue_status', 'is_closed' %>

    - -

    -<%= check_box 'issue_status', 'is_default' %>

    - -<%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %> - - -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_statuses/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=h @issue_status %>

    + +<% form_for @issue_status, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/edit.rhtml --- a/app/views/issue_statuses/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses', :action => 'index' %> » <%=h @issue_status %>

    - -<% form_tag({:action => 'update', :id => @issue_status}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/index.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_statuses/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +api.array :issue_statuses do + @issue_statuses.each do |status| + api.issue_status do + api.id status.id + api.name status.name + api.is_default status.is_default + api.is_closed status.is_closed + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/index.html.erb --- a/app/views/issue_statuses/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/issue_statuses/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,10 @@
    -<%= link_to l(:label_issue_status_new), {:action => 'new'}, :class => 'icon icon-add' %> -<%= link_to(l(:label_update_issue_done_ratios), {:action => 'update_issue_done_ratio'}, :class => 'icon icon-multiple', :method => 'post', :confirm => l(:text_are_you_sure)) if Issue.use_status_for_done_ratio? %> +<%= link_to l(:label_issue_status_new), new_issue_status_path, :class => 'icon icon-add' %> +<%= link_to(l(:label_update_issue_done_ratios), update_issue_done_ratio_issue_statuses_path, :class => 'icon icon-multiple', :method => 'post', :confirm => l(:text_are_you_sure)) if Issue.use_status_for_done_ratio? %>

    <%=l(:label_issue_status_plural)%>

    - + @@ -16,21 +16,21 @@ - + <% for status in @issue_statuses %> "> - + <% if Issue.use_status_for_done_ratio? %> <% end %> - + <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issue_statuses/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=l(:label_issue_status_new)%>

    + +<% form_for @issue_status, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issue_statuses/new.rhtml --- a/app/views/issue_statuses/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses', :action => 'index' %> » <%=l(:label_issue_status_new)%>

    - -<% form_tag({:action => 'create'}, :class => "tabular") do %> - <%= render :partial => 'form' %> - <%= submit_tag l(:button_create) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_action_menu.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_action_menu.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +
    +<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %> +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %> +<%= watcher_tag(@issue, User.current) %> +<%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %> +<%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %> +<%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %> +<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => issues_destroy_confirmation_message(@issue), :method => :post, :class => 'icon icon-del' %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_action_menu.rhtml --- a/app/views/issues/_action_menu.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -
    -<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %> -<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %> -<%= watcher_tag(@issue, User.current) %> -<%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %> -<%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %> -<%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %> -<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => issues_destroy_confirmation_message(@issue), :method => :post, :class => 'icon icon-del' %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_attributes.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_attributes.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +<% fields_for :issue, @issue, :builder => TabularFormBuilder do |f| %> + +
    +<% if @issue.new_record? || @allowed_statuses.any? %> +

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    +<% else %> +

    <%= h(@issue.status.name) %>

    +<% end %> + +

    <%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %>

    +

    <%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %>

    +<% unless @project.issue_categories.empty? %> +

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> +<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), + l(:label_issue_category_new), + 'issue_category[name]', + {:controller => 'issue_categories', :action => 'create', :project_id => @project}, + :title => l(:label_issue_category_new), + :tabindex => 199) if authorize_for('issue_categories', 'new') %>

    +<% end %> +<% unless @issue.assignable_versions.empty? %> +

    <%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %> +<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), + l(:label_version_new), + 'version[name]', + {:controller => 'versions', :action => 'create', :project_id => @project}, + :title => l(:label_version_new), + :tabindex => 200) if authorize_for('versions', 'new') %> +

    +<% end %> +
    + +
    +<% if User.current.allowed_to?(:manage_subtasks, @project) %> +

    <%= f.text_field :parent_issue_id, :size => 10 %>

    +
    +<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> +<% end %> +

    <%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_start_date') if @issue.leaf? %>

    +

    <%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_due_date') if @issue.leaf? %>

    +

    <%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf? %> <%= l(:field_hours) %>

    +<% if @issue.leaf? && Issue.use_field_for_done_ratio? %> +

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    +<% end %> +
    + +
    +<%= render :partial => 'issues/form_custom_fields' %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_attributes.rhtml --- a/app/views/issues/_attributes.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -<% fields_for :issue, @issue, :builder => TabularFormBuilder do |f| %> - -
    -<% if @issue.new_record? || @allowed_statuses.any? %> -

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    -<% else %> -

    <%= @issue.status.name %>

    -<% end %> - -

    <%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %>

    -

    <%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), {:include_blank => true} %>

    -<% unless @project.issue_categories.empty? %> -

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> -<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), - l(:label_issue_category_new), - 'category[name]', - {:controller => 'issue_categories', :action => 'new', :project_id => @project}, - :title => l(:label_issue_category_new), - :tabindex => 199) if authorize_for('issue_categories', 'new') %>

    -<% end %> -<% unless @issue.assignable_versions.empty? %> -

    <%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %> -<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), - l(:label_version_new), - 'version[name]', - {:controller => 'versions', :action => 'create', :project_id => @project}, - :title => l(:label_version_new), - :tabindex => 200) if authorize_for('versions', 'new') %> -

    -<% end %> -
    - -
    -<% if User.current.allowed_to?(:manage_subtasks, @project) %> -

    <%= f.text_field :parent_issue_id, :size => 10 %>

    -
    -<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> -<% end %> -

    <%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_start_date') if @issue.leaf? %>

    -

    <%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_due_date') if @issue.leaf? %>

    -

    <%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf? %> <%= l(:field_hours) %>

    -<% if @issue.leaf? && Issue.use_field_for_done_ratio? %> -

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    -<% end %> -
    - -
    -<%= render :partial => 'issues/form_custom_fields' %> - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_changesets.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_changesets.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +<% changesets.each do |changeset| %> +
    +

    <%= link_to_revision(changeset, changeset.project, + :text => "#{l(:label_revision)} #{changeset.format_identifier}") %>
    + <%= authoring(changeset.committed_on, changeset.author) %>

    +
    + <%= textilizable(changeset, :comments) %> +
    +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_changesets.rhtml --- a/app/views/issues/_changesets.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -<% changesets.each do |changeset| %> -
    -

    <%= link_to_revision(changeset, changeset.project, - :text => "#{l(:label_revision)} #{changeset.format_identifier}") %>
    - <%= authoring(changeset.committed_on, changeset.author) %>

    -
    - <%= textilizable(changeset, :comments) %> -
    -
    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +<% labelled_tabular_form_for :issue, @issue, + :url => {:action => 'update', :id => @issue}, + :html => {:id => 'issue-form', + :class => nil, + :method => :put, + :multipart => true} do |f| %> + <%= error_messages_for 'issue', 'time_entry' %> +
    + <% if @edit_allowed || !@allowed_statuses.empty? %> +
    <%= l(:label_change_properties) %> + <% if !@issue.new_record? && !@issue.errors.any? && @edit_allowed %> + (<%= link_to l(:label_more), {}, :onclick => 'Effect.toggle("issue_descr_fields", "appear", {duration:0.3}); return false;' %>) + <% end %> + + <%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %> +
    + <% end %> + <% if User.current.allowed_to?(:log_time, @project) %> +
    <%= l(:button_log_time) %> + <% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %> +
    +

    <%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %>

    +
    +
    +

    <%= time_entry.select :activity_id, activity_collection_for_select_options %>

    +
    +

    <%= time_entry.text_field :comments, :size => 60 %>

    + <% @time_entry.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :time_entry, value %>

    + <% end %> + <% end %> +
    + <% end %> + +
    <%= l(:field_notes) %> + <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'notes' %> + <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> + +

    <%=l(:label_attachment_plural)%>
    <%= render :partial => 'attachments/form' %>

    +
    +
    + + <%= f.hidden_field :lock_version %> + <%= submit_tag l(:button_submit) %> + <%= link_to_remote l(:label_preview), + { :url => preview_issue_path(:project_id => @project, :id => @issue), + :method => 'post', + :update => 'preview', + :with => 'Form.serialize("issue-form")', + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> +<% end %> + +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_edit.rhtml --- a/app/views/issues/_edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -<% labelled_tabular_form_for :issue, @issue, - :url => {:action => 'update', :id => @issue}, - :html => {:id => 'issue-form', - :class => nil, - :method => :put, - :multipart => true} do |f| %> - <%= error_messages_for 'issue', 'time_entry' %> -
    - <% if @edit_allowed || !@allowed_statuses.empty? %> -
    <%= l(:label_change_properties) %> - <% if !@issue.new_record? && !@issue.errors.any? && @edit_allowed %> - (<%= link_to l(:label_more), {}, :onclick => 'Effect.toggle("issue_descr_fields", "appear", {duration:0.3}); return false;' %>) - <% end %> - - <%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %> -
    - <% end %> - <% if authorize_for('timelog', 'edit') %> -
    <%= l(:button_log_time) %> - <% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %> -
    -

    <%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %>

    -
    -
    -

    <%= time_entry.select :activity_id, activity_collection_for_select_options %>

    -
    -

    <%= time_entry.text_field :comments, :size => 60 %>

    - <% @time_entry.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :time_entry, value %>

    - <% end %> - <% end %> -
    - <% end %> - -
    <%= l(:field_notes) %> - <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> - <%= wikitoolbar_for 'notes' %> - <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> - -

    <%=l(:label_attachment_plural)%>
    <%= render :partial => 'attachments/form' %>

    -
    -
    - - <%= f.hidden_field :lock_version %> - <%= submit_tag l(:button_submit) %> - <%= link_to_remote l(:label_preview), - { :url => preview_issue_path(:project_id => @project, :id => @issue), - :method => 'post', - :update => 'preview', - :with => 'Form.serialize("issue-form")', - :complete => "Element.scrollTo('preview')" - }, :accesskey => accesskey(:preview) %> -<% end %> - -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %> + +
    > +<% if @issue.safe_attribute_names.include?('is_private') %> +

    + +

    +<% end %> +

    <%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %>

    +<%= observe_field :issue_tracker_id, :url => { :action => :new, :project_id => @project, :id => @issue }, + :update => :attributes, + :with => "Form.serialize('issue-form')" %> + +

    <%= f.text_field :subject, :size => 80, :required => true %>

    + +

    <%= f.text_area :description, + :cols => 60, + :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min), + :accesskey => accesskey(:edit), + :class => 'wiki-edit' %>

    +
    + +
    + <%= render :partial => 'issues/attributes' %> +
    + +<% if @issue.new_record? %> +

    <%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %>

    +<% end %> + +<% if @issue.new_record? && User.current.allowed_to?(:add_issue_watchers, @project) -%> +

    +<% @issue.project.users.sort.each do |user| -%> + +<% end -%> +

    +<% end %> + +<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %> + +<%= wikitoolbar_for 'issue_description' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_form.rhtml --- a/app/views/issues/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %> - -
    > -<% if @issue.safe_attribute_names.include?('is_private') %> -

    - -

    -<% end %> -

    <%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %>

    -<%= observe_field :issue_tracker_id, :url => { :action => :new, :project_id => @project, :id => @issue }, - :update => :attributes, - :with => "Form.serialize('issue-form')" %> - -

    <%= f.text_field :subject, :size => 80, :required => true %>

    - -

    <%= f.text_area :description, - :cols => 60, - :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min), - :accesskey => accesskey(:edit), - :class => 'wiki-edit' %>

    -
    - -
    - <%= render :partial => 'issues/attributes' %> -
    - -<% if @issue.new_record? %> -

    <%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %>

    -<% end %> - -<% if @issue.new_record? && User.current.allowed_to?(:add_issue_watchers, @project) -%> -

    -<% @issue.project.users.sort.each do |user| -%> - -<% end -%> -

    -<% end %> - -<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %> - -<%= wikitoolbar_for 'issue_description' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_form_custom_fields.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_form_custom_fields.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +
    +<% i = 0 %> +<% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %> +<% @issue.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :issue, value %>

    +<% if i == split_on -%> +
    +<% end -%> +<% i += 1 -%> +<% end -%> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_form_custom_fields.rhtml --- a/app/views/issues/_form_custom_fields.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -
    -<% i = 0 %> -<% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %> -<% @issue.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :issue, value %>

    -<% if i == split_on -%> -
    -<% end -%> -<% i += 1 -%> -<% end -%> -
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_form_update.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_form_update.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +
    +
    +

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    +

    <%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %>

    +
    +
    +<% if Issue.use_field_for_done_ratio? %> +

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    +<% end %> +<% unless @issue.assignable_versions.empty? %> +

    <%= f.select :fixed_version_id, (@issue.assignable_versions.collect {|v| [v.name, v.id]}), :include_blank => true %>

    +<% end %> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_form_update.rhtml --- a/app/views/issues/_form_update.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -
    -
    -

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    -

    <%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %>

    -
    -
    -<% if Issue.use_field_for_done_ratio? %> -

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    -<% end %> -<% unless @issue.assignable_versions.empty? %> -

    <%= f.select :fixed_version_id, (@issue.assignable_versions.collect {|v| [v.name, v.id]}), :include_blank => true %>

    -<% end %> -
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_history.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_history.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ +<% reply_links = authorize_for('issues', 'edit') -%> +<% for journal in journals %> +
    +

    + <%= avatar(journal.user, :size => "24") %> + <%= content_tag('a', '', :name => "note-#{journal.indice}")%> + <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

    + + <% if journal.details.any? %> +
      + <% for detail in journal.details %> +
    • <%= show_detail(detail) %>
    • + <% end %> +
    + <% end %> + <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %> +
    + <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> +<% end %> + +<% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_history.rhtml --- a/app/views/issues/_history.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -<% reply_links = authorize_for('issues', 'edit') -%> -<% for journal in journals %> -
    -

    - <%= avatar(journal.user, :size => "24") %> - <%= content_tag('a', '', :name => "note-#{journal.indice}")%> - <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

    - - <% if journal.details.any? %> -
      - <% for detail in journal.details %> -
    • <%= show_detail(detail) %>
    • - <% end %> -
    - <% end %> - <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %> -
    - <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> -<% end %> - -<% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_list.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_list.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +<% form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params) %> +
    +
    <%=l(:field_status)%><%=l(:button_sort)%>
    <%= link_to status.name, :action => 'edit', :id => status %><%= link_to h(status.name), edit_issue_status_path(status) %><%= h status.default_done_ratio %><%= checked_image status.is_default? %> <%= checked_image status.is_closed? %><%= reorder_links('issue_status', {:action => 'update', :id => status}) %><%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %> - <%= link_to(l(:button_delete), { :action => 'destroy', :id => status }, - :method => :post, - :confirm => l(:text_are_you_sure), - :class => 'icon icon-del') %> + <%= link_to(l(:button_delete), issue_status_path(status), + :method => :delete, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %>
    + + + <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %> + <% query.columns.each do |column| %> + <%= column_header(column) %> + <% end %> + + <% previous_group = false %> + + <% issue_list(issues) do |issue, level| -%> + <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %> + <% reset_cycle %> + + + + <% previous_group = group %> + <% end %> + "> + + + <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.css_classes %><% end %> + + <% end -%> + +
    <%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> +
    +   + <%= group.blank? ? 'None' : column_content(@query.group_by_column, issue) %> (<%= @issue_count_by_group[group] %>) + <%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %> +
    <%= check_box_tag("ids[]", issue.id, false, :id => nil) %><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
    +
    +<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_list.rhtml --- a/app/views/issues/_list.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -<% form_tag({}) do -%> -<%= hidden_field_tag 'back_url', url_for(params) %> -
    - - - - <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %> - <% query.columns.each do |column| %> - <%= column_header(column) %> - <% end %> - - <% previous_group = false %> - - <% issue_list(issues) do |issue, level| -%> - <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %> - <% reset_cycle %> - - - - <% previous_group = group %> - <% end %> - "> - - - <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.css_classes %><% end %> - - <% end -%> - -
    <%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> -
    -   - <%= group.blank? ? 'None' : column_content(@query.group_by_column, issue) %> (<%= @issue_count_by_group[group] %>) - <%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %> -
    <%= check_box_tag("ids[]", issue.id, false, :id => nil) %><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
    -
    -<% end -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_list_simple.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_list_simple.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +<% if issues && issues.any? %> +<% form_tag({}) do %> + + + + + + + + + <% for issue in issues %> + + + + + + + <% end %> + +
    #<%=l(:field_project)%><%=l(:field_tracker)%><%=l(:field_subject)%>
    + <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> + <%= link_to(h(issue.id), :controller => 'issues', :action => 'show', :id => issue) %> + <%= link_to_project(issue.project) %><%=h issue.tracker %> + <%= link_to h(truncate(issue.subject, :length => 60)), :controller => 'issues', :action => 'show', :id => issue %> (<%=h issue.status %>) +
    +<% end %> +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_list_simple.rhtml --- a/app/views/issues/_list_simple.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -<% if issues && issues.any? %> -<% form_tag({}) do %> - - - - - - - - - <% for issue in issues %> - - - - - - - <% end %> - -
    #<%=l(:field_project)%><%=l(:field_tracker)%><%=l(:field_subject)%>
    - <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> - <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %> - <%= link_to_project(issue.project) %><%=h issue.tracker %> - <%= link_to h(truncate(issue.subject, :length => 60)), :controller => 'issues', :action => 'show', :id => issue %> (<%=h issue.status %>) -
    -<% end %> -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_relations.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_relations.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +
    +<% if User.current.allowed_to?(:manage_issue_relations, @project) %> + <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %> +<% end %> +
    + +

    <%=l(:label_related_issues)%>

    + +<% if @relations.present? %> +
    + +<% @relations.each do |relation| %> + + + + + + + + +<% end %> +
    <%= check_box_tag("ids[]", relation.other_issue(@issue).id, false, :id => nil) %><%= l(relation.label_for(@issue)) %> <%= "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)})" if relation.delay && relation.delay != 0 %> + <%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %> + <%= link_to_issue(relation.other_issue(@issue), :truncate => 60) %> +<%=h relation.other_issue(@issue).status.name %><%= format_date(relation.other_issue(@issue).start_date) %><%= format_date(relation.other_issue(@issue).due_date) %><%= link_to_remote(image_tag('link_break.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :id => relation}, + :method => :delete + }, :title => l(:label_relation_delete)) if authorize_for('issue_relations', 'destroy') %>
    +
    +<% end %> + +<% remote_form_for(:relation, @relation, + :url => {:controller => 'issue_relations', :action => 'create', :issue_id => @issue}, + :method => :post, + :complete => "Form.Element.focus('relation_issue_to_id');", + :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')}) do |f| %> +<%= render :partial => 'issue_relations/form', :locals => {:f => f}%> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_relations.rhtml --- a/app/views/issues/_relations.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -
    -<% if User.current.allowed_to?(:manage_issue_relations, @project) %> - <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %> -<% end %> -
    - -

    <%=l(:label_related_issues)%>

    - -<% if @relations.present? %> -
    - -<% @relations.each do |relation| %> - - - - - - - - -<% end %> -
    <%= check_box_tag("ids[]", relation.other_issue(@issue).id, false, :id => nil) %><%= l(relation.label_for(@issue)) %> <%= "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)})" if relation.delay && relation.delay != 0 %> - <%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %> - <%= link_to_issue(relation.other_issue(@issue), :truncate => 60) %> -<%= relation.other_issue(@issue).status.name %><%= format_date(relation.other_issue(@issue).start_date) %><%= format_date(relation.other_issue(@issue).due_date) %><%= link_to_remote(image_tag('link_break.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :issue_id => @issue, :id => relation}, - :method => :post - }, :title => l(:label_relation_delete)) if authorize_for('issue_relations', 'destroy') %>
    -
    -<% end %> - -<% remote_form_for(:relation, @relation, - :url => {:controller => 'issue_relations', :action => 'new', :issue_id => @issue}, - :method => :post, - :complete => "Form.Element.focus('relation_issue_to_id');", - :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')}) do |f| %> -<%= render :partial => 'issue_relations/form', :locals => {:f => f}%> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_sidebar.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/_sidebar.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +

    <%= l(:label_issue_plural) %>

    +<%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %>
    +<% if @project %> +<%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %>
    +<% end %> +<%= call_hook(:view_issues_sidebar_issues_bottom) %> + +<% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> + <%= link_to(l(:label_calendar), :controller => 'calendars', :action => 'show', :project_id => @project) %>
    +<% end %> +<% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> + <%= link_to(l(:label_gantt), :controller => 'gantts', :action => 'show', :project_id => @project) %>
    +<% end %> +<%= call_hook(:view_issues_sidebar_planning_bottom) %> + +<%= render_sidebar_queries %> +<%= call_hook(:view_issues_sidebar_queries_bottom) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/_sidebar.rhtml --- a/app/views/issues/_sidebar.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -

    <%= l(:label_issue_plural) %>

    -<%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %>
    -<% if @project %> -<%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %>
    -<% end %> -<%= call_hook(:view_issues_sidebar_issues_bottom) %> - -<% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> - <%= link_to(l(:label_calendar), :controller => 'calendars', :action => 'show', :project_id => @project) %>
    -<% end %> -<% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> - <%= link_to(l(:label_gantt), :controller => 'gantts', :action => 'show', :project_id => @project) %>
    -<% end %> -<%= call_hook(:view_issues_sidebar_planning_bottom) %> - -<%= render_sidebar_queries %> -<%= call_hook(:view_issues_sidebar_queries_bottom) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/bulk_edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/bulk_edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,91 @@ +

    <%= l(:label_bulk_edit_selected_issues) %>

    + +
      <%= @issues.collect {|i| content_tag('li', link_to(h("#{i.tracker} ##{i.id}"), { :action => 'show', :id => i }) + h(": #{i.subject}")) }.join("\n") %>
    + +<% form_tag(:action => 'bulk_update') do %> +<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> +
    +
    +<%= l(:label_change_properties) %> + +
    +

    + + <%= select_tag('issue[tracker_id]', "" + options_from_collection_for_select(@trackers, :id, :name)) %> +

    +<% if @available_statuses.any? %> +

    + + <%= select_tag('issue[status_id]', "" + options_from_collection_for_select(@available_statuses, :id, :name)) %> +

    +<% end %> +

    + + <%= select_tag('issue[priority_id]', "" + options_from_collection_for_select(IssuePriority.active, :id, :name)) %> +

    +

    + + <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_nobody), :value => 'none') + + principals_options_for_select(@assignables)) %> +

    +<% if @project %> +

    + + <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + options_from_collection_for_select(@project.issue_categories, :id, :name)) %> +

    +<% end %> +<% #TODO: allow editing versions when multiple projects %> +<% if @project %> +

    + + <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + version_options_for_select(@project.shared_versions.open.sort)) %> +

    +<% end %> + +<% @custom_fields.each do |custom_field| %> +

    +<% end %> + +<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> +
    + +
    +<% if @project && User.current.allowed_to?(:manage_subtasks, @project) %> +

    + + <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> +

    +
    +<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %> +<% end %> +

    + + <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %> +

    +

    + + <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %> +

    +<% if Issue.use_field_for_done_ratio? %> +

    + + <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> +

    +<% end %> +
    + +
    + +
    <%= l(:field_notes) %> +<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> +<%= wikitoolbar_for 'notes' %> +
    +
    + +

    <%= submit_tag l(:button_submit) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/bulk_edit.rhtml --- a/app/views/issues/bulk_edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -

    <%= l(:label_bulk_edit_selected_issues) %>

    - -
      <%= @issues.collect {|i| content_tag('li', link_to(h("#{i.tracker} ##{i.id}"), { :action => 'show', :id => i }) + h(": #{i.subject}")) }.join("\n") %>
    - -<% form_tag(:action => 'bulk_update') do %> -<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> -
    -
    -<%= l(:label_change_properties) %> - -
    -

    - - <%= select_tag('issue[tracker_id]', "" + options_from_collection_for_select(@trackers, :id, :name)) %> -

    -<% if @available_statuses.any? %> -

    - - <%= select_tag('issue[status_id]', "" + options_from_collection_for_select(@available_statuses, :id, :name)) %> -

    -<% end %> -

    - - <%= select_tag('issue[priority_id]', "" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %> -

    -

    - - <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + - content_tag('option', l(:label_nobody), :value => 'none') + - options_from_collection_for_select(@assignables, :id, :name)) %> -

    -<% if @project %> -

    - - <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + - content_tag('option', l(:label_none), :value => 'none') + - options_from_collection_for_select(@project.issue_categories, :id, :name)) %> -

    -<% end %> -<% #TODO: allow editing versions when multiple projects %> -<% if @project %> -

    - - <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + - content_tag('option', l(:label_none), :value => 'none') + - version_options_for_select(@project.shared_versions.open.sort)) %> -

    -<% end %> - -<% @custom_fields.each do |custom_field| %> -

    <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %>

    -<% end %> - -<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> -
    - -
    -<% if @project && User.current.allowed_to?(:manage_subtasks, @project) %> -

    - - <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> -

    -
    -<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %> -<% end %> -

    - - <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %> -

    -

    - - <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %> -

    -<% if Issue.use_field_for_done_ratio? %> -

    - - <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> -

    -<% end %> -
    - -
    - -
    <%= l(:field_notes) %> -<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> -<%= wikitoolbar_for 'notes' %> -
    -
    - -

    <%= submit_tag l(:button_submit) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/destroy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/destroy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%= l(:label_confirmation) %>

    + +<% form_tag do %> +<%= @issues.collect {|i| hidden_field_tag 'ids[]', i.id } %> +
    +

    <%= l(:text_destroy_time_entries_question, :hours => number_with_precision(@hours, :precision => 2)) %>

    +

    +
    +
    + +<%= text_field_tag 'reassign_to_id', params[:reassign_to_id], :size => 6, :onfocus => '$("todo_reassign").checked=true;' %> +

    +
    +<%= submit_tag l(:button_apply) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/destroy.rhtml --- a/app/views/issues/destroy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -

    <%= l(:label_confirmation) %>

    - -<% form_tag do %> -<%= @issues.collect {|i| hidden_field_tag 'ids[]', i.id } %> -
    -

    <%= l(:text_destroy_time_entries_question, :hours => number_with_precision(@hours, :precision => 2)) %>

    -

    -
    -
    - -<%= text_field_tag 'reassign_to_id', params[:reassign_to_id], :size => 6, :onfocus => '$("todo_reassign").checked=true;' %> -

    -
    -<%= submit_tag l(:button_apply) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%=h "#{@issue.tracker.name} ##{@issue.id}" %>

    + +<%= render :partial => 'edit' %> +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/edit.rhtml --- a/app/views/issues/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%=h "#{@issue.tracker.name} ##{@issue.id}" %>

    - -<%= render :partial => 'edit' %> -<% content_for :header_tags do %> - <%= robot_exclusion_tag %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/index.api.rsb --- a/app/views/issues/index.api.rsb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/issues/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -11,18 +11,24 @@ api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil? api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil? api.parent(:id => issue.parent_id) unless issue.parent.nil? - - api.subject issue.subject + + api.subject issue.subject api.description issue.description - api.start_date issue.start_date - api.due_date issue.due_date - api.done_ratio issue.done_ratio + api.start_date issue.start_date + api.due_date issue.due_date + api.done_ratio issue.done_ratio api.estimated_hours issue.estimated_hours - + render_api_custom_values issue.custom_field_values, api - + api.created_on issue.created_on api.updated_on issue.updated_on + + api.array :relations do + issue.relations.each do |relation| + api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay) + end + end if include_in_api_response?('relations') end end end diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,90 @@ +
    +<% if !@query.new_record? && @query.editable_by?(User.current) %> + <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), query_path(@query), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> +<% end %> +
    + +

    <%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %>

    +<% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %> + +<% form_tag({ :controller => 'issues', :action => 'index', :project_id => @project }, :method => :get, :id => 'query_form') do %> + <%= hidden_field_tag 'set_filter', '1' %> +
    +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +
    +

    + + <%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %> + <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %> + <%= link_to_function l(:button_save), "$('query_form').action='#{ @project ? new_project_query_path : new_query_path }'; submit_query_form('query_form')", :class => 'icon icon-save' %> + <% end %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<% if @issues.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> +

    <%= pagination_links_full @issue_pages, @issue_count %>

    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %> + <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '330px'); return false;" %> + <%= f.link_to 'PDF', :url => params %> +<% end %> + + + +<% end %> +<%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %> + <%= auto_discovery_link_tag(:atom, {:controller => 'journals', :action => 'index', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %> +<% end %> + +<%= context_menu issues_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/index.rhtml --- a/app/views/issues/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -
    -<% if !@query.new_record? && @query.editable_by?(User.current) %> - <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => @query}, :class => 'icon icon-edit' %> - <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> -<% end %> -
    - -

    <%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %>

    -<% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %> - -<% form_tag({ :controller => 'issues', :action => 'index', :project_id => @project }, :method => :get, :id => 'query_form') do %> - <%= hidden_field_tag 'set_filter', '1' %> -
    -
    "> - <%= l(:label_filter_plural) %> -
    "> - <%= render :partial => 'queries/filters', :locals => {:query => @query} %> -
    -
    - -
    -

    - - <%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %> - <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %> - <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %> - <%= link_to_function l(:button_save), "$('query_form').action='#{ url_for :controller => 'queries', :action => 'new', :project_id => @project }'; submit_query_form('query_form')", :class => 'icon icon-save' %> - <% end %> -

    -<% end %> - -<%= error_messages_for 'query' %> -<% if @query.valid? %> -<% if @issues.empty? %> -

    <%= l(:label_no_data) %>

    -<% else %> -<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> -

    <%= pagination_links_full @issue_pages, @issue_count %>

    -<% end %> - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %> - <%= f.link_to 'CSV', :url => params %> - <%= f.link_to 'PDF', :url => params %> -<% end %> - -<% end %> -<%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %> - -<% content_for :sidebar do %> - <%= render :partial => 'issues/sidebar' %> -<% end %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %> - <%= auto_discovery_link_tag(:atom, {:controller => 'journals', :action => 'index', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %> -<% end %> - -<%= context_menu issues_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +

    <%=l(:label_issue_new)%>

    + +<% labelled_tabular_form_for :issue, @issue, :url => {:controller => 'issues', :action => 'create', :project_id => @project}, + :html => {:multipart => true, :id => 'issue-form', :class => 'tabular new-issue-form'} do |f| %> + <%= error_messages_for 'issue' %> +
    + <%= render :partial => 'issues/form', :locals => {:f => f} %> +
    + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> + <%= link_to_remote l(:label_preview), + { :url => preview_issue_path(:project_id => @project), + :method => 'post', + :update => 'preview', + :with => "Form.serialize('issue-form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> + + <%= javascript_tag "Form.Element.focus('issue_subject');" %> +<% end %> + +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> + <%= robot_exclusion_tag %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/new.rhtml --- a/app/views/issues/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -

    <%=l(:label_issue_new)%>

    - -<% labelled_tabular_form_for :issue, @issue, :url => {:controller => 'issues', :action => 'create', :project_id => @project}, - :html => {:multipart => true, :id => 'issue-form', :class => 'tabular new-issue-form'} do |f| %> - <%= error_messages_for 'issue' %> -
    - <%= render :partial => 'issues/form', :locals => {:f => f} %> -
    - <%= submit_tag l(:button_create) %> - <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> - <%= link_to_remote l(:label_preview), - { :url => preview_issue_path(:project_id => @project), - :method => 'post', - :update => 'preview', - :with => "Form.serialize('issue-form')", - :complete => "Element.scrollTo('preview')" - }, :accesskey => accesskey(:preview) %> - - <%= javascript_tag "Form.Element.focus('issue_subject');" %> -<% end %> - -
    - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> - <%= robot_exclusion_tag %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/show.api.rsb --- a/app/views/issues/show.api.rsb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/issues/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -9,7 +9,7 @@ api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil? api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil? api.parent(:id => @issue.parent_id) unless @issue.parent.nil? - + api.subject @issue.subject api.description @issue.description api.start_date @issue.start_date @@ -17,20 +17,26 @@ api.done_ratio @issue.done_ratio api.estimated_hours @issue.estimated_hours api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project) - + render_api_custom_values @issue.custom_field_values, api - + api.created_on @issue.created_on api.updated_on @issue.updated_on - + render_api_issue_children(@issue, api) if include_in_api_response?('children') - + + api.array :attachments do + @issue.attachments.each do |attachment| + render_api_attachment(attachment, api) + end + end if include_in_api_response?('attachments') + api.array :relations do @relations.each do |relation| - api.relation(:id => relation.id, :issue_id => relation.other_issue(@issue).id, :relation_type => relation.relation_type_for(@issue), :delay => relation.delay) + api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay) end end if include_in_api_response?('relations') && @relations.present? - + api.array :changesets do @issue.changesets.each do |changeset| api.changeset :revision => changeset.revision do @@ -40,7 +46,7 @@ end end end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project) - + api.array :journals do @issue.journals.each do |journal| api.journal :id => journal.id do diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/issues/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,137 @@ +<%= render :partial => 'action_menu' %> + +

    <%= issue_heading(@issue) %>

    + +
    + <%= avatar(@issue.author, :size => "50") %> + +
    +<%= render_issue_subject_with_tree(@issue) %> +
    +

    + <%= authoring @issue.created_on, @issue.author %>. + <% if @issue.created_on != @issue.updated_on %> + <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>. + <% end %> +

    + + + + + + + + + + + + + + + + + <% if User.current.allowed_to?(:view_time_entries, @project) %> + + + <% end %> + + + + <% if @issue.estimated_hours %> + + <% end %> + +<%= render_custom_fields_rows(@issue) %> +<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> +
    <%=l(:field_status)%>:<%= h(@issue.status.name) %><%=l(:field_start_date)%>:<%= format_date(@issue.start_date) %>
    <%=l(:field_priority)%>:<%= h(@issue.priority.name) %><%=l(:field_due_date)%>:<%= format_date(@issue.due_date) %>
    <%=l(:field_assigned_to)%>:<%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %><%=l(:field_done_ratio)%>:<%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %>
    <%=l(:field_category)%>:<%=h(@issue.category ? @issue.category.name : "-") %><%=l(:label_spent_time)%>:<%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %>
    <%=l(:field_fixed_version)%>:<%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %><%=l(:field_estimated_hours)%>:<%= l_hours(@issue.estimated_hours) %>
    + +<% if @issue.description? || @issue.attachments.any? -%> +
    +<% if @issue.description? %> +
    + <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %> +
    + +

    <%=l(:field_description)%>

    +
    + <%= textilizable @issue, :description, :attachments => @issue.attachments %> +
    +<% end %> +<%= link_to_attachments @issue %> +<% end -%> + +<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> + +<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> +
    +
    +
    + <%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %> +
    +

    <%=l(:label_subtask_plural)%>

    +<%= render_descendants_tree(@issue) unless @issue.leaf? %> +
    +<% end %> + +<% if @relations.present? || User.current.allowed_to?(:manage_issue_relations, @project) %> +
    +
    +<%= render :partial => 'relations' %> +
    +<% end %> + +
    + +<% if @changesets.present? %> +
    +

    <%=l(:label_associated_revisions)%>

    +<%= render :partial => 'changesets', :locals => { :changesets => @changesets} %> +
    +<% end %> + +<% if @journals.present? %> +
    +

    <%=l(:label_history)%>

    +<%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %> +
    +<% end %> + + +
    +<%= render :partial => 'action_menu' %> + +
    +<% if authorize_for('issues', 'edit') %> + +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> + <%= f.link_to 'PDF' %> +<% end %> + +<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> + + <% if User.current.allowed_to?(:add_issue_watchers, @project) || + (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %> +
    + <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %> +
    + <% end %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> + <%= stylesheet_link_tag 'scm' %> + <%= javascript_include_tag 'context_menu' %> + <%= stylesheet_link_tag 'context_menu' %> + <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %> +<% end %> + +<%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/issues/show.rhtml --- a/app/views/issues/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -<%= render :partial => 'action_menu' %> - -

    <%= issue_heading(@issue) %>

    - -
    - <%= avatar(@issue.author, :size => "50") %> - -
    -<%= render_issue_subject_with_tree(@issue) %> -
    -

    - <%= authoring @issue.created_on, @issue.author %>. - <% if @issue.created_on != @issue.updated_on %> - <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>. - <% end %> -

    - - - - - - - - - - - - - - - - - <% if User.current.allowed_to?(:view_time_entries, @project) %> - - - <% end %> - - - - <% if @issue.estimated_hours %> - - <% end %> - -<%= render_custom_fields_rows(@issue) %> -<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> -
    <%=l(:field_status)%>:<%= @issue.status.name %><%=l(:field_start_date)%>:<%= format_date(@issue.start_date) %>
    <%=l(:field_priority)%>:<%= @issue.priority.name %><%=l(:field_due_date)%>:<%= format_date(@issue.due_date) %>
    <%=l(:field_assigned_to)%>:<%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %><%=l(:field_done_ratio)%>:<%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %>
    <%=l(:field_category)%>:<%=h @issue.category ? @issue.category.name : "-" %><%=l(:label_spent_time)%>:<%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %>
    <%=l(:field_fixed_version)%>:<%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %><%=l(:field_estimated_hours)%>:<%= l_hours(@issue.estimated_hours) %>
    - -<% if @issue.description? || @issue.attachments.any? -%> -
    -<% if @issue.description? %> -
    - <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %> -
    - -

    <%=l(:field_description)%>

    -
    - <%= textilizable @issue, :description, :attachments => @issue.attachments %> -
    -<% end %> -<%= link_to_attachments @issue %> -<% end -%> - -<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> - -<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> -
    -
    -
    - <%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %> -
    -

    <%=l(:label_subtask_plural)%>

    -<%= render_descendants_tree(@issue) unless @issue.leaf? %> -
    -<% end %> - -<% if @relations.present? || User.current.allowed_to?(:manage_issue_relations, @project) %> -
    -
    -<%= render :partial => 'relations' %> -
    -<% end %> - -
    - -<% if @changesets.present? %> -
    -

    <%=l(:label_associated_revisions)%>

    -<%= render :partial => 'changesets', :locals => { :changesets => @changesets} %> -
    -<% end %> - -<% if @journals.present? %> -
    -

    <%=l(:label_history)%>

    -<%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %> -
    -<% end %> - - -
    -<%= render :partial => 'action_menu' %> - -
    -<% if authorize_for('issues', 'edit') %> - -<% end %> - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> - <%= f.link_to 'PDF' %> -<% end %> - -<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> - -<% content_for :sidebar do %> - <%= render :partial => 'issues/sidebar' %> - - <% if User.current.allowed_to?(:add_issue_watchers, @project) || - (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %> -
    - <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %> -
    - <% end %> -<% end %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> - <%= stylesheet_link_tag 'scm' %> - <%= javascript_include_tag 'context_menu' %> - <%= stylesheet_link_tag 'context_menu' %> - <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %> -<% end %> - -<%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/journals/_notes_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/journals/_notes_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %> + <%= label_tag "notes", l(:description_notes), :class => "hidden-for-sighted" %> + <%= text_area_tag :notes, @journal.notes, + :id => "journal_#{@journal.id}_notes", + :class => 'wiki-edit', + :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> + <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %> +

    <%= submit_tag l(:button_save) %> + <%= link_to_remote l(:label_preview), + { :url => preview_issue_path(:project_id => @project, :id => @journal.issue), + :method => 'post', + :update => "journal_#{@journal.id}_preview", + :with => "Form.serialize('journal-#{@journal.id}-form')", + :complete => "Element.scrollTo('journal_#{@journal.id}_preview')" + }, :accesskey => accesskey(:preview) %> + | + <%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " + + "Element.show('journal-#{@journal.id}-notes'); return false;" %>

    + +
    +<% end %> +<%= wikitoolbar_for "journal_#{@journal.id}_notes" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/journals/_notes_form.rhtml --- a/app/views/journals/_notes_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %> - <%= text_area_tag :notes, @journal.notes, - :id => "journal_#{@journal.id}_notes", - :class => 'wiki-edit', - :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> - <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %> -

    <%= submit_tag l(:button_save) %> - <%= link_to_remote l(:label_preview), - { :url => preview_issue_path(:project_id => @project, :id => @journal.issue), - :method => 'post', - :update => "journal_#{@journal.id}_preview", - :with => "Form.serialize('journal-#{@journal.id}-form')", - :complete => "Element.scrollTo('journal_#{@journal.id}_preview')" - }, :accesskey => accesskey(:preview) %> - | - <%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " + - "Element.show('journal-#{@journal.id}-notes'); return false;" %>

    - -
    -<% end %> -<%= wikitoolbar_for "journal_#{@journal.id}_notes" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/journals/index.builder --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/journals/index.builder Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do + xml.title @title + xml.link "rel" => "self", "href" => url_for(:format => 'atom', :key => User.current.rss_key, :only_path => false) + xml.link "rel" => "alternate", "href" => home_url(:only_path => false) + xml.id url_for(:controller => 'welcome', :only_path => false) + xml.updated((@journals.first ? @journals.first.event_datetime : Time.now).xmlschema) + xml.author { xml.name "#{Setting.app_title}" } + @journals.each do |change| + issue = change.issue + xml.entry do + xml.title "#{issue.project.name} - #{issue.tracker.name} ##{issue.id}: #{issue.subject}" + xml.link "rel" => "alternate", "href" => url_for(:controller => 'issues' , :action => 'show', :id => issue, :only_path => false) + xml.id url_for(:controller => 'issues' , :action => 'show', :id => issue, :journal_id => change, :only_path => false) + xml.updated change.created_on.xmlschema + xml.author do + xml.name change.user.name + xml.email(change.user.mail) if change.user.is_a?(User) && !change.user.mail.blank? && !change.user.pref.hide_mail + end + xml.content "type" => "html" do + xml.text! '
      ' + change.details.each do |detail| + xml.text! '
    • ' + show_detail(detail, false) + '
    • ' + end + xml.text! '
    ' + xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank? + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/journals/index.rxml --- a/app/views/journals/index.rxml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -xml.instruct! -xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do - xml.title @title - xml.link "rel" => "self", "href" => url_for(:format => 'atom', :key => User.current.rss_key, :only_path => false) - xml.link "rel" => "alternate", "href" => home_url(:only_path => false) - xml.id url_for(:controller => 'welcome', :only_path => false) - xml.updated((@journals.first ? @journals.first.event_datetime : Time.now).xmlschema) - xml.author { xml.name "#{Setting.app_title}" } - @journals.each do |change| - issue = change.issue - xml.entry do - xml.title "#{issue.project.name} - #{issue.tracker.name} ##{issue.id}: #{issue.subject}" - xml.link "rel" => "alternate", "href" => url_for(:controller => 'issues' , :action => 'show', :id => issue, :only_path => false) - xml.id url_for(:controller => 'issues' , :action => 'show', :id => issue, :journal_id => change, :only_path => false) - xml.updated change.created_on.xmlschema - xml.author do - xml.name change.user.name - xml.email(change.user.mail) if change.user.is_a?(User) && !change.user.mail.blank? && !change.user.pref.hide_mail - end - xml.content "type" => "html" do - xml.text! '
      ' - change.details.each do |detail| - xml.text! '
    • ' + show_detail(detail, false) + '
    • ' - end - xml.text! '
    ' - xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank? - end - end - end -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/admin.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/layouts/admin.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<% unless controller_name == 'admin' && action_name == 'index' %> + <% content_for :sidebar do %> +

    <%=l(:label_administration)%>

    + <%= render :partial => 'admin/menu' %> + <% end %> +<% end %> + +<%= render :file => "layouts/base" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/admin.rhtml --- a/app/views/layouts/admin.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -<% unless controller_name == 'admin' && action_name == 'index' %> - <% content_for :sidebar do %> -

    <%=l(:label_administration)%>

    - <%= render :partial => 'admin/menu' %> - <% end %> -<% end %> - -<%= render :file => "layouts/base" %> diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/base.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/layouts/base.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,106 @@ + + + + +<%=h html_title %> + + +<%= csrf_meta_tag %> +<%= favicon %> +<%= stylesheet_link_tag 'application', :media => 'all' %> +<%= stylesheet_platform_font_tag %> +<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> +<%= javascript_heads %> +<%= heads_for_theme %> + +<%= call_hook :view_layouts_base_html_head %> + +<%= yield :header_tags -%> + + +
    +
    +
    +
    + <%= render_menu :account_menu -%> +
    + <%= content_tag( + 'div', + "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, + :id => 'loggedas') if User.current.logged? %> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> +
    + +<%= tag('div', {:id => 'header', :class => (display_main_menu?(@project) ? 'header-project' : 'header-general')}, true) %> + <% if User.current.logged? || !Setting.login_required? %> + +
    + + +
    + <%= render_project_jump_box %> +
    +
    + <% end %> + + <% unless page_header_title[1].empty? %> +

    <%= page_header_title[1] %>

    + <% end %> + +

    + style="margin-top: 0px; " + <% end %> + ><% if display_main_menu?(@project) %> + <%= link_to_project(@project) %> + <% else %> + <%= page_header_title[0] %> + <% end %> +

    + + <% if display_main_menu?(@project) %> + + <% end %> +
    + +<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %> + + +
    + <%= render_flash_messages %> + <%= yield %> + <%= call_hook :view_layouts_base_content %> +
    +
    +
    + + + + + + +<%= call_hook :view_layouts_base_body_bottom %> + + diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/base.rhtml --- a/app/views/layouts/base.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ - - - - -<%=h html_title %> - - -<%= csrf_meta_tag %> -<%= favicon %> -<%= stylesheet_link_tag 'application', :media => 'all' %> -<%= stylesheet_platform_font_tag %> -<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> -<%= javascript_heads %> -<%= heads_for_theme %> - -<%= call_hook :view_layouts_base_html_head %> - -<%= yield :header_tags -%> - - -
    -
    -
    -
    - <%= render_menu :account_menu -%> -
    - <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}", :id => 'loggedas') if User.current.logged? %> - <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> -
    - -<%= tag('div', {:id => 'header', :class => (display_main_menu?(@project) ? 'header-project' : 'header-general')}, true) %> - <% if User.current.logged? || !Setting.login_required? %> - -
    - - -
    - <%= render_project_jump_box %> -
    -
    - <% end %> - - <% unless page_header_title[1].empty? %> -

    <%= page_header_title[1] %>

    - <% end %> - -

    - style="margin-top: 0px; " - <% end %> - ><% if display_main_menu?(@project) %> - <%= link_to_project(@project) %> - <% else %> - <%= page_header_title[0] %> - <% end %> -

    - - <% if display_main_menu?(@project) %> - - <% end %> -
    - -<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %> - - -
    - <%= render_flash_messages %> - <%= yield %> - <%= call_hook :view_layouts_base_content %> -
    -
    -
    - - - - - - -<%= call_hook :view_layouts_base_body_bottom %> - - diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/mailer.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/layouts/mailer.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ + + + + + +<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_header) %> +<%= yield %> +
    +<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer) %> + + diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/mailer.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/layouts/mailer.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= Setting.emails_header %> +<%= yield %> +-- +<%= Setting.emails_footer %> diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/mailer.text.html.erb --- a/app/views/layouts/mailer.text.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ - - - - - -<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_header) %> -<%= yield %> -
    -<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer) %> - - diff -r 487d96eac004 -r 5e80956cc792 app/views/layouts/mailer.text.plain.erb --- a/app/views/layouts/mailer.text.plain.erb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<%= Setting.emails_header %> -<%= yield %> --- -<%= Setting.emails_footer %> diff -r 487d96eac004 -r 5e80956cc792 app/views/ldap_auth_sources/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/ldap_auth_sources/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,44 @@ +<%= error_messages_for 'auth_source' %> + +
    + +

    +<%= text_field 'auth_source', 'name' %>

    + +

    +<%= text_field 'auth_source', 'host' %>

    + +

    +<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls' %> LDAPS

    + +

    +<%= text_field 'auth_source', 'account' %>

    + +

    +<%= password_field 'auth_source', 'account_password', :name => 'ignore', + :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)), + :onfocus => "this.value=''; this.name='auth_source[account_password]';", + :onchange => "this.name='auth_source[account_password]';" %>

    + +

    +<%= text_field 'auth_source', 'base_dn', :size => 60 %>

    + +

    +<%= check_box 'auth_source', 'onthefly_register' %>

    +
    + +
    <%=l(:label_attribute_plural)%> +

    +<%= text_field 'auth_source', 'attr_login', :size => 20 %>

    + +

    +<%= text_field 'auth_source', 'attr_firstname', :size => 20 %>

    + +

    +<%= text_field 'auth_source', 'attr_lastname', :size => 20 %>

    + +

    +<%= text_field 'auth_source', 'attr_mail', :size => 20 %>

    +
    + + diff -r 487d96eac004 -r 5e80956cc792 app/views/ldap_auth_sources/_form.rhtml --- a/app/views/ldap_auth_sources/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -<%= error_messages_for 'auth_source' %> - -
    - -

    -<%= text_field 'auth_source', 'name' %>

    - -

    -<%= text_field 'auth_source', 'host' %>

    - -

    -<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls' %> LDAPS

    - -

    -<%= text_field 'auth_source', 'account' %>

    - -

    -<%= password_field 'auth_source', 'account_password', :name => 'ignore', - :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)), - :onfocus => "this.value=''; this.name='auth_source[account_password]';", - :onchange => "this.name='auth_source[account_password]';" %>

    - -

    -<%= text_field 'auth_source', 'base_dn', :size => 60 %>

    - -

    -<%= check_box 'auth_source', 'onthefly_register' %>

    -
    - -
    <%=l(:label_attribute_plural)%> -

    -<%= text_field 'auth_source', 'attr_login', :size => 20 %>

    - -

    -<%= text_field 'auth_source', 'attr_firstname', :size => 20 %>

    - -

    -<%= text_field 'auth_source', 'attr_lastname', :size => 20 %>

    - -

    -<%= text_field 'auth_source', 'attr_mail', :size => 20 %>

    -
    - - diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/_issue.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/_issue.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %>

    + +
      +
    • <%=l(:field_author)%>: <%=h issue.author %>
    • +
    • <%=l(:field_status)%>: <%=h issue.status %>
    • +
    • <%=l(:field_priority)%>: <%=h issue.priority %>
    • +
    • <%=l(:field_assigned_to)%>: <%=h issue.assigned_to %>
    • +
    • <%=l(:field_category)%>: <%=h issue.category %>
    • +
    • <%=l(:field_fixed_version)%>: <%=h issue.fixed_version %>
    • +<% issue.custom_field_values.each do |c| %> +
    • <%=h c.custom_field.name %>: <%=h show_value(c) %>
    • +<% end %> +
    + +<%= textilizable(issue, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/_issue.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/_issue.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +<%= "#{issue.tracker.name} ##{issue.id}: #{issue.subject}" %> +<%= issue_url %> + +<%=l(:field_author)%>: <%= issue.author %> +<%=l(:field_status)%>: <%= issue.status %> +<%=l(:field_priority)%>: <%= issue.priority %> +<%=l(:field_assigned_to)%>: <%= issue.assigned_to %> +<%=l(:field_category)%>: <%= issue.category %> +<%=l(:field_fixed_version)%>: <%= issue.fixed_version %> +<% issue.custom_field_values.each do |c| %><%= c.custom_field.name %>: <%= show_value(c) %> +<% end %> + +<%= issue.description %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/_issue_text_html.rhtml --- a/app/views/mailer/_issue_text_html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -

    <%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %>

    - -
      -
    • <%=l(:field_author)%>: <%=h issue.author %>
    • -
    • <%=l(:field_status)%>: <%=h issue.status %>
    • -
    • <%=l(:field_priority)%>: <%=h issue.priority %>
    • -
    • <%=l(:field_assigned_to)%>: <%=h issue.assigned_to %>
    • -
    • <%=l(:field_category)%>: <%=h issue.category %>
    • -
    • <%=l(:field_fixed_version)%>: <%=h issue.fixed_version %>
    • -<% issue.custom_field_values.each do |c| %> -
    • <%=h c.custom_field.name %>: <%=h show_value(c) %>
    • -<% end %> -
    - -<%= textilizable(issue, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/_issue_text_plain.rhtml --- a/app/views/mailer/_issue_text_plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -<%= "#{issue.tracker.name} ##{issue.id}: #{issue.subject}" %> -<%= issue_url %> - -<%=l(:field_author)%>: <%= issue.author %> -<%=l(:field_status)%>: <%= issue.status %> -<%=l(:field_priority)%>: <%= issue.priority %> -<%=l(:field_assigned_to)%>: <%= issue.assigned_to %> -<%=l(:field_category)%>: <%= issue.category %> -<%=l(:field_fixed_version)%>: <%= issue.fixed_version %> -<% issue.custom_field_values.each do |c| %><%= c.custom_field.name %>: <%= show_value(c) %> -<% end %> - -<%= issue.description %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_activated.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/account_activated.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

    <%= l(:notice_account_activated) %>

    +

    <%= l(:label_login) %>: <%= link_to h(@login_url), @login_url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_activated.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/account_activated.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +<%= l(:notice_account_activated) %> +<%= l(:label_login) %>: <%= @login_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_activated.text.html.rhtml --- a/app/views/mailer/account_activated.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -

    <%= l(:notice_account_activated) %>

    -

    <%= l(:label_login) %>: <%= link_to @login_url, @login_url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_activated.text.plain.rhtml --- a/app/views/mailer/account_activated.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -<%= l(:notice_account_activated) %> -<%= l(:label_login) %>: <%= @login_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_activation_request.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/account_activation_request.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

    <%= l(:mail_body_account_activation_request, h(@user.login)) %>

    +

    <%= link_to h(@url), @url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_activation_request.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/account_activation_request.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +<%= l(:mail_body_account_activation_request, @user.login) %> +<%= @url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_information.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/account_information.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +<% if @user.auth_source %> +

    <%= l(:mail_body_account_information_external, h(@user.auth_source.name)) %>

    +<% else %> +

    <%= l(:mail_body_account_information) %>:

    +
      +
    • <%= l(:field_login) %>: <%=h @user.login %>
    • +
    • <%= l(:field_password) %>: <%=h @password %>
    • +
    +<% end %> + +

    <%= l(:label_login) %>: <%= auto_link(@login_url) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_information.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/account_information.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +<% if @user.auth_source %><%= l(:mail_body_account_information_external, @user.auth_source.name) %> +<% else %><%= l(:mail_body_account_information) %>: +* <%= l(:field_login) %>: <%= @user.login %> +* <%= l(:field_password) %>: <%= @password %> +<% end %> +<%= l(:label_login) %>: <%= @login_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_information.text.html.rhtml --- a/app/views/mailer/account_information.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -<% if @user.auth_source %> -

    <%= l(:mail_body_account_information_external, h(@user.auth_source.name)) %>

    -<% else %> -

    <%= l(:mail_body_account_information) %>:

    -
      -
    • <%= l(:field_login) %>: <%=h @user.login %>
    • -
    • <%= l(:field_password) %>: <%=h @password %>
    • -
    -<% end %> - -

    <%= l(:label_login) %>: <%= auto_link(@login_url) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/account_information.text.plain.rhtml --- a/app/views/mailer/account_information.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -<% if @user.auth_source %><%= l(:mail_body_account_information_external, @user.auth_source.name) %> -<% else %><%= l(:mail_body_account_information) %>: -* <%= l(:field_login) %>: <%= @user.login %> -* <%= l(:field_password) %>: <%= @password %> -<% end %> -<%= l(:label_login) %>: <%= @login_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/attachments_added.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/attachments_added.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +<%= link_to h(@added_to), @added_to_url %>
    + +
      <% @attachments.each do |attachment | %> +
    • <%=h attachment.filename %>
    • +<% end %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/attachments_added.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/attachments_added.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= @added_to %><% @attachments.each do |attachment | %> +- <%= attachment.filename %><% end %> + +<%= @added_to_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/attachments_added.text.html.rhtml --- a/app/views/mailer/attachments_added.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -<%= link_to @added_to, @added_to_url %>
    - -
      <% @attachments.each do |attachment | %> -
    • <%=h attachment.filename %>
    • -<% end %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/attachments_added.text.plain.rhtml --- a/app/views/mailer/attachments_added.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<%= @added_to %><% @attachments.each do |attachment | %> -- <%= attachment.filename %><% end %> - -<%= @added_to_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/document_added.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/document_added.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +<%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)
    +
    +<%= textilizable(@document, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/document_added.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/document_added.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= @document.title %> (<%= @document.category.name %>) +<%= @document_url %> + +<%= @document.description %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/document_added.text.html.rhtml --- a/app/views/mailer/document_added.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -<%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)
    -
    -<%= textilizable(@document, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/document_added.text.plain.rhtml --- a/app/views/mailer/document_added.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<%= @document.title %> (<%= @document.category.name %>) -<%= @document_url %> - -<%= @document.description %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_add.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/issue_add.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %> +
    +<%= render :partial => "issue.html.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_add.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/issue_add.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %> + +---------------------------------------- +<%= render :partial => "issue.text.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_add.text.html.rhtml --- a/app/views/mailer/issue_add.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %> -
    -<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_add.text.plain.rhtml --- a/app/views/mailer/issue_add.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %> - ----------------------------------------- -<%= render :partial => "issue_text_plain", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/issue_edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %> + +
      +<% for detail in @journal.details %> +
    • <%= show_detail(detail, true) %>
    • +<% end %> +
    + +<%= textilizable(@journal, :notes, :only_path => false) %> +
    +<%= render :partial => "issue.html.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_edit.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/issue_edit.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> + +<% for detail in @journal.details -%> +<%= show_detail(detail, true) %> +<% end -%> + +<%= @journal.notes if @journal.notes? %> +---------------------------------------- +<%= render :partial => "issue.text.erb", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_edit.text.html.rhtml --- a/app/views/mailer/issue_edit.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %> - -
      -<% for detail in @journal.details %> -
    • <%= show_detail(detail, true) %>
    • -<% end %> -
    - -<%= textilizable(@journal, :notes, :only_path => false) %> -
    -<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/issue_edit.text.plain.rhtml --- a/app/views/mailer/issue_edit.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> - -<% for detail in @journal.details -%> -<%= show_detail(detail, true) %> -<% end -%> - -<%= @journal.notes if @journal.notes? %> ----------------------------------------- -<%= render :partial => "issue_text_plain", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/lost_password.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/lost_password.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +

    <%= l(:mail_body_lost_password) %>
    +<%= auto_link(@url) %>

    + +

    <%= l(:field_login) %>: <%=h @token.user.login %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/lost_password.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/lost_password.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= l(:mail_body_lost_password) %> +<%= @url %> + +<%= l(:field_login) %>: <%= @token.user.login %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/lost_password.text.html.rhtml --- a/app/views/mailer/lost_password.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -

    <%= l(:mail_body_lost_password) %>
    -<%= auto_link(@url) %>

    - -

    <%= l(:field_login) %>: <%=h @token.user.login %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/lost_password.text.plain.rhtml --- a/app/views/mailer/lost_password.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<%= l(:mail_body_lost_password) %> -<%= @url %> - -<%= l(:field_login) %>: <%= @token.user.login %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/message_posted.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/message_posted.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +

    <%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %>

    +<%=h @message.author %> + +<%= textilizable(@message, :content, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/message_posted.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/message_posted.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<%= @message_url %> +<%= @message.author %> + +<%= @message.content %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/message_posted.text.html.rhtml --- a/app/views/mailer/message_posted.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -

    <%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %>

    -<%=h @message.author %> - -<%= textilizable(@message, :content, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/message_posted.text.plain.rhtml --- a/app/views/mailer/message_posted.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<%= @message_url %> -<%= @message.author %> - -<%= @message.content %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_added.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/news_added.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +

    <%= link_to(h(@news.title), @news_url) %>

    +<%=h @news.author.name %> + +<%= textilizable(@news, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_added.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/news_added.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +<%= @news.title %> +<%= @news_url %> +<%= @news.author.name %> + +<%= @news.description %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_added.text.html.rhtml --- a/app/views/mailer/news_added.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -

    <%= link_to(h(@news.title), @news_url) %>

    -<%=h @news.author.name %> - -<%= textilizable(@news, :description, :only_path => false) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_added.text.plain.rhtml --- a/app/views/mailer/news_added.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -<%= @news.title %> -<%= @news_url %> -<%= @news.author.name %> - -<%= @news.description %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_comment_added.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/news_comment_added.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%= link_to(h(@news.title), @news_url) %>

    + +

    <%= l(:text_user_wrote, :value => h(@comment.author)) %>

    + +<%= textilizable @comment, :comments, :only_path => false %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_comment_added.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/news_comment_added.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +<%= @news.title %> +<%= @news_url %> + +<%= l(:text_user_wrote, :value => @comment.author) %> + +<%= @comment.comments %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_comment_added.text.html.rhtml --- a/app/views/mailer/news_comment_added.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -

    <%= link_to(h(@news.title), @news_url) %>

    - -

    <%= l(:text_user_wrote, :value => h(@comment.author)) %>

    - -<%= textilizable @comment, :comments, :only_path => false %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/news_comment_added.text.plain.rhtml --- a/app/views/mailer/news_comment_added.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -<%= @news.title %> -<%= @news_url %> - -<%= l(:text_user_wrote, :value => @comment.author) %> - -<%= @comment.comments %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/register.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/register.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

    <%= l(:mail_body_register) %>
    +<%= auto_link(@url) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/register.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/register.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +<%= l(:mail_body_register) %> +<%= @url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/register.text.html.rhtml --- a/app/views/mailer/register.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -

    <%= l(:mail_body_register) %>
    -<%= auto_link(@url) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/register.text.plain.rhtml --- a/app/views/mailer/register.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -<%= l(:mail_body_register) %> -<%= @url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/reminder.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/reminder.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>

    + +
      +<% @issues.each do |issue| -%> +
    • <%=h issue.project %> - <%=link_to(h("#{issue.tracker} ##{issue.id}"), :controller => 'issues', :action => 'show', :id => issue, :only_path => false)%>: <%=h issue.subject %>
    • +<% end -%> +
    + +

    <%= link_to l(:label_issue_view_all), @issues_url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/reminder.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/reminder.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +<%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>: + +<% @issues.each do |issue| -%> +* <%= "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %> +<% end -%> + +<%= @issues_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/reminder.text.html.rhtml --- a/app/views/mailer/reminder.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -

    <%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>

    - -
      -<% @issues.each do |issue| -%> -
    • <%=h issue.project %> - <%=link_to("#{issue.tracker} ##{issue.id}", :controller => 'issues', :action => 'show', :id => issue, :only_path => false)%>: <%=h issue.subject %>
    • -<% end -%> -
    - -

    <%= link_to l(:label_issue_view_all), @issues_url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/reminder.text.plain.rhtml --- a/app/views/mailer/reminder.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -<%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>: - -<% @issues.each do |issue| -%> -* <%= "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %> -<% end -%> - -<%= @issues_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/test.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/test.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +

    This is a test email sent by Redmine.
    +Redmine URL: <%= auto_link(@url) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/test.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/test.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,2 @@ +This is a test email sent by Redmine. +Redmine URL: <%= @url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/test.text.html.rhtml --- a/app/views/mailer/test.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -

    This is a test email sent by Redmine.
    -Redmine URL: <%= auto_link(@url) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/test.text.plain.rhtml --- a/app/views/mailer/test.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -This is a test email sent by Redmine. -Redmine URL: <%= @url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_added.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/wiki_content_added.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +

    <%= l(:mail_body_wiki_content_added, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), + :author => h(@wiki_content.author)) %>
    +<%=h @wiki_content.comments %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_added.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/wiki_content_added.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +<%= l(:mail_body_wiki_content_added, :id => h(@wiki_content.page.pretty_title), + :author => h(@wiki_content.author)) %> +<%= @wiki_content.comments %> + +<%= @wiki_content_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_added.text.html.rhtml --- a/app/views/mailer/wiki_content_added.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -

    <%= l(:mail_body_wiki_content_added, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), - :author => h(@wiki_content.author)) %>
    -<%=h @wiki_content.comments %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_added.text.plain.rhtml --- a/app/views/mailer/wiki_content_added.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -<%= l(:mail_body_wiki_content_added, :id => h(@wiki_content.page.pretty_title), - :author => h(@wiki_content.author)) %> -<%= @wiki_content.comments %> - -<%= @wiki_content_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_updated.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/wiki_content_updated.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:mail_body_wiki_content_updated, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), + :author => h(@wiki_content.author)) %>
    +<%=h @wiki_content.comments %>

    + +

    <%= l(:label_view_diff) %>:
    +<%= link_to h(@wiki_diff_url), @wiki_diff_url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_updated.text.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/mailer/wiki_content_updated.text.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<%= l(:mail_body_wiki_content_updated, :id => h(@wiki_content.page.pretty_title), + :author => h(@wiki_content.author)) %> +<%= @wiki_content.comments %> + +<%= @wiki_content.page.pretty_title %>: +<%= @wiki_content_url %> +<%= l(:label_view_diff) %>: +<%= @wiki_diff_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_updated.text.html.rhtml --- a/app/views/mailer/wiki_content_updated.text.html.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= l(:mail_body_wiki_content_updated, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), - :author => h(@wiki_content.author)) %>
    -<%=h @wiki_content.comments %>

    - -

    <%= l(:label_view_diff) %>:
    -<%= link_to @wiki_diff_url, @wiki_diff_url %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/mailer/wiki_content_updated.text.plain.rhtml --- a/app/views/mailer/wiki_content_updated.text.plain.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -<%= l(:mail_body_wiki_content_updated, :id => h(@wiki_content.page.pretty_title), - :author => h(@wiki_content.author)) %> -<%= @wiki_content.comments %> - -<%= @wiki_content.page.pretty_title %>: -<%= @wiki_content_url %> -<%= l(:label_view_diff) %>: -<%= @wiki_diff_url %> diff -r 487d96eac004 -r 5e80956cc792 app/views/members/autocomplete_for_member.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/members/autocomplete_for_member.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +<% if params[:q] && params[:q].length > 1 %> +<%= principals_check_box_tags 'member[user_ids][]', @principals %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/members/autocomplete_for_member.rhtml --- a/app/views/members/autocomplete_for_member.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -<% if params[:q] && params[:q].length > 1 %> -<%= principals_check_box_tags 'member[user_ids][]', @principals %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/messages/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +<%= error_messages_for 'message' %> +<% replying ||= false %> + +
    + +


    +<%= f.text_field :subject, :size => 120, :id => "message_subject" %> + +<% if !replying && User.current.allowed_to?(:edit_messages, @project) %> + + +<% end %> +

    + +<% if !replying && !@message.new_record? && User.current.allowed_to?(:edit_messages, @project) %> +


    + <%= f.select :board_id, @project.boards.collect {|b| [b.name, b.id]} %>

    +<% end %> + +

    +<%= label_tag "message_content", l(:description_message_content), :class => "hidden-for-sighted" %> +<%= f.text_area :content, :cols => 80, :rows => 15, :class => 'wiki-edit', :id => 'message_content' %>

    +<%= wikitoolbar_for 'message_content' %> + + +

    <%= l(:label_attachment_plural) %>
    +<%= render :partial => 'attachments/form' %>

    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/_form.rhtml --- a/app/views/messages/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -<%= error_messages_for 'message' %> -<% replying ||= false %> - -
    - -


    -<%= f.text_field :subject, :size => 120 %> - -<% if !replying && User.current.allowed_to?(:edit_messages, @project) %> - - -<% end %> -

    - -<% if !replying && !@message.new_record? && User.current.allowed_to?(:edit_messages, @project) %> -


    - <%= f.select :board_id, @project.boards.collect {|b| [b.name, b.id]} %>

    -<% end %> - -

    <%= f.text_area :content, :cols => 80, :rows => 15, :class => 'wiki-edit', :id => 'message_content' %>

    -<%= wikitoolbar_for 'message_content' %> - - -

    <%= l(:label_attachment_plural) %>
    -<%= render :partial => 'attachments/form' %>

    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/messages/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +

    <%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%=h @message.subject %>

    + +<% form_for :message, @message, :url => {:action => 'edit'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f, :replying => !@message.parent.nil?} %> + <%= submit_tag l(:button_save) %> + <%= link_to_remote l(:label_preview), + { :url => { :controller => 'messages', :action => 'preview', :board_id => @board }, + :method => 'post', + :update => 'preview', + :with => "Form.serialize('message-form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> +<% end %> +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/edit.rhtml --- a/app/views/messages/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -

    <%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%=h @message.subject %>

    - -<% form_for :message, @message, :url => {:action => 'edit'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> - <%= render :partial => 'form', :locals => {:f => f, :replying => !@message.parent.nil?} %> - <%= submit_tag l(:button_save) %> - <%= link_to_remote l(:label_preview), - { :url => { :controller => 'messages', :action => 'preview', :board_id => @board }, - :method => 'post', - :update => 'preview', - :with => "Form.serialize('message-form')", - :complete => "Element.scrollTo('preview')" - }, :accesskey => accesskey(:preview) %> -<% end %> -
    - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/messages/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +

    <%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%= l(:label_message_new) %>

    + +<% form_for :message, @message, :url => {:action => 'new'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> + <%= link_to_remote l(:label_preview), + { :url => { :controller => 'messages', :action => 'preview', :board_id => @board }, + :method => 'post', + :update => 'preview', + :with => "Form.serialize('message-form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %> +<% end %> + +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/new.rhtml --- a/app/views/messages/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -

    <%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%= l(:label_message_new) %>

    - -<% form_for :message, @message, :url => {:action => 'new'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> - <%= render :partial => 'form', :locals => {:f => f} %> - <%= submit_tag l(:button_create) %> - <%= link_to_remote l(:label_preview), - { :url => { :controller => 'messages', :action => 'preview', :board_id => @board }, - :method => 'post', - :update => 'preview', - :with => "Form.serialize('message-form')", - :complete => "Element.scrollTo('preview')" - }, :accesskey => accesskey(:preview) %> -<% end %> - -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/messages/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,66 @@ +<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}), + link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %> + +
    + <%= watcher_tag(@topic, User.current) %> + <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment') unless @topic.locked? %> + <%= link_to(l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit') if @message.editable_by?(User.current) %> + <%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %> +
    + +

    <%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %>

    + +
    +

    <%= authoring @topic.created_on, @topic.author %>

    +
    +<%= textilizable(@topic.content, :attachments => @topic.attachments) %> +
    +<%= link_to_attachments @topic, :author => false %> +
    +
    + +<% unless @replies.empty? %> +

    <%= l(:label_reply_plural) %> (<%= @reply_count %>)

    +<% @replies.each do |message| %> +
    "> +
    + <%= link_to_remote_if_authorized(image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote)) unless @topic.locked? %> + <%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %> + <%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %> +
    +

    + <%= avatar(message.author, :size => "24") %> + <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :r => message, :anchor => "message-#{message.id}" } %> + - + <%= authoring message.created_on, message.author %> +

    +
    <%= textilizable message, :content, :attachments => message.attachments %>
    + <%= link_to_attachments message, :author => false %> +
    +<% end %> +

    <%= pagination_links_full @reply_pages, @reply_count, :per_page_links => false %>

    +<% end %> + +<% if !@topic.locked? && authorize_for('messages', 'reply') %> +

    <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>

    + +<% end %> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% html_title @topic.subject %> diff -r 487d96eac004 -r 5e80956cc792 app/views/messages/show.rhtml --- a/app/views/messages/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}), - link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %> - -
    - <%= watcher_tag(@topic, User.current) %> - <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment') unless @topic.locked? %> - <%= link_to(l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit') if @message.editable_by?(User.current) %> - <%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %> -
    - -

    <%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %>

    - -
    -

    <%= authoring @topic.created_on, @topic.author %>

    -
    -<%= textilizable(@topic.content, :attachments => @topic.attachments) %> -
    -<%= link_to_attachments @topic, :author => false %> -
    -
    - -<% unless @replies.empty? %> -

    <%= l(:label_reply_plural) %> (<%= @reply_count %>)

    -<% @replies.each do |message| %> -
    "> -
    - <%= link_to_remote_if_authorized(image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote)) unless @topic.locked? %> - <%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %> - <%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %> -
    -

    - <%= avatar(message.author, :size => "24") %> - <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :r => message, :anchor => "message-#{message.id}" } %> - - - <%= authoring message.created_on, message.author %> -

    -
    <%= textilizable message, :content, :attachments => message.attachments %>
    - <%= link_to_attachments message, :author => false %> -
    -<% end %> -

    <%= pagination_links_full @reply_pages, @reply_count, :per_page_links => false %>

    -<% end %> - -<% if !@topic.locked? && authorize_for('messages', 'reply') %> -

    <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>

    - -<% end %> - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> -<% end %> - -<% html_title h(@topic.subject) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/_block.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/_block.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +
    + +
    + <%= link_to_remote "", { + :url => { :action => "remove_block", :block => block_name }, + :complete => "removeBlock('block_#{block_name.dasherize}')" }, + :class => "close-icon" + %> +
    + +
    + <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/my/_block.rhtml --- a/app/views/my/_block.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -
    - -
    - <%= link_to_remote "", { - :url => { :action => "remove_block", :block => block_name }, - :complete => "removeBlock('block_#{block_name.dasherize}')" }, - :class => "close-icon" - %> -
    - -
    - <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %> -
    -
    \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/my/_sidebar.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/_sidebar.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +

    <%=l(:label_my_account)%>

    + +

    <%=l(:field_login)%>: <%= link_to_user(@user, :format => :username) %>
    +<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

    + + +

    <%= l(:label_feeds_access_key) %>

    + +

    +<% if @user.rss_token %> +<%= l(:label_feeds_access_key_created_on, distance_of_time_in_words(Time.now, @user.rss_token.created_on)) %> +<% else %> +<%= l(:label_missing_feeds_access_key) %> +<% end %> +(<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>) +

    + +<% if Setting.rest_api_enabled? %> +

    <%= l(:label_api_access_key) %>

    +
    + <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> +
    <%= h(@user.api_key) %>
    +
    +<%= javascript_tag("$('api-access-key').hide();") %> +

    +<% if @user.api_token %> +<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> +<% else %> +<%= l(:label_missing_api_access_key) %> +<% end %> +(<%= link_to l(:button_reset), {:action => 'reset_api_key'}, :method => :post %>) +

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/_sidebar.rhtml --- a/app/views/my/_sidebar.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -

    <%=l(:label_my_account)%>

    - -

    <%=l(:field_login)%>: <%= link_to_user(@user, :format => :username) %>
    -<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

    - - -

    <%= l(:label_feeds_access_key) %>

    - -

    -<% if @user.rss_token %> -<%= l(:label_feeds_access_key_created_on, distance_of_time_in_words(Time.now, @user.rss_token.created_on)) %> -<% else %> -<%= l(:label_missing_feeds_access_key) %> -<% end %> -(<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>) -

    - -<% if Setting.rest_api_enabled? %> -

    <%= l(:label_api_access_key) %>

    -
    - <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> -
    <%= h(@user.api_key) %>
    -
    -<%= javascript_tag("$('api-access-key').hide();") %> -

    -<% if @user.api_token %> -<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> -<% else %> -<%= l(:label_missing_api_access_key) %> -<% end %> -(<%= link_to l(:button_reset), {:action => 'reset_api_key'}, :method => :post %>) -

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/account.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/account.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,89 @@ +<%= javascript_include_tag "ssamr_institutions" %> + +
    +<%= link_to(l(:button_change_password), {:action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %> +<%= call_hook(:view_my_account_contextual, :user => @user)%> +
    + +

    <%=l(:label_my_account)%>

    +<%= error_messages_for 'user' %> + +<% form_for :user, @user, :url => { :action => "account" }, + :builder => TabularFormBuilder, + :lang => current_language, + :html => { :id => 'my_account_form' } do |f| %> + + +
    +
    + <%=l(:label_information_plural)%> +

    <%= f.text_field :firstname, :required => true %>

    +

    <%= f.text_field :lastname, :required => true %>

    +

    <%= f.text_field :mail, :required => true %>

    +

    <%= f.select :language, lang_options_for_select %>

    + <% if Setting.openid? %> +

    <%= f.text_field :identity_url %>

    + <% end %> + + <% @user.custom_field_values.select(&:editable?).each do |value| %> +

    <%= custom_field_tag_with_label :user, value %>

    + <% end %> + + <%= call_hook(:view_my_account, :user => @user, :form => f) %> +
    + +

    <%=l(:label_ssamr_details)%>

    +
    + <% fields_for :ssamr_user_details, :builder => TabularFormBuilder, :lang => current_language do |ssamr_user_detail| %> +

    + <%= ssamr_user_detail.text_area :description, :rows => 3, :cols => 25, :required => true, :class => 'wiki-edit' %> +

    + + +

    + + <%= ssamr_user_detail.radio_button :institution_type, true %> + <%= ssamr_user_detail.collection_select(:institution_id, Institution.find(:all, :order => "institutions.order"), :id, :name, {:selected => @selected_institution_id, :prompt => true} ).gsub('&', '&') %> + +

    + +

    + + <%= ssamr_user_detail.radio_button :institution_type, false %> Other: + <%= ssamr_user_detail.text_field :other_institution, :size => 19 %> + +

    + <% end %> +
    + + +<%= submit_tag l(:button_save) %> +
    + +
    +
    + <%=l(:field_mail_notification)%> + <%= render :partial => 'users/mail_notifications' %> +
    + +
    + <%=l(:label_preferences)%> + <%= render :partial => 'users/preferences' %> +
    + +
    +<% end %> + + + + + + + + + +<% content_for :sidebar do %> +<%= render :partial => 'sidebar' %> +<% end %> + +<% html_title(l(:label_my_account)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/account.rhtml --- a/app/views/my/account.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -<%= javascript_include_tag "ssamr_institutions" %> - -
    -<%= link_to(l(:button_change_password), :action => 'password') if @user.change_password_allowed? %> -<%= call_hook(:view_my_account_contextual, :user => @user)%> -
    -

    <%=l(:label_my_account)%>

    -<%= error_messages_for 'user' %> - -<% form_for :user, @user, :url => { :action => "account" }, - :builder => TabularFormBuilder, - :lang => current_language, - :html => { :id => 'my_account_form' } do |f| %> - - -
    -

    <%=l(:label_information_plural)%>

    -
    -

    <%= f.text_field :firstname, :required => true %>

    -

    <%= f.text_field :lastname, :required => true %>

    -

    <%= f.text_field :mail, :required => true %>

    -

    <%= f.select :language, lang_options_for_select %>

    -<% if Setting.openid? %> -

    <%= f.text_field :identity_url %>

    -<% end %> - -<% @user.custom_field_values.select(&:editable?).each do |value| %> -

    <%= custom_field_tag_with_label :user, value %>

    -<% end %> - -<%= call_hook(:view_my_account, :user => @user, :form => f) %> -
    - -

    <%=l(:label_ssamr_details)%>

    -
    - <% fields_for :ssamr_user_details, :builder => TabularFormBuilder, :lang => current_language do |ssamr_user_detail| %> -

    - <%= ssamr_user_detail.text_area :description, :rows => 3, :cols => 25, :required => true, :class => 'wiki-edit' %> -

    - - -

    - - <%= ssamr_user_detail.radio_button :institution_type, true %> - <%= ssamr_user_detail.collection_select(:institution_id, Institution.find(:all, :order => "institutions.order"), :id, :name, {:selected => @selected_institution_id, :prompt => true} ).gsub('&', '&') %> - -

    - -

    - - <%= ssamr_user_detail.radio_button :institution_type, false %> Other: - <%= ssamr_user_detail.text_field :other_institution, :size => 19 %> - -

    - <% end %> -
    - - -<%= submit_tag l(:button_save) %> -
    - -
    -

    <%=l(:field_mail_notification)%>

    -
    -<%= render :partial => 'users/mail_notifications' %> -
    - -

    <%=l(:label_preferences)%>

    -
    -<%= render :partial => 'users/preferences' %> -
    - -
    -<% end %> - - - - - - - - - -<% content_for :sidebar do %> -<%= render :partial => 'sidebar' %> -<% end %> - -<% html_title(l(:label_my_account)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_calendar.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_calendar.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%= l(:label_calendar) %>

    + +<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week) + calendar.events = Issue.visible.find :all, + :conditions => ["#{Issue.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", calendar.startdt, calendar.enddt, calendar.startdt, calendar.enddt], + :include => [:project, :tracker, :priority, :assigned_to] unless @user.projects.empty? %> + +<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_calendar.rhtml --- a/app/views/my/blocks/_calendar.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -

    <%= l(:label_calendar) %>

    - -<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week) - calendar.events = Issue.visible.find :all, - :conditions => ["#{Issue.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", calendar.startdt, calendar.enddt, calendar.startdt, calendar.enddt], - :include => [:project, :tracker, :priority, :assigned_to] unless @user.projects.empty? %> - -<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_documents.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_documents.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +

    <%=l(:label_document_plural)%>

    + +<% project_ids = @user.projects.select {|p| @user.allowed_to?(:view_documents, p)}.collect(&:id) %> +<%= render(:partial => 'documents/document', + :collection => Document.find(:all, + :limit => 10, + :order => "#{Document.table_name}.created_on DESC", + :conditions => "#{Document.table_name}.project_id in (#{project_ids.join(',')})", + :include => [:project])) unless project_ids.empty? %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_documents.rhtml --- a/app/views/my/blocks/_documents.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -

    <%=l(:label_document_plural)%>

    - -<% project_ids = @user.projects.select {|p| @user.allowed_to?(:view_documents, p)}.collect(&:id) %> -<%= render(:partial => 'documents/document', - :collection => Document.find(:all, - :limit => 10, - :order => "#{Document.table_name}.created_on DESC", - :conditions => "#{Document.table_name}.project_id in (#{project_ids.join(',')})", - :include => [:project])) unless project_ids.empty? %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_issuesassignedtome.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_issuesassignedtome.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +

    <%=l(:label_assigned_to_me_issues)%> (<%= Issue.visible.open.count(:conditions => {:assigned_to_id => ([User.current.id] + User.current.group_ids)})%>)

    + +<% assigned_issues = Issue.visible.open.find(:all, + :conditions => {:assigned_to_id => ([User.current.id] + User.current.group_ids)}, + :limit => 10, + :include => [ :status, :project, :tracker, :priority ], + :order => "#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC") %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> +<% if assigned_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :assigned_to_id => 'me', + :sort => 'priority:desc,updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :assigned_to_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_assigned_to_me_issues)}) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_issuesassignedtome.rhtml --- a/app/views/my/blocks/_issuesassignedtome.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -

    <%=l(:label_assigned_to_me_issues)%> (<%= Issue.visible.open.count(:conditions => {:assigned_to_id => User.current.id})%>)

    - -<% assigned_issues = Issue.visible.open.find(:all, - :conditions => {:assigned_to_id => User.current.id}, - :limit => 10, - :include => [ :status, :project, :tracker, :priority ], - :order => "#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC") %> -<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> -<% if assigned_issues.length > 0 %> -

    <%= link_to l(:label_issue_view_all), :controller => 'issues', - :action => 'index', - :set_filter => 1, - :assigned_to_id => 'me', - :sort => 'priority:desc,updated_on:desc' %>

    -<% end %> - -<% content_for :header_tags do %> -<%= auto_discovery_link_tag(:atom, - {:controller => 'issues', :action => 'index', :set_filter => 1, - :assigned_to_id => 'me', :format => 'atom', :key => User.current.rss_key}, - {:title => l(:label_assigned_to_me_issues)}) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_issuesreportedbyme.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_issuesreportedbyme.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +

    <%=l(:label_reported_issues)%> (<%= Issue.visible.count(:conditions => { :author_id => User.current.id }) %>)

    + +<% reported_issues = Issue.visible.find(:all, + :conditions => { :author_id => User.current.id }, + :limit => 10, + :include => [ :status, :project, :tracker ], + :order => "#{Issue.table_name}.updated_on DESC") %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> +<% if reported_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :status_id => '*', + :author_id => 'me', + :sort => 'updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :author_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_reported_issues)}) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_issuesreportedbyme.rhtml --- a/app/views/my/blocks/_issuesreportedbyme.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -

    <%=l(:label_reported_issues)%> (<%= Issue.visible.count(:conditions => { :author_id => User.current.id }) %>)

    - -<% reported_issues = Issue.visible.find(:all, - :conditions => { :author_id => User.current.id }, - :limit => 10, - :include => [ :status, :project, :tracker ], - :order => "#{Issue.table_name}.updated_on DESC") %> -<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> -<% if reported_issues.length > 0 %> -

    <%= link_to l(:label_issue_view_all), :controller => 'issues', - :action => 'index', - :set_filter => 1, - :status_id => '*', - :author_id => 'me', - :sort => 'updated_on:desc' %>

    -<% end %> - -<% content_for :header_tags do %> -<%= auto_discovery_link_tag(:atom, - {:controller => 'issues', :action => 'index', :set_filter => 1, - :author_id => 'me', :format => 'atom', :key => User.current.rss_key}, - {:title => l(:label_reported_issues)}) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_issueswatched.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_issueswatched.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,11 @@ +

    <%=l(:label_watched_issues)%> (<%= Issue.visible.watched_by(user.id).count %>)

    +<% watched_issues = Issue.visible.on_active_project.watched_by(user.id).recently_updated.with_limit(10) %> + +<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %> +<% if watched_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all_watched), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :watcher_id => 'me', + :sort => 'updated_on:desc' %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_issueswatched.rhtml --- a/app/views/my/blocks/_issueswatched.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -

    <%=l(:label_watched_issues)%> (<%= Issue.visible.watched_by(user.id).count %>)

    -<% watched_issues = Issue.visible.on_active_project.watched_by(user.id).recently_updated.with_limit(10) %> - -<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %> -<% if watched_issues.length > 0 %> -

    <%= link_to l(:label_issue_view_all_watched), :controller => 'issues', - :action => 'index', - :set_filter => 1, - :watcher_id => 'me', - :sort => 'updated_on:desc' %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_news.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_news.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +

    <%=l(:label_news_latest)%>

    + +<%= render(:partial => 'news/news', + :collection => News.find(:all, + :limit => 10, + :order => "#{News.table_name}.created_on DESC", + :conditions => "#{News.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", + :include => [:project, :author])) unless @user.projects.empty? %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_news.rhtml --- a/app/views/my/blocks/_news.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -

    <%=l(:label_news_latest)%>

    - -<%= render(:partial => 'news/news', - :collection => News.find(:all, - :limit => 10, - :order => "#{News.table_name}.created_on DESC", - :conditions => "#{News.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", - :include => [:project, :author])) unless @user.projects.empty? %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_timelog.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/blocks/_timelog.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +

    <%=l(:label_spent_time)%> (<%= l(:label_last_n_days, 7) %>)

    +<% +entries = TimeEntry.find(:all, + :conditions => ["#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", @user.id, Date.today - 6, Date.today], + :include => [:activity, :project, {:issue => [:tracker, :status]}], + :order => "#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC") +entries_by_day = entries.group_by(&:spent_on) +%> + +
    +

    <%= l(:label_total) %>: <%= html_hours("%.2f" % entries.sum(&:hours).to_f) %>

    +
    + +<% if entries.any? %> + + + + + + + + + +<% entries_by_day.keys.sort.reverse.each do |day| %> + + + + + + + <% entries_by_day[day].each do |entry| -%> + + + + + + + + <% end -%> +<% end -%> + +
    <%= l(:label_activity) %><%= l(:label_project) %><%= l(:field_comments) %><%= l(:field_hours) %>
    <%= day == Date.today ? l(:label_today).titleize : format_date(day) %><%= html_hours("%.2f" % entries_by_day[day].sum(&:hours).to_f) %>
    <%=h entry.activity %><%=h entry.project %> <%= ' - ' + link_to_issue(entry.issue, :truncate => 50) if entry.issue %><%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> + <% if entry.editable_by?(@user) -%> + <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry}, + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry}, + :confirm => l(:text_are_you_sure), + :method => :delete, + :title => l(:button_delete) %> + <% end -%> +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/blocks/_timelog.rhtml --- a/app/views/my/blocks/_timelog.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -

    <%=l(:label_spent_time)%> (<%= l(:label_last_n_days, 7) %>)

    -<% -entries = TimeEntry.find(:all, - :conditions => ["#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", @user.id, Date.today - 6, Date.today], - :include => [:activity, :project, {:issue => [:tracker, :status]}], - :order => "#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC") -entries_by_day = entries.group_by(&:spent_on) -%> - -
    -

    <%= l(:label_total) %>: <%= html_hours("%.2f" % entries.sum(&:hours).to_f) %>

    -
    - -<% if entries.any? %> - - - - - - - - - -<% entries_by_day.keys.sort.reverse.each do |day| %> - - - - - - - <% entries_by_day[day].each do |entry| -%> - - - - - - - - <% end -%> -<% end -%> - -
    <%= l(:label_activity) %><%= l(:label_project) %><%= l(:field_comments) %><%= l(:field_hours) %>
    <%= day == Date.today ? l(:label_today).titleize : format_date(day) %><%= html_hours("%.2f" % entries_by_day[day].sum(&:hours).to_f) %>
    <%=h entry.activity %><%=h entry.project %> <%= ' - ' + link_to_issue(entry.issue, :truncate => 50) if entry.issue %><%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> - <% if entry.editable_by?(@user) -%> - <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry}, - :title => l(:button_edit) %> - <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry}, - :confirm => l(:text_are_you_sure), - :method => :delete, - :title => l(:button_delete) %> - <% end -%> -
    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/page.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/page.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +
    + <%= link_to l(:label_personalize_page), :action => 'page_layout' %> + <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> +
    + +

    <%=l(:label_my_page)%>

    + +
    + <% @blocks['top'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> +
    + <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
    + <% end if @blocks['top'] %> +
    + +
    + <% @blocks['left'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> +
    + <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
    + <% end if @blocks['left'] %> +
    + +
    + <% @blocks['right'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> +
    + <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
    + <% end if @blocks['right'] %> +
    + +<%= context_menu :controller => 'issues', :action => 'context_menu' %> + +<% html_title(l(:label_my_page)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/page.rhtml --- a/app/views/my/page.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -
    - <%= link_to l(:label_personalize_page), :action => 'page_layout' %> - <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> -
    - -

    <%=l(:label_my_page)%>

    - -
    - <% @blocks['top'].each do |b| - next unless MyController::BLOCKS.keys.include? b %> -
    - <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> -
    - <% end if @blocks['top'] %> -
    - -
    - <% @blocks['left'].each do |b| - next unless MyController::BLOCKS.keys.include? b %> -
    - <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> -
    - <% end if @blocks['left'] %> -
    - -
    - <% @blocks['right'].each do |b| - next unless MyController::BLOCKS.keys.include? b %> -
    - <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> -
    - <% end if @blocks['right'] %> -
    - -<%= context_menu :controller => 'issues', :action => 'context_menu' %> - -<% html_title(l(:label_my_page)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/page_layout.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/page_layout.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,107 @@ + + +
    +<% form_tag({:action => "add_block"}, :id => "block-form") do %> +<%= label_tag('block-select', l(:label_my_page_block)) %>: +<%= select_tag 'block', "" + options_for_select(@block_options), :id => "block-select" %> +<%= link_to_remote l(:button_add), + {:url => { :action => "add_block" }, + :with => "Form.serialize('block-form')", + :update => "list-top", + :position => :top, + :complete => "afterAddBlock();" + }, :class => 'icon icon-add' + %> +<% end %> +<%= link_to l(:button_back), {:action => 'page'}, :class => 'icon icon-cancel' %> +
    + +

    <%=l(:label_my_page)%>

    + +
    + <% @blocks['top'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['top'] %> +
    + +
    + <% @blocks['left'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['left'] %> +
    + +
    + <% @blocks['right'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['right'] %> +
    + +<%= sortable_element 'list-top', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :url => { :action => "order_blocks", :group => "top" } + %> + +<%= sortable_element 'list-left', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :url => { :action => "order_blocks", :group => "left" } + %> + +<%= sortable_element 'list-right', + :tag => 'div', + :only => 'mypage-box', + :handle => "handle", + :dropOnEmpty => true, + :containment => ['list-top', 'list-left', 'list-right'], + :constraint => false, + :url => { :action => "order_blocks", :group => "right" } + %> + +<%= javascript_tag "updateSelect()" %> +<% html_title(l(:label_my_page)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/page_layout.rhtml --- a/app/views/my/page_layout.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ - - -
    -<% form_tag({:action => "add_block"}, :id => "block-form") do %> -<%= label_tag('block-select', l(:label_my_page_block)) %>: -<%= select_tag 'block', "" + options_for_select(@block_options), :id => "block-select" %> -<%= link_to_remote l(:button_add), - {:url => { :action => "add_block" }, - :with => "Form.serialize('block-form')", - :update => "list-top", - :position => :top, - :complete => "afterAddBlock();" - }, :class => 'icon icon-add' - %> -<% end %> -<%= link_to l(:button_back), {:action => 'page'}, :class => 'icon icon-cancel' %> -
    - -

    <%=l(:label_my_page)%>

    - -
    - <% @blocks['top'].each do |b| - next unless MyController::BLOCKS.keys.include? b %> - <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> - <% end if @blocks['top'] %> -
    - -
    - <% @blocks['left'].each do |b| - next unless MyController::BLOCKS.keys.include? b %> - <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> - <% end if @blocks['left'] %> -
    - -
    - <% @blocks['right'].each do |b| - next unless MyController::BLOCKS.keys.include? b %> - <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> - <% end if @blocks['right'] %> -
    - -<%= sortable_element 'list-top', - :tag => 'div', - :only => 'mypage-box', - :handle => "handle", - :dropOnEmpty => true, - :containment => ['list-top', 'list-left', 'list-right'], - :constraint => false, - :url => { :action => "order_blocks", :group => "top" } - %> - - -<%= sortable_element 'list-left', - :tag => 'div', - :only => 'mypage-box', - :handle => "handle", - :dropOnEmpty => true, - :containment => ['list-top', 'list-left', 'list-right'], - :constraint => false, - :url => { :action => "order_blocks", :group => "left" } - %> - -<%= sortable_element 'list-right', - :tag => 'div', - :only => 'mypage-box', - :handle => "handle", - :dropOnEmpty => true, - :containment => ['list-top', 'list-left', 'list-right'], - :constraint => false, - :url => { :action => "order_blocks", :group => "right" } - %> - -<%= javascript_tag "updateSelect()" %> -<% html_title(l(:label_my_page)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/password.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/my/password.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +

    <%=l(:button_change_password)%>

    + +<%= error_messages_for 'user' %> + +<% form_tag({}, :class => "tabular") do %> +
    +

    +<%= password_field_tag 'password', nil, :size => 25 %>

    + +

    +<%= password_field_tag 'new_password', nil, :size => 25 %>
    +<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    + +

    +<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    +
    +<%= submit_tag l(:button_apply) %> +<% end %> + +<% content_for :sidebar do %> +<%= render :partial => 'sidebar' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/my/password.rhtml --- a/app/views/my/password.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -

    <%=l(:button_change_password)%>

    - -<%= error_messages_for 'user' %> - -<% form_tag({}, :class => "tabular") do %> -
    -

    -<%= password_field_tag 'password', nil, :size => 25 %>

    - -

    -<%= password_field_tag 'new_password', nil, :size => 25 %>
    -<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    - -

    -<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    -
    -<%= submit_tag l(:button_apply) %> -<% end %> - -<% content_for :sidebar do %> -<%= render :partial => 'sidebar' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/news/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +<%= f.error_messages %> +
    +

    <%= f.text_field :title, :required => true, :size => 60 %>

    +

    <%= f.text_area :summary, :cols => 60, :rows => 2 %>

    +

    <%= f.text_area :description, :required => true, :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    +
    + +<%= wikitoolbar_for 'news_description' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/_form.rhtml --- a/app/views/news/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -<%= error_messages_for 'news' %> -
    -

    <%= f.text_field :title, :required => true, :size => 60 %>

    -

    <%= f.text_area :summary, :cols => 60, :rows => 2 %>

    -

    <%= f.text_area :description, :required => true, :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    -
    - -<%= wikitoolbar_for 'news_description' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/_news.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/news/_news.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +
    +
    +<%= format_time(news.created_on) %> +<% project ||= @project %> +<% if !project %> +<%= link_to_project(news.project) %> +<% end %> +<%= link_to h(news.title), news_path(news) %> +<%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %> +
    +<% unless news.summary.blank? %><%=h news.summary %>
    <% end %> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/news/_news.rhtml --- a/app/views/news/_news.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -
    -
    -<%= format_time(news.created_on) %> -<% project ||= @project %> -<% if !project %> -<%= link_to_project(news.project) %> -<% end %> -<%= link_to h(news.title), news_path(news) %> -<%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %> -
    -<% unless news.summary.blank? %><%=h news.summary %>
    <% end %> -
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/news/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/news/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +

    <%=l(:label_news)%>

    + +<% labelled_tabular_form_for @news, :html => { :id => 'news-form', :method => :put } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<%= link_to_remote l(:label_preview), + { :url => preview_news_path(:project_id => @project), + :method => 'get', + :update => 'preview', + :with => "Form.serialize('news-form')" + }, :accesskey => accesskey(:preview) %> +<% end %> +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/edit.rhtml --- a/app/views/news/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -

    <%=l(:label_news)%>

    - -<% labelled_tabular_form_for :news, @news, :url => news_path(@news), - :html => { :id => 'news-form', :method => :put } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<%= link_to_remote l(:label_preview), - { :url => preview_news_path(:project_id => @project), - :method => 'get', - :update => 'preview', - :with => "Form.serialize('news-form')" - }, :accesskey => accesskey(:preview) %> -<% end %> -
    - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/index.api.rsb --- a/app/views/news/index.api.rsb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/news/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -4,10 +4,10 @@ api.id news.id api.project(:id => news.project_id, :name => news.project.name) unless news.project.nil? api.author(:id => news.author_id, :name => news.author.name) unless news.author.nil? - - api.title news.title - api.summary news.summary - api.description news.description + + api.title news.title + api.summary news.summary + api.description news.description api.created_on news.created_on end end diff -r 487d96eac004 -r 5e80956cc792 app/views/news/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/news/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +
    +<%= link_to(l(:label_news_new), + new_project_news_path(@project), + :class => 'icon icon-add', + :onclick => 'Element.show("add-news"); Form.Element.focus("news_title"); return false;') if @project && User.current.allowed_to?(:manage_news, @project) %> +
    + + + +

    <%=l(:label_news_plural)%>

    + +<% if @newss.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +<% @newss.each do |news| %> +

    <%= avatar(news.author, :size => "24") %><%= link_to_project(news.project) + ': ' unless news.project == @project %> + <%= link_to h(news.title), news_path(news) %> + <%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>

    +

    <%= authoring news.created_on, news.author %>

    +
    + <%= textilizable(news.description) %> +
    +<% end %> +<% end %> +

    <%= pagination_links_full @news_pages %>

    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% html_title(l(:label_news_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/index.rhtml --- a/app/views/news/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -
    -<%= link_to(l(:label_news_new), - new_project_news_path(@project), - :class => 'icon icon-add', - :onclick => 'Element.show("add-news"); Form.Element.focus("news_title"); return false;') if @project && User.current.allowed_to?(:manage_news, @project) %> -
    - - - -

    <%=l(:label_news_plural)%>

    - -<% if @newss.empty? %> -

    <%= l(:label_no_data) %>

    -<% else %> -<% @newss.each do |news| %> -

    <%= link_to_project(news.project) + ': ' unless news.project == @project %> - <%= link_to h(news.title), news_path(news) %> - <%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>

    -

    <%= authoring news.created_on, news.author %>

    -
    - <%= textilizable(news.description) %> -
    -<% end %> -<% end %> -

    <%= pagination_links_full @news_pages %>

    - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %> -<% end %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> - <%= stylesheet_link_tag 'scm' %> -<% end %> - -<% html_title(l(:label_news_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/news/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +

    <%=l(:label_news_new)%>

    + +<% labelled_tabular_form_for @news, :url => project_news_index_path(@project), + :html => { :id => 'news-form' } do |f| %> + <%= render :partial => 'news/form', :locals => { :f => f } %> + <%= submit_tag l(:button_create) %> + <%= link_to_remote l(:label_preview), + { :url => preview_news_path(:project_id => @project), + :method => 'get', + :update => 'preview', + :with => "Form.serialize('news-form')" + }, :accesskey => accesskey(:preview) %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/news/new.rhtml --- a/app/views/news/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -

    <%=l(:label_news_new)%>

    - -<% labelled_tabular_form_for :news, @news, :url => project_news_index_path(@project), - :html => { :id => 'news-form' } do |f| %> -<%= render :partial => 'news/form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<%= link_to_remote l(:label_preview), - { :url => preview_news_path(:project_id => @project), - :method => 'get', - :update => 'preview', - :with => "Form.serialize('news-form')" - }, :accesskey => accesskey(:preview) %> -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/news/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/news/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,70 @@ +
    +<%= watcher_tag(@news, User.current) %> +<%= link_to(l(:button_edit), + edit_news_path(@news), + :class => 'icon icon-edit', + :accesskey => accesskey(:edit), + :onclick => 'Element.show("edit-news"); return false;') if User.current.allowed_to?(:manage_news, @project) %> +<%= link_to(l(:button_delete), + news_path(@news), + :confirm => l(:text_are_you_sure), + :method => :delete, + :class => 'icon icon-del') if User.current.allowed_to?(:manage_news, @project) %> +
    + +

    <%= avatar(@news.author, :size => "24") %><%=h @news.title %>

    + +<% if authorize_for('news', 'edit') %> + +<% end %> + +

    <% unless @news.summary.blank? %><%=h @news.summary %>
    <% end %> +<%= authoring @news.created_on, @news.author %>

    +
    +<%= textilizable(@news.description) %> +
    +
    + +
    +

    <%= l(:label_comment_plural) %>

    +<% @comments.each do |comment| %> + <% next if comment.new_record? %> +
    + <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment}, + :confirm => l(:text_are_you_sure), :method => :delete, :title => l(:button_delete) %> +
    +

    <%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %>

    + <%= textilizable(comment.comments) %> +<% end if @comments.any? %> +
    + +<% if authorize_for 'comments', 'create' %> +

    <%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %>

    +<% form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %> +
    + <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'comment_comments' %> +
    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +<% end %> + +<% html_title @news.title -%> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/news/show.rhtml --- a/app/views/news/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -
    -<%= watcher_tag(@news, User.current) %> -<%= link_to(l(:button_edit), - edit_news_path(@news), - :class => 'icon icon-edit', - :accesskey => accesskey(:edit), - :onclick => 'Element.show("edit-news"); return false;') if User.current.allowed_to?(:manage_news, @project) %> -<%= link_to(l(:button_delete), - news_path(@news), - :confirm => l(:text_are_you_sure), - :method => :delete, - :class => 'icon icon-del') if User.current.allowed_to?(:manage_news, @project) %> -
    - -

    <%= avatar(@news.author, :size => "24") %><%=h @news.title %>

    - -<% if authorize_for('news', 'edit') %> - -<% end %> - -

    <% unless @news.summary.blank? %><%=h @news.summary %>
    <% end %> -<%= authoring @news.created_on, @news.author %>

    -
    -<%= textilizable(@news.description) %> -
    -
    - -
    -

    <%= l(:label_comment_plural) %>

    -<% @comments.each do |comment| %> - <% next if comment.new_record? %> -
    - <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment}, - :confirm => l(:text_are_you_sure), :method => :delete, :title => l(:button_delete) %> -
    -

    <%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %>

    - <%= textilizable(comment.comments) %> -<% end if @comments.any? %> -
    - -<% if authorize_for 'comments', 'create' %> -

    <%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %>

    -<% form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %> -
    - <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %> - <%= wikitoolbar_for 'comment_comments' %> -
    -

    <%= submit_tag l(:button_add) %>

    -<% end %> -<% end %> - -<% html_title @news.title -%> - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/previews/issue.html.erb --- a/app/views/previews/issue.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/previews/issue.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,11 +1,11 @@ <% if @notes %> -
    <%= l(:field_notes) %> - <%= textilizable @notes, :attachments => @attachements, :object => @issue %> -
    +
    <%= l(:field_notes) %> + <%= textilizable @notes, :attachments => @attachements, :object => @issue %> +
    <% end %> <% if @description %> -
    <%= l(:field_description) %> - <%= textilizable @description, :attachments => @attachements, :object => @issue %> -
    +
    <%= l(:field_description) %> + <%= textilizable @description, :attachments => @attachements, :object => @issue %> +
    <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/_edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/_edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +<% labelled_tabular_form_for @project do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/_edit.rhtml --- a/app/views/projects/_edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<% labelled_tabular_form_for :project, @project, :url => project_path(@project), :html => {:method => (@project.new_record? ? :post : :put) } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,79 @@ +<%= error_messages_for 'project' %> + +
    + +

    <%= f.text_field :name, :required => true, :size => 60 %> +
    + <%= l(:text_project_name_info) %> +

    + +<% unless @project.allowed_parents.compact.empty? %> +

    <%= label(:project, :parent_id, l(:field_parent)) %><%= parent_project_select_tag(@project) %>

    +<% end %> + +

    <%= f.text_area :description, :rows => 5, :class => 'wiki-edit' %>

    +

    <%= f.text_field :identifier, :required => true, :size => 60, :disabled => @project.identifier_frozen? %> +<% unless @project.identifier_frozen? %> +
    + <%= l(:text_project_identifier_info) %> +<% end %>

    +

    <%= f.text_field :homepage, :size => 60 %> +
    + <%= l(:text_project_homepage_info) %> +

    +

    <%= f.check_box :is_public %> +
    + <%= l(:text_project_visibility_info) %> +

    +<%= wikitoolbar_for 'project_description' %> + +<% @project.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :project, value %>

    +<% end %> +<%= call_hook(:view_projects_form, :project => @project, :form => f) %> +
    + +<% if @project.new_record? %> +
    <%= l(:label_module_plural) %> +<% Redmine::AccessControl.available_project_modules.each do |m| %> + +<% end %> +<%= hidden_field_tag 'project[enabled_module_names][]', '' %> +<%= javascript_tag 'observeProjectModules()' %> +
    +<% end %> + +<% if @project.new_record? %> +<% @trackers.each do |tracker| %> + <%= hidden_field_tag 'project[tracker_ids][]', tracker.id %> +<% end %> +<%= hidden_field_tag 'project[tracker_ids][]', '' %> +<% elsif @project.module_enabled?('issue_tracking') %> +<% unless @trackers.empty? %> +
    <%=l(:label_tracker_plural)%> +<% @trackers.each do |tracker| %> + +<% end %> +<%= hidden_field_tag 'project[tracker_ids][]', '' %> +
    +<% end %> + +<% unless @issue_custom_fields.empty? %> +
    <%=l(:label_custom_field_plural)%> +<% @issue_custom_fields.each do |custom_field| %> + +<% end %> +<%= hidden_field_tag 'project[issue_custom_field_ids][]', '' %> +
    +<% end %> +<% end %> + diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/_form.rhtml --- a/app/views/projects/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -<%= error_messages_for 'project' %> - -
    - -

    <%= f.text_field :name, :required => true, :size => 60 %> -
    - <%= l(:text_project_name_info) %> -

    - -<% unless @project.allowed_parents.compact.empty? %> -

    <%= label(:project, :parent_id, l(:field_parent)) %><%= parent_project_select_tag(@project) %>

    -<% end %> - -

    <%= f.text_area :description, :rows => 5, :class => 'wiki-edit' %>

    -

    <%= f.text_field :identifier, :required => true, :size => 60, :disabled => @project.identifier_frozen? %> -<% unless @project.identifier_frozen? %> -
    - <%= l(:text_project_identifier_info) %> -<% end %>

    -

    <%= f.text_field :homepage, :size => 60 %> -
    - <%= l(:text_project_homepage_info) %> -

    -

    <%= f.check_box :is_public %> -
    - <%= l(:text_project_visibility_info) %> -

    -<%= wikitoolbar_for 'project_description' %> - -<% @project.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :project, value %>

    -<% end %> -<%= call_hook(:view_projects_form, :project => @project, :form => f) %> -
    - -<% if @project.new_record? %> -
    <%= l(:label_module_plural) %> -<% Redmine::AccessControl.available_project_modules.each do |m| %> - -<% end %> -<%= hidden_field_tag 'project[enabled_module_names][]', '' %> -<%= javascript_tag 'observeProjectModules()' %> -
    -<% end %> - -<% if @project.new_record? %> -<% @trackers.each do |tracker| %> - <%= hidden_field_tag 'project[tracker_ids][]', tracker.id %> -<% end %> -<%= hidden_field_tag 'project[tracker_ids][]', '' %> -<% elsif @project.module_enabled?('issue_tracking') %> -<% unless @trackers.empty? %> -
    <%=l(:label_tracker_plural)%> -<% @trackers.each do |tracker| %> - -<% end %> -<%= hidden_field_tag 'project[tracker_ids][]', '' %> -
    -<% end %> - -<% unless @issue_custom_fields.empty? %> -
    <%=l(:label_custom_field_plural)%> -<% @issue_custom_fields.each do |custom_field| %> - -<% end %> -<%= hidden_field_tag 'project[issue_custom_field_ids][]', '' %> -
    -<% end %> -<% end %> - diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/_members_box.html.erb --- a/app/views/projects/_members_box.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/projects/_members_box.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,8 +1,8 @@ <% if @users_by_role.any? %> -
    -

    <%=l(:label_member_plural)%>

    -

    <% @users_by_role.keys.sort.each do |role| %> - <%=h role %>: <%= @users_by_role[role].sort.collect{|u| link_to_user u}.join(", ") %>
    - <% end %>

    -
    - <% end %> +
    +

    <%=l(:label_member_plural)%>

    +

    <% @users_by_role.keys.sort.each do |role| %> + <%=h role %>: <%= @users_by_role[role].sort.collect{|u| link_to_user u}.join(", ") %>
    + <% end %>

    +
    + <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/copy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/copy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,20 @@ +

    <%=l(:label_project_new)%>

    + +<% labelled_tabular_form_for @project, :url => { :action => "copy" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> + +
    <%= l(:button_copy) %> + + + + + + + + <%= hidden_field_tag 'only[]', '' %> +
    + +
    + +<%= submit_tag l(:button_copy) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/copy.rhtml --- a/app/views/projects/copy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -

    <%=l(:label_project_new)%>

    - -<% labelled_tabular_form_for :project, @project, :url => { :action => "copy" } do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> - -
    <%= l(:button_copy) %> - - - - - - - - <%= hidden_field_tag 'only[]', '' %> -
    - -
    - -<%= submit_tag l(:button_copy) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/destroy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/destroy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +

    <%=l(:label_confirmation)%>

    +
    +

    <%=h @project_to_destroy %>
    +<%=l(:text_project_destroy_confirmation)%> + +<% if @project_to_destroy.descendants.any? %> +
    <%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.descendants.collect{|p| p.to_s}.join(', ')))) %> +<% end %> +

    +

    + <% form_tag(project_path(@project_to_destroy), :method => :delete) do %> + + <%= submit_tag l(:button_delete) %> + <% end %> +

    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/destroy.rhtml --- a/app/views/projects/destroy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -

    <%=l(:label_confirmation)%>

    -
    -

    <%=h @project_to_destroy %>
    -<%=l(:text_project_destroy_confirmation)%> - -<% if @project_to_destroy.descendants.any? %> -
    <%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.descendants.collect{|p| p.to_s}.join(', ')))) %> -<% end %> -

    -

    - <% form_tag(project_path(@project_to_destroy), :method => :delete) do %> - - <%= submit_tag l(:button_delete) %> - <% end %> -

    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/index.api.rsb --- a/app/views/projects/index.api.rsb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/projects/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -6,9 +6,9 @@ api.identifier project.identifier api.description project.description api.parent(:id => project.parent.id, :name => project.parent.name) if project.parent && project.parent.visible? - + render_api_custom_values project.visible_custom_field_values, api - + api.created_on project.created_on api.updated_on project.updated_on end diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +
    + <%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%> + <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> +
    + +<% if @user_projects %> + + <%= render_my_project_hierarchy(@user_projects)%> + +<% end %> + +

    +<%= l("label_project_all") %> +

    + +<%= render_project_table(@projects) %> + +

    <%= pagination_links_full @project_pages, @project_count %>

    + + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title(l(:label_project_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/index.rhtml --- a/app/views/projects/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %> -<% end %> - -
    - <%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%> - <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> -
    - -<% if @user_projects %> - - <%= render_my_project_hierarchy(@user_projects)%> - -<% end %> - -

    -<%= l("label_project_all") %> -

    - -<%= render_project_table(@projects) %> - -

    <%= pagination_links_full @project_pages, @project_count %>

    - - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> -<% end %> - -<% html_title(l(:label_project_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/list_members.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/list_members.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +

    <%=l(:label_member_plural)%>

    + +<% if @members.empty? %>

    <%= l(:label_no_data) %>

    <% end %> + +<% members = @members.group_by {|m| m.role } %> +<% members.keys.sort{|x,y| x.position <=> y.position}.each do |role| %> +

    <%= h(role.name) %>

    +
      +<% members[role].each do |m| %> +
    • <%= link_to_user m.user %> (<%= format_date m.created_on %>)
    • +<% end %> +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/list_members.rhtml --- a/app/views/projects/list_members.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -

    <%=l(:label_member_plural)%>

    - -<% if @members.empty? %>

    <%= l(:label_no_data) %>

    <% end %> - -<% members = @members.group_by {|m| m.role } %> -<% members.keys.sort{|x,y| x.position <=> y.position}.each do |role| %> -

    <%= role.name %>

    -
      -<% members[role].each do |m| %> -
    • <%= link_to_user m.user %> (<%= format_date m.created_on %>)
    • -<% end %> -
    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/new.html.erb --- a/app/views/projects/new.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/projects/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,8 @@

    <%=l(:label_project_new)%>

    -<% labelled_tabular_form_for :project, @project, :url => { :action => "create" } do |f| %> +<% labelled_tabular_form_for @project do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> +<%= submit_tag l(:button_create) %> +<%= submit_tag l(:button_create_and_continue), :name => 'continue' %> <%= javascript_tag "Form.Element.focus('project_name');" %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%=l(:label_settings)%>

    + +<%= render_tabs project_settings_tabs %> + +<% html_title(l(:label_settings)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings.rhtml --- a/app/views/projects/settings.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -

    <%=l(:label_settings)%>

    - -<%= render_tabs project_settings_tabs %> - -<% html_title(l(:label_settings)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_activities.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_activities.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +<% form_tag(project_project_enumerations_path(@project), :method => :put, :class => "tabular") do %> + + + + + + <% TimeEntryActivity.new.available_custom_fields.each do |value| %> + + <% end %> + + + + <% @project.activities(true).each do |enumeration| %> + <% fields_for "enumerations[#{enumeration.id}]", enumeration do |ff| %> + + + + <% enumeration.custom_field_values.each do |value| %> + + <% end %> + + + <% end %> + <% end %> +
    <%= l(:field_name) %><%= l(:enumeration_system_activity) %><%= h value.name %><%= l(:field_active) %>
    + <%= ff.hidden_field :parent_id, :value => enumeration.id unless enumeration.project %> + <%= h(enumeration) %> + <%= checked_image !enumeration.project %> + <%= custom_field_tag "enumerations[#{enumeration.id}]", value %> + + <%= ff.check_box :active %> +
    + +
    +<%= link_to(l(:button_reset), project_project_enumerations_path(@project), + :method => :delete, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_activities.rhtml --- a/app/views/projects/settings/_activities.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -<% form_tag(project_project_enumerations_path(@project), :method => :put, :class => "tabular") do %> - - - - - - <% TimeEntryActivity.new.available_custom_fields.each do |value| %> - - <% end %> - - - - <% @project.activities(true).each do |enumeration| %> - <% fields_for "enumerations[#{enumeration.id}]", enumeration do |ff| %> - - - - <% enumeration.custom_field_values.each do |value| %> - - <% end %> - - - <% end %> - <% end %> -
    <%= l(:field_name) %><%= l(:enumeration_system_activity) %><%= h value.name %><%= l(:field_active) %>
    - <%= ff.hidden_field :parent_id, :value => enumeration.id unless enumeration.project %> - <%= h(enumeration) %> - <%= checked_image !enumeration.project %> - <%= custom_field_tag "enumerations[#{enumeration.id}]", value %> - - <%= ff.check_box :active %> -
    - -
    -<%= link_to(l(:button_reset), project_project_enumerations_path(@project), - :method => :delete, - :confirm => l(:text_are_you_sure), - :class => 'icon icon-del') %> -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_boards.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_boards.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,32 @@ +<% if @project.boards.any? %> + + + + + + + + +<% @project.boards.each do |board| + next if board.new_record? %> + + + + + + +<% end %> + +
    <%= l(:label_board) %><%= l(:field_description) %>
    <%=h board.name %><%=h board.description %> + <% if authorize_for("boards", "edit") %> + <%= reorder_links('board', {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}) %> + <% end %> + + <%= link_to_if_authorized l(:button_edit), {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}, :class => 'icon icon-edit' %> + <%= link_to_if_authorized l(:button_delete), {:controller => 'boards', :action => 'destroy', :project_id => @project, :id => board}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +

    <%= link_to_if_authorized l(:label_board_new), {:controller => 'boards', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_boards.rhtml --- a/app/views/projects/settings/_boards.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -<% if @project.boards.any? %> - - - - - - - - -<% @project.boards.each do |board| - next if board.new_record? %> - - - - - - -<% end %> - -
    <%= l(:label_board) %><%= l(:field_description) %>
    <%=h board.name %><%=h board.description %> - <% if authorize_for("boards", "edit") %> - <%= reorder_links('board', {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}) %> - <% end %> - - <%= link_to_if_authorized l(:button_edit), {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}, :class => 'icon icon-edit' %> - <%= link_to_if_authorized l(:button_delete), {:controller => 'boards', :action => 'destroy', :project_id => @project, :id => board}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> -
    -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> - -

    <%= link_to_if_authorized l(:label_board_new), {:controller => 'boards', :action => 'new', :project_id => @project} %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_issue_categories.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_issue_categories.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,29 @@ +<% if @project.issue_categories.any? %> + + + + + + + +<% for category in @project.issue_categories %> + <% unless category.new_record? %> + + + + + + <% end %> +<% end %> + +
    <%= l(:label_issue_category) %><%= l(:field_assigned_to) %>
    <%=h(category.name) %><%=h(category.assigned_to.name) if category.assigned_to %> + <% if User.current.allowed_to?(:manage_categories, @project) %> + <%= link_to l(:button_edit), edit_issue_category_path(category), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), issue_category_path(category), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +

    <%= link_to l(:label_issue_category_new), new_project_issue_category_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_categories, @project) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_issue_categories.rhtml --- a/app/views/projects/settings/_issue_categories.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -<% if @project.issue_categories.any? %> - - - - - - - -<% for category in @project.issue_categories %> - <% unless category.new_record? %> - - - - - - <% end %> -<% end %> - -
    <%= l(:label_issue_category) %><%= l(:field_assigned_to) %>
    <%=h(category.name) %><%=h(category.assigned_to.name) if category.assigned_to %> - <%= link_to_if_authorized l(:button_edit), { :controller => 'issue_categories', :action => 'edit', :id => category }, :class => 'icon icon-edit' %> - <%= link_to_if_authorized l(:button_delete), {:controller => 'issue_categories', :action => 'destroy', :id => category}, :method => :post, :class => 'icon icon-del' %> -
    -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> - -

    <%= link_to_if_authorized l(:label_issue_category_new), :controller => 'issue_categories', :action => 'new', :project_id => @project %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_members.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_members.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,83 @@ +<%= error_messages_for 'member' %> +<% roles = Role.find_all_givable + members = @project.member_principals.find(:all, :include => [:roles, :principal]).sort %> + +
    +<% if members.any? %> + + + + + + <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %> + + + <% members.each do |member| %> + <% next if member.new_record? %> + + + + + <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %> + +<% end; reset_cycle %> + +
    <%= l(:label_user) %> / <%= l(:label_group) %><%= l(:label_role_plural) %>
    <%= link_to_user member.principal %> + <%=h member.roles.sort.collect(&:to_s).join(', ') %> + <% if authorize_for('members', 'edit') %> + <% remote_form_for(:member, member, :url => {:controller => 'members', :action => 'edit', :id => member}, + :method => :post, + :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }) do |f| %> +

    <% roles.each do |role| %> +
    + <% end %>

    + <%= hidden_field_tag 'member[role_ids][]', '' %> +

    <%= submit_tag l(:button_change), :class => "small" %> + <%= link_to_function l(:button_cancel), "$('member-#{member.id}-roles').show(); $('member-#{member.id}-roles-form').hide(); return false;" %>

    + <% end %> + <% end %> +
    + <%= link_to_function l(:button_edit), "$('member-#{member.id}-roles').hide(); $('member-#{member.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %> + <%= link_to_remote(l(:button_delete), { :url => {:controller => 'members', :action => 'destroy', :id => member}, + :method => :post, + :confirm => (!User.current.admin? && member.include?(User.current) ? l(:text_own_membership_delete_confirmation) : nil) + }, :title => l(:button_delete), + :class => 'icon icon-del') if member.deletable? %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + +<% principals = Principal.active.find(:all, :limit => 100, :order => 'type, login, lastname ASC') - @project.principals %> + +
    +<% if roles.any? && principals.any? %> + <% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post, + :loading => '$(\'member-add-submit\').disable();', + :complete => 'if($(\'member-add-submit\')) $(\'member-add-submit\').enable();') do |f| %> +
    <%=l(:label_member_new)%> + +

    <%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %>

    + <%= observe_field(:principal_search, + :frequency => 0.5, + :update => :principals, + :url => { :controller => 'members', :action => 'autocomplete_for_member', :id => @project }, + :with => 'q') + %> + +
    + <%= principals_check_box_tags 'member[user_ids][]', principals %> +
    + +

    <%= l(:label_role_plural) %>: + <% roles.each do |role| %> + + <% end %>

    + +

    <%= submit_tag l(:button_add), :id => 'member-add-submit' %>

    +
    + <% end %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_modules.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_modules.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +<% form_for :project, @project, + :url => { :action => 'modules', :id => @project }, + :html => {:id => 'modules-form'} do |f| %> + +
    +
    +<%= l(:text_select_project_modules) %> + +<% Redmine::AccessControl.available_project_modules.each do |m| %> +

    +<% end %> +
    +
    + +

    <%= check_all_links 'modules-form' %>

    +

    <%= submit_tag l(:button_save) %>

    + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_modules.rhtml --- a/app/views/projects/settings/_modules.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -<% form_for :project, @project, - :url => { :action => 'modules', :id => @project }, - :html => {:id => 'modules-form'} do |f| %> - -
    -
    -<%= l(:text_select_project_modules) %> - -<% Redmine::AccessControl.available_project_modules.each do |m| %> -

    -<% end %> -
    -
    - -

    <%= check_all_links 'modules-form' %>

    -

    <%= submit_tag l(:button_save) %>

    - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_repository.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_repository.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ + +<%= javascript_include_tag 'repository' %> + +<% remote_form_for :repository, @repository, + :url => { :controller => 'repositories', :action => 'edit', :id => @project }, + :builder => TabularFormBuilder, + :lang => current_language do |f| %> + +<%= error_messages_for 'repository' %> + +
    + +

    +<% if @repository %> + <%= l(:text_settings_repo_explanation) %> + <% if @repository.is_external %> +

    <%= l(:text_settings_repo_is_external) %> + <% else %> +

    <%= l(:text_settings_repo_is_internal) %> + <% end %> +

    + + + + + +

    + <%= label_tag('repository_is_external', l(:label_is_external_repository)) %> + <%= check_box :repository, :is_external, :onclick => "toggle_ext_url()" %> +
    <%= l(:setting_external_repository) %> +

    + + +

    + <%= label_tag('repository_external_url', l(:label_repository_external_url)) %> + <%= text_field :repository, :external_url, :disabled => !(@repository and @repository.is_external) %> +
    <%= l(:setting_external_repository_url) %> +

    + +

    <%= l(:text_settings_repo_need_help) %>

    + +
    + +
    +<% if @repository && !@repository.new_record? %> +<%= link_to(l(:label_user_plural), + { + :controller => 'repositories', + :action => 'committers', + :id => @project + }, + :class => 'icon icon-user') %> +<% end %> +
    + +<%= submit_tag(l(:button_save), :onclick => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)")) %> + +<% else %> + <%= l(:text_settings_repo_creation) %> +<% end %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_repository.rhtml --- a/app/views/projects/settings/_repository.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ - -<%= javascript_include_tag 'repository' %> - -<% remote_form_for :repository, @repository, - :url => { :controller => 'repositories', :action => 'edit', :id => @project }, - :builder => TabularFormBuilder, - :lang => current_language do |f| %> - -<%= error_messages_for 'repository' %> - -
    - -

    -<% if @repository %> - <%= l(:text_settings_repo_explanation) %> - <% if @repository.is_external %> -

    <%= l(:text_settings_repo_is_external) %> - <% else %> -

    <%= l(:text_settings_repo_is_internal) %> - <% end %> -

    - - - - - -

    - <%= label_tag('repository_is_external', l(:label_is_external_repository)) %> - <%= check_box :repository, :is_external, :onclick => "toggle_ext_url()" %> -
    <%= l(:setting_external_repository) %> -

    - - -

    - <%= label_tag('repository_external_url', l(:label_repository_external_url)) %> - <%= text_field :repository, :external_url, :disabled => !(@repository and @repository.is_external) %> -
    <%= l(:setting_external_repository_url) %> -

    - -

    <%= l(:text_settings_repo_need_help) %>

    - -
    - -
    -<% if @repository && !@repository.new_record? %> -<%= link_to(l(:label_user_plural), - { - :controller => 'repositories', - :action => 'committers', - :id => @project - }, - :class => 'icon icon-user') %> -<% end %> -
    - -<%= submit_tag(l(:button_save), :onclick => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)")) %> - -<% else %> - <%= l(:text_settings_repo_creation) %> -<% end %> - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_versions.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_versions.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<% if @project.shared_versions.any? %> + + + + + + + + + + + +<% for version in @project.shared_versions.sort %> + + + + + + + + + +<% end; reset_cycle %> + +
    <%= l(:label_version) %><%= l(:field_effective_date) %><%= l(:field_description) %><%= l(:field_status) %><%= l(:field_sharing) %><%= l(:label_wiki_page) %>
    <%= link_to_version version %><%= format_date(version.effective_date) %><%=h version.description %><%= l("version_status_#{version.status}") %><%= link_to_if_authorized(h(version.wiki_page_title), {:controller => 'wiki', :action => 'show', :project_id => version.project, :id => Wiki.titleize(version.wiki_page_title)}) || h(version.wiki_page_title) unless version.wiki_page_title.blank? || version.project.wiki.nil? %> + <% if version.project == @project && User.current.allowed_to?(:manage_versions, @project) %> + <%= link_to l(:button_edit), edit_version_path(version), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), version_path(version), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +
    +<% if @project.versions.any? %> + <%= link_to l(:label_close_versions), close_completed_project_versions_path(@project), :method => :put %> +<% end %> +
    + +

    <%= link_to l(:label_version_new), new_project_version_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_versions, @project) %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_versions.rhtml --- a/app/views/projects/settings/_versions.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -<% if @project.shared_versions.any? %> - - - - - - - - - - - -<% for version in @project.shared_versions.sort %> - - - - - - - - - -<% end; reset_cycle %> - -
    <%= l(:label_version) %><%= l(:field_effective_date) %><%= l(:field_description) %><%= l(:field_status) %><%= l(:field_sharing) %><%= l(:label_wiki_page) %>
    <%= link_to_version version %><%= format_date(version.effective_date) %><%=h version.description %><%= l("version_status_#{version.status}") %><%= link_to_if_authorized(h(version.wiki_page_title), {:controller => 'wiki', :action => 'show', :project_id => version.project, :id => Wiki.titleize(version.wiki_page_title)}) || h(version.wiki_page_title) unless version.wiki_page_title.blank? || version.project.wiki.nil? %> - <% if version.project == @project %> - <%= link_to_if_authorized l(:button_edit), {:controller => 'versions', :action => 'edit', :id => version }, :class => 'icon icon-edit' %> - <%= link_to_if_authorized l(:button_delete), {:controller => 'versions', :action => 'destroy', :id => version}, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> - <% end %> -
    -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> - -
    -<% if @project.versions.any? %> - <%= link_to l(:label_close_versions), close_completed_project_versions_path(@project), :method => :put %> -<% end %> -
    - -

    <%= link_to_if_authorized l(:label_version_new), :controller => 'versions', :action => 'new', :project_id => @project %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_wiki.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/settings/_wiki.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +<% remote_form_for :wiki, @wiki, + :url => { :controller => 'wikis', :action => 'edit', :id => @project }, + :builder => TabularFormBuilder, + :lang => current_language do |f| %> + +<%= error_messages_for 'wiki' %> + +
    +

    <%= f.text_field :start_page, :size => 60, :required => true %>
    +<%= l(:text_unallowed_characters) %>: , . / ? ; : |

    +
    + +
    +<%= link_to(l(:button_delete), {:controller => 'wikis', :action => 'destroy', :id => @project}, + :class => 'icon icon-del') if @wiki && !@wiki.new_record? %> +
    + +<%= submit_tag((@wiki.nil? || @wiki.new_record?) ? l(:button_create) : l(:button_save)) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/settings/_wiki.rhtml --- a/app/views/projects/settings/_wiki.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -<% remote_form_for :wiki, @wiki, - :url => { :controller => 'wikis', :action => 'edit', :id => @project }, - :builder => TabularFormBuilder, - :lang => current_language do |f| %> - -<%= error_messages_for 'wiki' %> - -
    -

    <%= f.text_field :start_page, :size => 60, :required => true %>
    -<%= l(:text_unallowed_characters) %>: , . / ? ; : |

    -
    - -
    -<%= link_to(l(:button_delete), {:controller => 'wikis', :action => 'destroy', :id => @project}, - :class => 'icon icon-del') if @wiki && !@wiki.new_record? %> -
    - -<%= submit_tag((@wiki.nil? || @wiki.new_record?) ? l(:button_create) : l(:button_save)) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/show.api.rsb --- a/app/views/projects/show.api.rsb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/projects/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -5,15 +5,21 @@ api.description @project.description api.homepage @project.homepage api.parent(:id => @project.parent.id, :name => @project.parent.name) if @project.parent && @project.parent.visible? - + render_api_custom_values @project.visible_custom_field_values, api - + api.created_on @project.created_on api.updated_on @project.updated_on - + api.array :trackers do @project.trackers.each do |tracker| api.tracker(:id => tracker.id, :name => tracker.name) end end if include_in_api_response?('trackers') + + api.array :issue_categories do + @project.issue_categories.each do |category| + api.issue_category(:id => category.id, :name => category.name) + end + end if include_in_api_response?('issue_categories') end diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/projects/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,117 @@ +
    + <% if User.current.allowed_to?(:add_subprojects, @project) %> + <%= link_to l(:label_subproject_new), {:controller => 'projects', :action => 'new', :parent_id => @project}, :class => 'icon icon-add' %> + <% end %> +
    + +<% if @project.has_welcome_page %> +<% page = @project.wiki.find_page("Overview") %> +<% end %> + +<% if page %> + +<% if @project.module_enabled? :wiki %> +<% if User.current.allowed_to?(:edit_wiki_pages, @project) %> +
    +<%= link_to(l(:button_welcome_page_edit_this), {:controller => 'wiki', :action => 'edit', :project_id => @project, :id => Wiki.titleize("Overview")}, :class => 'icon icon-edit') %> +
    +<% end %> +<% end %> + +
    +
      +<% unless @project.homepage.blank? %>
    • <%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %>
    • <% end %> +<% if @subprojects.any? %> +
    • <%=l(:label_subproject_plural)%>: + <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %>
    • +<% end %> +
    +
    + +<%= render(:partial => "wiki/content", :locals => {:content => page.content_for_version()}) %> + +<% else %> + +

    <%=l(:label_overview)%>

    + +
    +
    + <%= textilizable @project.description %> +
    +
      + <% unless @project.homepage.blank? %>
    • <%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %>
    • <% end %> + <% if @subprojects.any? %> +
    • <%=l(:label_subproject_plural)%>: + <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ").html_safe %>
    • + <% end %> + <% @project.visible_custom_field_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
    • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    • + <% end %> + <% end %> +
    + + <% if User.current.allowed_to?(:view_issues, @project) and @open_issues_by_tracker.values.any? %> + +
    +

    <%=l(:label_issue_tracking)%>

    +
      + <% for tracker in @trackers %> +
    • <%= link_to h(tracker.name), :controller => 'issues', :action => 'index', :project_id => @project, + :set_filter => 1, + "tracker_id" => tracker.id %>: + <%= l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i, + :total => @total_issues_by_tracker[tracker].to_i) %> +
    • + <% end %> +
    +

    + <%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 %> + <% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> + | <%= link_to(l(:label_calendar), :controller => 'calendars', :action => 'show', :project_id => @project) %> + <% end %> + <% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> + | <%= link_to(l(:label_gantt), :controller => 'gantts', :action => 'show', :project_id => @project) %> + <% end %> +

    +
    + + <% end %> + + <%= call_hook(:view_projects_show_left, :project => @project) %> +
    + +
    + <%= render :partial => 'members_box' %> + + <% if @news.any? && authorize_for('news', 'index') %> +
    +

    <%=l(:label_news_latest)%>

    + <%= render :partial => 'news/news', :collection => @news %> +

    <%= link_to l(:label_news_view_all), :controller => 'news', :action => 'index', :project_id => @project %>

    +
    + <% end %> + + <%= render :partial => 'activities/recent' %> + + <%= call_hook(:view_projects_show_right, :project => @project) %> +
    + +<% content_for :sidebar do %> + <%= call_hook(:view_projects_show_sidebar_top, :project => @project) %> + <% if @total_hours.present? %> +

    <%= l(:label_spent_time) %>

    +

    <%= l_hours(@total_hours) %>

    +

    <%= link_to(l(:label_details), {:controller => 'timelog', :action => 'index', :project_id => @project}) %> | + <%= link_to(l(:label_report), {:controller => 'time_entry_reports', :action => 'report', :project_id => @project}) %>

    + <% end %> + <%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %> +<% end %> + +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +<% html_title(l(:label_overview)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/projects/show.rhtml --- a/app/views/projects/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -
    - <% if User.current.allowed_to?(:add_subprojects, @project) %> - <%= link_to l(:label_subproject_new), {:controller => 'projects', :action => 'new', :parent_id => @project}, :class => 'icon icon-add' %> - <% end %> -
    - -<% if @project.has_welcome_page %> -<% page = @project.wiki.find_page("Overview") %> -<% end %> - -<% if page %> - -<% if @project.module_enabled? :wiki %> -<% if User.current.allowed_to?(:edit_wiki_pages, @project) %> -
    -<%= link_to(l(:button_welcome_page_edit_this), {:controller => 'wiki', :action => 'edit', :project_id => @project, :id => Wiki.titleize("Overview")}, :class => 'icon icon-edit') %> -
    -<% end %> -<% end %> - -
    -
      -<% unless @project.homepage.blank? %>
    • <%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %>
    • <% end %> -<% if @subprojects.any? %> -
    • <%=l(:label_subproject_plural)%>: - <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %>
    • -<% end %> -
    -
    - -<%= render(:partial => "wiki/content", :locals => {:content => page.content_for_version()}) %> - -<% else %> - -

    <%=l(:label_overview)%>

    - -
    -
    - <%= textilizable @project.description %> -
    -
      - <% unless @project.homepage.blank? %>
    • <%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %>
    • <% end %> - <% if @subprojects.any? %> -
    • <%=l(:label_subproject_plural)%>: - <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %>
    • - <% end %> - <% @project.visible_custom_field_values.each do |custom_value| %> - <% if !custom_value.value.blank? %> -
    • <%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %>
    • - <% end %> - <% end %> -
    - - <% if User.current.allowed_to?(:view_issues, @project) and @open_issues_by_tracker.values.any? %> - -
    -

    <%=l(:label_issue_tracking)%>

    -
      - <% for tracker in @trackers %> -
    • <%= link_to tracker.name, :controller => 'issues', :action => 'index', :project_id => @project, - :set_filter => 1, - "tracker_id" => tracker.id %>: - <%= l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i, - :total => @total_issues_by_tracker[tracker].to_i) %> -
    • - <% end %> -
    -

    - <%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 %> - <% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> - | <%= link_to(l(:label_calendar), :controller => 'calendars', :action => 'show', :project_id => @project) %> - <% end %> - <% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> - | <%= link_to(l(:label_gantt), :controller => 'gantts', :action => 'show', :project_id => @project) %> - <% end %> -

    -
    - - <% end %> - - <%= call_hook(:view_projects_show_left, :project => @project) %> -
    - -
    - <%= render :partial => 'members_box' %> - - <% if @news.any? && authorize_for('news', 'index') %> -
    -

    <%=l(:label_news_latest)%>

    - <%= render :partial => 'news/news', :collection => @news %> -

    <%= link_to l(:label_news_view_all), :controller => 'news', :action => 'index', :project_id => @project %>

    -
    - <% end %> - - <%= render :partial => 'activities/recent' %> - - <%= call_hook(:view_projects_show_right, :project => @project) %> -
    - -<% content_for :sidebar do %> - <%= call_hook(:view_projects_show_sidebar_top, :project => @project) %> - <% if @total_hours.present? %> -

    <%= l(:label_spent_time) %>

    -

    <%= l_hours(@total_hours) %>

    -

    <%= link_to(l(:label_details), {:controller => 'timelog', :action => 'index', :project_id => @project}) %> | - <%= link_to(l(:label_report), {:controller => 'time_entry_reports', :action => 'report', :project_id => @project}) %>

    - <% end %> - <%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %> -<% end %> - -<% end %> - -<% content_for :header_tags do %> -<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %> -<% end %> - -<% html_title(l(:label_overview)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/_columns.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/_columns.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ + + + + + + + +
    + <%= label_tag "available_columns", l(:description_available_columns) %> +
    + <%= select_tag 'available_columns', + options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}), + :multiple => true, :size => 10, :style => "width:150px", + :ondblclick => "moveOptions(this.form.available_columns, this.form.selected_columns);" %> +
    +
    + +
    + <%= label_tag "selected_columns", l(:description_selected_columns) %> +
    + <%= select_tag 'c[]', + options_for_select(query.columns.collect {|column| [column.caption, column.name]}), + :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px", + :ondblclick => "moveOptions(this.form.selected_columns, this.form.available_columns);" %> +
    +
    + +
    + +<% content_for :header_tags do %> +<%= javascript_include_tag 'select_list_move' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/_columns.rhtml --- a/app/views/queries/_columns.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ - - - - - - - -
    <%= select_tag 'available_columns', - options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}), - :multiple => true, :size => 10, :style => "width:150px" %> - -
    - -
    <%= select_tag 'c[]', - options_for_select(query.columns.collect {|column| [column.caption, column.name]}), - :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px" %> - -
    - -
    - -<% content_for :header_tags do %> -<%= javascript_include_tag 'select_list_move' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/_filters.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/_filters.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,155 @@ + + + + + + + +
    + +<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %> + <% field = filter[0] + options = filter[1] %> + id="tr_<%= field %>" class="filter"> + + + + +<% end %> +
    + <%= check_box_tag 'f[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %> + + + <%= label_tag "op_#{field}", l(:description_filter), :class => "hidden-for-sighted" %> + <%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), + query.operator_for(field)), :id => "operators_#{field}", + :onchange => "toggle_operator('#{field}');" %> + + + +
    +
    +<%= label_tag('add_filter_select', l(:label_filter_add)) %> +<%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), + :onchange => "add_filter();", + :name => nil %> +
    +<%= hidden_field_tag 'f[]', '' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/_filters.rhtml --- a/app/views/queries/_filters.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ - - - - - - - -
    - -<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %> - <% field = filter[0] - options = filter[1] %> - id="tr_<%= field %>" class="filter"> - - - - -<% end %> -
    - <%= check_box_tag 'f[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %> - - - <%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %> - - - -
    -
    -<%= label_tag('add_filter_select', l(:label_filter_add)) %>: -<%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), - :onchange => "add_filter();", - :class => "select-small", - :name => nil %> -
    -<%= hidden_field_tag 'f[]', '' %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +<%= error_messages_for 'query' %> + +
    +
    +

    +<%= text_field 'query', 'name', :size => 80 %>

    + +<% if User.current.admin? || User.current.allowed_to?(:manage_public_queries, @project) %> +

    +<%= check_box 'query', 'is_public', + :onchange => (User.current.admin? ? nil : 'if (this.checked) {$("query_is_for_all").checked = false; $("query_is_for_all").disabled = true;} else {$("query_is_for_all").disabled = false;}') %>

    +<% end %> + +

    +<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, + :disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %>

    + +

    +<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', + :onclick => 'if (this.checked) {Element.hide("columns")} else {Element.show("columns")}' %>

    + +

    +<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %>

    +
    + +
    <%= l(:label_filter_plural) %> +<%= render :partial => 'queries/filters', :locals => {:query => query}%> +
    + +
    <%= l(:label_sort) %> +<% 3.times do |i| %> +<%= i+1 %>: +<%= label_tag "query_sort_criteria_attribute_" + i.to_s, + l(:description_query_sort_criteria_attribute), :class => "hidden-for-sighted" %> +<%= select_tag("query[sort_criteria][#{i}][]", + options_for_select([[]] + query.available_columns.select(&:sortable?).collect {|column| [column.caption, column.name.to_s]}, @query.sort_criteria_key(i)), + :id => "query_sort_criteria_attribute_" + i.to_s)%> +<%= label_tag "query_sort_criteria_direction_" + i.to_s, + l(:description_query_sort_criteria_direction), :class => "hidden-for-sighted" %> +<%= select_tag("query[sort_criteria][#{i}][]", + options_for_select([[], [l(:label_ascending), 'asc'], [l(:label_descending), 'desc']], @query.sort_criteria_order(i)), + :id => "query_sort_criteria_direction_" + i.to_s) %> +
    +<% end %> +
    + +<% content_tag 'fieldset', :id => 'columns', :style => (query.has_default_columns? ? 'display:none;' : nil) do %> +<%= l(:field_column_names) %> +<%= render :partial => 'queries/columns', :locals => {:query => query}%> +<% end %> + +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/_form.rhtml --- a/app/views/queries/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -<%= error_messages_for 'query' %> -<%= hidden_field_tag 'confirm', 1 %> - -
    -
    -

    -<%= text_field 'query', 'name', :size => 80 %>

    - -<% if User.current.admin? || User.current.allowed_to?(:manage_public_queries, @project) %> -

    -<%= check_box 'query', 'is_public', - :onchange => (User.current.admin? ? nil : 'if (this.checked) {$("query_is_for_all").checked = false; $("query_is_for_all").disabled = true;} else {$("query_is_for_all").disabled = false;}') %>

    -<% end %> - -

    -<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, - :disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %>

    - -

    -<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', - :onclick => 'if (this.checked) {Element.hide("columns")} else {Element.show("columns")}' %>

    - -

    -<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %>

    -
    - -
    <%= l(:label_filter_plural) %> -<%= render :partial => 'queries/filters', :locals => {:query => query}%> -
    - -
    <%= l(:label_sort) %> -<% 3.times do |i| %> -<%= i+1 %>: <%= select_tag("query[sort_criteria][#{i}][]", - options_for_select([[]] + query.available_columns.select(&:sortable?).collect {|column| [column.caption, column.name.to_s]}, @query.sort_criteria_key(i))) %> - <%= select_tag("query[sort_criteria][#{i}][]", - options_for_select([[], [l(:label_ascending), 'asc'], [l(:label_descending), 'desc']], @query.sort_criteria_order(i))) %>
    -<% end %> -
    - -<% content_tag 'fieldset', :id => 'columns', :style => (query.has_default_columns? ? 'display:none;' : nil) do %> -<%= l(:field_column_names) %> -<%= render :partial => 'queries/columns', :locals => {:query => query}%> -<% end %> - -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_query) %>

    + +<% form_tag(query_path(@query), :onsubmit => 'selectAllOptions("selected_columns");', :method => :put) do %> + <%= render :partial => 'form', :locals => {:query => @query} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/edit.rhtml --- a/app/views/queries/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= l(:label_query) %>

    - -<% form_tag({:action => 'edit', :id => @query}, :onsubmit => 'selectAllOptions("selected_columns");') do %> - <%= render :partial => 'form', :locals => {:query => @query} %> - <%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/index.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +api.array :queries, api_meta(:total_count => @query_count, :offset => @offset, :limit => @limit) do + @queries.each do |query| + api.query do + api.id query.id + api.name query.name + api.is_public query.is_public + api.project_id query.project_id + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +
    +<%= link_to_if_authorized l(:label_query_new), new_project_query_path(:project_id => @project), :class => 'icon icon-add' %> +
    + +

    <%= l(:label_query_plural) %>

    + +<% if @queries.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> + + <% @queries.each do |query| %> + + + + + <% end %> +
    + <%= link_to h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %> + + + <% if query.editable_by?(User.current) %> + <%= link_to l(:button_edit), edit_query_path(query), :class => 'icon icon-edit' %> + <%= link_to l(:button_delete), query_path(query), :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %> + + <% end %> +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/index.rhtml --- a/app/views/queries/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -
    -<%= link_to_if_authorized l(:label_query_new), {:controller => 'queries', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %> -
    - -

    <%= l(:label_query_plural) %>

    - -<% if @queries.empty? %> -

    <%=l(:label_no_data)%>

    -<% else %> - - <% @queries.each do |query| %> - - - - - <% end %> -
    - <%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %> - - - <% if query.editable_by?(User.current) %> - <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => query}, :class => 'icon icon-edit' %> - <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> - - <% end %> -
    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/queries/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= l(:label_query_new) %>

    + +<% form_tag(@project ? project_queries_path : queries_path, :onsubmit => 'selectAllOptions("selected_columns");') do %> + <%= render :partial => 'form', :locals => {:query => @query} %> + <%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/queries/new.rhtml --- a/app/views/queries/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= l(:label_query_new) %>

    - -<% form_tag({:action => 'new', :project_id => @query.project}, :onsubmit => 'selectAllOptions("selected_columns");') do %> - <%= render :partial => 'form', :locals => {:query => @query} %> - <%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/_details.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/reports/_details.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,53 @@ +<% if @statuses.empty? or rows.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> +<% col_width = 70 / (@statuses.length+3) %> + + + +<% for status in @statuses %> + +<% end %> + + + + + +<% for row in rows %> +"> + + <% for status in @statuses %> + + <% end %> + + + + +<% end %> + +
    <%=h status.name %><%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to h(row.name), :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "status_id" => status.id }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "status_id" => status.id, + "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "o" %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "c" %><%= aggregate_link data, { field_name => row.id }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "*" %>
    +<% end + reset_cycle %> diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/_details.rhtml --- a/app/views/reports/_details.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -<% if @statuses.empty? or rows.empty? %> -

    <%=l(:label_no_data)%>

    -<% else %> -<% col_width = 70 / (@statuses.length+3) %> - - - -<% for status in @statuses %> - -<% end %> - - - - - -<% for row in rows %> -"> - - <% for status in @statuses %> - - <% end %> - - - - -<% end %> - -
    <%= status.name %><%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "status_id" => status.id }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "status_id" => status.id, - "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id, - "status_id" => "o" %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id, - "status_id" => "c" %><%= aggregate_link data, { field_name => row.id }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id, - "status_id" => "*" %>
    -<% end - reset_cycle %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/_simple.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/reports/_simple.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<% if @statuses.empty? or rows.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> + + + + + + + + +<% for row in rows %> +"> + + + + + +<% end %> + +
    <%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to h(row.name), :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "o" %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "c" %><%= aggregate_link data, { field_name => row.id }, + :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), + :set_filter => 1, + :subproject_id => '!*', + "#{field_name}" => row.id, + "status_id" => "*" %>
    +<% end + reset_cycle %> diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/_simple.rhtml --- a/app/views/reports/_simple.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -<% if @statuses.empty? or rows.empty? %> -

    <%=l(:label_no_data)%>

    -<% else %> - - - - - - - - -<% for row in rows %> -"> - - - - - -<% end %> - -
    <%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id, - "status_id" => "o" %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id, - "status_id" => "c" %><%= aggregate_link data, { field_name => row.id }, - :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)), - :set_filter => 1, - :subproject_id => '!*', - "#{field_name}" => row.id, - "status_id" => "*" %>
    -<% end - reset_cycle %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/issue_report.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/reports/issue_report.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,33 @@ +

    <%=l(:label_report_plural)%>

    + +
    +

    <%=l(:field_tracker)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'tracker' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> +
    +

    <%=l(:field_priority)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'priority' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> +
    +

    <%=l(:field_assigned_to)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'assigned_to' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => "assigned_to_id", :rows => @assignees } %> +
    +

    <%=l(:field_author)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'author' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> +
    +<%= call_hook(:view_reports_issue_report_split_content_left, :project => @project) %> +
    + +
    +

    <%=l(:field_version)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'version' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_version, :field_name => "fixed_version_id", :rows => @versions } %> +
    +<% if @project.children.any? %> +

    <%=l(:field_subproject)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'subproject' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => "project_id", :rows => @subprojects } %> +
    +<% end %> +

    <%=l(:field_category)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'category' %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> +
    +<%= call_hook(:view_reports_issue_report_split_content_right, :project => @project) %> +
    + diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/issue_report.rhtml --- a/app/views/reports/issue_report.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -

    <%=l(:label_report_plural)%>

    - -
    -

    <%=l(:field_tracker)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'tracker' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> -
    -

    <%=l(:field_priority)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'priority' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> -
    -

    <%=l(:field_assigned_to)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'assigned_to' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => "assigned_to_id", :rows => @assignees } %> -
    -

    <%=l(:field_author)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'author' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> -
    -<%= call_hook(:view_reports_issue_report_split_content_left, :project => @project) %> -
    - -
    -

    <%=l(:field_version)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'version' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_version, :field_name => "fixed_version_id", :rows => @versions } %> -
    -<% if @project.children.any? %> -

    <%=l(:field_subproject)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'subproject' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => "project_id", :rows => @subprojects } %> -
    -<% end %> -

    <%=l(:field_category)%>  <%= link_to image_tag('zoom_in.png'), :action => 'issue_report_details', :detail => 'category' %>

    -<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> -
    -<%= call_hook(:view_reports_issue_report_split_content_right, :project => @project) %> -
    - diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/issue_report_details.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/reports/issue_report_details.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +

    <%=l(:label_report_plural)%>

    + +

    <%=@report_title%>

    +<%= render :partial => 'details', :locals => { :data => @data, :field_name => @field, :rows => @rows } %> +
    +<%= link_to l(:button_back), :action => 'issue_report' %> + diff -r 487d96eac004 -r 5e80956cc792 app/views/reports/issue_report_details.rhtml --- a/app/views/reports/issue_report_details.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -

    <%=l(:label_report_plural)%>

    - -

    <%=@report_title%>

    -<%= render :partial => 'details', :locals => { :data => @data, :field_name => @field, :rows => @rows } %> -
    -<%= link_to l(:button_back), :action => 'issue_report' %> - diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_breadcrumbs.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_breadcrumbs.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev %> +<% +dirs = path.split('/') +if 'file' == kind + filename = dirs.pop +end +link_path = '' +dirs.each do |dir| + next if dir.blank? + link_path << '/' unless link_path.empty? + link_path << "#{dir}" + %> + / <%= link_to h(dir), :action => 'show', :id => @project, + :path => to_path_param(link_path), :rev => @rev %> +<% end %> +<% if filename %> + / <%= link_to h(filename), + :action => 'changes', :id => @project, + :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> +<% end %> +<% + # @rev is revsion or Git and Mercurial branch or tag. + # For Mercurial *tip*, @rev and @changeset are nil. + rev_text = @changeset.nil? ? @rev : format_revision(@changeset) +%> +<%= "@ #{h rev_text}" unless rev_text.blank? %> + +<% html_title(with_leading_slash(path)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_breadcrumbs.rhtml --- a/app/views/repositories/_breadcrumbs.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -<%= link_to 'root', :action => 'show', :id => @project, :path => '', :rev => @rev %> -<% -dirs = path.split('/') -if 'file' == kind - filename = dirs.pop -end -link_path = '' -dirs.each do |dir| - next if dir.blank? - link_path << '/' unless link_path.empty? - link_path << "#{dir}" - %> - / <%= link_to h(dir), :action => 'show', :id => @project, - :path => to_path_param(link_path), :rev => @rev %> -<% end %> -<% if filename %> - / <%= link_to h(filename), - :action => 'changes', :id => @project, - :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> -<% end %> -<% - # @rev is revsion or Git and Mercurial branch or tag. - # For Mercurial *tip*, @rev and @changeset are nil. - rev_text = @changeset.nil? ? @rev : format_revision(@changeset) -%> -<%= "@ #{h rev_text}" unless rev_text.blank? %> - -<% html_title(with_leading_slash(path)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_dir_list.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_dir_list.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ + + + + + +<% if @repository.report_last_commit %> + + + + +<% end %> + + + +<%= render :partial => 'dir_list_content' %> + +
    <%= l(:field_name) %><%= l(:field_filesize) %><%= l(:label_revision) %><%= l(:label_age) %><%= l(:field_author) %><%= l(:field_comments) %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_dir_list.rhtml --- a/app/views/repositories/_dir_list.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ - - - - - -<% if @repository.report_last_commit %> - - - - -<% end %> - - - -<%= render :partial => 'dir_list_content' %> - -
    <%= l(:field_name) %><%= l(:field_filesize) %><%= l(:label_revision) %><%= l(:label_age) %><%= l(:field_author) %><%= l(:field_comments) %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_dir_list_content.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_dir_list_content.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +<% @entries.each do |entry| %> +<% tr_id = Digest::MD5.hexdigest(entry.path) + depth = params[:depth].to_i %> +<% ent_path = Redmine::CodesetUtil.replace_invalid_utf8(entry.path) %> +<% ent_name = Redmine::CodesetUtil.replace_invalid_utf8(entry.name) %> + +";> +<% if entry.is_dir? %> + "scmEntryClick('#{tr_id}')" + ) %>">  +<% end %> +<%= link_to h(ent_name), + {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(ent_path), :rev => @rev}, + :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(ent_name)}")%> + +<%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> +<% changeset = @project.repository.find_changeset_by_name(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> +<% if @repository.report_last_commit %> +<%= link_to_revision(changeset, @project) if changeset %> +<%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> +<%= changeset.nil? ? h(Redmine::CodesetUtil.replace_invalid_utf8(entry.lastrev.author.to_s.split('<').first)) : h(changeset.author) if entry.lastrev %> +<%=h truncate(changeset.comments, :length => 50) unless changeset.nil? %> +<% end %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_dir_list_content.rhtml --- a/app/views/repositories/_dir_list_content.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -<% @entries.each do |entry| %> -<% tr_id = Digest::MD5.hexdigest(entry.path) - depth = params[:depth].to_i %> -<% ent_path = Redmine::CodesetUtil.replace_invalid_utf8(entry.path) %> -<% ent_name = Redmine::CodesetUtil.replace_invalid_utf8(entry.name) %> - -";> -<% if entry.is_dir? %> - "scmEntryClick('#{tr_id}')"%>">  -<% end %> -<%= link_to h(ent_name), - {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :path => to_path_param(ent_path), :rev => @rev}, - :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(ent_name)}")%> - -<%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> -<% changeset = @project.repository.find_changeset_by_name(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> -<% if @repository.report_last_commit %> -<%= link_to_revision(changeset, @project) if changeset %> -<%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> -<%= changeset.nil? ? h(Redmine::CodesetUtil.replace_invalid_utf8(entry.lastrev.author.to_s.split('<').first)) : changeset.author if entry.lastrev %> -<%=h truncate(changeset.comments, :length => 50) unless changeset.nil? %> -<% end %> - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_link_to_functions.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_link_to_functions.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +<% if @entry && @entry.kind == 'file' %> + +

    +<%= link_to_if action_name != 'changes', l(:label_history), {:action => 'changes', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | +<% if @repository.supports_cat? %> + <%= link_to_if action_name != 'entry', l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | +<% end %> +<% if @repository.supports_annotate? %> + <%= link_to_if action_name != 'annotate', l(:button_annotate), {:action => 'annotate', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | +<% end %> +<%= link_to(l(:button_download), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev, :format => 'raw' }) if @repository.supports_cat? %> +<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %> +

    + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_link_to_functions.rhtml --- a/app/views/repositories/_link_to_functions.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -<% if @entry && @entry.kind == 'file' %> - -

    -<%= link_to_if action_name != 'changes', l(:label_history), {:action => 'changes', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | -<% if @repository.supports_cat? %> - <%= link_to_if action_name != 'entry', l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | -<% end %> -<% if @repository.supports_annotate? %> - <%= link_to_if action_name != 'annotate', l(:button_annotate), {:action => 'annotate', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | -<% end %> -<%= link_to(l(:button_download), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev, :format => 'raw' }) if @repository.supports_cat? %> -<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %> -

    - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_navigation.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_navigation.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +<% content_for :header_tags do %> + <%= javascript_include_tag 'repository_navigation' %> +<% end %> + +<%= link_to_revision_archive(@repository, @rev, @project, { :text => l(:label_download_revision), :class => 'icon icon-package' }) %> + +<% form_tag({:action => controller.action_name, :id => @project, :path => to_path_param(@path), :rev => ''}, {:method => :get, :id => 'revision_selector'}) do -%> + + <% if !@repository.branches.nil? && @repository.branches.length > 0 -%> + | <%= l(:label_branch) %>: + <%= select_tag :branch, options_for_select([''] + @repository.branches,@rev), :id => 'branch' %> + <% end -%> + + <% if !@repository.tags.nil? && @repository.tags.length > 0 -%> + | <%= l(:label_tag) %>: + <%= select_tag :tag, options_for_select([''] + @repository.tags,@rev), :id => 'tag' %> + <% end -%> + + | <%= l(:label_revision) %>: + <%= text_field_tag 'rev', @rev, :size => 8 %> +<% end -%> + + diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_navigation.rhtml --- a/app/views/repositories/_navigation.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -<% content_for :header_tags do %> - <%= javascript_include_tag 'repository_navigation' %> -<% end %> - -<%= link_to_revision_archive(@repository, @rev, @project, { :text => l(:label_download_revision), :class => 'icon icon-package' }) %> - -<% form_tag({:action => controller.action_name, :id => @project, :path => to_path_param(@path), :rev => ''}, {:method => :get, :id => 'revision_selector'}) do -%> - - <% if !@repository.branches.nil? && @repository.branches.length > 0 -%> - | <%= l(:label_branch) %>: - <%= select_tag :branch, options_for_select([''] + @repository.branches,@rev), :id => 'branch' %> - <% end -%> - - <% if !@repository.tags.nil? && @repository.tags.length > 0 -%> - | <%= l(:label_tag) %>: - <%= select_tag :tag, options_for_select([''] + @repository.tags,@rev), :id => 'tag' %> - <% end -%> - - | <%= l(:label_revision) %>: - <%= text_field_tag 'rev', @rev, :size => 8 %> -<% end -%> - - diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_revision_graph.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_revision_graph.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +<%= javascript_include_tag "raphael.js" %> + +<%= javascript_include_tag "revision_graph.js" %> + + + +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_revisions.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/_revisions.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +<% show_revision_graph = ( @repository.supports_revision_graph? && path.blank? ) %> +<% form_tag({:controller => 'repositories', :action => 'diff', :id => @project, :path => to_path_param(path)}, :method => :get) do %> + + +<% if show_revision_graph %> + +<% end %> + + + + + + + + +<% show_diff = revisions.size > 1 %> +<% line_num = 1 %> +<% revisions.each do |changeset| %> + +<% if show_revision_graph %> + <% if line_num == 1 %> + + <% end %> +<% end %> + + + + + +<% if show_revision_graph %> + +<% else %> + +<% end %> + +<% line_num += 1 %> +<% end %> + +
    #<%= l(:label_date) %><%= l(:field_author) %><%= l(:field_comments) %>
    + <% href_base = Proc.new {|x| url_for(:controller => 'repositories', + :action => 'revision', + :id => project, + :rev => x) } %> + <%= render :partial => 'revision_graph', + :locals => { + :commits => index_commits( + revisions, + @repository.branches, + href_base + ) + } %> + <%= link_to_revision(changeset, project) %><%= radio_button_tag('rev', changeset.identifier, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %><%= radio_button_tag('rev_to', changeset.identifier, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %><%= format_time(changeset.committed_on) %><%= h truncate(changeset.author.to_s, :length => 30) %> + <%= textilizable(truncate(truncate_at_line_break(changeset.comments, 0), :length => 90)) %> + <%= textilizable(truncate_at_line_break(changeset.comments)) %>
    +<%= submit_tag(l(:label_view_diff), :name => nil) if show_diff %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/_revisions.rhtml --- a/app/views/repositories/_revisions.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -<% form_tag({:controller => 'repositories', :action => 'diff', :id => @project, :path => to_path_param(path)}, :method => :get) do %> - - - - - - - - - - -<% show_diff = revisions.size > 1 %> -<% line_num = 1 %> -<% revisions.each do |changeset| %> - - - - - - - - -<% line_num += 1 %> -<% end %> - -
    #<%= l(:label_date) %><%= l(:field_author) %><%= l(:field_comments) %>
    <%= link_to_revision(changeset, project) %><%= radio_button_tag('rev', changeset.identifier, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %><%= radio_button_tag('rev_to', changeset.identifier, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %><%= format_time(changeset.committed_on) %><%=h changeset.author %><%= textilizable(truncate_at_line_break(changeset.comments)) %>
    -<%= submit_tag(l(:label_view_diff), :name => nil) if show_diff %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/annotate.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/annotate.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,36 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    + +

    <%= render :partial => 'link_to_functions' %>

    + +<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> + +
    + + + <% line_num = 1 %> + <% syntax_highlight(@path, Redmine::CodesetUtil.to_utf8_by_setting(@annotate.content)).each_line do |line| %> + <% revision = @annotate.revisions[line_num - 1] %> + + + + + + + <% line_num += 1 %> + <% end %> + +
    <%= line_num %> + <%= (revision.identifier ? link_to_revision(revision, @project) : format_revision(revision)) if revision %><%= h(revision.author.to_s.split('<').first) if revision %>
    <%= line %>
    +
    + +<% html_title(l(:button_annotate)) -%> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/annotate.rhtml --- a/app/views/repositories/annotate.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> - -
    - <%= render :partial => 'navigation' %> -
    - -

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    - -

    <%= render :partial => 'link_to_functions' %>

    - -<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> - -
    - - - <% line_num = 1 %> - <% syntax_highlight(@path, to_utf8(@annotate.content)).each_line do |line| %> - <% revision = @annotate.revisions[line_num-1] %> - - - - - - - <% line_num += 1 %> - <% end %> - -
    <%= line_num %> - <%= (revision.identifier ? link_to_revision(revision, @project) : format_revision(revision)) if revision %><%= h(revision.author.to_s.split('<').first) if revision %>
    <%= line %>
    -
    - -<% html_title(l(:button_annotate)) -%> - -<% content_for :header_tags do %> -<%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/changes.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/changes.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    + <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %> +

    + +

    <%= render :partial => 'link_to_functions' %>

    + +<%= render_properties(@properties) %> + +<%= render(:partial => 'revisions', + :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %> + +<% html_title(l(:label_change_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/changes.rhtml --- a/app/views/repositories/changes.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> - -
    - <%= render :partial => 'navigation' %> -
    - -

    - <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %> -

    - -

    <%= render :partial => 'link_to_functions' %>

    - -<%= render_properties(@properties) %> - -<%= render(:partial => 'revisions', - :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %> - -<% html_title(l(:label_change_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/committers.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/committers.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ +

    <%= l(:label_repository) %>

    + +<%= simple_format(l(:text_repository_usernames_mapping)) %> + +<% if @committers.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> + +<% form_tag({}) do %> + + + + + + + + +<% i = 0 -%> +<% @committers.each do |committer, user_id| -%> + + + + + <% i += 1 -%> +<% end -%> + +
    <%= l(:field_login) %><%= l(:label_user) %>
    <%=h committer %> + <%= hidden_field_tag "committers[#{i}][]", committer %> + <%= select_tag "committers[#{i}][]", content_tag('option', "-- #{l :actionview_instancetag_blank_option} --", :value => '') + options_from_collection_for_select(@users, 'id', 'name', user_id.to_i) %> +
    +

    <%= submit_tag(l(:button_update)) %>

    +<% end %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/committers.rhtml --- a/app/views/repositories/committers.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -

    <%= l(:label_repository) %>

    - -<%= simple_format(l(:text_repository_usernames_mapping)) %> - -<% if @committers.empty? %> -

    <%= l(:label_no_data) %>

    -<% else %> - -<% form_tag({}) do %> - - - - - - - - -<% i = 0 -%> -<% @committers.each do |committer, user_id| -%> - - - - - <% i += 1 -%> -<% end -%> - -
    <%= l(:field_login) %><%= l(:label_user) %>
    <%=h committer %> - <%= hidden_field_tag "committers[#{i}][]", committer %> - <%= select_tag "committers[#{i}][]", content_tag('option', "-- #{l :actionview_instancetag_blank_option} --", :value => '') + options_from_collection_for_select(@users, 'id', 'name', user_id.to_i) %> -
    -

    <%= submit_tag(l(:button_update)) %>

    -<% end %> - -<% end %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/diff.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/diff.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,28 @@ +

    <%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %>

    + + +<% form_tag({:path => to_path_param(@path)}, :method => 'get') do %> + <%= hidden_field_tag('rev', params[:rev]) if params[:rev] %> + <%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %> +

    + + <%= select_tag 'type', + options_for_select( + [[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), + :onchange => "if (this.value != '') {this.form.submit()}" %> +

    +<% end %> + +<% cache(@cache_key) do -%> +<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %> +<% end -%> + +<% other_formats_links do |f| %> + <%= f.link_to 'Diff', :url => params, :caption => 'Unified diff' %> +<% end %> + +<% html_title(with_leading_slash(@path), 'Diff') -%> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/diff.rhtml --- a/app/views/repositories/diff.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -

    <%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %>

    - - -<% form_tag({:path => to_path_param(@path)}, :method => 'get') do %> - <%= hidden_field_tag('rev', params[:rev]) if params[:rev] %> - <%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %> -

    - <%= select_tag 'type', options_for_select([[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), :onchange => "if (this.value != '') {this.form.submit()}" %>

    -<% end %> - -<% cache(@cache_key) do -%> -<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %> -<% end -%> - -<% other_formats_links do |f| %> - <%= f.link_to 'Diff', :url => params, :caption => 'Unified diff' %> -<% end %> - -<% html_title(with_leading_slash(@path), 'Diff') -%> - -<% content_for :header_tags do %> -<%= stylesheet_link_tag "scm" %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/entry.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/entry.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    + +

    <%= render :partial => 'link_to_functions' %>

    + +<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/entry.rhtml --- a/app/views/repositories/entry.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> - -
    - <%= render :partial => 'navigation' %> -
    - -

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    - -

    <%= render :partial => 'link_to_functions' %>

    - -<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %> - -<% content_for :header_tags do %> -<%= stylesheet_link_tag "scm" %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/revision.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/revision.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,102 @@ +
    + + <%= link_to_revision_archive(@repository, @changeset, @project, { :text => l(:label_download_revision), :class => 'icon icon-package' }) %> +    + + « + <% unless @changeset.previous.nil? -%> + <%= link_to_revision(@changeset.previous, @project, :text => l(:label_previous)) %> + <% else -%> + <%= l(:label_previous) %> + <% end -%> + + <% unless @changeset.next.nil? -%> + <%= link_to_revision(@changeset.next, @project, :text => l(:label_next)) %> + <% else -%> + <%= l(:label_next) %> + <% end -%> + »  + + <% form_tag({:controller => 'repositories', + :action => 'revision', + :id => @project, + :rev => nil}, + :method => :get) do %> + <%= text_field_tag 'rev', @rev, :size => 8 %> + <%= submit_tag 'OK', :name => nil %> + <% end %> + +
    + +

    <%= l(:label_revision) %> <%= format_revision(@changeset) %>

    + + + <% if @changeset.scmid %> + + + + <% end %> + <% unless @changeset.parents.blank? %> + + + + + <% end %> + <% unless @changeset.children.blank? %> + + + + + <% end %> +
    ID<%= h(@changeset.scmid) %>
    <%= l(:label_parent_revision) %> + <%= @changeset.parents.collect{ + |p| link_to_revision(p, @project, :text => format_revision(p)) + }.join(", ") %> +
    <%= l(:label_child_revision) %> + <%= @changeset.children.collect{ + |p| link_to_revision(p, @project, :text => format_revision(p)) + }.join(", ") %> +
    +

    + +<%= authoring(@changeset.committed_on, @changeset.author) %> + +

    + +<%= textilizable @changeset.comments %> + +<% if @changeset.issues.visible.any? %> +

    <%= l(:label_related_issues) %>

    +
      +<% @changeset.issues.visible.each do |issue| %> +
    • <%= link_to_issue issue %>
    • +<% end %> +
    +<% end %> + +<% if User.current.allowed_to?(:browse_repository, @project) %> +

    <%= l(:label_attachment_plural) %>

    +
      +
    • <%= l(:label_added) %>
    • +
    • <%= l(:label_modified) %>
    • +
    • <%= l(:label_copied) %>
    • +
    • <%= l(:label_renamed) %>
    • +
    • <%= l(:label_deleted) %>
    • +
    + +

    <%= link_to(l(:label_view_diff), + :action => 'diff', + :id => @project, + :path => "", + :rev => @changeset.identifier) if @changeset.changes.any? %>

    + +
    +<%= render_changeset_changes %> +
    +<% end %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title("#{l(:label_revision)} #{format_revision(@changeset)}") -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/revision.rhtml --- a/app/views/repositories/revision.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -
    - - <%= link_to_revision_archive(@repository, @changeset, @project, { :text => l(:label_download_revision), :class => 'icon icon-package' }) %> -    - - « - <% unless @changeset.previous.nil? -%> - <%= link_to_revision(@changeset.previous, @project, :text => l(:label_previous)) %> - <% else -%> - <%= l(:label_previous) %> - <% end -%> - - <% unless @changeset.next.nil? -%> - <%= link_to_revision(@changeset.next, @project, :text => l(:label_next)) %> - <% else -%> - <%= l(:label_next) %> - <% end -%> - »  - - <% form_tag({:controller => 'repositories', - :action => 'revision', - :id => @project, - :rev => nil}, - :method => :get) do %> - <%= text_field_tag 'rev', @rev, :size => 8 %> - <%= submit_tag 'OK', :name => nil %> - <% end %> - -
    - -

    <%= l(:label_revision) %> <%= format_revision(@changeset) %>

    - -

    <% if @changeset.scmid %>ID: <%= @changeset.scmid %>
    <% end %> -<%= authoring(@changeset.committed_on, @changeset.author) %>

    - -<%= textilizable @changeset.comments %> - -<% if @changeset.issues.visible.any? %> -

    <%= l(:label_related_issues) %>

    -
      -<% @changeset.issues.visible.each do |issue| %> -
    • <%= link_to_issue issue %>
    • -<% end %> -
    -<% end %> - -<% if User.current.allowed_to?(:browse_repository, @project) %> -

    <%= l(:label_attachment_plural) %>

    -
      -
    • <%= l(:label_added) %>
    • -
    • <%= l(:label_modified) %>
    • -
    • <%= l(:label_copied) %>
    • -
    • <%= l(:label_renamed) %>
    • -
    • <%= l(:label_deleted) %>
    • -
    - -

    <%= link_to(l(:label_view_diff), - :action => 'diff', - :id => @project, - :path => "", - :rev => @changeset.identifier) if @changeset.changes.any? %>

    - -
    -<%= render_changeset_changes %> -
    -<% end %> - -<% content_for :header_tags do %> -<%= stylesheet_link_tag "scm" %> -<% end %> - -<% html_title("#{l(:label_revision)} #{format_revision(@changeset)}") -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/revisions.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/revisions.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +
    +<% form_tag({:action => 'revision', :id => @project}) do %> +<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %> +<%= submit_tag 'OK' %> +<% end %> +
    + +

    <%= l(:label_revision_plural) %>

    + +<%= render :partial => 'revisions', + :locals => {:project => @project, + :path => '', + :revisions => @changesets, + :entry => nil } %> + +

    <%= pagination_links_full @changeset_pages,@changeset_count %>

    + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<%= auto_discovery_link_tag( + :atom, + params.merge( + {:format => 'atom', :page => nil, :key => User.current.rss_key})) %> +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title(l(:label_revision_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/revisions.rhtml --- a/app/views/repositories/revisions.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -
    -<% form_tag({:action => 'revision', :id => @project}) do %> -<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %> -<%= submit_tag 'OK' %> -<% end %> -
    - -

    <%= l(:label_revision_plural) %>

    - -<%= render :partial => 'revisions', - :locals => {:project => @project, - :path => '', - :revisions => @changesets, - :entry => nil } %> - -

    <%= pagination_links_full @changeset_pages,@changeset_count %>

    - -<% content_for :header_tags do %> -<%= stylesheet_link_tag "scm" %> -<%= auto_discovery_link_tag( - :atom, - params.merge( - {:format => 'atom', :page => nil, :key => User.current.rss_key})) %> -<% end %> - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> -<% end %> - -<% html_title(l(:label_revision_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,69 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %>

    + +<% if !@entries.nil? && authorize_for('repositories', 'browse') %> +<%= render :partial => 'dir_list' %> +<% end %> + +<%= render_properties(@properties) %> + +<% if authorize_for('repositories', 'revisions') %> +<% if @changesets && !@changesets.empty? %> +

    <%= l(:label_latest_revision_plural) %>

    +<%= render :partial => 'revisions', + :locals => {:project => @project, :path => @path, + :revisions => @changesets, :entry => nil }%> +<% end %> +

    +<% + has_branches = (!@repository.branches.nil? && @repository.branches.length > 0) + sep = '' + %> +<% if @repository.supports_all_revisions? && @path.blank? %> +<%= link_to l(:label_view_all_revisions), :action => 'revisions', :id => @project %> +<% sep = '|' %> +<% end %> +<% + if @repository.supports_directory_revisions? && + ( has_branches || !@path.blank? || !@rev.blank? ) + %> +<%= sep %> +<%= + link_to l(:label_view_revisions), + :action => 'changes', + :path => to_path_param(@path), + :id => @project, + :rev => @rev + %> +<% end %> +

    + +<% if true # @path.blank? %> +<% content_for :header_tags do %> + <%= auto_discovery_link_tag( + :atom, params.merge( + {:format => 'atom', :action => 'revisions', + :id => @project, :page => nil, :key => User.current.rss_key})) %> +<% end %> + +

    +<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> +

    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %> +<% end %> + +<% end %> +<% end %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title(l(:label_repository)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/show.rhtml --- a/app/views/repositories/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> - -
    - <%= render :partial => 'navigation' %> -
    - -

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %>

    - -<% if !@entries.nil? && authorize_for('repositories', 'browse') %> -<%= render :partial => 'dir_list' %> -<% end %> - -<%= render_properties(@properties) %> - -<% if authorize_for('repositories', 'revisions') %> -<% if @changesets && !@changesets.empty? %> -

    <%= l(:label_latest_revision_plural) %>

    -<%= render :partial => 'revisions', - :locals => {:project => @project, :path => @path, - :revisions => @changesets, :entry => nil }%> -<% end %> -

    -<% - has_branches = (!@repository.branches.nil? && @repository.branches.length > 0) - sep = '' - %> -<% if @repository.supports_all_revisions? && @path.blank? %> -<%= link_to l(:label_view_all_revisions), :action => 'revisions', :id => @project %> -<% sep = '|' %> -<% end %> -<% - if @repository.supports_directory_revisions? && - ( has_branches || !@path.blank? || !@rev.blank? ) - %> -<%= sep %> -<%= - link_to l(:label_view_revisions), - :action => 'changes', - :path => to_path_param(@path), - :id => @project, - :rev => @rev - %> -<% end %> -

    - -<% if true # @path.blank? %> -<% content_for :header_tags do %> - <%= auto_discovery_link_tag( - :atom, params.merge( - {:format => 'atom', :action => 'revisions', - :id => @project, :page => nil, :key => User.current.rss_key})) %> -<% end %> - -

    -<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> -

    - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %> -<% end %> - -<% end %> -<% end %> - -<% content_for :header_tags do %> -<%= stylesheet_link_tag "scm" %> -<% end %> - -<% html_title(l(:label_repository)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/stats.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/repositories/stats.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +

    <%= l(:label_statistics) %>

    + +

    +<%= tag("embed", :width => 800, :height => 300, :type => "image/svg+xml", :src => url_for(:controller => 'repositories', :action => 'graph', :id => @project, :graph => "commits_per_month")) %> +

    +

    +<%= tag("embed", :width => 800, :height => 400, :type => "image/svg+xml", :src => url_for(:controller => 'repositories', :action => 'graph', :id => @project, :graph => "commits_per_author")) %> +

    + +

    <%= link_to l(:button_back), :action => 'show', :id => @project %>

    + +<% html_title(l(:label_repository), l(:label_statistics)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/repositories/stats.rhtml --- a/app/views/repositories/stats.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -

    <%= l(:label_statistics) %>

    - -

    -<%= tag("embed", :width => 800, :height => 300, :type => "image/svg+xml", :src => url_for(:controller => 'repositories', :action => 'graph', :id => @project, :graph => "commits_per_month")) %> -

    -

    -<%= tag("embed", :width => 800, :height => 400, :type => "image/svg+xml", :src => url_for(:controller => 'repositories', :action => 'graph', :id => @project, :graph => "commits_per_author")) %> -

    - -

    <%= link_to l(:button_back), :action => 'show', :id => @project %>

    - -<% html_title(l(:label_repository), l(:label_statistics)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/roles/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,30 @@ +<%= error_messages_for 'role' %> + +
    +<% unless @role.builtin? %> +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.check_box :assignable %>

    +<% end %> +

    <%= f.select :issues_visibility, Role::ISSUES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %>

    +<% if @role.new_record? && @roles.any? %> +

    +<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@roles, :id, :name)) %>

    +<% end %> +
    + +

    <%= l(:label_permissions) %>

    +
    +<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> +<% perms_by_module.keys.sort.each do |mod| %> +
    <%= mod.blank? ? l(:label_project) : l_or_humanize(mod, :prefix => 'project_module_') %> + <% perms_by_module[mod].each do |permission| %> + + <% end %> +
    +<% end %> +
    <%= check_all_links 'permissions' %> +<%= hidden_field_tag 'role[permissions][]', '' %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/_form.rhtml --- a/app/views/roles/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -<%= error_messages_for 'role' %> - -
    -<% unless @role.builtin? %> -

    <%= f.text_field :name, :required => true %>

    -

    <%= f.check_box :assignable %>

    -<% end %> -

    <%= f.select :issues_visibility, Role::ISSUES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %>

    -<% if @role.new_record? && @roles.any? %> -

    -<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@roles, :id, :name)) %>

    -<% end %> -
    - -

    <%= l(:label_permissions) %>

    -
    -<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> -<% perms_by_module.keys.sort.each do |mod| %> -
    <%= mod.blank? ? l(:label_project) : l_or_humanize(mod, :prefix => 'project_module_') %> - <% perms_by_module[mod].each do |permission| %> - - <% end %> -
    -<% end %> -
    <%= check_all_links 'permissions' %> -<%= hidden_field_tag 'role[permissions][]', '' %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/roles/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=h @role.name %>

    + +<% labelled_tabular_form_for :role, @role, :url => { :action => 'edit' }, :html => {:id => 'role_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/edit.rhtml --- a/app/views/roles/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=h @role.name %>

    - -<% labelled_tabular_form_for :role, @role, :url => { :action => 'edit' }, :html => {:id => 'role_form'} do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/index.html.erb --- a/app/views/roles/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/roles/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -8,12 +8,12 @@ <%=l(:label_role)%> <%=l(:button_sort)%> - + <% for role in @roles %> "> - <%= content_tag(role.builtin? ? 'em' : 'span', link_to(role.name, :action => 'edit', :id => role)) %> + <%= content_tag(role.builtin? ? 'em' : 'span', link_to(h(role.name), :action => 'edit', :id => role)) %> <% unless role.builtin? %> <%= reorder_links('role', {:action => 'edit', :id => role}) %> @@ -21,9 +21,9 @@ <%= link_to(l(:button_delete), { :action => 'destroy', :id => role }, - :method => :post, - :confirm => l(:text_are_you_sure), - :class => 'icon icon-del') unless role.builtin? %> + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') unless role.builtin? %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/roles/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=l(:label_role_new)%>

    + +<% labelled_tabular_form_for :role, @role, :url => { :action => 'new' }, :html => {:id => 'role_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/new.rhtml --- a/app/views/roles/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=l(:label_role_new)%>

    - -<% labelled_tabular_form_for :role, @role, :url => { :action => 'new' }, :html => {:id => 'role_form'} do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/report.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/roles/report.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,52 @@ +

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=l(:label_permissions_report)%>

    + +<% form_tag({:action => 'report'}, :id => 'permissions_form') do %> +<%= hidden_field_tag 'permissions[0]', '', :id => nil %> +
    + + + + + <% @roles.each do |role| %> + + <% end %> + + + +<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> +<% perms_by_module.keys.sort.each do |mod| %> + <% unless mod.blank? %> + + + + <% end %> + <% perms_by_module[mod].each do |permission| %> + + + <% @roles.each do |role| %> + + <% end %> + + <% end %> +<% end %> + +
    <%=l(:label_permissions)%> + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.role-#{role.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> +
    +   + <%= l_or_humanize(mod, :prefix => 'project_module_') %> +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('.permission-#{permission.name} input')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%= l_or_humanize(permission.name, :prefix => 'permission_') %> + + <% if role.setable_permissions.include? permission %> + <%= check_box_tag "permissions[#{role.id}][]", permission.name, (role.permissions.include? permission.name), :id => nil, :class => "role-#{role.id}" %> + <% end %> +
    +
    +

    <%= check_all_links 'permissions_form' %>

    +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/roles/report.rhtml --- a/app/views/roles/report.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -

    <%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> » <%=l(:label_permissions_report)%>

    - -<% form_tag({:action => 'report'}, :id => 'permissions_form') do %> -<%= hidden_field_tag 'permissions[0]', '', :id => nil %> -
    - - - - - <% @roles.each do |role| %> - - <% end %> - - - -<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> -<% perms_by_module.keys.sort.each do |mod| %> - <% unless mod.blank? %> - - - - <% end %> - <% perms_by_module[mod].each do |permission| %> - - - <% @roles.each do |role| %> - - <% end %> - - <% end %> -<% end %> - -
    <%=l(:label_permissions)%> - <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> - <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.role-#{role.id}')", - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> -
    -   - <%= l_or_humanize(mod, :prefix => 'project_module_') %> -
    - <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('.permission-#{permission.name} input')", - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> - <%= l_or_humanize(permission.name, :prefix => 'permission_') %> - - <% if role.setable_permissions.include? permission %> - <%= check_box_tag "permissions[#{role.id}][]", permission.name, (role.permissions.include? permission.name), :id => nil, :class => "role-#{role.id}" %> - <% end %> -
    -
    -

    <%= check_all_links 'permissions_form' %>

    -

    <%= submit_tag l(:button_save) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/search/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/search/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +

    <%= l(:label_search) %>

    + +
    +<% form_tag({}, :method => :get) do %> +<%= label_tag "search-input", l(:description_search), :class => "hidden-for-sighted" %> +

    <%= text_field_tag 'q', @question, :size => 60, :id => 'search-input' %> +<%= javascript_tag "Field.focus('search-input')" %> +<%= project_select_tag %> +<%= hidden_field_tag 'all_words', '', :id => nil %> + +<%= hidden_field_tag 'titles_only', '', :id => nil %> + +

    +

    +<% @object_types.each do |t| %> + +<% end %> +

    + +

    <%= submit_tag l(:button_submit), :name => 'submit' %>

    +<% end %> +
    + +<% if @project_matches and !@project_matches.empty? and (@project_matches.count < 6) and !@pagination_previous_date %> +

    <%= l(:label_matching_project_plural) %> (<%= @project_matches.count %>)

    +
    + <% @project_matches.each do |e| %> +
    <%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(e.event_title, :length => 255), @tokens), e.event_url %>
    +
    <%= e.short_description %> + <% end %> +
    +<% end %> + +<% if @results %> + +

    <%= l(:label_result_plural) %> (<%= @results_by_type.values.sum %>)

    +
    + <%= render_results_by_type(@results_by_type) unless @scope.size == 1 %> +
    +
    + <% @results.each do |e| %> +
    <%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(h(e.event_title), :length => 255), @tokens), e.event_url %>
    +
    <%= highlight_tokens(h(e.event_description), @tokens) %> + <%= format_time(e.event_datetime) %>
    + <% end %> +
    +<% end %> + +

    +<% if @pagination_previous_date %> +<%= link_to_content_update("\xc2\xab " + l(:label_previous), + params.merge(:previous => 1, + :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>  +<% end %> +<% if @pagination_next_date %> +<%= link_to_content_update(l(:label_next) + " \xc2\xbb", + params.merge(:previous => nil, + :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %> +<% end %> +

    + +<% html_title(l(:label_search)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/search/index.rhtml --- a/app/views/search/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -

    <%= l(:label_search) %>

    - -
    -<% form_tag({}, :method => :get) do %> -

    <%= text_field_tag 'q', @question, :size => 60, :id => 'search-input' %> -<%= javascript_tag "Field.focus('search-input')" %> -<%= project_select_tag %> -<%= hidden_field_tag 'all_words', '', :id => nil %> - -<%= hidden_field_tag 'titles_only', '', :id => nil %> - -

    -

    -<% @object_types.each do |t| %> - -<% end %> -

    - -

    <%= submit_tag l(:button_submit), :name => 'submit' %>

    -<% end %> -
    - -<% if @project_matches and !@project_matches.empty? and (@project_matches.count < 6) and !@pagination_previous_date %> -

    <%= l(:label_matching_project_plural) %> (<%= @project_matches.count %>)

    -
    - <% @project_matches.each do |e| %> -
    <%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(e.event_title, :length => 255), @tokens), e.event_url %>
    -
    <%= e.short_description %> - <% end %> -
    -<% end %> - -<% if @results %> - -

    <%= l(:label_result_plural) %> (<%= @results_by_type.values.sum %>)

    -
    - <%= render_results_by_type(@results_by_type) unless @scope.size == 1 %> -
    -
    - <% @results.each do |e| %> -
    <%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(e.event_title, :length => 255), @tokens), e.event_url %>
    -
    <%= highlight_tokens(e.event_description, @tokens) %> - <%= format_time(e.event_datetime) %>
    - <% end %> -
    -<% end %> - -

    -<% if @pagination_previous_date %> -<%= link_to_content_update('« ' + l(:label_previous), - params.merge(:previous => 1, :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>  -<% end %> -<% if @pagination_next_date %> -<%= link_to_content_update(l(:label_next) + ' »', - params.merge(:previous => nil, :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %> -<% end %> -

    - -<% html_title(l(:label_search)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_authentication.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_authentication.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +<% form_tag({:action => 'edit', :tab => 'authentication'}) do %> + +
    +

    <%= setting_check_box :login_required %>

    + +

    <%= setting_select :autologin, [[l(:label_disabled), 0]] + [1, 7, 30, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), days.to_s]} %>

    + +

    <%= setting_select :self_registration, [[l(:label_disabled), "0"], + [l(:label_registration_activation_by_email), "1"], + [l(:label_registration_manual_activation), "2"], + [l(:label_registration_automatic_activation), "3"]] %>

    + +

    <%= setting_text_field :password_min_length, :size => 6 %>

    + +

    <%= setting_check_box :lost_password, :label => :label_password_lost %>

    + +

    <%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %>

    + +

    <%= setting_check_box :rest_api_enabled %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_authentication.rhtml --- a/app/views/settings/_authentication.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -<% form_tag({:action => 'edit', :tab => 'authentication'}) do %> - -
    -

    <%= setting_check_box :login_required %>

    - -

    <%= setting_select :autologin, [[l(:label_disabled), 0]] + [1, 7, 30, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), days.to_s]} %>

    - -

    <%= setting_select :self_registration, [[l(:label_disabled), "0"], - [l(:label_registration_activation_by_email), "1"], - [l(:label_registration_manual_activation), "2"], - [l(:label_registration_automatic_activation), "3"]] %>

    - -

    <%= setting_text_field :password_min_length, :size => 6 %>

    - -

    <%= setting_check_box :lost_password, :label => :label_password_lost %>

    - -

    <%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %>

    - -

    <%= setting_check_box :rest_api_enabled %>

    -
    - -
    - <%= link_to l(:label_ldap_authentication), {:controller => 'ldap_auth_sources', :action => 'index'}, :class => 'icon icon-server-authentication' %> -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_display.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_display.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +<% form_tag({:action => 'edit', :tab => 'display'}) do %> + +
    +

    <%= setting_select :ui_theme, Redmine::Themes.themes.collect {|t| [t.name, t.id]}, :blank => :label_default, :label => :label_theme %>

    + +

    <%= setting_select :default_language, lang_options_for_select(false) %>

    + +

    <%= setting_select :start_of_week, [[day_name(1),'1'], [day_name(6),'6'], [day_name(7),'7']], :blank => :label_language_based %>

    + +

    <%= setting_select :date_format, Setting::DATE_FORMATS.collect {|f| [Date.today.strftime(f), f]}, :blank => :label_language_based %>

    + +

    <%= setting_select :time_format, Setting::TIME_FORMATS.collect {|f| [Time.now.strftime(f), f]}, :blank => :label_language_based %>

    + +

    <%= setting_select :user_format, @options[:user_format] %>

    + +

    <%= setting_check_box :gravatar_enabled %>

    + +

    <%= setting_select :gravatar_default, [["Wavatars", 'wavatar'], ["Identicons", 'identicon'], ["Monster ids", 'monsterid'], ["Retro", 'retro'], ["Mystery man", 'mm']], :blank => :label_none %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_display.rhtml --- a/app/views/settings/_display.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -<% form_tag({:action => 'edit', :tab => 'display'}) do %> - -
    -

    <%= setting_select :ui_theme, Redmine::Themes.themes.collect {|t| [t.name, t.id]}, :blank => :label_default, :label => :label_theme %>

    - -

    <%= setting_select :default_language, lang_options_for_select(false) %>

    - -

    <%= setting_select :start_of_week, [[day_name(1),'1'], [day_name(6),'6'], [day_name(7),'7']], :blank => :label_language_based %>

    - -

    <%= setting_select :date_format, Setting::DATE_FORMATS.collect {|f| [Date.today.strftime(f), f]}, :blank => :label_language_based %>

    - -

    <%= setting_select :time_format, Setting::TIME_FORMATS.collect {|f| [Time.now.strftime(f), f]}, :blank => :label_language_based %>

    - -

    <%= setting_select :user_format, @options[:user_format] %>

    - -

    <%= setting_check_box :gravatar_enabled %>

    - -

    <%= setting_select :gravatar_default, [["Wavatars", 'wavatar'], ["Identicons", 'identicon'], ["Monster ids", 'monsterid'], ["Retro", 'retro'], ["Mystery man", 'mm']], :blank => :label_none %>

    -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_general.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_general.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +<% form_tag({:action => 'edit'}) do %> + +
    +

    <%= setting_text_field :app_title, :size => 30 %>

    + +

    <%= setting_text_area :notifications_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    + <%= wikitoolbar_for 'settings_notifications_text' %> + +

    <%= setting_text_area :welcome_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    +<%= wikitoolbar_for 'settings_welcome_text' %> + +

    <%= setting_text_area :tipoftheday_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    +<%= wikitoolbar_for 'settings_tipoftheday_text' %> + +

    <%= setting_text_field :attachment_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

    + +

    <%= setting_text_field :per_page_options, :size => 20 %>
    +<%= l(:text_comma_separated) %>

    + +

    <%= setting_text_field :activity_days_default, :size => 6 %> <%= l(:label_day_plural) %>

    + +

    <%= setting_text_field :host_name, :size => 60 %>
    +<%= l(:label_example) %>: <%= @guessed_host_and_path %>

    + +

    <%= setting_select :protocol, [['HTTP', 'http'], ['HTTPS', 'https']] %>

    + +

    <%= setting_select :text_formatting, Redmine::WikiFormatting.format_names.collect{|name| [name, name.to_s]}, :blank => :label_none %>

    + +

    <%= setting_check_box :cache_formatted_text %>

    + +

    <%= setting_select :wiki_compression, [['Gzip', 'gzip']], :blank => :label_none %>

    + +

    <%= setting_text_field :feeds_limit, :size => 6 %>

    + +

    <%= setting_text_field :file_max_size_displayed, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

    + +

    <%= setting_text_field :diff_max_lines_displayed, :size => 6 %>

    + +

    <%= setting_text_field :repositories_encodings, :size => 60 %>
    +<%= l(:text_comma_separated) %>

    + +<%= call_hook(:view_settings_general_form) %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_general.rhtml --- a/app/views/settings/_general.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -<% form_tag({:action => 'edit'}) do %> - -
    -

    <%= setting_text_field :app_title, :size => 30 %>

    - -

    <%= setting_text_area :notifications_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    - <%= wikitoolbar_for 'settings_notifications_text' %> - -

    <%= setting_text_area :welcome_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    -<%= wikitoolbar_for 'settings_welcome_text' %> - -

    <%= setting_text_area :tipoftheday_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    -<%= wikitoolbar_for 'settings_tipoftheday_text' %> - -

    <%= setting_text_field :attachment_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

    - -

    <%= setting_text_field :per_page_options, :size => 20 %>
    -<%= l(:text_comma_separated) %>

    - -

    <%= setting_text_field :activity_days_default, :size => 6 %> <%= l(:label_day_plural) %>

    - -

    <%= setting_text_field :host_name, :size => 60 %>
    -<%= l(:label_example) %>: <%= @guessed_host_and_path %>

    - -

    <%= setting_select :protocol, [['HTTP', 'http'], ['HTTPS', 'https']] %>

    - -

    <%= setting_select :text_formatting, Redmine::WikiFormatting.format_names.collect{|name| [name, name.to_s]}, :blank => :label_none %>

    - -

    <%= setting_check_box :cache_formatted_text %>

    - -

    <%= setting_select :wiki_compression, [['Gzip', 'gzip']], :blank => :label_none %>

    - -

    <%= setting_text_field :feeds_limit, :size => 6 %>

    - -

    <%= setting_text_field :file_max_size_displayed, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

    - -

    <%= setting_text_field :diff_max_lines_displayed, :size => 6 %>

    - -<%= call_hook(:view_settings_general_form) %> -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_issues.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_issues.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +<% form_tag({:action => 'edit', :tab => 'issues'}) do %> + +
    +

    <%= setting_check_box :cross_project_issue_relations %>

    + +

    <%= setting_check_box :issue_group_assignment %>

    + +

    <%= setting_check_box :default_issue_start_date_to_creation_date %>

    + +

    <%= setting_check_box :display_subprojects_issues %>

    + +

    <%= setting_select :issue_done_ratio, Issue::DONE_RATIO_OPTIONS.collect {|i| [l("setting_issue_done_ratio_#{i}"), i]} %>

    + +

    <%= setting_text_field :issues_export_limit, :size => 6 %>

    + +

    <%= setting_text_field :gantt_items_limit, :size => 6 %>

    +
    + +
    <%= l(:setting_issue_list_default_columns) %> +<%= setting_multiselect(:issue_list_default_columns, + Query.new.available_columns.collect {|c| [c.caption, c.name.to_s]}, :label => false) %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_issues.rhtml --- a/app/views/settings/_issues.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -<% form_tag({:action => 'edit', :tab => 'issues'}) do %> - -
    -

    <%= setting_check_box :cross_project_issue_relations %>

    - -

    <%= setting_check_box :display_subprojects_issues %>

    - -

    <%= setting_select :issue_done_ratio, Issue::DONE_RATIO_OPTIONS.collect {|i| [l("setting_issue_done_ratio_#{i}"), i]} %>

    - -

    <%= setting_text_field :issues_export_limit, :size => 6 %>

    - -

    <%= setting_text_field :gantt_items_limit, :size => 6 %>

    -
    - -
    <%= l(:setting_issue_list_default_columns) %> -<%= setting_multiselect(:issue_list_default_columns, - Query.new.available_columns.collect {|c| [c.caption, c.name.to_s]}, :label => false) %> -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_mail_handler.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_mail_handler.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +<% form_tag({:action => 'edit', :tab => 'mail_handler'}) do %> + +
    +

    + <%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %> +
    <%= l(:text_line_separated) %> +

    +
    + +
    +

    <%= setting_check_box :mail_handler_api_enabled, + :onclick => "if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }"%>

    + +

    <%= setting_text_field :mail_handler_api_key, :size => 30, + :id => 'settings_mail_handler_api_key', + :disabled => !Setting.mail_handler_api_enabled? %> + <%= link_to_function l(:label_generate_key), "if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }" %> +

    +
    + +<%= submit_tag l(:button_save) %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_mail_handler.rhtml --- a/app/views/settings/_mail_handler.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -<% form_tag({:action => 'edit', :tab => 'mail_handler'}) do %> - -
    -

    - <%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %> -
    <%= l(:text_line_separated) %> -

    -
    - -
    -

    <%= setting_check_box :mail_handler_api_enabled, - :onclick => "if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }"%>

    - -

    <%= setting_text_field :mail_handler_api_key, :size => 30, - :id => 'settings_mail_handler_api_key', - :disabled => !Setting.mail_handler_api_enabled? %> - <%= link_to_function l(:label_generate_key), "if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }" %> -

    -
    - -<%= submit_tag l(:button_save) %> - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_notifications.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_notifications.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,42 @@ +<% if @deliveries %> +<% form_tag({:action => 'edit', :tab => 'notifications'}) do %> + +
    +

    <%= setting_text_field :mail_from, :size => 60 %>

    + +

    <%= setting_check_box :bcc_recipients %>

    + +

    <%= setting_check_box :plain_text_mail %>

    + +

    <%= setting_select(:default_notification_option, User.valid_notification_options.collect {|o| [l(o.last), o.first.to_s]}) %>

    + +
    + +
    <%=l(:text_select_mail_notifications)%> +<%= hidden_field_tag 'settings[notified_events][]', '' %> +<% @notifiables.each do |notifiable| %> +<%= notification_field notifiable %> +
    +<% end %> +

    <%= check_all_links('notified_events') %>

    +
    + +
    <%= l(:setting_emails_header) %> +<%= setting_text_area :emails_header, :label => false, :class => 'wiki-edit', :rows => 5 %> +
    + +
    <%= l(:setting_emails_footer) %> +<%= setting_text_area :emails_footer, :label => false, :class => 'wiki-edit', :rows => 5 %> +
    + +
    +<%= link_to l(:label_send_test_email), :controller => 'admin', :action => 'test_email' %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> +<% else %> +
    +<%= simple_format(l(:text_email_delivery_not_configured)) %> +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_notifications.rhtml --- a/app/views/settings/_notifications.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -<% if @deliveries %> -<% form_tag({:action => 'edit', :tab => 'notifications'}) do %> - -
    -

    <%= setting_text_field :mail_from, :size => 60 %>

    - -

    <%= setting_check_box :bcc_recipients %>

    - -

    <%= setting_check_box :plain_text_mail %>

    - -

    <%= setting_select(:default_notification_option, User.valid_notification_options.collect {|o| [l(o.last), o.first.to_s]}) %>

    - -
    - -
    <%=l(:text_select_mail_notifications)%> -<%= hidden_field_tag 'settings[notified_events][]', '' %> -<% @notifiables.each do |notifiable| %> -<%= notification_field notifiable %> -
    -<% end %> -

    <%= check_all_links('notified_events') %>

    -
    - -
    <%= l(:setting_emails_header) %> -<%= setting_text_area :emails_header, :label => false, :class => 'wiki-edit', :rows => 5 %> -
    - -
    <%= l(:setting_emails_footer) %> -<%= setting_text_area :emails_footer, :label => false, :class => 'wiki-edit', :rows => 5 %> -
    - -
    -<%= link_to l(:label_send_test_email), :controller => 'admin', :action => 'test_email' %> -
    - -<%= submit_tag l(:button_save) %> -<% end %> -<% else %> -
    -<%= simple_format(l(:text_email_delivery_not_configured)) %> -
    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_projects.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_projects.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +<% form_tag({:action => 'edit', :tab => 'projects'}) do %> + +
    +

    <%= setting_check_box :default_projects_public %>

    + +

    <%= setting_multiselect(:default_projects_modules, + Redmine::AccessControl.available_project_modules.collect {|m| [l_or_humanize(m, :prefix => "project_module_"), m.to_s]}) %>

    + +

    <%= setting_check_box :sequential_project_identifiers %>

    + +

    <%= setting_select :new_project_user_role_id, + Role.find_all_givable.collect {|r| [r.name, r.id.to_s]}, + :blank => "--- #{l(:actionview_instancetag_blank_option)} ---" %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_projects.rhtml --- a/app/views/settings/_projects.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -<% form_tag({:action => 'edit', :tab => 'projects'}) do %> - -
    -

    <%= setting_check_box :default_projects_public %>

    - -

    <%= setting_multiselect(:default_projects_modules, - Redmine::AccessControl.available_project_modules.collect {|m| [l_or_humanize(m, :prefix => "project_module_"), m.to_s]}) %>

    - -

    <%= setting_check_box :sequential_project_identifiers %>

    - -

    <%= setting_select :new_project_user_role_id, - Role.find_all_givable.collect {|r| [r.name, r.id.to_s]}, - :blank => "--- #{l(:actionview_instancetag_blank_option)} ---" %>

    -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_repositories.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/_repositories.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,92 @@ +<% form_tag({:action => 'edit', :tab => 'repositories'}) do %> + +
    +<%= hidden_field_tag 'settings[enabled_scm][]', '' %> +<%= l(:setting_enabled_scm) %> + + + + + + + <% Redmine::Scm::Base.all.collect do |choice| %> + <% scm_class = "Repository::#{choice}".constantize %> + <% text, value = (choice.is_a?(Array) ? choice : [choice, choice]) %> + <% setting = :enabled_scm %> + + + + + + <% end %> +
    <%= l(:text_scm_command) %><%= l(:text_scm_command_version) %>
    + <%= + check_box_tag( + "settings[#{setting}][]", + value, + Setting.send(setting).include?(value)) + %> + <%= text.to_s %> + + <%= + image_tag( + (scm_class.scm_available ? 'true.png' : 'exclamation.png'), + :style => "vertical-align:bottom;" + ) + %> + <%= scm_class.scm_command %> + + <%= scm_class.scm_version_string %> +
    +

    <%= l(:text_scm_config) %>

    +
    + +
    +

    <%= setting_check_box :autofetch_changesets %>

    + +

    <%= setting_check_box :sys_api_enabled, + :onclick => + "if (this.checked) { Form.Element.enable('settings_sys_api_key'); } else { Form.Element.disable('settings_sys_api_key'); }" %>

    + +

    <%= setting_text_field :sys_api_key, + :size => 30, + :id => 'settings_sys_api_key', + :disabled => !Setting.sys_api_enabled?, + :label => :setting_mail_handler_api_key %> + <%= link_to_function l(:label_generate_key), + "if ($('settings_sys_api_key').disabled == false) { $('settings_sys_api_key').value = randomKey(20) }" %> +

    + +

    <%= setting_text_field :repository_log_display_limit, :size => 6 %>

    +
    + +
    +<%= l(:text_issues_ref_in_commit_messages) %> +

    <%= setting_text_field :commit_ref_keywords, :size => 30 %>
    +<%= l(:text_comma_separated) %>

    + +

    <%= setting_text_field :commit_fix_keywords, :size => 30 %> + <%= l(:label_applied_status) %>: <%= setting_select :commit_fix_status_id, + [["", 0]] + + IssueStatus.find(:all).collect{ + |status| [status.name, status.id.to_s] + }, + :label => false %> + <%= l(:field_done_ratio) %>: <%= setting_select :commit_fix_done_ratio, + (0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] }, + :blank => :label_no_change_option, + :label => false %> +
    <%= l(:text_comma_separated) %>

    + +

    <%= setting_check_box :commit_logtime_enabled, + :onclick => + "if (this.checked) { Form.Element.enable('settings_commit_logtime_activity_id'); } else { Form.Element.disable('settings_commit_logtime_activity_id'); }"%>

    + +

    <%= setting_select :commit_logtime_activity_id, + [[l(:label_default), 0]] + + TimeEntryActivity.shared.active.collect{|activity| [activity.name, activity.id.to_s]}, + :disabled => !Setting.commit_logtime_enabled?%>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/_repositories.rhtml --- a/app/views/settings/_repositories.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -<% form_tag({:action => 'edit', :tab => 'repositories'}) do %> - -
    -<%= l(:setting_enabled_scm) %> - - - - - - - <% Redmine::Scm::Base.all.collect do |choice| %> - <% scm_class = "Repository::#{choice}".constantize %> - <% text, value = (choice.is_a?(Array) ? choice : [choice, choice]) %> - <% setting = :enabled_scm %> - - - - - - <% end %> -
    <%= l(:text_scm_command) %><%= l(:text_scm_command_version) %>
    - <%= - check_box_tag( - "settings[#{setting}][]", - value, - Setting.send(setting).include?(value)) - %> - <%= text.to_s %> - - <%= - image_tag( - (scm_class.scm_available ? 'true.png' : 'exclamation.png'), - :style => "vertical-align:bottom;" - ) - %> - <%= scm_class.scm_command %> - - <%= scm_class.scm_version_string %> -
    -

    -<%= l(:text_scm_config) %> -

    -
    - -
    -

    <%= setting_check_box :autofetch_changesets %>

    - -

    <%= setting_check_box :sys_api_enabled, - :onclick => - "if (this.checked) { Form.Element.enable('settings_sys_api_key'); } else { Form.Element.disable('settings_sys_api_key'); }" %>

    - -

    <%= setting_text_field :sys_api_key, - :size => 30, - :id => 'settings_sys_api_key', - :disabled => !Setting.sys_api_enabled?, - :label => :setting_mail_handler_api_key %> - <%= link_to_function l(:label_generate_key), - "if ($('settings_sys_api_key').disabled == false) { $('settings_sys_api_key').value = randomKey(20) }" %> -

    - -

    <%= setting_text_field :repositories_encodings, :size => 60 %>
    -<%= l(:text_comma_separated) %>

    - -

    <%= setting_text_field :repository_log_display_limit, :size => 6 %>

    -
    - -
    -<%= l(:text_issues_ref_in_commit_messages) %> -

    <%= setting_text_field :commit_ref_keywords, :size => 30 %>
    -<%= l(:text_comma_separated) %>

    - -

    <%= setting_text_field :commit_fix_keywords, :size => 30 %> - <%= l(:label_applied_status) %>: <%= setting_select :commit_fix_status_id, - [["", 0]] + - IssueStatus.find(:all).collect{ - |status| [status.name, status.id.to_s] - }, - :label => false %> - <%= l(:field_done_ratio) %>: <%= setting_select :commit_fix_done_ratio, - (0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] }, - :blank => :label_no_change_option, - :label => false %> -
    <%= l(:text_comma_separated) %>

    - -

    <%= setting_check_box :commit_logtime_enabled, - :onclick => - "if (this.checked) { Form.Element.enable('settings_commit_logtime_activity_id'); } else { Form.Element.disable('settings_commit_logtime_activity_id'); }"%>

    - -

    <%= setting_select :commit_logtime_activity_id, - [[l(:label_default), 0]] + - TimeEntryActivity.shared.all.collect{|activity| [activity.name, activity.id.to_s]}, - :disabled => !Setting.commit_logtime_enabled?%>

    -
    - -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%= l(:label_settings) %>

    + +<%= render_tabs administration_settings_tabs %> + +<% html_title(l(:label_settings), l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/edit.rhtml --- a/app/views/settings/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -

    <%= l(:label_settings) %>

    - -<%= render_tabs administration_settings_tabs %> - -<% html_title(l(:label_settings), l(:label_administration)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/plugin.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/settings/plugin.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +

    <%= l(:label_settings) %>: <%=h @plugin.name %>

    + +
    +<% form_tag({:action => 'plugin'}) do %> +
    +<%= render :partial => @partial, :locals => {:settings => @settings}%> +
    +<%= submit_tag l(:button_apply) %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/settings/plugin.rhtml --- a/app/views/settings/plugin.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -

    <%= l(:label_settings) %>: <%=h @plugin.name %>

    - -
    -<% form_tag({:action => 'plugin'}) do %> -
    -<%= render :partial => @partial, :locals => {:settings => @settings}%> -
    -<%= submit_tag l(:button_apply) %> -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/time_entry_reports/_report_criteria.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/time_entry_reports/_report_criteria.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,19 @@ +<% @hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| %> +<% hours_for_value = select_hours(hours, criterias[level], value) -%> +<% next if hours_for_value.empty? -%> + +<%= '' * level %> +<%= h(format_criteria_value(criterias[level], value)) %> +<%= '' * (criterias.length - level - 1) -%> + <% total = 0 -%> + <% @periods.each do |period| -%> + <% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)); total += sum -%> + <%= html_hours("%.2f" % sum) if sum > 0 %> + <% end -%> + <%= html_hours("%.2f" % total) if total > 0 %> + +<% if criterias.length > level+1 -%> + <%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %> +<% end -%> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/time_entry_reports/_report_criteria.rhtml --- a/app/views/time_entry_reports/_report_criteria.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -<% @hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| %> -<% hours_for_value = select_hours(hours, criterias[level], value) -%> -<% next if hours_for_value.empty? -%> - -<%= '' * level %> -<%= h(format_criteria_value(criterias[level], value)) %> -<%= '' * (criterias.length - level - 1) -%> - <% total = 0 -%> - <% @periods.each do |period| -%> - <% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)); total += sum -%> - <%= html_hours("%.2f" % sum) if sum > 0 %> - <% end -%> - <%= html_hours("%.2f" % total) if total > 0 %> - -<% if criterias.length > level+1 -%> - <%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %> -<% end -%> - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/time_entry_reports/report.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/time_entry_reports/report.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +
    +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %> +
    + +<%= render_timelog_breadcrumb %> + +

    <%= l(:label_spent_time) %>

    + +<% form_tag({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> + <% @criterias.each do |criteria| %> + <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> + <% end %> + <%= render :partial => 'timelog/date_range' %> + +

    : <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], + [l(:label_month), 'month'], + [l(:label_week), 'week'], + [l(:label_day_plural).titleize, 'day']], @columns), + :onchange => "this.form.onsubmit();" %> + + : <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l_or_humanize(@available_criterias[k][:label]), k]}), + :onchange => "this.form.submit();", + :style => 'width: 200px', + :id => nil, + :disabled => (@criterias.length >= 3), :id => "criterias") %> + <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, :class => 'icon icon-reload' %>

    +<% end %> + +<% unless @criterias.empty? %> +
    +

    <%= l(:label_total) %>: <%= html_hours(l_hours(@total_hours)) %>

    +
    + +<% unless @hours.empty? %> +
    + + + +<% @criterias.each do |criteria| %> + +<% end %> +<% columns_width = (40 / (@periods.length+1)).to_i %> +<% @periods.each do |period| %> + +<% end %> + + + + +<%= render :partial => 'report_criteria', :locals => {:criterias => @criterias, :hours => @hours, :level => 0} %> + + + <%= '' * (@criterias.size - 1) %> + <% total = 0 -%> + <% @periods.each do |period| -%> + <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%> + + <% end -%> + + + +
    <%= l_or_humanize(@available_criterias[criteria][:label]) %><%= period %><%= l(:label_total) %>
    <%= l(:label_total) %><%= html_hours("%.2f" % sum) if sum > 0 %><%= html_hours("%.2f" % total) if total > 0 %>
    +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'CSV', :url => params %> +<% end %> +<% end %> +<% end %> + +<% html_title l(:label_spent_time), l(:label_report) %> + diff -r 487d96eac004 -r 5e80956cc792 app/views/time_entry_reports/report.rhtml --- a/app/views/time_entry_reports/report.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -
    -<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %> -
    - -<%= render_timelog_breadcrumb %> - -

    <%= l(:label_spent_time) %>

    - -<% form_tag({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> - <% @criterias.each do |criteria| %> - <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> - <% end %> - <%= render :partial => 'timelog/date_range' %> - -

    <%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], - [l(:label_month), 'month'], - [l(:label_week), 'week'], - [l(:label_day_plural).titleize, 'day']], @columns), - :onchange => "this.form.onsubmit();" %> - - <%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l_or_humanize(@available_criterias[k][:label]), k]}), - :onchange => "this.form.submit();", - :style => 'width: 200px', - :id => nil, - :disabled => (@criterias.length >= 3)) %> - <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, :class => 'icon icon-reload' %>

    -<% end %> - -<% unless @criterias.empty? %> -
    -

    <%= l(:label_total) %>: <%= html_hours(l_hours(@total_hours)) %>

    -
    - -<% unless @hours.empty? %> - - - -<% @criterias.each do |criteria| %> - -<% end %> -<% columns_width = (40 / (@periods.length+1)).to_i %> -<% @periods.each do |period| %> - -<% end %> - - - - -<%= render :partial => 'report_criteria', :locals => {:criterias => @criterias, :hours => @hours, :level => 0} %> - - - <%= '' * (@criterias.size - 1) %> - <% total = 0 -%> - <% @periods.each do |period| -%> - <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%> - - <% end -%> - - - -
    <%= l_or_humanize(@available_criterias[criteria][:label]) %><%= period %><%= l(:label_total) %>
    <%= l(:label_total) %><%= html_hours("%.2f" % sum) if sum > 0 %><%= html_hours("%.2f" % total) if total > 0 %>
    - -<% other_formats_links do |f| %> - <%= f.link_to 'CSV', :url => params %> -<% end %> -<% end %> -<% end %> - -<% html_title l(:label_spent_time), l(:label_report) %> - diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/_date_range.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/timelog/_date_range.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,38 @@ +
    +<%= l(:label_date_range) %> +
    +

    +<%= label_tag "period_type_list", l(:description_date_range_list), :class => "hidden-for-sighted" %> +<%= radio_button_tag 'period_type', '1', !@free_period, :onclick => 'Form.Element.disable("from");Form.Element.disable("to");Form.Element.enable("period");', :id => "period_type_list"%> +<%= select_tag 'period', options_for_period_select(params[:period]), + :onchange => 'this.form.submit();', + :onfocus => '$("period_type_1").checked = true;', + :disabled => @free_period %> +

    +

    +<%= label_tag "period_type_interval", l(:description_date_range_interval), :class => "hidden-for-sighted" %> +<%= radio_button_tag 'period_type', '2', @free_period, :onclick => 'Form.Element.enable("from");Form.Element.enable("to");Form.Element.disable("period");', :id => "period_type_interval" %> + +<%= l(:label_date_from_to, + :start => ((label_tag "from", l(:description_date_from), :class => "hidden-for-sighted") + + text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), + :end => ((label_tag "to", l(:description_date_to), :class => "hidden-for-sighted") + + text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))) %> + +

    +
    +
    +

    + <%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), {:controller => controller_name, :action => action_name, :project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %> +

    + +
    +<% url_params = @free_period ? { :from => @from, :to => @to } : { :period => params[:period] } %> +
      +
    • <%= link_to(l(:label_details), url_params.merge({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue }), + :class => (@controller.action_name == 'index' ? 'selected' : nil)) %>
    • +
    • <%= link_to(l(:label_report), url_params.merge({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}), + :class => (@controller.action_name == 'report' ? 'selected' : nil)) %>
    • +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/_date_range.rhtml --- a/app/views/timelog/_date_range.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -
    -<%= l(:label_date_range) %> -
    -

    -<%= radio_button_tag 'period_type', '1', !@free_period, :onclick => 'Form.Element.disable("from");Form.Element.disable("to");Form.Element.enable("period");' %> -<%= select_tag 'period', options_for_period_select(params[:period]), - :onchange => 'this.form.submit();', - :onfocus => '$("period_type_1").checked = true;', - :disabled => @free_period %> -

    -

    -<%= radio_button_tag 'period_type', '2', @free_period, :onclick => 'Form.Element.enable("from");Form.Element.enable("to");Form.Element.disable("period");' %> - -<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), - :end => (text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))) %> - -

    -
    -
    -

    - <%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %> - <%= link_to l(:button_clear), {:controller => controller_name, :action => action_name, :project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %> -

    - -
    -<% url_params = @free_period ? { :from => @from, :to => @to } : { :period => params[:period] } %> -
      -
    • <%= link_to(l(:label_details), url_params.merge({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue }), - :class => (@controller.action_name == 'index' ? 'selected' : nil)) %>
    • -
    • <%= link_to(l(:label_report), url_params.merge({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}), - :class => (@controller.action_name == 'report' ? 'selected' : nil)) %>
    • -
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/_list.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/timelog/_list.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +<% form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params) %> +
    + + + + +<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %> +<%= sort_header_tag('user', :caption => l(:label_member)) %> +<%= sort_header_tag('activity', :caption => l(:label_activity)) %> +<%= sort_header_tag('project', :caption => l(:label_project)) %> +<%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %> + +<%= sort_header_tag('hours', :caption => l(:field_hours)) %> + + + + +<% entries.each do |entry| -%> + hascontextmenu"> + + + + + + + + + + +<% end -%> + +
    + <%= link_to image_tag('toggle_check.png'), + {}, + :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> +<%= l(:field_comments) %>
    <%= check_box_tag("ids[]", entry.id, false, :id => nil) %><%= format_date(entry.spent_on) %><%= link_to_user(entry.user) %><%=h entry.activity %><%= link_to_project(entry.project) %> +<% if entry.issue -%> +<%= entry.issue.visible? ? link_to_issue(entry.issue, :truncate => 50) : "##{entry.issue.id}" -%> +<% end -%> +<%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> +<% if entry.editable_by?(User.current) -%> + <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry, :project_id => nil}, + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry, :project_id => nil}, + :confirm => l(:text_are_you_sure), + :method => :delete, + :title => l(:button_delete) %> +<% end -%> +
    +
    +<% end -%> + +<%= context_menu time_entries_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/_list.rhtml --- a/app/views/timelog/_list.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -<% form_tag({}) do -%> -<%= hidden_field_tag 'back_url', url_for(params) %> - - - - -<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %> -<%= sort_header_tag('user', :caption => l(:label_member)) %> -<%= sort_header_tag('activity', :caption => l(:label_activity)) %> -<%= sort_header_tag('project', :caption => l(:label_project)) %> -<%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %> - -<%= sort_header_tag('hours', :caption => l(:field_hours)) %> - - - - -<% entries.each do |entry| -%> - hascontextmenu"> - - - - - - - - - - -<% end -%> - -
    - <%= link_to image_tag('toggle_check.png'), - {}, - :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> -<%= l(:field_comments) %>
    <%= check_box_tag("ids[]", entry.id, false, :id => nil) %><%= format_date(entry.spent_on) %><%=h entry.user %><%=h entry.activity %><%=h entry.project %> -<% if entry.issue -%> -<%= entry.issue.visible? ? link_to_issue(entry.issue, :truncate => 50) : "##{entry.issue.id}" -%> -<% end -%> -<%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> -<% if entry.editable_by?(User.current) -%> - <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry, :project_id => nil}, - :title => l(:button_edit) %> - <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry, :project_id => nil}, - :confirm => l(:text_are_you_sure), - :method => :delete, - :title => l(:button_delete) %> -<% end -%> -
    -<% end -%> - -<%= context_menu time_entries_context_menu_path %> diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/bulk_edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/timelog/bulk_edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,49 @@ +

    <%= l(:label_bulk_edit_selected_time_entries) %>

    + +
      <%= @time_entries.collect {|i| content_tag('li', link_to(h("#{i.spent_on.strftime("%Y-%m-%d")} -- #{i.project}: #{l(:label_f_hour_plural, :value => i.hours)}"), { :action => 'edit', :id => i }))} %>
    + +<% form_tag(:action => 'bulk_update') do %> +<%= @time_entries.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> +
    +
    + <%= l(:label_change_properties) %> +
    +

    + + <%= text_field :time_entry, :issue_id, :size => 6 %> +

    + +

    + + <%= text_field :time_entry, :spent_on, :size => 10 %><%= calendar_for('time_entry_spent_on') %> +

    + +

    + + <%= text_field :time_entry, :hours, :size => 6 %> +

    + + <% if @available_activities.any? %> +

    + + <%= select_tag('time_entry[activity_id]', "" + options_from_collection_for_select(@available_activities, :id, :name)) %> +

    + <% end %> + +

    + + <%= text_field(:time_entry, :comments, :size => 100) %> +

    + + <% @custom_fields.each do |custom_field| %> +

    <%= custom_field_tag_for_bulk_edit('time_entry', custom_field, @projects) %>

    + <% end %> + + <%= call_hook(:view_time_entries_bulk_edit_details_bottom, { :time_entries => @time_entries }) %> +
    + +
    +
    + +

    <%= submit_tag l(:button_submit) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/bulk_edit.rhtml --- a/app/views/timelog/bulk_edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -

    <%= l(:label_bulk_edit_selected_time_entries) %>

    - -
      <%= @time_entries.collect {|i| content_tag('li', link_to(h("#{i.spent_on.strftime("%Y-%m-%d")} -- #{i.project}: #{l(:label_f_hour_plural, :value => i.hours)}"), { :action => 'edit', :id => i }))} %>
    - -<% form_tag(:action => 'bulk_update') do %> -<%= @time_entries.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> -
    -
    - <%= l(:label_change_properties) %> -
    -

    - - <%= text_field :time_entry, :issue_id, :size => 6 %> -

    - -

    - - <%= text_field :time_entry, :spent_on, :size => 10 %><%= calendar_for('time_entry_spent_on') %> -

    - -

    - - <%= text_field :time_entry, :hours, :size => 6 %> -

    - - <% if @available_activities.any? %> -

    - - <%= select_tag('time_entry[activity_id]', "" + options_from_collection_for_select(@available_activities, :id, :name)) %> -

    - <% end %> - -

    - - <%= text_field(:time_entry, :comments, :size => 100) %> -

    - - <% @custom_fields.each do |custom_field| %> -

    <%= custom_field_tag_for_bulk_edit('time_entry', custom_field, @projects) %>

    - <% end %> - - <%= call_hook(:view_time_entries_bulk_edit_details_bottom, { :time_entries => @time_entries }) %> -
    - -
    -
    - -

    <%= submit_tag l(:button_submit) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/timelog/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +

    <%= l(:label_spent_time) %>

    + +<% labelled_tabular_form_for(:time_entry, @time_entry, :url => { + :action => (@time_entry.new_record? ? 'create' : 'update'), + :id => @time_entry, + :project_id => @time_entry.project + }, + :html => {:method => @time_entry.new_record? ? :post : :put}) do |f| %> +<%= error_messages_for 'time_entry' %> +<%= back_url_hidden_field_tag %> + +
    +

    <%= f.text_field :issue_id, :size => 6 %> <%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %>

    +

    <%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %>

    +

    <%= f.text_field :hours, :size => 6, :required => true %>

    +

    <%= f.text_field :comments, :size => 100 %>

    +

    <%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %>

    +<% @time_entry.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :time_entry, value %>

    +<% end %> +<%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %> +
    + +<%= submit_tag l(:button_save) %> + +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/edit.rhtml --- a/app/views/timelog/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -

    <%= l(:label_spent_time) %>

    - -<% labelled_tabular_form_for(:time_entry, @time_entry, :url => { - :action => (@time_entry.new_record? ? 'create' : 'update'), - :id => @time_entry, - :project_id => @time_entry.project - }, - :html => {:method => @time_entry.new_record? ? :post : :put}) do |f| %> -<%= error_messages_for 'time_entry' %> -<%= back_url_hidden_field_tag %> - -
    -

    <%= f.text_field :issue_id, :size => 6 %> <%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %>

    -

    <%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %>

    -

    <%= f.text_field :hours, :size => 6, :required => true %>

    -

    <%= f.text_field :comments, :size => 100 %>

    -

    <%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %>

    -<% @time_entry.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :time_entry, value %>

    -<% end %> -<%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %> -
    - -<%= submit_tag l(:button_save) %> - -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/timelog/index.html.erb --- a/app/views/timelog/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/timelog/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -19,8 +19,8 @@

    <%= pagination_links_full @entry_pages, @entry_count %>

    <% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => params.merge({:issue_id => @issue, :key => User.current.rss_key}) %> - <%= f.link_to 'CSV', :url => params %> + <%= f.link_to 'Atom', :url => params.merge({:issue_id => @issue, :key => User.current.rss_key}) %> + <%= f.link_to 'CSV', :url => params %> <% end %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/trackers/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +<%= error_messages_for 'tracker' %> + +
    +
    + +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.check_box :is_in_roadmap %>

    + +<% if IssueCustomField.all.any? %> +

    + + <% IssueCustomField.all.each do |field| %> + + <% end %> +

    +<%= hidden_field_tag 'tracker[custom_field_ids][]', '' %> +<% end %> + +<% if @tracker.new_record? && @trackers.any? %> +

    +<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@trackers, :id, :name)) %>

    +<% end %> + +
    +<%= submit_tag l(@tracker.new_record? ? :button_create : :button_save) %> +
    + +
    +<% if @projects.any? %> +
    <%= l(:label_project_plural) %> +<%= project_nested_ul(@projects) do |p| + content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p)) +end %> +<%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %> +

    <%= check_all_links 'tracker_project_ids' %>

    +
    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/_form.rhtml --- a/app/views/trackers/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -<%= error_messages_for 'tracker' %> - -
    -
    - -

    <%= f.text_field :name, :required => true %>

    -

    <%= f.check_box :is_in_roadmap %>

    - -<% if IssueCustomField.all.any? %> -

    - - <% IssueCustomField.all.each do |field| %> - - <% end %> -

    -<%= hidden_field_tag 'tracker[custom_field_ids][]', '' %> -<% end %> - -<% if @tracker.new_record? && @trackers.any? %> -

    -<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@trackers, :id, :name)) %>

    -<% end %> - -
    -<%= submit_tag l(@tracker.new_record? ? :button_create : :button_save) %> -
    - -
    -<% if @projects.any? %> -
    <%= l(:label_project_plural) %> -<%= project_nested_ul(@projects) do |p| - content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p)) -end %> -<%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %> -

    <%= check_all_links 'tracker_project_ids' %>

    -
    -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/trackers/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%= link_to l(:label_tracker_plural), trackers_path %> » <%=h @tracker %>

    + +<% form_for @tracker, :builder => TabularFormBuilder do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/edit.rhtml --- a/app/views/trackers/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -

    <%= link_to l(:label_tracker_plural), :controller => 'trackers', :action => 'index' %> » <%=h @tracker %>

    - -<% form_for :tracker, @tracker, :url => { :action => 'edit' }, :builder => TabularFormBuilder do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/index.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/trackers/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,8 @@ +api.array :trackers do + @trackers.each do |tracker| + api.tracker do + api.id tracker.id + api.name tracker.name + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/index.html.erb --- a/app/views/trackers/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/trackers/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,5 +1,5 @@
    -<%= link_to l(:label_tracker_new), {:action => 'new'}, :class => 'icon icon-add' %> +<%= link_to l(:label_tracker_new), new_tracker_path, :class => 'icon icon-add' %>

    <%=l(:label_tracker_plural)%>

    @@ -14,14 +14,14 @@ <% for tracker in @trackers %> "> - <%= link_to tracker.name, :action => 'edit', :id => tracker %> + <%= link_to h(tracker.name), edit_tracker_path(tracker) %> <% unless tracker.workflows.count > 0 %><%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), {:controller => 'workflows', :action => 'edit', :tracker_id => tracker} %>)<% end %> - <%= reorder_links('tracker', {:action => 'edit', :id => tracker}) %> + <%= reorder_links('tracker', {:action => 'update', :id => tracker}, :put) %> - <%= link_to(l(:button_delete), { :action => 'destroy', :id => tracker }, - :method => :post, - :confirm => l(:text_are_you_sure), - :class => 'icon icon-del') %> + <%= link_to(l(:button_delete), tracker_path(tracker), + :method => :delete, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/new.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/trackers/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +

    <%= link_to l(:label_tracker_plural), trackers_path %> » <%=l(:label_tracker_new)%>

    + +<% form_for @tracker, :builder => TabularFormBuilder do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/trackers/new.rhtml --- a/app/views/trackers/new.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -

    <%= link_to l(:label_tracker_plural), :controller => 'trackers', :action => 'index' %> » <%=l(:label_tracker_new)%>

    - -<% form_for :tracker, @tracker, :url => { :action => 'new' }, :builder => TabularFormBuilder do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,81 @@ +<%= javascript_include_tag "ssamr_institutions" %> + + +<%= error_messages_for 'user' %> + +
    + +
    +
    + <%=l(:label_information_plural)%> +

    <%= f.text_field :login, :required => true, :size => 25 %>

    +

    <%= f.text_field :firstname, :required => true %>

    +

    <%= f.text_field :lastname, :required => true %>

    +

    <%= f.text_field :mail, :required => true %>

    +

    <%= f.select :language, lang_options_for_select %>

    + <% if Setting.openid? %> +

    <%= f.text_field :identity_url %>

    + <% end %> + + <% @user.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :user, value %>

    + <% end %> + +

    <%= f.check_box :admin, :disabled => (@user == User.current) %>

    + <%= call_hook(:view_users_form, :user => @user, :form => f) %> +
    + +
    +

    <%=l(:label_ssamr_details)%>

    + <% fields_for :ssamr_user_details, :builder => TabularFormBuilder, :lang => current_language do |ssamr_user_detail| %> +

    + <%= ssamr_user_detail.text_area :description, :rows => 3, :cols => 40, :required => true, :class => 'wiki-edit' %> +

    + +

    + + <%= ssamr_user_detail.radio_button :institution_type, true %> + <%= ssamr_user_detail.collection_select(:institution_id, Institution.find(:all, :order => "institutions.order"), :id, :name, {:selected => @selected_institution_id, :prompt => true} ).gsub('&', '&') %> + +

    + + + +

    + + <%= ssamr_user_detail.radio_button :institution_type, false %> Other: + <%= ssamr_user_detail.text_field :other_institution %> + +

    + <% end %> +
    + + + +
    + <%=l(:label_authentication)%> + <% unless @auth_sources.empty? %> +

    <%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {Element.show('password_fields');} else {Element.hide('password_fields');}" %>

    + <% end %> +
    +

    <%= f.password_field :password, :required => true, :size => 25 %>
    + <%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    +

    <%= f.password_field :password_confirmation, :required => true, :size => 25 %>

    +
    +
    +
    + +
    +
    + <%=l(:field_mail_notification)%> + <%= render :partial => 'users/mail_notifications' %> +
    + +
    + <%=l(:label_preferences)%> + <%= render :partial => 'users/preferences' %> +
    +
    +
    +
    + diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_form.rhtml --- a/app/views/users/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -<%= javascript_include_tag "ssamr_institutions" %> - - -<%= error_messages_for 'user' %> - -
    - -
    -

    <%=l(:label_information_plural)%>

    -
    -

    <%= f.text_field :login, :required => true, :size => 25 %>

    -

    <%= f.text_field :firstname, :required => true %>

    -

    <%= f.text_field :lastname, :required => true %>

    -

    <%= f.text_field :mail, :required => true %>

    -

    <%= f.select :language, lang_options_for_select %>

    -<% if Setting.openid? %> -

    <%= f.text_field :identity_url %>

    -<% end %> - -<% @user.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :user, value %>

    -<% end %> - -

    <%= f.check_box :admin, :disabled => (@user == User.current) %>

    -<%= call_hook(:view_users_form, :user => @user, :form => f) %> -
    - -
    -

    <%=l(:label_ssamr_details)%>

    - <% fields_for :ssamr_user_details, :builder => TabularFormBuilder, :lang => current_language do |ssamr_user_detail| %> -

    - <%= ssamr_user_detail.text_area :description, :rows => 3, :cols => 40, :required => true, :class => 'wiki-edit' %> -

    - -

    - - <%= ssamr_user_detail.radio_button :institution_type, true %> - <%= ssamr_user_detail.collection_select(:institution_id, Institution.find(:all, :order => "institutions.order"), :id, :name, {:selected => @selected_institution_id, :prompt => true} ).gsub('&', '&') %> - -

    - - - -

    - - <%= ssamr_user_detail.radio_button :institution_type, false %> Other: - <%= ssamr_user_detail.text_field :other_institution %> - -

    - <% end %> -
    - - - -

    <%=l(:label_authentication)%>

    -
    -<% unless @auth_sources.empty? %> -

    <%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {Element.show('password_fields');} else {Element.hide('password_fields');}" %>

    -<% end %> -
    -

    <%= f.password_field :password, :required => true, :size => 25 %>
    -<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    -

    <%= f.password_field :password_confirmation, :required => true, :size => 25 %>

    -
    -
    -
    - -
    -

    <%=l(:field_mail_notification)%>

    -
    -<%= render :partial => 'users/mail_notifications' %> -
    - -

    <%=l(:label_preferences)%>

    -
    -<%= render :partial => 'users/preferences' %> -
    -
    -
    -
    - diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_general.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/_general.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +<% form_for @user, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + <% if @user.active? && email_delivery_enabled? -%> +

    + <% end -%> +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_general.rhtml --- a/app/views/users/_general.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -<% labelled_tabular_form_for :user, @user, :url => { :controller => 'users', :action => "update", :tab => nil }, :html => { :method => :put, :class => nil } do |f| %> - <%= render :partial => 'form', :locals => { :f => f } %> - <% if @user.active? -%> -

    - <% end -%> -

    <%= submit_tag l(:button_save) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_groups.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/_groups.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +<% form_for(:user, :url => { :action => 'update' }, :html => {:method => :put}) do %> +
    +<% Group.all.sort.each do |group| %> +
    +<% end %> +<%= hidden_field_tag 'user[group_ids][]', '' %> +
    +<%= submit_tag l(:button_save) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_groups.rhtml --- a/app/views/users/_groups.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -<% form_for(:user, :url => { :action => 'update' }, :html => {:method => :put}) do %> -
    -<% Group.all.sort.each do |group| %> -
    -<% end %> -<%= hidden_field_tag 'user[group_ids][]', '' %> -
    -<%= submit_tag l(:button_save) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_mail_notifications.html.erb --- a/app/views/users/_mail_notifications.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/users/_mail_notifications.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,5 @@

    +<%= label_tag "user_mail_notification", l(:description_user_mail_notification), :class => "hidden-for-sighted" %> <%= select_tag 'user[mail_notification]', options_for_select(user_mail_notification_options(@user), @user.mail_notification), :onchange => 'if (this.value == "selected") {Element.show("notified-projects")} else {Element.hide("notified-projects")}' %>

    @@ -8,5 +9,5 @@ <% end %>

    <%= l(:text_user_mail_option) %>

    <% end %> -

    <%= check_box_tag 'no_self_notified', 1, @user.pref[:no_self_notified] %>

    +

    diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_memberships.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/_memberships.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,62 @@ +<% roles = Role.find_all_givable %> +<% projects = Project.active.find(:all, :order => 'lft') %> + +
    +<% if @user.memberships.any? %> + + + + + + <%= call_hook(:view_users_memberships_table_header, :user => @user )%> + + + <% @user.memberships.each do |membership| %> + <% next if membership.new_record? %> + + + + + <%= call_hook(:view_users_memberships_table_row, :user => @user, :membership => membership, :roles => roles, :projects => projects )%> + + <% end; reset_cycle %> + +
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    + <%= link_to_project membership.project %> + + <%=h membership.roles.sort.collect(&:to_s).join(', ') %> + <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user, :membership_id => membership }, + :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %> +

    <% roles.each do |role| %> +
    + <% end %>

    + <%= hidden_field_tag 'membership[role_ids][]', '' %> +

    <%= submit_tag l(:button_change) %> + <%= link_to_function l(:button_cancel), "$('member-#{membership.id}-roles').show(); $('member-#{membership.id}-roles-form').hide(); return false;" %>

    + <% end %> +
    + <%= link_to_function l(:button_edit), "$('member-#{membership.id}-roles').hide(); $('member-#{membership.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %> + <%= link_to_remote(l(:button_delete), { :url => { :controller => 'users', :action => 'destroy_membership', :id => @user, :membership_id => membership }, + :method => :post }, + :class => 'icon icon-del') if membership.deletable? %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + +
    +<% if projects.any? %> +
    <%=l(:label_project_new)%> +<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user }) do %> +<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, projects) %> +

    <%= l(:label_role_plural) %>: +<% roles.each do |role| %> + +<% end %>

    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +
    +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/users/_memberships.rhtml --- a/app/views/users/_memberships.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -<% roles = Role.find_all_givable %> -<% projects = Project.active.find(:all, :order => 'lft') %> - -
    -<% if @user.memberships.any? %> - - - - - - <%= call_hook(:view_users_memberships_table_header, :user => @user )%> - - - <% @user.memberships.each do |membership| %> - <% next if membership.new_record? %> - - - - - <%= call_hook(:view_users_memberships_table_row, :user => @user, :membership => membership, :roles => roles, :projects => projects )%> - - <% end; reset_cycle %> - -
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    - <%= link_to_project membership.project %> - - <%=h membership.roles.sort.collect(&:to_s).join(', ') %> - <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user, :membership_id => membership }, - :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %> -

    <% roles.each do |role| %> -
    - <% end %>

    - <%= hidden_field_tag 'membership[role_ids][]', '' %> -

    <%= submit_tag l(:button_change) %> - <%= link_to_function l(:button_cancel), "$('member-#{membership.id}-roles').show(); $('member-#{membership.id}-roles-form').hide(); return false;" %>

    - <% end %> -
    - <%= link_to_function l(:button_edit), "$('member-#{membership.id}-roles').hide(); $('member-#{membership.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %> - <%= link_to_remote(l(:button_delete), { :url => { :controller => 'users', :action => 'destroy_membership', :id => @user, :membership_id => membership }, - :method => :post }, - :class => 'icon icon-del') if membership.deletable? %> -
    -<% else %> -

    <%= l(:label_no_data) %>

    -<% end %> -
    - -
    -<% if projects.any? %> -
    <%=l(:label_project_new)%> -<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user }) do %> -<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, projects) %> -

    <%= l(:label_role_plural) %>: -<% roles.each do |role| %> - -<% end %>

    -

    <%= submit_tag l(:button_add) %>

    -<% end %> -
    -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/users/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,12 @@ +
    +<%= link_to l(:label_profile), user_path(@user), :class => 'icon icon-user' %> +<%= change_status_link(@user) %> +<%= link_to(l(:button_delete), @user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current != @user %> +
    + +

    <%= link_to l(:label_user_plural), users_path %> » <%=h @user.login %>

    + +<%= render_tabs user_settings_tabs %> + +<% html_title(l(:label_user), @user.login, l(:label_administration)) -%> + diff -r 487d96eac004 -r 5e80956cc792 app/views/users/edit.rhtml --- a/app/views/users/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -
    -<%= link_to l(:label_profile), user_path(@user), :class => 'icon icon-user' %> -<%= change_status_link(@user) %> -<%= link_to(l(:button_delete), @user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current != @user %> -
    - -

    <%= link_to l(:label_user_plural), :controller => 'users', :action => 'index' %> » <%=h @user.login %>

    - -<%= render_tabs user_settings_tabs %> - -<% html_title(l(:label_user), @user.login, l(:label_administration)) -%> - diff -r 487d96eac004 -r 5e80956cc792 app/views/users/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +
    +<%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_user_plural)%>

    + +<% form_tag({}, :method => :get) do %> +
    <%= l(:label_filter_plural) %> + +<%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + +<% if @groups.present? %> + +<%= select_tag 'group_id', '' + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %> +<% end %> + + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %> +<%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %> +
    +<% end %> +  + +
    + + + <%= sort_header_tag('login', :caption => l(:field_login)) %> + <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> + <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> + <%= sort_header_tag('mail', :caption => l(:field_mail)) %> + <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %> + <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> + <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %> + + + +<% for user in @users -%> + <%= %w(anon active registered locked)[user.status] %>"> + + + + + + + + + +<% end -%> + +
    <%= avatar(user, :size => "14") %><%= link_to h(user.login), edit_user_path(user) %><%= h(user.firstname) %><%= h(user.lastname) %><%= checked_image user.admin? %><%= format_time(user.created_on) %> + <%= change_status_link(user) %> + <%= link_to(l(:button_delete), user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') unless User.current == user %> +
    +
    +

    <%= pagination_links_full @user_pages, @user_count %>

    + +<% html_title(l(:label_user_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/index.rhtml --- a/app/views/users/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -
    -<%= link_to l(:label_user_new), {:action => 'new'}, :class => 'icon icon-add' %> -
    - -

    <%=l(:label_user_plural)%>

    - -<% form_tag({}, :method => :get) do %> -
    <%= l(:label_filter_plural) %> - -<%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> - -<% if @groups.present? %> - -<%= select_tag 'group_id', '' + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %> -<% end %> - - -<%= text_field_tag 'name', params[:name], :size => 30 %> -<%= submit_tag l(:button_apply), :class => "small", :name => nil %> -<%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %> -
    -<% end %> -  - -
    - - - <%= sort_header_tag('login', :caption => l(:field_login)) %> - <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> - <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> - <%= sort_header_tag('mail', :caption => l(:field_mail)) %> - <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %> - <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> - <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %> - - - -<% for user in @users -%> - <%= %w(anon active registered locked)[user.status] %>"> - - - - - - - - - -<% end -%> - -
    <%= avatar(user, :size => "14") %><%= link_to h(user.login), edit_user_path(user) %><%= h(user.firstname) %><%= h(user.lastname) %><%= checked_image user.admin? %><%= format_time(user.created_on) %> - <%= change_status_link(user) %> - <%= link_to(l(:button_delete), user, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') unless User.current == user %> -
    -
    -

    <%= pagination_links_full @user_pages, @user_count %>

    - -<% html_title(l(:label_user_plural)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/new.html.erb --- a/app/views/users/new.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/users/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,12 @@ -

    <%= link_to l(:label_user_plural), :controller => 'users', :action => 'index' %> » <%=l(:label_user_new)%>

    +

    <%= link_to l(:label_user_plural), users_path %> » <%=l(:label_user_new)%>

    -<% labelled_tabular_form_for :user, @user, :url => { :action => "create" }, :html => { :class => nil } do |f| %> - <%= render :partial => 'form', :locals => { :f => f } %> -

    -

    - <%= submit_tag l(:button_create) %> - <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> -

    +<% form_for @user, :builder => TabularFormBuilder do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + <% if email_delivery_enabled? %> +

    + <% end %> +

    + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> +

    <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/show.api.rsb --- a/app/views/users/show.api.rsb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/users/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -6,9 +6,9 @@ api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail api.created_on @user.created_on api.last_login_on @user.last_login_on - + render_api_custom_values @user.visible_custom_field_values, api - + api.array :memberships do @memberships.each do |membership| api.membership do diff -r 487d96eac004 -r 5e80956cc792 app/views/users/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/users/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,77 @@ +
    +<%= link_to(l(:button_edit), edit_user_path(@user), :class => 'icon icon-edit') if User.current.admin? %> +
    + +

    <%= avatar @user, :size => "50" %> <%=h @user.name %>

    + +
    +
      + <% unless @user.pref.hide_mail %> +
    • <%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %>
    • + <% end %> + <% @user.visible_custom_field_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
    • <%=h custom_value.custom_field.name%>: <%=h show_value(custom_value) %>
    • + <% end %> + <% end %> +
    • <%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
    • + <% unless @user.last_login_on.nil? %> +
    • <%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %>
    • + <% end %> +
    + +

    <%=l(:label_ssamr_description)%>

    +<%= textilizable @description %> + +

    <%=l(:label_ssamr_institution)%>

    +

    <%= h @institution_name %>

    + + +<% unless @memberships.empty? %> +

    <%=l(:label_project_plural)%>

    +
      +<% for membership in @memberships %> +
    • <%= link_to_project(membership.project) %> + (<%=h membership.roles.sort.collect(&:to_s).join(', ') %>, <%= format_date(membership.created_on) %>)
    • +<% end %> +
    +<% end %> +<%= call_hook :view_account_left_bottom, :user => @user %> +
    + +
    + +<% unless @events_by_day.empty? %> +

    <%= link_to l(:label_activity), :controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %>

    + +

    +<%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %> +

    + +
    +<% @events_by_day.keys.sort.reverse.each do |day| %> +

    <%= format_activity_day(day) %>

    +
    +<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> +
    + <%= format_time(e.event_datetime, false) %> + <%= content_tag('span', h(e.project), :class => 'project') %> + <%= link_to format_activity_title(e.event_title), e.event_url %>
    +
    <%= format_activity_description(e.event_description) %>
    +<% end -%> +
    +<% end -%> +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :user_id => @user, :format => :atom, :key => User.current.rss_key) %> +<% end %> +<% end %> +<%= call_hook :view_account_right_bottom, :user => @user %> +
    + +<% html_title @user.name %> diff -r 487d96eac004 -r 5e80956cc792 app/views/users/show.rhtml --- a/app/views/users/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -
    -<%= link_to(l(:button_edit), edit_user_path(@user), :class => 'icon icon-edit') if User.current.admin? %> -
    - -

    <%= avatar @user, :size => "50" %> <%=h @user.name %>

    - -
    -
      - <% unless @user.pref.hide_mail %> -
    • <%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %>
    • - <% end %> - <% @user.visible_custom_field_values.each do |custom_value| %> - <% if !custom_value.value.blank? %> -
    • <%=h custom_value.custom_field.name%>: <%=h show_value(custom_value) %>
    • - <% end %> - <% end %> -
    • <%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
    • - <% unless @user.last_login_on.nil? %> -
    • <%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %>
    • - <% end %> -
    - -

    <%=l(:label_ssamr_description)%>

    -<%= textilizable @description %> - -

    <%=l(:label_ssamr_institution)%>

    -

    <%= h @institution_name %>

    - - -<% unless @memberships.empty? %> -

    <%=l(:label_project_plural)%>

    -
      -<% for membership in @memberships %> -
    • <%= link_to_project(membership.project) %> - (<%=h membership.roles.sort.collect(&:to_s).join(', ') %>, <%= format_date(membership.created_on) %>)
    • -<% end %> -
    -<% end %> -<%= call_hook :view_account_left_bottom, :user => @user %> -
    - -
    - -<% unless @events_by_day.empty? %> -

    <%= link_to l(:label_activity), :controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %>

    - -

    -<%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %> -

    - -
    -<% @events_by_day.keys.sort.reverse.each do |day| %> -

    <%= format_activity_day(day) %>

    -
    -<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> -
    - <%= format_time(e.event_datetime, false) %> - <%= content_tag('span', h(e.project), :class => 'project') %> - <%= link_to format_activity_title(e.event_title), e.event_url %>
    -
    <%= format_activity_description(e.event_description) %>
    -<% end -%> -
    -<% end -%> -
    - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :key => User.current.rss_key} %> -<% end %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :user_id => @user, :format => :atom, :key => User.current.rss_key) %> -<% end %> -<% end %> -<%= call_hook :view_account_right_bottom, :user => @user %> -
    - -<% html_title @user.name %> diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/_form.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +<%= back_url_hidden_field_tag %> +<%= error_messages_for 'version' %> + +
    +

    <%= f.text_field :name, :size => 60, :required => true %>

    +

    <%= f.text_field :description, :size => 60 %>

    +

    <%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %>

    +

    <%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %>

    +

    <%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %>

    +

    <%= f.select :sharing, @version.allowed_sharings.collect {|v| [format_version_sharing(v), v]} %>

    + +<% @version.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :version, value %>

    +<% end %> + +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/_form.rhtml --- a/app/views/versions/_form.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -<%= error_messages_for 'version' %> - -
    -

    <%= f.text_field :name, :size => 60, :required => true %>

    -

    <%= f.text_field :description, :size => 60 %>

    -

    <%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %>

    -

    <%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %>

    -

    <%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %>

    -

    <%= f.select :sharing, @version.allowed_sharings.collect {|v| [format_version_sharing(v), v]} %>

    - -<% @version.custom_field_values.each do |value| %> -

    <%= custom_field_tag_with_label :version, value %>

    -<% end %> - -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/_issue_counts.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/_issue_counts.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +
    +
    + +<%= l(:label_issues_by, + select_tag('status_by', + status_by_options_for_select(criteria), + :id => 'status_by_select', + :onchange => remote_function(:url => status_by_version_path(version), + :with => "Form.serialize('status_by_form')"))) %> + +<% if counts.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> + + <% counts.each do |count| %> + + + + + <% end %> +
    + <%= link_to h(count[:group]), {:controller => 'issues', + :action => 'index', + :project_id => version.project, + :set_filter => 1, + :status_id => '*', + :fixed_version_id => version}.merge("#{criteria}_id".to_sym => count[:group]) %> + + <%= progress_bar((count[:closed].to_f / count[:total])*100, + :legend => "#{count[:closed]}/#{count[:total]}", + :width => "#{(count[:total].to_f / max * 200).floor}px;") %> +
    +<% end %> +
    +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/_issue_counts.rhtml --- a/app/views/versions/_issue_counts.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -
    -
    - -<%= l(:label_issues_by, - select_tag('status_by', - status_by_options_for_select(criteria), - :id => 'status_by_select', - :onchange => remote_function(:url => status_by_project_version_path(version.project, version), - :with => "Form.serialize('status_by_form')"))) %> - -<% if counts.empty? %> -

    <%= l(:label_no_data) %>

    -<% else %> - - <% counts.each do |count| %> - - - - - <% end %> -
    - <%= link_to count[:group], {:controller => 'issues', - :action => 'index', - :project_id => version.project, - :set_filter => 1, - :status_id => '*', - :fixed_version_id => version}.merge("#{criteria}_id".to_sym => count[:group]) %> - - <%= progress_bar((count[:closed].to_f / count[:total])*100, - :legend => "#{count[:closed]}/#{count[:total]}", - :width => "#{(count[:total].to_f / max * 200).floor}px;") %> -
    -<% end %> -
    -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/_overview.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/_overview.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +<% if version.completed? %> +

    <%= format_date(version.effective_date) %>

    +<% elsif version.effective_date %> +

    <%= due_date_distance_in_words(version.effective_date) %> (<%= format_date(version.effective_date) %>)

    +<% end %> + +

    <%=h version.description %>

    +
      + <% version.custom_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
    • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    • + <% end %> + <% end %> +
    + +<% if version.fixed_issues.count > 0 %> + <%= progress_bar([version.closed_pourcent, version.completed_pourcent], :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %> +

    + <%= link_to_if(version.closed_issues_count > 0, l(:label_x_closed_issues_abbr, :count => version.closed_issues_count), :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %> + (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%) +   + <%= link_to_if(version.open_issues_count > 0, l(:label_x_open_issues_abbr, :count => version.open_issues_count), :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %> + (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%) +

    +<% else %> +

    <%= l(:label_roadmap_no_issues) %>

    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/_overview.rhtml --- a/app/views/versions/_overview.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -<% if version.completed? %> -

    <%= format_date(version.effective_date) %>

    -<% elsif version.effective_date %> -

    <%= due_date_distance_in_words(version.effective_date) %> (<%= format_date(version.effective_date) %>)

    -<% end %> - -

    <%=h version.description %>

    -
      - <% version.custom_values.each do |custom_value| %> - <% if !custom_value.value.blank? %> -
    • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    • - <% end %> - <% end %> -
    - -<% if version.fixed_issues.count > 0 %> - <%= progress_bar([version.closed_pourcent, version.completed_pourcent], :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %> -

    - <%= link_to_if(version.closed_issues_count > 0, l(:label_x_closed_issues_abbr, :count => version.closed_issues_count), :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %> - (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%) -   - <%= link_to_if(version.open_issues_count > 0, l(:label_x_open_issues_abbr, :count => version.open_issues_count), :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %> - (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%) -

    -<% else %> -

    <%= l(:label_roadmap_no_issues) %>

    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +

    <%=l(:label_version)%>

    + +<% labelled_tabular_form_for @version do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> + diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/edit.rhtml --- a/app/views/versions/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -

    <%=l(:label_version)%>

    - -<% labelled_tabular_form_for :version, @version, :url => project_version_path(@project, @version), :html => {:method => :put} do |f| %> -<%= render :partial => 'form', :locals => { :f => f } %> -<%= submit_tag l(:button_save) %> -<% end %> - diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/index.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/index.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +api.array :versions, api_meta(:total_count => @versions.size) do + @versions.each do |version| + api.version do + api.id version.id + api.project(:id => version.project_id, :name => version.project.name) unless version.project.nil? + + api.name version.name + api.description version.description + api.status version.status + api.due_date version.effective_date + + render_api_custom_values version.custom_field_values, api + + api.created_on version.created_on + api.updated_on version.updated_on + end + end +end diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/index.html.erb --- a/app/views/versions/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/versions/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,24 +1,28 @@ +
    + <%= link_to l(:label_version_new), new_project_version_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_versions, @project) %> +
    +

    <%=l(:label_roadmap)%>

    <% if @versions.empty? %>

    <%= l(:label_no_data) %>

    <% else %>
    -<% @versions.each do |version| %> -

    <%= tag 'a', :name => version.name %><%= link_to_version version %>

    +<% @versions.each do |version| %> +

    <%= tag 'a', :name => h(version.name) %><%= link_to_version version %>

    <%= render :partial => 'versions/overview', :locals => {:version => version} %> <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %> <% if (issues = @issues_by_version[version]) && issues.size > 0 %> - <% form_tag({}) do -%> + <% form_tag({}) do -%> - <%- issues.each do |issue| -%> + <% issues.each do |issue| -%> - <%- end -%> + <% end -%> <% end %> <% end %> @@ -37,7 +41,7 @@
    <% if @project.descendants.active.any? %> - <%= hidden_field_tag 'with_subprojects', 0 %> + <%= hidden_field_tag 'with_subprojects', 0 %>
    <% end %>

    <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %>

    diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/new.html.erb --- a/app/views/versions/new.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/versions/new.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,6 @@

    <%=l(:label_version_new)%>

    -<% labelled_tabular_form_for :version, @version, :url => project_versions_path(@project) do |f| %> +<% labelled_tabular_form_for @version, :url => project_versions_path(@project) do |f| %> <%= render :partial => 'versions/form', :locals => { :f => f } %> <%= submit_tag l(:button_create) %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/show.api.rsb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/show.api.rsb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +api.version do + api.id @version.id + api.project(:id => @version.project_id, :name => @version.project.name) unless @version.project.nil? + + api.name @version.name + api.description @version.description + api.status @version.status + api.due_date @version.effective_date + + render_api_custom_values @version.custom_field_values, api + + api.created_on @version.created_on + api.updated_on @version.updated_on +end diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/versions/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,56 @@ +
    +<%= link_to(l(:button_edit), edit_version_path(@version), :class => 'icon icon-edit') if User.current.allowed_to?(:manage_versions, @version.project) %> +<%= link_to_if_authorized(l(:button_edit_associated_wikipage, :page_title => @version.wiki_page_title), {:controller => 'wiki', :action => 'edit', :project_id => @version.project, :id => Wiki.titleize(@version.wiki_page_title)}, :class => 'icon icon-edit') unless @version.wiki_page_title.blank? || @version.project.wiki.nil? %> +<%= link_to(l(:button_delete), version_path(@version, :back_url => url_for(:controller => 'versions', :action => 'index', :project_id => @version.project)), + :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del') if User.current.allowed_to?(:manage_versions, @version.project) %> +<%= call_hook(:view_versions_show_contextual, { :version => @version, :project => @project }) %> +
    + +

    <%= h(@version.name) %>

    + +
    +<%= render :partial => 'versions/overview', :locals => {:version => @version} %> +<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> + +
    +<% if @version.estimated_hours > 0 || User.current.allowed_to?(:view_time_entries, @project) %> +
    <%= l(:label_time_tracking) %> + + + + + +<% if User.current.allowed_to?(:view_time_entries, @project) %> + + + + +<% end %> +
    <%= l(:field_estimated_hours) %><%= html_hours(l_hours(@version.estimated_hours)) %>
    <%= l(:label_spent_time) %><%= html_hours(l_hours(@version.spent_hours)) %>
    +
    +<% end %> + +
    +<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %> +
    +
    + +<% if @issues.present? %> +<% form_tag({}) do -%> + + + <%- @issues.each do |issue| -%> + + + + + <% end %> + +<% end %> +<%= context_menu issues_context_menu_path %> +<% end %> +
    + +<%= call_hook :view_versions_show_bottom, :version => @version %> + +<% html_title @version.name %> diff -r 487d96eac004 -r 5e80956cc792 app/views/versions/show.rhtml --- a/app/views/versions/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -
    -<%= link_to_if_authorized l(:button_edit), {:controller => 'versions', :action => 'edit', :id => @version}, :class => 'icon icon-edit' %> -<%= link_to_if_authorized(l(:button_edit_associated_wikipage, :page_title => @version.wiki_page_title), {:controller => 'wiki', :action => 'edit', :project_id => @version.project, :id => Wiki.titleize(@version.wiki_page_title)}, :class => 'icon icon-edit') unless @version.wiki_page_title.blank? || @version.project.wiki.nil? %> -<%= call_hook(:view_versions_show_contextual, { :version => @version, :project => @project }) %> -
    - -

    <%= h(@version.name) %>

    - -
    -<%= render :partial => 'versions/overview', :locals => {:version => @version} %> -<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> - -
    -<% if @version.estimated_hours > 0 || User.current.allowed_to?(:view_time_entries, @project) %> -
    <%= l(:label_time_tracking) %> - - - - - -<% if User.current.allowed_to?(:view_time_entries, @project) %> - - - - -<% end %> -
    <%= l(:field_estimated_hours) %><%= html_hours(l_hours(@version.estimated_hours)) %>
    <%= l(:label_spent_time) %><%= html_hours(l_hours(@version.spent_hours)) %>
    -
    -<% end %> - -
    -<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %> -
    -
    - -<% if @issues.present? %> -<% form_tag({}) do -%> - - - <%- @issues.each do |issue| -%> - - - - - <% end %> - -<% end %> -<%= context_menu issues_context_menu_path %> -<% end %> -
    - -<%= call_hook :view_versions_show_bottom, :version => @version %> - -<% html_title @version.name %> diff -r 487d96eac004 -r 5e80956cc792 app/views/watchers/_watchers.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/watchers/_watchers.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +
    +<%= link_to_remote l(:button_add), + :url => {:controller => 'watchers', + :action => 'new', + :object_type => watched.class.name.underscore, + :object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %> +
    + +

    <%= l(:label_issue_watchers) %> (<%= watched.watcher_users.size %>)

    + +<% unless @watcher.nil? %> + <% remote_form_for(:watcher, @watcher, + :url => {:controller => 'watchers', + :action => 'new', + :object_type => watched.class.name.underscore, + :object_id => watched}, + :method => :post, + :html => {:id => 'new-watcher-form'}) do |f| %> +

    <%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %> + + <%= submit_tag l(:button_add) %> + <%= toggle_link l(:button_cancel), 'new-watcher-form'%>

    + <% end %> +<% end %> + +<%= watchers_list(watched) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/watchers/_watchers.rhtml --- a/app/views/watchers/_watchers.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -
    -<%= link_to_remote l(:button_add), - :url => {:controller => 'watchers', - :action => 'new', - :object_type => watched.class.name.underscore, - :object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %> -
    - -

    <%= l(:label_issue_watchers) %> (<%= watched.watcher_users.size %>)

    - -<% unless @watcher.nil? %> - <% remote_form_for(:watcher, @watcher, - :url => {:controller => 'watchers', - :action => 'new', - :object_type => watched.class.name.underscore, - :object_id => watched}, - :method => :post, - :html => {:id => 'new-watcher-form'}) do |f| %> -

    <%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %> - - <%= submit_tag l(:button_add) %> - <%= toggle_link l(:button_cancel), 'new-watcher-form'%>

    - <% end %> -<% end %> - -<%= watchers_list(watched) %> diff -r 487d96eac004 -r 5e80956cc792 app/views/welcome/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/welcome/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +<% if not Setting.notifications_text.empty? %> +
    + <%= textilizable Setting.notifications_text %> +
    +<% end %> + +

    <%= l(:label_home_heading) %>

    + +
    + <%= textilizable Setting.welcome_text %> + + <%= call_hook(:view_welcome_index_left, :projects => @projects) %> +
    + +
    + <% if @site_news.any? %> +
    +

    <%=l(:label_news_site_latest)%>

    + <%= render :partial => 'news/news', :locals => { :project => @site_project }, :collection => @site_news %> + + <%= link_to l(:label_news_more), { :controller => 'projects', :action => @site_project.identifier, :id => 'news' } %> +
    + <% end %> + <% if @projects.any? %> +
    +

    <%=l(:label_project_latest)%>

    +
      + <% for project in @projects %> + <% @project = project %> +
    • + <%= link_to_project project %> + <%= format_time(project.created_on)%> + <%= render_project_short_description project %> +
    • + <% end %> + <% @project = nil %> +
    + <%= link_to l(:label_projects_more), :controller => 'projects' %> +
    + <% end %> + <%= call_hook(:view_welcome_index_right, :projects => @projects) %> +
    + +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<%= auto_discovery_link_tag(:atom, {:controller => 'news', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, + :title => "#{Setting.app_title}: #{l(:label_news_latest)}") %> +<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, + :title => "#{Setting.app_title}: #{l(:label_activity)}") %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/welcome/index.rhtml --- a/app/views/welcome/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -<% if not Setting.notifications_text.empty? %> -
    - <%= textilizable Setting.notifications_text %> -
    -<% end %> - -

    <%= l(:label_home_heading) %>

    - -
    - <%= textilizable Setting.welcome_text %> - - <%= call_hook(:view_welcome_index_left, :projects => @projects) %> -
    - -
    - <% if @site_news.any? %> -
    -

    <%=l(:label_news_site_latest)%>

    - <%= render :partial => 'news/news', :locals => { :project => @site_project }, :collection => @site_news %> - - <%= link_to l(:label_news_more), { :controller => 'projects', :action => @site_project.identifier, :id => 'news' } %> -
    - <% end %> - <% if @projects.any? %> -
    -

    <%=l(:label_project_latest)%>

    -
      - <% for project in @projects %> - <% @project = project %> -
    • - <%= link_to_project project %> - <%= format_time(project.created_on)%> - <%= render_project_short_description project %> -
    • - <% end %> - <% @project = nil %> -
    - <%= link_to l(:label_projects_more), :controller => 'projects' %> -
    - <% end %> - <%= call_hook(:view_welcome_index_right, :projects => @projects) %> -
    - -<% content_for :header_tags do %> -<%= stylesheet_link_tag 'scm' %> -<%= auto_discovery_link_tag(:atom, {:controller => 'news', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, - :title => "#{Setting.app_title}: #{l(:label_news_latest)}") %> -<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, - :title => "#{Setting.app_title}: #{l(:label_activity)}") %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/welcome/robots.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/welcome/robots.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +User-agent: * +<% @projects.each do |p| -%> +Disallow: /projects/<%= p.to_param %>/repository +Disallow: /projects/<%= p.to_param %>/issues +Disallow: /projects/<%= p.to_param %>/activity +<% end -%> +Disallow: /issues/gantt +Disallow: /issues/calendar +Disallow: /activity diff -r 487d96eac004 -r 5e80956cc792 app/views/welcome/robots.rhtml --- a/app/views/welcome/robots.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -User-agent: * -<% @projects.each do |p| -%> -Disallow: /projects/<%= p.to_param %>/repository -Disallow: /projects/<%= p.to_param %>/issues -Disallow: /projects/<%= p.to_param %>/activity -<% end -%> -Disallow: /issues/gantt -Disallow: /issues/calendar -Disallow: /activity diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/_content.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/_content.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,4 @@ +
    + <%= textilizable content, :text, :attachments => content.page.attachments, + :edit_section_links => (@sections_editable && {:controller => 'wiki', :action => 'edit', :project_id => @page.project, :id => @page.title}) %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/_content.rhtml --- a/app/views/wiki/_content.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -
    - <%= textilizable content, :text, :attachments => content.page.attachments %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/_sidebar.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/_sidebar.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,9 @@ +<% if @wiki && @wiki.sidebar -%> + <%= textilizable @wiki.sidebar.content, :text %> +<% end -%> + +

    <%= l(:label_wiki) %>

    + +<%= link_to l(:field_start_page), {:action => 'show', :id => nil} %>
    +<%= link_to l(:label_index_by_title), {:action => 'index'} %>
    +<%= link_to l(:label_index_by_date), {:action => 'date_index'} %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/_sidebar.rhtml --- a/app/views/wiki/_sidebar.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -<% if @wiki && @wiki.sidebar -%> - <%= textilizable @wiki.sidebar.content, :text %> -<% end -%> - -

    <%= l(:label_wiki) %>

    - -<%= link_to l(:field_start_page), {:action => 'show', :id => nil} %>
    -<%= link_to l(:label_index_by_title), {:action => 'index'} %>
    -<%= link_to l(:label_index_by_date), {:action => 'date_index'} %>
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/annotate.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/annotate.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +
    +<%= link_to(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit') %> +<%= link_to(l(:label_history), + {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +

    +<%= l(:label_version) %> <%= link_to h(@annotate.content.version), + :action => 'show', :project_id => @project, + :id => @page.title, :version => @annotate.content.version %> +(<%= h(@annotate.content.author ? + @annotate.content.author.name : l(:label_user_anonymous)) + %>, <%= format_time(@annotate.content.updated_on) %>) +

    + +<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> + + + +<% line_num = 1 %> +<% @annotate.lines.each do |line| -%> + + + + + + +<% line_num += 1 %> +<% end -%> + +
    <%= line_num %><%= link_to line[0], :controller => 'wiki', + :action => 'show', :project_id => @project, + :id => @page.title, :version => line[0] %><%= h(line[1]) %>
    <%=h line[2] %>
    + +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/annotate.rhtml --- a/app/views/wiki/annotate.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -
    -<%= link_to(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit') %> -<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> -
    - -

    <%= @page.pretty_title %>

    - -

    -<%= l(:label_version) %> <%= link_to @annotate.content.version, :action => 'show', :id => @page.title, :version => @annotate.content.version %> -(<%= @annotate.content.author ? @annotate.content.author.name : "anonyme" %>, <%= format_time(@annotate.content.updated_on) %>) -

    - -<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> - - - -<% line_num = 1 %> -<% @annotate.lines.each do |line| -%> - - - - - - -<% line_num += 1 %> -<% end -%> - -
    <%= line_num %><%= link_to line[0], :controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title, :version => line[0] %><%= h(line[1]) %>
    <%=h line[2] %>
    - -<% content_for :header_tags do %> -<%= stylesheet_link_tag 'scm' %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/date_index.html.erb --- a/app/views/wiki/date_index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/wiki/date_index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -12,7 +12,7 @@

    <%= format_date(date) %>

      <% @pages_by_date[date].each do |page| %> -
    • <%= link_to page.pretty_title, :action => 'show', :id => page.title, :project_id => page.project %>
    • +
    • <%= link_to h(page.pretty_title), :action => 'show', :id => page.title, :project_id => page.project %>
    • <% end %>
    <% end %> @@ -23,8 +23,8 @@ <% unless @pages.empty? %> <% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> - <%= f.link_to('HTML', :url => {:action => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> + <%= f.link_to('HTML', :url => {:action => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %> <% end %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/destroy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/destroy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,22 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +<% form_tag({}, :method => :delete) do %> +
    +

    <%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %>

    +


    + +<% if @reassignable_to.any? %> +
    +: +<%= label_tag "reassign_to_id", l(:description_wiki_subpages_reassign), :class => "hidden-for-sighted" %> +<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to), + :onclick => "$('todo_reassign').checked = true;" %> +<% end %> +

    +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/destroy.rhtml --- a/app/views/wiki/destroy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -

    <%=h @page.pretty_title %>

    - -<% form_tag({}, :method => :delete) do %> -
    -

    <%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %>

    -


    - -<% if @reassignable_to.any? %> -
    -: -<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to), - :onclick => "$('todo_reassign').checked = true;" %> -<% end %> -

    -
    - -<%= submit_tag l(:button_apply) %> -<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/diff.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/diff.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,27 @@ +
    +<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, + :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h(@page.pretty_title) %>

    + +

    +<%= l(:label_version) %> <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %> +(<%= @diff.content_from.author ? + @diff.content_from.author.name : l(:label_user_anonymous) + %>, <%= format_time(@diff.content_from.updated_on) %>) +→ +<%= l(:label_version) %> <%= link_to @diff.content_to.version, :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => @diff.content_to.version + %>/<%= @page.content.version %> +(<%= @diff.content_to.author ? + link_to_user(@diff.content_to.author.name) : l(:label_user_anonymous) + %>, <%= format_time(@diff.content_to.updated_on) %>) +

    + +
    +<%= simple_format_without_paragraph @diff.to_html %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/diff.rhtml --- a/app/views/wiki/diff.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -
    -<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> -
    - -

    <%= @page.pretty_title %>

    - -

    -<%= l(:label_version) %> <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %> -(<%= @diff.content_from.author ? @diff.content_from.author.name : "anonyme" %>, <%= format_time(@diff.content_from.updated_on) %>) -→ -<%= l(:label_version) %> <%= link_to @diff.content_to.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_to.version %>/<%= @page.content.version %> -(<%= @diff.content_to.author ? @diff.content_to.author.name : "anonyme" %>, <%= format_time(@diff.content_to.updated_on) %>) -

    - -
    -<%= simple_format_without_paragraph @diff.to_html %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +<% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> +<%= f.hidden_field :version %> +<% if @section %> +<%= hidden_field_tag 'section', @section %> +<%= hidden_field_tag 'section_hash', @section_hash %> +<% end %> +<%= error_messages_for 'content' %> + +

    <%= text_area_tag 'content[text]', @text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %>

    +


    <%= f.text_field :comments, :size => 120 %>

    +


    <%= render :partial => 'attachments/form' %>

    + +

    <%= submit_tag l(:button_save) %> + <%= link_to_remote l(:label_preview), + { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title }, + :method => :post, + :update => 'preview', + :with => "Form.serialize('wiki_form')", + :complete => "Element.scrollTo('preview')" + }, :accesskey => accesskey(:preview) %>

    +<%= wikitoolbar_for 'content_text' %> +<% end %> + +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> + <%= robot_exclusion_tag %> +<% end %> + +<% html_title @page.pretty_title %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/edit.rhtml --- a/app/views/wiki/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -

    <%=h @page.pretty_title %>

    - -<% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> -<%= f.hidden_field :version %> -<%= error_messages_for 'content' %> - -

    <%= f.text_area :text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %>

    -


    <%= f.text_field :comments, :size => 120 %>

    -


    <%= render :partial => 'attachments/form' %>

    - -

    <%= submit_tag l(:button_save) %> - <%= link_to_remote l(:label_preview), - { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title }, - :method => :post, - :update => 'preview', - :with => "Form.serialize('wiki_form')", - :complete => "Element.scrollTo('preview')" - }, :accesskey => accesskey(:preview) %>

    -<%= wikitoolbar_for 'content_text' %> -<% end %> - -
    - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> - <%= robot_exclusion_tag %> -<% end %> - -<% html_title @page.pretty_title %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/export.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/export.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,21 @@ + + + +<%=h @page.pretty_title %> + + + + +<%= textilizable @content, :text, :wiki_links => :local %> + + diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/export.rhtml --- a/app/views/wiki/export.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ - - - -<%=h @page.pretty_title %> - - - - -<%= textilizable @content, :text, :wiki_links => :local %> - - diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/export_multiple.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/export_multiple.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,34 @@ + + + +<%=h @wiki.project.name %> + + + + + +<%= l(:label_index_by_title) %> + + +<% @pages.each do |page| %> +
    + +<%= textilizable page.content ,:text, :wiki_links => :anchor %> +<% end %> + + + diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/export_multiple.rhtml --- a/app/views/wiki/export_multiple.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ - - - -<%=h @wiki.project.name %> - - - - - -<%= l(:label_index_by_title) %> - - -<% @pages.each do |page| %> -
    - -<%= textilizable page.content ,:text, :wiki_links => :anchor %> -<% end %> - - - diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/history.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/history.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,37 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h(@page.pretty_title) %>

    + +

    <%= l(:label_history) %>

    + +<% form_tag({:action => "diff"}, :method => :get) do %> + + + + + + + + + + + +<% show_diff = @versions.size > 1 %> +<% line_num = 1 %> +<% @versions.each do |ver| %> +"> + + + + + + + + +<% line_num += 1 %> +<% end %> + +
    #<%= l(:field_updated_on) %><%= l(:field_author) %><%= l(:field_comments) %>
    <%= link_to h(ver.version), :action => 'show', :id => @page.title, :project_id => @page.project, :version => ver.version %><%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < @versions.size) %><%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}") if show_diff && (line_num > 1) %><%= format_time(ver.updated_on) %><%= link_to_user ver.author %><%=h ver.comments %><%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %>
    +<%= submit_tag l(:label_view_diff), :class => 'small' if show_diff %> +<%= pagination_links_full @version_pages, @version_count, :page_param => :p %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/history.rhtml --- a/app/views/wiki/history.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -

    <%= @page.pretty_title %>

    - -

    <%= l(:label_history) %>

    - -<% form_tag({:action => "diff"}, :method => :get) do %> - - - - - - - - - - - -<% show_diff = @versions.size > 1 %> -<% line_num = 1 %> -<% @versions.each do |ver| %> -"> - - - - - - - - -<% line_num += 1 %> -<% end %> - -
    #<%= l(:field_updated_on) %><%= l(:field_author) %><%= l(:field_comments) %>
    <%= link_to ver.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => ver.version %><%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < @versions.size) %><%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}") if show_diff && (line_num > 1) %><%= format_time(ver.updated_on) %><%= link_to_user ver.author %><%=h ver.comments %><%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %>
    -<%= submit_tag l(:label_view_diff), :class => 'small' if show_diff %> -<%= pagination_links_full @version_pages, @version_count, :page_param => :p %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/index.html.erb --- a/app/views/wiki/index.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/wiki/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -16,8 +16,8 @@ <% unless @pages.empty? %> <% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> - <%= f.link_to('HTML', :url => {:action => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> + <%= f.link_to('HTML', :url => {:action => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %> <% end %> <% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/rename.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/rename.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @original_title %>

    + +<%= error_messages_for 'page' %> + +<% labelled_tabular_form_for :wiki_page, @page, :url => { :action => 'rename' } do |f| %> +
    +

    <%= f.text_field :title, :required => true, :size => 100 %>

    +

    <%= f.check_box :redirect_existing_links %>

    +

    <%= f.select :parent_id, "" + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - @page.self_and_descendants, @page.parent), :label => :field_parent_title %>

    +
    +<%= submit_tag l(:button_rename) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/rename.rhtml --- a/app/views/wiki/rename.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -

    <%= l(:button_rename) %>: <%= @original_title %>

    - -<%= error_messages_for 'page' %> - -<% labelled_tabular_form_for :wiki_page, @page, :url => { :action => 'rename' } do |f| %> -
    -

    <%= f.text_field :title, :required => true, :size => 100 %>

    -

    <%= f.check_box :redirect_existing_links %>

    -

    <%= f.select :parent_id, "" + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - @page.self_and_descendants, @page.parent), :label => :field_parent_title %>

    -
    -<%= submit_tag l(:button_rename) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/show.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wiki/show.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,69 @@ +
    +<% if @editable %> +<%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.current_version? %> +<%= watcher_tag(@page, User.current) %> +<%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %> +<%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %> +<%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') if @content.current_version? %> +<%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %> +<%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page.title, :version => @content.version }, :class => 'icon icon-cancel') unless @content.current_version? %> +<% end %> +<%= link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +<% unless @content.current_version? %> +

    + <%= link_to(("\xc2\xab " + l(:label_previous)), + :action => 'show', :id => @page.title, :project_id => @page.project, + :version => (@content.version - 1)) + " - " if @content.version > 1 %> + <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> + <%= '(' + link_to(l(:label_diff), :controller => 'wiki', :action => 'diff', + :id => @page.title, :project_id => @page.project, + :version => @content.version) + ')' if @content.version > 1 %> - + <%= link_to((l(:label_next) + " \xc2\xbb"), :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %> + <%= link_to(l(:label_current_version), :action => 'show', :id => @page.title, :project_id => @page.project) %> +
    + <%= @content.author ? link_to_user(@content.author) : l(:label_user_anonymous) + %>, <%= format_time(@content.updated_on) %>
    + <%=h @content.comments %> +

    +
    +<% end %> + +<%= render(:partial => "wiki/content", :locals => {:content => @content}) %> + +<%= link_to_attachments @page %> + +<% if @editable && authorize_for('wiki', 'add_attachment') %> +
    +

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", + :id => 'attach_files_link' %>

    +<% form_tag({ :controller => 'wiki', :action => 'add_attachment', :project_id => @project, :id => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> +
    +

    <%= render :partial => 'attachments/form' %>

    +
    +<%= submit_tag l(:button_add) %> +<%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %> +<% end %> +
    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'PDF', :url => {:id => @page.title, :version => params[:version]} %> + <%= f.link_to 'HTML', :url => {:id => @page.title, :version => params[:version]} %> + <%= f.link_to 'TXT', :url => {:id => @page.title, :version => params[:version]} %> +<% end if User.current.allowed_to?(:export_wiki_pages, @project) %> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% html_title @page.pretty_title %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wiki/show.rhtml --- a/app/views/wiki/show.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -
    -<% if @editable %> -<%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.version == @page.content.version %> -<%= watcher_tag(@page, User.current) %> -<%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %> -<%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %> -<%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %> -<%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %> -<%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page.title, :version => @content.version }, :class => 'icon icon-cancel') if @content.version < @page.content.version %> -<% end %> -<%= link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> -
    - -<%= breadcrumb(@page.ancestors.reverse.collect {|parent| link_to h(parent.pretty_title), {:id => parent.title, :project_id => parent.project}}) %> - -<% if @content.version != @page.content.version %> -

    - <%= link_to(('« ' + l(:label_previous)), :action => 'show', :id => @page.title, :project_id => @page.project, :version => (@content.version - 1)) + " - " if @content.version > 1 %> - <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> - <%= '(' + link_to('diff', :controller => 'wiki', :action => 'diff', :id => @page.title, :project_id => @page.project, :version => @content.version) + ')' if @content.version > 1 %> - - <%= link_to((l(:label_next) + ' »'), :action => 'show', :id => @page.title, :project_id => @page.project, :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %> - <%= link_to(l(:label_current_version), :action => 'show', :id => @page.title, :project_id => @page.project) %> -
    - <%= @content.author ? @content.author.name : "anonyme" %>, <%= format_time(@content.updated_on) %>
    - <%=h @content.comments %> -

    -
    -<% end %> - -<%= render(:partial => "wiki/content", :locals => {:content => @content}) %> - -<%= link_to_attachments @page %> - -<% if @editable && authorize_for('wiki', 'add_attachment') %> -
    -

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", - :id => 'attach_files_link' %>

    -<% form_tag({ :controller => 'wiki', :action => 'add_attachment', :project_id => @project, :id => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> -
    -

    <%= render :partial => 'attachments/form' %>

    -
    -<%= submit_tag l(:button_add) %> -<%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %> -<% end %> -
    -<% end %> - -<% other_formats_links do |f| %> - <%= f.link_to 'HTML', :url => {:id => @page.title, :version => @content.version} %> - <%= f.link_to 'TXT', :url => {:id => @page.title, :version => @content.version} %> -<% end if User.current.allowed_to?(:export_wiki_pages, @project) %> - -<% content_for :header_tags do %> - <%= stylesheet_link_tag 'scm' %> -<% end %> - -<% content_for :sidebar do %> - <%= render :partial => 'sidebar' %> -<% end %> - -<% html_title @page.pretty_title %> diff -r 487d96eac004 -r 5e80956cc792 app/views/wikis/destroy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/wikis/destroy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,10 @@ +

    <%=l(:label_confirmation)%>

    + +
    +

    <%= h(@project.name) %>
    <%=l(:text_wiki_destroy_confirmation)%>

    + +<% form_tag({:controller => 'wikis', :action => 'destroy', :id => @project}) do %> +<%= hidden_field_tag "confirm", 1 %> +<%= submit_tag l(:button_delete) %> +<% end %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/wikis/destroy.rhtml --- a/app/views/wikis/destroy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -

    <%=l(:label_confirmation)%>

    - -
    -

    <%= @project.name %>
    <%=l(:text_wiki_destroy_confirmation)%>

    - -<% form_tag({:controller => 'wikis', :action => 'destroy', :id => @project}) do %> -<%= hidden_field_tag "confirm", 1 %> -<%= submit_tag l(:button_delete) %> -<% end %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/_action_menu.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/workflows/_action_menu.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,5 @@ +
    +<%= link_to l(:button_edit), {:action => 'edit'}, :class => 'icon icon-edit' %> +<%= link_to l(:button_copy), {:action => 'copy'}, :class => 'icon icon-copy' %> +<%= link_to l(:field_summary), {:action => 'index'}, :class => 'icon icon-summary' %> +
    diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/_action_menu.rhtml --- a/app/views/workflows/_action_menu.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -
    -<%= link_to l(:button_edit), {:action => 'edit'}, :class => 'icon icon-edit' %> -<%= link_to l(:button_copy), {:action => 'copy'}, :class => 'icon icon-copy' %> -<%= link_to l(:field_summary), {:action => 'index'}, :class => 'icon icon-summary' %> -
    diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/_form.html.erb --- a/app/views/workflows/_form.html.erb Fri Feb 24 20:18:25 2012 +0000 +++ b/app/views/workflows/_form.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -1,40 +1,40 @@ - - + - - - - - <% for new_status in @statuses %> - - <% end %> - + + + + + <% for new_status in @statuses %> + + <% end %> + - <% for old_status in @statuses %> - "> - - <% for new_status in @statuses -%> - - <% end -%> - - <% end %> + <% for old_status in @statuses %> + "> + + <% for new_status in @statuses -%> + + <% end -%> + + <% end %> -
    - <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input')", - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> <%=l(:label_current_status)%> <%=l(:label_new_statuses_allowed)%>
    - <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.new-status-#{new_status.id}')", - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> - <%=h new_status.name %> -
    <%=l(:label_new_statuses_allowed)%>
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.new-status-#{new_status.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%=h new_status.name %> +
    - <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.id}')", - :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> - - <%=h old_status.name %> - - <%= check_box_tag "issue_status[#{ old_status.id }][#{new_status.id}][]", name, workflows.detect {|w| w.old_status_id == old_status.id && w.new_status_id == new_status.id}, - :class => "old-status-#{old_status.id} new-status-#{new_status.id}" %> -
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + + <%=h old_status.name %> + + <%= check_box_tag "issue_status[#{ old_status.id }][#{new_status.id}][]", name, workflows.detect {|w| w.old_status_id == old_status.id && w.new_status_id == new_status.id}, + :class => "old-status-#{old_status.id} new-status-#{new_status.id}" %> +
    \ No newline at end of file + diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/copy.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/workflows/copy.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,40 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +<% form_tag({}, :id => 'workflow_copy_form') do %> +
    +<%= l(:label_copy_source) %> +

    + + <%= select_tag('source_tracker_id', + "" + + "" + + options_from_collection_for_select(@trackers, 'id', 'name', @source_tracker && @source_tracker.id)) %> +

    +

    + + <%= select_tag('source_role_id', + "" + + "" + + options_from_collection_for_select(@roles, 'id', 'name', @source_role && @source_role.id)) %> +

    +
    + +
    +<%= l(:label_copy_target) %> +

    + + <%= select_tag 'target_tracker_ids', + "" + + options_from_collection_for_select(@trackers, 'id', 'name', @target_trackers && @target_trackers.map(&:id)), :multiple => true %> +

    +

    + + <%= select_tag 'target_role_ids', + "" + + options_from_collection_for_select(@roles, 'id', 'name', @target_roles && @target_roles.map(&:id)), :multiple => true %> +

    +
    +<%= submit_tag l(:button_copy) %> +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/copy.rhtml --- a/app/views/workflows/copy.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -<%= render :partial => 'action_menu' %> - -

    <%=l(:label_workflow)%>

    - -<% form_tag({}, :id => 'workflow_copy_form') do %> -
    -

    - - <%= l(:label_tracker) %>
    - <%= select_tag('source_tracker_id', - "" + - "" + - options_from_collection_for_select(@trackers, 'id', 'name', @source_tracker && @source_tracker.id)) %>
    - <%= l(:label_role) %>
    - <%= select_tag('source_role_id', - "" + - "" + - options_from_collection_for_select(@roles, 'id', 'name', @source_role && @source_role.id)) %> -

    -

    - - <%= l(:label_tracker) %>
    - <%= select_tag 'target_tracker_ids', - "" + - options_from_collection_for_select(@trackers, 'id', 'name', @target_trackers && @target_trackers.map(&:id)), :multiple => true %>
    - <%= l(:label_role) %>
    - <%= select_tag 'target_role_ids', - "" + - options_from_collection_for_select(@roles, 'id', 'name', @target_roles && @target_roles.map(&:id)), :multiple => true %> -

    -
    -<%= submit_tag l(:button_copy) %> -<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/edit.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/workflows/edit.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +

    <%=l(:text_workflow_edit)%>:

    + +<% form_tag({}, :method => 'get') do %> +

    + + + + + <%= hidden_field_tag 'used_statuses_only', '0' %> + +

    +

    +<%= submit_tag l(:button_edit), :name => nil %> +

    +<% end %> + +<% if @tracker && @role && @statuses.any? %> + <% form_tag({}, :id => 'workflow_form' ) do %> + <%= hidden_field_tag 'tracker_id', @tracker.id %> + <%= hidden_field_tag 'role_id', @role.id %> +
    + <%= render :partial => 'form', :locals => {:name => 'always', :workflows => @workflows['always']} %> + +
    + <%= l(:label_additional_workflow_transitions_for_author) %> +
    + <%= render :partial => 'form', :locals => {:name => 'author', :workflows => @workflows['author']} %> +
    +
    + <%= javascript_tag "hideFieldset($('author_workflows'))" unless @workflows['author'].present? %> + +
    + <%= l(:label_additional_workflow_transitions_for_assignee) %> +
    + <%= render :partial => 'form', :locals => {:name => 'assignee', :workflows => @workflows['assignee']} %> +
    +
    + <%= javascript_tag "hideFieldset($('assignee_workflows'))" unless @workflows['assignee'].present? %> +
    + <%= submit_tag l(:button_save) %> + <% end %> +<% end %> + +<% html_title(l(:label_workflow)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/edit.rhtml --- a/app/views/workflows/edit.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -<%= render :partial => 'action_menu' %> - -

    <%=l(:label_workflow)%>

    - -

    <%=l(:text_workflow_edit)%>:

    - -<% form_tag({}, :method => 'get') do %> -

    - - <%= select_tag 'role_id', options_from_collection_for_select(@roles, "id", "name", @role && @role.id) %> - - - <%= select_tag 'tracker_id', options_from_collection_for_select(@trackers, "id", "name", @tracker && @tracker.id) %> - - <%= hidden_field_tag 'used_statuses_only', '0' %> - -

    -

    -<%= submit_tag l(:button_edit), :name => nil %> -

    -<% end %> - -<% if @tracker && @role && @statuses.any? %> - <% form_tag({}, :id => 'workflow_form' ) do %> - <%= hidden_field_tag 'tracker_id', @tracker.id %> - <%= hidden_field_tag 'role_id', @role.id %> -
    - <%= render :partial => 'form', :locals => {:name => 'always', :workflows => @workflows['always']} %> - -
    - <%= l(:label_additional_workflow_transitions_for_author) %> -
    - <%= render :partial => 'form', :locals => {:name => 'author', :workflows => @workflows['author']} %> -
    -
    - <%= javascript_tag "hideFieldset($('author_workflows'))" unless @workflows['author'].present? %> - -
    - <%= l(:label_additional_workflow_transitions_for_assignee) %> -
    - <%= render :partial => 'form', :locals => {:name => 'assignee', :workflows => @workflows['assignee']} %> -
    -
    - <%= javascript_tag "hideFieldset($('assignee_workflows'))" unless @workflows['assignee'].present? %> -
    - <%= submit_tag l(:button_save) %> - <% end %> -<% end %> - -<% html_title(l(:label_workflow)) -%> diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/index.html.erb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/views/workflows/index.html.erb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +<% if @workflow_counts.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +
    + + + + + <% @workflow_counts.first.last.each do |role, count| %> + + + <% end %> + + + +<% @workflow_counts.each do |tracker, roles| -%> + + + <% roles.each do |role, count| -%> + + <% end -%> + +<% end -%> + +
    + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> +
    <%= h tracker %> + <%= link_to((count > 0 ? count : image_tag('false.png')), {:action => 'edit', :role_id => role, :tracker_id => tracker}, :title => l(:button_edit)) %> +
    +
    +<% end %> diff -r 487d96eac004 -r 5e80956cc792 app/views/workflows/index.rhtml --- a/app/views/workflows/index.rhtml Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -<%= render :partial => 'action_menu' %> - -

    <%=l(:label_workflow)%>

    - -<% if @workflow_counts.empty? %> -

    <%= l(:label_no_data) %>

    -<% else %> -
    - - - - - <% @workflow_counts.first.last.each do |role, count| %> - - - <% end %> - - - -<% @workflow_counts.each do |tracker, roles| -%> - - - <% roles.each do |role, count| -%> - - <% end -%> - -<% end -%> - -
    - <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> -
    <%= h tracker %> - <%= link_to((count > 0 ? count : image_tag('false.png')), {:action => 'edit', :role_id => role, :tracker_id => tracker}, :title => l(:button_edit)) %> -
    -
    -<% end %> diff -r 487d96eac004 -r 5e80956cc792 config/boot.rb --- a/config/boot.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/config/boot.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,11 @@ # Don't change this file! # Configure your app in config/environment.rb and config/environments/*.rb +if RUBY_VERSION >= '1.9' + require 'yaml' + YAML::ENGINE.yamler = 'syck' +end + RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) module Rails @@ -62,8 +67,12 @@ gem 'rails' end rescue Gem::LoadError => load_error - $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) - exit 1 + if load_error.message =~ /Could not find RubyGem rails/ + STDERR.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) + exit 1 + else + raise + end end class << self @@ -106,17 +115,5 @@ end end -# TODO: Workaround for #7013 to be removed for 1.2.0 -# Loads i18n 0.4.2 before Rails loads any more recent gem -# 0.5.0 is not compatible with the old interpolation syntax -# Plugins will have to migrate to the new syntax for 1.2.0 -require 'rubygems' -begin - gem 'i18n', '0.4.2' -rescue Gem::LoadError => load_error - $stderr.puts %(Missing the i18n 0.4.2 gem. Please `gem install -v=0.4.2 i18n`) - exit 1 -end - # All that for this: Rails.boot! diff -r 487d96eac004 -r 5e80956cc792 config/configuration.yml.example --- a/config/configuration.yml.example Fri Feb 24 20:18:25 2012 +0000 +++ b/config/configuration.yml.example Mon Feb 27 13:53:18 2012 +0000 @@ -5,6 +5,7 @@ # Environment specific configuration options override the default ones. # # Note that this file needs to be a valid YAML file. +# DO NOT USE TABS! Use 2 spaces instead of tabs for identation. # # == Outgoing email settings (email_delivery setting) # @@ -61,6 +62,7 @@ # delivery_method: :smtp # smtp_settings: # tls: true +# enable_starttls_auto: true # address: "smtp.gmail.com" # port: 587 # domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps @@ -89,7 +91,7 @@ authentication: :login user_name: "redmine@example.net" password: "redmine" - + # Absolute path to the directory where attachments are stored. # The default is the 'files' directory in your Redmine instance. # Your Redmine instance needs to have write permission on this @@ -98,7 +100,7 @@ # attachments_storage_path: /var/redmine/files # attachments_storage_path: D:/redmine/files attachments_storage_path: - + # Configuration of the autologin cookie. # autologin_cookie_name: the name of the cookie (default: autologin) # autologin_cookie_path: the cookie path (default: /) @@ -106,10 +108,17 @@ autologin_cookie_name: autologin_cookie_path: autologin_cookie_secure: - + # Configuration of SCM executable command. + # # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe) - # On Windows, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work. + # On Windows + CRuby, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work. + # + # On Windows + JRuby 1.6.2, path which contains spaces does not work. + # For example, "C:\Program Files\TortoiseHg\hg.exe". + # If you want to this feature, you need to install to the path which does not contains spaces. + # For example, "C:\TortoiseHg\hg.exe". + # # Examples: # scm_subversion_command: svn # (default: svn) # scm_mercurial_command: C:\Program Files\TortoiseHg\hg.exe # (default: hg) @@ -117,13 +126,14 @@ # scm_cvs_command: cvs # (default: cvs) # scm_bazaar_command: bzr.exe # (default: bzr) # scm_darcs_command: darcs-1.0.9-i386-linux # (default: darcs) + # scm_subversion_command: scm_mercurial_command: scm_git_command: scm_cvs_command: scm_bazaar_command: scm_darcs_command: - + # Key used to encrypt sensitive data in the database (SCM and LDAP passwords). # If you don't want to enable data encryption, just leave it blank. # WARNING: losing/changing this key will make encrypted data unreadable. @@ -136,8 +146,8 @@ # * decrypt data using 'rake db:decrypt RAILS_ENV=production' first # * change the cipher key here in your configuration file # * encrypt data using 'rake db:encrypt RAILS_ENV=production' - database_cipher_key: - + database_cipher_key: + # specific configuration options for production environment # that overrides the default ones production: diff -r 487d96eac004 -r 5e80956cc792 config/database.yml.example --- a/config/database.yml.example Fri Feb 24 20:18:25 2012 +0000 +++ b/config/database.yml.example Mon Feb 27 13:53:18 2012 +0000 @@ -7,7 +7,7 @@ username: root password: encoding: utf8 - + development: adapter: mysql database: redmine_development diff -r 487d96eac004 -r 5e80956cc792 config/environment.rb --- a/config/environment.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/config/environment.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,11 +1,15 @@ # Be sure to restart your web server when you modify this file. -# Uncomment below to force Rails into production mode when +# Uncomment below to force Rails into production mode when # you don't control web/app server and can't set it the proper way # ENV['RAILS_ENV'] ||= 'production' # Specifies gem version of Rails to use when vendor/rails is not present -RAILS_GEM_VERSION = '2.3.11' unless defined? RAILS_GEM_VERSION +RAILS_GEM_VERSION = '2.3.14' unless defined? RAILS_GEM_VERSION + +if RUBY_VERSION >= '1.9' + Encoding.default_external = 'UTF-8' +end # Bootstrap the Rails environment, frameworks, and default configuration require File.join(File.dirname(__FILE__), 'boot') @@ -19,40 +23,40 @@ Rails::Initializer.run do |config| # Settings in config/environments/* take precedence those specified here - + # Skip frameworks you're not going to use # config.frameworks -= [ :action_web_service, :action_mailer ] # Add additional load paths for sweepers config.autoload_paths += %W( #{RAILS_ROOT}/app/sweepers ) - # Force all environments to use the same logger level + # Force all environments to use the same logger level # (by default production uses :info, the others :debug) # config.log_level = :debug # Enable page/fragment caching by setting a file-based store # (remember to create the caching directory and make it readable to the application) # config.action_controller.cache_store = :file_store, "#{RAILS_ROOT}/tmp/cache" - + # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer, :comment_observer # Make Active Record use UTC-base instead of local time # config.active_record.default_timezone = :utc - + # Use Active Record's schema dumper instead of SQL when creating the test database # (enables use of different database adapters for development and test environments) # config.active_record.schema_format = :ruby - + # Deliveries are disabled by default. Do NOT modify this section. # Define your email configuration in configuration.yml instead. # It will automatically turn deliveries on config.action_mailer.perform_deliveries = false config.gem 'rubytree', :lib => 'tree' - config.gem 'coderay', :version => '~>0.9.7' - + config.gem 'coderay', :version => '~>1.0.0' + # Load any local configuration that is kept out of source control # (e.g. gems, patches). if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) diff -r 487d96eac004 -r 5e80956cc792 config/initializers/10-patches.rb --- a/config/initializers/10-patches.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/config/initializers/10-patches.rb Mon Feb 27 13:53:18 2012 +0000 @@ -4,7 +4,7 @@ module ActiveRecord class Base include Redmine::I18n - + # Translate attribute names for validation errors display def self.human_attribute_name(attr) l("field_#{attr.to_s.gsub(/_id$/, '')}", :default => attr) @@ -65,28 +65,42 @@ ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } -# Adds :async_smtp and :async_sendmail delivery methods -# to perform email deliveries asynchronously module AsynchronousMailer + # Adds :async_smtp and :async_sendmail delivery methods + # to perform email deliveries asynchronously %w(smtp sendmail).each do |type| define_method("perform_delivery_async_#{type}") do |mail| Thread.start do send "perform_delivery_#{type}", mail - end + end end end + + # Adds a delivery method that writes emails in tmp/emails for testing purpose + def perform_delivery_tmp_file(mail) + dest_dir = File.join(Rails.root, 'tmp', 'emails') + Dir.mkdir(dest_dir) unless File.directory?(dest_dir) + File.open(File.join(dest_dir, mail.message_id.gsub(/[<>]/, '') + '.eml'), 'wb') {|f| f.write(mail.encoded) } + end end ActionMailer::Base.send :include, AsynchronousMailer -# TMail::Unquoter.convert_to_with_fallback_on_iso_8859_1 introduced in TMail 1.2.7 -# triggers a test failure in test_add_issue_with_japanese_keywords(MailHandlerTest) module TMail + # TMail::Unquoter.convert_to_with_fallback_on_iso_8859_1 introduced in TMail 1.2.7 + # triggers a test failure in test_add_issue_with_japanese_keywords(MailHandlerTest) class Unquoter class << self alias_method :convert_to, :convert_to_without_fallback_on_iso_8859_1 end end + + # Patch for TMail 1.2.7. See http://www.redmine.org/issues/8751 + class Encoder + def puts_meta(str) + add_text str + end + end end module ActionController diff -r 487d96eac004 -r 5e80956cc792 config/initializers/backtrace_silencers.rb --- a/config/initializers/backtrace_silencers.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/config/initializers/backtrace_silencers.rb Mon Feb 27 13:53:18 2012 +0000 @@ -4,4 +4,4 @@ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying do debug a problem that might steem from framework code. -# Rails.backtrace_cleaner.remove_silencers! \ No newline at end of file +# Rails.backtrace_cleaner.remove_silencers! diff -r 487d96eac004 -r 5e80956cc792 config/locales/ar.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/locales/ar.yml Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1008 @@ +ar: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: rtl + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [الاحد, الاثنين, الثلاثاء, الاربعاء, الخميس, الجمعة, السبت] + abbr_day_names: [أح, اث, ث, ار, خ, ج, س] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, كانون الثاني, شباط, آذار, نيسان, أيار, حزيران, تموز, آب, أيلول, تشرين الأول, تشرين الثاني, كانون الأول] + abbr_month_names: [~, كانون الثاني, شباط, آذار, نيسان, أيار, حزيران, تموز, آب, أيلول, تشرين الأول, تشرين الثاني, كانون الأول] + # Used in date_select and datime_select. + order: + - :السنة + - :الشهر + - :اليوم + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "صباحا" + pm: "مساءا" + + datetime: + distance_in_words: + half_a_minute: "نصف دقيقة" + less_than_x_seconds: + one: "أقل من ثانية" + other: "ثواني %{count}أقل من " + x_seconds: + one: "ثانية" + other: "%{count}ثواني " + less_than_x_minutes: + one: "أقل من دقيقة" + other: "دقائق%{count}أقل من " + x_minutes: + one: "دقيقة" + other: "%{count} دقائق" + about_x_hours: + one: "حوالي ساعة" + other: "ساعات %{count}حوالي " + x_days: + one: "يوم" + other: "%{count} أيام" + about_x_months: + one: "حوالي شهر" + other: "أشهر %{count} حوالي" + x_months: + one: "شهر" + other: "%{count} أشهر" + about_x_years: + one: "حوالي سنة" + other: "سنوات %{count}حوالي " + over_x_years: + one: "اكثر من سنة" + other: "سنوات %{count}أكثر من " + almost_x_years: + one: "تقريبا سنة" + other: "سنوات %{count} نقريبا" + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "kB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "و" + skip_last_comma: خطأ + + activerecord: + errors: + template: + header: + one: " %{model} خطأ يمنع تخزين" + other: " %{model} يمنع تخزين%{count}خطأ رقم " + messages: + inclusion: "غير مدرجة على القائمة" + exclusion: "محجوز" + invalid: "غير صالح" + confirmation: "غير متطابق" + accepted: "مقبولة" + empty: "لا يمكن ان تكون فارغة" + blank: "لا يمكن ان تكون فارغة" + too_long: " %{count}طويلة جدا، الحد الاقصى هو )" + too_short: " %{count}قصيرة جدا، الحد الادنى هو)" + wrong_length: " %{count}خطأ في الطول، يجب ان يكون )" + taken: "لقد اتخذت سابقا" + not_a_number: "ليس رقما" + not_a_date: "ليس تاريخا صالحا" + greater_than: "%{count}يجب ان تكون اكثر من " + greater_than_or_equal_to: "%{count}يجب ان تكون اكثر من او تساوي" + equal_to: "%{count}يجب ان تساوي" + less_than: " %{count}يجب ان تكون اقل من" + less_than_or_equal_to: " %{count}يجب ان تكون اقل من او تساوي" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "يجب ان تكون اكثر من تاريخ البداية" + not_same_project: "لا ينتمي الى نفس المشروع" + circular_dependency: "هذه العلاقة سوف تخلق علاقة تبعية دائرية" + cant_link_an_issue_with_a_descendant: "لا يمكن ان تكون المشكلة مرتبطة بواحدة من المهام الفرعية" + + actionview_instancetag_blank_option: الرجاء التحديد + + general_text_No: 'لا' + general_text_Yes: 'نعم' + general_text_no: 'لا' + general_text_yes: 'نعم' + general_lang_name: 'Arabic (عربي)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: لقد تم تجديد الحساب بنجاح. + notice_account_invalid_creditentials: اسم المستخدم او كلمة المرور غير صحيحة + notice_account_password_updated: لقد تم تجديد كلمة المرور بنجاح. + notice_account_wrong_password: كلمة المرور غير صحيحة + notice_account_register_done: لقد تم انشاء حسابك بنجاح، الرجاء تأكيد الطلب من البريد الالكتروني + notice_account_unknown_email: مستخدم غير معروف. + notice_can_t_change_password: هذا الحساب يستخدم جهاز خارجي غير مصرح به لا يمكن تغير كلمة المرور + notice_account_lost_email_sent: لقد تم ارسال رسالة على بريدك بالتعليمات اللازمة لتغير كلمة المرور + notice_account_activated: لقد تم تفعيل حسابك، يمكنك الدخول الان + notice_successful_create: لقد تم الانشاء بنجاح + notice_successful_update: لقد تم التحديث بنجاح + notice_successful_delete: لقد تم الحذف بنجاح + notice_successful_connection: لقد تم الربط بنجاح + notice_file_not_found: الصفحة التي تحاول الدخول اليها غير موجوده او تم حذفها + notice_locking_conflict: تم تحديث البيانات عن طريق مستخدم آخر. + notice_not_authorized: غير مصرح لك الدخول الى هذه المنطقة. + notice_not_authorized_archived_project: المشروع الذي تحاول الدخول اليه تم ارشفته + notice_email_sent: "%{value}تم ارسال رسالة الى " + notice_email_error: " (%{value})لقد حدث خطأ ما اثناء ارسال الرسالة الى " + notice_feeds_access_key_reseted: كلمة الدخول RSSلقد تم تعديل . + notice_api_access_key_reseted: كلمة الدخولAPIلقد تم تعديل . + notice_failed_to_save_issues: "فشل في حفظ الملف" + notice_failed_to_save_members: "فشل في حفظ الاعضاء: %{errors}." + notice_no_issue_selected: "لم يتم تحديد شيء، الرجاء تحديد المسألة التي تريد" + notice_account_pending: "لقد تم انشاء حسابك، الرجاء الانتظار حتى تتم الموافقة" + notice_default_data_loaded: تم تحميل التكوين الافتراضي بنجاح + notice_unable_delete_version: غير قادر على مسح النسخة. + notice_unable_delete_time_entry: غير قادر على مسح وقت الدخول. + notice_issue_done_ratios_updated: لقد تم تحديث النسب. + notice_gantt_chart_truncated: " (%{max})لقد تم اقتطاع الرسم البياني لانه تجاوز الاحد الاقصى لعدد العناصر المسموح عرضها " + notice_issue_successful_create: "%{id}لقد تم انشاء " + + + error_can_t_load_default_data: "لم يتم تحميل التكوين الافتراضي كاملا %{value}" + error_scm_not_found: "لم يتم العثور على ادخال في المستودع" + error_scm_command_failed: "حدث خطأ عند محاولة الوصول الى المستودع: %{value}" + error_scm_annotate: "الادخال غير موجود." + error_scm_annotate_big_text_file: "لا يمكن حفظ الادخال لانه تجاوز الحد الاقصى لحجم الملف." + error_issue_not_found_in_project: 'لم يتم العثور على المخرج او انه ينتمي الى مشروع اخر' + error_no_tracker_in_project: 'لا يوجد متتبع لهذا المشروع، الرجاء التحقق من إعدادات المشروع. ' + error_no_default_issue_status: 'لم يتم التعرف على اي وضع افتراضي، الرجاء التحقق من التكوين الخاص بك (اذهب الى إدارة-إصدار الحالات)' + error_can_not_delete_custom_field: غير قادر على حذف الحقل المظلل + error_can_not_delete_tracker: "هذا المتتبع يحتوي على مسائل نشطة ولا يمكن حذفه" + error_can_not_remove_role: "هذا الدور قيد الاستخدام، لا يمكن حذفه" + error_can_not_reopen_issue_on_closed_version: 'لا يمكن إعادة فتح قضية معينه لاصدار مقفل' + error_can_not_archive_project: لا يمكن ارشفة هذا المشروع + error_issue_done_ratios_not_updated: "لم يتم تحديث النسب" + error_workflow_copy_source: 'الرجاء اختيار المتتبع او الادوار' + error_workflow_copy_target: 'الرجاء اختيار هدف المتتبع او هدف الادوار' + error_unable_delete_issue_status: 'غير قادر على حذف حالة القضية' + error_unable_to_connect: "تعذر الاتصال(%{value})" + error_attachment_too_big: " (%{max_size})لا يمكن تحميل هذا الملف، لقد تجاوز الحد الاقصى المسموح به " + warning_attachments_not_saved: "%{count}تعذر حفظ الملف" + + mail_subject_lost_password: " %{value}كلمة المرور الخاصة بك " + mail_body_lost_password: 'لتغير كلمة المرور، انقر على الروابط التالية:' + mail_subject_register: " %{value}تفعيل حسابك " + mail_body_register: 'لتفعيل حسابك، انقر على الروابط التالية:' + mail_body_account_information_external: " %{value}اصبح بامكانك استخدام حسابك للدخول" + mail_body_account_information: معلومات حسابك + mail_subject_account_activation_request: "%{value}طلب تفعيل الحساب " + mail_body_account_activation_request: " (%{value})تم تسجيل حساب جديد، بانتظار الموافقة:" + mail_subject_reminder: "%{count}تم تأجيل المهام التالية " + mail_body_reminder: "%{count}يجب ان تقوم بتسليم المهام التالية :" + mail_subject_wiki_content_added: "'%{id}' تم اضافة صفحة ويكي" + mail_body_wiki_content_added: "The '%{id}' تم اضافة صفحة ويكي من قبل %{author}." + mail_subject_wiki_content_updated: "'%{id}' تم تحديث صفحة ويكي" + mail_body_wiki_content_updated: "The '%{id}'تم تحديث صفحة ويكي من قبل %{author}." + + gui_validation_error: خطأ + gui_validation_error_plural: "%{count}أخطاء" + + field_name: الاسم + field_description: الوصف + field_summary: الملخص + field_is_required: مطلوب + field_firstname: الاسم الاول + field_lastname: الاسم الاخير + field_mail: البريد الالكتروني + field_filename: اسم الملف + field_filesize: حجم الملف + field_downloads: التنزيل + field_author: المؤلف + field_created_on: تم الانشاء في + field_updated_on: تم التحديث + field_field_format: تنسيق الحقل + field_is_for_all: لكل المشروعات + field_possible_values: قيم محتملة + field_regexp: التعبير العادي + field_min_length: الحد الادنى للطول + field_max_length: الحد الاعلى للطول + field_value: القيمة + field_category: الفئة + field_title: العنوان + field_project: المشروع + field_issue: القضية + field_status: الحالة + field_notes: ملاحظات + field_is_closed: القضية مغلقة + field_is_default: القيمة الافتراضية + field_tracker: المتتبع + field_subject: الموضوع + field_due_date: تاريخ الاستحقاق + field_assigned_to: المحال اليه + field_priority: الأولوية + field_fixed_version: الاصدار المستهدف + field_user: المستخدم + field_principal: الرئيسي + field_role: دور + field_homepage: الصفحة الرئيسية + field_is_public: عام + field_parent: مشروع فرعي من + field_is_in_roadmap: القضايا المعروضة في خارطة الطريق + field_login: تسجيل الدخول + field_mail_notification: ملاحظات على البريد الالكتروني + field_admin: المدير + field_last_login_on: اخر اتصال + field_language: لغة + field_effective_date: تاريخ + field_password: كلمة المرور + field_new_password: كلمة المرور الجديدة + field_password_confirmation: تأكيد + field_version: إصدار + field_type: نوع + field_host: المضيف + field_port: المنفذ + field_account: الحساب + field_base_dn: DN قاعدة + field_attr_login: سمة الدخول + field_attr_firstname: سمة الاسم الاول + field_attr_lastname: سمة الاسم الاخير + field_attr_mail: سمة البريد الالكتروني + field_onthefly: إنشاء حساب مستخدم على تحرك + field_start_date: تاريخ البدية + field_done_ratio: "% تم" + field_auth_source: وضع المصادقة + field_hide_mail: إخفاء بريدي الإلكتروني + field_comments: تعليق + field_url: رابط + field_start_page: صفحة البداية + field_subproject: المشروع الفرعي + field_hours: ساعات + field_activity: النشاط + field_spent_on: تاريخ + field_identifier: المعرف + field_is_filter: استخدم كتصفية + field_issue_to: القضايا المتصلة + field_delay: تأخير + field_assignable: يمكن ان تستند القضايا الى هذا الدور + field_redirect_existing_links: إعادة توجيه الروابط الموجودة + field_estimated_hours: الوقت المتوقع + field_column_names: أعمدة + field_time_entries: وقت الدخول + field_time_zone: المنطقة الزمنية + field_searchable: يمكن البحث فيه + field_default_value: القيمة الافتراضية + field_comments_sorting: اعرض التعليقات + field_parent_title: صفحة الوالدين + field_editable: يمكن اعادة تحريره + field_watcher: مراقب + field_identity_url: افتح الرابط الخاص بالهوية الشخصية + field_content: المحتويات + field_group_by: مجموعة النتائج عن طريق + field_sharing: مشاركة + field_parent_issue: مهمة الوالدين + field_member_of_group: "مجموعة المحال" + field_assigned_to_role: "دور المحال" + field_text: حقل نصي + field_visible: غير مرئي + field_warn_on_leaving_unsaved: "الرجاء التحذير عند مغادرة صفحة والنص غير محفوظ" + field_issues_visibility: القضايا المرئية + field_is_private: خاص + field_commit_logs_encoding: رسائل الترميز + field_scm_path_encoding: ترميز المسار + field_path_to_repository: مسار المستودع + field_root_directory: دليل الجذر + field_cvsroot: CVSجذر + field_cvs_module: وحدة + + setting_app_title: عنوان التطبيق + setting_app_subtitle: العنوان الفرعي للتطبيق + setting_welcome_text: نص الترحيب + setting_default_language: اللغة الافتراضية + setting_login_required: مطلوب المصادقة + setting_self_registration: التسجيل الذاتي + setting_attachment_max_size: الحد الاقصى للملفات المرفقة + setting_issues_export_limit: الحد الاقصى لقضايا التصدير + setting_mail_from: انبعاثات عنوان بريدك + setting_bcc_recipients: مستلمين النسخ المخفية (bcc) + setting_plain_text_mail: نص عادي (no HTML) + setting_host_name: اسم ومسار المستخدم + setting_text_formatting: تنسيق النص + setting_wiki_compression: ضغط تاريخ الويكي + setting_feeds_limit: Atom feeds الحد الاقصى لعدد البنود في + setting_default_projects_public: المشاريع الجديده متاحة للجميع افتراضيا + setting_autofetch_changesets: الإحضار التلقائي + setting_sys_api_enabled: من ادارة المستودع WS تمكين + setting_commit_ref_keywords: مرجعية الكلمات المفتاحية + setting_commit_fix_keywords: تصحيح الكلمات المفتاحية + setting_autologin: الدخول التلقائي + setting_date_format: تنسيق التاريخ + setting_time_format: تنسيق الوقت + setting_cross_project_issue_relations: السماح بادارج القضايا في هذا المشروع + setting_issue_list_default_columns: الاعمدة الافتراضية المعروضة في قائمة القضية + setting_repositories_encodings: ترميز المرفقات والمستودعات + setting_emails_header: رأس رسائل البريد الإلكتروني + setting_emails_footer: ذيل رسائل البريد الإلكتروني + setting_protocol: بروتوكول + setting_per_page_options: الكائنات لكل خيارات الصفحة + setting_user_format: تنسيق عرض المستخدم + setting_activity_days_default: الايام المعروضة على نشاط المشروع + setting_display_subprojects_issues: عرض القضايا الفرعية للمشارع الرئيسية بشكل افتراضي + setting_enabled_scm: SCM تمكين + setting_mail_handler_body_delimiters: "اقتطاع رسائل البريد الإلكتروني بعد هذه الخطوط" + setting_mail_handler_api_enabled: للرسائل الواردةWS تمكين + setting_mail_handler_api_key: API مفتاح + setting_sequential_project_identifiers: انشاء معرفات المشروع المتسلسلة + setting_gravatar_enabled: كأيقونة مستخدمGravatar استخدام + setting_gravatar_default: الافتراضيةGravatar صورة + setting_diff_max_lines_displayed: الحد الاقصى لعدد الخطوط + setting_file_max_size_displayed: الحد الأقصى لحجم النص المعروض على الملفات المرفقة + setting_repository_log_display_limit: الحد الاقصى لعدد التنقيحات المعروضة على ملف السجل + setting_openid: السماح بدخول اسم المستخدم المفتوح والتسجيل + setting_password_min_length: الحد الادني لطول كلمة المرور + setting_new_project_user_role_id: الدور المسند الى المستخدم غير المسؤول الذي يقوم بإنشاء المشروع + setting_default_projects_modules: تمكين الوحدات النمطية للمشاريع الجديدة بشكل افتراضي + setting_issue_done_ratio: حساب نسبة القضية المنتهية + setting_issue_done_ratio_issue_field: استخدم حقل القضية + setting_issue_done_ratio_issue_status: استخدم وضع القضية + setting_start_of_week: بدأ التقويم + setting_rest_api_enabled: تمكين باقي خدمات الويب + setting_cache_formatted_text: النص المسبق تنسيقه في ذاكرة التخزين المؤقت + setting_default_notification_option: خيار الاعلام الافتراضي + setting_commit_logtime_enabled: تميكن وقت الدخول + setting_commit_logtime_activity_id: النشاط في وقت الدخول + setting_gantt_items_limit: الحد الاقصى لعدد العناصر المعروضة على المخطط + setting_issue_group_assignment: السماح للإحالة الى المجموعات + setting_default_issue_start_date_to_creation_date: استخدام التاريخ الحالي كتاريخ بدأ للقضايا الجديدة + + permission_add_project: إنشاء مشروع + permission_add_subprojects: إنشاء مشاريع فرعية + permission_edit_project: تعديل مشروع + permission_select_project_modules: تحديد شكل المشروع + permission_manage_members: إدارة الاعضاء + permission_manage_project_activities: ادارة اصدارات المشروع + permission_manage_versions: ادارة الاصدارات + permission_manage_categories: ادارة انواع القضايا + permission_view_issues: عرض القضايا + permission_add_issues: اضافة القضايا + permission_edit_issues: تعديل القضايا + permission_manage_issue_relations: ادارة علاقات القضايا + permission_set_issues_private: تعين قضايا عامة او خاصة + permission_set_own_issues_private: تعين القضايا الخاصة بك كقضايا عامة او خاصة + permission_add_issue_notes: اضافة ملاحظات + permission_edit_issue_notes: تعديل ملاحظات + permission_edit_own_issue_notes: تعديل ملاحظاتك + permission_move_issues: تحريك القضايا + permission_delete_issues: حذف القضايا + permission_manage_public_queries: ادارة الاستعلامات العامة + permission_save_queries: حفظ الاستعلامات + permission_view_gantt: عرض طريقة"جانت" + permission_view_calendar: عرض التقويم + permission_view_issue_watchers: عرض قائمة المراقبين + permission_add_issue_watchers: اضافة مراقبين + permission_delete_issue_watchers: حذف مراقبين + permission_log_time: الوقت المستغرق بالدخول + permission_view_time_entries: عرض الوقت المستغرق + permission_edit_time_entries: تعديل الدخولات الزمنية + permission_edit_own_time_entries: تعديل الدخولات الشخصية + permission_manage_news: ادارة الاخبار + permission_comment_news: اخبار التعليقات + permission_manage_documents: ادارة المستندات + permission_view_documents: عرض المستندات + permission_manage_files: ادارة الملفات + permission_view_files: عرض الملفات + permission_manage_wiki: ادارة ويكي + permission_rename_wiki_pages: اعادة تسمية صفحات ويكي + permission_delete_wiki_pages: حذق صفحات ويكي + permission_view_wiki_pages: عرض ويكي + permission_view_wiki_edits: عرض تاريخ ويكي + permission_edit_wiki_pages: تعديل صفحات ويكي + permission_delete_wiki_pages_attachments: حذف المرفقات + permission_protect_wiki_pages: حماية صفحات ويكي + permission_manage_repository: ادارة المستودعات + permission_browse_repository: استعراض المستودعات + permission_view_changesets: عرض طاقم التغيير + permission_commit_access: الوصول + permission_manage_boards: ادارة المنتديات + permission_view_messages: عرض الرسائل + permission_add_messages: نشر الرسائل + permission_edit_messages: تحرير الرسائل + permission_edit_own_messages: تحرير الرسائل الخاصة + permission_delete_messages: حذف الرسائل + permission_delete_own_messages: حذف الرسائل الخاصة + permission_export_wiki_pages: تصدير صفحات ويكي + permission_manage_subtasks: ادارة المهام الفرعية + + project_module_issue_tracking: تعقب القضايا + project_module_time_tracking: التعقب الزمني + project_module_news: الاخبار + project_module_documents: المستندات + project_module_files: الملفات + project_module_wiki: ويكي + project_module_repository: المستودع + project_module_boards: المنتديات + project_module_calendar: التقويم + project_module_gantt: جانت + + label_user: المستخدم + label_user_plural: المستخدمين + label_user_new: مستخدم جديد + label_user_anonymous: مجهول الهوية + label_project: مشروع + label_project_new: مشروع جديد + label_project_plural: مشاريع + label_x_projects: + zero: لا يوجد مشاريع + one: مشروع واحد + other: "%{count} مشاريع" + label_project_all: كل المشاريع + label_project_latest: احدث المشاريع + label_issue: قضية + label_issue_new: قضية جديدة + label_issue_plural: قضايا + label_issue_view_all: عرض كل القضايا + label_issues_by: " %{value}القضية لصحابها" + label_issue_added: تم اضافة القضية + label_issue_updated: تم تحديث القضية + label_issue_note_added: تم اضافة الملاحظة + label_issue_status_updated: تم تحديث الحالة + label_issue_priority_updated: تم تحديث الاولويات + label_document: مستند + label_document_new: مستند جديد + label_document_plural: مستندات + label_document_added: تم اضافة مستند + label_role: دور + label_role_plural: ادوار + label_role_new: دور جديد + label_role_and_permissions: الادوار والاذن + label_role_anonymous: مجهول الهوية + label_role_non_member: ليس عضو + label_member: عضو + label_member_new: عضو جديد + label_member_plural: اعضاء + label_tracker: المتتبع + label_tracker_plural: المتتبعين + label_tracker_new: متتبع جديد + label_workflow: سير العمل + label_issue_status: وضع القضية + label_issue_status_plural: اوضاع القضية + label_issue_status_new: وضع جديد + label_issue_category: نوع القضية + label_issue_category_plural: انواع القضايا + label_issue_category_new: نوع جديد + label_custom_field: تخصيص حقل + label_custom_field_plural: تخصيص حقول + label_custom_field_new: حقل مخصص جديد + label_enumerations: التعدادات + label_enumeration_new: قيمة جديدة + label_information: معلومة + label_information_plural: معلومات + label_please_login: برجى تسجيل الدخول + label_register: تسجيل + label_login_with_open_id_option: او الدخول بهوية مفتوحة + label_password_lost: فقدت كلمة السر + label_home: الصفحة الرئيسية + label_my_page: الصفحة الخاصة بي + label_my_account: حسابي + label_my_projects: مشاريعي الخاصة + label_my_page_block: حجب صفحتي الخاصة + label_administration: الإدارة + label_login: تسجيل الدخول + label_logout: تسجيل الخروج + label_help: مساعدة + label_reported_issues: أبلغ القضايا + label_assigned_to_me_issues: المسائل المعنية إلى + label_last_login: آخر اتصال + label_registered_on: مسجل على + label_activity: النشاط + label_overall_activity: النشاط العام + label_user_activity: "قيمة النشاط" + label_new: جديدة + label_logged_as: تم تسجيل دخولك + label_environment: البيئة + label_authentication: المصادقة + label_auth_source: وضع المصادقة + label_auth_source_new: وضع مصادقة جديدة + label_auth_source_plural: أوضاع المصادقة + label_subproject_plural: مشاريع فرعية + label_subproject_new: مشروع فرعي جديد + label_and_its_subprojects: "قيمةالمشاريع الفرعية الخاصة بك" + label_min_max_length: الحد الاقصى والادنى للطول + label_list: قائمة + label_date: تاريخ + label_integer: عدد صحيح + label_float: تعويم + label_boolean: منطقية + label_string: النص + label_text: نص طويل + label_attribute: سمة + label_attribute_plural: السمات + label_download: "تحميل" + label_download_plural: "تحميل" + label_no_data: لا توجد بيانات للعرض + label_change_status: تغيير الوضع + label_history: التاريخ + label_attachment: الملف + label_attachment_new: ملف جديد + label_attachment_delete: حذف الملف + label_attachment_plural: الملفات + label_file_added: الملف المضاف + label_report: تقرير + label_report_plural: التقارير + label_news: الأخبار + label_news_new: إضافة الأخبار + label_news_plural: الأخبار + label_news_latest: آخر الأخبار + label_news_view_all: عرض كل الأخبار + label_news_added: الأخبار المضافة + label_news_comment_added: إضافة التعليقات على أخبار + label_settings: إعدادات + label_overview: لمحة عامة + label_version: الإصدار + label_version_new: الإصدار الجديد + label_version_plural: الإصدارات + label_close_versions: أكملت إغلاق الإصدارات + label_confirmation: تأكيد + label_export_to: 'متوفرة أيضا في:' + label_read: القراءة... + label_public_projects: المشاريع العامة + label_open_issues: فتح قضية + label_open_issues_plural: فتح قضايا + label_closed_issues: قضية مغلقة + label_closed_issues_plural: قضايا مغلقة + label_x_open_issues_abbr_on_total: + zero: 0 مفتوح / %{total} + one: 1 مفتوح / %{total} + other: "%{count} مفتوح / %{total}" + label_x_open_issues_abbr: + zero: 0 مفتوح + one: 1 مقتوح + other: "%{count} مفتوح" + label_x_closed_issues_abbr: + zero: 0 مغلق + one: 1 مغلق + other: "%{count} مغلق" + label_total: الإجمالي + label_permissions: أذونات + label_current_status: الوضع الحالي + label_new_statuses_allowed: يسمح بادراج حالات جديدة + label_all: جميع + label_none: لا شيء + label_nobody: لا أحد + label_next: القادم + label_previous: السابق + label_used_by: التي يستخدمها + label_details: التفاصيل + label_add_note: إضافة ملاحظة + label_per_page: كل صفحة + label_calendar: التقويم + label_months_from: بعد أشهر من + label_gantt: جانت + label_internal: الداخلية + label_last_changes: "آخر التغييرات %{count}" + label_change_view_all: عرض كافة التغييرات + label_personalize_page: تخصيص هذه الصفحة + label_comment: تعليق + label_comment_plural: تعليقات + label_x_comments: + zero: لا يوجد تعليقات + one: تعليق واحد + other: "%{count} تعليقات" + label_comment_add: إضافة تعليق + label_comment_added: تم إضافة التعليق + label_comment_delete: حذف التعليقات + label_query: استعلام مخصص + label_query_plural: استعلامات مخصصة + label_query_new: استعلام جديد + label_my_queries: استعلاماتي المخصصة + label_filter_add: إضافة عامل تصفية + label_filter_plural: عوامل التصفية + label_equals: يساوي + label_not_equals: لا يساوي + label_in_less_than: في أقل من + label_in_more_than: في أكثر من + label_greater_or_equal: '>=' + label_less_or_equal: '< =' + label_between: بين + label_in: في + label_today: اليوم + label_all_time: كل الوقت + label_yesterday: بالأمس + label_this_week: هذا الأسبوع + label_last_week: الأسبوع الماضي + label_last_n_days: "ايام %{count} اخر" + label_this_month: هذا الشهر + label_last_month: الشهر الماضي + label_this_year: هذا العام + label_date_range: نطاق التاريخ + label_less_than_ago: أقل من قبل أيام + label_more_than_ago: أكثر من قبل أيام + label_ago: منذ أيام + label_contains: يحتوي على + label_not_contains: لا يحتوي على + label_day_plural: أيام + label_repository: المستودع + label_repository_plural: المستودعات + label_browse: تصفح + label_modification: "%{count} تغير" + label_modification_plural: "%{count}تغيرات " + label_branch: فرع + label_tag: ربط + label_revision: مراجعة + label_revision_plural: تنقيحات + label_revision_id: " %{value}مراجعة" + label_associated_revisions: التنقيحات المرتبطة + label_added: إضافة + label_modified: تعديل + label_copied: نسخ + label_renamed: إعادة تسمية + label_deleted: حذف + label_latest_revision: آخر تنقيح + label_latest_revision_plural: أحدث المراجعات + label_view_revisions: عرض التنقيحات + label_view_all_revisions: عرض كافة المراجعات + label_max_size: الحد الأقصى للحجم + label_sort_highest: التحرك إلى أعلى + label_sort_higher: تحريك لأعلى + label_sort_lower: تحريك لأسفل + label_sort_lowest: الانتقال إلى أسفل + label_roadmap: خارطة الطريق + label_roadmap_due_in: " %{value}تستحق في " + label_roadmap_overdue: "%{value}تأخير" + label_roadmap_no_issues: لا يوجد قضايا لهذا الإصدار + label_search: البحث + label_result_plural: النتائج + label_all_words: كل الكلمات + label_wiki: ويكي + label_wiki_edit: تحرير ويكي + label_wiki_edit_plural: عمليات تحرير ويكي + label_wiki_page: صفحة ويكي + label_wiki_page_plural: ويكي صفحات + label_index_by_title: الفهرس حسب العنوان + label_index_by_date: الفهرس حسب التاريخ + label_current_version: الإصدار الحالي + label_preview: معاينة + label_feed_plural: موجز ويب + label_changes_details: تفاصيل جميع التغييرات + label_issue_tracking: تعقب القضايا + label_spent_time: أمضى بعض الوقت + label_overall_spent_time: الوقت الذي تم انفاقه كاملا + label_f_hour: "%{value} ساعة" + label_f_hour_plural: "%{value} ساعات" + label_time_tracking: تعقب الوقت + label_change_plural: التغييرات + label_statistics: إحصاءات + label_commits_per_month: يثبت في الشهر + label_commits_per_author: يثبت لكل مؤلف + label_diff: الاختلافات + label_view_diff: عرض الاختلافات + label_diff_inline: مضمنة + label_diff_side_by_side: جنبا إلى جنب + label_options: خيارات + label_copy_workflow_from: نسخ سير العمل من + label_permissions_report: تقرير أذونات + label_watched_issues: شاهد القضايا + label_related_issues: القضايا ذات الصلة + label_applied_status: تطبيق مركز + label_loading: تحميل... + label_relation_new: علاقة جديدة + label_relation_delete: حذف العلاقة + label_relates_to: ذات الصلة إلى + label_duplicates: التكرارات + label_duplicated_by: ازدواج + label_blocks: حظر + label_blocked_by: حظر بواسطة + label_precedes: يسبق + label_follows: يتبع + label_end_to_start: نهاية لبدء + label_end_to_end: نهاية إلى نهاية + label_start_to_start: بدء إلى بدء + label_start_to_end: بداية لنهاية + label_stay_logged_in: تسجيل الدخول في + label_disabled: تعطيل + label_show_completed_versions: أكملت إظهار إصدارات + label_me: لي + label_board: المنتدى + label_board_new: منتدى جديد + label_board_plural: المنتديات + label_board_locked: تأمين + label_board_sticky: لزجة + label_topic_plural: المواضيع + label_message_plural: رسائل + label_message_last: آخر رسالة + label_message_new: رسالة جديدة + label_message_posted: تم اضافة الرسالة + label_reply_plural: الردود + label_send_information: إرسال معلومات الحساب للمستخدم + label_year: سنة + label_month: شهر + label_week: أسبوع + label_date_from: من + label_date_to: إلى + label_language_based: استناداً إلى لغة المستخدم + label_sort_by: " %{value}الترتيب حسب " + label_send_test_email: ارسل رسالة الكترونية كاختبار + label_feeds_access_key: RSS مفتاح دخول + label_missing_feeds_access_key: مفقودRSS مفتاح دخول + label_feeds_access_key_created_on: "RSS تم انشاء مفتاح %{value} منذ" + label_module_plural: الوحدات النمطية + label_added_time_by: " تم اضافته من قبل%{author} %{age} منذ" + label_updated_time_by: " تم تحديثه من قبل%{author} %{age} منذ" + label_updated_time: "تم التحديث %{value} منذ" + label_jump_to_a_project: الانتقال إلى مشروع... + label_file_plural: الملفات + label_changeset_plural: اعدادات التغير + label_default_columns: الاعمدة الافتراضية + label_no_change_option: (أي تغيير) + label_bulk_edit_selected_issues: تحرير القضايا المظللة + label_bulk_edit_selected_time_entries: تعديل كل الإدخالات في كل الاوقات + label_theme: الموضوع + label_default: الافتراضي + label_search_titles_only: البحث في العناوين فقط + label_user_mail_option_all: "جميع الخيارات" + label_user_mail_option_selected: "الخيارات المظللة فقط" + label_user_mail_option_none: "لم يتم تحديد اي خيارات" + label_user_mail_option_only_my_events: "السماح لي فقط بمشاهدة الاحداث الخاصة" + label_user_mail_option_only_assigned: "فقط الخيارات التي تم تعيينها" + label_user_mail_option_only_owner: "فقط للخيارات التي املكها" + label_user_mail_no_self_notified: "لا تريد اعلامك بالتغيرات التي تجريها بنفسك" + label_registration_activation_by_email: حساب التنشيط عبر البريد الإلكتروني + label_registration_manual_activation: تنشيط الحساب اليدوي + label_registration_automatic_activation: تنشيط الحساب التلقائي + label_display_per_page: "لكل صفحة: %{value}" + label_age: العمر + label_change_properties: تغيير الخصائص + label_general: عامة + label_more: أكثر + label_scm: scm + label_plugins: الإضافات + label_ldap_authentication: مصادقة LDAP + label_downloads_abbr: D/L + label_optional_description: وصف اختياري + label_add_another_file: إضافة ملف آخر + label_preferences: تفضيلات + label_chronological_order: في ترتيب زمني + label_reverse_chronological_order: في ترتيب زمني عكسي + label_planning: التخطيط + label_incoming_emails: رسائل البريد الإلكتروني الوارد + label_generate_key: إنشاء مفتاح + label_issue_watchers: المراقبون + label_example: مثال + label_display: العرض + label_sort: فرز + label_ascending: تصاعدي + label_descending: تنازلي + label_date_from_to: من %{start} الى %{end} + label_wiki_content_added: إضافة صفحة ويكي + label_wiki_content_updated: تحديث صفحة ويكي + label_group: مجموعة + label_group_plural: المجموعات + label_group_new: مجموعة جديدة + label_time_entry_plural: أمضى بعض الوقت + label_version_sharing_none: لم يشارك + label_version_sharing_descendants: يشارك + label_version_sharing_hierarchy: مع التسلسل الهرمي للمشروع + label_version_sharing_tree: مع شجرة المشروع + label_version_sharing_system: مع جميع المشاريع + label_update_issue_done_ratios: تحديث قضيةالنسب + label_copy_source: مصدر + label_copy_target: الهدف + label_copy_same_as_target: نفس الهدف + label_display_used_statuses_only: عرض الحالات المستخدمة من قبل هذا "تعقب" فقط + label_api_access_key: مفتاح الوصول إلى API + label_missing_api_access_key: API لم يتم الحصول على مفتاح الوصول + label_api_access_key_created_on: " API إنشاء مفتاح الوصول إلى" + label_profile: الملف الشخصي + label_subtask_plural: المهام الفرعية + label_project_copy_notifications: إرسال إشعار الى البريد الإلكتروني عند نسخ المشروع + label_principal_search: "البحث عن مستخدم أو مجموعة:" + label_user_search: "البحث عن المستخدم:" + label_additional_workflow_transitions_for_author: الانتقالات الإضافية المسموح بها عند المستخدم صاحب البلاغ + label_additional_workflow_transitions_for_assignee: الانتقالات الإضافية المسموح بها عند المستخدم المحال إليه + label_issues_visibility_all: جميع القضايا + label_issues_visibility_public: جميع القضايا الخاصة + label_issues_visibility_own: القضايا التي أنشأها المستخدم + label_git_report_last_commit: اعتماد التقرير الأخير للملفات والدلائل + label_parent_revision: الوالدين + label_child_revision: الطفل + label_export_options: "%{export_format} خيارات التصدير" + + button_login: دخول + button_submit: تثبيت + button_save: حفظ + button_check_all: نحديد الكل + button_uncheck_all: عدم تحديد الكل + button_collapse_all: تقليص الكل + button_expand_all: عرض الكل + button_delete: حذف + button_create: انشاء + button_create_and_continue: انشاء واستمرار + button_test: اختبار + button_edit: تعديل + button_edit_associated_wikipage: "تغير صفحة ويكي: %{page_title}" + button_add: اضافة + button_change: تغير + button_apply: تطبيق + button_clear: واضح + button_lock: قفل + button_unlock: الغاء القفل + button_download: تنزيل + button_list: قائمة + button_view: عرض + button_move: تحرك + button_move_and_follow: تحرك واتبع + button_back: رجوع + button_cancel: إلغاء + button_activate: تنشيط + button_sort: ترتيب + button_log_time: وقت الدخول + button_rollback: الرجوع الى هذا الاصدار + button_watch: يشاهد + button_unwatch: إلغاء المشاهدة + button_reply: رد + button_archive: الارشيف + button_unarchive: إلغاء الارشفة + button_reset: إعادة + button_rename: إعادة التسمية + button_change_password: تغير كلمة المرور + button_copy: نسخ + button_copy_and_follow: نسخ واتباع + button_annotate: تعليق + button_update: تحديث + button_configure: تكوين + button_quote: يقتبس + button_duplicate: يضاعف + button_show: يظهر + button_edit_section: يعدل هذا الجزء + button_export: يستورد + + status_active: نشيط + status_registered: مسجل + status_locked: مقفل + + version_status_open: مفتوح + version_status_locked: مقفل + version_status_closed: مغلق + + field_active: فعال + + text_select_mail_notifications: حدد الامور التي يجب ابلاغك بها عن طريق البريد الالكتروني + text_regexp_info: مثال. ^[A-Z0-9]+$ + text_min_max_length_info: الحد الاقصى والادني لطول المعلومات + text_project_destroy_confirmation: هل أنت متأكد من أنك تريد حذف هذا المشروع والبيانات ذات الصلة؟ + text_subprojects_destroy_warning: "subproject(s): سيتم حذف أيضا." + text_workflow_edit: حدد دوراً وتعقب لتحرير سير العمل + text_are_you_sure: هل أنت متأكد؟ + text_are_you_sure_with_children: "حذف الموضوع وجميع المسائل المتعلقة بالطفل؟" + text_journal_changed: "%{label} تغير %{old} الى %{new}" + text_journal_changed_no_detail: "%{label} تم التحديث" + text_journal_set_to: "%{label} تغير الى %{value}" + text_journal_deleted: "%{label} تم الحذف (%{old})" + text_journal_added: "%{label} %{value} تم الاضافة" + text_tip_issue_begin_day: قضية بدأت اليوم + text_tip_issue_end_day: قضية انتهت اليوم + text_tip_issue_begin_end_day: قضية بدأت وانتهت اليوم + text_caracters_maximum: "%{count} الحد الاقصى." + text_caracters_minimum: "الحد الادنى %{count}" + text_length_between: "الطول %{min} بين %{max} رمز" + text_tracker_no_workflow: لم يتم تحديد سير العمل لهذا المتتبع + text_unallowed_characters: رموز غير مسموحة + text_comma_separated: مسموح رموز متنوعة يفصلها فاصلة . + text_line_separated: مسموح رموز متنوعة يفصلها سطور + text_issues_ref_in_commit_messages: الرجوع واصلاح القضايا في رسائل المشتكين + text_issue_added: "القضية %{id} تم ابلاغها عن طريق %{author}." + text_issue_updated: "القضية %{id} تم تحديثها عن طريق %{author}." + text_wiki_destroy_confirmation: هل انت متأكد من رغبتك في حذف هذا الويكي ومحتوياته؟ + text_issue_category_destroy_question: "بعض القضايا (%{count}) مرتبطة بهذه الفئة، ماذا تريد ان تفعل بها؟" + text_issue_category_destroy_assignments: حذف الفئة + text_issue_category_reassign_to: اعادة تثبيت البنود في الفئة + text_user_mail_option: "بالنسبة للمشاريع غير المحددة، سوف يتم ابلاغك عن المشاريع التي تشاهدها او تشارك بها فقط!" + text_no_configuration_data: "الادوار والمتتبع وحالات القضية ومخطط سير العمل لم يتم تحديد وضعها الافتراضي بعد. " + text_load_default_configuration: احمل الاعدادات الافتراضية + text_status_changed_by_changeset: " طبق التغيرات المعينة على %{value}." + text_time_logged_by_changeset: "تم تطبيق التغيرات المعينة على %{value}." + text_issues_destroy_confirmation: هل انت متأكد من حذف البنود المظللة؟' + text_issues_destroy_descendants_confirmation: "سوف يؤدي هذا الى حذف %{count} المهام الفرعية ايضا." + text_time_entries_destroy_confirmation: "هل انت متأكد من رغبتك في حذف الادخالات الزمنية المحددة؟" + text_select_project_modules: قم بتحديد الوضع المناسب لهذا المشروع:' + text_default_administrator_account_changed: تم تعديل الاعدادات الافتراضية لحساب المدير + text_file_repository_writable: المرفقات قابلة للكتابة + text_plugin_assets_writable: الدليل المساعد قابل للكتابة + text_destroy_time_entries_question: " ساعة على القضية التي تود حذفها، ماذا تريد ان تفعل؟ %{hours} تم تثبيت" + text_destroy_time_entries: قم بحذف الساعات المسجلة + text_assign_time_entries_to_project: ثبت الساعات المسجلة على التقرير + text_reassign_time_entries: 'اعادة تثبيت الساعات المسجلة لهذه القضية:' + text_user_wrote: "%{value} كتب:" + text_enumeration_destroy_question: "%{count} الكائنات المعنية لهذه القيمة" + text_enumeration_category_reassign_to: اعادة تثبيت الكائنات التالية لهذه القيمة:' + text_email_delivery_not_configured: "لم يتم تسليم البريد الالكتروني" + text_diff_truncated: '... لقد تم اقتطلع هذا الجزء لانه تجاوز الحد الاقصى المسموح بعرضه' + text_custom_field_possible_values_info: 'سطر لكل قيمة' + text_wiki_page_nullify_children: "الاحتفاظ بصفحات الطفل كصفحات جذر" + text_wiki_page_destroy_children: "حذف صفحات الطفل وجميع أولادهم" + text_wiki_page_reassign_children: "إعادة تعيين صفحات تابعة لهذه الصفحة الأصلية" + text_own_membership_delete_confirmation: "انت على وشك إزالة بعض أو كافة الأذونات الخاصة بك، لن تكون قادراً على تحرير هذا المشروع بعد ذلك. هل أنت متأكد من أنك تريد المتابعة؟" + text_zoom_in: تصغير + text_zoom_out: تكبير + text_warn_on_leaving_unsaved: "الصفحة تحتوي على نص غير مخزن، سوف يفقد النص اذا تم الخروج من الصفحة." + text_scm_path_encoding_note: "الافتراضي: UTF-8" + text_git_repository_note: مستودع فارغ ومحلي + text_mercurial_repository_note: مستودع محلي + text_scm_command: امر + text_scm_command_version: اصدار + text_scm_config: الرجاء اعادة تشغيل التطبيق + text_scm_command_not_available: الامر غير متوفر، الرجاء التحقق من لوحة التحكم + + default_role_manager: مدير + default_role_developer: مطور + default_role_reporter: مراسل + default_tracker_bug: الشوائب + default_tracker_feature: خاصية + default_tracker_support: دعم + default_issue_status_new: جديد + default_issue_status_in_progress: جاري التحميل + default_issue_status_resolved: الحل + default_issue_status_feedback: التغذية الراجعة + default_issue_status_closed: مغلق + default_issue_status_rejected: مرفوض + default_doc_category_user: مستندات المستخدم + default_doc_category_tech: المستندات التقنية + default_priority_low: قليل + default_priority_normal: عادي + default_priority_high: عالي + default_priority_urgent: طارئ + default_priority_immediate: مباشرة + default_activity_design: تصميم + default_activity_development: تطوير + + enumeration_issue_priorities: الاولويات + enumeration_doc_categories: تصنيف المستندات + enumeration_activities: الانشطة + enumeration_system_activity: نشاط النظام + description_filter: فلترة + description_search: حقل البحث + description_choose_project: مشاريع + description_project_scope: مجال البحث + description_notes: ملاحظات + description_message_content: محتويات الرسالة + description_query_sort_criteria_attribute: نوع الترتيب + description_query_sort_criteria_direction: اتجاه الترتيب + description_user_mail_notification: إعدادات البريد الالكتروني + description_available_columns: الاعمدة المتوفرة + description_selected_columns: الاعمدة المحددة + description_all_columns: كل الاعمدة + description_issue_category_reassign: اختر التصنيف + description_wiki_subpages_reassign: اختر صفحة جديدة + description_date_range_list: اختر المجال من القائمة + description_date_range_interval: اختر المدة عن طريق اختيار تاريخ البداية والنهاية + description_date_from: ادخل تاريخ البداية + description_date_to: ادخل تاريخ الانتهاء + text_rmagick_available: RMagick available (optional) + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_project_identifier_info: Only lower case letters (a-z), numbers and dashes are allowed.
    Once saved, the identifier cannot be changed. + text_repository_usernames_mapping: |- + Select or update the Redmine user mapped to each username found in the repository log. + Users with the same Redmine and repository username or email are automatically mapped. diff -r 487d96eac004 -r 5e80956cc792 config/locales/bg.yml --- a/config/locales/bg.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/bg.yml Mon Feb 27 13:53:18 2012 +0000 @@ -9,10 +9,10 @@ default: "%d-%m-%Y" short: "%b %d" long: "%B %d, %Y" - + day_names: [Неделя, Понеделник, Вторник, Сряда, Четвъртък, Петък, Събота] abbr_day_names: [Нед, Пон, Вто, Сря, Чет, Пет, Съб] - + # Don't forget the nil at the beginning; there's no such thing as a 0th month month_names: [~, Януари, Февруари, Март, Април, Май, Юни, Юли, Август, Септември, Октомври, Ноември, Декември] abbr_month_names: [~, Яну, Фев, Мар, Апр, Май, Юни, Юли, Авг, Сеп, Окт, Ное, Дек] @@ -30,7 +30,7 @@ long: "%B %d, %Y %H:%M" am: "am" pm: "pm" - + datetime: distance_in_words: half_a_minute: "half a minute" @@ -69,19 +69,19 @@ other: "почти %{count} години" number: - # Default format for numbers format: separator: "." delimiter: "" precision: 3 + human: format: precision: 1 delimiter: "" - storage_units: + storage_units: format: "%n %u" - units: - byte: + units: + byte: one: Byte other: Bytes kb: "KB" @@ -89,13 +89,12 @@ gb: "GB" tb: "TB" - # Used in array.to_sentence. support: array: sentence_connector: "и" skip_last_comma: false - + activerecord: errors: template: @@ -129,7 +128,7 @@ cant_link_an_issue_with_a_descendant: "Една задача не може да бъде свързвана към своя подзадача" actionview_instancetag_blank_option: Изберете - + general_text_No: 'Не' general_text_Yes: 'Да' general_text_no: 'не' @@ -140,7 +139,7 @@ general_csv_encoding: UTF-8 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: Профилът е обновен успешно. notice_account_invalid_creditentials: Невалиден потребител или парола. notice_account_password_updated: Паролата е успешно променена. @@ -157,7 +156,7 @@ notice_file_not_found: Несъществуваща или преместена страница. notice_locking_conflict: Друг потребител променя тези данни в момента. notice_not_authorized: Нямате право на достъп до тази страница. - notice_not_authorized_archived_project: Проектът, който се опитвате да видите е архивиран. + notice_not_authorized_archived_project: Проектът, който се опитвате да видите е архивиран. Ако смятате, че това не е правилно, обърнете се към администратора за разархивиране. notice_email_sent: "Изпратен e-mail на %{value}" notice_email_error: "Грешка при изпращане на e-mail (%{value})" notice_feeds_access_key_reseted: Вашия ключ за RSS достъп беше променен. @@ -171,11 +170,13 @@ notice_unable_delete_time_entry: Невъзможност за изтриване на запис на time log. notice_issue_done_ratios_updated: Обновен процент на завършените задачи. notice_gantt_chart_truncated: Мрежовият график е съкратен, понеже броят на обектите, които могат да бъдат показани е твърде голям (%{max}) - + notice_issue_successful_create: Задача %{id} е създадена. + error_can_t_load_default_data: "Грешка при зареждане на примерната информация: %{value}" error_scm_not_found: Несъществуващ обект в хранилището. error_scm_command_failed: "Грешка при опит за комуникация с хранилище: %{value}" error_scm_annotate: "Обектът не съществува или не може да бъде анотиран." + error_scm_annotate_big_text_file: "Файлът не може да бъде анотиран, понеже надхвърля максималния размер за текстови файлове." error_issue_not_found_in_project: 'Задачата не е намерена или не принадлежи на този проект' error_no_tracker_in_project: Няма асоциирани тракери с този проект. Проверете настройките на проекта. error_no_default_issue_status: Няма установено подразбиращо се състояние за задачите. Моля проверете вашата конфигурация (Вижте "Администрация -> Състояния на задачи"). @@ -189,8 +190,9 @@ error_workflow_copy_target: Моля изберете тракер(и) и роля (роли). error_unable_delete_issue_status: Невъзможност за изтриване на състояние на задача error_unable_to_connect: Невъзможност за свързване с (%{value}) + error_attachment_too_big: Този файл не може да бъде качен, понеже надхвърля максималната възможна големина (%{max_size}) warning_attachments_not_saved: "%{count} файла не бяха записани." - + mail_subject_lost_password: "Вашата парола (%{value})" mail_body_lost_password: 'За да смените паролата си, използвайте следния линк:' mail_subject_register: "Активация на профил (%{value})" @@ -203,12 +205,12 @@ mail_body_reminder: "%{count} задачи, назначени на вас са с краен срок в следващите %{days} дни:" mail_subject_wiki_content_added: "Wiki страницата '%{id}' беше добавена" mail_body_wiki_content_added: Wiki страницата '%{id}' беше добавена от %{author}. - mail_subject_wiki_content_updated: "Wiki страницата '%{id}' не беше обновена" + mail_subject_wiki_content_updated: "Wiki страницата '%{id}' беше обновена" mail_body_wiki_content_updated: Wiki страницата '%{id}' беше обновена от %{author}. - + gui_validation_error: 1 грешка gui_validation_error_plural: "%{count} грешки" - + field_name: Име field_description: Описание field_summary: Анотация @@ -265,7 +267,7 @@ field_port: Порт field_account: Профил field_base_dn: Base DN - field_attr_login: Атрибут Login + field_attr_login: Атрибут Login field_attr_firstname: Атрибут Първо име (Firstname) field_attr_lastname: Атрибут Фамилия (Lastname) field_attr_mail: Атрибут Email @@ -329,10 +331,10 @@ setting_plain_text_mail: само чист текст (без HTML) setting_host_name: Хост setting_text_formatting: Форматиране на текста - setting_wiki_compression: Wiki компресиране на историята - setting_feeds_limit: Максимален брой за емисии + setting_wiki_compression: Компресиране на Wiki историята + setting_feeds_limit: Максимален брой записи в ATOM емисии setting_default_projects_public: Новите проекти са публични по подразбиране - setting_autofetch_changesets: Автоматично обработване на ревизиите + setting_autofetch_changesets: Автоматично извличане на ревизиите setting_sys_api_enabled: Разрешаване на WS за управление setting_commit_ref_keywords: Отбелязващи ключови думи setting_commit_fix_keywords: Приключващи ключови думи @@ -341,14 +343,14 @@ setting_time_format: Формат на часа setting_cross_project_issue_relations: Релации на задачи между проекти setting_issue_list_default_columns: Показвани колони по подразбиране - setting_repositories_encodings: Кодови таблици + setting_repositories_encodings: Кодова таблица на прикачените файлове и хранилищата setting_emails_header: Emails header setting_emails_footer: Подтекст за e-mail setting_protocol: Протокол setting_per_page_options: Опции за страниране setting_user_format: Потребителски формат setting_activity_days_default: Брой дни показвани на таб Дейност - setting_display_subprojects_issues: Показване на подпроектите в проектите по подразбиране + setting_display_subprojects_issues: Задачите от подпроектите по подразбиране се показват в главните проекти setting_enabled_scm: Разрешена SCM setting_mail_handler_body_delimiters: Отрязване на e-mail-ите след един от тези редове setting_mail_handler_api_enabled: Разрешаване на WS за входящи e-mail-и @@ -356,7 +358,7 @@ setting_sequential_project_identifiers: Генериране на последователни проектни идентификатори setting_gravatar_enabled: Използване на портребителски икони от Gravatar setting_gravatar_default: Подразбиращо се изображение от Gravatar - setting_diff_max_lines_displayed: Максимален брой показани diff редове + setting_diff_max_lines_displayed: Максимален брой показвани diff редове setting_file_max_size_displayed: Максимален размер на текстовите файлове, показвани inline setting_repository_log_display_limit: Максимален брой на показванете ревизии в лог файла setting_openid: Рарешаване на OpenID вход и регистрация @@ -368,12 +370,14 @@ setting_issue_done_ratio_issue_status: Използване на състоянието на задачите setting_start_of_week: Първи ден на седмицата setting_rest_api_enabled: Разрешаване на REST web сървис - setting_cache_formatted_text: Cache formatted text + setting_cache_formatted_text: Кеширане на форматираните текстове setting_default_notification_option: Подразбиращ се начин за известяване setting_commit_logtime_enabled: Разрешаване на отчитането на работното време setting_commit_logtime_activity_id: Дейност при отчитане на работното време setting_gantt_items_limit: Максимален брой обекти, които да се показват в мрежов график - + setting_issue_group_assignment: Разрешено назначаването на задачи на групи + setting_default_issue_start_date_to_creation_date: Начална дата на новите задачи по подразбиране да бъде днешната дата + permission_add_project: Създаване на проект permission_add_subprojects: Създаване на подпроекти permission_edit_project: Редактиране на проект @@ -623,6 +627,7 @@ label_in_more_than: след повече от label_greater_or_equal: ">=" label_less_or_equal: <= + label_between: между label_in: в следващите label_today: днес label_all_time: всички @@ -693,6 +698,7 @@ label_statistics: Статистики label_commits_per_month: Ревизии по месеци label_commits_per_author: Ревизии по автор + label_diff: diff label_view_diff: Виж разликите label_diff_inline: хоризонтално label_diff_side_by_side: вертикално @@ -821,6 +827,9 @@ label_issues_visibility_public: Всички не-лични задачи label_issues_visibility_own: Задачи, създадени от или назначени на потребителя label_git_report_last_commit: Извеждане на последното поверяване за файлове и папки + label_parent_revision: Ревизия родител + label_child_revision: Ревизия наследник + label_export_options: "%{export_format} опции за експорт" button_login: Вход button_submit: Прикачване @@ -868,11 +877,13 @@ button_quote: Цитат button_duplicate: Дублиране button_show: Показване - + button_edit_section: Редактиране на тази секция + button_export: Експорт + status_active: активен status_registered: регистриран status_locked: заключен - + version_status_open: отворена version_status_locked: заключена version_status_closed: затворена @@ -976,3 +987,21 @@ enumeration_doc_categories: Категории документи enumeration_activities: Дейности (time tracking) enumeration_system_activity: Системна активност + description_filter: Филтър + description_search: Търсене + description_choose_project: Проекти + description_project_scope: Обхват на търсенето + description_notes: Бележки + description_message_content: Съдържание на съобщението + description_query_sort_criteria_attribute: Атрибут на сортиране + description_query_sort_criteria_direction: Посока на сортиране + description_user_mail_notification: Конфигурация известията по пощата + description_available_columns: Налични колони + description_selected_columns: Избрани колони + description_issue_category_reassign: Изберете категория + description_wiki_subpages_reassign: Изберете нова родителска страница + description_all_columns: Всички колони + description_date_range_list: Изберете диапазон от списъка + description_date_range_interval: Изберете диапазон чрез задаване на начална и крайна дати + description_date_from: Въведете начална дата + description_date_to: Въведете крайна дата diff -r 487d96eac004 -r 5e80956cc792 config/locales/bs.yml --- a/config/locales/bs.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/bs.yml Mon Feb 27 13:53:18 2012 +0000 @@ -314,7 +314,6 @@ setting_time_format: Format vremena setting_cross_project_issue_relations: Omogući relacije između aktivnosti na različitim projektima setting_issue_list_default_columns: Podrazumjevane koleone za prikaz na listi aktivnosti - setting_repositories_encodings: Enkodiranje repozitorija setting_emails_footer: Potpis na email-ovima setting_protocol: Protokol setting_per_page_options: Broj objekata po stranici @@ -984,10 +983,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/ca.yml --- a/config/locales/ca.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/ca.yml Mon Feb 27 13:53:18 2012 +0000 @@ -329,7 +329,6 @@ setting_time_format: Format de hora setting_cross_project_issue_relations: "Permet les relacions d'assumptes entre projectes" setting_issue_list_default_columns: "Columnes mostrades per defecte en la llista d'assumptes" - setting_repositories_encodings: Codificacions del dipòsit setting_emails_footer: Peu dels correus electrònics setting_protocol: Protocol setting_per_page_options: Opcions dels objectes per pàgina @@ -973,10 +972,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/cs.yml --- a/config/locales/cs.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/cs.yml Mon Feb 27 13:53:18 2012 +0000 @@ -336,7 +336,6 @@ setting_time_format: Formát času setting_cross_project_issue_relations: Povolit vazby úkolů napříč projekty setting_issue_list_default_columns: Výchozí sloupce zobrazené v seznamu úkolů - setting_repositories_encodings: Kódování setting_emails_header: Hlavička emailů setting_emails_footer: Patička emailů setting_protocol: Protokol @@ -974,10 +973,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/da.yml --- a/config/locales/da.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/da.yml Mon Feb 27 13:53:18 2012 +0000 @@ -303,7 +303,6 @@ setting_time_format: Tidsformat setting_cross_project_issue_relations: Tillad sagsrelationer på tværs af projekter setting_issue_list_default_columns: Standardkolonner på sagslisten - setting_repositories_encodings: Repository-tegnsæt setting_emails_footer: Email-fodnote setting_protocol: Protokol setting_user_format: Brugervisningsformat @@ -987,10 +986,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/de.yml --- a/config/locales/de.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/de.yml Mon Feb 27 13:53:18 2012 +0000 @@ -344,7 +344,6 @@ setting_time_format: Zeitformat setting_cross_project_issue_relations: Ticket-Beziehungen zwischen Projekten erlauben setting_issue_list_default_columns: Default-Spalten in der Ticket-Auflistung - setting_repositories_encodings: Kodierungen der Projektarchive setting_emails_footer: E-Mail-Fußzeile setting_protocol: Protokoll setting_per_page_options: Objekte pro Seite @@ -988,7 +987,6 @@ field_root_directory: Wurzelverzeichnis field_cvs_module: Modul field_cvsroot: CVSROOT - text_git_repository_note: Bare und lokales repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Lokales repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Kommando text_scm_command_version: Version @@ -996,3 +994,37 @@ text_scm_config: Die SCM-Kommandos können in der in config/configuration.yml konfiguriert werden. Redmine muss anschließend neu gestartet werden. text_scm_command_not_available: Scm Kommando ist nicht verfügbar. Bitte prüfen Sie die Einstellungen im Administrationspanel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + + description_filter: Filter + description_search: Suchfeld + description_choose_project: Projekte + description_project_scope: Suchbereich + description_notes: Kommentare + description_message_content: Nachrichteninhalt + description_query_sort_criteria_attribute: Sortierattribut + description_query_sort_criteria_direction: Sortierrichtung + description_user_mail_notification: Mailbenachrichtigungseinstellung + description_available_columns: Verfügbare Spalten + description_selected_columns: Ausgewählte Spalten + description_issue_category_reassign: Neue Kategorie wählen + description_wiki_subpages_reassign: Neue Elternseite wählen + description_date_range_list: Zeitraum aus einer Liste wählen + description_date_range_interval: Zeitraum durch Start- und Enddatum festlegen + description_date_from: Startdatum eintragen + description_date_to: Enddatum eintragen + + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/el.yml --- a/config/locales/el.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/el.yml Mon Feb 27 13:53:18 2012 +0000 @@ -309,7 +309,6 @@ setting_time_format: Μορφή ώρας setting_cross_project_issue_relations: Επιτρέψτε συσχετισμό θεμάτων σε διασταύρωση-έργων setting_issue_list_default_columns: Προκαθορισμένες εμφανιζόμενες στήλες στη λίστα θεμάτων - setting_repositories_encodings: Κωδικοποίηση χαρακτήρων αποθετηρίου setting_emails_footer: Υποσέλιδο στα email setting_protocol: Πρωτόκολο setting_per_page_options: Αντικείμενα ανά σελίδα επιλογών @@ -970,10 +969,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/en-GB.yml --- a/config/locales/en-GB.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/en-GB.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,1 +1,33 @@ en-GB: + error_scm_annotate_big_text_file: "The entry cannot be annotated, as it exceeds the maximum text file size." + setting_issue_group_assignment: Allow issue assignment to groups + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + notice_issue_successful_create: Issue %{id} created. + label_between: between + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/en.yml --- a/config/locales/en.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/en.yml Mon Feb 27 13:53:18 2012 +0000 @@ -8,10 +8,10 @@ default: "%d/%m/%Y" short: "%d %b" long: "%d %B, %Y" - + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] - + # Don't forget the nil at the beginning; there's no such thing as a 0th month month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] @@ -29,7 +29,7 @@ long: "%d %B, %Y %H:%M" am: "am" pm: "pm" - + datetime: distance_in_words: half_a_minute: "half a minute" @@ -92,13 +92,12 @@ gb: "GB" tb: "TB" - # Used in array.to_sentence. support: array: sentence_connector: "and" skip_last_comma: false - + activerecord: errors: template: @@ -133,7 +132,7 @@ must_accept_terms_and_conditions: "You must accept the Terms and Conditions" actionview_instancetag_blank_option: Please select - + general_text_No: 'No' general_text_Yes: 'Yes' general_text_no: 'no' @@ -144,7 +143,7 @@ general_csv_encoding: ISO-8859-1 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: Account was successfully updated. notice_account_invalid_creditentials: Invalid user or password notice_account_password_updated: Password was successfully updated. @@ -175,11 +174,13 @@ notice_unable_delete_time_entry: Unable to delete time log entry. notice_issue_done_ratios_updated: Issue done ratios updated. notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" - + notice_issue_successful_create: "Issue %{id} created." + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" error_scm_not_found: "The entry or revision was not found in the repository." error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" error_scm_annotate: "The entry does not exist or cannot be annotated." + error_scm_annotate_big_text_file: "The entry cannot be annotated, as it exceeds the maximum text file size." error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' @@ -193,8 +194,9 @@ error_workflow_copy_target: 'Please select target tracker(s) and role(s)' error_unable_delete_issue_status: 'Unable to delete issue status' error_unable_to_connect: "Unable to connect (%{value})" + error_attachment_too_big: "This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})" warning_attachments_not_saved: "%{count} file(s) could not be saved." - + mail_subject_lost_password: "Your %{value} password" mail_body_lost_password: 'To change your password, click on the following link:' mail_subject_register: "Your %{value} account activation" @@ -209,7 +211,7 @@ mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." - + gui_validation_error: 1 error gui_validation_error_plural: "%{count} errors" @@ -338,7 +340,7 @@ setting_default_language: Default language setting_login_required: Authentication required setting_self_registration: Self-registration - setting_attachment_max_size: Attachment max. size + setting_attachment_max_size: Maximum attachment size setting_issues_export_limit: Issues export limit setting_mail_from: Emission email address setting_bcc_recipients: Blind carbon copy recipients (bcc) @@ -346,9 +348,9 @@ setting_host_name: Host name and path setting_text_formatting: Text formatting setting_wiki_compression: Wiki history compression - setting_feeds_limit: Feed content limit + setting_feeds_limit: Maximum number of items in Atom feeds setting_default_projects_public: New projects are public by default - setting_autofetch_changesets: Autofetch commits + setting_autofetch_changesets: Fetch commits automatically setting_sys_api_enabled: Enable WS for repository management setting_commit_ref_keywords: Referencing keywords setting_commit_fix_keywords: Fixing keywords @@ -357,7 +359,7 @@ setting_time_format: Time format setting_cross_project_issue_relations: Allow cross-project issue relations setting_issue_list_default_columns: Default columns displayed on the issue list - setting_repositories_encodings: Repositories encodings + setting_repositories_encodings: Attachments and repositories encodings setting_emails_header: Emails header setting_emails_footer: Emails footer setting_protocol: Protocol @@ -372,8 +374,8 @@ setting_sequential_project_identifiers: Generate sequential project identifiers setting_gravatar_enabled: Use Gravatar user icons setting_gravatar_default: Default Gravatar image - setting_diff_max_lines_displayed: Max number of diff lines displayed - setting_file_max_size_displayed: Max size of text files displayed inline + setting_diff_max_lines_displayed: Maximum number of diff lines displayed + setting_file_max_size_displayed: Maximum size of text files displayed inline setting_repository_log_display_limit: Maximum number of revisions displayed on file log setting_openid: Allow OpenID login and registration setting_password_min_length: Minimum password length @@ -392,7 +394,9 @@ setting_gantt_items_limit: Maximum number of items displayed on the gantt chart setting_tipoftheday_text: Tip of the Day setting_notifications_text: Notifications - + setting_issue_group_assignment: Allow issue assignment to groups + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + permission_add_project: Create project permission_add_subprojects: Create subprojects permission_edit_project: Edit project @@ -450,7 +454,7 @@ permission_delete_own_messages: Delete own messages permission_export_wiki_pages: Export wiki pages permission_manage_subtasks: Manage subtasks - + project_module_issue_tracking: Issue tracking (bugs and feature requests) project_module_time_tracking: Time tracking project_module_news: News updates @@ -660,6 +664,7 @@ label_in_more_than: in more than label_greater_or_equal: '>=' label_less_or_equal: '<=' + label_between: between label_in: in label_today: today label_all_time: all time @@ -684,7 +689,7 @@ label_modification: "%{count} change" label_modification_plural: "%{count} changes" label_branch: Branch - label_tag: Tag + label_tag: Tag label_revision: Revision label_revision_plural: Revisions label_revision_id: "Revision %{value}" @@ -733,6 +738,7 @@ label_statistics: Statistics label_commits_per_month: Commits per month label_commits_per_author: Commits per author + label_diff: diff label_view_diff: View differences label_diff_inline: inline label_diff_side_by_side: side by side @@ -864,6 +870,9 @@ label_issues_visibility_public: All non private issues label_issues_visibility_own: Issues created by or assigned to the user label_git_report_last_commit: Report last commit for files and directories + label_parent_revision: Parent + label_child_revision: Child + label_export_options: %{export_format} export options button_login: Login button_submit: Submit @@ -913,6 +922,8 @@ button_show: Show button_welcome_page_edit: Create or edit welcome page button_welcome_page_edit_this: Edit this page + button_edit_section: Edit this section + button_export: Export status_active: active status_registered: registered @@ -997,8 +1008,8 @@ text_files_active_change:
    Click the star to switch active status for a download on or off.
    Active files will be shown more prominently in the download page. text_settings_repo_creation: Creating repository...

    The source code repository for a project will be set up automatically within a few minutes of the project being created.

    Please check again in five minutes, and contact us if there is any problem.

    If you wish to use this project to track a repository that is already hosted somewhere else, please wait until the repository has been created here and then return to this settings page to configure it.

    If you don't want a repository at all, go to the Modules tab and switch it off there. text_scm_path_encoding_note: "Default: UTF-8" - text_git_repository_note: "Bare and local repository (e.g. /gitrepo, c:\gitrepo)" - text_mercurial_repository_note: "Local repository (e.g. /hgrepo, c:\hgrepo)" + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. @@ -1047,3 +1058,21 @@ notice_added_to_project: 'You have been added to the project "{{project_name}}".' notice_project_homepage: "You can visit the project using the following link: {{project_url}}" mail_subject_added_to_project: "You've been added to a project on {{value}}" + description_filter: Filter + description_search: Searchfield + description_choose_project: Projects + description_project_scope: Search scope + description_notes: Notes + description_message_content: Message content + description_query_sort_criteria_attribute: Sort attribute + description_query_sort_criteria_direction: Sort direction + description_user_mail_notification: Mail notification settings + description_available_columns: Available Columns + description_selected_columns: Selected Columns + description_all_columns: All Columns + description_issue_category_reassign: Choose issue category + description_wiki_subpages_reassign: Choose new parent page + description_date_range_list: Choose range from list + description_date_range_interval: Choose range by selecting start and end date + description_date_from: Enter start date + description_date_to: Enter end date diff -r 487d96eac004 -r 5e80956cc792 config/locales/es.yml --- a/config/locales/es.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/es.yml Mon Feb 27 13:53:18 2012 +0000 @@ -132,7 +132,7 @@ greater_than_start_date: "debe ser posterior a la fecha de comienzo" not_same_project: "no pertenece al mismo proyecto" circular_dependency: "Esta relación podría crear una dependencia circular" - cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + cant_link_an_issue_with_a_descendant: "Esta petición no puede ser ligada a una de estas tareas" # Append your own errors here or at the model/attributes scope. @@ -245,6 +245,7 @@ error_can_t_load_default_data: "No se ha podido cargar la configuración por defecto: %{value}" error_issue_not_found_in_project: 'La petición no se encuentra o no está asociada a este proyecto' error_scm_annotate: "No existe la entrada o no ha podido ser anotada" + error_scm_annotate_big_text_file: "La entrada no puede anotarse, al superar el tamaño máximo para ficheros de texto." error_scm_command_failed: "Se produjo un error al acceder al repositorio: %{value}" error_scm_not_found: "La entrada y/o la revisión no existe en el repositorio." field_account: Cuenta @@ -319,7 +320,7 @@ field_start_date: Fecha de inicio field_start_page: Página principal field_status: Estado - field_subject: Tema + field_subject: Asunto field_subproject: Proyecto secundario field_summary: Resumen field_time_zone: Zona horaria @@ -777,7 +778,6 @@ setting_per_page_options: Objetos por página setting_plain_text_mail: sólo texto plano (no HTML) setting_protocol: Protocolo - setting_repositories_encodings: Codificaciones del repositorio setting_self_registration: Registro permitido setting_sequential_project_identifiers: Generar identificadores de proyecto setting_sys_api_enabled: Habilitar SW para la gestión del repositorio @@ -1007,10 +1007,40 @@ field_root_directory: Directorio raíz field_cvs_module: Módulo field_cvsroot: CVSROOT - text_git_repository_note: Repositorio local (bare repository) (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Repositorio local (e.g. /hgrepo, c:\hgrepo) text_scm_command: Orden text_scm_command_version: Versión label_git_report_last_commit: Informar del último commit para ficheros y directorios text_scm_config: Puede configurar las órdenes de cada scm en configuration/configuration.yml. Por favor, reinicie la aplicación después de editarlo text_scm_command_not_available: La orden para el Scm no está disponible. Por favor, compruebe la configuración en el panel de administración. + notice_issue_successful_create: Petición %{id} creada. + label_between: entre + setting_issue_group_assignment: Permitir asignar peticiones a grupos + label_diff: diferencias + text_git_repository_note: El repositorio es básico y local (p.e. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Dirección de ordenación + description_project_scope: Ámbito de búsqueda + description_filter: Filtro + description_user_mail_notification: Configuración de notificaciones por correo + description_date_from: Introduzca la fecha de inicio + description_message_content: Contenido del mensaje + description_available_columns: Columnas disponibles + description_date_range_interval: Elija el rango seleccionando la fecha de inicio y fin + description_issue_category_reassign: Elija la categoría de la petición + description_search: Campo de búsqueda + description_notes: Notas + description_date_range_list: Elija el rango en la lista + description_choose_project: Proyectos + description_date_to: Introduzca la fecha fin + description_query_sort_criteria_attribute: Atributo de ordenación + description_wiki_subpages_reassign: Elija la nueva página padre + description_selected_columns: Columnas seleccionadas + label_parent_revision: Padre + label_child_revision: Hijo + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: Todas las columnas + button_export: Exportar + label_export_options: "%{export_format} opciones de exportación" + error_attachment_too_big: Este fichero no se puede adjuntar porque excede el tamaño máximo de fichero (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/eu.yml --- a/config/locales/eu.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/eu.yml Mon Feb 27 13:53:18 2012 +0000 @@ -320,7 +320,6 @@ setting_time_format: Ordu formatua setting_cross_project_issue_relations: Zereginak proiektuen artean erlazionatzea baimendu setting_issue_list_default_columns: Zereginen zerrendan defektuz ikusten diren zutabeak - setting_repositories_encodings: Biltegien kodeketak setting_emails_footer: Eposten oina setting_protocol: Protokoloa setting_per_page_options: Orriko objektuen aukerak @@ -974,10 +973,41 @@ field_root_directory: Erro direktorioa field_cvs_module: Modulua field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Biltegi locala (adib. /hgrepo, c:\hgrepo) text_scm_command: Komandoa text_scm_command_version: Bertsioa label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/fa.yml --- a/config/locales/fa.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/fa.yml Mon Feb 27 13:53:18 2012 +0000 @@ -332,7 +332,6 @@ setting_time_format: قالب زمان setting_cross_project_issue_relations: توانایی وابستگی میان پروژه‌ای پیامدها setting_issue_list_default_columns: ستون‌های پیش‌گزیده نمایش داده شده در فهرست پیامدها - setting_repositories_encodings: کدگذاری انباره‌ها setting_emails_header: سرنویس ایمیل‌ها setting_emails_footer: پانویس ایمیل‌ها setting_protocol: پیوندنامه @@ -899,7 +898,7 @@ text_user_wrote: "%{value} نوشت:" text_enumeration_destroy_question: "%{count} داده به این برشمردنی وابسته شده‌اند." text_enumeration_category_reassign_to: 'به این برشمردنی وابسته شوند:' - text_email_delivery_not_configured: "دریافت ایمیل پیکربندی نشده است و آگاه‌سازی‌ها غیر فعال هستند.\nکارگزار SMTP خود را در config/email.yml پیکربندی کنید و برنامه را بازنشانی کنید تا فعال شوند." + text_email_delivery_not_configured: "دریافت ایمیل پیکربندی نشده است و آگاه‌سازی‌ها غیر فعال هستند.\nکارگزار SMTP خود را در config/configuration.yml پیکربندی کنید و برنامه را بازنشانی کنید تا فعال شوند." text_repository_usernames_mapping: "کاربر Redmine که به هر نام کاربری پیام‌های انباره نگاشت می‌شود را برگزینید.\nکاربرانی که نام کاربری یا ایمیل همسان دارند، خود به خود نگاشت می‌شوند." text_diff_truncated: '... این تفاوت بریده شده چون بیشتر از بیشترین اندازه نمایش دادنی است.' text_custom_field_possible_values_info: 'یک خط برای هر مقدار' @@ -972,10 +971,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/fi.yml --- a/config/locales/fi.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/fi.yml Mon Feb 27 13:53:18 2012 +0000 @@ -311,7 +311,6 @@ setting_time_format: Ajan muoto setting_cross_project_issue_relations: Salli projektien väliset tapahtuminen suhteet setting_issue_list_default_columns: Vakiosarakkeiden näyttö tapahtumalistauksessa - setting_repositories_encodings: Tietovaraston koodaus setting_emails_footer: Sähköpostin alatunniste setting_protocol: Protokolla setting_per_page_options: Sivun objektien määrän asetukset @@ -991,10 +990,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/fr.yml --- a/config/locales/fr.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/fr.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -# French translations for Ruby on Rails +# French translations for Ruby on Rails # by Christian Lescuyer (christian@flyingcoders.com) # contributor: Sebastien Grosjean - ZenCocoon.com # contributor: Thibaut Cuvelier - Developpez.com @@ -21,7 +21,7 @@ - :day - :month - :year - + time: formats: default: "%d/%m/%Y %H:%M" @@ -78,7 +78,7 @@ hour: "Heure" minute: "Minute" second: "Seconde" - + number: format: precision: 3 @@ -102,7 +102,7 @@ mb: "Mo" gb: "Go" tb: "To" - + support: array: sentence_connector: 'et' @@ -110,11 +110,11 @@ word_connector: ", " two_words_connector: " et " last_word_connector: " et " - + activerecord: errors: template: - header: + header: one: "Impossible d'enregistrer %{model} : une erreur" other: "Impossible d'enregistrer %{model} : %{count} erreurs." body: "Veuillez vérifier les champs suivants :" @@ -145,7 +145,7 @@ cant_link_an_issue_with_a_descendant: "Une demande ne peut pas être liée à l'une de ses sous-tâches" actionview_instancetag_blank_option: Choisir - + general_text_No: 'Non' general_text_Yes: 'Oui' general_text_no: 'non' @@ -156,7 +156,7 @@ general_csv_encoding: ISO-8859-1 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: Le compte a été mis à jour avec succès. notice_account_invalid_creditentials: Identifiant ou mot de passe invalide. notice_account_password_updated: Mot de passe mis à jour avec succès. @@ -185,7 +185,8 @@ notice_issue_done_ratios_updated: L'avancement des demandes a été mis à jour. notice_api_access_key_reseted: Votre clé d'accès API a été réinitialisée. notice_gantt_chart_truncated: "Le diagramme a été tronqué car il excède le nombre maximal d'éléments pouvant être affichés (%{max})" - + notice_issue_successful_create: "La demande %{id} a été créée." + error_can_t_load_default_data: "Une erreur s'est produite lors du chargement du paramétrage : %{value}" error_scm_not_found: "L'entrée et/ou la révision demandée n'existe pas dans le dépôt." error_scm_command_failed: "Une erreur s'est produite lors de l'accès au dépôt : %{value}" @@ -196,9 +197,10 @@ error_workflow_copy_source: 'Veuillez sélectionner un tracker et/ou un rôle source' error_workflow_copy_target: 'Veuillez sélectionner les trackers et rôles cibles' error_issue_done_ratios_not_updated: L'avancement des demandes n'a pas pu être mis à jour. - + error_attachment_too_big: Ce fichier ne peut pas être attaché car il excède la taille maximale autorisée (%{max_size}) + warning_attachments_not_saved: "%{count} fichier(s) n'ont pas pu être sauvegardés." - + mail_subject_lost_password: "Votre mot de passe %{value}" mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :' mail_subject_register: "Activation de votre compte %{value}" @@ -213,10 +215,10 @@ mail_body_wiki_content_added: "La page wiki '%{id}' a été ajoutée par %{author}." mail_subject_wiki_content_updated: "Page wiki '%{id}' mise à jour" mail_body_wiki_content_updated: "La page wiki '%{id}' a été mise à jour par %{author}." - + gui_validation_error: 1 erreur gui_validation_error_plural: "%{count} erreurs" - + field_name: Nom field_description: Description field_summary: Résumé @@ -321,26 +323,25 @@ setting_default_language: Langue par défaut setting_login_required: Authentification obligatoire setting_self_registration: Inscription des nouveaux utilisateurs - setting_attachment_max_size: Taille max des fichiers - setting_issues_export_limit: Limite export demandes + setting_attachment_max_size: Taille maximale des fichiers + setting_issues_export_limit: Limite d'exportation des demandes setting_mail_from: Adresse d'émission setting_bcc_recipients: Destinataires en copie cachée (cci) - setting_plain_text_mail: Mail texte brut (non HTML) + setting_plain_text_mail: Mail en texte brut (non HTML) setting_host_name: Nom d'hôte et chemin setting_text_formatting: Formatage du texte - setting_wiki_compression: Compression historique wiki - setting_feeds_limit: Limite du contenu des flux RSS + setting_wiki_compression: Compression de l'historique des pages wiki + setting_feeds_limit: Nombre maximal d'éléments dans les flux Atom setting_default_projects_public: Définir les nouveaux projets comme publics par défaut - setting_autofetch_changesets: Récupération auto. des commits + setting_autofetch_changesets: Récupération automatique des commits setting_sys_api_enabled: Activer les WS pour la gestion des dépôts setting_commit_ref_keywords: Mots-clés de référencement setting_commit_fix_keywords: Mots-clés de résolution - setting_autologin: Autologin + setting_autologin: Durée maximale de connexion automatique setting_date_format: Format de date setting_time_format: Format d'heure setting_cross_project_issue_relations: Autoriser les relations entre demandes de différents projets setting_issue_list_default_columns: Colonnes affichées par défaut sur la liste des demandes - setting_repositories_encodings: Encodages des dépôts setting_emails_footer: Pied-de-page des emails setting_protocol: Protocole setting_per_page_options: Options d'objets affichés par page @@ -370,7 +371,9 @@ setting_commit_logtime_enabled: Permettre la saisie de temps setting_commit_logtime_activity_id: Activité pour le temps saisi setting_gantt_items_limit: Nombre maximum d'éléments affichés sur le gantt - + setting_issue_group_assignment: Permettre l'assignement des demandes aux groupes + setting_default_issue_start_date_to_creation_date: Donner à la date de début d'une nouvelle demande la valeur de la date du jour + permission_add_project: Créer un projet permission_add_subprojects: Créer des sous-projets permission_edit_project: Modifier le projet @@ -428,7 +431,7 @@ permission_export_wiki_pages: Exporter les pages permission_manage_project_activities: Gérer les activités permission_manage_subtasks: Gérer les sous-tâches - + project_module_issue_tracking: Suivi des demandes project_module_time_tracking: Suivi du temps passé project_module_news: Publication d'annonces @@ -437,7 +440,7 @@ project_module_wiki: Wiki project_module_repository: Dépôt de sources project_module_boards: Forums de discussion - + label_user: Utilisateur label_user_plural: Utilisateurs label_user_new: Nouvel utilisateur @@ -802,7 +805,8 @@ label_issues_visibility_all: Toutes les demandes label_issues_visibility_public: Toutes les demandes non privées label_issues_visibility_own: Demandes créées par ou assignées à l'utilisateur - + label_export_options: Options d'exportation %{export_format} + button_login: Connexion button_submit: Soumettre button_save: Sauvegarder @@ -848,15 +852,17 @@ button_quote: Citer button_duplicate: Dupliquer button_show: Afficher - + button_edit_section: Modifier cette section + button_export: Exporter + status_active: actif status_registered: enregistré status_locked: verrouillé - + version_status_open: ouvert version_status_locked: verrouillé version_status_closed: fermé - + text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée text_regexp_info: ex. ^[A-Z0-9]+$ text_min_max_length_info: 0 pour aucune restriction @@ -911,7 +917,7 @@ text_wiki_page_reassign_children: "Réaffecter les sous-pages à cette page" text_own_membership_delete_confirmation: "Vous allez supprimer tout ou partie de vos permissions sur ce projet et ne serez peut-être plus autorisé à modifier ce projet.\nEtes-vous sûr de vouloir continuer ?" text_warn_on_leaving_unsaved: "Cette page contient du texte non sauvegardé qui sera perdu si vous quittez la page." - + default_role_manager: "Manager " default_role_developer: "Développeur " default_role_reporter: "Rapporteur " @@ -933,12 +939,13 @@ default_priority_immediate: Immédiat default_activity_design: Conception default_activity_development: Développement - + enumeration_issue_priorities: Priorités des demandes enumeration_doc_categories: Catégories des documents enumeration_activities: Activités (suivi du temps) label_greater_or_equal: ">=" label_less_or_equal: "<=" + label_between: entre label_view_all_revisions: Voir toutes les révisions label_tag: Tag label_branch: Branche @@ -985,10 +992,33 @@ field_root_directory: Répertoire racine field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: "Dépôt nu (bare) et local (exemples : /gitrepo, c:\gitrepo)" - text_mercurial_repository_note: "Dépôt local (exemples : /hgrepo, c:\hgrepo)" + text_mercurial_repository_note: "Dépôt local (exemples : /hgrepo, c:\\hgrepo)" text_scm_command: Commande text_scm_command_version: Version label_git_report_last_commit: Afficher le dernier commit des fichiers et répertoires text_scm_config: Vous pouvez configurer les commandes des SCM dans config/configuration.yml. Redémarrer l'application après modification. text_scm_command_not_available: Ce SCM n'est pas disponible. Vérifier les paramètres dans la section administration. + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Ordre de tri + description_project_scope: Périmètre de recherche + description_filter: Filtre + description_user_mail_notification: Option de notification + description_date_from: Date de début + description_message_content: Contenu du message + description_available_columns: Colonnes disponibles + description_all_columns: Toutes les colonnes + description_date_range_interval: Choisir une période + description_issue_category_reassign: Choisir une catégorie + description_search: Champ de recherche + description_notes: Notes + description_date_range_list: Choisir une période prédéfinie + description_choose_project: Projets + description_date_to: Date de fin + description_query_sort_criteria_attribute: Critère de tri + description_wiki_subpages_reassign: Choisir une nouvelle page parent + description_selected_columns: Colonnes sélectionnées + label_parent_revision: Parent + label_child_revision: Enfant + error_scm_annotate_big_text_file: Cette entrée ne peut pas être annotée car elle excède la taille maximale. + setting_repositories_encodings: Encodages des fichiers et des dépôts diff -r 487d96eac004 -r 5e80956cc792 config/locales/gl.yml --- a/config/locales/gl.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/gl.yml Mon Feb 27 13:53:18 2012 +0000 @@ -754,7 +754,6 @@ setting_per_page_options: Obxectos por páxina setting_plain_text_mail: só texto plano (non HTML) setting_protocol: Protocolo - setting_repositories_encodings: Codificacións do repositorio setting_self_registration: Rexistro permitido setting_sequential_project_identifiers: Xerar identificadores de proxecto setting_sys_api_enabled: Habilitar SW para a xestión do repositorio @@ -982,10 +981,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/he.yml --- a/config/locales/he.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/he.yml Mon Feb 27 13:53:18 2012 +0000 @@ -332,7 +332,6 @@ setting_time_format: פורמט זמן setting_cross_project_issue_relations: הרשה קישור נושאים בין פרויקטים setting_issue_list_default_columns: עמודות ברירת מחדל המוצגות ברשימת הנושאים - setting_repositories_encodings: קידוד המאגרים setting_emails_footer: תחתית דוא"ל setting_protocol: פרוטוקול setting_per_page_options: אפשרויות אוביקטים לפי דף @@ -975,10 +974,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/hr.yml --- a/config/locales/hr.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/hr.yml Mon Feb 27 13:53:18 2012 +0000 @@ -315,7 +315,6 @@ setting_time_format: Format vremena setting_cross_project_issue_relations: Dozvoli povezivanje predmeta izmedu različitih projekata setting_issue_list_default_columns: Stupci prikazani na listi predmeta - setting_repositories_encodings: Kodna stranica setting_emails_footer: Zaglavlje e-pošte setting_protocol: Protokol setting_per_page_options: Objekata po stranici opcija @@ -977,10 +976,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/hu.yml --- a/config/locales/hu.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/hu.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -# Hungarian translations for Ruby on Rails +# Hungarian translations for Ruby on Rails # by Richard Abonyi (richard.abonyi@gmail.com) # thanks to KKata, replaced and #hup.hu # Cleaned up by László Bácsi (http://lackac.hu) @@ -34,40 +34,40 @@ distance_in_words: half_a_minute: 'fél perc' less_than_x_seconds: -# zero: 'kevesebb, mint 1 másodperc' - one: 'kevesebb, mint 1 másodperc' - other: 'kevesebb, mint %{count} másodperc' +# zero: 'kevesebb, mint 1 másodperce' + one: 'kevesebb, mint 1 másodperce' + other: 'kevesebb, mint %{count} másodperce' x_seconds: - one: '1 másodperc' - other: '%{count} másodperc' + one: '1 másodperce' + other: '%{count} másodperce' less_than_x_minutes: -# zero: 'kevesebb, mint 1 perc' - one: 'kevesebb, mint 1 perc' - other: 'kevesebb, mint %{count} perc' +# zero: 'kevesebb, mint 1 perce' + one: 'kevesebb, mint 1 perce' + other: 'kevesebb, mint %{count} perce' x_minutes: - one: '1 perc' - other: '%{count} perc' + one: '1 perce' + other: '%{count} perce' about_x_hours: - one: 'majdnem 1 óra' - other: 'majdnem %{count} óra' + one: 'csaknem 1 órája' + other: 'csaknem %{count} órája' x_days: - one: '1 nap' - other: '%{count} nap' + one: '1 napja' + other: '%{count} napja' about_x_months: - one: 'majdnem 1 hónap' - other: 'majdnem %{count} hónap' + one: 'csaknem 1 hónapja' + other: 'csaknem %{count} hónapja' x_months: - one: '1 hónap' - other: '%{count} hónap' + one: '1 hónapja' + other: '%{count} hónapja' about_x_years: - one: 'majdnem 1 év' - other: 'majdnem %{count} év' + one: 'csaknem 1 éve' + other: 'csaknem %{count} éve' over_x_years: - one: 'több, mint 1 év' - other: 'több, mint %{count} év' + one: 'több, mint 1 éve' + other: 'több, mint %{count} éve' almost_x_years: - one: "közel 1 év" - other: "közel %{count} év" + one: "csaknem 1 éve" + other: "csaknem %{count} éve" prompts: year: "Év" month: "Hónap" @@ -149,7 +149,7 @@ cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" actionview_instancetag_blank_option: Kérem válasszon - + general_text_No: 'Nem' general_text_Yes: 'Igen' general_text_no: 'nem' @@ -160,7 +160,7 @@ general_csv_encoding: ISO-8859-2 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: A fiók adatai sikeresen frissítve. notice_account_invalid_creditentials: Hibás felhasználói név, vagy jelszó notice_account_password_updated: A jelszó módosítása megtörtént. @@ -184,13 +184,13 @@ notice_no_issue_selected: "Nincs feladat kiválasztva! Kérem jelölje meg melyik feladatot szeretné szerkeszteni!" notice_account_pending: "A fiókja létrejött, és adminisztrátori jóváhagyásra vár." notice_default_data_loaded: Az alapértelmezett konfiguráció betöltése sikeresen megtörtént. - + error_can_t_load_default_data: "Az alapértelmezett konfiguráció betöltése nem lehetséges: %{value}" error_scm_not_found: "A bejegyzés, vagy revízió nem található a tárolóban." error_scm_command_failed: "A tároló elérése közben hiba lépett fel: %{value}" error_scm_annotate: "A bejegyzés nem létezik, vagy nics jegyzetekkel ellátva." error_issue_not_found_in_project: 'A feladat nem található, vagy nem ehhez a projekthez tartozik' - + mail_subject_lost_password: Az Ön Redmine jelszava mail_body_lost_password: 'A Redmine jelszó megváltoztatásához, kattintson a következő linkre:' mail_subject_register: Redmine azonosító aktiválása @@ -199,10 +199,10 @@ mail_body_account_information: Az Ön Redmine azonosítójának információi mail_subject_account_activation_request: Redmine azonosító aktiválási kérelem mail_body_account_activation_request: "Egy új felhasználó (%{value}) regisztrált, azonosítója jóváhasgyásra várakozik:" - + gui_validation_error: 1 hiba gui_validation_error_plural: "%{count} hiba" - + field_name: Név field_description: Leírás field_summary: Összegzés @@ -264,7 +264,7 @@ field_attr_mail: E-mail field_onthefly: On-the-fly felhasználó létrehozás field_start_date: Kezdés dátuma - field_done_ratio: Elkészült (%) + field_done_ratio: Készültség (%) field_auth_source: Azonosítási mód field_hide_mail: Rejtse el az e-mail címem field_comments: Megjegyzés @@ -280,13 +280,13 @@ field_delay: Késés field_assignable: Feladat rendelhető ehhez a szerepkörhöz field_redirect_existing_links: Létező linkek átirányítása - field_estimated_hours: Becsült idő + field_estimated_hours: Becsült időigény field_column_names: Oszlopok field_time_zone: Időzóna field_searchable: Kereshető field_default_value: Alapértelmezett érték field_comments_sorting: Feljegyzések megjelenítése - + setting_app_title: Alkalmazás címe setting_app_subtitle: Alkalmazás alcíme setting_welcome_text: Üdvözlő üzenet @@ -311,7 +311,6 @@ setting_time_format: Idő formátum setting_cross_project_issue_relations: Kereszt-projekt feladat hivatkozások engedélyezése setting_issue_list_default_columns: Az alapértelmezésként megjelenített oszlopok a feladat listában - setting_repositories_encodings: Tárolók kódolása setting_emails_footer: E-mail lábléc setting_protocol: Protokol setting_per_page_options: Objektum / oldal opciók @@ -319,16 +318,16 @@ setting_activity_days_default: Napok megjelenítése a project aktivitásnál setting_display_subprojects_issues: Alapértelmezettként mutassa az alprojektek feladatait is a projekteken setting_start_of_week: A hét első napja - + project_module_issue_tracking: Feladat követés project_module_time_tracking: Idő rögzítés project_module_news: Hírek project_module_documents: Dokumentumok project_module_files: Fájlok project_module_wiki: Wiki - project_module_repository: Tároló + project_module_repository: Forráskód project_module_boards: Fórumok - + label_user: Felhasználó label_user_plural: Felhasználók label_user_new: Új felhasználó @@ -392,7 +391,7 @@ label_assigned_to_me_issues: A nekem kiosztott feladatok label_last_login: Utolsó bejelentkezés label_registered_on: Regisztrált - label_activity: Tevékenységek + label_activity: Történések label_overall_activity: Teljes aktivitás label_new: Új label_logged_as: Bejelentkezve, mint @@ -511,8 +510,8 @@ label_contains: tartalmazza label_not_contains: nem tartalmazza label_day_plural: nap - label_repository: Tároló - label_repository_plural: Tárolók + label_repository: Forráskód + label_repository_plural: Forráskódok label_browse: Tallóz label_modification: "%{count} változás" label_modification_plural: "%{count} változás" @@ -601,10 +600,10 @@ label_language_based: A felhasználó nyelve alapján label_sort_by: "%{value} szerint rendezve" label_send_test_email: Teszt e-mail küldése - label_feeds_access_key_created_on: "RSS hozzáférési kulcs létrehozva ennyivel ezelőtt: %{value}" + label_feeds_access_key_created_on: "RSS hozzáférési kulcs létrehozva %{value}" label_module_plural: Modulok - label_added_time_by: "%{author} adta hozzá ennyivel ezelőtt: %{age}" - label_updated_time: "Utolsó módosítás ennyivel ezelőtt: %{value}" + label_added_time_by: "%{author} adta hozzá %{age}" + label_updated_time: "Utolsó módosítás %{value}" label_jump_to_a_project: Ugrás projekthez... label_file_plural: Fájlok label_changeset_plural: Changesets @@ -635,7 +634,7 @@ label_chronological_order: Időrendben label_reverse_chronological_order: Fordított időrendben label_planning: Tervezés - + button_login: Bejelentkezés button_submit: Elfogad button_save: Mentés @@ -673,11 +672,11 @@ button_annotate: Jegyzetel button_update: Módosít button_configure: Konfigurál - + status_active: aktív status_registered: regisztrált status_locked: zárolt - + text_select_mail_notifications: Válasszon eseményeket, amelyekről e-mail értesítést kell küldeni. text_regexp_info: pl. ^[A-Z0-9]+$ text_min_max_length_info: 0 = nincs korlátozás @@ -696,11 +695,11 @@ text_unallowed_characters: Tiltott karakterek text_comma_separated: Több érték megengedett (vesszővel elválasztva) text_issues_ref_in_commit_messages: Hivatkozás feladatokra, feladatok javítása a commit üzenetekben - text_issue_added: "A feladatot %{id} bejelentette: %{author}." - text_issue_updated: "A feladatot %{id} módosította: %{author}." + text_issue_added: "%{author} új feladatot hozott létre %{id} sorszámmal." + text_issue_updated: "%{author} módosította a %{id} sorszámú feladatot." text_wiki_destroy_confirmation: Biztosan törölni szeretné ezt a wiki-t minden tartalmával együtt ? - text_issue_category_destroy_question: "Néhány feladat (%{count}) hozzá van rendelve ehhez a kategóriához. Mit szeretne tenni ?" - text_issue_category_destroy_assignments: Kategória hozzárendelés megszűntetése + text_issue_category_destroy_question: "Néhány feladat (%{count}) hozzá van rendelve ehhez a kategóriához. Mit szeretne tenni?" + text_issue_category_destroy_assignments: Kategória hozzárendelés megszüntetése text_issue_category_reassign_to: Feladatok újra hozzárendelése másik kategóriához text_user_mail_option: "A nem kiválasztott projektekről csak akkor kap értesítést, ha figyelést kér rá, vagy részt vesz benne (pl. Ön a létrehozó, vagy a hozzárendelő)" text_no_configuration_data: "Szerepkörök, feladat típusok, feladat státuszok, és workflow adatok még nincsenek konfigurálva.\nErősen ajánlott, az alapértelmezett konfiguráció betöltése, és utána módosíthatja azt." @@ -710,18 +709,18 @@ text_select_project_modules: 'Válassza ki az engedélyezett modulokat ehhez a projekthez:' text_default_administrator_account_changed: Alapértelmezett adminisztrátor fiók megváltoztatva text_file_repository_writable: Fájl tároló írható - text_rmagick_available: RMagick elérhető (opcionális) - text_destroy_time_entries_question: "%{hours} órányi munka van rögzítve a feladatokon, amiket törölni szeretne. Mit szeretne tenni ?" + text_rmagick_available: RMagick elérhető (nem kötelező) + text_destroy_time_entries_question: "%{hours} órányi munka van rögzítve a feladatokon, amiket törölni szeretne. Mit szeretne tenni?" text_destroy_time_entries: A rögzített órák törlése text_assign_time_entries_to_project: A rögzített órák hozzárendelése a projekthez text_reassign_time_entries: 'A rögzített órák újra hozzárendelése másik feladathoz:' - + default_role_manager: Vezető default_role_developer: Fejlesztő default_role_reporter: Bejelentő default_tracker_bug: Hiba default_tracker_feature: Fejlesztés - default_tracker_support: Support + default_tracker_support: Támogatás default_issue_status_new: Új default_issue_status_in_progress: Folyamatban default_issue_status_resolved: Megoldva @@ -737,12 +736,12 @@ default_priority_immediate: Azonnal default_activity_design: Tervezés default_activity_development: Fejlesztés - + enumeration_issue_priorities: Feladat prioritások enumeration_doc_categories: Dokumentum kategóriák enumeration_activities: Tevékenységek (idő rögzítés) mail_body_reminder: "%{count} neked kiosztott feladat határidős az elkövetkező %{days} napban:" - mail_subject_reminder: "%{count} feladat határidős az elkövetkező %{days} napokban" + mail_subject_reminder: "%{count} feladat határidős az elkövetkező %{days} napban" text_user_wrote: "%{value} írta:" label_duplicated_by: duplikálta setting_enabled_scm: Forráskódkezelő (SCM) engedélyezése @@ -813,14 +812,14 @@ permission_edit_own_messages: Saját üzenetek szerkesztése permission_delete_own_messages: Saját üzenetek törlése label_user_activity: "%{value} tevékenységei" - label_updated_time_by: "Módosította %{author} ennyivel ezelőtt: %{age}" + label_updated_time_by: "Módosította %{author} %{age}" text_diff_truncated: '... A diff fájl vége nem jelenik meg, mert hosszab, mint a megjeleníthető sorok száma.' setting_diff_max_lines_displayed: A megjelenítendő sorok száma (maximum) a diff fájloknál text_plugin_assets_writable: Plugin eszközök könyvtár írható warning_attachments_not_saved: "%{count} fájl mentése nem sikerült." button_create_and_continue: Létrehozás és folytatás text_custom_field_possible_values_info: 'Értékenként egy sor' - label_display: Megjelenés + label_display: Megmutat field_editable: Szerkeszthető setting_repository_log_display_limit: Maximum hány revíziót mutasson meg a log megjelenítésekor setting_file_max_size_displayed: Maximum mekkora szövegfájlokat jelenítsen meg soronkénti összehasonlításnál @@ -836,40 +835,40 @@ label_greater_or_equal: ">=" label_less_or_equal: "<=" text_wiki_page_destroy_question: Ennek az oldalnak %{descendants} gyermek-, és leszármazott oldala van. Mit szeretne tenni? - text_wiki_page_reassign_children: Az aloldalak hozzárendelése ehhez a szülő oldalhoz - text_wiki_page_nullify_children: Az aloldalak megtartása, mint főoldalak + text_wiki_page_reassign_children: Aloldalak hozzárendelése ehhez a szülő oldalhoz + text_wiki_page_nullify_children: Aloldalak átalakítása főoldallá text_wiki_page_destroy_children: Minden aloldal és leszármazottjának törlése setting_password_min_length: Minimum jelszó hosszúság field_group_by: Szerint csoportosítva mail_subject_wiki_content_updated: "'%{id}' wiki oldal frissítve" label_wiki_content_added: Wiki oldal hozzáadva mail_subject_wiki_content_added: "Új wiki oldal: '%{id}'" - mail_body_wiki_content_added: A '%{id}' wiki oldalt %{author} hozta létre. + mail_body_wiki_content_added: "%{author} létrehozta a '%{id}' wiki oldalt." label_wiki_content_updated: Wiki oldal frissítve - mail_body_wiki_content_updated: A '%{id}' wiki oldalt %{author} frissítette. + mail_body_wiki_content_updated: "%{author} frissítette a '%{id}' wiki oldalt." permission_add_project: Projekt létrehozása setting_new_project_user_role_id: Projekt létrehozási jog nem adminisztrátor felhasználóknak - label_view_all_revisions: Minden revízió megtekintése + label_view_all_revisions: Összes verzió label_tag: Tag label_branch: Branch error_no_tracker_in_project: Nincs feladat típus hozzárendelve ehhez a projekthez. Kérem ellenőrizze a projekt beállításait. error_no_default_issue_status: Nincs alapértelmezett feladat státusz beállítva. Kérem ellenőrizze a beállításokat (Itt találja "Adminisztráció -> Feladat státuszok"). - text_journal_changed: "%{label} változott erről: %{old} erre: %{new}" + text_journal_changed: "%{label} megváltozott, %{old} helyett %{new} lett" text_journal_set_to: "%{label} új értéke: %{value}" - text_journal_deleted: "%{label} törölve (%{old})" + text_journal_deleted: "%{label} törölve lett (%{old})" label_group_plural: Csoportok label_group: Csoport label_group_new: Új csoport - label_time_entry_plural: Rögzített idő + label_time_entry_plural: Időráfordítás text_journal_added: "%{label} %{value} hozzáadva" field_active: Aktív - enumeration_system_activity: Rendszer Tevékenység + enumeration_system_activity: Rendszertevékenység permission_delete_issue_watchers: Megfigyelők törlése version_status_closed: lezárt version_status_locked: zárolt version_status_open: nyitott error_can_not_reopen_issue_on_closed_version: Lezárt verzióhoz rendelt feladatot nem lehet újranyitni - label_user_anonymous: Anonymous + label_user_anonymous: Névtelen button_move_and_follow: Mozgatás és követés setting_default_projects_modules: Alapértelmezett modulok az új projektekhez setting_gravatar_default: Alapértelmezett Gravatar kép @@ -989,10 +988,41 @@ field_root_directory: Gyökér könyvtár field_cvs_module: Modul field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Helyi repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Parancs text_scm_command_version: Verzió label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/id.yml --- a/config/locales/id.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/id.yml Mon Feb 27 13:53:18 2012 +0000 @@ -314,7 +314,6 @@ setting_time_format: Format waktu setting_cross_project_issue_relations: Perbolehkan kaitan masalah proyek berbeda setting_issue_list_default_columns: Kolom default ditampilkan di daftar masalah - setting_repositories_encodings: Repositories encodings setting_emails_footer: Footer untuk email setting_protocol: Protokol setting_per_page_options: Pilihan obyek per halaman @@ -978,10 +977,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/it.yml --- a/config/locales/it.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/it.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -# Italian translations for Ruby on Rails +# Italian translations for Ruby on Rails # by Claudio Poli (masterkain@gmail.com) # by Diego Pierotto (ita.translations@tiscali.it) # by Emidio Stani (emidiostani@gmail.com) @@ -20,7 +20,7 @@ - :day - :month - :year - + time: formats: default: "%a %d %b %Y, %H:%M:%S %z" @@ -28,14 +28,14 @@ short: "%d %b %H:%M" long: "%d %B %Y %H:%M" only_second: "%S" - + datetime: formats: default: "%d-%m-%YT%H:%M:%S%Z" - + am: 'am' pm: 'pm' - + datetime: distance_in_words: half_a_minute: "mezzo minuto" @@ -72,7 +72,7 @@ almost_x_years: one: "quasi 1 anno" other: "quasi %{count} anni" - + number: format: precision: 3 @@ -94,16 +94,16 @@ mb: "MB" gb: "GB" tb: "TB" - + support: array: sentence_connector: "e" skip_last_comma: false - + activerecord: errors: template: - header: + header: one: "Non posso salvare questo %{model}: 1 errore" other: "Non posso salvare questo %{model}: %{count} errori." body: "Per favore ricontrolla i seguenti campi:" @@ -133,7 +133,7 @@ cant_link_an_issue_with_a_descendant: "Una segnalazione non può essere collegata a una delle sue discendenti" actionview_instancetag_blank_option: Scegli - + general_text_No: 'No' general_text_Yes: 'Sì' general_text_no: 'no' @@ -144,7 +144,7 @@ general_csv_encoding: ISO-8859-1 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: L'utente è stato aggiornato. notice_account_invalid_creditentials: Nome utente o password non validi. notice_account_password_updated: La password è stata aggiornata. @@ -164,18 +164,18 @@ notice_email_sent: "Una email è stata spedita a %{value}" notice_email_error: "Si è verificato un errore durante l'invio di una email (%{value})" notice_feeds_access_key_reseted: La tua chiave di accesso RSS è stata reimpostata. - + error_scm_not_found: "La risorsa e/o la versione non esistono nel repository." error_scm_command_failed: "Si è verificato un errore durante l'accesso al repository: %{value}" - + mail_subject_lost_password: "Password %{value}" mail_body_lost_password: 'Per cambiare la password, usa il seguente collegamento:' mail_subject_register: "Attivazione utente %{value}" mail_body_register: "Per attivare l'utente, usa il seguente collegamento:" - + gui_validation_error: 1 errore gui_validation_error_plural: "%{count} errori" - + field_name: Nome field_description: Descrizione field_summary: Sommario @@ -206,7 +206,7 @@ field_is_default: Stato predefinito field_tracker: Tracker field_subject: Oggetto - field_due_date: Data ultima + field_due_date: Scadenza field_assigned_to: Assegnato a field_priority: Priorità field_fixed_version: Versione prevista @@ -255,7 +255,7 @@ field_redirect_existing_links: Redirige i collegamenti esistenti field_estimated_hours: Tempo stimato field_default_value: Stato predefinito - + setting_app_title: Titolo applicazione setting_app_subtitle: Sottotitolo applicazione setting_welcome_text: Testo di benvenuto @@ -276,7 +276,7 @@ setting_autologin: Connessione automatica setting_date_format: Formato data setting_cross_project_issue_relations: Consenti la creazione di relazioni tra segnalazioni in progetti differenti - + label_user: Utente label_user_plural: Utenti label_user_new: Nuovo utente @@ -533,7 +533,7 @@ label_added_time_by: "Aggiunto da %{author} %{age} fa" label_updated_time: "Aggiornato %{value} fa" label_jump_to_a_project: Vai al progetto... - + button_login: Entra button_submit: Invia button_save: Salva @@ -566,11 +566,11 @@ button_unarchive: Ripristina button_reset: Reimposta button_rename: Rinomina - + status_active: attivo status_registered: registrato status_locked: bloccato - + text_select_mail_notifications: Seleziona le azioni per cui deve essere inviata una notifica. text_regexp_info: es. ^[A-Z0-9]+$ text_min_max_length_info: 0 significa nessuna restrizione @@ -593,7 +593,7 @@ text_issue_category_destroy_question: "Alcune segnalazioni (%{count}) risultano assegnate a questa categoria. Cosa vuoi fare ?" text_issue_category_destroy_assignments: Rimuovi le assegnazioni a questa categoria text_issue_category_reassign_to: Riassegna segnalazioni a questa categoria - + default_role_manager: Gestore default_role_developer: Sviluppatore default_role_reporter: Segnalatore @@ -615,7 +615,7 @@ default_priority_immediate: Immediata default_activity_design: Progettazione default_activity_development: Sviluppo - + enumeration_issue_priorities: Priorità segnalazioni enumeration_doc_categories: Categorie di documenti enumeration_activities: Attività (time tracking) @@ -624,7 +624,6 @@ field_column_names: Colonne label_default_columns: Colonne predefinite setting_issue_list_default_columns: Colonne predefinite mostrate nell'elenco segnalazioni - setting_repositories_encodings: Codifiche dei repository notice_no_issue_selected: "Nessuna segnalazione selezionata! Seleziona le segnalazioni che intendi modificare." label_bulk_edit_selected_issues: Modifica massiva delle segnalazioni selezionate label_no_change_option: (Nessuna modifica) @@ -940,41 +939,72 @@ setting_commit_logtime_enabled: Abilita registrazione del tempo di collegamento notice_gantt_chart_truncated: Il grafico è stato troncato perchè eccede il numero di oggetti (%{max}) da visualizzare setting_gantt_items_limit: Massimo numero di oggetti da visualizzare sul diagramma di gantt - field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text - text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. - label_my_queries: My custom queries - text_journal_changed_no_detail: "%{label} updated" - label_news_comment_added: Comment added to a news - button_expand_all: Expand all - button_collapse_all: Collapse all - label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee - label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author - label_bulk_edit_selected_time_entries: Bulk edit selected time entries - text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? - label_role_anonymous: Anonymous - label_role_non_member: Non member - label_issue_note_added: Note added - label_issue_status_updated: Status updated - label_issue_priority_updated: Priority updated - label_issues_visibility_own: Issues created by or assigned to the user - field_issues_visibility: Issues visibility - label_issues_visibility_all: All issues - permission_set_own_issues_private: Set own issues public or private - field_is_private: Private - permission_set_issues_private: Set issues public or private - label_issues_visibility_public: All non private issues - text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_warn_on_leaving_unsaved: Avvisami quando lascio una pagina con testo non salvato + text_warn_on_leaving_unsaved: La pagina corrente contiene del testo non salvato che verrà perso se lasci questa pagina. + label_my_queries: Le mie queries personalizzate + text_journal_changed_no_detail: "%{label} aggiornato" + label_news_comment_added: Commento aggiunto a una notizia + button_expand_all: Espandi tutto + button_collapse_all: Comprimi tutto + label_additional_workflow_transitions_for_assignee: Transizioni supplementari consentite quando l'utente è l'assegnatario + label_additional_workflow_transitions_for_author: Transizioni supplementari consentite quando l'utente è l'autore + label_bulk_edit_selected_time_entries: Modifica massiva delle ore segnalate selezionate + text_time_entries_destroy_confirmation: Sei sicuro di voler eliminare l'ora\e selezionata\e? + label_role_anonymous: Anonimo + label_role_non_member: Non membro + label_issue_note_added: Nota aggiunta + label_issue_status_updated: Stato aggiornato + label_issue_priority_updated: Priorità aggiornata + label_issues_visibility_own: Segnalazioni create o assegnate all'utente + field_issues_visibility: Visibilità segnalazioni + label_issues_visibility_all: Tutte le segnalazioni + permission_set_own_issues_private: Imposta le proprie segnalazioni pubbliche o private + field_is_private: Privato + permission_set_issues_private: Imposta le segnalazioni pubbliche o private + label_issues_visibility_public: Tutte le segnalazioni non private + text_issues_destroy_descendants_confirmation: Questo eliminerà anche %{count} sottoattività. field_commit_logs_encoding: Codifica dei messaggi di commit - field_scm_path_encoding: Path encoding - text_scm_path_encoding_note: "Default: UTF-8" - field_path_to_repository: Path to repository - field_root_directory: Root directory - field_cvs_module: Module + field_scm_path_encoding: Codifica del percorso + text_scm_path_encoding_note: "Predefinito: UTF-8" + field_path_to_repository: Percorso del repository + field_root_directory: Directory radice + field_cvs_module: Modulo field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) - text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) - text_scm_command: Command - text_scm_command_version: Version - label_git_report_last_commit: Report last commit for files and directories - text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. - text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + text_mercurial_repository_note: Repository locale (es. /hgrepo, c:\hgrepo) + text_scm_command: Comando + text_scm_command_version: Versione + label_git_report_last_commit: Riporta l'ultimo commit per files e directories + text_scm_config: Puoi configurare i comandi scm nel file config/configuration.yml. E' necessario riavviare l'applicazione dopo averlo modificato. + text_scm_command_not_available: Il comando scm non è disponibile. Controllare le impostazioni nel pannello di amministrazione. + notice_issue_successful_create: Segnalazione %{id} creata. + label_between: tra + setting_issue_group_assignment: Permetti di assegnare una segnalazione a gruppi + label_diff: diff + text_git_repository_note: Il repository è bare e locale (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Ordinamento + description_project_scope: Search scope + description_filter: Filtro + description_user_mail_notification: Impostazioni notifica via mail + description_date_from: Inserisci la data d'inizio + description_message_content: Contenuto del messaggio + description_available_columns: Colonne disponibili + description_date_range_interval: Scegli l'intervallo selezionando la data di inizio e di fine + description_issue_category_reassign: Scegli la categoria della segnalazione + description_search: Campo di ricerca + description_notes: Note + description_date_range_list: Scegli l'intervallo dalla lista + description_choose_project: Progetti + description_date_to: Inserisci la data di fine + description_query_sort_criteria_attribute: Attributo di ordinamento + description_wiki_subpages_reassign: Scegli la nuova pagina padre + description_selected_columns: Colonne selezionate + label_parent_revision: Padre + label_child_revision: Figlio + error_scm_annotate_big_text_file: La nota non può essere salvata, supera la dimensiona massima del campo di testo. + setting_default_issue_start_date_to_creation_date: Usa la data corrente come data d'inizio per le nuove segnalazioni + button_edit_section: Modifica questa sezione + setting_repositories_encodings: Codifica degli allegati e dei repository + description_all_columns: Tutte le colonne + button_export: Esporta + label_export_options: "%{export_format} opzioni per l'export" + error_attachment_too_big: Questo file non può essere caricato in quanto la sua dimensione supera la massima consentita (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/ja.yml --- a/config/locales/ja.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/ja.yml Mon Feb 27 13:53:18 2012 +0000 @@ -322,7 +322,7 @@ field_time_zone: タイムゾーン field_searchable: 検索条件に設定可能とする field_default_value: デフォルト値 - field_comments_sorting: コメントを表示 + field_comments_sorting: コメントの表示順 field_parent_title: 親ページ field_editable: 編集可能 field_watcher: ウォッチャー @@ -349,8 +349,8 @@ setting_default_language: 既定の言語 setting_login_required: 認証が必要 setting_self_registration: ユーザは自分で登録できる - setting_attachment_max_size: 添付ファイルの最大サイズ - setting_issues_export_limit: 出力するチケット数の上限 + setting_attachment_max_size: 添付ファイルサイズの上限 + setting_issues_export_limit: エクスポートするチケット数の上限 setting_mail_from: 送信元メールアドレス setting_bcc_recipients: ブラインドカーボンコピーで受信(bcc) setting_plain_text_mail: プレインテキストのみ(HTMLなし) @@ -369,14 +369,14 @@ setting_time_format: 時刻の形式 setting_cross_project_issue_relations: 異なるプロジェクトのチケット間で関係の設定を許可 setting_issue_list_default_columns: チケットの一覧で表示する項目 - setting_repositories_encodings: リポジトリのエンコーディング + setting_repositories_encodings: 添付ファイルとリポジトリのエンコーディング setting_emails_header: メールのヘッダ setting_emails_footer: メールのフッタ setting_protocol: プロトコル setting_per_page_options: ページ毎の表示件数 setting_user_format: ユーザ名の表示書式 setting_activity_days_default: プロジェクトの活動ページに表示される日数 - setting_display_subprojects_issues: デフォルトでサブプロジェクトのチケットをメインプロジェクトに表示する + setting_display_subprojects_issues: サブプロジェクトのチケットをメインプロジェクトに表示する setting_enabled_scm: 使用するバージョン管理システム setting_mail_handler_body_delimiters: "メール本文から一致する行以降を切り取る" setting_mail_handler_api_enabled: 受信メール用のWebサービスを有効にする @@ -385,7 +385,7 @@ setting_gravatar_enabled: Gravatarのアイコンを使用する setting_gravatar_default: デフォルトのGravatarアイコン setting_diff_max_lines_displayed: 差分の表示行数の上限 - setting_file_max_size_displayed: テキストファイルのインライン表示行数の上限 + setting_file_max_size_displayed: 画面表示するテキストファイルサイズの上限 setting_repository_log_display_limit: ファイルのリビジョン表示数の上限 setting_openid: OpenIDによるログインと登録 setting_password_min_length: パスワードの最低必要文字数 @@ -439,7 +439,7 @@ permission_rename_wiki_pages: Wikiページ名の変更 permission_delete_wiki_pages: Wikiページの削除 permission_view_wiki_pages: Wikiの閲覧 - permission_export_wiki_pages: Wikiページを他の形式に出力 + permission_export_wiki_pages: Wikiページを他の形式にエクスポート permission_view_wiki_edits: Wiki履歴の閲覧 permission_edit_wiki_pages: Wikiページの編集 permission_delete_wiki_pages_attachments: 添付ファイルの削除 @@ -584,7 +584,7 @@ label_version_plural: バージョン label_confirmation: 確認 label_close_versions: 完了したバージョンを終了にする - label_export_to: '他の形式に出力:' + label_export_to: '他の形式にエクスポート:' label_read: 読む... label_public_projects: 公開プロジェクト label_open_issues: 未完了 @@ -681,7 +681,7 @@ label_latest_revision_plural: 最新リビジョン label_view_revisions: リビジョンを見る label_view_all_revisions: すべてのリビジョンを見る - label_max_size: 最大サイズ + label_max_size: サイズの上限 label_sort_highest: 一番上へ label_sort_higher: 上へ label_sort_lower: 下へ @@ -714,6 +714,7 @@ label_statistics: 統計 label_commits_per_month: 月別のコミット label_commits_per_author: 起票者別のコミット + label_diff: 差分 label_view_diff: 差分を見る label_diff_inline: インライン label_diff_side_by_side: 横に並べる @@ -835,6 +836,8 @@ label_principal_search: "ユーザまたはグループの検索:" label_user_search: "ユーザの検索:" label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する + label_parent_revision: 親 + label_child_revision: 子 button_login: ログイン button_submit: 変更 @@ -876,17 +879,17 @@ button_change_password: パスワード変更 button_copy: コピー button_copy_and_follow: コピー後表示 - button_annotate: 注釈 + button_annotate: アノテート button_update: 更新 button_configure: 設定 button_quote: 引用 button_duplicate: 複製 button_show: 表示 - + status_active: 有効 status_registered: 登録 status_locked: ロック - + version_status_open: 進行中 version_status_locked: ロック中 version_status_closed: 終了 @@ -955,8 +958,8 @@ text_zoom_out: 縮小 text_warn_on_leaving_unsaved: このページから移動すると、保存されていないデータが失われます。 text_scm_path_encoding_note: "デフォルト: UTF-8" - text_git_repository_note: "Bare、かつ、ローカルリポジトリ (例: /gitrepo, c:\gitrepo)" - text_mercurial_repository_note: "ローカルリポジトリ (例: /hgrepo, c:\hgrepo)" + text_mercurial_repository_note: "ローカルリポジトリ (例: /hgrepo, c:\\hgrepo)" + text_git_repository_note: "Bare、かつ、ローカルリポジトリ (例: /gitrepo, c:\\gitrepo)" text_scm_command: コマンド text_scm_command_version: バージョン text_scm_config: バージョン管理システムのコマンドをconfig/configuration.ymlで設定できます。設定後、Redmineを再起動してください。 @@ -983,7 +986,7 @@ default_priority_immediate: 今すぐ default_activity_design: 設計作業 default_activity_development: 開発作業 - + enumeration_issue_priorities: チケットの優先度 enumeration_doc_categories: 文書カテゴリ enumeration_activities: 作業分類 (時間トラッキング) @@ -1006,4 +1009,31 @@ field_is_private: プライベート permission_set_issues_private: チケットをプライベートに設定 label_issues_visibility_public: プライベートチケット以外 - text_issues_destroy_descendants_confirmation: %{count}個の子チケットも削除されます。 + text_issues_destroy_descendants_confirmation: "%{count}個の子チケットも削除されます。" + notice_issue_successful_create: チケット %{id} が作成されました。 + label_between: 次の範囲内 + setting_issue_group_assignment: グループへのチケット割り当てを許可 + description_query_sort_criteria_direction: 順序 + description_project_scope: 検索範囲 + description_filter: Filter + description_user_mail_notification: メール通知の設定 + description_date_from: 開始日 + description_message_content: 内容 + description_available_columns: 利用できる項目 + description_date_range_interval: 日付で指定 + description_issue_category_reassign: 新しいカテゴリを選択してください + description_search: 検索キーワード + description_notes: 注記 + description_date_range_list: 一覧から選択 + description_choose_project: プロジェクト + description_date_to: 終了日 + description_query_sort_criteria_attribute: 項目 + description_wiki_subpages_reassign: 新しい親ページを選択してください + description_selected_columns: 選択された項目 + error_scm_annotate_big_text_file: テキストファイルサイズの上限を超えているためアノテートできません。 + setting_default_issue_start_date_to_creation_date: 現在の日付を新しいチケットの開始日とする + button_edit_section: このセクションを編集 + description_all_columns: すべての項目 + button_export: エクスポート + label_export_options: "%{export_format} エクスポート設定" + error_attachment_too_big: このファイルはアップロードできません。添付ファイルサイズの上限(%{max_size})を超えています。 diff -r 487d96eac004 -r 5e80956cc792 config/locales/ko.yml --- a/config/locales/ko.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/ko.yml Mon Feb 27 13:53:18 2012 +0000 @@ -2,7 +2,8 @@ # by Kihyun Yoon(ddumbugie@gmail.com),http://plenum.textcube.com/ # by John Hwang (jhwang@tavon.org),http://github.com/tavon # by Yonghwan SO(please insert your email), last update at 2009-09-11 -# last update at 2010-09-06 by Kihyun Yoon +# by Ki Won Kim(xyz37@naver.com, http://xyz37.blog.me, https://x10.mine.nu/redmine), last update at 2012-02-01 +# last update at 2012-02-02 by Ki Won Kim ko: direction: ltr date: @@ -176,7 +177,7 @@ greater_than_start_date: "는 시작날짜보다 커야 합니다" not_same_project: "는 같은 프로젝트에 속해 있지 않습니다" circular_dependency: "이 관계는 순환 의존관계를 만들 수 있습니다" - cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + cant_link_an_issue_with_a_descendant: "일감은 그것의 하위 일감과 연결할 수 없습니다." actionview_instancetag_blank_option: 선택하세요 @@ -287,7 +288,7 @@ field_admin: 관리자 field_last_login_on: 마지막 로그인 field_language: 언어 - field_effective_date: 일자 + field_effective_date: 날짜 field_password: 비밀번호 field_new_password: 새 비밀번호 field_password_confirmation: 비밀번호 확인 @@ -357,14 +358,13 @@ setting_time_format: 시간 형식 setting_cross_project_issue_relations: 다른 프로젝트의 일감과 연결하는 것을 허용 setting_issue_list_default_columns: 일감 목록에 표시할 항목 - setting_repositories_encodings: 저장소 인코딩 setting_emails_footer: 메일 꼬리 setting_protocol: 프로토콜 setting_per_page_options: 목록에서, 한 페이지에 표시할 행 setting_user_format: 사용자 표시 형식 setting_activity_days_default: 프로젝트 작업내역에 표시할 기간 setting_display_subprojects_issues: 하위 프로젝트의 일감을 함께 표시 - setting_enabled_scm: 지원할 SCM + setting_enabled_scm: "지원할 SCM(Source Control Management)" setting_mail_handler_api_enabled: 수신 메일에 WS를 허용 setting_mail_handler_api_key: API 키 setting_sequential_project_identifiers: 프로젝트 식별자를 순차적으로 생성 @@ -688,10 +688,10 @@ label_blocked_by: "다음 일감에게 막혀 있음:" label_precedes: "다음에 진행할 일감:" label_follows: "다음 일감을 우선 진행:" - label_end_to_start: end to start - label_end_to_end: end to end - label_start_to_start: start to start - label_start_to_end: start to end + label_end_to_start: "끝에서 시작" + label_end_to_end: "끝에서 끝" + label_start_to_start: "시작에서 시작" + label_start_to_end: "시작에서 끝" label_stay_logged_in: 로그인 유지 label_disabled: 비활성화 label_show_completed_versions: 완료된 버전 보기 @@ -989,43 +989,74 @@ setting_commit_logtime_activity_id: 기록된 시간에 적용할 작업분류 text_time_logged_by_changeset: "변경묶음 %{value}에서 적용되었습니다." setting_commit_logtime_enabled: 커밋 시점에 작업 시간 기록 활성화 - notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) - setting_gantt_items_limit: Maximum number of items displayed on the gantt chart - field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text - text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. - label_my_queries: My custom queries - text_journal_changed_no_detail: "%{label} updated" - label_news_comment_added: Comment added to a news - button_expand_all: Expand all - button_collapse_all: Collapse all - label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee - label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author - label_bulk_edit_selected_time_entries: Bulk edit selected time entries - text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + notice_gantt_chart_truncated: "표시할 수 있는 최대 항목수(%{max})를 초과하여 차트가 잘렸습니다." + setting_gantt_items_limit: "Gantt 차트에 표시되는 최대 항목수" + field_warn_on_leaving_unsaved: "저장하지 않은 페이지를 빠져나갈 때 나에게 알림" + text_warn_on_leaving_unsaved: "현재 페이지는 저장되지 않은 문자가 있습니다. 이 페이지를 빠져나가면 내용을 잃을것입니다." + label_my_queries: "내 검색 양식" + text_journal_changed_no_detail: "%{label}이 변경되었습니다." + label_news_comment_added: "뉴스에 설명이 추가되었습니다." + button_expand_all: "모두 확장" + button_collapse_all: "모두 축소" + label_additional_workflow_transitions_for_assignee: "사용자가 작업자일 때 허용되는 추가 상태" + label_additional_workflow_transitions_for_author: "사용자가 저자일 때 허용되는 추가 상태" + label_bulk_edit_selected_time_entries: "선택된 소요 시간 대량 편집" + text_time_entries_destroy_confirmation: "선택한 소요 시간 항목을 삭제하시겠습니까?" label_role_anonymous: Anonymous label_role_non_member: Non member - label_issue_note_added: Note added - label_issue_status_updated: Status updated - label_issue_priority_updated: Priority updated - label_issues_visibility_own: Issues created by or assigned to the user - field_issues_visibility: Issues visibility - label_issues_visibility_all: All issues - permission_set_own_issues_private: Set own issues public or private - field_is_private: Private - permission_set_issues_private: Set issues public or private - label_issues_visibility_public: All non private issues - text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). - field_commit_logs_encoding: 제출(commit) 기록 인코딩 - field_scm_path_encoding: Path encoding - text_scm_path_encoding_note: "Default: UTF-8" - field_path_to_repository: Path to repository - field_root_directory: Root directory - field_cvs_module: Module - field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) - text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) - text_scm_command: Command - text_scm_command_version: Version - label_git_report_last_commit: Report last commit for files and directories - text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. - text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + label_issue_note_added: "덧글이 추가되었습니다." + label_issue_status_updated: "상태가 변경되었습니다." + label_issue_priority_updated: "우선 순위가 변경되었습니다." + label_issues_visibility_own: "일감을 생성하거나 할당된 사용자" + field_issues_visibility: "일감 보임" + label_issues_visibility_all: "모든 일감" + permission_set_own_issues_private: "자신의 일감을 공개나 비공개로 설정" + field_is_private: "비공개" + permission_set_issues_private: "일감을 공개나 비공개로 설정" + label_issues_visibility_public: "모든 비공개 일감" + text_issues_destroy_descendants_confirmation: "%{count} 개의 하위 일감을 삭제할 것입니다." + field_commit_logs_encoding: "제출(commit) 기록 인코딩" + field_scm_path_encoding: "경로 인코딩" + text_scm_path_encoding_note: "기본: UTF-8" + field_path_to_repository: "저장소 경로" + field_root_directory: "루트 경로" + field_cvs_module: "모듈" + field_cvsroot: "CVS 루트" + text_mercurial_repository_note: "로컬 저장소 (예: /hgrepo, c:\hgrepo)" + text_scm_command: "명령" + text_scm_command_version: "버전" + label_git_report_last_commit: "파일이나 폴더의 마지막 제출(commit)을 보고" + text_scm_config: "SCM 명령을 config/configuration.yml에서 수정할 수 있습니다. 수정후에는 재시작하십시오." + text_scm_command_not_available: "SCM 명령을 사용할 수 없습니다. 관리 페이지의 설정을 검사하십시오." + notice_issue_successful_create: "%{id} 일감이 생성되었습니다." + label_between: "사이" + setting_issue_group_assignment: "그룹에 일감 할당 허용" + label_diff: "비교(diff)" + text_git_repository_note: "저장소는 노출된 로컬입니다. (예: /gitrepo, c:\gitrepo)" + description_query_sort_criteria_direction: "정렬 방향" + description_project_scope: "검색 범위" + description_filter: "검색 조건" + description_user_mail_notification: "메일 알림 설정" + description_date_from: "시작 날짜 입력" + description_message_content: "메세지 내용" + description_available_columns: "가능한 컬럼" + description_date_range_interval: 시작과 끝 날짜로 범위를 선택하십시오." + description_issue_category_reassign: "일감 범주를 선택하십시오." + description_search: "검색항목" + description_notes: "덧글" + description_date_range_list: "목록에서 범위를 선택 하십시오." + description_choose_project: "프로젝트" + description_date_to: "종료 날짜 입력" + description_query_sort_criteria_attribute: "정렬 속성" + description_wiki_subpages_reassign: "새로운 상위 페이지를 선택하십시오." + description_selected_columns: "선택된 컬럼" + label_parent_revision: "상위" + label_child_revision: "하위" + error_scm_annotate_big_text_file: "최대 텍스트 파일 크기를 초과 하면 항목은 이력화 될 수 없습니다." + setting_default_issue_start_date_to_creation_date: "새로운 일감의 시작 날짜로 오늘 날짜 사용" + button_edit_section: "이 부분 수정" + setting_repositories_encodings: "첨부파일이나 저장소 인코딩" + description_all_columns: "모든 컬럼" + button_export: "내보내기" + label_export_options: "내보내기 옵션: %{export_format}" + error_attachment_too_big: "이 파일은 제한된 크기(%{max_size})를 초과하였기 때문에 업로드 할 수 없습니다." diff -r 487d96eac004 -r 5e80956cc792 config/locales/lt.yml --- a/config/locales/lt.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/lt.yml Mon Feb 27 13:53:18 2012 +0000 @@ -370,7 +370,6 @@ setting_time_format: Laiko formatas setting_cross_project_issue_relations: Leisti tarprojektinius darbų ryšius setting_issue_list_default_columns: Numatytosios skiltys darbų sąraše - setting_repositories_encodings: Saugyklos koduotė setting_emails_footer: elektroninio pašto puslapinė poraštė setting_protocol: Protokolas setting_per_page_options: Įrašų puslapyje nustatimas @@ -1030,10 +1029,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/lv.yml --- a/config/locales/lv.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/lv.yml Mon Feb 27 13:53:18 2012 +0000 @@ -311,7 +311,6 @@ setting_time_format: Laika formāts setting_cross_project_issue_relations: "Atļaut starp-projektu uzdevumu relācijas" setting_issue_list_default_columns: Noklusēti rādītās kolonnas uzdevumu sarakstā - setting_repositories_encodings: Repozitoriju kodējumi setting_emails_footer: "E-pastu kājene" setting_protocol: Protokols setting_per_page_options: Objekti vienā lapā @@ -965,10 +964,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/mk.yml --- a/config/locales/mk.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/mk.yml Mon Feb 27 13:53:18 2012 +0000 @@ -326,7 +326,6 @@ setting_time_format: Формат на време setting_cross_project_issue_relations: Дозволи релации на задачи меѓу проекти setting_issue_list_default_columns: Default columns displayed on the issue list - setting_repositories_encodings: Repositories encodings setting_emails_footer: Emails footer setting_protocol: Протокол setting_per_page_options: Objects per page options @@ -970,10 +969,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/mn.yml --- a/config/locales/mn.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/mn.yml Mon Feb 27 13:53:18 2012 +0000 @@ -315,7 +315,6 @@ setting_time_format: Цагийн формат setting_cross_project_issue_relations: Төсөл хооронд асуудал хамааруулахыг зөвшөөрөх setting_issue_list_default_columns: Асуудлуудыг харуулах стандарт баганууд - setting_repositories_encodings: Репозиторийн энкодинг setting_emails_footer: Имэйлүүдийн хөл хэсэг setting_protocol: Протокол setting_per_page_options: Нэг хуудсанд байх обьектуудын тохиргоо @@ -971,10 +970,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/nl.yml --- a/config/locales/nl.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/nl.yml Mon Feb 27 13:53:18 2012 +0000 @@ -123,7 +123,7 @@ greater_than_start_date: "moet na de startdatum liggen" not_same_project: "hoort niet bij hetzelfde project" circular_dependency: "Deze relatie zou een circulaire afhankelijkheid tot gevolg hebben" - cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + cant_link_an_issue_with_a_descendant: "Een issue kan niet gelinked worden met een subtask" actionview_instancetag_blank_option: Selecteer @@ -704,7 +704,7 @@ setting_bcc_recipients: Blind carbon copy ontvangers (bcc) setting_commit_fix_keywords: Gefixeerde trefwoorden setting_commit_ref_keywords: Refererende trefwoorden - setting_cross_project_issue_relations: Sta crossproject issuerelaties toe + setting_cross_project_issue_relations: Sta cross-project issuerelaties toe setting_date_format: Datumformaat setting_default_language: Standaard taal setting_default_projects_public: Nieuwe projecten zijn standaard publiek @@ -724,7 +724,6 @@ setting_per_page_options: Aantal objecten per pagina (opties) setting_plain_text_mail: platte tekst (geen HTML) setting_protocol: Protocol - setting_repositories_encodings: Repositories coderingen setting_self_registration: Zelfregistratie toegestaan setting_sequential_project_identifiers: Genereer sequentiële projectidentiteiten setting_sys_api_enabled: Gebruik WS voor repository beheer @@ -909,8 +908,8 @@ label_user_mail_option_only_my_events: Alleen voor dingen die ik volg of bij betrokken ben label_user_mail_option_only_assigned: Alleen voor dingen die aan mij zijn toegewezen label_user_mail_option_none: Bij geen enkele gebeurtenis - field_member_of_group: Assignee's group - field_assigned_to_role: Assignee's role + field_member_of_group: Groep van toegewezene + field_assigned_to_role: Rol van toegewezene notice_not_authorized_archived_project: Het project dat u wilt bezoeken is gearchiveerd. label_principal_search: "Zoek naar gebruiker of groep:" label_user_search: "Zoek naar gebruiker:" @@ -926,10 +925,10 @@ label_my_queries: Mijn aangepaste zoekopdrachten text_journal_changed_no_detail: "%{label} updated" label_news_comment_added: Commentaar toegevoegd aan een nieuwsitem - button_expand_all: Expand all - button_collapse_all: Collapse all - label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee - label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + button_expand_all: Klap uit + button_collapse_all: Klap in + label_additional_workflow_transitions_for_assignee: Aanvullende veranderingen toegestaan wanneer de gebruiker de toegewezene is + label_additional_workflow_transitions_for_author: Aanvullende veranderingen toegestaan wanneer de gebruiker de auteur is label_bulk_edit_selected_time_entries: Bulk edit selected time entries text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? label_role_anonymous: Anonymous @@ -947,15 +946,46 @@ text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). field_commit_logs_encoding: Encodering van commit berichten field_scm_path_encoding: Path encoding - text_scm_path_encoding_note: "Default: UTF-8" + text_scm_path_encoding_note: "Standaard: UTF-8" field_path_to_repository: Path to repository field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/no.yml --- a/config/locales/no.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/no.yml Mon Feb 27 13:53:18 2012 +0000 @@ -114,11 +114,11 @@ greater_than_start_date: "må være større enn startdato" not_same_project: "hører ikke til samme prosjekt" circular_dependency: "Denne relasjonen ville lagd en sirkulær avhengighet" - cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + cant_link_an_issue_with_a_descendant: "En sak kan ikke kobles mot en av sine undersaker" - + actionview_instancetag_blank_option: Vennligst velg - + general_text_No: 'Nei' general_text_Yes: 'Ja' general_text_no: 'nei' @@ -129,7 +129,7 @@ general_csv_encoding: ISO-8859-1 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: Kontoen er oppdatert. notice_account_invalid_creditentials: Feil brukernavn eller passord notice_account_password_updated: Passordet er oppdatert. @@ -153,13 +153,13 @@ notice_no_issue_selected: "Ingen sak valgt! Vennligst merk sakene du vil endre." notice_account_pending: "Din konto ble opprettet og avventer nå administrativ godkjenning." notice_default_data_loaded: Standardkonfigurasjonen lastet inn. - + error_can_t_load_default_data: "Standardkonfigurasjonen kunne ikke lastes inn: %{value}" error_scm_not_found: "Elementet og/eller revisjonen eksisterer ikke i depoet." error_scm_command_failed: "En feil oppstod under tilkobling til depoet: %{value}" error_scm_annotate: "Elementet eksisterer ikke, eller kan ikke noteres." error_issue_not_found_in_project: 'Saken eksisterer ikke, eller hører ikke til dette prosjektet' - + mail_subject_lost_password: "Ditt %{value} passord" mail_body_lost_password: 'Klikk følgende lenke for å endre ditt passord:' mail_subject_register: "%{value} kontoaktivering" @@ -170,10 +170,10 @@ mail_body_account_activation_request: "En ny bruker (%{value}) er registrert, og avventer din godkjenning:" mail_subject_reminder: "%{count} sak(er) har frist de kommende %{days} dagene" mail_body_reminder: "%{count} sak(er) som er tildelt deg har frist de kommende %{days} dager:" - + gui_validation_error: 1 feil gui_validation_error_plural: "%{count} feil" - + field_name: Navn field_description: Beskrivelse field_summary: Oppsummering @@ -212,7 +212,7 @@ field_role: Rolle field_homepage: Hjemmeside field_is_public: Offentlig - field_parent: Underprosjekt til + field_parent: Underprosjekt av field_is_in_roadmap: Vises i veikart field_login: Brukernavn field_mail_notification: E-post-varsling @@ -236,8 +236,8 @@ field_onthefly: On-the-fly brukeropprettelse field_start_date: Start field_done_ratio: "% Ferdig" - field_auth_source: Autentifikasjonsmodus - field_hide_mail: Skjul min e-post-adresse + field_auth_source: Autentiseringskilde + field_hide_mail: Skjul min epost-adresse field_comments: Kommentarer field_url: URL field_start_page: Startside @@ -247,7 +247,7 @@ field_spent_on: Dato field_identifier: Identifikasjon field_is_filter: Brukes som filter - field_issue_to: Relatert saker + field_issue_to: Relaterte saker field_delay: Forsinkelse field_assignable: Saker kan tildeles denne rollen field_redirect_existing_links: Viderekoble eksisterende lenker @@ -257,7 +257,7 @@ field_searchable: Søkbar field_default_value: Standardverdi field_comments_sorting: Vis kommentarer - + setting_app_title: Applikasjonstittel setting_app_subtitle: Applikasjonens undertittel setting_welcome_text: Velkomsttekst @@ -266,40 +266,39 @@ setting_self_registration: Selvregistrering setting_attachment_max_size: Maks. størrelse vedlegg setting_issues_export_limit: Eksportgrense for saker - setting_mail_from: Avsenders e-post + setting_mail_from: Avsenders epost setting_bcc_recipients: Blindkopi (bcc) til mottakere setting_host_name: Vertsnavn setting_text_formatting: Tekstformattering setting_wiki_compression: Komprimering av Wiki-historikk setting_feeds_limit: Innholdsgrense for Feed setting_default_projects_public: Nye prosjekter er offentlige som standard - setting_autofetch_changesets: Autohenting av innsendinger + setting_autofetch_changesets: Autohenting av endringssett setting_sys_api_enabled: Aktiver webservice for depot-administrasjon setting_commit_ref_keywords: Nøkkelord for referanse setting_commit_fix_keywords: Nøkkelord for retting setting_autologin: Autoinnlogging setting_date_format: Datoformat setting_time_format: Tidsformat - setting_cross_project_issue_relations: Tillat saksrelasjoner mellom prosjekter + setting_cross_project_issue_relations: Tillat saksrelasjoner på kryss av prosjekter setting_issue_list_default_columns: Standardkolonner vist i sakslisten - setting_repositories_encodings: Depot-tegnsett - setting_emails_footer: E-post-signatur + setting_emails_footer: Epost-signatur setting_protocol: Protokoll setting_per_page_options: Alternativer, objekter pr. side setting_user_format: Visningsformat, brukere setting_activity_days_default: Dager vist på prosjektaktivitet setting_display_subprojects_issues: Vis saker fra underprosjekter på hovedprosjekt som standard setting_enabled_scm: Aktiviserte SCM - - project_module_issue_tracking: Sakssporing - project_module_time_tracking: Tidssporing + + project_module_issue_tracking: Sakshåndtering + project_module_time_tracking: Tidsregistrering project_module_news: Nyheter project_module_documents: Dokumenter project_module_files: Filer project_module_wiki: Wiki project_module_repository: Depot project_module_boards: Forumer - + label_user: Bruker label_user_plural: Brukere label_user_new: Ny bruker @@ -326,7 +325,7 @@ label_role: Rolle label_role_plural: Roller label_role_new: Ny rolle - label_role_and_permissions: Roller og tillatelser + label_role_and_permissions: Roller og rettigheter label_member: Medlem label_member_new: Nytt medlem label_member_plural: Medlemmer @@ -343,7 +342,7 @@ label_custom_field: Eget felt label_custom_field_plural: Egne felt label_custom_field_new: Nytt eget felt - label_enumerations: Kodelister + label_enumerations: Listeverdier label_enumeration_new: Ny verdi label_information: Informasjon label_information_plural: Informasjon @@ -360,7 +359,7 @@ label_logout: Logg ut label_help: Hjelp label_reported_issues: Rapporterte saker - label_assigned_to_me_issues: Saker tildelt meg + label_assigned_to_me_issues: Saker tildelt meg label_last_login: Sist innlogget label_registered_on: Registrert label_activity: Aktivitet @@ -368,10 +367,10 @@ label_new: Ny label_logged_as: Innlogget som label_environment: Miljø - label_authentication: Autentifikasjon - label_auth_source: Autentifikasjonsmodus - label_auth_source_new: Ny autentifikasjonmodus - label_auth_source_plural: Autentifikasjonsmoduser + label_authentication: Autentisering + label_auth_source: Autentiseringskilde + label_auth_source_new: Ny autentiseringskilde + label_auth_source_plural: Autentiseringskilder label_subproject_plural: Underprosjekter label_and_its_subprojects: "%{value} og dets underprosjekter" label_min_max_length: Min.-maks. lengde @@ -424,13 +423,13 @@ one: 1 åpen other: "%{count} åpne" label_x_closed_issues_abbr: - zero: 0 lukka - one: 1 lukka - other: "%{count} lukka" + zero: 0 lukket + one: 1 lukket + other: "%{count} lukket" label_total: Totalt - label_permissions: Godkjenninger + label_permissions: Rettigheter label_current_status: Nåværende status - label_new_statuses_allowed: Tillatte nye statuser + label_new_statuses_allowed: Tillate nye statuser label_all: alle label_none: ingen label_nobody: ingen @@ -438,7 +437,7 @@ label_previous: Forrige label_used_by: Brukt av label_details: Detaljer - label_add_note: Legg til notis + label_add_note: Legg til notat label_per_page: Pr. side label_calendar: Kalender label_months_from: måneder fra @@ -450,7 +449,7 @@ label_comment: Kommentar label_comment_plural: Kommentarer label_x_comments: - zero: no kommentarer + zero: ingen kommentarer one: 1 kommentar other: "%{count} kommentarer" label_comment_add: Legg til kommentar @@ -519,11 +518,11 @@ label_preview: Forhåndsvis label_feed_plural: Feeder label_changes_details: Detaljer om alle endringer - label_issue_tracking: Sakssporing + label_issue_tracking: Sakshåndtering label_spent_time: Brukt tid label_f_hour: "%{value} time" label_f_hour_plural: "%{value} timer" - label_time_tracking: Tidssporing + label_time_tracking: Tidsregistrering label_change_plural: Endringer label_statistics: Statistikk label_commits_per_month: Innsendinger pr. måned @@ -533,7 +532,7 @@ label_diff_side_by_side: side ved side label_options: Alternativer label_copy_workflow_from: Kopier arbeidsflyt fra - label_permissions_report: Godkjenningsrapport + label_permissions_report: Rettighetsrapport label_watched_issues: Overvåkede saker label_related_issues: Relaterte saker label_applied_status: Gitt status @@ -572,7 +571,7 @@ label_date_to: Til label_language_based: Basert på brukerens språk label_sort_by: "Sorter etter %{value}" - label_send_test_email: Send en e-post-test + label_send_test_email: Send en epost-test label_feeds_access_key_created_on: "RSS tilgangsnøkkel opprettet for %{value} siden" label_module_plural: Moduler label_added_time_by: "Lagt til av %{author} for %{age} siden" @@ -599,7 +598,7 @@ label_more: Mer label_scm: SCM label_plugins: Tillegg - label_ldap_authentication: LDAP-autentifikasjon + label_ldap_authentication: LDAP-autentisering label_downloads_abbr: Nedl. label_optional_description: Valgfri beskrivelse label_add_another_file: Legg til en fil til @@ -607,7 +606,7 @@ label_chronological_order: I kronologisk rekkefølge label_reverse_chronological_order: I omvendt kronologisk rekkefølge label_planning: Planlegging - + button_login: Logg inn button_submit: Send button_save: Lagre @@ -645,13 +644,13 @@ button_annotate: Notér button_update: Oppdater button_configure: Konfigurer - + status_active: aktiv status_registered: registrert status_locked: låst - + text_select_mail_notifications: Velg hendelser som skal varsles med e-post. - text_regexp_info: eg. ^[A-Z0-9]+$ + text_regexp_info: f.eks. ^[A-Z0-9]+$ text_min_max_length_info: 0 betyr ingen begrensning text_project_destroy_confirmation: Er du sikker på at du vil slette dette prosjekter og alle relatert data ? text_subprojects_destroy_warning: "Underprojekt(ene): %{value} vil også bli slettet." @@ -668,8 +667,8 @@ text_unallowed_characters: Ugyldige tegn text_comma_separated: Flere verdier tillat (kommaseparert). text_issues_ref_in_commit_messages: Referering og retting av saker i innsendingsmelding - text_issue_added: "Issue %{id} has been reported by %{author}." - text_issue_updated: "Issue %{id} has been updated by %{author}." + text_issue_added: "Sak %{id} er innrapportert av %{author}." + text_issue_updated: "Sak %{id} er oppdatert av %{author}." text_wiki_destroy_confirmation: Er du sikker på at du vil slette denne wikien og alt innholdet ? text_issue_category_destroy_question: "Noen saker (%{count}) er lagt til i denne kategorien. Hva vil du gjøre ?" text_issue_category_destroy_assignments: Fjern bruk av kategorier @@ -688,7 +687,7 @@ text_assign_time_entries_to_project: Overfør førte timer til prosjektet text_reassign_time_entries: 'Overfør førte timer til denne saken:' text_user_wrote: "%{value} skrev:" - + default_role_manager: Leder default_role_developer: Utvikler default_role_reporter: Rapportør @@ -696,12 +695,12 @@ default_tracker_feature: Funksjon default_tracker_support: Support default_issue_status_new: Ny - default_issue_status_in_progress: In Progress + default_issue_status_in_progress: Pågår default_issue_status_resolved: Avklart default_issue_status_feedback: Tilbakemelding default_issue_status_closed: Lukket default_issue_status_rejected: Avvist - default_doc_category_user: Bruker-dokumentasjon + default_doc_category_user: Brukerdokumentasjon default_doc_category_tech: Teknisk dokumentasjon default_priority_low: Lav default_priority_normal: Normal @@ -710,18 +709,18 @@ default_priority_immediate: Omgående default_activity_design: Design default_activity_development: Utvikling - + enumeration_issue_priorities: Sakssprioriteringer - enumeration_doc_categories: Dokument-kategorier - enumeration_activities: Aktiviteter (tidssporing) + enumeration_doc_categories: Dokumentkategorier + enumeration_activities: Aktiviteter (tidsregistrering) text_enumeration_category_reassign_to: 'Endre dem til denne verdien:' text_enumeration_destroy_question: "%{count} objekter er endret til denne verdien." label_incoming_emails: Innkommende e-post label_generate_key: Generer en nøkkel - setting_mail_handler_api_enabled: Skru på WS for innkommende e-post + setting_mail_handler_api_enabled: Skru på WS for innkommende epost setting_mail_handler_api_key: API-nøkkel - text_email_delivery_not_configured: "Levering av e-post er ikke satt opp, og varsler er skrudd av.\nStill inn din SMTP-tjener i config/configuration.yml og start programmet på nytt for å skru det på." - field_parent_title: Foreldreside + text_email_delivery_not_configured: "Levering av epost er ikke satt opp, og varsler er skrudd av.\nStill inn din SMTP-tjener i config/configuration.yml og start programmet på nytt for å skru det på." + field_parent_title: Overordnet side label_issue_watchers: Overvåkere button_quote: Sitat setting_sequential_project_identifiers: Generer sekvensielle prosjekt-IDer @@ -732,39 +731,39 @@ permission_view_files: Vise filer permission_edit_issues: Redigere saker permission_edit_own_time_entries: Redigere egne timelister - permission_manage_public_queries: Behandle delte søk + permission_manage_public_queries: Administrere delte søk permission_add_issues: Legge inn saker permission_log_time: Loggføre timer permission_view_changesets: Vise endringssett permission_view_time_entries: Vise brukte timer - permission_manage_versions: Behandle versjoner - permission_manage_wiki: Behandle wiki - permission_manage_categories: Behandle kategorier for saker + permission_manage_versions: Administrere versjoner + permission_manage_wiki: Administrere wiki + permission_manage_categories: Administrere kategorier for saker permission_protect_wiki_pages: Beskytte wiki-sider permission_comment_news: Kommentere nyheter permission_delete_messages: Slette meldinger - permission_select_project_modules: Velge prosjekt-moduler - permission_manage_documents: Behandle dokumenter + permission_select_project_modules: Velge prosjektmoduler + permission_manage_documents: Administrere dokumenter permission_edit_wiki_pages: Redigere wiki-sider permission_add_issue_watchers: Legge til overvåkere permission_view_gantt: Vise gantt-diagram permission_move_issues: Flytte saker - permission_manage_issue_relations: Behandle saksrelasjoner + permission_manage_issue_relations: Administrere saksrelasjoner permission_delete_wiki_pages: Slette wiki-sider - permission_manage_boards: Behandle forum + permission_manage_boards: Administrere forum permission_delete_wiki_pages_attachments: Slette vedlegg permission_view_wiki_edits: Vise wiki-historie permission_add_messages: Sende meldinger permission_view_messages: Vise meldinger - permission_manage_files: Behandle filer + permission_manage_files: Administrere filer permission_edit_issue_notes: Redigere notater - permission_manage_news: Behandle nyheter + permission_manage_news: Administrere nyheter permission_view_calendar: Vise kalender - permission_manage_members: Behandle medlemmer + permission_manage_members: Administrere medlemmer permission_edit_messages: Redigere meldinger permission_delete_issues: Slette saker permission_view_issue_watchers: Vise liste over overvåkere - permission_manage_repository: Behandle depot + permission_manage_repository: Administrere depot permission_commit_access: Tilgang til innsending permission_browse_repository: Bla gjennom depot permission_view_documents: Vise dokumenter @@ -778,189 +777,223 @@ setting_gravatar_enabled: Bruk Gravatar-brukerikoner label_example: Eksempel text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." - permission_edit_own_messages: Edit own messages - permission_delete_own_messages: Delete own messages - label_user_activity: "%{value}'s activity" - label_updated_time_by: "Updated by %{author} %{age} ago" + permission_edit_own_messages: Rediger egne meldinger + permission_delete_own_messages: Slett egne meldinger + label_user_activity: "%{value}s aktivitet" + label_updated_time_by: "Oppdatert av %{author} for %{age} siden" text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' setting_diff_max_lines_displayed: Max number of diff lines displayed text_plugin_assets_writable: Plugin assets directory writable - warning_attachments_not_saved: "%{count} file(s) could not be saved." - button_create_and_continue: Create and continue - text_custom_field_possible_values_info: 'One line for each value' - label_display: Display - field_editable: Editable - setting_repository_log_display_limit: Maximum number of revisions displayed on file log + warning_attachments_not_saved: "%{count} fil(er) kunne ikke lagres." + button_create_and_continue: Opprett og fortsett + text_custom_field_possible_values_info: 'En linje for hver verdi' + label_display: Visning + field_editable: Redigerbar + setting_repository_log_display_limit: Maks antall revisjoner vist i fil-loggen setting_file_max_size_displayed: Max size of text files displayed inline - field_watcher: Watcher - setting_openid: Allow OpenID login and registration + field_watcher: Overvåker + setting_openid: Tillat OpenID innlogging og registrering field_identity_url: OpenID URL - label_login_with_open_id_option: or login with OpenID - field_content: Content - label_descending: Descending - label_sort: Sort - label_ascending: Ascending - label_date_from_to: From %{start} to %{end} + label_login_with_open_id_option: eller logg inn med OpenID + field_content: Innhold + label_descending: Synkende + label_sort: Sorter + label_ascending: Stigende + label_date_from_to: Fra %{start} til %{end} label_greater_or_equal: ">=" label_less_or_equal: <= - text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? - text_wiki_page_reassign_children: Reassign child pages to this parent page - text_wiki_page_nullify_children: Keep child pages as root pages - text_wiki_page_destroy_children: Delete child pages and all their descendants - setting_password_min_length: Minimum password length - field_group_by: Group results by - mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" - label_wiki_content_added: Wiki page added - mail_subject_wiki_content_added: "'%{id}' wiki page has been added" - mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. - label_wiki_content_updated: Wiki page updated - mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. - permission_add_project: Create project - setting_new_project_user_role_id: Role given to a non-admin user who creates a project - label_view_all_revisions: View all revisions + text_wiki_page_destroy_question: Denne siden har %{descendants} underside(r). Hva ønsker du å gjøre? + text_wiki_page_reassign_children: Tilknytt undersider til denne overordnede siden + text_wiki_page_nullify_children: Behold undersider som rotsider + text_wiki_page_destroy_children: Slett undersider og alle deres underliggende sider + setting_password_min_length: Minimum passordlengde + field_group_by: Grupper resultater etter + mail_subject_wiki_content_updated: "Wiki-side '%{id}' er oppdatert" + label_wiki_content_added: Wiki-side opprettet + mail_subject_wiki_content_added: "Wiki-side '%{id}' er opprettet" + mail_body_wiki_content_added: Wiki-siden '%{id}' ble opprettet av %{author}. + label_wiki_content_updated: Wiki-side oppdatert + mail_body_wiki_content_updated: Wiki-siden '%{id}' ble oppdatert av %{author}. + permission_add_project: Opprett prosjekt + setting_new_project_user_role_id: Rolle gitt en ikke-administratorbruker som oppretter et prosjekt + label_view_all_revisions: Se alle revisjoner label_tag: Tag - label_branch: Branch - error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. - error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). - text_journal_changed: "%{label} changed from %{old} to %{new}" - text_journal_set_to: "%{label} set to %{value}" - text_journal_deleted: "%{label} deleted (%{old})" - label_group_plural: Groups - label_group: Group - label_group_new: New group - label_time_entry_plural: Spent time - text_journal_added: "%{label} %{value} added" - field_active: Active - enumeration_system_activity: System Activity - permission_delete_issue_watchers: Delete watchers - version_status_closed: closed - version_status_locked: locked - version_status_open: open - error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened - label_user_anonymous: Anonymous - button_move_and_follow: Move and follow - setting_default_projects_modules: Default enabled modules for new projects - setting_gravatar_default: Default Gravatar image - field_sharing: Sharing - label_version_sharing_hierarchy: With project hierarchy - label_version_sharing_system: With all projects - label_version_sharing_descendants: With subprojects - label_version_sharing_tree: With project tree - label_version_sharing_none: Not shared - error_can_not_archive_project: This project can not be archived - button_duplicate: Duplicate - button_copy_and_follow: Copy and follow - label_copy_source: Source - setting_issue_done_ratio: Calculate the issue done ratio with - setting_issue_done_ratio_issue_status: Use the issue status - error_issue_done_ratios_not_updated: Issue done ratios not updated. - error_workflow_copy_target: Please select target tracker(s) and role(s) - setting_issue_done_ratio_issue_field: Use the issue field - label_copy_same_as_target: Same as target - label_copy_target: Target - notice_issue_done_ratios_updated: Issue done ratios updated. - error_workflow_copy_source: Please select a source tracker or role - label_update_issue_done_ratios: Update issue done ratios - setting_start_of_week: Start calendars on - permission_view_issues: View Issues - label_display_used_statuses_only: Only display statuses that are used by this tracker + label_branch: Gren + error_no_tracker_in_project: Ingen sakstyper er tilknyttet dette prosjektet. Vennligst kontroller prosjektets innstillinger. + error_no_default_issue_status: Ingen standard saksstatus er angitt. Vennligst kontroller konfigurasjonen (Gå til "Administrasjon -> Saksstatuser"). + text_journal_changed: "%{label} endret fra %{old} til %{new}" + text_journal_set_to: "%{label} satt til %{value}" + text_journal_deleted: "%{label} slettet (%{old})" + label_group_plural: Grupper + label_group: Gruppe + label_group_new: Ny gruppe + label_time_entry_plural: Brukt tid + text_journal_added: "%{label} %{value} lagt til" + field_active: Aktiv + enumeration_system_activity: Systemaktivitet + permission_delete_issue_watchers: Slett overvåkere + version_status_closed: stengt + version_status_locked: låst + version_status_open: åpen + error_can_not_reopen_issue_on_closed_version: En sak tilknyttet en stengt versjon kan ikke gjenåpnes. + label_user_anonymous: Anonym + button_move_and_follow: Flytt og følg etter + setting_default_projects_modules: Standard aktiverte moduler for nye prosjekter + setting_gravatar_default: Standard Gravatar-bilde + field_sharing: Deling + label_version_sharing_hierarchy: Med prosjekt-hierarki + label_version_sharing_system: Med alle prosjekter + label_version_sharing_descendants: Med underprosjekter + label_version_sharing_tree: Med prosjekt-tre + label_version_sharing_none: Ikke delt + error_can_not_archive_project: Dette prosjektet kan ikke arkiveres + button_duplicate: Duplikat + button_copy_and_follow: Kopier og følg etter + label_copy_source: Kilde + setting_issue_done_ratio: Kalkuler ferdigstillingsprosent ut i fra + setting_issue_done_ratio_issue_status: Bruk saksstatuser + error_issue_done_ratios_not_updated: Ferdigstillingsprosent oppdateres ikke. + error_workflow_copy_target: Vennligst velg sakstype(r) og rolle(r) + setting_issue_done_ratio_issue_field: Bruk felt fra saker + label_copy_same_as_target: Samme som mål + label_copy_target: Mål + notice_issue_done_ratios_updated: Ferdigstillingsprosent oppdatert. + error_workflow_copy_source: Vennligst velg en kilde-sakstype eller rolle. + label_update_issue_done_ratios: Oppdatert ferdigstillingsprosent + setting_start_of_week: Start kalender på + permission_view_issues: Se på saker + label_display_used_statuses_only: Vis kun statuser som brukes av denne sakstypen label_revision_id: Revision %{value} - label_api_access_key: API access key - label_api_access_key_created_on: API access key created %{value} ago - label_feeds_access_key: RSS access key - notice_api_access_key_reseted: Your API access key was reset. - setting_rest_api_enabled: Enable REST web service - label_missing_api_access_key: Missing an API access key - label_missing_feeds_access_key: Missing a RSS access key - button_show: Show - text_line_separated: Multiple values allowed (one line for each value). - setting_mail_handler_body_delimiters: Truncate emails after one of these lines - permission_add_subprojects: Create subprojects - label_subproject_new: New subproject + label_api_access_key: API tilgangsnøkkel + label_api_access_key_created_on: API tilgangsnøkkel opprettet for %{value} siden + label_feeds_access_key: RSS tilgangsnøkkel + notice_api_access_key_reseted: Din API tilgangsnøkkel ble resatt. + setting_rest_api_enabled: Aktiver REST webservice + label_missing_api_access_key: Mangler en API tilgangsnøkkel + label_missing_feeds_access_key: Mangler en RSS tilgangsnøkkel + button_show: Vis + text_line_separated: Flere verdier er tillatt (en linje per verdi). + setting_mail_handler_body_delimiters: Avkort epost etter en av disse linjene + permission_add_subprojects: Opprett underprosjekt + label_subproject_new: Nytt underprosjekt text_own_membership_delete_confirmation: |- - You are about to remove some or all of your permissions and may no longer be able to edit this project after that. - Are you sure you want to continue? - label_close_versions: Close completed versions - label_board_sticky: Sticky - label_board_locked: Locked - permission_export_wiki_pages: Export wiki pages - setting_cache_formatted_text: Cache formatted text - permission_manage_project_activities: Manage project activities - error_unable_delete_issue_status: Unable to delete issue status - label_profile: Profile - permission_manage_subtasks: Manage subtasks - field_parent_issue: Parent task - label_subtask_plural: Subtasks - label_project_copy_notifications: Send email notifications during the project copy - error_can_not_delete_custom_field: Unable to delete custom field - error_unable_to_connect: Unable to connect (%{value}) - error_can_not_remove_role: This role is in use and can not be deleted. - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + Du er i ferd med å fjerne noen eller alle rettigheter og vil kanskje ikke være i stand til å redigere dette prosjektet etterpå. + Er du sikker på at du vil fortsette? + label_close_versions: Steng fullførte versjoner + label_board_sticky: Fast + label_board_locked: Låst + permission_export_wiki_pages: Eksporter wiki-sider + setting_cache_formatted_text: Mellomlagre formattert tekst + permission_manage_project_activities: Administrere prosjektaktiviteter + error_unable_delete_issue_status: Kan ikke slette saksstatus + label_profile: Profil + permission_manage_subtasks: Administrere undersaker + field_parent_issue: Overordnet sak + label_subtask_plural: Undersaker + label_project_copy_notifications: Send epost-varslinger under prosjektkopiering + error_can_not_delete_custom_field: Kan ikke slette eget felt + error_unable_to_connect: Kunne ikke koble til (%{value}) + error_can_not_remove_role: Denne rollen er i bruk og kan ikke slettes. + error_can_not_delete_tracker: Denne sakstypen inneholder saker og kan ikke slettes. field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): %{errors}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time - field_time_entries: Log time + label_my_page_block: Min side felt + notice_failed_to_save_members: "Feil ved lagring av medlem(mer): %{errors}." + text_zoom_out: Zoom ut + text_zoom_in: Zoom inn + notice_unable_delete_time_entry: Kan ikke slette oppføring fra timeliste. + label_overall_spent_time: All tidsbruk + field_time_entries: Loggfør tid project_module_gantt: Gantt - project_module_calendar: Calendar - button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" - text_are_you_sure_with_children: Delete issue and all child issues? - field_text: Text field - label_user_mail_option_only_owner: Only for things I am the owner of - setting_default_notification_option: Default notification option - label_user_mail_option_only_my_events: Only for things I watch or I'm involved in - label_user_mail_option_only_assigned: Only for things I am assigned to - label_user_mail_option_none: No events - field_member_of_group: Assignee's group - field_assigned_to_role: Assignee's role - notice_not_authorized_archived_project: The project you're trying to access has been archived. - label_principal_search: "Search for user or group:" - label_user_search: "Search for user:" - field_visible: Visible - setting_emails_header: Emails header - setting_commit_logtime_activity_id: Activity for logged time - text_time_logged_by_changeset: Applied in changeset %{value}. - setting_commit_logtime_enabled: Enable time logging - notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) - setting_gantt_items_limit: Maximum number of items displayed on the gantt chart - field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text - text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. - label_my_queries: My custom queries - text_journal_changed_no_detail: "%{label} updated" - label_news_comment_added: Comment added to a news - button_expand_all: Expand all - button_collapse_all: Collapse all - label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee - label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author - label_bulk_edit_selected_time_entries: Bulk edit selected time entries - text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? - label_role_anonymous: Anonymous - label_role_non_member: Non member - label_issue_note_added: Note added - label_issue_status_updated: Status updated - label_issue_priority_updated: Priority updated - label_issues_visibility_own: Issues created by or assigned to the user - field_issues_visibility: Issues visibility - label_issues_visibility_all: All issues - permission_set_own_issues_private: Set own issues public or private - field_is_private: Private - permission_set_issues_private: Set issues public or private - label_issues_visibility_public: All non private issues - text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + project_module_calendar: Kalender + button_edit_associated_wikipage: "Rediger tilhørende Wiki-side: %{page_title}" + text_are_you_sure_with_children: Slett sak og alle undersaker? + field_text: Tekstfelt + label_user_mail_option_only_owner: Kun for ting jeg eier + setting_default_notification_option: Standardvalg for varslinger + label_user_mail_option_only_my_events: Kun for ting jeg overvåker eller er involvert i + label_user_mail_option_only_assigned: Kun for ting jeg er tildelt + label_user_mail_option_none: Ingen hendelser + field_member_of_group: Den tildeltes gruppe + field_assigned_to_role: Den tildeltes rolle + notice_not_authorized_archived_project: Prosjektet du forsøker å åpne er blitt arkivert. + label_principal_search: "Søk etter bruker eller gruppe:" + label_user_search: "Søk etter bruker:" + field_visible: Synlig + setting_emails_header: Eposthode + setting_commit_logtime_activity_id: Aktivitet for logget tid. + text_time_logged_by_changeset: Lagt til i endringssett %{value}. + setting_commit_logtime_enabled: Muliggjør loggføring av tid + notice_gantt_chart_truncated: Diagrammet ble avkortet fordi det overstiger det maksimale antall elementer som kan vises (%{max}) + setting_gantt_items_limit: Maksimalt antall elementer vist på gantt-diagrammet + field_warn_on_leaving_unsaved: Vis meg en advarsel når jeg forlater en side med ikke lagret tekst + text_warn_on_leaving_unsaved: Den gjeldende siden inneholder tekst som ikke er lagret, som vil bli tapt hvis du forlater denne siden. + label_my_queries: Mine egne spørringer + text_journal_changed_no_detail: "%{label} oppdatert" + label_news_comment_added: Kommentar lagt til en nyhet + button_expand_all: Utvid alle + button_collapse_all: Kollaps alle + label_additional_workflow_transitions_for_assignee: Ytterligere overganger tillatt når brukeren er sakens tildelte + label_additional_workflow_transitions_for_author: Ytterligere overganger tillatt når brukeren er den som har opprettet saken + label_bulk_edit_selected_time_entries: Masserediger valgte timeliste-oppføringer + text_time_entries_destroy_confirmation: Er du sikker på du vil slette de(n) valgte timeliste-oppføringen(e)? + label_role_anonymous: Anonym + label_role_non_member: Ikke medlem + label_issue_note_added: Notat lagt til + label_issue_status_updated: Status oppdatert + label_issue_priority_updated: Prioritet oppdatert + label_issues_visibility_own: Saker opprettet av eller tildelt brukeren + field_issues_visibility: Synlighet på saker + label_issues_visibility_all: Alle saker + permission_set_own_issues_private: Gjør egne saker offentlige eller private + field_is_private: Privat + permission_set_issues_private: Gjør saker offentlige eller private + label_issues_visibility_public: Alle ikke-private saker + text_issues_destroy_descendants_confirmation: Dette vil også slette %{count} undersak(er). field_commit_logs_encoding: Tegnkoding for innsendingsmeldinger - field_scm_path_encoding: Path encoding - text_scm_path_encoding_note: "Default: UTF-8" - field_path_to_repository: Path to repository - field_root_directory: Root directory - field_cvs_module: Module + field_scm_path_encoding: Koding av sti + text_scm_path_encoding_note: "Standard: UTF-8" + field_path_to_repository: Sti til depot + field_root_directory: Rotkatalog + field_cvs_module: Modul field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) - text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) - text_scm_command: Command - text_scm_command_version: Version - label_git_report_last_commit: Report last commit for files and directories - text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. - text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + text_mercurial_repository_note: Lokalt depot (f.eks. /hgrepo, c:\hgrepo) + text_scm_command: Kommando + text_scm_command_version: Versjon + label_git_report_last_commit: Rapporter siste innsending for filer og kataloger + text_scm_config: Du kan konfigurere scm kommandoer i config/configuration.yml. Vennligst restart applikasjonen etter å ha redigert filen. + text_scm_command_not_available: Scm kommando er ikke tilgjengelig. Vennligst kontroller innstillingene i administrasjonspanelet. + + text_git_repository_note: Depot er bart og lokalt (f.eks. /gitrepo, c:\gitrepo) + + notice_issue_successful_create: Sak %{id} opprettet. + label_between: mellom + setting_issue_group_assignment: Tillat tildeling av saker til grupper + label_diff: diff + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/pl.yml --- a/config/locales/pl.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/pl.yml Mon Feb 27 13:53:18 2012 +0000 @@ -754,7 +754,6 @@ setting_per_page_options: Opcje ilości obiektów na stronie setting_plain_text_mail: tylko tekst (bez HTML) setting_protocol: Protokoł - setting_repositories_encodings: Kodowanie repozytoriów setting_self_registration: Samodzielna rejestracja użytkowników setting_sequential_project_identifiers: Generuj sekwencyjne identyfikatory projektów setting_sys_api_enabled: Włączenie WS do zarządzania repozytorium @@ -987,10 +986,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/pt-BR.yml --- a/config/locales/pt-BR.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/pt-BR.yml Mon Feb 27 13:53:18 2012 +0000 @@ -316,7 +316,6 @@ setting_time_format: Formato de hora setting_cross_project_issue_relations: Permitir relacionar tarefas entre projetos setting_issue_list_default_columns: Colunas padrão visíveis na lista de tarefas - setting_repositories_encodings: Codificação dos repositórios setting_emails_footer: Rodapé do e-mail setting_protocol: Protocolo setting_per_page_options: Número de itens exibidos por página @@ -962,7 +961,7 @@ setting_commit_logtime_enabled: Habilitar registro de horas notice_gantt_chart_truncated: O gráfico foi cortado por exceder o tamanho máximo de linhas que podem ser exibidas (%{max}) setting_gantt_items_limit: Número máximo de itens exibidos no gráfico gatt - field_warn_on_leaving_unsaved: Alertar-me ao sarir de uma página sem salvar o texto + field_warn_on_leaving_unsaved: Alertar-me ao sair de uma página sem salvar o texto text_warn_on_leaving_unsaved: A página atual contem texto que não foi salvo e será perdido se você sair desta página. label_my_queries: Minhas consultas personalizadas text_journal_changed_no_detail: "%{label} atualizado(a)" @@ -991,10 +990,43 @@ field_root_directory: Diretório raiz field_cvs_module: Módulo field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) - text_mercurial_repository_note: "repositório local (ex.: /hgrepo, c:\hgrepo)" + text_mercurial_repository_note: "Repositório local (ex.: /hgrepo, c:\\hgrepo)" text_scm_command: Comando text_scm_command_version: Versão label_git_report_last_commit: Relatar última alteração para arquivos e diretórios text_scm_config: Você pode configurar seus comandos de versionamento em config/configurations.yml. Por favor reinicie a aplicação após alterá-lo. text_scm_command_not_available: Comando de versionamento não disponível. Por favor verifique as configurações no painel de administração. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Escopo da pesquisa + description_filter: Filtro + description_user_mail_notification: Configuração de notificações por e-mail + description_date_from: Digita a data inicial + description_message_content: Conteúdo da mensagem + description_available_columns: Colunas disponíveis + description_date_range_interval: Escolha um período selecionando a data de início e fim + description_issue_category_reassign: Escolha uma categoria de tarefas + description_search: Searchfield + description_notes: Notas + description_date_range_list: Escolha um período a partira da lista + description_choose_project: Projetos + description_date_to: Digite a data final + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Escolha uma nova página pai + description_selected_columns: Colunas selecionadas + + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Usar data corrente como data inicial para novas tarefas + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/pt.yml --- a/config/locales/pt.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/pt.yml Mon Feb 27 13:53:18 2012 +0000 @@ -6,7 +6,7 @@ array: sentence_connector: "e" skip_last_comma: true - + direction: ltr date: formats: @@ -22,16 +22,16 @@ - :day - :month - :year - + time: - formats: + formats: default: "%A, %d de %B de %Y, %H:%Mh" time: "%H:%M" short: "%d/%m, %H:%M hs" long: "%A, %d de %B de %Y, %H:%Mh" am: '' pm: '' - + datetime: distance_in_words: half_a_minute: "meio minuto" @@ -41,7 +41,7 @@ x_seconds: one: "1 segundo" other: "%{count} segundos" - less_than_x_minutes: + less_than_x_minutes: one: "menos de um minuto" other: "menos de %{count} minutos" x_minutes: @@ -68,7 +68,7 @@ almost_x_years: one: "almost 1 year" other: "almost %{count} years" - + number: format: precision: 3 @@ -136,7 +136,7 @@ ## Translated by: Pedro Araújo actionview_instancetag_blank_option: Seleccione - + general_text_No: 'Não' general_text_Yes: 'Sim' general_text_no: 'não' @@ -147,7 +147,7 @@ general_csv_encoding: ISO-8859-15 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: A conta foi actualizada com sucesso. notice_account_invalid_creditentials: Utilizador ou palavra-chave inválidos. notice_account_password_updated: A palavra-chave foi alterada com sucesso. @@ -172,13 +172,13 @@ notice_account_pending: "A sua conta foi criada e está agora à espera de aprovação do administrador." notice_default_data_loaded: Configuração padrão carregada com sucesso. notice_unable_delete_version: Não foi possível apagar a versão. - + error_can_t_load_default_data: "Não foi possível carregar a configuração padrão: %{value}" error_scm_not_found: "A entrada ou revisão não foi encontrada no repositório." error_scm_command_failed: "Ocorreu um erro ao tentar aceder ao repositório: %{value}" error_scm_annotate: "A entrada não existe ou não pode ser anotada." error_issue_not_found_in_project: 'A tarefa não foi encontrada ou não pertence a este projecto.' - + mail_subject_lost_password: "Palavra-chave de %{value}" mail_body_lost_password: 'Para mudar a sua palavra-chave, clique na ligação abaixo:' mail_subject_register: "Activação de conta de %{value}" @@ -189,10 +189,10 @@ mail_body_account_activation_request: "Um novo utilizador (%{value}) registou-se. A sua conta está à espera de aprovação:" mail_subject_reminder: "%{count} tarefa(s) para entregar nos próximos %{days} dias" mail_body_reminder: "%{count} tarefa(s) que estão atribuídas a si estão agendadas para estarem completas nos próximos %{days} dias:" - + gui_validation_error: 1 erro gui_validation_error_plural: "%{count} erros" - + field_name: Nome field_description: Descrição field_summary: Sumário @@ -223,7 +223,7 @@ field_is_default: Valor por omissão field_tracker: Tipo field_subject: Assunto - field_due_date: Data final + field_due_date: Data fim field_assigned_to: Atribuído a field_priority: Prioridade field_fixed_version: Versão @@ -253,7 +253,7 @@ field_attr_lastname: Atributo último nome field_attr_mail: Atributo e-mail field_onthefly: Criação imediata de utilizadores - field_start_date: Início + field_start_date: Data início field_done_ratio: "% Completo" field_auth_source: Modo de autenticação field_hide_mail: Esconder endereço de e-mail @@ -277,7 +277,7 @@ field_default_value: Valor por omissão field_comments_sorting: Mostrar comentários field_parent_title: Página pai - + setting_app_title: Título da aplicação setting_app_subtitle: Sub-título da aplicação setting_welcome_text: Texto de boas vindas @@ -302,7 +302,6 @@ setting_time_format: Formato do tempo setting_cross_project_issue_relations: Permitir relações entre tarefas de projectos diferentes setting_issue_list_default_columns: Colunas na lista de tarefas por omissão - setting_repositories_encodings: Encodings dos repositórios setting_emails_footer: Rodapé do e-mails setting_protocol: Protocolo setting_per_page_options: Opções de objectos por página @@ -313,7 +312,7 @@ setting_mail_handler_api_enabled: Activar Web Service para e-mails recebidos setting_mail_handler_api_key: Chave da API setting_sequential_project_identifiers: Gerar identificadores de projecto sequênciais - + project_module_issue_tracking: Tarefas project_module_time_tracking: Registo de tempo project_module_news: Notícias @@ -322,7 +321,7 @@ project_module_wiki: Wiki project_module_repository: Repositório project_module_boards: Forum - + label_user: Utilizador label_user_plural: Utilizadores label_user_new: Novo utilizador @@ -635,7 +634,7 @@ label_incoming_emails: E-mails a chegar label_generate_key: Gerar uma chave label_issue_watchers: Observadores - + button_login: Entrar button_submit: Submeter button_save: Guardar @@ -674,11 +673,11 @@ button_update: Actualizar button_configure: Configurar button_quote: Citar - + status_active: activo status_registered: registado status_locked: bloqueado - + text_select_mail_notifications: Seleccionar as acções que originam uma notificação por e-mail. text_regexp_info: ex. ^[A-Z0-9]+$ text_min_max_length_info: 0 siginifica sem restrição @@ -720,7 +719,7 @@ text_enumeration_destroy_question: "%{count} objectos estão atribuídos a este valor." text_enumeration_category_reassign_to: 'Re-atribuí-los para este valor:' text_email_delivery_not_configured: "Entrega por e-mail não está configurada, e as notificação estão desactivadas.\nConfigure o seu servidor de SMTP em config/configuration.yml e reinicie a aplicação para activar estas funcionalidades." - + default_role_manager: Gestor default_role_developer: Programador default_role_reporter: Repórter @@ -742,7 +741,7 @@ default_priority_immediate: Imediata default_activity_design: Planeamento default_activity_development: Desenvolvimento - + enumeration_issue_priorities: Prioridade de tarefas enumeration_doc_categories: Categorias de documentos enumeration_activities: Actividades (Registo de tempo) @@ -869,7 +868,7 @@ button_duplicate: Duplicar button_copy_and_follow: Copiar e seguir label_copy_source: Origem - setting_issue_done_ratio: Calcular a percentagem de progresso da tarefa + setting_issue_done_ratio: Calcular a percentagem de progresso da tarefa setting_issue_done_ratio_issue_status: Através do estado da tarefa error_issue_done_ratios_not_updated: Percentagens de progresso da tarefa não foram actualizadas. error_workflow_copy_target: Seleccione os tipos de tarefas e funções desejadas @@ -975,10 +974,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/ro.yml --- a/config/locales/ro.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/ro.yml Mon Feb 27 13:53:18 2012 +0000 @@ -293,7 +293,6 @@ setting_time_format: Format oră setting_cross_project_issue_relations: Permite legături de tichete între proiecte setting_issue_list_default_columns: Coloane implicite afișate în lista de tichete - setting_repositories_encodings: Codare pentru depozit setting_emails_footer: Subsol email setting_protocol: Protocol setting_per_page_options: Număr de obiecte pe pagină @@ -963,10 +962,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/ru.yml --- a/config/locales/ru.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/ru.yml Mon Feb 27 13:53:18 2012 +0000 @@ -60,7 +60,7 @@ percentage: format: delimiter: "" - + precision: format: delimiter: "" @@ -207,7 +207,7 @@ # Rails 2.2 sentence_connector: "и" skip_last_comma: true - + # Rails 2.3 words_connector: ", " two_words_connector: " и " @@ -242,7 +242,7 @@ button_quote: Цитировать button_rename: Переименовать button_reply: Ответить - button_reset: Перезапустить + button_reset: Сбросить button_rollback: Вернуться к данной версии button_save: Сохранить button_sort: Сортировать @@ -259,7 +259,7 @@ default_activity_design: Проектирование default_activity_development: Разработка default_doc_category_tech: Техническая документация - default_doc_category_user: Документация пользователя + default_doc_category_user: Пользовательская документация default_issue_status_in_progress: В работе default_issue_status_closed: Закрыта default_issue_status_feedback: Обратная связь @@ -273,7 +273,7 @@ default_priority_urgent: Срочный default_role_developer: Разработчик default_role_manager: Менеджер - default_role_reporter: Генератор отчетов + default_role_reporter: Репортёр default_tracker_bug: Ошибка default_tracker_feature: Улучшение default_tracker_support: Поддержка @@ -281,7 +281,7 @@ enumeration_activities: Действия (учет времени) enumeration_doc_categories: Категории документов enumeration_issue_priorities: Приоритеты задач - + error_can_not_remove_role: Эта роль используется и не может быть удалена. error_can_not_delete_custom_field: Невозможно удалить настраиваемое поле error_can_not_delete_tracker: Этот трекер содержит задачи и не может быть удален. @@ -300,26 +300,26 @@ field_assigned_to: Назначена field_attr_firstname: Имя field_attr_lastname: Фамилия - field_attr_login: Атрибут Регистрация + field_attr_login: Атрибут Login field_attr_mail: email field_author: Автор field_auth_source: Режим аутентификации field_base_dn: BaseDN field_category: Категория - field_column_names: Колонки + field_column_names: Столбцы field_comments: Комментарий field_comments_sorting: Отображение комментариев field_content: Content - field_created_on: Создан + field_created_on: Создано field_default_value: Значение по умолчанию field_delay: Отложить field_description: Описание - field_done_ratio: Готовность в % + field_done_ratio: Готовность field_downloads: Загрузки field_due_date: Дата выполнения - field_editable: Редактируемый + field_editable: Редактируемое field_effective_date: Дата - field_estimated_hours: Оцененное время + field_estimated_hours: Оценка времени field_field_format: Формат field_filename: Файл field_filesize: Размер @@ -371,11 +371,11 @@ field_status: Статус field_subject: Тема field_subproject: Подпроект - field_summary: Сводка + field_summary: Краткое описание field_text: Текстовое поле field_time_entries: Затраченное время field_time_zone: Часовой пояс - field_title: Название + field_title: Заголовок field_tracker: Трекер field_type: Тип field_updated_on: Обновлено @@ -391,9 +391,9 @@ general_first_day_of_week: '1' general_lang_name: 'Russian (Русский)' general_pdf_encoding: UTF-8 - general_text_no: 'Нет' + general_text_no: 'нет' general_text_No: 'Нет' - general_text_yes: 'Да' + general_text_yes: 'да' general_text_Yes: 'Да' gui_validation_error: 1 ошибка @@ -401,7 +401,7 @@ gui_validation_error_plural2: "%{count} ошибки" gui_validation_error_plural5: "%{count} ошибок" - label_activity: Активность + label_activity: Действия label_add_another_file: Добавить ещё один файл label_added_time_by: "Добавил(а) %{author} %{age} назад" label_added: добавлено @@ -434,7 +434,7 @@ label_board_plural: Форумы label_boolean: Логический label_browse: Обзор - label_bulk_edit_selected_issues: Редактировать все выбранные вопросы + label_bulk_edit_selected_issues: Редактировать все выбранные задачи label_calendar: Календарь label_calendar_filter: Включая label_calendar_no_assigned: не мои @@ -443,9 +443,9 @@ label_change_status: Изменить статус label_change_view_all: Просмотреть все изменения label_changes_details: Подробности по всем изменениям - label_changeset_plural: Хранилище + label_changeset_plural: Изменения label_chronological_order: В хронологическом порядке - label_closed_issues: закрыт + label_closed_issues: закрыто label_closed_issues_plural: закрыто label_closed_issues_plural2: закрыто label_closed_issues_plural5: закрыто @@ -474,11 +474,11 @@ label_date: Дата label_day_plural: дней(я) label_default: По умолчанию - label_default_columns: Колонки по умолчанию + label_default_columns: Столбцы по умолчанию label_deleted: удалено label_descending: По убыванию label_details: Подробности - label_diff_inline: вставкой + label_diff_inline: в тексте label_diff_side_by_side: рядом label_disabled: отключено label_display: Отображение @@ -497,9 +497,9 @@ label_end_to_end: с конца к концу label_end_to_start: с конца к началу label_enumeration_new: Новое значение - label_enumerations: Справочники + label_enumerations: Списки значений label_environment: Окружение - label_equals: соответствует + label_equals: является label_example: Пример label_export_to: Экспортировать в label_feed_plural: RSS @@ -539,9 +539,9 @@ label_issue_plural: Задачи label_issues_by: "Сортировать по %{value}" label_issue_status_new: Новый статус - label_issue_status_plural: Статусы задачи + label_issue_status_plural: Статусы задач label_issue_status: Статус задачи - label_issue_tracking: Ситуация по задачам + label_issue_tracking: Задачи label_issue_updated: Обновлена задача label_issue_view_all: Просмотреть все задачи label_issue_watchers: Наблюдатели @@ -551,7 +551,7 @@ label_last_login: Последнее подключение label_last_month: последний месяц label_last_n_days: "последние %{count} дней" - label_last_week: последняя неделю + label_last_week: последняя неделя label_latest_revision: Последняя редакция label_latest_revision_plural: Последние редакции label_ldap_authentication: Авторизация с помощью LDAP @@ -559,7 +559,7 @@ label_less_than_ago: менее, чем дней(я) назад label_list: Список label_loading: Загрузка... - label_logged_as: Вошел как + label_logged_as: Вошли как label_login: Войти label_login_with_open_id_option: или войти с помощью OpenID label_logout: Выйти @@ -588,30 +588,30 @@ label_my_page_block: Блок моей страницы label_my_projects: Мои проекты label_new: Новый - label_new_statuses_allowed: Разрешены новые статусы - label_news_added: Новость добавлена + label_new_statuses_allowed: Разрешенные новые статусы + label_news_added: Добавлена новость label_news_latest: Последние новости label_news_new: Добавить новость label_news_plural: Новости label_news_view_all: Посмотреть все новости label_news: Новости - label_next: Следующий + label_next: Следующее label_nobody: никто label_no_change_option: (Нет изменений) label_no_data: Нет данных для отображения label_none: отсутствует label_not_contains: не содержит - label_not_equals: не соответствует - label_open_issues: открыт + label_not_equals: не является + label_open_issues: открыто label_open_issues_plural: открыто label_open_issues_plural2: открыто label_open_issues_plural5: открыто - label_optional_description: Описание (опционально) + label_optional_description: Описание (необязательно) label_options: Опции - label_overall_activity: Сводная активность + label_overall_activity: Сводный отчет действий label_overview: Обзор label_password_lost: Восстановление пароля - label_permissions_report: Отчет о правах доступа + label_permissions_report: Отчет по правам доступа label_permissions: Права доступа label_per_page: На страницу label_personalize_page: Персонализировать данную страницу @@ -620,10 +620,10 @@ label_plugins: Модули label_precedes: следующая label_preferences: Предпочтения - label_preview: Предварительный просмотр - label_previous: Предыдущий + label_preview: Предпросмотр + label_previous: Предыдущее label_profile: Профиль - label_project: проект + label_project: Проект label_project_all: Все проекты label_project_copy_notifications: Отправлять уведомления по электронной почте при копировании проекта label_project_latest: Последние проекты @@ -664,7 +664,7 @@ label_role_and_permissions: Роли и права доступа label_role_new: Новая роль label_role_plural: Роли - label_scm: 'Тип хранилища' + label_scm: Тип хранилища label_search: Поиск label_search_titles_only: Искать только в названиях label_send_information: Отправить пользователю информацию по учетной записи @@ -702,7 +702,7 @@ label_updated_time_by: "Обновлено %{author} %{age} назад" label_used_by: Используется label_user: Пользователь - label_user_activity: "Активность пользователя %{value}" + label_user_activity: "Действия пользователя %{value}" label_user_mail_no_self_notified: "Не извещать об изменениях, которые я сделал сам" label_user_mail_option_all: "О всех событиях во всех моих проектах" label_user_mail_option_selected: "О всех событиях только в выбранном проекте..." @@ -760,8 +760,8 @@ mail_body_account_activation_request: "Зарегистрирован новый пользователь (%{value}). Учетная запись ожидает Вашего утверждения:" mail_body_account_information: Информация о Вашей учетной записи mail_body_account_information_external: "Вы можете использовать Вашу %{value} учетную запись для входа." - mail_body_lost_password: 'Для изменения пароля зайдите по следующей ссылке:' - mail_body_register: 'Для активации учетной записи зайдите по следующей ссылке:' + mail_body_lost_password: 'Для изменения пароля пройдите по следующей ссылке:' + mail_body_register: 'Для активации учетной записи пройдите по следующей ссылке:' mail_body_reminder: "%{count} назначенных на Вас задач на следующие %{days} дней:" mail_subject_account_activation_request: "Запрос на активацию пользователя в системе %{value}" mail_subject_lost_password: "Ваш %{value} пароль" @@ -772,8 +772,8 @@ notice_account_invalid_creditentials: Неправильное имя пользователя или пароль notice_account_lost_email_sent: Вам отправлено письмо с инструкциями по выбору нового пароля. notice_account_password_updated: Пароль успешно обновлен. - notice_account_pending: "Ваша учетная запись уже создана и ожидает подтверждения администратора." - notice_account_register_done: Учетная запись успешно создана. Для активации Вашей учетной записи зайдите по ссылке, которая выслана Вам по электронной почте. + notice_account_pending: "Ваша учетная запись создана и ожидает подтверждения администратора." + notice_account_register_done: Учетная запись успешно создана. Для активации Вашей учетной записи пройдите по ссылке, которая выслана Вам по электронной почте. notice_account_unknown_email: Неизвестный пользователь. notice_account_updated: Учетная запись успешно обновлена. notice_account_wrong_password: Неверный пароль @@ -783,15 +783,15 @@ notice_email_sent: "Отправлено письмо %{value}" notice_failed_to_save_issues: "Не удалось сохранить %{count} пункт(ов) из %{total} выбранных: %{ids}." notice_failed_to_save_members: "Не удалось сохранить участника(ов): %{errors}." - notice_feeds_access_key_reseted: Ваш ключ доступа RSS был перезапущен. + notice_feeds_access_key_reseted: Ваш ключ доступа RSS был сброшен. notice_file_not_found: Страница, на которую Вы пытаетесь зайти, не существует или удалена. notice_locking_conflict: Информация обновлена другим пользователем. notice_no_issue_selected: "Не выбрано ни одной задачи! Пожалуйста, отметьте задачи, которые Вы хотите отредактировать." notice_not_authorized: У Вас нет прав для посещения данной страницы. notice_successful_connection: Подключение успешно установлено. - notice_successful_create: Создание успешно завершено. - notice_successful_delete: Удаление успешно завершено. - notice_successful_update: Обновление успешно завершено. + notice_successful_create: Создание успешно. + notice_successful_delete: Удаление успешно. + notice_successful_update: Обновление успешно. notice_unable_delete_version: Невозможно удалить версию. permission_add_issues: Добавление задач @@ -800,7 +800,7 @@ permission_add_messages: Отправка сообщений permission_browse_repository: Просмотр хранилища permission_comment_news: Комментирование новостей - permission_commit_access: Разрешение фиксации + permission_commit_access: Изменение файлов в хранилище permission_delete_issues: Удаление задач permission_delete_messages: Удаление сообщений permission_delete_own_messages: Удаление собственных сообщений @@ -819,7 +819,7 @@ permission_log_time: Учет затраченного времени permission_view_changesets: Просмотр изменений хранилища permission_view_time_entries: Просмотр затраченного времени - permission_manage_project_activities: Управление активностью проекта + permission_manage_project_activities: Управление типами действий для проекта permission_manage_boards: Управление форумами permission_manage_categories: Управление категориями задач permission_manage_documents: Управление документами @@ -857,13 +857,13 @@ project_module_gantt: Диаграмма Ганта project_module_calendar: Календарь - setting_activity_days_default: Количество дней, отображаемых в Активности + setting_activity_days_default: Количество дней, отображаемых в Действиях setting_app_subtitle: Подзаголовок приложения setting_app_title: Название приложения setting_attachment_max_size: Максимальный размер вложения setting_autofetch_changesets: Автоматически следить за изменениями хранилища setting_autologin: Автоматический вход - setting_bcc_recipients: Использовать скрытые списки (BCC) + setting_bcc_recipients: Использовать скрытые копии (BCC) setting_cache_formatted_text: Кешировать форматированный текст setting_commit_fix_keywords: Назначение ключевых слов setting_commit_ref_keywords: Ключевые слова для поиска @@ -880,19 +880,18 @@ setting_file_max_size_displayed: Максимальный размер текстового файла для отображения setting_gravatar_enabled: Использовать аватар пользователя из Gravatar setting_host_name: Имя компьютера - setting_issue_list_default_columns: Колонки, отображаемые в списке задач по умолчанию + setting_issue_list_default_columns: Столбцы, отображаемые в списке задач по умолчанию setting_issues_export_limit: Ограничение по экспортируемым задачам setting_login_required: Необходима аутентификация - setting_mail_from: email адрес для передачи информации + setting_mail_from: Исходящий email адрес setting_mail_handler_api_enabled: Включить веб-сервис для входящих сообщений setting_mail_handler_api_key: API ключ setting_openid: Разрешить OpenID для входа и регистрации - setting_per_page_options: Количество строк на страницу + setting_per_page_options: Количество записей на страницу setting_plain_text_mail: Только простой текст (без HTML) setting_protocol: Протокол - setting_repositories_encodings: Кодировки хранилища setting_repository_log_display_limit: Максимальное количество редакций, отображаемых в журнале изменений - setting_self_registration: Возможна саморегистрация + setting_self_registration: Саморегистрация setting_sequential_project_identifiers: Генерировать последовательные идентификаторы проектов setting_sys_api_enabled: Включить веб-сервис для управления хранилищем setting_text_formatting: Форматирование текста @@ -904,23 +903,23 @@ status_active: активен status_locked: заблокирован status_registered: зарегистрирован - + text_are_you_sure_with_children: Удалить задачу и все ее подзадачи? - text_are_you_sure: Подтвердите + text_are_you_sure: Вы уверены? text_assign_time_entries_to_project: Прикрепить зарегистрированное время к проекту text_caracters_maximum: "Максимум %{count} символов(а)." text_caracters_minimum: "Должно быть не менее %{count} символов." text_comma_separated: Допустимы несколько значений (через запятую). text_custom_field_possible_values_info: 'По одному значению в каждой строке' text_default_administrator_account_changed: Учетная запись администратора по умолчанию изменена - text_destroy_time_entries_question: Вы собираетесь удалить %{hours} часа(ов), прикрепленных за этой задачей. + text_destroy_time_entries_question: "На эту задачу зарегистрировано %{hours} часа(ов) затраченного времени. Что Вы хотите предпринять?" text_destroy_time_entries: Удалить зарегистрированное время text_diff_truncated: '... Этот diff ограничен, так как превышает максимальный отображаемый размер.' text_email_delivery_not_configured: "Параметры работы с почтовым сервером не настроены и функция уведомления по email не активна.\nНастроить параметры для Вашего SMTP-сервера Вы можете в файле config/configuration.yml. Для применения изменений перезапустите приложение." text_enumeration_category_reassign_to: 'Назначить им следующее значение:' text_enumeration_destroy_question: "%{count} объект(а,ов) связаны с этим значением." text_file_repository_writable: Хранилище с доступом на запись - text_issue_added: "По задаче %{id} был создан отчет (%{author})." + text_issue_added: "Создана новая задача %{id} (%{author})." text_issue_category_destroy_assignments: Удалить назначения категории text_issue_category_destroy_question: "Несколько задач (%{count}) назначено в данную категорию. Что Вы хотите предпринять?" text_issue_category_reassign_to: Переназначить задачи для данной категории @@ -932,31 +931,31 @@ text_journal_set_to: "Параметр %{label} изменился на %{value}" text_length_between: "Длина между %{min} и %{max} символов." text_load_default_configuration: Загрузить конфигурацию по умолчанию - text_min_max_length_info: 0 означает отсутствие запретов + text_min_max_length_info: 0 означает отсутствие ограничений text_no_configuration_data: "Роли, трекеры, статусы задач и оперативный план не были сконфигурированы.\nНастоятельно рекомендуется загрузить конфигурацию по-умолчанию. Вы сможете её изменить потом." - text_plugin_assets_writable: Каталог для плагинов доступен по записи + text_plugin_assets_writable: Каталог модулей доступен для записи text_project_destroy_confirmation: Вы настаиваете на удалении данного проекта и всей относящейся к нему информации? text_project_identifier_info: 'Допустимы строчные буквы (a-z), цифры и дефис.
    Сохраненный идентификатор не может быть изменен.' text_reassign_time_entries: 'Перенести зарегистрированное время на следующую задачу:' - text_regexp_info: напр. ^[A-Z0-9]+$ + text_regexp_info: "например: ^[A-Z0-9]+$" text_repository_usernames_mapping: "Выберите или обновите пользователя Redmine, связанного с найденными именами в журнале хранилища.\nПользователи с одинаковыми именами или email в Redmine и хранилище связываются автоматически." text_rmagick_available: Доступно использование RMagick (опционально) - text_select_mail_notifications: Выберите действия, на которые будет отсылаться уведомление на электронную почту. + text_select_mail_notifications: Выберите действия, при которых будет отсылаться уведомление на электронную почту. text_select_project_modules: 'Выберите модули, которые будут использованы в проекте:' text_status_changed_by_changeset: "Реализовано в %{value} редакции." text_subprojects_destroy_warning: "Подпроекты: %{value} также будут удалены." text_tip_issue_begin_day: дата начала задачи - text_tip_issue_begin_end_day: начало задачи и окончание ее в этот день + text_tip_issue_begin_end_day: начало задачи и окончание ее в этот же день text_tip_issue_end_day: дата завершения задачи text_tracker_no_workflow: Для этого трекера последовательность действий не определена text_unallowed_characters: Запрещенные символы - text_user_mail_option: "Для невыбранных проектов, Вы будете получать уведомления только о том что просматриваете или в чем участвуете (например, вопросы, автором которых Вы являетесь или которые Вам назначены)." + text_user_mail_option: "Для невыбранных проектов, Вы будете получать уведомления только о том, что просматриваете или в чем участвуете (например, задачи, автором которых Вы являетесь, или которые Вам назначены)." text_user_wrote: "%{value} писал(а):" text_wiki_destroy_confirmation: Вы уверены, что хотите удалить данную Wiki и все ее содержимое? text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний warning_attachments_not_saved: "%{count} файл(ов) невозможно сохранить." - text_wiki_page_destroy_question: Эта страница имеет %{descendants} дочерних страниц и их потомков. Что вы хотите сделать? + text_wiki_page_destroy_question: Эта страница имеет %{descendants} дочерних страниц и их потомков. Что вы хотите предпринять? text_wiki_page_reassign_children: Переопределить дочерние страницы на текущую страницу text_wiki_page_nullify_children: Сделать дочерние страницы главными страницами text_wiki_page_destroy_children: Удалить дочерние страницы и всех их потомков @@ -974,14 +973,14 @@ label_tag: Метка label_branch: Ветвь error_no_tracker_in_project: С этим проектом не ассоциирован ни один трекер. Проверьте настройки проекта. - error_no_default_issue_status: Не определен статус задача по умолчанию. Проверьте настройки (см. "Администрирование -> Статусы задачи"). + error_no_default_issue_status: Не определен статус задач по умолчанию. Проверьте настройки (см. "Администрирование -> Статусы задач"). label_group_plural: Группы label_group: Группа label_group_new: Новая группа label_time_entry_plural: Затраченное время text_journal_added: "%{label} %{value} добавлен" field_active: Активно - enumeration_system_activity: Системная активность + enumeration_system_activity: Системное permission_delete_issue_watchers: Удаление наблюдателей version_status_closed: закрыт version_status_locked: заблокирован @@ -997,7 +996,7 @@ label_version_sharing_descendants: С подпроектами label_version_sharing_tree: С деревом проектов label_version_sharing_none: Без совместного использования - error_can_not_archive_project: Этот проект не может быть архивирован + error_can_not_archive_project: Этот проект не может быть заархивирован button_duplicate: Дублировать button_copy_and_follow: Копировать и продолжить label_copy_source: Источник @@ -1008,7 +1007,7 @@ setting_issue_done_ratio_issue_field: Готовность задачи label_copy_same_as_target: То же, что и у цели label_copy_target: Цель - notice_issue_done_ratios_updated: Параметр готовность задач обновлен. + notice_issue_done_ratios_updated: Параметр «готовность» обновлен. error_workflow_copy_source: Выберите исходный трекер или роль label_update_issue_done_ratios: Обновить готовность задач setting_start_of_week: День начала недели @@ -1044,15 +1043,15 @@ notice_not_authorized_archived_project: Запрашиваемый проект был архивирован. label_principal_search: "Найти пользователя или группу:" label_user_search: "Найти пользователя:" - field_visible: Видимый + field_visible: Видимое setting_emails_header: Заголовок письма - setting_commit_logtime_activity_id: Активность для учета времени + setting_commit_logtime_activity_id: Действие для учета времени text_time_logged_by_changeset: Учтено в редакции %{value}. setting_commit_logtime_enabled: Включить учет времени notice_gantt_chart_truncated: Диаграмма будет усечена, поскольку превышено максимальное кол-во элементов, которые могут отображаться (%{max}) setting_gantt_items_limit: Максимальное кол-во элементов отображаемых на диаграмме Ганта - field_warn_on_leaving_unsaved: Предупреждать при закратии страницы с несохраненным текстом + field_warn_on_leaving_unsaved: Предупреждать при закрытии страницы с несохраненным текстом text_warn_on_leaving_unsaved: Текущая страница содержит несохраненный текст, который будет потерян, если вы покинете эту страницу. label_my_queries: Мои сохраненные запросы text_journal_changed_no_detail: "%{label} обновлено" @@ -1061,8 +1060,8 @@ button_collapse_all: Свернуть все label_additional_workflow_transitions_for_assignee: Дополнительные переходы, когда пользователь является исполнителем label_additional_workflow_transitions_for_author: Дополнительные переходы, когда пользователь является автором - label_bulk_edit_selected_time_entries: Массовое изменение выбранных записей затраченного времени времени - text_time_entries_destroy_confirmation: Вы уверены что хотите удалить выбраные записи затраченного времени? + label_bulk_edit_selected_time_entries: Массовое изменение выбранных записей затраченного времени + text_time_entries_destroy_confirmation: Вы уверены что хотите удалить выбранные записи затраченного времени? label_role_anonymous: Аноним label_role_non_member: Не участник label_issue_note_added: Примечание добавлено @@ -1071,22 +1070,53 @@ label_issues_visibility_own: Задачи созданные или назначенные пользователю field_issues_visibility: Видимость задач label_issues_visibility_all: Все задачи - permission_set_own_issues_private: Устанавливать видимость (общая/частная) для собственных задач + permission_set_own_issues_private: Установление видимости (общая/частная) для собственных задач field_is_private: Частная - permission_set_issues_private: Устанавливать видимость (общая/частная) для задач + permission_set_issues_private: Установление видимости (общая/частная) для задач label_issues_visibility_public: Только общие задачи - text_issues_destroy_descendants_confirmation: Так же будет удалено %{count} задачи. + text_issues_destroy_descendants_confirmation: Так же будет удалено %{count} задач(и). field_commit_logs_encoding: Кодировка комментариев в хранилище field_scm_path_encoding: Кодировка пути text_scm_path_encoding_note: "По умолчанию: UTF-8" - field_path_to_repository: Путь к репозиторию - field_root_directory: Корневую директорию + field_path_to_repository: Путь к хранилищу + field_root_directory: Корневая директория field_cvs_module: Модуль field_cvsroot: CVSROOT - text_git_repository_note: Локальный и bare репозиторий (например, /gitrepo, c:\gitrepo) - text_mercurial_repository_note: Локальный репозиторий (например, /hgrepo, c:\hgrepo) - text_scm_command: Command - text_scm_command_version: Version - label_git_report_last_commit: Report last commit for files and directories - text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. - text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + text_mercurial_repository_note: Локальное хранилище (например, /hgrepo, c:\hgrepo) + text_scm_command: Команда + text_scm_command_version: Версия + label_git_report_last_commit: Указывать последнее изменения для файлов и директорий + text_scm_config: Вы можете настроить команды SCM в файле config/configuration.yml. Пожалуйста, перезапустите приложение после редактирования этого файла. + text_scm_command_not_available: Команда системы контроля версий недоступна. Пожалуйста, проверьте настройки в административной панели. + notice_issue_successful_create: Задача %{id} создана. + label_between: между + setting_issue_group_assignment: Разрешить назначение задач группам пользователей + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/sk.yml --- a/config/locales/sk.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/sk.yml Mon Feb 27 13:53:18 2012 +0000 @@ -823,7 +823,6 @@ permission_add_project: Vytvorenie projektu label_wiki_content_updated: Wiki stránka aktualizovaná mail_body_wiki_content_updated: Wiki stránka '%{id}' bola aktualizovaná užívateľom %{author}. - setting_repositories_encodings: Kódovanie repozitára setting_new_project_user_role_id: Rola dána non-admin užívateľovi, ktorý vytvorí projekt label_view_all_revisions: Zobraziť všetkz revízie label_tag: Tag @@ -965,10 +964,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/sl.yml --- a/config/locales/sl.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/sl.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,5 @@ sl: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) direction: ltr date: formats: @@ -8,13 +9,13 @@ default: "%Y-%m-%d" short: "%b %d" long: "%B %d, %Y" - - day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] - abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] - + + day_names: [Nedelja, Ponedeljek, Torek, Sreda, Četrtek, Petek, Sobota] + abbr_day_names: [Ned, Pon, To, Sr, Čet, Pet, Sob] + # Don't forget the nil at the beginning; there's no such thing as a 0th month - month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] - abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + month_names: [~, Januar, Februar, Marec, April, Maj, Junij, Julij, Avgust, September, Oktober, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Aug, Sep, Okt, Nov, Dec] # Used in date_select and datime_select. order: - :year @@ -29,76 +30,76 @@ long: "%B %d, %Y %H:%M" am: "am" pm: "pm" - + datetime: distance_in_words: - half_a_minute: "half a minute" + half_a_minute: "pol minute" less_than_x_seconds: - one: "less than 1 second" - other: "less than %{count} seconds" + one: "manj kot 1. sekundo" + other: "manj kot %{count} sekund" x_seconds: - one: "1 second" - other: "%{count} seconds" + one: "1. sekunda" + other: "%{count} sekund" less_than_x_minutes: - one: "less than a minute" - other: "less than %{count} minutes" + one: "manj kot minuto" + other: "manj kot %{count} minut" x_minutes: - one: "1 minute" - other: "%{count} minutes" + one: "1 minuta" + other: "%{count} minut" about_x_hours: - one: "about 1 hour" - other: "about %{count} hours" + one: "okrog 1. ure" + other: "okrog %{count} ur" x_days: - one: "1 day" - other: "%{count} days" + one: "1 dan" + other: "%{count} dni" about_x_months: - one: "about 1 month" - other: "about %{count} months" + one: "okrog 1. mesec" + other: "okrog %{count} mesecev" x_months: - one: "1 month" - other: "%{count} months" + one: "1 mesec" + other: "%{count} mesecev" about_x_years: - one: "about 1 year" - other: "about %{count} years" + one: "okrog 1. leto" + other: "okrog %{count} let" over_x_years: - one: "over 1 year" - other: "over %{count} years" + one: "več kot 1. leto" + other: "več kot %{count} let" almost_x_years: - one: "almost 1 year" - other: "almost %{count} years" + one: "skoraj 1. leto" + other: "skoraj %{count} let" number: format: separator: "," delimiter: "." precision: 3 - human: - format: + human: + format: precision: 1 delimiter: "" - storage_units: + storage_units: format: "%n %u" - units: + units: kb: KB tb: TB gb: GB - byte: + byte: one: Byte other: Bytes mb: MB - + # Used in array.to_sentence. support: array: - sentence_connector: "and" + sentence_connector: "in" skip_last_comma: false - + activerecord: errors: template: header: - one: "1 error prohibited this %{model} from being saved" - other: "%{count} errors prohibited this %{model} from being saved" + one: "1. napaka je preprečila temu %{model} da bi se shranil" + other: "%{count} napak je preprečilo temu %{model} da bi se shranil" messages: inclusion: "ni vključen na seznamu" exclusion: "je rezerviran" @@ -113,20 +114,20 @@ taken: "je že zaseden" not_a_number: "ni število" not_a_date: "ni veljaven datum" - greater_than: "must be greater than %{count}" - greater_than_or_equal_to: "must be greater than or equal to %{count}" - equal_to: "must be equal to %{count}" - less_than: "must be less than %{count}" - less_than_or_equal_to: "must be less than or equal to %{count}" - odd: "must be odd" - even: "must be even" - greater_than_start_date: "mora biti kasnejši kot začeten datum" + greater_than: "mora biti večji kot %{count}" + greater_than_or_equal_to: "mora biti večji ali enak kot %{count}" + equal_to: "mora biti enak kot %{count}" + less_than: "mora biti manjši kot %{count}" + less_than_or_equal_to: "mora biti manjši ali enak kot %{count}" + odd: "mora biti sodo" + even: "mora biti liho" + greater_than_start_date: "mora biti kasnejši kot začetni datum" not_same_project: "ne pripada istemu projektu" circular_dependency: "Ta odnos bi povzročil krožno odvisnost" - cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + cant_link_an_issue_with_a_descendant: "Zahtevek ne more biti povezan s svojo podnalogo" actionview_instancetag_blank_option: Prosimo izberite - + general_text_No: 'Ne' general_text_Yes: 'Da' general_text_no: 'ne' @@ -137,7 +138,7 @@ general_csv_encoding: UTF-8 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: Račun je bil uspešno posodobljen. notice_account_invalid_creditentials: Napačno uporabniško ime ali geslo notice_account_password_updated: Geslo je bilo uspešno posodobljeno. @@ -162,13 +163,13 @@ notice_account_pending: "Vaš račun je bil ustvarjen in čaka na potrditev s strani administratorja." notice_default_data_loaded: Privzete nastavitve so bile uspešno naložene. notice_unable_delete_version: Verzije ni bilo mogoče izbrisati. - + error_can_t_load_default_data: "Privzetih nastavitev ni bilo mogoče naložiti: %{value}" error_scm_not_found: "Vnos ali revizija v shrambi ni bila najdena ." error_scm_command_failed: "Med vzpostavljem povezave s shrambo je prišlo do napake: %{value}" error_scm_annotate: "Vnos ne obstaja ali pa ga ni mogoče komentirati." error_issue_not_found_in_project: 'Zahtevek ni bil najden ali pa ne pripada temu projektu' - + mail_subject_lost_password: "Vaše %{value} geslo" mail_body_lost_password: 'Za spremembo glesla kliknite na naslednjo povezavo:' mail_subject_register: "Aktivacija %{value} vašega računa" @@ -179,10 +180,10 @@ mail_body_account_activation_request: "Registriral se je nov uporabnik (%{value}). Račun čaka na vašo odobritev:" mail_subject_reminder: "%{count} zahtevek(zahtevki) zapadejo v naslednjih %{days} dneh" mail_body_reminder: "%{count} zahtevek(zahtevki), ki so vam dodeljeni bodo zapadli v naslednjih %{days} dneh:" - + gui_validation_error: 1 napaka gui_validation_error_plural: "%{count} napak" - + field_name: Ime field_description: Opis field_summary: Povzetek @@ -267,7 +268,7 @@ field_default_value: Privzeta vrednost field_comments_sorting: Prikaži komentarje field_parent_title: Matična stran - + setting_app_title: Naslov aplikacije setting_app_subtitle: Podnaslov aplikacije setting_welcome_text: Pozdravno besedilo @@ -293,7 +294,6 @@ setting_time_format: Oblika časa setting_cross_project_issue_relations: Dovoli povezave zahtevkov med različnimi projekti setting_issue_list_default_columns: Privzeti stolpci prikazani na seznamu zahtevkov - setting_repositories_encodings: Kodiranje shrambe setting_emails_footer: Noga e-sporočil setting_protocol: Protokol setting_per_page_options: Število elementov na stran @@ -306,7 +306,7 @@ setting_sequential_project_identifiers: Generiraj projektne identifikatorje sekvenčno setting_gravatar_enabled: Uporabljaj Gravatar ikone setting_diff_max_lines_displayed: Maksimalno število prikazanih vrstic različnosti - + permission_edit_project: Uredi projekt permission_select_project_modules: Izberi module projekta permission_manage_members: Uredi člane @@ -355,7 +355,7 @@ permission_edit_own_messages: Uredi lastna sporočila permission_delete_messages: Izbriši sporočila permission_delete_own_messages: Izbriši lastna sporočila - + project_module_issue_tracking: Sledenje zahtevkom project_module_time_tracking: Sledenje časa project_module_news: Novice @@ -364,7 +364,7 @@ project_module_wiki: Wiki project_module_repository: Shramba project_module_boards: Table - + label_user: Uporabnik label_user_plural: Uporabniki label_user_new: Nov uporabnik @@ -372,9 +372,9 @@ label_project_new: Nov projekt label_project_plural: Projekti label_x_projects: - zero: no projects - one: 1 project - other: "%{count} projects" + zero: ni projektov + one: 1 projekt + other: "%{count} projektov" label_project_all: Vsi projekti label_project_latest: Zadnji projekti label_issue: Zahtevek @@ -477,22 +477,22 @@ label_export_to: 'Na razpolago tudi v:' label_read: Preberi... label_public_projects: Javni projekti - label_open_issues: odpri zahtevek - label_open_issues_plural: odpri zahtevke - label_closed_issues: zapri zahtevek - label_closed_issues_plural: zapri zahtevke + label_open_issues: odprt zahtevek + label_open_issues_plural: odprti zahtevki + label_closed_issues: zaprt zahtevek + label_closed_issues_plural: zaprti zahtevki label_x_open_issues_abbr_on_total: - zero: 0 open / %{total} - one: 1 open / %{total} - other: "%{count} open / %{total}" + zero: 0 odprtih / %{total} + one: 1 odprt / %{total} + other: "%{count} odprtih / %{total}" label_x_open_issues_abbr: - zero: 0 open - one: 1 open - other: "%{count} open" + zero: 0 odprtih + one: 1 odprt + other: "%{count} odprtih" label_x_closed_issues_abbr: - zero: 0 closed - one: 1 closed - other: "%{count} closed" + zero: 0 zaprtih + one: 1 zaprt + other: "%{count} zaprtih" label_total: Skupaj label_permissions: Dovoljenja label_current_status: Trenutno stanje @@ -508,7 +508,7 @@ label_per_page: Na stran label_calendar: Koledar label_months_from: mesecev od - label_gantt: Gantt + label_gantt: Gantogram label_internal: Notranji label_last_changes: "zadnjih %{count} sprememb" label_change_view_all: Poglej vse spremembe @@ -516,9 +516,9 @@ label_comment: Komentar label_comment_plural: Komentarji label_x_comments: - zero: no comments - one: 1 comment - other: "%{count} comments" + zero: ni komentarjev + one: 1 komentar + other: "%{count} komentarjev" label_comment_add: Dodaj komentar label_comment_added: Komentar dodan label_comment_delete: Izbriši komentarje @@ -680,7 +680,7 @@ label_generate_key: Ustvari ključ label_issue_watchers: Spremljevalci label_example: Vzorec - + button_login: Prijavi se button_submit: Pošlji button_save: Shrani @@ -719,11 +719,11 @@ button_update: Posodobi button_configure: Konfiguriraj button_quote: Citiraj - + status_active: aktivni status_registered: registriran status_locked: zaklenjen - + text_select_mail_notifications: Izberi dejanja za katera naj bodo poslana oznanila preko e-pošto. text_regexp_info: npr. ^[A-Z0-9]+$ text_min_max_length_info: 0 pomeni brez omejitev @@ -767,7 +767,7 @@ text_email_delivery_not_configured: "E-poštna dostava ni nastavljena in oznanila so onemogočena.\nNastavite vaš SMTP strežnik v config/configuration.yml in ponovno zaženite aplikacijo da ga omogočite.\n" text_repository_usernames_mapping: "Izberite ali posodobite Redmine uporabnika dodeljenega vsakemu uporabniškemu imenu najdenemu v zapisniku shrambe.\n Uporabniki z enakim Redmine ali shrambinem uporabniškem imenu ali e-poštnem naslovu so samodejno dodeljeni." text_diff_truncated: '... Ta sprememba je bila odsekana ker presega največjo velikost ki je lahko prikazana.' - + default_role_manager: Upravnik default_role_developer: Razvijalec default_role_reporter: Poročevalec @@ -775,7 +775,7 @@ default_tracker_feature: Funkcija default_tracker_support: Podpora default_issue_status_new: Nov - default_issue_status_in_progress: In Progress + default_issue_status_in_progress: V teku default_issue_status_resolved: Rešen default_issue_status_feedback: Povratna informacija default_issue_status_closed: Zaključen @@ -789,187 +789,221 @@ default_priority_immediate: Takojšnje ukrepanje default_activity_design: Oblikovanje default_activity_development: Razvoj - + enumeration_issue_priorities: Prioritete zahtevkov enumeration_doc_categories: Kategorije dokumentov enumeration_activities: Aktivnosti (sledenje časa) - warning_attachments_not_saved: "%{count} file(s) could not be saved." - field_editable: Editable - text_plugin_assets_writable: Plugin assets directory writable - label_display: Display - button_create_and_continue: Create and continue - text_custom_field_possible_values_info: 'One line for each value' - setting_repository_log_display_limit: Maximum number of revisions displayed on file log - setting_file_max_size_displayed: Max size of text files displayed inline - field_watcher: Watcher - setting_openid: Allow OpenID login and registration + warning_attachments_not_saved: "%{count} datotek(e) ni bilo mogoče shraniti." + field_editable: Uredljivo + text_plugin_assets_writable: Zapisljiva mapa za vtičnike + label_display: Prikaz + button_create_and_continue: Ustvari in nadaljuj + text_custom_field_possible_values_info: 'Ena vrstica za vsako vrednost' + setting_repository_log_display_limit: Največje število prikazanih revizij v log datoteki + setting_file_max_size_displayed: Največja velikost besedilnih datotek v vključenem prikazu + field_watcher: Opazovalec + setting_openid: Dovoli OpenID prijavo in registracijo field_identity_url: OpenID URL - label_login_with_open_id_option: or login with OpenID - field_content: Content - label_descending: Descending - label_sort: Sort - label_ascending: Ascending - label_date_from_to: From %{start} to %{end} + label_login_with_open_id_option: ali se prijavi z OpenID + field_content: Vsebina + label_descending: Padajoče + label_sort: Razvrsti + label_ascending: Naraščajoče + label_date_from_to: Od %{start} do %{end} label_greater_or_equal: ">=" label_less_or_equal: <= - text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? - text_wiki_page_reassign_children: Reassign child pages to this parent page - text_wiki_page_nullify_children: Keep child pages as root pages - text_wiki_page_destroy_children: Delete child pages and all their descendants - setting_password_min_length: Minimum password length - field_group_by: Group results by - mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" - label_wiki_content_added: Wiki page added - mail_subject_wiki_content_added: "'%{id}' wiki page has been added" - mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. - label_wiki_content_updated: Wiki page updated - mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. - permission_add_project: Create project - setting_new_project_user_role_id: Role given to a non-admin user who creates a project - label_view_all_revisions: View all revisions - label_tag: Tag - label_branch: Branch - error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. - error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). - text_journal_changed: "%{label} changed from %{old} to %{new}" - text_journal_set_to: "%{label} set to %{value}" - text_journal_deleted: "%{label} deleted (%{old})" - label_group_plural: Groups - label_group: Group - label_group_new: New group - label_time_entry_plural: Spent time - text_journal_added: "%{label} %{value} added" - field_active: Active - enumeration_system_activity: System Activity - permission_delete_issue_watchers: Delete watchers - version_status_closed: closed - version_status_locked: locked - version_status_open: open - error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened - label_user_anonymous: Anonymous - button_move_and_follow: Move and follow - setting_default_projects_modules: Default enabled modules for new projects - setting_gravatar_default: Default Gravatar image - field_sharing: Sharing - label_version_sharing_hierarchy: With project hierarchy - label_version_sharing_system: With all projects - label_version_sharing_descendants: With subprojects - label_version_sharing_tree: With project tree - label_version_sharing_none: Not shared - error_can_not_archive_project: This project can not be archived - button_duplicate: Duplicate - button_copy_and_follow: Copy and follow - label_copy_source: Source - setting_issue_done_ratio: Calculate the issue done ratio with - setting_issue_done_ratio_issue_status: Use the issue status - error_issue_done_ratios_not_updated: Issue done ratios not updated. - error_workflow_copy_target: Please select target tracker(s) and role(s) - setting_issue_done_ratio_issue_field: Use the issue field - label_copy_same_as_target: Same as target - label_copy_target: Target - notice_issue_done_ratios_updated: Issue done ratios updated. - error_workflow_copy_source: Please select a source tracker or role - label_update_issue_done_ratios: Update issue done ratios - setting_start_of_week: Start calendars on - permission_view_issues: View Issues - label_display_used_statuses_only: Only display statuses that are used by this tracker - label_revision_id: Revision %{value} - label_api_access_key: API access key - label_api_access_key_created_on: API access key created %{value} ago - label_feeds_access_key: RSS access key - notice_api_access_key_reseted: Your API access key was reset. - setting_rest_api_enabled: Enable REST web service - label_missing_api_access_key: Missing an API access key - label_missing_feeds_access_key: Missing a RSS access key - button_show: Show - text_line_separated: Multiple values allowed (one line for each value). - setting_mail_handler_body_delimiters: Truncate emails after one of these lines - permission_add_subprojects: Create subprojects - label_subproject_new: New subproject + text_wiki_page_destroy_question: Ta stran ima %{descendants} podstran(i) in naslednik(ov). Kaj želite storiti? + text_wiki_page_reassign_children: Znova dodeli podstrani tej glavni strani + text_wiki_page_nullify_children: Obdrži podstrani kot glavne strani + text_wiki_page_destroy_children: Izbriši podstrani in vse njihove naslednike + setting_password_min_length: Minimalna dolžina gesla + field_group_by: Združi rezultate po + mail_subject_wiki_content_updated: "'%{id}' wiki stran je bila posodobljena" + label_wiki_content_added: Wiki stran dodana + mail_subject_wiki_content_added: "'%{id}' wiki stran je bila dodana" + mail_body_wiki_content_added: "%{author} je dodal '%{id}' wiki stran" + label_wiki_content_updated: Wiki stran posodobljena + mail_body_wiki_content_updated: "%{author} je posodobil '%{id}' wiki stran." + permission_add_project: Ustvari projekt + setting_new_project_user_role_id: Vloga, dodeljena neadministratorskemu uporabniku, ki je ustvaril projekt + label_view_all_revisions: Poglej vse revizije + label_tag: Oznaka + label_branch: Veja + error_no_tracker_in_project: Noben sledilnik ni povezan s tem projektom. Prosimo preverite nastavitve projekta. + error_no_default_issue_status: Privzeti zahtevek ni definiran. Prosimo preverite svoje nastavitve (Pojdite na "Administracija -> Stanje zahtevkov"). + text_journal_changed: "%{label} se je spremenilo iz %{old} v %{new}" + text_journal_set_to: "%{label} nastavljeno na %{value}" + text_journal_deleted: "%{label} izbrisan (%{old})" + label_group_plural: Skupine + label_group: Skupina + label_group_new: Nova skupina + label_time_entry_plural: Porabljen čas + text_journal_added: "%{label} %{value} dodan" + field_active: Aktiven + enumeration_system_activity: Sistemska aktivnost + permission_delete_issue_watchers: Izbriši opazovalce + version_status_closed: zaprt + version_status_locked: zaklenjen + version_status_open: odprt + error_can_not_reopen_issue_on_closed_version: Zahtevek dodeljen zaprti verziji ne more biti ponovno odprt + label_user_anonymous: Anonimni + button_move_and_follow: Premakni in sledi + setting_default_projects_modules: Privzeti moduli za nove projekte + setting_gravatar_default: Privzeta Gravatar slika + field_sharing: Deljenje + label_version_sharing_hierarchy: S projektno hierarhijo + label_version_sharing_system: Z vsemi projekti + label_version_sharing_descendants: S podprojekti + label_version_sharing_tree: Z drevesom projekta + label_version_sharing_none: Ni deljeno + error_can_not_archive_project: Ta projekt ne more biti arhiviran + button_duplicate: Podvoji + button_copy_and_follow: Kopiraj in sledi + label_copy_source: Vir + setting_issue_done_ratio: Izračunaj razmerje opravljenega zahtevka z + setting_issue_done_ratio_issue_status: Uporabi stanje zahtevka + error_issue_done_ratios_not_updated: Razmerje opravljenega zahtevka ni bilo posodobljeno. + error_workflow_copy_target: Prosimo izberite ciljni(e) sledilnik(e) in vlogo(e) + setting_issue_done_ratio_issue_field: Uporabi polje zahtevka + label_copy_same_as_target: Enako kot cilj + label_copy_target: Cilj + notice_issue_done_ratios_updated: Razmerje opravljenega zahtevka posodobljeno. + error_workflow_copy_source: Prosimo izberite vir zahtevka ali vlogo + label_update_issue_done_ratios: Posodobi razmerje opravljenega zahtevka + setting_start_of_week: Začni koledarje z + permission_view_issues: Poglej zahtevke + label_display_used_statuses_only: Prikaži samo stanja ki uporabljajo ta sledilnik + label_revision_id: Revizija %{value} + label_api_access_key: API dostopni ključ + label_api_access_key_created_on: API dostopni ključ ustvarjen pred %{value} + label_feeds_access_key: RSS dostopni ključ + notice_api_access_key_reseted: Vaš API dostopni ključ je bil ponastavljen. + setting_rest_api_enabled: Omogoči REST spletni servis + label_missing_api_access_key: Manjkajoč API dostopni ključ + label_missing_feeds_access_key: Manjkajoč RSS dostopni ključ + button_show: Prikaži + text_line_separated: Dovoljenih več vrednosti (ena vrstica za vsako vrednost). + setting_mail_handler_body_delimiters: Odreži e-pošto po eni od teh vrstic + permission_add_subprojects: Ustvari podprojekte + label_subproject_new: Nov podprojekt text_own_membership_delete_confirmation: |- - You are about to remove some or all of your permissions and may no longer be able to edit this project after that. - Are you sure you want to continue? - label_close_versions: Close completed versions - label_board_sticky: Sticky - label_board_locked: Locked - permission_export_wiki_pages: Export wiki pages - setting_cache_formatted_text: Cache formatted text - permission_manage_project_activities: Manage project activities - error_unable_delete_issue_status: Unable to delete issue status - label_profile: Profile - permission_manage_subtasks: Manage subtasks - field_parent_issue: Parent task - label_subtask_plural: Subtasks - label_project_copy_notifications: Send email notifications during the project copy - error_can_not_delete_custom_field: Unable to delete custom field - error_unable_to_connect: Unable to connect (%{value}) - error_can_not_remove_role: This role is in use and can not be deleted. - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): %{errors}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time - field_time_entries: Log time - project_module_gantt: Gantt - project_module_calendar: Calendar - button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" - text_are_you_sure_with_children: Delete issue and all child issues? - field_text: Text field - label_user_mail_option_only_owner: Only for things I am the owner of - setting_default_notification_option: Default notification option - label_user_mail_option_only_my_events: Only for things I watch or I'm involved in - label_user_mail_option_only_assigned: Only for things I am assigned to - label_user_mail_option_none: No events - field_member_of_group: Assignee's group - field_assigned_to_role: Assignee's role - notice_not_authorized_archived_project: The project you're trying to access has been archived. - label_principal_search: "Search for user or group:" - label_user_search: "Search for user:" - field_visible: Visible - setting_emails_header: Emails header - setting_commit_logtime_activity_id: Activity for logged time - text_time_logged_by_changeset: Applied in changeset %{value}. - setting_commit_logtime_enabled: Enable time logging - notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) - setting_gantt_items_limit: Maximum number of items displayed on the gantt chart - field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text - text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. - label_my_queries: My custom queries - text_journal_changed_no_detail: "%{label} updated" - label_news_comment_added: Comment added to a news - button_expand_all: Expand all - button_collapse_all: Collapse all - label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee - label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author - label_bulk_edit_selected_time_entries: Bulk edit selected time entries - text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? - label_role_anonymous: Anonymous - label_role_non_member: Non member - label_issue_note_added: Note added - label_issue_status_updated: Status updated - label_issue_priority_updated: Priority updated - label_issues_visibility_own: Issues created by or assigned to the user - field_issues_visibility: Issues visibility - label_issues_visibility_all: All issues - permission_set_own_issues_private: Set own issues public or private - field_is_private: Private - permission_set_issues_private: Set issues public or private - label_issues_visibility_public: All non private issues - text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + Odstranili boste nekatere ali vse od dovoljenj zaradi česar morda ne boste mogli več urejati tega projekta. + Ali ste prepričani, da želite nadaljevati? + label_close_versions: Zapri dokončane verzije + label_board_sticky: Lepljivo + label_board_locked: Zaklenjeno + permission_export_wiki_pages: Izvozi wiki strani + setting_cache_formatted_text: Predpomni oblikovano besedilo + permission_manage_project_activities: Uredi aktivnosti projekta + error_unable_delete_issue_status: Stanja zahtevka ni bilo možno spremeniti + label_profile: Profil + permission_manage_subtasks: Uredi podnaloge + field_parent_issue: Nadrejena naloga + label_subtask_plural: Podnaloge + label_project_copy_notifications: Med kopiranjem projekta pošlji e-poštno sporočilo + error_can_not_delete_custom_field: Polja po meri ni mogoče izbrisati + error_unable_to_connect: Povezava ni mogoča (%{value}) + error_can_not_remove_role: Ta vloga je v uporabi in je ni mogoče izbrisati. + error_can_not_delete_tracker: Ta sledilnik vsebuje zahtevke in se ga ne more izbrisati. + field_principal: Upravnik varnosti + label_my_page_block: Moj gradnik strani + notice_failed_to_save_members: "Shranjevanje uporabnika(ov) ni uspelo: %{errors}." + text_zoom_out: Približaj + text_zoom_in: Oddalji + notice_unable_delete_time_entry: Brisanje dnevnika porabljenaga časa ni mogoče. + label_overall_spent_time: Skupni porabljeni čas + field_time_entries: Beleži porabljeni čas + project_module_gantt: Gantogram + project_module_calendar: Koledear + button_edit_associated_wikipage: "Uredi povezano Wiki stran: %{page_title}" + text_are_you_sure_with_children: Izbriši zahtevek in vse podazahtevke? + field_text: Besedilno polje + label_user_mail_option_only_owner: Samo za stvari katerih lastnik sem + setting_default_notification_option: Privzeta možnost obveščanja + label_user_mail_option_only_my_events: Samo za stvari, ki jih opazujem ali sem v njih vpleten + label_user_mail_option_only_assigned: Samo za stvari, ki smo mi dodeljene + label_user_mail_option_none: Noben dogodek + field_member_of_group: Pooblaščenčeva skupina + field_assigned_to_role: Pooblaščenčeva vloga + notice_not_authorized_archived_project: Projekt, do katerega poskušate dostopati, je bil arhiviran. + label_principal_search: "Poišči uporabnika ali skupino:" + label_user_search: "Poišči uporabnikia:" + field_visible: Viden + setting_emails_header: Glava e-pošte + setting_commit_logtime_activity_id: Aktivnost zabeleženega časa + text_time_logged_by_changeset: Uporabljeno v spremembi %{value}. + setting_commit_logtime_enabled: Omogoči beleženje časa + notice_gantt_chart_truncated: Graf je bil odrezan, ker je prekoračil največje dovoljeno število elementov, ki se jih lahko prikaže (%{max}) + setting_gantt_items_limit: Največje število elementov prikazano na gantogramu + field_warn_on_leaving_unsaved: Opozori me, kadar zapuščam stran z neshranjenim besedilom + text_warn_on_leaving_unsaved: Trenutna stran vsebuje neshranjeno besedilo ki bo izgubljeno, če zapustite to stran. + label_my_queries: Moje poizvedbe po meri + text_journal_changed_no_detail: "%{label} posodobljen" + label_news_comment_added: Komentar dodan novici + button_expand_all: Razširi vse + button_collapse_all: Skrči vse + label_additional_workflow_transitions_for_assignee: Dovoljeni dodatni prehodi kadar je uporabnik pooblaščenec + label_additional_workflow_transitions_for_author: Dovoljeni dodatni prehodi kadar je uporabnik avtor + label_bulk_edit_selected_time_entries: Skupinsko urejanje izbranih časovnih zapisov + text_time_entries_destroy_confirmation: Ali ste prepričani, da želite izbristai izbran(e) časovn(i/e) zapis(e)? + label_role_anonymous: Anonimni + label_role_non_member: Nečlan + label_issue_note_added: Dodan zaznamek + label_issue_status_updated: Status posodobljen + label_issue_priority_updated: Prioriteta posodobljena + label_issues_visibility_own: Zahtevek ustvarjen s strani uporabnika ali dodeljen uporabniku + field_issues_visibility: Vidljivost zahtevkov + label_issues_visibility_all: Vsi zahtevki + permission_set_own_issues_private: Nastavi lastne zahtevke kot javne ali zasebne + field_is_private: Zaseben + permission_set_issues_private: Nastavi zahtevke kot javne ali zasebne + label_issues_visibility_public: Vsi nezasebni zahtevki + text_issues_destroy_descendants_confirmation: To bo izbrisalo tudi %{count} podnalog(o). field_commit_logs_encoding: Kodiranje sporočil ob predaji - field_scm_path_encoding: Path encoding - text_scm_path_encoding_note: "Default: UTF-8" - field_path_to_repository: Path to repository - field_root_directory: Root directory - field_cvs_module: Module + field_scm_path_encoding: Pot do kodiranja + text_scm_path_encoding_note: "Privzeto: UTF-8" + field_path_to_repository: Pot do shrambe + field_root_directory: Korenska mapa + field_cvs_module: Modul field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) - text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) - text_scm_command: Command - text_scm_command_version: Version - label_git_report_last_commit: Report last commit for files and directories - text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. - text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + text_mercurial_repository_note: Lokalna shramba (npr. /hgrepo, c:\hgrepo) + text_scm_command: Ukaz + text_scm_command_version: Verzija + label_git_report_last_commit: Sporoči zadnje uveljavljanje datotek in map + text_scm_config: Svoje SCM ukaze lahko nastavite v datoteki config/configuration.yml. Po urejanju prosimo ponovno zaženite aplikacijo. + text_scm_command_not_available: SCM ukaz ni na voljo. Prosimo preverite nastavitve v upravljalskem podoknu. + + text_git_repository_note: Shramba je prazna in lokalna (npr. /gitrepo, c:\gitrepo) + + notice_issue_successful_create: Ustvarjen zahtevek %{id}. + label_between: med + setting_issue_group_assignment: Dovoli dodeljevanje zahtevka skupinam + label_diff: diff + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/sr-YU.yml --- a/config/locales/sr-YU.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/sr-YU.yml Mon Feb 27 13:53:18 2012 +0000 @@ -325,7 +325,6 @@ setting_time_format: Format vremena setting_cross_project_issue_relations: Dozvoli povezivanje problema iz unakrsnih projekata setting_issue_list_default_columns: Podrazumevane kolone prikazane na spisku problema - setting_repositories_encodings: Kodiranje spremišta setting_emails_footer: Podnožje stranice e-poruke setting_protocol: Protokol setting_per_page_options: Opcije prikaza objekata po stranici @@ -970,10 +969,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/sr.yml --- a/config/locales/sr.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/sr.yml Mon Feb 27 13:53:18 2012 +0000 @@ -325,7 +325,6 @@ setting_time_format: Формат времена setting_cross_project_issue_relations: Дозволи повезивање проблема из унакрсних пројеката setting_issue_list_default_columns: Подразумеване колоне приказане на списку проблема - setting_repositories_encodings: Кодирање спремишта setting_emails_footer: Подножје странице е-поруке setting_protocol: Протокол setting_per_page_options: Опције приказа објеката по страници @@ -971,10 +970,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/sv.yml --- a/config/locales/sv.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/sv.yml Mon Feb 27 13:53:18 2012 +0000 @@ -212,6 +212,7 @@ notice_unable_delete_time_entry: Tidloggning kunde inte tas bort. notice_issue_done_ratios_updated: "% klart uppdaterade." notice_gantt_chart_truncated: "Schemat förminskades eftersom det överskrider det maximala antalet aktiviteter som får visas (%{max})" + notice_issue_successful_create: Ärende %{id} skapades. error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %{value}" error_scm_not_found: "Inlägg och/eller revision finns inte i detta versionsarkiv." @@ -383,7 +384,6 @@ setting_time_format: Tidsformat setting_cross_project_issue_relations: Tillåt ärenderelationer mellan projekt setting_issue_list_default_columns: Standardkolumner i ärendelistan - setting_repositories_encodings: Teckenuppsättningar för versionsarkiv setting_emails_header: Mail-header setting_emails_footer: Signatur setting_protocol: Protokoll @@ -415,6 +415,7 @@ setting_commit_logtime_enabled: Aktivera tidloggning setting_commit_logtime_activity_id: Aktivitet för loggad tid setting_gantt_items_limit: Maximalt antal aktiviteter som visas i gantt-schemat + setting_issue_group_assignment: Tillåt att ärenden tilldelas till grupper permission_add_project: Skapa projekt permission_add_subprojects: Skapa underprojekt @@ -665,6 +666,7 @@ label_in_more_than: om mer än label_greater_or_equal: '>=' label_less_or_equal: '<=' + label_between: mellan label_in: om label_today: idag label_all_time: närsom @@ -985,7 +987,6 @@ text_zoom_in: Zooma in text_warn_on_leaving_unsaved: Nuvarande sida innehåller osparad text som kommer försvinna om du lämnar sidan. text_scm_path_encoding_note: "Standard: UTF-8" - text_git_repository_note: Naket och lokalt versionsarkiv (t.ex. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Lokalt versionsarkiv (t.ex. /hgrepo, c:\hgrepo) text_scm_command: Kommando text_scm_command_version: Version @@ -1018,3 +1019,32 @@ enumeration_doc_categories: Dokumentkategorier enumeration_activities: Aktiviteter (tidsuppföljning) enumeration_system_activity: Systemaktivitet + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/th.yml --- a/config/locales/th.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/th.yml Mon Feb 27 13:53:18 2012 +0000 @@ -288,7 +288,6 @@ setting_time_format: รูปแบบเวลา setting_cross_project_issue_relations: อนุญาตให้ระบุปัญหาข้ามโครงการ setting_issue_list_default_columns: สดมภ์เริ่มต้นแสดงในรายการปัญหา - setting_repositories_encodings: การเข้ารหัสที่เก็บต้นฉบับ setting_emails_footer: คำลงท้ายอีเมล์ setting_protocol: Protocol setting_per_page_options: ตัวเลือกจำนวนต่อหน้า @@ -967,10 +966,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/tr.yml --- a/config/locales/tr.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/tr.yml Mon Feb 27 13:53:18 2012 +0000 @@ -312,7 +312,6 @@ setting_time_format: Zaman Formatı setting_cross_project_issue_relations: Çapraz-Proje iş ilişkilendirmesine izin ver setting_issue_list_default_columns: İş listesinde gösterilen varsayılan sütunlar - setting_repositories_encodings: Depo dil kodlaması setting_emails_footer: E-posta dip not setting_protocol: Protokol setting_per_page_options: Sayfada başına öğe sayısı @@ -989,10 +988,41 @@ field_root_directory: Ana dizin field_cvs_module: Modül field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Komut text_scm_command_version: Sürüm label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/uk.yml --- a/config/locales/uk.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/uk.yml Mon Feb 27 13:53:18 2012 +0000 @@ -8,10 +8,10 @@ default: "%Y-%m-%d" short: "%b %d" long: "%B %d, %Y" - + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] - + # Don't forget the nil at the beginning; there's no such thing as a 0th month month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] @@ -29,7 +29,7 @@ long: "%B %d, %Y %H:%M" am: "am" pm: "pm" - + datetime: distance_in_words: half_a_minute: "half a minute" @@ -67,32 +67,32 @@ one: "almost 1 year" other: "almost %{count} years" - number: + number: format: separator: "." delimiter: "" precision: 3 - human: - format: + human: + format: precision: 1 delimiter: "" - storage_units: + storage_units: format: "%n %u" - units: + units: kb: KB tb: TB gb: GB - byte: + byte: one: Byte other: Bytes mb: MB - + # Used in array.to_sentence. support: array: sentence_connector: "and" skip_last_comma: false - + activerecord: errors: template: @@ -126,7 +126,7 @@ cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" actionview_instancetag_blank_option: Оберіть - + general_text_No: 'Ні' general_text_Yes: 'Так' general_text_no: 'Ні' @@ -137,7 +137,7 @@ general_csv_encoding: UTF-8 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - + notice_account_updated: Обліковий запис успішно оновлений. notice_account_invalid_creditentials: Неправильне ім'я користувача або пароль notice_account_password_updated: Пароль успішно оновлений. @@ -161,7 +161,7 @@ notice_failed_to_save_issues: "Не вдалося зберегти %{count} пункт(ів) з %{total} вибраних: %{ids}." notice_no_issue_selected: "Не вибрано жодної задачі! Будь ласка, відзначте задачу, яку ви хочете відредагувати." notice_account_pending: "Ваш обліковий запис створено і він чекає на підтвердження адміністратором." - + mail_subject_lost_password: "Ваш %{value} пароль" mail_body_lost_password: 'Для зміни пароля, зайдіть за наступним посиланням:' mail_subject_register: "Активація облікового запису %{value}" @@ -170,10 +170,10 @@ mail_body_account_information: Інформація по Вашому обліковому запису mail_subject_account_activation_request: "Запит на активацію облікового запису %{value}" mail_body_account_activation_request: "Новий користувач (%{value}) зареєструвався. Його обліковий запис чекає на ваше підтвердження:" - + gui_validation_error: 1 помилка gui_validation_error_plural: "%{count} помилки(ок)" - + field_name: Ім'я field_description: Опис field_summary: Короткий опис @@ -191,8 +191,8 @@ field_is_for_all: Для усіх проектів field_possible_values: Можливі значення field_regexp: Регулярний вираз - field_min_length: Мінімальна довжина - field_max_length: Максимальна довжина + field_min_length: Мінімальна довжина + field_max_length: Максимальна довжина field_value: Значення field_category: Категорія field_title: Назва @@ -214,9 +214,9 @@ field_is_public: Публічний field_parent: Підпроект field_is_in_roadmap: Питання, що відображаються в оперативному плані - field_login: Вхід + field_login: Вхід field_mail_notification: Повідомлення за електронною поштою - field_admin: Адміністратор + field_admin: Адміністратор field_last_login_on: Останнє підключення field_language: Мова field_effective_date: Дата @@ -255,7 +255,7 @@ field_column_names: Колонки field_time_zone: Часовий пояс field_searchable: Вживається у пошуку - + setting_app_title: Назва додатку setting_app_subtitle: Підзаголовок додатку setting_welcome_text: Текст привітання @@ -279,10 +279,9 @@ setting_time_format: Формат часу setting_cross_project_issue_relations: Дозволити міжпроектні відносини між питаннями setting_issue_list_default_columns: Колонки, що відображаються за умовчанням в списку питань - setting_repositories_encodings: Кодування репозиторія setting_emails_footer: Підпис до електронної пошти setting_protocol: Протокол - + label_user: Користувач label_user_plural: Користувачі label_user_new: Новий користувач @@ -406,15 +405,15 @@ label_total: Всього label_permissions: Права доступу label_current_status: Поточний статус - label_new_statuses_allowed: Дозволені нові статуси + label_new_statuses_allowed: Дозволені нові статуси label_all: Усі label_none: Нікому label_nobody: Ніхто label_next: Наступний label_previous: Попередній - label_used_by: Використовується + label_used_by: Використовується label_details: Подробиці - label_add_note: Додати зауваження + label_add_note: Додати зауваження label_per_page: На сторінку label_calendar: Календар label_months_from: місяців(ця) з @@ -444,8 +443,8 @@ label_in: у label_today: сьогодні label_this_week: цього тижня - label_less_than_ago: менш ніж днів(я) назад - label_more_than_ago: більш ніж днів(я) назад + label_less_than_ago: менш ніж днів(я) назад + label_more_than_ago: більш ніж днів(я) назад label_ago: днів(я) назад label_contains: містить label_not_contains: не містить @@ -457,7 +456,7 @@ label_revision: Версія label_revision_plural: Версій label_added: додано - label_modified: змінене + label_modified: змінене label_deleted: видалено label_latest_revision: Остання версія label_latest_revision_plural: Останні версії @@ -472,11 +471,11 @@ label_roadmap_overdue: "%{value} запізнення" label_roadmap_no_issues: Немає питань для даної версії label_search: Пошук - label_result_plural: Результати + label_result_plural: Результати label_all_words: Всі слова label_wiki: Wiki label_wiki_edit: Редагування Wiki - label_wiki_edit_plural: Редагування Wiki + label_wiki_edit_plural: Редагування Wiki label_wiki_page: Сторінка Wiki label_wiki_page_plural: Сторінки Wiki label_index_by_title: Індекс за назвою @@ -484,7 +483,7 @@ label_current_version: Поточна версія label_preview: Попередній перегляд label_feed_plural: Подання - label_changes_details: Подробиці по всіх змінах + label_changes_details: Подробиці по всіх змінах label_issue_tracking: Координація питань label_spent_time: Витрачений час label_f_hour: "%{value} година" @@ -493,7 +492,7 @@ label_change_plural: Зміни label_statistics: Статистика label_commits_per_month: Подань на місяць - label_commits_per_author: Подань на користувача + label_commits_per_author: Подань на користувача label_view_diff: Проглянути відмінності label_diff_inline: підключений label_diff_side_by_side: поряд @@ -509,7 +508,7 @@ label_relates_to: пов'язане з label_duplicates: дублює label_blocks: блокує - label_blocked_by: заблоковане + label_blocked_by: заблоковане label_precedes: передує label_follows: наступний за label_end_to_start: з кінця до початку @@ -557,12 +556,12 @@ label_registration_manual_activation: ручна активація облікового запису label_registration_automatic_activation: автоматична активація облыкового label_my_time_report: Мій звіт витраченого часу - + button_login: Вхід button_submit: Відправити button_save: Зберегти - button_check_all: Відзначити все - button_uncheck_all: Очистити + button_check_all: Відзначити все + button_uncheck_all: Очистити button_delete: Видалити button_create: Створити button_test: Перевірити @@ -590,14 +589,14 @@ button_unarchive: Розархівувати button_reset: Перезапустити button_rename: Перейменувати - button_change_password: Змінити пароль + button_change_password: Змінити пароль button_copy: Копіювати button_annotate: Анотувати - + status_active: Активний - status_registered: Зареєстрований + status_registered: Зареєстрований status_locked: Заблокований - + text_select_mail_notifications: Виберіть дії, на які відсилатиметься повідомлення на електронну пошту. text_regexp_info: eg. ^[A-Z0-9]+$ text_min_max_length_info: 0 означає відсутність заборон @@ -622,12 +621,14 @@ text_issue_category_destroy_assignments: Видалити призначення категорії text_issue_category_reassign_to: Перепризначити задачі до даної категорії text_user_mail_option: "Для невибраних проектів ви отримуватимете повідомлення тільки про те, що проглядаєте або в чому берете участь (наприклад, питання автором яких ви є або які вам призначені)." - + default_role_manager: Менеджер default_role_developer: Розробник default_role_reporter: Репортер - звітів default_tracker_bug: Помилка - default_tracker_feature: Властивість + # default_tracker_bug: Bug + # звітів default_tracker_bug: Помилка + default_tracker_bug: Помилка + default_tracker_feature: Властивість default_tracker_support: Підтримка default_issue_status_new: Новий default_issue_status_in_progress: In Progress @@ -636,7 +637,7 @@ default_issue_status_closed: Зачинено default_issue_status_rejected: Відмовлено default_doc_category_user: Документація користувача - default_doc_category_tech: Технічна документація + default_doc_category_tech: Технічна документація default_priority_low: Низький default_priority_normal: Нормальний default_priority_high: Високий @@ -644,7 +645,7 @@ default_priority_immediate: Негайний default_activity_design: Проектування default_activity_development: Розробка - + enumeration_issue_priorities: Пріоритети питань enumeration_doc_categories: Категорії документів enumeration_activities: Дії (облік часу) @@ -665,7 +666,6 @@ label_file_added: File added label_more: More field_default_value: Default value - default_tracker_bug: Bug label_scm: SCM label_general: General button_update: Update @@ -966,10 +966,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/vi.yml --- a/config/locales/vi.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/vi.yml Mon Feb 27 13:53:18 2012 +0000 @@ -346,7 +346,6 @@ setting_time_format: Định dạng giờ setting_cross_project_issue_relations: Cho phép quan hệ chéo giữa các dự án setting_issue_list_default_columns: Default columns displayed on the issue list - setting_repositories_encodings: Repositories encodings setting_emails_footer: Chữ ký cuối thư setting_protocol: Giao thức setting_per_page_options: Objects per page options @@ -1021,10 +1020,41 @@ field_root_directory: Root directory field_cvs_module: Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: Command text_scm_command_version: Version label_git_report_last_commit: Report last commit for files and directories text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/locales/zh-TW.yml --- a/config/locales/zh-TW.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/zh-TW.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -# Chinese (Taiwan) translations for Ruby on Rails +# Chinese (Taiwan) translations for Ruby on Rails # by tsechingho (http://github.com/tsechingho) # See http://github.com/svenfuchs/rails-i18n/ for details. @@ -24,7 +24,7 @@ - :year - :month - :day - + time: formats: default: "%Y年%b%d日 %A %H:%M:%S %Z" @@ -69,9 +69,9 @@ percentage: format: # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 - # separator: + # separator: delimiter: "" - # precision: + # precision: # 使用於 number_to_precision() precision: @@ -79,13 +79,13 @@ # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 # separator: delimiter: "" - # precision: + # precision: # 使用於 number_to_human_size() human: format: # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 - # separator: + # separator: delimiter: "" precision: 1 # 儲存單位輸出格式. @@ -149,7 +149,7 @@ activerecord: errors: template: - header: + header: one: "有 1 個錯誤發生使得「%{model}」無法被儲存。" other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。" # The variable :count is also available @@ -180,7 +180,7 @@ greater_than_start_date: "必須在開始日期之後" not_same_project: "不屬於同一個專案" circular_dependency: "這個關聯會導致環狀相依" - cant_link_an_issue_with_a_descendant: "項目無法被連結至自己的子任務" + cant_link_an_issue_with_a_descendant: "問題無法被連結至自己的子任務" # You can define own errors for models or model attributes. # The values :model, :attribute and :value are always available for interpolation. @@ -192,16 +192,16 @@ # attributes: # login: # blank: "This is a custom blank message for User login" - # Will define custom blank validation message for User model and + # Will define custom blank validation message for User model and # custom blank validation message for login attribute of User model. #models: - + # Translate model names. Used in Model.human_name(). #models: # For example, # user: "Dude" # will translate User model name to "Dude" - + # Translate model attribute names. Used in Model.human_attribute_name(attribute). #attributes: # For example, @@ -210,7 +210,7 @@ # will translate User attribute "login" as "Handle" actionview_instancetag_blank_option: 請選擇 - + general_text_No: '否' general_text_Yes: '是' general_text_no: '否' @@ -221,7 +221,7 @@ general_csv_encoding: Big5 general_pdf_encoding: Big5 general_first_day_of_week: '7' - + notice_account_updated: 帳戶更新資訊已儲存 notice_account_invalid_creditentials: 帳戶或密碼不正確 notice_account_password_updated: 帳戶新密碼已儲存 @@ -243,35 +243,38 @@ notice_email_error: "寄送郵件的過程中發生錯誤 (%{value})" notice_feeds_access_key_reseted: 您的 RSS 存取金鑰已被重新設定。 notice_api_access_key_reseted: 您的 API 存取金鑰已被重新設定。 - notice_failed_to_save_issues: " %{count} 個項目儲存失敗(總共選取 %{total} 個項目): %{ids} 。" + notice_failed_to_save_issues: " %{count} 個問題儲存失敗(總共選取 %{total} 個問題): %{ids} 。" notice_failed_to_save_members: "成員儲存失敗: %{errors}." - notice_no_issue_selected: "未選擇任何項目!請勾選您想要編輯的項目。" + notice_no_issue_selected: "未選擇任何問題!請勾選您想要編輯的問題。" notice_account_pending: "您的帳號已經建立,正在等待管理員的審核。" notice_default_data_loaded: 預設組態已載入成功。 notice_unable_delete_version: 無法刪除版本。 notice_unable_delete_time_entry: 無法刪除工時記錄項目。 - notice_issue_done_ratios_updated: 項目完成百分比已更新。 + notice_issue_done_ratios_updated: 問題完成百分比已更新。 notice_gantt_chart_truncated: "由於項目數量超過可顯示數量的最大值 (%{max}),故此甘特圖尾部已被截斷" + notice_issue_successful_create: "問題 %{id} 已建立。" error_can_t_load_default_data: "無法載入預設組態: %{value}" error_scm_not_found: "在儲存機制中找不到這個項目或修訂版。" error_scm_command_failed: "嘗試存取儲存機制時發生錯誤: %{value}" error_scm_annotate: "項目不存在或項目無法被加上附註。" - error_issue_not_found_in_project: '該項目不存在或不屬於此專案' + error_scm_annotate_big_text_file: 此項目無法被標註,因為它已經超過最大的文字檔大小。 + error_issue_not_found_in_project: '該問題不存在或不屬於此專案' error_no_tracker_in_project: '此專案尚未指定追蹤標籤。請檢查專案的設定資訊。' - error_no_default_issue_status: '尚未定義項目狀態的預設值。請您前往「網站管理」->「項目狀態清單」頁面,檢查相關組態設定。' + error_no_default_issue_status: '尚未定義問題狀態的預設值。請您前往「網站管理」->「問題狀態清單」頁面,檢查相關組態設定。' error_can_not_delete_custom_field: 無法刪除自訂欄位 - error_can_not_delete_tracker: "此追蹤標籤已包含項目,無法被刪除。" + error_can_not_delete_tracker: "此追蹤標籤已包含問題,無法被刪除。" error_can_not_remove_role: "此角色已被使用,無法將其刪除。" - error_can_not_reopen_issue_on_closed_version: '指派給「已結束」版本的項目,無法再將其狀態變更為「進行中」' + error_can_not_reopen_issue_on_closed_version: '指派給「已結束」版本的問題,無法再將其狀態變更為「進行中」' error_can_not_archive_project: 此專案無法被歸檔 - error_issue_done_ratios_not_updated: "項目完成百分比未更新。" - error_workflow_copy_source: '請選擇一個來源項目追蹤標籤或角色' - error_workflow_copy_target: '請選擇一個(或多個)目的項目追蹤標籤或角色' - error_unable_delete_issue_status: '無法刪除項目狀態' + error_issue_done_ratios_not_updated: "問題完成百分比未更新。" + error_workflow_copy_source: '請選擇一個來源問題追蹤標籤或角色' + error_workflow_copy_target: '請選擇一個(或多個)目的問題追蹤標籤或角色' + error_unable_delete_issue_status: '無法刪除問題狀態' error_unable_to_connect: "無法連線至(%{value})" + error_attachment_too_big: "這個檔案無法被上傳,因為它已經超過最大的檔案大小 (%{max_size})" warning_attachments_not_saved: "%{count} 個附加檔案無法被儲存。" - + mail_subject_lost_password: 您的 Redmine 網站密碼 mail_body_lost_password: '欲變更您的 Redmine 網站密碼, 請點選以下鏈結:' mail_subject_register: 啟用您的 Redmine 帳號 @@ -280,16 +283,16 @@ mail_body_account_information: 您的 Redmine 帳號資訊 mail_subject_account_activation_request: Redmine 帳號啟用需求通知 mail_body_account_activation_request: "有位新用戶 (%{value}) 已經完成註冊,正等候您的審核:" - mail_subject_reminder: "您有 %{count} 個項目即將到期 (%{days})" - mail_body_reminder: "%{count} 個指派給您的項目,將於 %{days} 天之內到期:" + mail_subject_reminder: "您有 %{count} 個問題即將到期 (%{days})" + mail_body_reminder: "%{count} 個指派給您的問題,將於 %{days} 天之內到期:" mail_subject_wiki_content_added: "'%{id}' wiki 頁面已被新增" mail_body_wiki_content_added: "此 '%{id}' wiki 頁面已被 %{author} 新增。" mail_subject_wiki_content_updated: "'%{id}' wiki 頁面已被更新" mail_body_wiki_content_updated: "此 '%{id}' wiki 頁面已被 %{author} 更新。" - + gui_validation_error: 1 個錯誤 gui_validation_error_plural: "%{count} 個錯誤" - + field_name: 名稱 field_description: 概述 field_summary: 摘要 @@ -313,10 +316,10 @@ field_category: 分類 field_title: 標題 field_project: 專案 - field_issue: 項目 + field_issue: 問題 field_status: 狀態 field_notes: 筆記 - field_is_closed: 項目結束 + field_is_closed: 問題已結束 field_is_default: 預設值 field_tracker: 追蹤標籤 field_subject: 主旨 @@ -330,8 +333,7 @@ field_homepage: 網站首頁 field_is_public: 公開 field_parent: 父專案 - field_is_in_chlog: 項目顯示於變更記錄中 - field_is_in_roadmap: 項目顯示於版本藍圖中 + field_is_in_roadmap: 問題顯示於版本藍圖中 field_login: 帳戶名稱 field_mail_notification: 電子郵件提醒選項 field_admin: 管理者 @@ -365,9 +367,9 @@ field_spent_on: 日期 field_identifier: 代碼 field_is_filter: 用來作為過濾器 - field_issue_to: 相關項目 + field_issue_to: 相關問題 field_delay: 逾期 - field_assignable: 項目可被分派至此角色 + field_assignable: 問題可被分派至此角色 field_redirect_existing_links: 重新導向現有連結 field_estimated_hours: 預估工時 field_column_names: 欄位 @@ -389,7 +391,7 @@ field_text: 內容文字 field_visible: 可被看見 field_warn_on_leaving_unsaved: "提醒我將要離開的頁面中尚有未儲存的資料" - field_issues_visibility: 項目可見度 + field_issues_visibility: 問題可見度 field_is_private: 私人 field_commit_logs_encoding: 認可訊息編碼 field_scm_path_encoding: 路徑編碼 @@ -397,7 +399,7 @@ field_root_directory: 根資料夾 field_cvsroot: CVSROOT field_cvs_module: 模組 - + setting_app_title: 標題 setting_app_subtitle: 副標題 setting_welcome_text: 歡迎詞 @@ -405,7 +407,7 @@ setting_login_required: 需要驗證 setting_self_registration: 註冊選項 setting_attachment_max_size: 附件大小限制 - setting_issues_export_limit: 項目匯出限制 + setting_issues_export_limit: 問題匯出限制 setting_mail_from: 寄件者電子郵件 setting_bcc_recipients: 使用密件副本 (BCC) setting_plain_text_mail: 純文字郵件 (不含 HTML) @@ -416,21 +418,21 @@ setting_autofetch_changesets: 自動擷取認可 setting_default_projects_public: 新建立之專案預設為「公開」 setting_sys_api_enabled: 啟用管理儲存機制的網頁服務 (Web Service) - setting_commit_ref_keywords: 認可用於參照項目之關鍵字 - setting_commit_fix_keywords: 認可用於修正項目之關鍵字 + setting_commit_ref_keywords: 認可用於參照之關鍵字 + setting_commit_fix_keywords: 認可用於修正之關鍵字 setting_autologin: 自動登入 setting_date_format: 日期格式 setting_time_format: 時間格式 - setting_cross_project_issue_relations: 允許關聯至其它專案的項目 - setting_issue_list_default_columns: 預設顯示於項目清單的欄位 - setting_repositories_encodings: 版本庫編碼 + setting_cross_project_issue_relations: 允許關聯至其它專案的問題 + setting_issue_list_default_columns: 預設顯示於問題清單的欄位 + setting_repositories_encodings: 附加檔案與儲存機制的編碼 setting_emails_header: 電子郵件前頭說明 setting_emails_footer: 電子郵件附帶說明 setting_protocol: 協定 setting_per_page_options: 每頁顯示個數選項 setting_user_format: 使用者顯示格式 setting_activity_days_default: 專案活動顯示天數 - setting_display_subprojects_issues: 預設於父專案中顯示子專案的項目 + setting_display_subprojects_issues: 預設於父專案中顯示子專案的問題 setting_enabled_scm: 啟用的 SCM setting_mail_handler_body_delimiters: "截去郵件中包含下列值之後的內容" setting_mail_handler_api_enabled: 啟用處理傳入電子郵件的服務 @@ -445,9 +447,9 @@ setting_password_min_length: 密碼最小長度 setting_new_project_user_role_id: 管理者以外之用戶建立新專案時,將被指派的角色 setting_default_projects_modules: 新專案預設啟用的模組 - setting_issue_done_ratio: 計算項目完成百分比之方式 - setting_issue_done_ratio_issue_field: 依據項目完成百分比欄位 - setting_issue_done_ratio_issue_status: 依據項目狀態 + setting_issue_done_ratio: 計算問題完成百分比之方式 + setting_issue_done_ratio_issue_field: 依據問題完成百分比欄位 + setting_issue_done_ratio_issue_status: 依據問題狀態 setting_start_of_week: 週的第一天 setting_rest_api_enabled: 啟用 REST 網路服務技術(Web Service) setting_cache_formatted_text: 快取已格式化文字 @@ -455,7 +457,9 @@ setting_commit_logtime_enabled: 啟用認可中的時間記錄 setting_commit_logtime_activity_id: 時間記錄對應的活動 setting_gantt_items_limit: 甘特圖中項目顯示數量的最大值 - + setting_issue_group_assignment: 允許問題被指派至群組 + setting_default_issue_start_date_to_creation_date: 設定新問題的起始日期為今天的日期 + permission_add_project: 建立專案 permission_add_subprojects: 建立子專案 permission_edit_project: 編輯專案 @@ -463,25 +467,25 @@ permission_manage_members: 管理成員 permission_manage_project_activities: 管理專案活動 permission_manage_versions: 管理版本 - permission_manage_categories: 管理項目分類 - permission_view_issues: 檢視項目 - permission_add_issues: 新增項目 - permission_edit_issues: 編輯項目 - permission_manage_issue_relations: 管理項目關聯 - permission_set_issues_private: 設定項目為公開或私人 - permission_set_own_issues_private: 設定自己的項目為公開或私人 + permission_manage_categories: 管理問題分類 + permission_view_issues: 檢視問題 + permission_add_issues: 新增問題 + permission_edit_issues: 編輯問題 + permission_manage_issue_relations: 管理問題關聯 + permission_set_issues_private: 設定問題為公開或私人 + permission_set_own_issues_private: 設定自己的問題為公開或私人 permission_add_issue_notes: 新增筆記 permission_edit_issue_notes: 編輯筆記 permission_edit_own_issue_notes: 編輯自己的筆記 - permission_move_issues: 搬移項目 - permission_delete_issues: 刪除項目 + permission_move_issues: 搬移問題 + permission_delete_issues: 刪除問題 permission_manage_public_queries: 管理公開查詢 permission_save_queries: 儲存查詢 permission_view_gantt: 檢視甘特圖 permission_view_calendar: 檢視日曆 - permission_view_issue_watchers: 檢視觀察者清單 - permission_add_issue_watchers: 新增觀察者 - permission_delete_issue_watchers: 刪除觀察者 + permission_view_issue_watchers: 檢視監看者清單 + permission_add_issue_watchers: 新增監看者 + permission_delete_issue_watchers: 刪除監看者 permission_log_time: 紀錄耗用工時 permission_view_time_entries: 檢視耗用工時 permission_edit_time_entries: 編輯工時紀錄 @@ -513,8 +517,8 @@ permission_delete_own_messages: 刪除自己的訊息 permission_export_wiki_pages: 匯出 wiki 頁面 permission_manage_subtasks: 管理子任務 - - project_module_issue_tracking: 項目追蹤 + + project_module_issue_tracking: 問題追蹤 project_module_time_tracking: 工時追蹤 project_module_news: 新聞 project_module_documents: 文件 @@ -524,7 +528,7 @@ project_module_boards: 討論區 project_module_calendar: 日曆 project_module_gantt: 甘特圖 - + label_user: 用戶 label_user_plural: 用戶清單 label_user_new: 建立新用戶 @@ -538,13 +542,13 @@ other: "%{count} 個專案" label_project_all: 全部的專案 label_project_latest: 最近的專案 - label_issue: 項目 - label_issue_new: 建立新項目 - label_issue_plural: 項目清單 - label_issue_view_all: 檢視所有項目 - label_issues_by: "項目按 %{value} 分組顯示" - label_issue_added: 項目已新增 - label_issue_updated: 項目已更新 + label_issue: 問題 + label_issue_new: 建立新問題 + label_issue_plural: 問題清單 + label_issue_view_all: 檢視所有問題 + label_issues_by: "問題按 %{value} 分組顯示" + label_issue_added: 問題已新增 + label_issue_updated: 問題已更新 label_issue_note_added: 筆記已新增 label_issue_status_updated: 狀態已更新 label_issue_priority_updated: 優先權已更新 @@ -565,11 +569,11 @@ label_tracker_plural: 追蹤標籤清單 label_tracker_new: 建立新的追蹤標籤 label_workflow: 流程 - label_issue_status: 項目狀態 - label_issue_status_plural: 項目狀態清單 + label_issue_status: 問題狀態 + label_issue_status_plural: 問題狀態清單 label_issue_status_new: 建立新狀態 - label_issue_category: 項目分類 - label_issue_category_plural: 項目分類清單 + label_issue_category: 問題分類 + label_issue_category_plural: 問題分類清單 label_issue_category_new: 建立新分類 label_custom_field: 自訂欄位 label_custom_field_plural: 自訂欄位清單 @@ -592,8 +596,8 @@ label_login: 登入 label_logout: 登出 label_help: 說明 - label_reported_issues: 我通報的項目 - label_assigned_to_me_issues: 分派給我的項目 + label_reported_issues: 我通報的問題 + label_assigned_to_me_issues: 分派給我的問題 label_last_login: 最近一次連線 label_registered_on: 註冊於 label_activity: 活動 @@ -705,6 +709,7 @@ label_in_more_than: 在大於 label_greater_or_equal: "大於等於 (>=)" label_less_or_equal: "小於等於 (<=)" + label_between: 區間 label_in: 在 label_today: 今天 label_all_time: 全部 @@ -728,7 +733,7 @@ label_modification: "%{count} 變更" label_modification_plural: "%{count} 變更" label_branch: 分支 - label_tag: 標籤 + label_tag: 標籤 label_revision: 修訂版 label_revision_plural: 修訂版清單 label_revision_id: "修訂版 %{value}" @@ -750,7 +755,7 @@ label_roadmap: 版本藍圖 label_roadmap_due_in: "剩餘 %{value}" label_roadmap_overdue: "逾期 %{value}" - label_roadmap_no_issues: 此版本尚未包含任何項目 + label_roadmap_no_issues: 此版本尚未包含任何問題 label_search: 搜尋 label_result_plural: 結果 label_all_words: 包含全部的字詞 @@ -765,7 +770,7 @@ label_preview: 預覽 label_feed_plural: Feeds label_changes_details: 所有變更的明細 - label_issue_tracking: 項目追蹤 + label_issue_tracking: 問題追蹤 label_spent_time: 耗用工時 label_overall_spent_time: 整體耗用工時 label_f_hour: "%{value} 小時" @@ -776,20 +781,21 @@ label_commits_per_month: 依月份統計認可 label_commits_per_author: 依作者統計認可 label_view_diff: 檢視差異 + label_diff: 差異 label_diff_inline: 直列 label_diff_side_by_side: 並排 label_options: 選項清單 label_copy_workflow_from: 從以下追蹤標籤複製工作流程 label_permissions_report: 權限報表 - label_watched_issues: 觀察中的項目清單 - label_related_issues: 相關的項目清單 + label_watched_issues: 監看中的問題清單 + label_related_issues: 相關的問題清單 label_applied_status: 已套用狀態 label_loading: 載入中... label_relation_new: 建立新關聯 label_relation_delete: 刪除關聯 label_relates_to: 關聯至 label_duplicates: 已重複 - label_duplicated_by: 與後面所列項目重複 + label_duplicated_by: 與後面所列問題重複 label_blocks: 阻擋 label_blocked_by: 被阻擋 label_precedes: 優先於 @@ -834,7 +840,7 @@ label_changeset_plural: 變更集清單 label_default_columns: 預設欄位清單 label_no_change_option: (維持不變) - label_bulk_edit_selected_issues: 大量編輯選取的項目 + label_bulk_edit_selected_issues: 大量編輯選取的問題 label_bulk_edit_selected_time_entries: 大量編輯選取的工時項目 label_theme: 畫面主題 label_default: 預設 @@ -866,7 +872,7 @@ label_planning: 計劃表 label_incoming_emails: 傳入的電子郵件 label_generate_key: 產生金鑰 - label_issue_watchers: 觀察者 + label_issue_watchers: 監看者 label_example: 範例 label_display: 顯示 label_sort: 排序 @@ -884,7 +890,7 @@ label_version_sharing_hierarchy: 與專案階層架構共用 label_version_sharing_tree: 與專案樹共用 label_version_sharing_system: 與全部的專案共用 - label_update_issue_done_ratios: 更新項目完成百分比 + label_update_issue_done_ratios: 更新問題完成百分比 label_copy_source: 來源 label_copy_target: 目的地 label_copy_same_as_target: 與目的地相同 @@ -899,10 +905,13 @@ label_user_search: "搜尋用戶:" label_additional_workflow_transitions_for_author: 用戶為作者時額外允許的流程轉換 label_additional_workflow_transitions_for_assignee: 用戶為被指定者時額外允許的流程轉換 - label_issues_visibility_all: 所有項目 - label_issues_visibility_public: 所有非私人項目 - label_issues_visibility_own: 使用者所建立的或被指派的項目 + label_issues_visibility_all: 所有問題 + label_issues_visibility_public: 所有非私人問題 + label_issues_visibility_own: 使用者所建立的或被指派的問題 label_git_report_last_commit: 報告最後認可的文件和目錄 + label_parent_revision: 父項 + label_child_revision: 子項 + label_export_options: %{export_format} 匯出選項 button_login: 登入 button_submit: 送出 @@ -950,17 +959,19 @@ button_quote: 引用 button_duplicate: 重製 button_show: 顯示 - + button_edit_section: 編輯此區塊 + button_export: 匯出 + status_active: 活動中 status_registered: 註冊完成 status_locked: 鎖定中 - + version_status_open: 進行中 version_status_locked: 已鎖定 version_status_closed: 已結束 - + field_active: 活動中 - + text_select_mail_notifications: 選擇欲寄送提醒通知郵件之動作 text_regexp_info: eg. ^[A-Z0-9]+$ text_min_max_length_info: 0 代表「不限制」 @@ -968,15 +979,15 @@ text_subprojects_destroy_warning: "下列子專案: %{value} 將一併被刪除。" text_workflow_edit: 選擇角色與追蹤標籤以設定其工作流程 text_are_you_sure: 確定執行? - text_are_you_sure_with_children: "確定刪除此工作項目及其子項目?" + text_are_you_sure_with_children: "確定刪除此問題及其子問題?" text_journal_changed: "%{label} 從 %{old} 變更為 %{new}" text_journal_changed_no_detail: "%{label} 已更新" text_journal_set_to: "%{label} 設定為 %{value}" text_journal_deleted: "%{label} 已刪除 (%{old})" text_journal_added: "%{label} %{value} 已新增" - text_tip_issue_begin_day: 今天起始的工作 - text_tip_issue_end_day: 今天截止的的工作 - text_tip_issue_begin_end_day: 今天起始與截止的工作 + text_tip_issue_begin_day: 今天起始的問題 + text_tip_issue_end_day: 今天截止的的問題 + text_tip_issue_begin_end_day: 今天起始與截止的問題 text_project_identifier_info: '只允許小寫英文字母(a-z)、阿拉伯數字與連字符號(-)。
    儲存後,代碼不可再被更改。' text_caracters_maximum: "最多 %{count} 個字元." text_caracters_minimum: "長度必須大於 %{count} 個字元." @@ -985,19 +996,19 @@ text_unallowed_characters: 不允許的字元 text_comma_separated: 可輸入多個值(須以逗號分隔)。 text_line_separated: 可輸入多個值(須以換行符號分隔,即每列只能輸入一個值)。 - text_issues_ref_in_commit_messages: 認可訊息中參照(或修正)項目之關鍵字 - text_issue_added: "項目 %{id} 已被 %{author} 通報。" - text_issue_updated: "項目 %{id} 已被 %{author} 更新。" + text_issues_ref_in_commit_messages: 認可訊息中參照(或修正)問題之關鍵字 + text_issue_added: "問題 %{id} 已被 %{author} 通報。" + text_issue_updated: "問題 %{id} 已被 %{author} 更新。" text_wiki_destroy_confirmation: 您確定要刪除這個 wiki 和其中的所有內容? - text_issue_category_destroy_question: "有 (%{count}) 個項目被指派到此分類. 請選擇您想要的動作?" - text_issue_category_destroy_assignments: 移除這些項目的分類 - text_issue_category_reassign_to: 重新指派這些項目至其它分類 - text_user_mail_option: "對於那些未被選擇的專案,將只會接收到您正在觀察中,或是參與中的項目通知。(「參與中的項目」包含您建立的或是指派給您的項目)" - text_no_configuration_data: "角色、追蹤標籤、項目狀態與流程尚未被設定完成。\n強烈建議您先載入預設的組態。將預設組態載入之後,您可再變更其中之值。" + text_issue_category_destroy_question: "有 (%{count}) 個問題被指派到此分類. 請選擇您想要的動作?" + text_issue_category_destroy_assignments: 移除這些問題的分類 + text_issue_category_reassign_to: 重新指派這些問題至其它分類 + text_user_mail_option: "對於那些未被選擇的專案,將只會接收到您正在觀察中,或是參與中的問題通知。(「參與中的問題」包含您建立的或是指派給您的問題)" + text_no_configuration_data: "角色、追蹤標籤、問題狀態與流程尚未被設定完成。\n強烈建議您先載入預設的組態。將預設組態載入之後,您可再變更其中之值。" text_load_default_configuration: 載入預設組態 text_status_changed_by_changeset: "已套用至變更集 %{value}." text_time_logged_by_changeset: "紀錄於變更集 %{value}." - text_issues_destroy_confirmation: '確定刪除已選擇的項目?' + text_issues_destroy_confirmation: '確定刪除已選擇的問題?' text_issues_destroy_descendants_confirmation: "這麼做將會一併刪除 %{count} 子任務。" text_time_entries_destroy_confirmation: 您確定要刪除所選擇的工時紀錄? text_select_project_modules: '選擇此專案可使用之模組:' @@ -1005,10 +1016,10 @@ text_file_repository_writable: 可寫入附加檔案目錄 text_plugin_assets_writable: 可寫入附加元件目錄 text_rmagick_available: 可使用 RMagick (選配) - text_destroy_time_entries_question: 您即將刪除的項目已報工 %{hours} 小時. 您的選擇是? + text_destroy_time_entries_question: 您即將刪除的問題已報工 %{hours} 小時. 您的選擇是? text_destroy_time_entries: 刪除已報工的時數 text_assign_time_entries_to_project: 指定已報工的時數至專案中 - text_reassign_time_entries: '重新指定已報工的時數至此項目:' + text_reassign_time_entries: '重新指定已報工的時數至此問題:' text_user_wrote: "%{value} 先前提到:" text_enumeration_destroy_question: "目前有 %{count} 個物件使用此列舉值。" text_enumeration_category_reassign_to: '重新設定其列舉值為:' @@ -1025,8 +1036,8 @@ text_zoom_out: 縮小 text_warn_on_leaving_unsaved: "若您離開這個頁面,此頁面所包含的未儲存資料將會遺失。" text_scm_path_encoding_note: "預設: UTF-8" - text_git_repository_note: "純(Bare)儲存機制與本機儲存機制 (e.g. /gitrepo, c:\gitrepo)" - text_mercurial_repository_note: "本機儲存機制 (e.g. /hgrepo, c:\hgrepo)" + text_git_repository_note: 儲存機制是本機的空(bare)目錄 (即: /gitrepo, c:\gitrepo) + text_mercurial_repository_note: 本機儲存機制 (即: /hgrepo, c:\hgrepo) text_scm_command: 命令 text_scm_command_version: 版本 text_scm_config: 您可以在 config/configuration.yml 中設定 SCM 命令。請在編輯該檔案之後重新啟動 Redmine 應用程式。 @@ -1053,8 +1064,26 @@ default_priority_immediate: 急 default_activity_design: 設計 default_activity_development: 開發 - - enumeration_issue_priorities: 項目優先權 + + enumeration_issue_priorities: 問題優先權 enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) enumeration_system_activity: 系統活動 + description_filter: 篩選條件 + description_search: 搜尋欄位 + description_choose_project: 專案清單 + description_project_scope: 搜尋範圍 + description_notes: 筆記 + description_message_content: 訊息內容 + description_query_sort_criteria_attribute: 排序屬性 + description_query_sort_criteria_direction: 排列順序 + description_user_mail_notification: 郵件通知設定 + description_available_columns: 可用欄位 + description_selected_columns: 已選取的欄位 + description_all_columns: 所有欄位 + description_issue_category_reassign: 選擇問題分類 + description_wiki_subpages_reassign: 選擇新的父頁面 + description_date_range_list: 從清單中選取範圍 + description_date_range_interval: 選擇起始與結束日期以設定範圍區間 + description_date_from: 輸入起始日期 + description_date_to: 輸入結束日期 diff -r 487d96eac004 -r 5e80956cc792 config/locales/zh.yml --- a/config/locales/zh.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/locales/zh.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -# Chinese (China) translations for Ruby on Rails +# Chinese (China) translations for Ruby on Rails # by tsechingho (http://github.com/tsechingho) zh: # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) @@ -11,7 +11,7 @@ default: "%Y-%m-%d" short: "%b%d日" long: "%Y年%b%d日" - + day_names: [星期天, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六] abbr_day_names: [日, 一, 二, 三, 四, 五, 六] @@ -73,7 +73,7 @@ number: # Default format for numbers format: - separator: "." + separator: "." delimiter: "" precision: 3 human: @@ -91,13 +91,12 @@ gb: "GB" tb: "TB" - # Used in array.to_sentence. support: array: sentence_connector: "和" skip_last_comma: false - + activerecord: errors: template: @@ -131,7 +130,7 @@ cant_link_an_issue_with_a_descendant: "问题不能关联到它的子任务" actionview_instancetag_blank_option: 请选择 - + general_text_No: '否' general_text_Yes: '是' general_text_no: '否' @@ -142,7 +141,7 @@ general_csv_encoding: gb18030 general_pdf_encoding: gb18030 general_first_day_of_week: '7' - + notice_account_updated: 帐号更新成功 notice_account_invalid_creditentials: 无效的用户名或密码 notice_account_password_updated: 密码更新成功 @@ -173,7 +172,7 @@ notice_unable_delete_time_entry: 无法删除工时 notice_issue_done_ratios_updated: 问题完成度已更新。 notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" - + error_can_t_load_default_data: "无法载入默认设置:%{value}" error_scm_not_found: "版本库中不存在该条目和(或)其修订版本。" error_scm_command_failed: "访问版本库时发生错误:%{value}" @@ -192,7 +191,7 @@ error_unable_delete_issue_status: '无法删除问题状态' error_unable_to_connect: "无法连接 (%{value})" warning_attachments_not_saved: "%{count} 个文件保存失败" - + mail_subject_lost_password: "您的 %{value} 密码" mail_body_lost_password: '请点击以下链接来修改您的密码:' mail_subject_register: "%{value}帐号激活" @@ -207,10 +206,10 @@ mail_body_wiki_content_added: "'%{id}' wiki页面已由 %{author} 添加。" mail_subject_wiki_content_updated: "'%{id}' wiki页面已更新。" mail_body_wiki_content_updated: "'%{id}' wiki页面已由 %{author} 更新。" - + gui_validation_error: 1 个错误 gui_validation_error_plural: "%{count} 个错误" - + field_name: 名称 field_description: 描述 field_summary: 摘要 @@ -241,7 +240,7 @@ field_is_default: 默认值 field_tracker: 跟踪 field_subject: 主题 - field_due_date: 完成日期 + field_due_date: 计划完成日期 field_assigned_to: 指派给 field_priority: 优先级 field_fixed_version: 目标版本 @@ -273,7 +272,7 @@ field_attr_mail: 邮件属性 field_onthefly: 即时用户生成 field_start_date: 开始日期 - field_done_ratio: % 完成 + field_done_ratio: "% 完成" field_auth_source: 认证模式 field_hide_mail: 隐藏我的邮件地址 field_comments: 注释 @@ -308,7 +307,7 @@ field_assigned_to_role: 角色的成员 field_text: 文本字段 field_visible: 可见的 - + setting_app_title: 应用程序标题 setting_app_subtitle: 应用程序子标题 setting_welcome_text: 欢迎文字 @@ -334,7 +333,6 @@ setting_time_format: 时间格式 setting_cross_project_issue_relations: 允许不同项目之间的问题关联 setting_issue_list_default_columns: 问题列表中显示的默认列 - setting_repositories_encodings: 版本库编码 setting_emails_header: 邮件头 setting_emails_footer: 邮件签名 setting_protocol: 协议 @@ -366,7 +364,7 @@ setting_commit_logtime_enabled: 激活时间日志 setting_commit_logtime_activity_id: 记录的活动 setting_gantt_items_limit: 在甘特图上显示的最大记录数 - + permission_add_project: 新建项目 permission_add_subprojects: 新建子项目 permission_edit_project: 编辑项目 @@ -402,7 +400,7 @@ permission_manage_files: 管理文件 permission_view_files: 查看文件 permission_manage_wiki: 管理Wiki - permission_rename_wiki_pages: 重命名Wiki页面 + permission_rename_wiki_pages: 重定向/重命名Wiki页面 permission_delete_wiki_pages: 删除Wiki页面 permission_view_wiki_pages: 查看Wiki permission_view_wiki_edits: 查看Wiki历史记录 @@ -422,7 +420,7 @@ permission_delete_own_messages: 删除自己的帖子 permission_export_wiki_pages: 导出 wiki 页面 permission_manage_subtasks: 管理子任务 - + project_module_issue_tracking: 问题跟踪 project_module_time_tracking: 时间跟踪 project_module_news: 新闻 @@ -433,7 +431,7 @@ project_module_boards: 讨论区 project_module_calendar: 日历 project_module_gantt: 甘特图 - + label_user: 用户 label_user_plural: 用户 label_user_new: 新建用户 @@ -798,7 +796,7 @@ label_project_copy_notifications: 复制项目时发送邮件通知 label_principal_search: "搜索用户或组:" label_user_search: "搜索用户:" - + button_login: 登录 button_submit: 提交 button_save: 保存 @@ -833,7 +831,7 @@ button_archive: 存档 button_unarchive: 取消存档 button_reset: 重置 - button_rename: 重命名 + button_rename: 重命名/重定向 button_change_password: 修改密码 button_copy: 复制 button_copy_and_follow: 复制并转到新问题 @@ -847,13 +845,13 @@ status_active: 活动的 status_registered: 已注册 status_locked: 已锁定 - + version_status_open: 打开 version_status_locked: 锁定 version_status_closed: 关闭 field_active: 活动 - + text_select_mail_notifications: 选择需要发送邮件通知的动作 text_regexp_info: 例如:^[A-Z0-9]+$ text_min_max_length_info: 0 表示没有限制 @@ -911,9 +909,9 @@ text_wiki_page_destroy_children: 删除子页面及其所有下级页面 text_wiki_page_reassign_children: 将子页面的上级页面设置为 text_own_membership_delete_confirmation: 你正在删除你现有的某些或全部权限,如果这样做了你可能将会再也无法编辑该项目了。你确定要继续吗? - text_zoom_in: Zoom in - text_zoom_out: Zoom out - + text_zoom_in: 放大 + text_zoom_out: 缩小 + default_role_manager: 管理人员 default_role_developer: 开发人员 default_role_reporter: 报告人员 @@ -935,48 +933,79 @@ default_priority_immediate: 立刻 default_activity_design: 设计 default_activity_development: 开发 - + enumeration_issue_priorities: 问题优先级 enumeration_doc_categories: 文档类别 enumeration_activities: 活动(时间跟踪) enumeration_system_activity: 系统活动 - field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text - text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. - label_my_queries: My custom queries - text_journal_changed_no_detail: "%{label} updated" - label_news_comment_added: Comment added to a news - button_expand_all: Expand all - button_collapse_all: Collapse all - label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee - label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author - label_bulk_edit_selected_time_entries: Bulk edit selected time entries - text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + field_warn_on_leaving_unsaved: 当离开未保存内容的页面时,提示我 + text_warn_on_leaving_unsaved: 若离开当前页面,则该页面内未保存的内容将丢失。 + label_my_queries: 我的自定义查询 + text_journal_changed_no_detail: "%{label} 已更新。" + label_news_comment_added: 添加到新闻的评论 + button_expand_all: 展开所有 + button_collapse_all: 合拢所有 + label_additional_workflow_transitions_for_assignee: 当用户是问题的分配对象时所允许的问题状态转换 + label_additional_workflow_transitions_for_author: 当用户是问题作者时所允许的问题状态转换 + label_bulk_edit_selected_time_entries: 批量修改选定的时间条目 + text_time_entries_destroy_confirmation: 是否确定要删除选定的时间条目? label_role_anonymous: Anonymous label_role_non_member: Non member - label_issue_note_added: Note added - label_issue_status_updated: Status updated - label_issue_priority_updated: Priority updated - label_issues_visibility_own: Issues created by or assigned to the user - field_issues_visibility: Issues visibility - label_issues_visibility_all: All issues - permission_set_own_issues_private: Set own issues public or private - field_is_private: Private - permission_set_issues_private: Set issues public or private - label_issues_visibility_public: All non private issues - text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + label_issue_note_added: 问题备注已添加 + label_issue_status_updated: 问题状态更新 + label_issue_priority_updated: 问题优先级更新 + label_issues_visibility_own: 创建或分配给用户的问题 + field_issues_visibility: 问题可见 + label_issues_visibility_all: 全部问题 + permission_set_own_issues_private: 设置自己的问题为公开或私有 + field_is_private: 私有 + permission_set_issues_private: 设置问题为公开或私有 + label_issues_visibility_public: 全部非私有问题 + text_issues_destroy_descendants_confirmation: 此操作同时会删除 %{count} 个子任务。 field_commit_logs_encoding: 提交注释的编码 - field_scm_path_encoding: Path encoding - text_scm_path_encoding_note: "Default: UTF-8" - field_path_to_repository: Path to repository - field_root_directory: Root directory - field_cvs_module: Module + field_scm_path_encoding: 路径编码 + text_scm_path_encoding_note: "默认: UTF-8" + field_path_to_repository: 库路径 + field_root_directory: 根目录 + field_cvs_module: CVS Module field_cvsroot: CVSROOT - text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) - text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) - text_scm_command: Command - text_scm_command_version: Version - label_git_report_last_commit: Report last commit for files and directories - text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. - text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. + text_mercurial_repository_note: 本地库 (e.g. /hgrepo, c:\hgrepo) + text_scm_command: 命令 + text_scm_command_version: 版本 + label_git_report_last_commit: 报告最后一次文件/目录提交 + text_scm_config: 您可以在config/configuration.yml中配置您的SCM命令。 请在编辑后,重启Redmine应用。 + text_scm_command_not_available: Scm命令不可用。 请检查管理面板的配置。 + text_git_repository_note: 库中无内容。(e.g. /gitrepo, c:\gitrepo) + notice_issue_successful_create: 问题 %{id} 已创建。 + label_between: 介于 + setting_issue_group_assignment: 允许问题被分配给组 + label_diff: diff + description_query_sort_criteria_direction: 排序方式 + description_project_scope: 搜索范围 + description_filter: 过滤器 + description_user_mail_notification: 邮件通知设置 + description_date_from: 输入开始日期 + description_message_content: 信息内容 + description_available_columns: 备选列 + description_date_range_interval: 按开始日期和结束日期选择范围 + description_issue_category_reassign: 选择问题类别 + description_search: 搜索字段 + description_notes: 批注 + description_date_range_list: 从列表中选择范围 + description_choose_project: 项目 + description_date_to: 输入结束日期 + description_query_sort_criteria_attribute: 排序方式 + description_wiki_subpages_reassign: 选择父页面 + description_selected_columns: 已选列 + label_parent_revision: 父修订 + label_child_revision: 子修订 + error_scm_annotate_big_text_file: 输入文本内容超长,无法输入。 + setting_default_issue_start_date_to_creation_date: 使用当前日期作为新问题的开始日期 + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) diff -r 487d96eac004 -r 5e80956cc792 config/routes.rb --- a/config/routes.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/config/routes.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ ActionController::Routing::Routes.draw do |map| # Add your own custom routes here. # The priority is based upon order of creation: first created -> highest priority. - + # Here's a sample route: # map.connect 'products/:id', :controller => 'catalog', :action => 'view' # Keep in mind you can assign values other than :controller and :action map.home '', :controller => 'welcome' - + map.signin 'login', :controller => 'account', :action => 'login' map.signout 'logout', :controller => 'account', :action => 'logout' - + map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow' map.connect 'help/:ctrl/:page', :controller => 'help' @@ -31,11 +31,11 @@ :controller => 'context_menus', :action => 'time_entries' # TODO: wasteful since this is also nested under issues, projects, and projects/issues map.resources :time_entries, :controller => 'timelog' - + map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post} map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get} map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post} - + map.with_options :controller => 'messages' do |messages_routes| messages_routes.with_options :conditions => {:method => :get} do |messages_views| messages_views.connect 'boards/:board_id/topics/new', :action => 'new' @@ -48,7 +48,7 @@ messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/ end end - + map.with_options :controller => 'boards' do |board_routes| board_routes.with_options :conditions => {:method => :get} do |board_views| board_views.connect 'projects/:project_id/boards', :action => 'index' @@ -62,7 +62,7 @@ board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/ end end - + map.with_options :controller => 'documents' do |document_routes| document_routes.with_options :conditions => {:method => :get} do |document_views| document_views.connect 'projects/:project_id/documents', :action => 'index' @@ -77,9 +77,10 @@ end map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move' + map.resources :queries, :except => [:show] # Misc issue routes. TODO: move into resources - map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues' + map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues', :conditions => { :method => :get } map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues' map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index' @@ -93,7 +94,7 @@ gantts_routes.connect '/projects/:project_id/issues/gantt.:format' gantts_routes.connect '/issues/gantt.:format' end - + map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes| calendars_routes.connect '/projects/:project_id/issues/calendar' calendars_routes.connect '/issues/calendar' @@ -107,25 +108,21 @@ # Following two routes conflict with the resources because #index allows POST map.connect '/issues', :controller => 'issues', :action => 'index', :conditions => { :method => :post } map.connect '/issues/create', :controller => 'issues', :action => 'index', :conditions => { :method => :post } - + map.resources :issues, :member => { :edit => :post }, :collection => {} do |issues| issues.resources :time_entries, :controller => 'timelog' + issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy] end - + map.resources :issues, :path_prefix => '/projects/:project_id', :collection => { :create => :post } do |issues| issues.resources :time_entries, :controller => 'timelog' end - map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations| - relations.connect 'issues/:issue_id/relations/:id', :action => 'new' - relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy' - end - map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new' map.with_options :controller => 'users' do |users| users.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil, :conditions => {:method => :get} - + users.with_options :conditions => {:method => :post} do |user_actions| user_actions.connect 'users/:id/memberships', :action => 'edit_membership' user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership' @@ -157,9 +154,11 @@ } do |project| project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy] project.resources :files, :only => [:index, :new, :create] - project.resources :versions, :collection => {:close_completed => :put}, :member => {:status_by => :post} + project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post} project.resources :news, :shallow => true project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id' + project.resources :queries, :only => [:new, :create] + project.resources :issue_categories, :shallow => true project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get} project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get} @@ -189,7 +188,7 @@ project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new' end end - + map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity| activity.connect 'projects/:id/activity' activity.connect 'projects/:id/activity.:format' @@ -197,11 +196,6 @@ activity.connect 'activity.:format', :id => nil end - - map.with_options :controller => 'issue_categories' do |categories| - categories.connect 'projects/:project_id/issue_categories/new', :action => 'new' - end - map.with_options :controller => 'repositories' do |repositories| repositories.with_options :conditions => {:method => :get} do |repository_views| repository_views.connect 'projects/:id/repository', :action => 'show' @@ -219,26 +213,30 @@ repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry' repository_views.connect 'projects/:id/repository/:action/*path' end - + repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post} end - map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/ + map.resources :attachments, :only => [:show, :destroy] + # additional routes for having the file name at the end of url map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/ map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/ - - map.resources :groups - + + map.resources :groups, :member => {:autocomplete_for_user => :get} + map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post} + map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete} + + map.resources :trackers, :except => :show + map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post} + #left old routes at the bottom for backwards compat - map.connect 'projects/:project_id/queries/:action', :controller => 'queries' map.connect 'projects/:project_id/issues/:action', :controller => 'issues' map.connect 'projects/:project_id/members/:action', :controller => 'members' map.connect 'projects/:project_id/documents/:action', :controller => 'documents' map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards' map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages' map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki' - map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations' - map.connect 'projects/:project_id/news/:action', :controller => 'news' + map.connect 'projects/:project_id/news/:action', :controller => 'news' map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/ map.with_options :controller => 'repositories' do |omap| omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse' @@ -248,7 +246,7 @@ omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate' omap.connect 'repositories/revision/:id/:rev', :action => 'revision' end - + map.with_options :controller => 'sys' do |sys| sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get} sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post} @@ -256,7 +254,7 @@ sys.connect 'sys/projects/:id/embedded.:format', :action => 'set_embedded_active', :conditions => { :method => :post } sys.connect 'sys/projects/:id/repository_cache.:format', :action => 'clear_repository_cache', :conditions => {:method => :post} end - + # Install the default route as the lowest priority. map.connect ':controller/:action/:id' map.connect 'robots.txt', :controller => 'welcome', :action => 'robots' diff -r 487d96eac004 -r 5e80956cc792 config/settings.yml --- a/config/settings.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/config/settings.yml Mon Feb 27 13:53:18 2012 +0000 @@ -125,6 +125,10 @@ format: symbol cross_project_issue_relations: default: 0 +issue_group_assignment: + default: 0 +default_issue_start_date_to_creation_date: + default: 1 notified_events: serialized: true default: diff -r 487d96eac004 -r 5e80956cc792 db/migrate/001_setup.rb --- a/db/migrate/001_setup.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/001_setup.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,35 +5,35 @@ # 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. class Setup < ActiveRecord::Migration - + class User < ActiveRecord::Base; end # model removed class Permission < ActiveRecord::Base; end - - def self.up - create_table "attachments", :force => true do |t| - t.column "container_id", :integer, :default => 0, :null => false - t.column "container_type", :string, :limit => 30, :default => "", :null => false - t.column "filename", :string, :default => "", :null => false - t.column "disk_filename", :string, :default => "", :null => false - t.column "filesize", :integer, :default => 0, :null => false - t.column "content_type", :string, :limit => 60, :default => "" - t.column "digest", :string, :limit => 40, :default => "", :null => false - t.column "downloads", :integer, :default => 0, :null => false - t.column "author_id", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - end + + def self.up + create_table "attachments", :force => true do |t| + t.column "container_id", :integer, :default => 0, :null => false + t.column "container_type", :string, :limit => 30, :default => "", :null => false + t.column "filename", :string, :default => "", :null => false + t.column "disk_filename", :string, :default => "", :null => false + t.column "filesize", :integer, :default => 0, :null => false + t.column "content_type", :string, :limit => 60, :default => "" + t.column "digest", :string, :limit => 40, :default => "", :null => false + t.column "downloads", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end create_table "auth_sources", :force => true do |t| t.column "type", :string, :limit => 30, :default => "", :null => false @@ -49,143 +49,143 @@ t.column "attr_mail", :string, :limit => 30 t.column "onthefly_register", :boolean, :default => false, :null => false end - + create_table "custom_fields", :force => true do |t| - t.column "type", :string, :limit => 30, :default => "", :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "field_format", :string, :limit => 30, :default => "", :null => false - t.column "possible_values", :text - t.column "regexp", :string, :default => "" - t.column "min_length", :integer, :default => 0, :null => false - t.column "max_length", :integer, :default => 0, :null => false + t.column "type", :string, :limit => 30, :default => "", :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "field_format", :string, :limit => 30, :default => "", :null => false + t.column "possible_values", :text + t.column "regexp", :string, :default => "" + t.column "min_length", :integer, :default => 0, :null => false + t.column "max_length", :integer, :default => 0, :null => false t.column "is_required", :boolean, :default => false, :null => false t.column "is_for_all", :boolean, :default => false, :null => false - end - - create_table "custom_fields_projects", :id => false, :force => true do |t| - t.column "custom_field_id", :integer, :default => 0, :null => false - t.column "project_id", :integer, :default => 0, :null => false - end + end + + create_table "custom_fields_projects", :id => false, :force => true do |t| + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + end create_table "custom_fields_trackers", :id => false, :force => true do |t| t.column "custom_field_id", :integer, :default => 0, :null => false t.column "tracker_id", :integer, :default => 0, :null => false end - - create_table "custom_values", :force => true do |t| + + create_table "custom_values", :force => true do |t| t.column "customized_type", :string, :limit => 30, :default => "", :null => false t.column "customized_id", :integer, :default => 0, :null => false - t.column "custom_field_id", :integer, :default => 0, :null => false - t.column "value", :text - end - - create_table "documents", :force => true do |t| - t.column "project_id", :integer, :default => 0, :null => false - t.column "category_id", :integer, :default => 0, :null => false - t.column "title", :string, :limit => 60, :default => "", :null => false - t.column "description", :text - t.column "created_on", :timestamp + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "value", :text end - - add_index "documents", ["project_id"], :name => "documents_project_id" - - create_table "enumerations", :force => true do |t| - t.column "opt", :string, :limit => 4, :default => "", :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - end - - create_table "issue_categories", :force => true do |t| - t.column "project_id", :integer, :default => 0, :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false + + create_table "documents", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "category_id", :integer, :default => 0, :null => false + t.column "title", :string, :limit => 60, :default => "", :null => false + t.column "description", :text + t.column "created_on", :timestamp end - - add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id" - - create_table "issue_histories", :force => true do |t| - t.column "issue_id", :integer, :default => 0, :null => false - t.column "status_id", :integer, :default => 0, :null => false - t.column "author_id", :integer, :default => 0, :null => false - t.column "notes", :text - t.column "created_on", :timestamp - end - - add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" - - create_table "issue_statuses", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "is_closed", :boolean, :default => false, :null => false - t.column "is_default", :boolean, :default => false, :null => false - t.column "html_color", :string, :limit => 6, :default => "FFFFFF", :null => false - end - - create_table "issues", :force => true do |t| - t.column "tracker_id", :integer, :default => 0, :null => false - t.column "project_id", :integer, :default => 0, :null => false - t.column "subject", :string, :default => "", :null => false + + add_index "documents", ["project_id"], :name => "documents_project_id" + + create_table "enumerations", :force => true do |t| + t.column "opt", :string, :limit => 4, :default => "", :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + create_table "issue_categories", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id" + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + create_table "issue_statuses", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "is_closed", :boolean, :default => false, :null => false + t.column "is_default", :boolean, :default => false, :null => false + t.column "html_color", :string, :limit => 6, :default => "FFFFFF", :null => false + end + + create_table "issues", :force => true do |t| + t.column "tracker_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + t.column "subject", :string, :default => "", :null => false t.column "description", :text - t.column "due_date", :date - t.column "category_id", :integer - t.column "status_id", :integer, :default => 0, :null => false - t.column "assigned_to_id", :integer - t.column "priority_id", :integer, :default => 0, :null => false - t.column "fixed_version_id", :integer + t.column "due_date", :date + t.column "category_id", :integer + t.column "status_id", :integer, :default => 0, :null => false + t.column "assigned_to_id", :integer + t.column "priority_id", :integer, :default => 0, :null => false + t.column "fixed_version_id", :integer t.column "author_id", :integer, :default => 0, :null => false - t.column "lock_version", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - add_index "issues", ["project_id"], :name => "issues_project_id" - - create_table "members", :force => true do |t| - t.column "user_id", :integer, :default => 0, :null => false - t.column "project_id", :integer, :default => 0, :null => false - t.column "role_id", :integer, :default => 0, :null => false - t.column "created_on", :timestamp - end - - create_table "news", :force => true do |t| - t.column "project_id", :integer - t.column "title", :string, :limit => 60, :default => "", :null => false - t.column "summary", :string, :limit => 255, :default => "" - t.column "description", :text - t.column "author_id", :integer, :default => 0, :null => false - t.column "created_on", :timestamp + t.column "lock_version", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + t.column "updated_on", :timestamp end - - add_index "news", ["project_id"], :name => "news_project_id" - - create_table "permissions", :force => true do |t| - t.column "controller", :string, :limit => 30, :default => "", :null => false - t.column "action", :string, :limit => 30, :default => "", :null => false - t.column "description", :string, :limit => 60, :default => "", :null => false - t.column "is_public", :boolean, :default => false, :null => false - t.column "sort", :integer, :default => 0, :null => false - t.column "mail_option", :boolean, :default => false, :null => false - t.column "mail_enabled", :boolean, :default => false, :null => false - end - - create_table "permissions_roles", :id => false, :force => true do |t| - t.column "permission_id", :integer, :default => 0, :null => false - t.column "role_id", :integer, :default => 0, :null => false - end - - add_index "permissions_roles", ["role_id"], :name => "permissions_roles_role_id" - - create_table "projects", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "description", :string, :default => "", :null => false - t.column "homepage", :string, :limit => 60, :default => "" + + add_index "issues", ["project_id"], :name => "issues_project_id" + + create_table "members", :force => true do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + create_table "news", :force => true do |t| + t.column "project_id", :integer + t.column "title", :string, :limit => 60, :default => "", :null => false + t.column "summary", :string, :limit => 255, :default => "" + t.column "description", :text + t.column "author_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + add_index "news", ["project_id"], :name => "news_project_id" + + create_table "permissions", :force => true do |t| + t.column "controller", :string, :limit => 30, :default => "", :null => false + t.column "action", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :limit => 60, :default => "", :null => false + t.column "is_public", :boolean, :default => false, :null => false + t.column "sort", :integer, :default => 0, :null => false + t.column "mail_option", :boolean, :default => false, :null => false + t.column "mail_enabled", :boolean, :default => false, :null => false + end + + create_table "permissions_roles", :id => false, :force => true do |t| + t.column "permission_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + end + + add_index "permissions_roles", ["role_id"], :name => "permissions_roles_role_id" + + create_table "projects", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :default => "", :null => false + t.column "homepage", :string, :limit => 60, :default => "" t.column "is_public", :boolean, :default => true, :null => false t.column "parent_id", :integer - t.column "projects_count", :integer, :default => 0 - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - create_table "roles", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - end + t.column "projects_count", :integer, :default => 0 + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + create_table "roles", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + end create_table "tokens", :force => true do |t| t.column "user_id", :integer, :default => 0, :null => false @@ -193,98 +193,98 @@ t.column "value", :string, :limit => 40, :default => "", :null => false t.column "created_on", :datetime, :null => false end - - create_table "trackers", :force => true do |t| - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "is_in_chlog", :boolean, :default => false, :null => false - end - - create_table "users", :force => true do |t| - t.column "login", :string, :limit => 30, :default => "", :null => false - t.column "hashed_password", :string, :limit => 40, :default => "", :null => false - t.column "firstname", :string, :limit => 30, :default => "", :null => false - t.column "lastname", :string, :limit => 30, :default => "", :null => false - t.column "mail", :string, :limit => 60, :default => "", :null => false - t.column "mail_notification", :boolean, :default => true, :null => false - t.column "admin", :boolean, :default => false, :null => false - t.column "status", :integer, :default => 1, :null => false - t.column "last_login_on", :datetime + + create_table "trackers", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "is_in_chlog", :boolean, :default => false, :null => false + end + + create_table "users", :force => true do |t| + t.column "login", :string, :limit => 30, :default => "", :null => false + t.column "hashed_password", :string, :limit => 40, :default => "", :null => false + t.column "firstname", :string, :limit => 30, :default => "", :null => false + t.column "lastname", :string, :limit => 30, :default => "", :null => false + t.column "mail", :string, :limit => 60, :default => "", :null => false + t.column "mail_notification", :boolean, :default => true, :null => false + t.column "admin", :boolean, :default => false, :null => false + t.column "status", :integer, :default => 1, :null => false + t.column "last_login_on", :datetime t.column "language", :string, :limit => 2, :default => "" - t.column "auth_source_id", :integer - t.column "created_on", :timestamp - t.column "updated_on", :timestamp - end - - create_table "versions", :force => true do |t| - t.column "project_id", :integer, :default => 0, :null => false - t.column "name", :string, :limit => 30, :default => "", :null => false - t.column "description", :string, :default => "" - t.column "effective_date", :date - t.column "created_on", :timestamp - t.column "updated_on", :timestamp + t.column "auth_source_id", :integer + t.column "created_on", :timestamp + t.column "updated_on", :timestamp end - - add_index "versions", ["project_id"], :name => "versions_project_id" - - create_table "workflows", :force => true do |t| - t.column "tracker_id", :integer, :default => 0, :null => false - t.column "old_status_id", :integer, :default => 0, :null => false - t.column "new_status_id", :integer, :default => 0, :null => false - t.column "role_id", :integer, :default => 0, :null => false - end - - # project - Permission.create :controller => "projects", :action => "show", :description => "label_overview", :sort => 100, :is_public => true - Permission.create :controller => "projects", :action => "changelog", :description => "label_change_log", :sort => 105, :is_public => true - Permission.create :controller => "reports", :action => "issue_report", :description => "label_report_plural", :sort => 110, :is_public => true - Permission.create :controller => "projects", :action => "settings", :description => "label_settings", :sort => 150 - Permission.create :controller => "projects", :action => "edit", :description => "button_edit", :sort => 151 - # members - Permission.create :controller => "projects", :action => "list_members", :description => "button_list", :sort => 200, :is_public => true - Permission.create :controller => "projects", :action => "add_member", :description => "button_add", :sort => 220 - Permission.create :controller => "members", :action => "edit", :description => "button_edit", :sort => 221 - Permission.create :controller => "members", :action => "destroy", :description => "button_delete", :sort => 222 - # versions - Permission.create :controller => "projects", :action => "add_version", :description => "button_add", :sort => 320 - Permission.create :controller => "versions", :action => "edit", :description => "button_edit", :sort => 321 - Permission.create :controller => "versions", :action => "destroy", :description => "button_delete", :sort => 322 - # issue categories - Permission.create :controller => "projects", :action => "add_issue_category", :description => "button_add", :sort => 420 - Permission.create :controller => "issue_categories", :action => "edit", :description => "button_edit", :sort => 421 - Permission.create :controller => "issue_categories", :action => "destroy", :description => "button_delete", :sort => 422 - # issues - Permission.create :controller => "projects", :action => "list_issues", :description => "button_list", :sort => 1000, :is_public => true + + create_table "versions", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :default => "" + t.column "effective_date", :date + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + add_index "versions", ["project_id"], :name => "versions_project_id" + + create_table "workflows", :force => true do |t| + t.column "tracker_id", :integer, :default => 0, :null => false + t.column "old_status_id", :integer, :default => 0, :null => false + t.column "new_status_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + end + + # project + Permission.create :controller => "projects", :action => "show", :description => "label_overview", :sort => 100, :is_public => true + Permission.create :controller => "projects", :action => "changelog", :description => "label_change_log", :sort => 105, :is_public => true + Permission.create :controller => "reports", :action => "issue_report", :description => "label_report_plural", :sort => 110, :is_public => true + Permission.create :controller => "projects", :action => "settings", :description => "label_settings", :sort => 150 + Permission.create :controller => "projects", :action => "edit", :description => "button_edit", :sort => 151 + # members + Permission.create :controller => "projects", :action => "list_members", :description => "button_list", :sort => 200, :is_public => true + Permission.create :controller => "projects", :action => "add_member", :description => "button_add", :sort => 220 + Permission.create :controller => "members", :action => "edit", :description => "button_edit", :sort => 221 + Permission.create :controller => "members", :action => "destroy", :description => "button_delete", :sort => 222 + # versions + Permission.create :controller => "projects", :action => "add_version", :description => "button_add", :sort => 320 + Permission.create :controller => "versions", :action => "edit", :description => "button_edit", :sort => 321 + Permission.create :controller => "versions", :action => "destroy", :description => "button_delete", :sort => 322 + # issue categories + Permission.create :controller => "projects", :action => "add_issue_category", :description => "button_add", :sort => 420 + Permission.create :controller => "issue_categories", :action => "edit", :description => "button_edit", :sort => 421 + Permission.create :controller => "issue_categories", :action => "destroy", :description => "button_delete", :sort => 422 + # issues + Permission.create :controller => "projects", :action => "list_issues", :description => "button_list", :sort => 1000, :is_public => true Permission.create :controller => "projects", :action => "export_issues_csv", :description => "label_export_csv", :sort => 1001, :is_public => true - Permission.create :controller => "issues", :action => "show", :description => "button_view", :sort => 1005, :is_public => true - Permission.create :controller => "issues", :action => "download", :description => "button_download", :sort => 1010, :is_public => true - Permission.create :controller => "projects", :action => "add_issue", :description => "button_add", :sort => 1050, :mail_option => 1, :mail_enabled => 1 - Permission.create :controller => "issues", :action => "edit", :description => "button_edit", :sort => 1055 - Permission.create :controller => "issues", :action => "change_status", :description => "label_change_status", :sort => 1060, :mail_option => 1, :mail_enabled => 1 - Permission.create :controller => "issues", :action => "destroy", :description => "button_delete", :sort => 1065 - Permission.create :controller => "issues", :action => "add_attachment", :description => "label_attachment_new", :sort => 1070 - Permission.create :controller => "issues", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1075 - # news - Permission.create :controller => "projects", :action => "list_news", :description => "button_list", :sort => 1100, :is_public => true - Permission.create :controller => "news", :action => "show", :description => "button_view", :sort => 1101, :is_public => true - Permission.create :controller => "projects", :action => "add_news", :description => "button_add", :sort => 1120 - Permission.create :controller => "news", :action => "edit", :description => "button_edit", :sort => 1121 - Permission.create :controller => "news", :action => "destroy", :description => "button_delete", :sort => 1122 + Permission.create :controller => "issues", :action => "show", :description => "button_view", :sort => 1005, :is_public => true + Permission.create :controller => "issues", :action => "download", :description => "button_download", :sort => 1010, :is_public => true + Permission.create :controller => "projects", :action => "add_issue", :description => "button_add", :sort => 1050, :mail_option => 1, :mail_enabled => 1 + Permission.create :controller => "issues", :action => "edit", :description => "button_edit", :sort => 1055 + Permission.create :controller => "issues", :action => "change_status", :description => "label_change_status", :sort => 1060, :mail_option => 1, :mail_enabled => 1 + Permission.create :controller => "issues", :action => "destroy", :description => "button_delete", :sort => 1065 + Permission.create :controller => "issues", :action => "add_attachment", :description => "label_attachment_new", :sort => 1070 + Permission.create :controller => "issues", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1075 + # news + Permission.create :controller => "projects", :action => "list_news", :description => "button_list", :sort => 1100, :is_public => true + Permission.create :controller => "news", :action => "show", :description => "button_view", :sort => 1101, :is_public => true + Permission.create :controller => "projects", :action => "add_news", :description => "button_add", :sort => 1120 + Permission.create :controller => "news", :action => "edit", :description => "button_edit", :sort => 1121 + Permission.create :controller => "news", :action => "destroy", :description => "button_delete", :sort => 1122 # documents - Permission.create :controller => "projects", :action => "list_documents", :description => "button_list", :sort => 1200, :is_public => true - Permission.create :controller => "documents", :action => "show", :description => "button_view", :sort => 1201, :is_public => true - Permission.create :controller => "documents", :action => "download", :description => "button_download", :sort => 1202, :is_public => true - Permission.create :controller => "projects", :action => "add_document", :description => "button_add", :sort => 1220 - Permission.create :controller => "documents", :action => "edit", :description => "button_edit", :sort => 1221 - Permission.create :controller => "documents", :action => "destroy", :description => "button_delete", :sort => 1222 - Permission.create :controller => "documents", :action => "add_attachment", :description => "label_attachment_new", :sort => 1223 - Permission.create :controller => "documents", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1224 - # files - Permission.create :controller => "projects", :action => "list_files", :description => "button_list", :sort => 1300, :is_public => true - Permission.create :controller => "versions", :action => "download", :description => "button_download", :sort => 1301, :is_public => true - Permission.create :controller => "projects", :action => "add_file", :description => "button_add", :sort => 1320 - Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322 - - # create default administrator account + Permission.create :controller => "projects", :action => "list_documents", :description => "button_list", :sort => 1200, :is_public => true + Permission.create :controller => "documents", :action => "show", :description => "button_view", :sort => 1201, :is_public => true + Permission.create :controller => "documents", :action => "download", :description => "button_download", :sort => 1202, :is_public => true + Permission.create :controller => "projects", :action => "add_document", :description => "button_add", :sort => 1220 + Permission.create :controller => "documents", :action => "edit", :description => "button_edit", :sort => 1221 + Permission.create :controller => "documents", :action => "destroy", :description => "button_delete", :sort => 1222 + Permission.create :controller => "documents", :action => "add_attachment", :description => "label_attachment_new", :sort => 1223 + Permission.create :controller => "documents", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1224 + # files + Permission.create :controller => "projects", :action => "list_files", :description => "button_list", :sort => 1300, :is_public => true + Permission.create :controller => "versions", :action => "download", :description => "button_download", :sort => 1301, :is_public => true + Permission.create :controller => "projects", :action => "add_file", :description => "button_add", :sort => 1320 + Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322 + + # create default administrator account user = User.create :login => "admin", :hashed_password => "d033e22ae348aeb5660fc2140aec35850c4da997", :admin => true, @@ -296,29 +296,29 @@ :status => 1 end - def self.down + def self.down drop_table :attachments - drop_table :auth_sources - drop_table :custom_fields + drop_table :auth_sources + drop_table :custom_fields drop_table :custom_fields_projects - drop_table :custom_fields_trackers - drop_table :custom_values - drop_table :documents - drop_table :enumerations - drop_table :issue_categories - drop_table :issue_histories - drop_table :issue_statuses - drop_table :issues - drop_table :members - drop_table :news - drop_table :permissions - drop_table :permissions_roles - drop_table :projects - drop_table :roles - drop_table :trackers + drop_table :custom_fields_trackers + drop_table :custom_values + drop_table :documents + drop_table :enumerations + drop_table :issue_categories + drop_table :issue_histories + drop_table :issue_statuses + drop_table :issues + drop_table :members + drop_table :news + drop_table :permissions + drop_table :permissions_roles + drop_table :projects + drop_table :roles + drop_table :trackers drop_table :tokens - drop_table :users - drop_table :versions + drop_table :users + drop_table :versions drop_table :workflows end end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/007_create_journals.rb --- a/db/migrate/007_create_journals.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/007_create_journals.rb Mon Feb 27 13:53:18 2012 +0000 @@ -4,7 +4,7 @@ class IssueHistory < ActiveRecord::Base; belongs_to :issue; end # model removed class Permission < ActiveRecord::Base; end - + def self.up create_table :journals, :force => true do |t| t.column "journalized_id", :integer, :default => 0, :null => false @@ -20,19 +20,19 @@ t.column "old_value", :string t.column "value", :string end - + # indexes add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" - + Permission.create :controller => "issues", :action => "history", :description => "label_history", :sort => 1006, :is_public => true, :mail_option => 0, :mail_enabled => 0 # data migration IssueHistory.find(:all, :include => :issue).each {|h| j = Journal.new(:journalized => h.issue, :user_id => h.author_id, :notes => h.notes, :created_on => h.created_on) j.details << JournalDetail.new(:property => 'attr', :prop_key => 'status_id', :value => h.status_id) - j.save - } + j.save + } drop_table :issue_histories end @@ -40,7 +40,7 @@ def self.down drop_table :journal_details drop_table :journals - + create_table "issue_histories", :force => true do |t| t.column "issue_id", :integer, :default => 0, :null => false t.column "status_id", :integer, :default => 0, :null => false @@ -48,7 +48,7 @@ t.column "notes", :text, :default => "" t.column "created_on", :timestamp end - + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" Permission.find(:first, :conditions => ["controller=? and action=?", 'issues', 'history']).destroy diff -r 487d96eac004 -r 5e80956cc792 db/migrate/027_create_wikis.rb --- a/db/migrate/027_create_wikis.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/027_create_wikis.rb Mon Feb 27 13:53:18 2012 +0000 @@ -4,7 +4,7 @@ t.column :project_id, :integer, :null => false t.column :start_page, :string, :limit => 255, :null => false t.column :status, :integer, :default => 1, :null => false - end + end add_index :wikis, :project_id, :name => :wikis_project_id end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/028_create_wiki_pages.rb --- a/db/migrate/028_create_wiki_pages.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/028_create_wiki_pages.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,7 +3,7 @@ create_table :wiki_pages do |t| t.column :wiki_id, :integer, :null => false t.column :title, :string, :limit => 255, :null => false - t.column :created_on, :datetime, :null => false + t.column :created_on, :datetime, :null => false end add_index :wiki_pages, [:wiki_id, :title], :name => :wiki_pages_wiki_id_title end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/029_create_wiki_contents.rb --- a/db/migrate/029_create_wiki_contents.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/029_create_wiki_contents.rb Mon Feb 27 13:53:18 2012 +0000 @@ -9,7 +9,7 @@ t.column :version, :integer, :null => false end add_index :wiki_contents, :page_id, :name => :wiki_contents_page_id - + create_table :wiki_content_versions do |t| t.column :wiki_content_id, :integer, :null => false t.column :page_id, :integer, :null => false diff -r 487d96eac004 -r 5e80956cc792 db/migrate/055_add_repositories_type.rb --- a/db/migrate/055_add_repositories_type.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/055_add_repositories_type.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,6 +1,6 @@ class AddRepositoriesType < ActiveRecord::Migration def self.up - add_column :repositories, :type, :string + add_column :repositories, :type, :string # Set class name for existing SVN repositories Repository.update_all "type = 'Subversion'" end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/062_insert_builtin_roles.rb --- a/db/migrate/062_insert_builtin_roles.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/062_insert_builtin_roles.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,10 +3,10 @@ nonmember = Role.new(:name => 'Non member', :position => 0) nonmember.builtin = Role::BUILTIN_NON_MEMBER nonmember.save - + anonymous = Role.new(:name => 'Anonymous', :position => 0) anonymous.builtin = Role::BUILTIN_ANONYMOUS - anonymous.save + anonymous.save end def self.down diff -r 487d96eac004 -r 5e80956cc792 db/migrate/068_create_enabled_modules.rb --- a/db/migrate/068_create_enabled_modules.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/068_create_enabled_modules.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,7 +5,7 @@ t.column :name, :string, :null => false end add_index :enabled_modules, [:project_id], :name => :enabled_modules_project_id - + # Enable all modules for existing projects Project.find(:all).each do |project| project.enabled_module_names = Redmine::AccessControl.available_project_modules diff -r 487d96eac004 -r 5e80956cc792 db/migrate/081_create_projects_trackers.rb --- a/db/migrate/081_create_projects_trackers.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/081_create_projects_trackers.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,7 +5,7 @@ t.column :tracker_id, :integer, :default => 0, :null => false end add_index :projects_trackers, :project_id, :name => :projects_trackers_project_id - + # Associates all trackers to all projects (as it was before) tracker_ids = Tracker.find(:all).collect(&:id) Project.find(:all).each do |project| diff -r 487d96eac004 -r 5e80956cc792 db/migrate/096_add_commit_access_permission.rb --- a/db/migrate/096_add_commit_access_permission.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/096_add_commit_access_permission.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,14 +1,13 @@ class AddCommitAccessPermission < ActiveRecord::Migration - def self.up - Role.find(:all).select { |r| not r.builtin? }.each do |r| - r.add_permission!(:commit_access) - end + Role.find(:all).select { |r| not r.builtin? }.each do |r| + r.add_permission!(:commit_access) + end end def self.down - Role.find(:all).select { |r| not r.builtin? }.each do |r| - r.remove_permission!(:commit_access) - end + Role.find(:all).select { |r| not r.builtin? }.each do |r| + r.remove_permission!(:commit_access) + end end end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/097_add_view_wiki_edits_permission.rb --- a/db/migrate/097_add_view_wiki_edits_permission.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/097_add_view_wiki_edits_permission.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,13 +1,13 @@ class AddViewWikiEditsPermission < ActiveRecord::Migration def self.up - Role.find(:all).each do |r| - r.add_permission!(:view_wiki_edits) if r.has_permission?(:view_wiki_pages) - end + Role.find(:all).each do |r| + r.add_permission!(:view_wiki_edits) if r.has_permission?(:view_wiki_pages) + end end def self.down - Role.find(:all).each do |r| - r.remove_permission!(:view_wiki_edits) - end + Role.find(:all).each do |r| + r.remove_permission!(:view_wiki_edits) + end end end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/099_add_delete_wiki_pages_attachments_permission.rb --- a/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,13 +1,13 @@ class AddDeleteWikiPagesAttachmentsPermission < ActiveRecord::Migration def self.up - Role.find(:all).each do |r| - r.add_permission!(:delete_wiki_pages_attachments) if r.has_permission?(:edit_wiki_pages) - end + Role.find(:all).each do |r| + r.add_permission!(:delete_wiki_pages_attachments) if r.has_permission?(:edit_wiki_pages) + end end def self.down - Role.find(:all).each do |r| - r.remove_permission!(:delete_wiki_pages_attachments) - end + Role.find(:all).each do |r| + r.remove_permission!(:delete_wiki_pages_attachments) + end end end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/20100313132032_add_issues_nested_sets_columns.rb --- a/db/migrate/20100313132032_add_issues_nested_sets_columns.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/20100313132032_add_issues_nested_sets_columns.rb Mon Feb 27 13:53:18 2012 +0000 @@ -4,7 +4,7 @@ add_column :issues, :root_id, :integer, :default => nil add_column :issues, :lft, :integer, :default => nil add_column :issues, :rgt, :integer, :default => nil - + Issue.update_all("parent_id = NULL, root_id = id, lft = 1, rgt = 2") end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/20100705164950_change_changes_path_length_limit.rb --- a/db/migrate/20100705164950_change_changes_path_length_limit.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/20100705164950_change_changes_path_length_limit.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,7 +3,7 @@ # these are two steps to please MySQL 5 on Win32 change_column :changes, :path, :text, :default => nil, :null => true change_column :changes, :path, :text, :null => false - + change_column :changes, :from_path, :text end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/20101104182107_add_unique_index_on_members.rb --- a/db/migrate/20101104182107_add_unique_index_on_members.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/db/migrate/20101104182107_add_unique_index_on_members.rb Mon Feb 27 13:53:18 2012 +0000 @@ -11,7 +11,7 @@ " WHERE m.id > (SELECT min(m1.id) FROM #{Member.table_name} m1 WHERE m1.user_id = m.user_id AND m1.project_id = m.project_id)").each do |i| Member.delete_all(["id = ?", i]) end - + # Then add a unique index add_index :members, [:user_id, :project_id], :unique => true end diff -r 487d96eac004 -r 5e80956cc792 db/migrate/20110902000000_create_changeset_parents.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/db/migrate/20110902000000_create_changeset_parents.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,14 @@ +class CreateChangesetParents < ActiveRecord::Migration + def self.up + create_table :changeset_parents, :id => false do |t| + t.column :changeset_id, :integer, :null => false + t.column :parent_id, :integer, :null => false + end + add_index :changeset_parents, [:changeset_id], :unique => false, :name => :changeset_parents_changeset_ids + add_index :changeset_parents, [:parent_id], :unique => false, :name => :changeset_parents_parent_ids + end + + def self.down + drop_table :changeset_parents + end +end diff -r 487d96eac004 -r 5e80956cc792 doc/CHANGELOG --- a/doc/CHANGELOG Fri Feb 24 20:18:25 2012 +0000 +++ b/doc/CHANGELOG Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,147 @@ == Redmine changelog Redmine - project management software -Copyright (C) 2006-2011 Jean-Philippe Lang +Copyright (C) 2006-2012 Jean-Philippe Lang http://www.redmine.org/ +== 2012-02-06 v1.3.1 + +* Defect #9775: app/views/repository/_revision_graph.html.erb sets window.onload directly.. +* Defect #9792: Ruby 1.9: [v1.3.0] Error: incompatible character encodings for it translation on Calendar page +* Defect #9793: Bad spacing between numbered list and heading (recently broken). +* Defect #9795: Unrelated error message when creating a group with an invalid name +* Defect #9832: Revision graph height should depend on height of rows in revisions table +* Defect #9937: Repository settings are not saved when all SCM are disabled +* Defect #9961: Ukrainian "default_tracker_bug" is wrong +* Defect #10013: Rest API - Create Version -> Internal server error 500 +* Defect #10115: Javascript error - Can't attach more than 1 file on IE 6 and 7 +* Defect #10130: Broken italic text style in edited comment preview +* Defect #10152: Attachment diff type is not saved in user preference +* Feature #9943: Arabic translation +* Patch #9874: pt-BR translation updates +* Patch #9922: Spanish translation updated +* Patch #10137: Korean language file ko.yml updated to Redmine 1.3.0 + +== 2011-12-10 v1.3.0 + +* Defect #2109: Context menu is being submitted twice per right click +* Defect #7717: MailHandler user creation for unknown_user impossible due to diverging length-limits of login and email fields +* Defect #7917: Creating users via email fails if user real name containes special chars +* Defect #7966: MailHandler does not include JournalDetail for attached files +* Defect #8368: Bad decimal separator in time entry CSV +* Defect #8371: MySQL error when filtering a custom field using the REST api +* Defect #8549: Export CSV has character encoding error +* Defect #8573: Do not show inactive Enumerations where not needed +* Defect #8611: rake/rdoctask is deprecated +* Defect #8751: Email notification: bug, when number of recipients more then 8 +* Defect #8894: Private issues - make it more obvious in the UI? +* Defect #8994: Hardcoded French string "anonyme" +* Defect #9043: Hardcoded string "diff" in Wiki#show and Repositories_Helper +* Defect #9051: wrong "text_issue_added" in russian translation. +* Defect #9108: Custom query not saving status filter +* Defect #9252: Regression: application title escaped 2 times +* Defect #9264: Bad Portuguese translation +* Defect #9470: News list is missing Avatars +* Defect #9471: Inline markup broken in Wiki link labels +* Defect #9489: Label all input field and control tags +* Defect #9534: Precedence: bulk email header is non standard and discouraged +* Defect #9540: Issue filter by assigned_to_role is not project specific +* Defect #9619: Time zone ignored when logging time while editing ticket +* Defect #9638: Inconsistent image filename extensions +* Defect #9669: Issue list doesn't sort assignees/authors regarding user display format +* Defect #9672: Message-quoting in forums module broken +* Defect #9719: Filtering by numeric custom field types broken after update to master +* Defect #9724: Can't remote add new categories +* Defect #9738: Setting of cross-project custom query is not remembered inside project +* Defect #9748: Error about configuration.yml validness should mention file path +* Feature #69: Textilized description in PDF +* Feature #401: Add pdf export for WIKI page +* Feature #1567: Make author column sortable and groupable +* Feature #2222: Single section edit. +* Feature #2269: Default issue start date should become configurable. +* Feature #2371: character encoding for attachment file +* Feature #2964: Ability to assign issues to groups +* Feature #3033: Bug Reporting: Using "Create and continue" should show bug id of saved bug +* Feature #3261: support attachment images in PDF export +* Feature #4264: Update CodeRay to 1.0 final +* Feature #4324: Redmine renames my files, it shouldn't. +* Feature #4729: Add Date-Based Filters for Issues List +* Feature #4742: CSV export: option to export selected or all columns +* Feature #4976: Allow rdm-mailhandler to read the API key from a file +* Feature #5501: Git: Mercurial: Adding visual merge/branch history to repository view +* Feature #5634: Export issue to PDF does not include Subtasks and Related Issues +* Feature #5670: Cancel option for file upload +* Feature #5737: Custom Queries available through the REST Api +* Feature #6180: Searchable custom fields do not provide adequate operators +* Feature #6954: Filter from date to date +* Feature #7180: List of statuses in REST API +* Feature #7181: List of trackers in REST API +* Feature #7366: REST API for Issue Relations +* Feature #7403: REST API for Versions +* Feature #7671: REST API for reading attachments +* Feature #7832: Ability to assign issue categories to groups +* Feature #8420: Consider removing #7013 workaround +* Feature #9196: Improve logging in MailHandler when user creation fails +* Feature #9496: Adds an option in mailhandler to disable server certificate verification +* Feature #9553: CRUD operations for "Issue categories" in REST API +* Feature #9593: HTML title should be reordered +* Feature #9600: Wiki links for news and forums +* Feature #9607: Filter for issues without start date (or any another field based on date type) +* Feature #9609: Upgrade to Rails 2.3.14 +* Feature #9612: "side by side" and "inline" patch view for attachments +* Feature #9667: Check attachment size before upload +* Feature #9690: Link in notification pointing to the actual update +* Feature #9720: Add note number for single issue's PDF +* Patch #8617: Indent subject of subtask ticket in exported issues PDF +* Patch #8778: Traditional Chinese 'issue' translation change +* Patch #9053: Fix up Russian translation +* Patch #9129: Improve wording of Git repository note at project setting +* Patch #9148: Better handling of field_due_date italian translation +* Patch #9273: Fix typos in russian localization +* Patch #9484: Limit SCM annotate to text files under the maximum file size for viewing +* Patch #9659: Indexing rows in auth_sources/index view +* Patch #9692: Fix Textilized description in PDF for CodeRay + +== 2011-12-10 v1.2.3 + +* Defect #8707: Reposman: wrong constant name +* Defect #8809: Table in timelog report overflows +* Defect #9055: Version files in Files module cannot be downloaded if issue tracking is disabled +* Defect #9137: db:encrypt fails to handle repositories with blank password +* Defect #9394: Custom date field only validating on regex and not a valid date +* Defect #9405: Any user with :log_time permission can edit time entries via context menu +* Defect #9448: The attached images are not shown in documents +* Defect #9520: Copied private query not visible after project copy +* Defect #9552: Error when reading ciphered text from the database without cipher key configured +* Defect #9566: Redmine.pm considers all projects private when login_required is enabled +* Defect #9567: Redmine.pm potential security issue with cache credential enabled and subversion +* Defect #9577: Deleting a subtasks doesn't update parent's rgt & lft values +* Defect #9597: Broken version links in wiki annotate history +* Defect #9682: Wiki HTML Export only useful when Access history is accessible +* Defect #9737: Custom values deleted before issue submit +* Defect #9741: calendar-hr.js (Croatian) is not UTF-8 +* Patch #9558: Simplified Chinese translation for 1.2.2 updated +* Patch #9695: Bulgarian translation (r7942) + +== 2011-11-11 v1.2.2 + +* Defect #3276: Incorrect handling of anchors in Wiki to HTML export +* Defect #7215: Wiki formatting mangles links to internal headers +* Defect #7613: Generated test instances may share the same attribute value object +* Defect #8411: Can't remove "Project" column on custom query +* Defect #8615: Custom 'version' fields don't show shared versions +* Defect #8633: Pagination counts non visible issues +* Defect #8651: Email attachments are not added to issues any more in v1.2 +* Defect #8825: JRuby + Windows: SCMs do not work on Redmine 1.2 +* Defect #8836: Additional workflow transitions not available when set to both author and assignee +* Defect #8865: Custom field regular expression is not validated +* Defect #8880: Error deleting issue with grandchild +* Defect #8884: Assignee is cleared when updating issue with locked assignee +* Defect #8892: Unused fonts in rfpdf plugin folder +* Defect #9161: pt-BR field_warn_on_leaving_unsaved has a small gramatical error +* Defect #9308: Search fails when a role haven't "view wiki" permission +* Defect #9465: Mercurial: can't browse named branch below Mercurial 1.5 + == 2011-07-11 v1.2.1 * Defect #5089: i18N error on truncated revision diff view @@ -417,7 +555,7 @@ * #819: Add a body ID and class to all pages * #871: Commit new CSS styles! * #3301: Add favicon to base layout -* #4656: On Issue#show page, clicking on “Add related issue” should focus on the input +* #4656: On Issue#show page, clicking on “Add related issueâ€� should focus on the input * #4896: Project identifier should be a limited field * #5084: Filter all isssues by projects * #5477: Replace Test::Unit::TestCase with ActiveSupport::TestCase @@ -1426,7 +1564,7 @@ * Search engines now supports pagination. Results are sorted in reverse chronological order * Added "Estimated hours" attribute on issues * A category with assigned issue can now be deleted. 2 options are proposed: remove assignments or reassign issues to another category -* Forum notifications are now also sent to the authors of the thread, even if they don�t watch the board +* Forum notifications are now also sent to the authors of the thread, even if they don�t watch the board * Added an application setting to specify the application protocol (http or https) used to generate urls in emails * Gantt chart: now starts at the current month by default * Gantt chart: month count and zoom factor are automatically saved as user preferences @@ -1434,7 +1572,7 @@ * Added wiki index by date * Added preview on add/edit issue form * Emails footer can now be customized from the admin interface (Admin -> Email notifications) -* Default encodings for repository files can now be set in application settings (used to convert files content and diff to UTF-8 so that they�re properly displayed) +* Default encodings for repository files can now be set in application settings (used to convert files content and diff to UTF-8 so that they�re properly displayed) * Calendar: first day of week can now be set in lang files * Automatic closing of duplicate issues * Added a cross-project issue list @@ -1446,7 +1584,7 @@ * Added some accesskeys * Added "Float" as a custom field format * Added basic Theme support -* Added the ability to set the �done ratio� of issues fixed by commit (Nikolay Solakov) +* Added the ability to set the �done ratio� of issues fixed by commit (Nikolay Solakov) * Added custom fields in issue related mail notifications * Email notifications are now sent in plain text and html * Gantt chart can now be exported to a graphic file (png). This functionality is only available if RMagick is installed. @@ -1479,7 +1617,7 @@ * Added Korean translation (Choi Jong Yoon) * Fixed: the link to delete issue relations is displayed even if the user is not authorized to delete relations * Performance improvement on calendar and gantt -* Fixed: wiki preview doesn�t work on long entries +* Fixed: wiki preview doesn�t work on long entries * Fixed: queries with multiple custom fields return no result * Fixed: Can not authenticate user against LDAP if its DN contains non-ascii characters * Fixed: URL with ~ broken in wiki formatting @@ -1490,7 +1628,7 @@ * per project forums added * added the ability to archive projects -* added �Watch� functionality on issues. It allows users to receive notifications about issue changes +* added �Watch� functionality on issues. It allows users to receive notifications about issue changes * custom fields for issues can now be used as filters on issue list * added per user custom queries * commit messages are now scanned for referenced or fixed issue IDs (keywords defined in Admin -> Settings) @@ -1531,7 +1669,7 @@ * added swedish translation (Thomas Habets) * italian translation update (Alessio Spadaro) * japanese translation update (Satoru Kurashiki) -* fixed: error on history atom feed when there�s no notes on an issue change +* fixed: error on history atom feed when there�s no notes on an issue change * fixed: error in journalizing an issue with longtext custom fields (Postgresql) * fixed: creation of Oracle schema * fixed: last day of the month not included in project activity diff -r 487d96eac004 -r 5e80956cc792 doc/INSTALL --- a/doc/INSTALL Fri Feb 24 20:18:25 2012 +0000 +++ b/doc/INSTALL Mon Feb 27 13:53:18 2012 +0000 @@ -11,12 +11,12 @@ * RubyGems 1.3.7 -* Ruby on Rails 2.3.11 (official downloadable Redmine releases are packaged with +* Ruby on Rails 2.3.14 (official downloadable Redmine releases are packaged with the appropriate Rails version) -* Rack 1.1.0 gem +* Rack 1.1.2 gem -* Rake 0.8.3 gem +* Rake 0.9.2 gem * I18n 0.4.2 gem diff -r 487d96eac004 -r 5e80956cc792 doc/RUNNING_TESTS --- a/doc/RUNNING_TESTS Fri Feb 24 20:18:25 2012 +0000 +++ b/doc/RUNNING_TESTS Mon Feb 27 13:53:18 2012 +0000 @@ -9,8 +9,9 @@ Run `rake --tasks test` to see available tests. `rake test` will run the entire testsuite. +You can run `ruby test/unit/issue_test.rb` for an each test. -Before running `rake test` you need to configure both development +Before running tests, you need to configure both development and test databases. Creating test repositories diff -r 487d96eac004 -r 5e80956cc792 doc/UPGRADING --- a/doc/UPGRADING Fri Feb 24 20:18:25 2012 +0000 +++ b/doc/UPGRADING Mon Feb 27 13:53:18 2012 +0000 @@ -30,7 +30,7 @@ 6. Migrate your database - If you are upgrading to Rails 2.3.11 as part of this migration, you + If you are upgrading to Rails 2.3.14 as part of this migration, you need to upgrade the plugin migrations before running the plugin migrations using: rake db:migrate:upgrade_plugin_migrations RAILS_ENV="production" @@ -56,7 +56,7 @@ == Notes -* Rails 2.3.11 is required for versions 1.2.x. +* Rails 2.3.14 is required for versions 1.3.x. == References diff -r 487d96eac004 -r 5e80956cc792 extra/mail_handler/rdm-mailhandler.rb --- a/extra/mail_handler/rdm-mailhandler.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/extra/mail_handler/rdm-mailhandler.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,6 +22,11 @@ # create: create a user account # --no-permission-check disable permission checking when receiving # the email +# --key-file=PATH path to a file that contains the Redmine +# API key (use this option instead of --key +# if you don't the key to appear in the +# command line) +# --no-check-certificate do not check server certificate # -h, --help show this help # -v, --verbose show extra information # -V, --version show version information and exit @@ -57,13 +62,16 @@ module Net class HTTPS < HTTP - def self.post_form(url, params, headers) + def self.post_form(url, params, headers, options={}) request = Post.new(url.path) request.form_data = params request.basic_auth url.user, url.password if url.user request.initialize_http_header(headers) http = new(url.host, url.port) http.use_ssl = (url.scheme == 'https') + if options[:no_check_certificate] + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + end http.start {|h| h.request(request) } end end @@ -72,7 +80,7 @@ class RedmineMailHandler VERSION = '0.1' - attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key + attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key, :no_check_certificate def initialize self.issue_attributes = {} @@ -83,6 +91,7 @@ [ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], [ '--url', '-u', GetoptLong::REQUIRED_ARGUMENT ], [ '--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + [ '--key-file', GetoptLong::REQUIRED_ARGUMENT], [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ], [ '--status', '-s', GetoptLong::REQUIRED_ARGUMENT ], [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT], @@ -90,7 +99,8 @@ [ '--priority', GetoptLong::REQUIRED_ARGUMENT], [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT], [ '--unknown-user', GetoptLong::REQUIRED_ARGUMENT], - [ '--no-permission-check', GetoptLong::NO_ARGUMENT] + [ '--no-permission-check', GetoptLong::NO_ARGUMENT], + [ '--no-check-certificate', GetoptLong::NO_ARGUMENT] ) opts.each do |opt, arg| @@ -99,6 +109,13 @@ self.url = arg.dup when '--key' self.key = arg.dup + when '--key-file' + begin + self.key = File.read(arg).strip + rescue Exception => e + $stderr.puts "Unable to read the key from #{arg}: #{e.message}" + exit 1 + end when '--help' usage when '--verbose' @@ -113,6 +130,8 @@ self.unknown_user = arg.dup when '--no-permission-check' self.no_permission_check = '1' + when '--no-check-certificate' + self.no_check_certificate = true end end @@ -131,7 +150,7 @@ issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value } debug "Posting to #{uri}..." - response = Net::HTTPS.post_form(URI.parse(uri), data, headers) + response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate) debug "Response received: #{response.code}" case response.code.to_i diff -r 487d96eac004 -r 5e80956cc792 extra/soundsoftware/reposman-soundsoftware.rb --- a/extra/soundsoftware/reposman-soundsoftware.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/extra/soundsoftware/reposman-soundsoftware.rb Mon Feb 27 13:53:18 2012 +0000 @@ -19,7 +19,8 @@ # -r redmine.example.net # -r http://redmine.example.net # -r https://example.net/redmine -# -k, --key=KEY use KEY as the Redmine API key +# -k, --key=KEY use KEY as the Redmine API key (you can use the +# --key-file option as an alternative) # # == Options # @@ -50,6 +51,9 @@ # and subversion. # --http-user=USER User for HTTP Basic authentication with Redmine WS # --http-pass=PASSWORD Password for Basic authentication with Redmine WS +# --key-file=PATH path to a file that contains the Redmine API key +# (use this option instead of --key if you don't +# the key to appear in the command line) # -t, --test only show what should be done # -h, --help show help and exit # -v, --verbose verbose @@ -73,6 +77,7 @@ ['--scm-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT], ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + ['--key-file', GetoptLong::REQUIRED_ARGUMENT], ['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT], ['--group', '-g', GetoptLong::REQUIRED_ARGUMENT], ['--url', '-u', GetoptLong::REQUIRED_ARGUMENT], @@ -136,6 +141,13 @@ when '--scm-dir'; $repos_base = arg.dup when '--redmine-host'; $redmine_host = arg.dup when '--key'; $api_key = arg.dup + when '--key-file' + begin + $api_key = File.read(arg).strip + rescue Exception => e + $stderr.puts "Unable to read the key from #{arg}: #{e.message}" + exit 1 + end when '--owner'; $svn_owner = arg.dup; $use_groupid = false; when '--group'; $svn_group = arg.dup; $use_groupid = false; when '--url'; $svn_url = arg.dup @@ -185,6 +197,7 @@ class Project < ActiveResource::Base self.headers["User-agent"] = "SoundSoftware repository manager/#{Version}" + self.format = :xml end log("querying Redmine for projects...", :level => 1); @@ -199,12 +212,14 @@ begin # Get all active projects that have the Repository module enabled projects = Project.find(:all, :params => {:key => $api_key}) +rescue ActiveResource::ForbiddenAccess + log("Request was denied by your Redmine server. Make sure that 'WS for repository management' is enabled in application settings and that you provided the correct API key.") rescue => e log("Unable to connect to #{Project.site}: #{e}", :exit => true) end if projects.nil? - log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) + log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) end log("retrieved #{projects.size} projects", :level => 1) diff -r 487d96eac004 -r 5e80956cc792 extra/svn/Redmine.pm --- a/extra/svn/Redmine.pm Fri Feb 24 20:18:25 2012 +0000 +++ b/extra/svn/Redmine.pm Mon Feb 27 13:53:18 2012 +0000 @@ -49,7 +49,7 @@ PerlAccessHandler Apache::Authn::Redmine::access_handler PerlAuthenHandler Apache::Authn::Redmine::authen_handler - + ## for mysql RedmineDSN "DBI:mysql:database=databasename;host=my.db.server" ## for postgres @@ -144,31 +144,32 @@ }, ); -sub RedmineDSN { +sub RedmineDSN { my ($self, $parms, $arg) = @_; $self->{RedmineDSN} = $arg; my $query = "SELECT hashed_password, salt, auth_source_id, permissions - FROM members, projects, users, roles, member_roles + FROM projects, users, roles WHERE - projects.id=members.project_id - AND member_roles.member_id=members.id - AND users.id=members.user_id - AND roles.id=member_roles.role_id + users.login=? + AND projects.identifier=? AND users.status=1 - AND login=? - AND identifier=? "; + AND ( + roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id) + OR + (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1')) + ) "; $self->{RedmineQuery} = trim($query); } sub RedmineDbUser { set_val('RedmineDbUser', @_); } sub RedmineDbPass { set_val('RedmineDbPass', @_); } -sub RedmineDbWhereClause { +sub RedmineDbWhereClause { my ($self, $parms, $arg) = @_; $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." "); } -sub RedmineCacheCredsMax { +sub RedmineCacheCredsMax { my ($self, $parms, $arg) = @_; if ($arg) { $self->{RedmineCachePool} = APR::Pool->new; @@ -208,17 +209,17 @@ my $project_id = get_project_identifier($r); $r->set_handlers(PerlAuthenHandler => [\&OK]) - if is_public_project($project_id, $r); + if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r); return OK } sub authen_handler { my $r = shift; - + my ($res, $redmine_pass) = $r->get_basic_auth_pw(); return $res unless $res == OK; - + if (is_member($r->user, $redmine_pass, $r)) { return OK; } else { @@ -245,7 +246,7 @@ } $sth->finish(); undef $sth; - + $dbh->disconnect(); undef $dbh; @@ -255,7 +256,7 @@ sub is_public_project { my $project_id = shift; my $r = shift; - + if (is_authentication_forced($r)) { return 0; } @@ -280,6 +281,29 @@ $ret; } +sub anonymous_role_allows_browse_repository { + my $r = shift; + + my $dbh = connect_database($r); + my $sth = $dbh->prepare( + "SELECT permissions FROM roles WHERE builtin = 2;" + ); + + $sth->execute(); + my $ret = 0; + if (my @row = $sth->fetchrow_array) { + if ($row[0] =~ /:browse_repository/) { + $ret = 1; + } + } + $sth->finish(); + undef $sth; + $dbh->disconnect(); + undef $dbh; + + $ret; +} + # perhaps we should use repository right (other read right) to check public access. # it could be faster BUT it doesn't work for the moment. # sub is_public_project_by_file { @@ -305,10 +329,12 @@ my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); + my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W"; + my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); my $usrprojpass; if ($cfg->{RedmineCacheCredsMax}) { - $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id); + $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode); return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); } my $query = $cfg->{RedmineQuery}; @@ -321,7 +347,7 @@ unless ($auth_source_id) { my $method = $r->method; my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest); - if ($hashed_password eq $salted_password && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) { + if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) { $ret = 1; last; } @@ -340,7 +366,7 @@ filter => "(".$rowldap[6]."=%s)" ); my $method = $r->method; - $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/)); + $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/)); } $sthldap->finish(); @@ -354,10 +380,10 @@ if ($cfg->{RedmineCacheCredsMax} and $ret) { if (defined $usrprojpass) { - $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest); + $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest); } else { if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) { - $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest); + $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest); $cfg->{RedmineCacheCredsCount}++; } else { $cfg->{RedmineCacheCreds}->clear(); @@ -371,7 +397,7 @@ sub get_project_identifier { my $r = shift; - + my $location = $r->location; my ($identifier) = $r->uri =~ m{$location/*([^/]+)}; $identifier; @@ -379,7 +405,7 @@ sub connect_database { my $r = shift; - + my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass}); } diff -r 487d96eac004 -r 5e80956cc792 extra/svn/reposman.rb --- a/extra/svn/reposman.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/extra/svn/reposman.rb Mon Feb 27 13:53:18 2012 +0000 @@ -19,7 +19,8 @@ # -r redmine.example.net # -r http://redmine.example.net # -r https://example.net/redmine -# -k, --key=KEY use KEY as the Redmine API key +# -k, --key=KEY use KEY as the Redmine API key (you can use the +# --key-file option as an alternative) # # == Options # @@ -52,6 +53,9 @@ # --http-pass=PASSWORD Password for Basic authentication with Redmine WS # -f, --force force repository creation even if the project # repository is already declared in Redmine +# --key-file=PATH path to a file that contains the Redmine API key +# (use this option instead of --key if you don't +# the key to appear in the command line) # -t, --test only show what should be done # -h, --help show help and exit # -v, --verbose verbose @@ -75,6 +79,7 @@ ['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT], ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + ['--key-file', GetoptLong::REQUIRED_ARGUMENT], ['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT], ['--group', '-g', GetoptLong::REQUIRED_ARGUMENT], ['--url', '-u', GetoptLong::REQUIRED_ARGUMENT], @@ -140,6 +145,13 @@ when '--svn-dir'; $repos_base = arg.dup when '--redmine-host'; $redmine_host = arg.dup when '--key'; $api_key = arg.dup + when '--key-file' + begin + $api_key = File.read(arg).strip + rescue Exception => e + $stderr.puts "Unable to read the key from #{arg}: #{e.message}" + exit 1 + end when '--owner'; $svn_owner = arg.dup; $use_groupid = false; when '--group'; $svn_group = arg.dup; $use_groupid = false; when '--url'; $svn_url = arg.dup @@ -190,6 +202,7 @@ class Project < ActiveResource::Base self.headers["User-agent"] = "Redmine repository manager/#{Version}" + self.format = :xml end log("querying Redmine for projects...", :level => 1); @@ -204,12 +217,14 @@ begin # Get all active projects that have the Repository module enabled projects = Project.find(:all, :params => {:key => $api_key}) +rescue ActiveResource::ForbiddenAccess + log("Request was denied by your Redmine server. Make sure that 'WS for repository management' is enabled in application settings and that you provided the correct API key.") rescue => e log("Unable to connect to #{Project.site}: #{e}", :exit => true) end if projects.nil? - log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) + log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) end log("retrieved #{projects.size} projects", :level => 1) diff -r 487d96eac004 -r 5e80956cc792 lib/ar_condition.rb --- a/lib/ar_condition.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/ar_condition.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,28 +1,28 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. class ARCondition attr_reader :conditions - + def initialize(condition=nil) @conditions = ['1=1'] add(condition) if condition end - + def add(condition) if condition.is_a?(Array) @conditions.first << " AND (#{condition.first})" diff -r 487d96eac004 -r 5e80956cc792 lib/diff.rb --- a/lib/diff.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/diff.rb Mon Feb 27 13:53:18 2012 +0000 @@ -9,14 +9,14 @@ afinish = a.length-1 bfinish = b.length-1 mvector = [] - + # First we prune off any common elements at the beginning while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart]) mvector[astart] = bstart astart += 1 bstart += 1 end - + # now the end while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish]) mvector[afinish] = bfinish @@ -27,7 +27,7 @@ bmatches = b.reverse_hash(bstart..bfinish) thresh = [] links = [] - + (astart..afinish).each { |aindex| aelem = a[aindex] next unless bmatches.has_key? aelem @@ -118,7 +118,7 @@ @difftype = diffs_or_a.class end end - + def match(ai, bi) @diffs.push @curdiffs unless @curdiffs.empty? @curdiffs = [] diff -r 487d96eac004 -r 5e80956cc792 lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb --- a/lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb Mon Feb 27 13:53:18 2012 +0000 @@ -14,7 +14,7 @@ end def destination_root - File.join(RAILS_ROOT, plugin_path) + File.join(Rails.root, plugin_path) end def manifest diff -r 487d96eac004 -r 5e80956cc792 lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb --- a/lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb Mon Feb 27 13:53:18 2012 +0000 @@ -14,7 +14,7 @@ end def destination_root - File.join(RAILS_ROOT, plugin_path) + File.join(Rails.root, plugin_path) end def manifest diff -r 487d96eac004 -r 5e80956cc792 lib/redcloth3.rb --- a/lib/redcloth3.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redcloth3.rb Mon Feb 27 13:53:18 2012 +0000 @@ -340,9 +340,9 @@ # A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/ A_VLGN = /[\-^~]/ - C_CLAS = '(?:\([^)]+\))' - C_LNGE = '(?:\[[^\[\]]+\])' - C_STYL = '(?:\{[^}]+\})' + C_CLAS = '(?:\([^")]+\))' + C_LNGE = '(?:\[[^"\[\]]+\])' + C_STYL = '(?:\{[^"}]+\})' S_CSPN = '(?:\\\\\d+)' S_RSPN = '(?:/\d+)' A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)" @@ -938,7 +938,7 @@ stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8] htmlesc title atts = pba( atts ) - atts = " src=\"#{ url }\"#{ atts }" + atts = " src=\"#{ htmlesc url.dup }\"#{ atts }" atts << " title=\"#{ title }\"" if title atts << " alt=\"#{ title }\"" # size = @getimagesize($url); @@ -1058,7 +1058,7 @@ end end - def rip_offtags( text, escape_aftertag=true ) + def rip_offtags( text, escape_aftertag=true, escape_line=true ) if text =~ /<.*>/ ## strip and encode

     content
                 codepre, used_offtags = 0, {}
    @@ -1068,7 +1068,7 @@
                         codepre += 1
                         used_offtags[offtag] = true
                         if codepre - used_offtags.length > 0
    -                        htmlesc( line, :NoQuotes )
    +                        htmlesc( line, :NoQuotes ) if escape_line
                             @pre_list.last << line
                             line = ""
                         else
    @@ -1086,7 +1086,7 @@
                         end
                     elsif $1 and codepre > 0
                         if codepre - used_offtags.length > 0
    -                        htmlesc( line, :NoQuotes )
    +                        htmlesc( line, :NoQuotes ) if escape_line
                             @pre_list.last << line
                             line = ""
                         end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine.rb
    --- a/lib/redmine.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -55,10 +55,10 @@
       map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
       map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
       map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
    -  
    +
       map.project_module :issue_tracking do |map|
         # Issue categories
    -    map.permission :manage_categories, {:projects => :settings, :issue_categories => [:new, :edit, :destroy]}, :require => :member
    +    map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
         # Issues
         map.permission :view_issues, {:issues => [:index, :show],
                                       :auto_complete => [:issues],
    @@ -69,7 +69,7 @@
                                       :reports => [:issue_report, :issue_report_details]}
         map.permission :add_issues, {:issues => [:new, :create, :update_form]}
         map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new]}
    -    map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
    +    map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
         map.permission :manage_subtasks, {}
         map.permission :set_issues_private, {}
         map.permission :set_own_issues_private, {}, :require => :loggedin
    @@ -79,22 +79,22 @@
         map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin
         map.permission :delete_issues, {:issues => :destroy}, :require => :member
         # Queries
    -    map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
    -    map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
    +    map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
    +    map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
         # Watchers
         map.permission :view_issue_watchers, {}
         map.permission :add_issue_watchers, {:watchers => :new}
         map.permission :delete_issue_watchers, {:watchers => :destroy}
       end
    -  
    +
       map.project_module :time_tracking do |map|
    -    map.permission :log_time, {:timelog => [:new, :create, :edit, :update, :bulk_edit, :bulk_update]}, :require => :loggedin
    +    map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
         map.permission :view_time_entries, :timelog => [:index, :show], :time_entry_reports => [:report]
    -    map.permission :edit_time_entries, {:timelog => [:new, :create, :edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
    -    map.permission :edit_own_time_entries, {:timelog => [:new, :create, :edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
    +    map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
    +    map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
         map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
       end
    -  
    +
       map.project_module :news do |map|
         map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member
         map.permission :view_news, {:news => [:index, :show]}, :public => true
    @@ -105,12 +105,12 @@
         map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin
         map.permission :view_documents, :documents => [:index, :show, :download]
       end
    -  
    +
       map.project_module :files do |map|
         map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin
         map.permission :view_files, :files => :index, :versions => :download
       end
    -    
    +
       map.project_module :wiki do |map|
         map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
         map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
    @@ -122,7 +122,7 @@
         map.permission :delete_wiki_pages_attachments, {}
         map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
       end
    -    
    +
       map.project_module :repository do |map|
         map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member
         map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/access_control.rb
    --- a/lib/redmine/access_control.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/access_control.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,23 +1,23 @@
    -# redMine - project management software
    -# Copyright (C) 2006-2007  Jean-Philippe Lang
    +# Redmine - project management software
    +# Copyright (C) 2006-2011  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 AccessControl
    -    
    +
         class << self
           def map
             mapper = Mapper.new
    @@ -25,69 +25,69 @@
             @permissions ||= []
             @permissions += mapper.mapped_permissions
           end
    -      
    +
           def permissions
             @permissions
           end
    -      
    +
           # Returns the permission of given name or nil if it wasn't found
           # Argument should be a symbol
           def permission(name)
             permissions.detect {|p| p.name == name}
           end
    -      
    +
           # Returns the actions that are allowed by the permission of given name
           def allowed_actions(permission_name)
             perm = permission(permission_name)
             perm ? perm.actions : []
           end
    -      
    +
           def public_permissions
             @public_permissions ||= @permissions.select {|p| p.public?}
           end
    -      
    +
           def members_only_permissions
             @members_only_permissions ||= @permissions.select {|p| p.require_member?}
           end
    -      
    +
           def loggedin_only_permissions
             @loggedin_only_permissions ||= @permissions.select {|p| p.require_loggedin?}
           end
    -      
    +
           def available_project_modules
             @available_project_modules ||= @permissions.collect(&:project_module).uniq.compact
           end
    -      
    +
           def modules_permissions(modules)
             @permissions.select {|p| p.project_module.nil? || modules.include?(p.project_module.to_s)}
           end
         end
    -    
    +
         class Mapper
           def initialize
             @project_module = nil
           end
    -      
    +
           def permission(name, hash, options={})
             @permissions ||= []
             options.merge!(:project_module => @project_module)
             @permissions << Permission.new(name, hash, options)
           end
    -      
    +
           def project_module(name, options={})
             @project_module = name
             yield self
             @project_module = nil
           end
    -      
    +
           def mapped_permissions
             @permissions
           end
         end
    -    
    +
         class Permission
           attr_reader :name, :actions, :project_module
    -      
    +
           def initialize(name, hash, options)
             @name = name
             @actions = []
    @@ -103,18 +103,18 @@
             end
             @actions.flatten!
           end
    -      
    +
           def public?
             @public
           end
    -      
    +
           def require_member?
             @require && @require == :member
           end
    -      
    +
           def require_loggedin?
             @require && (@require == :member || @require == :loggedin)
           end
    -    end    
    +    end
       end
     end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/access_keys.rb
    --- a/lib/redmine/access_keys.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/access_keys.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,16 +1,16 @@
    -# redMine - project management software
    -# Copyright (C) 2006-2008  Jean-Philippe Lang
    +# Redmine - project management software
    +# Copyright (C) 2006-2011  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.
    @@ -23,7 +23,7 @@
                       :search => '4',
                       :new_issue => '7'
                      }.freeze unless const_defined?(:ACCESSKEYS)
    -                 
    +
         def self.key_for(action)
           ACCESSKEYS[action]
         end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/activity.rb
    --- a/lib/redmine/activity.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/activity.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,25 +1,25 @@
     # Redmine - project management software
    -# Copyright (C) 2006-2008  Jean-Philippe Lang
    +# Copyright (C) 2006-2011  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 Activity
    -  
    +
         mattr_accessor :available_event_types, :default_event_types, :providers
    -    
    +
         @@available_event_types = []
         @@default_event_types = []
         @@providers = Hash.new {|h,k| h[k]=[] }
    @@ -28,15 +28,15 @@
           def map(&block)
             yield self
           end
    -      
    +
           # Registers an activity provider
           def register(event_type, options={})
             options.assert_valid_keys(:class_name, :default)
    -        
    +
             event_type = event_type.to_s
             providers = options[:class_name] || event_type.classify
             providers = ([] << providers) unless providers.is_a?(Array)
    -        
    +
             @@available_event_types << event_type unless @@available_event_types.include?(event_type)
             @@default_event_types << event_type unless options[:default] == false
             @@providers[event_type] += providers
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/activity/fetcher.rb
    --- a/lib/redmine/activity/fetcher.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/activity/fetcher.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,16 +1,16 @@
     # Redmine - project management software
    -# Copyright (C) 2006-2008  Jean-Philippe Lang
    +# Copyright (C) 2006-2011  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.
    @@ -20,33 +20,33 @@
         # Class used to retrieve activity events
         class Fetcher
           attr_reader :user, :project, :scope
    -      
    +
           # Needs to be unloaded in development mode
           @@constantized_providers = Hash.new {|h,k| h[k] = Redmine::Activity.providers[k].collect {|t| t.constantize } }
    -      
    +
           def initialize(user, options={})
             options.assert_valid_keys(:project, :with_subprojects, :author)
             @user = user
             @project = options[:project]
             @options = options
    -        
    +
             @scope = event_types
           end
    -      
    +
           # Returns an array of available event types
           def event_types
             return @event_types unless @event_types.nil?
    -        
    +
             @event_types = Redmine::Activity.available_event_types
             @event_types = @event_types.select {|o| @project.self_and_descendants.detect {|p| @user.allowed_to?("view_#{o}".to_sym, p)}} if @project
             @event_types
           end
    -      
    +
           # Yields to filter the activity scope
           def scope_select(&block)
             @scope = @scope.select {|t| yield t }
           end
    -      
    +
           # Sets the scope
           # Argument can be :all, :default or an array of event types
           def scope=(s)
    @@ -59,34 +59,34 @@
               @scope = s & event_types
             end
           end
    -      
    +
           # Resets the scope to the default scope
           def default_scope!
             @scope = Redmine::Activity.default_event_types
           end
    -      
    +
           # Returns an array of events for the given date range
           # sorted in reverse chronological order
           def events(from = nil, to = nil, options={})
             e = []
             @options[:limit] = options[:limit]
    -        
    +
             @scope.each do |event_type|
               constantized_providers(event_type).each do |provider|
                 e += provider.find_events(event_type, @user, from, to, @options)
               end
             end
    -        
    +
             e.sort! {|a,b| b.event_datetime <=> a.event_datetime}
    -        
    +
             if options[:limit]
               e = e.slice(0, options[:limit])
             end
             e
           end
    -      
    +
           private
    -      
    +
           def constantized_providers(event_type)
             @@constantized_providers[event_type]
           end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/ciphering.rb
    --- a/lib/redmine/ciphering.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/ciphering.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -17,13 +17,13 @@
     
     module Redmine
       module Ciphering
    -    def self.included(base) 
    +    def self.included(base)
           base.extend ClassMethods
         end
    -    
    +
         class << self
           def encrypt_text(text)
    -        if cipher_key.blank?
    +        if cipher_key.blank? || text.blank?
               text
             else
               c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
    @@ -36,9 +36,13 @@
               "aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--')
             end
           end
    -      
    +
           def decrypt_text(text)
             if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/)
    +          if cipher_key.blank?
    +            logger.error "Attempt to decrypt a ciphered text with no cipher key configured in config/configuration.yml" if logger
    +            return text
    +          end
               text = match[1]
               c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
               e, iv = text.split("--").map {|s| Base64.decode64(s)}
    @@ -51,13 +55,17 @@
               text
             end
           end
    -      
    +
           def cipher_key
             key = Redmine::Configuration['database_cipher_key'].to_s
             key.blank? ? nil : Digest::SHA256.hexdigest(key)
           end
    +      
    +      def logger
    +        Rails.logger
    +      end
         end
    -  
    +
         module ClassMethods
           def encrypt_all(attribute)
             transaction do
    @@ -68,7 +76,7 @@
               end
             end ? true : false
           end
    -      
    +
           def decrypt_all(attribute)
             transaction do
               all.each do |object|
    @@ -79,14 +87,14 @@
             end
           end ? true : false
         end
    -    
    +
         private
    -    
    +
         # Returns the value of the given ciphered attribute
         def read_ciphered_attribute(attribute)
           Redmine::Ciphering.decrypt_text(read_attribute(attribute))
         end
    -    
    +
         # Sets the value of the given ciphered attribute
         def write_ciphered_attribute(attribute, value)
           write_attribute(attribute, Redmine::Ciphering.encrypt_text(value))
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/codeset_util.rb
    --- a/lib/redmine/codeset_util.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/codeset_util.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -11,6 +11,13 @@
               str = str.encode("US-ASCII", :invalid => :replace,
                     :undef => :replace, :replace => '?').encode("UTF-8")
             end
    +      elsif RUBY_PLATFORM == 'java'
    +        begin
    +          ic = Iconv.new('UTF-8', 'UTF-8')
    +          str = ic.iconv(str)
    +        rescue
    +          str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
    +        end
           else
             ic = Iconv.new('UTF-8', 'UTF-8')
             txtar = ""
    @@ -27,5 +34,116 @@
           end
           str
         end
    +
    +    def self.to_utf8(str, encoding)
    +      return str if str.nil?
    +      str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
    +      if str.empty?
    +        str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
    +        return str
    +      end
    +      enc = encoding.blank? ? "UTF-8" : encoding
    +      if str.respond_to?(:force_encoding)
    +        if enc.upcase != "UTF-8"
    +          str.force_encoding(enc)
    +          str = str.encode("UTF-8", :invalid => :replace,
    +                :undef => :replace, :replace => '?')
    +        else
    +          str.force_encoding("UTF-8")
    +          if ! str.valid_encoding?
    +            str = str.encode("US-ASCII", :invalid => :replace,
    +                  :undef => :replace, :replace => '?').encode("UTF-8")
    +          end
    +        end
    +      elsif RUBY_PLATFORM == 'java'
    +        begin
    +          ic = Iconv.new('UTF-8', enc)
    +          str = ic.iconv(str)
    +        rescue
    +          str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
    +        end
    +      else
    +        ic = Iconv.new('UTF-8', enc)
    +        txtar = ""
    +        begin
    +          txtar += ic.iconv(str)
    +        rescue Iconv::IllegalSequence
    +          txtar += $!.success
    +          str = '?' + $!.failed[1,$!.failed.length]
    +          retry
    +        rescue
    +          txtar += $!.success
    +        end
    +        str = txtar
    +      end
    +      str
    +    end
    +
    +    def self.to_utf8_by_setting(str)
    +      return str if str.nil?
    +      str = self.to_utf8_by_setting_internal(str)
    +      if str.respond_to?(:force_encoding)
    +        str.force_encoding('UTF-8')
    +      end
    +      str
    +    end
    +
    +    def self.to_utf8_by_setting_internal(str)
    +      return str if str.nil?
    +      if str.respond_to?(:force_encoding)
    +        str.force_encoding('ASCII-8BIT')
    +      end
    +      return str if str.empty?
    +      return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
    +      if str.respond_to?(:force_encoding)
    +        str.force_encoding('UTF-8')
    +      end
    +      encodings = Setting.repositories_encodings.split(',').collect(&:strip)
    +      encodings.each do |encoding|
    +        begin
    +          return Iconv.conv('UTF-8', encoding, str)
    +        rescue Iconv::Failure
    +          # do nothing here and try the next encoding
    +        end
    +      end
    +      str = self.replace_invalid_utf8(str)
    +      if str.respond_to?(:force_encoding)
    +        str.force_encoding('UTF-8')
    +      end
    +      str
    +    end
    +
    +    def self.from_utf8(str, encoding)
    +      str ||= ''
    +      if str.respond_to?(:force_encoding)
    +        str.force_encoding('UTF-8')
    +        if encoding.upcase != 'UTF-8'
    +          str = str.encode(encoding, :invalid => :replace,
    +                           :undef => :replace, :replace => '?')
    +        else
    +          str = self.replace_invalid_utf8(str)
    +        end
    +      elsif RUBY_PLATFORM == 'java'
    +        begin
    +          ic = Iconv.new(encoding, 'UTF-8')
    +          str = ic.iconv(str)
    +        rescue
    +          str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
    +        end
    +      else
    +        ic = Iconv.new(encoding, 'UTF-8')
    +        txtar = ""
    +        begin
    +          txtar += ic.iconv(str)
    +        rescue Iconv::IllegalSequence
    +          txtar += $!.success
    +          str = '?' + $!.failed[1, $!.failed.length]
    +          retry
    +        rescue
    +          txtar += $!.success
    +        end
    +        str = txtar
    +      end
    +    end
       end
     end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/configuration.rb
    --- a/lib/redmine/configuration.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/configuration.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -5,42 +5,42 @@
     # 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 Configuration
    -    
    +
         # Configuration default values
         @defaults = {
           'email_delivery' => nil
         }
    -    
    +
         @config = nil
    -    
    +
         class << self
           # Loads the Redmine configuration file
           # Valid options:
           # * :file: the configuration file to load (default: config/configuration.yml)
    -      # * :env: the environment to load the configuration for (default: Rails.env) 
    +      # * :env: the environment to load the configuration for (default: Rails.env)
           def load(options={})
             filename = options[:file] || File.join(Rails.root, 'config', 'configuration.yml')
             env = options[:env] || Rails.env
    -        
    +
             @config = @defaults.dup
    -        
    +
             load_deprecated_email_configuration(env)
             if File.file?(filename)
               @config.merge!(load_from_yaml(filename, env))
             end
    -        
    +
             # Compatibility mode for those who copy email.yml over configuration.yml
             %w(delivery_method smtp_settings sendmail_settings).each do |key|
               if value = @config.delete(key)
    @@ -48,7 +48,7 @@
                 @config['email_delivery'][key] = value
               end
             end
    -        
    +
             if @config['email_delivery']
               ActionMailer::Base.perform_deliveries = true
               @config['email_delivery'].each do |k, v|
    @@ -56,16 +56,16 @@
                 ActionMailer::Base.send("#{k}=", v)
               end
             end
    -          
    +
             @config
           end
    -      
    +
           # Returns a configuration setting
           def [](name)
             load unless @config
             @config[name]
           end
    -      
    +
           # Yields a block with the specified hash configuration settings
           def with(settings)
             settings.stringify_keys!
    @@ -75,11 +75,17 @@
             yield if block_given?
             @config.merge! was
           end
    -      
    +
           private
    -      
    +
           def load_from_yaml(filename, env)
    -        yaml = YAML::load_file(filename)
    +        yaml = nil
    +        begin
    +          yaml = YAML::load_file(filename)
    +        rescue ArgumentError
    +          $stderr.puts "Your Redmine configuration file located at #{filename} is not a valid YAML file and could not be loaded."
    +          exit 1
    +        end
             conf = {}
             if yaml.is_a?(Hash)
               if yaml['default']
    @@ -89,12 +95,12 @@
                 conf.merge!(yaml[env])
               end
             else
    -          $stderr.puts "#{filename} is not a valid Redmine configuration file"
    +          $stderr.puts "Your Redmine configuration file located at #{filename} is not a valid Redmine configuration file."
               exit 1
             end
             conf
           end
    -      
    +
           def load_deprecated_email_configuration(env)
             deprecated_email_conf = File.join(Rails.root, 'config', 'email.yml')
             if File.file?(deprecated_email_conf)
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/core_ext/string/conversions.rb
    --- a/lib/redmine/core_ext/string/conversions.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/core_ext/string/conversions.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,16 +1,16 @@
    -# redMine - project management software
    -# Copyright (C) 2008  Jean-Philippe Lang
    +# Redmine - project management software
    +# Copyright (C) 2006-2011  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.
    @@ -36,7 +36,7 @@
               s.gsub!(',', '.')
               begin; Kernel.Float(s); rescue; nil; end
             end
    -        
    +
             # Object#to_a removed in ruby1.9
             if RUBY_VERSION > '1.9'
               def to_a
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/core_ext/string/inflections.rb
    --- a/lib/redmine/core_ext/string/inflections.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/core_ext/string/inflections.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,16 +1,16 @@
     # Redmine - project management software
    -# Copyright (C) 2009  Jean-Philippe Lang
    +# Copyright (C) 2006-2011  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.
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/custom_field_format.rb
    --- a/lib/redmine/custom_field_format.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/custom_field_format.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,16 +1,16 @@
     # Redmine - project management software
    -# Copyright (C) 2006-2009  Jean-Philippe Lang
    +# Copyright (C) 2006-2011  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.
    @@ -49,7 +49,7 @@
             return value
           }
         end
    -    
    +
         ['user', 'version'].each do |name|
           define_method("format_as_#{name}") {|value|
             return value.blank? ? "" : name.classify.constantize.find_by_id(value.to_i).to_s
    @@ -60,7 +60,7 @@
           def map(&block)
             yield self
           end
    -      
    +
           # Registers a custom field format
           def register(custom_field_format, options={})
             @@available[custom_field_format.name] = custom_field_format unless @@available.keys.include?(custom_field_format.name)
    @@ -100,5 +100,5 @@
             end
           end
         end
    -  end 
    +  end
     end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/default_data/loader.rb
    --- a/lib/redmine/default_data/loader.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/default_data/loader.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -5,12 +5,12 @@
     # 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.
    @@ -21,7 +21,7 @@
     
         module Loader
           include Redmine::I18n
    -    
    +
           class << self
             # Returns true if no data is already loaded in the database
             # otherwise false
    @@ -31,24 +31,24 @@
                 !IssueStatus.find(:first) &&
                 !Enumeration.find(:first)
             end
    -        
    +
             # Loads the default data
             # Raises a RecordNotSaved exception if something goes wrong
             def load(lang=nil)
               raise DataAlreadyLoaded.new("Some configuration data is already loaded.") unless no_data?
               set_language_if_valid(lang)
    -          
    +
               Role.transaction do
                 # Roles
    -            manager = Role.create! :name => l(:default_role_manager), 
    +            manager = Role.create! :name => l(:default_role_manager),
                                        :issues_visibility => 'all',
                                        :position => 1
                 manager.permissions = manager.setable_permissions.collect {|p| p.name}
                 manager.save!
    -            
    -            developer = Role.create!  :name => l(:default_role_developer), 
    -                                      :position => 2, 
    -                                      :permissions => [:manage_versions, 
    +
    +            developer = Role.create!  :name => l(:default_role_developer),
    +                                      :position => 2,
    +                                      :permissions => [:manage_versions,
                                                           :manage_categories,
                                                           :view_issues,
                                                           :add_issues,
    @@ -74,7 +74,7 @@
                                                           :browse_repository,
                                                           :view_changesets,
                                                           :commit_access]
    -            
    +
                 reporter = Role.create! :name => l(:default_role_reporter),
                                         :position => 3,
                                         :permissions => [:view_issues,
    @@ -94,7 +94,7 @@
                                                         :view_files,
                                                         :browse_repository,
                                                         :view_changesets]
    -                        
    +
                 Role.non_member.update_attribute :permissions, [:view_issues,
                                                                 :add_issues,
                                                                 :add_issue_notes,
    @@ -110,7 +110,7 @@
                                                                 :view_files,
                                                                 :browse_repository,
                                                                 :view_changesets]
    -          
    +
                 Role.anonymous.update_attribute :permissions, [:view_issues,
                                                                :view_gantt,
                                                                :view_calendar,
    @@ -121,12 +121,12 @@
                                                                :view_files,
                                                                :browse_repository,
                                                                :view_changesets]
    -                                                             
    +
                 # Trackers
                 Tracker.create!(:name => l(:default_tracker_bug),     :is_in_chlog => true,  :is_in_roadmap => false, :position => 1)
                 Tracker.create!(:name => l(:default_tracker_feature), :is_in_chlog => true,  :is_in_roadmap => true,  :position => 2)
                 Tracker.create!(:name => l(:default_tracker_support), :is_in_chlog => false, :is_in_roadmap => false, :position => 3)
    -            
    +
                 # Issue statuses
                 new       = IssueStatus.create!(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :position => 1)
                 in_progress  = IssueStatus.create!(:name => l(:default_issue_status_in_progress), :is_closed => false, :is_default => false, :position => 2)
    @@ -134,43 +134,43 @@
                 feedback  = IssueStatus.create!(:name => l(:default_issue_status_feedback), :is_closed => false, :is_default => false, :position => 4)
                 closed    = IssueStatus.create!(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :position => 5)
                 rejected  = IssueStatus.create!(:name => l(:default_issue_status_rejected), :is_closed => true, :is_default => false, :position => 6)
    -            
    +
                 # Workflow
                 Tracker.find(:all).each { |t|
                   IssueStatus.find(:all).each { |os|
                     IssueStatus.find(:all).each { |ns|
                       Workflow.create!(:tracker_id => t.id, :role_id => manager.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns
    -                }        
    -              }      
    +                }
    +              }
                 }
    -            
    +
                 Tracker.find(:all).each { |t|
                   [new, in_progress, resolved, feedback].each { |os|
                     [in_progress, resolved, feedback, closed].each { |ns|
                       Workflow.create!(:tracker_id => t.id, :role_id => developer.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns
    -                }        
    -              }      
    +                }
    +              }
                 }
    -            
    +
                 Tracker.find(:all).each { |t|
                   [new, in_progress, resolved, feedback].each { |os|
                     [closed].each { |ns|
                       Workflow.create!(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns
    -                }        
    +                }
                   }
                   Workflow.create!(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => resolved.id, :new_status_id => feedback.id)
                 }
    -          
    +
                 # Enumerations
                 DocumentCategory.create!(:name => l(:default_doc_category_user), :position => 1)
                 DocumentCategory.create!(:name => l(:default_doc_category_tech), :position => 2)
    -          
    +
                 IssuePriority.create!(:name => l(:default_priority_low), :position => 1)
                 IssuePriority.create!(:name => l(:default_priority_normal), :position => 2, :is_default => true)
                 IssuePriority.create!(:name => l(:default_priority_high), :position => 3)
                 IssuePriority.create!(:name => l(:default_priority_urgent), :position => 4)
                 IssuePriority.create!(:name => l(:default_priority_immediate), :position => 5)
    -          
    +
                 TimeEntryActivity.create!(:name => l(:default_activity_design), :position => 1)
                 TimeEntryActivity.create!(:name => l(:default_activity_development), :position => 2)
               end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/export/pdf.rb
    --- a/lib/redmine/export/pdf.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/export/pdf.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -18,27 +18,27 @@
     # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     
     require 'iconv'
    -require 'rfpdf/fpdf'
     require 'fpdf/chinese'
     require 'fpdf/japanese'
     require 'fpdf/korean'
    +require 'core/rmagick'
     
     module Redmine
       module Export
         module PDF
           include ActionView::Helpers::TextHelper
           include ActionView::Helpers::NumberHelper
    +      include IssuesHelper
     
           class ITCPDF < TCPDF
             include Redmine::I18n
             attr_accessor :footer_date
     
             def initialize(lang)
    +          @@k_path_cache = Rails.root.join('tmp', 'pdf')
    +          FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
               set_language_if_valid lang
               pdf_encoding = l(:general_pdf_encoding).upcase
    -          if RUBY_VERSION < '1.9'
    -            @ic = Iconv.new(pdf_encoding, 'UTF-8')
    -          end
               super('P', 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding)
               case current_language.to_s.downcase
               when 'vi'
    @@ -104,7 +104,7 @@
             end
     
             def fix_text_encoding(txt)
    -          RDMPdfEncoding::rdm_pdf_iconv(@ic, txt)
    +          RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
             end
     
             def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
    @@ -115,6 +115,24 @@
               MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
             end
     
    +        def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
    +          @attachments = attachments
    +          writeHTMLCell(w, h, x, y,
    +            fix_text_encoding(
    +              Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
    +            border, ln, fill)
    +        end
    +
    +        def getImageFilename(attrname)
    +          # attrname: general_pdf_encoding string file/uri name
    +          atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
    +          if atta
    +            return atta.diskfile
    +          else
    +            return nil
    +          end
    +        end
    +
             def Footer
               SetFont(@font_for_footer, 'I', 8)
               SetY(-15)
    @@ -150,7 +168,8 @@
             col_width = []
             unless query.columns.empty?
               col_width = query.columns.collect do |c|
    -            (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) && ['string', 'text'].include?(c.custom_field.field_format)))? 4.0 : 1.0
    +            (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
    +              ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
               end
               ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
               col_width = col_width.collect {|w| w * ratio}
    @@ -182,7 +201,7 @@
             pdf.SetFontStyle('',8)
             pdf.SetFillColor(255, 255, 255)
             previous_group = false
    -        issues.each do |issue|
    +        issue_list(issues) do |issue, level|
               if query.grouped? &&
                    (group = query.group_by_column.value(issue)) != previous_group
                 pdf.SetFontStyle('B',9)
    @@ -199,6 +218,9 @@
                   show_value(cv)
                 else
                   value = issue.send(column.name)
    +              if column.name == :subject
    +                value = "  " * level + value
    +              end
                   if value.is_a?(Date)
                     format_date(value)
                   elsif value.is_a?(Time)
    @@ -278,8 +300,18 @@
             pdf.footer_date = format_date(Date.today)
             pdf.AddPage
             pdf.SetFontStyle('B',11)
    -        pdf.RDMMultiCell(190,5,
    -             "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
    +        buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
    +        pdf.RDMMultiCell(190, 5, buf)
    +        pdf.Ln
    +        pdf.SetFontStyle('',8)
    +        base_x = pdf.GetX
    +        i = 1
    +        issue.ancestors.each do |ancestor|
    +          pdf.SetX(base_x + i)
    +          buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
    +          pdf.RDMMultiCell(190 - i, 5, buf)
    +          i += 1 if i < 35
    +        end
             pdf.Ln
     
             pdf.SetFontStyle('B',9)
    @@ -340,7 +372,61 @@
             pdf.SetFontStyle('B',9)
             pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
             pdf.SetFontStyle('',9)
    -        pdf.RDMMultiCell(35+155, 5, issue.description.to_s, "LRB")
    +
    +        # Set resize image scale
    +        pdf.SetImageScale(1.6)
    +        pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
    +              issue.description.to_s, issue.attachments, "LRB")
    +
    +        unless issue.leaf?
    +          # for CJK
    +          truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
    +  
    +          pdf.SetFontStyle('B',9)
    +          pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
    +          pdf.Ln
    +          issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
    +            buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
    +                           :length => truncate_length)
    +            level = 10 if level >= 10
    +            pdf.SetFontStyle('',8)
    +            pdf.RDMCell(35+135,5, (level >=1 ? "  " * level : "") + buf, "L")
    +            pdf.SetFontStyle('B',8)
    +            pdf.RDMCell(20,5, child.status.to_s, "R")
    +            pdf.Ln
    +          end
    +        end
    +
    +        relations = issue.relations.select { |r| r.other_issue(issue).visible? }
    +        unless relations.empty?
    +          # for CJK
    +          truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
    +  
    +          pdf.SetFontStyle('B',9)
    +          pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
    +          pdf.Ln
    +          relations.each do |relation|
    +            buf = ""
    +            buf += "#{l(relation.label_for(issue))} "
    +            if relation.delay && relation.delay != 0
    +              buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
    +            end
    +            if Setting.cross_project_issue_relations?
    +              buf += "#{relation.other_issue(issue).project} - "
    +            end
    +            buf += "#{relation.other_issue(issue).tracker}" +
    +                   " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
    +            buf = truncate(buf, :length => truncate_length)
    +            pdf.SetFontStyle('', 8)
    +            pdf.RDMCell(35+155-60, 5, buf, "L")
    +            pdf.SetFontStyle('B',8)
    +            pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
    +            pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
    +            pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
    +            pdf.Ln
    +          end
    +        end
    +        pdf.RDMCell(190,5, "", "T")
             pdf.Ln
     
             if issue.changesets.any? &&
    @@ -356,7 +442,8 @@
                 pdf.Ln
                 unless changeset.comments.blank?
                   pdf.SetFontStyle('',8)
    -              pdf.RDMMultiCell(190,5, changeset.comments.to_s)
    +              pdf.RDMwriteHTMLCell(190,5,0,0,
    +                    changeset.comments.to_s, issue.attachments, "")
                 end
                 pdf.Ln
               end
    @@ -365,12 +452,16 @@
             pdf.SetFontStyle('B',9)
             pdf.RDMCell(190,5, l(:label_history), "B")
             pdf.Ln
    +        indice = 0
             for journal in issue.journals.find(
                               :all, :include => [:user, :details],
                               :order => "#{Journal.table_name}.created_on ASC")
    +          indice = indice + 1
               pdf.SetFontStyle('B',8)
               pdf.RDMCell(190,5,
    -             format_time(journal.created_on) + " - " + journal.user.name)
    +             "#" + indice.to_s +
    +             " - " + format_time(journal.created_on) +
    +             " - " + journal.user.name)
               pdf.Ln
               pdf.SetFontStyle('I',8)
               for detail in journal.details
    @@ -379,7 +470,8 @@
               if journal.notes?
                 pdf.Ln unless journal.details.empty?
                 pdf.SetFontStyle('',8)
    -            pdf.RDMMultiCell(190,5, journal.notes.to_s)
    +            pdf.RDMwriteHTMLCell(190,5,0,0,
    +                  journal.notes.to_s, issue.attachments, "")
               end
               pdf.Ln
             end
    @@ -400,42 +492,61 @@
             pdf.Output
           end
     
    +      # Returns a PDF string of a single wiki page
    +      def wiki_to_pdf(page, project)
    +        pdf = ITCPDF.new(current_language)
    +        pdf.SetTitle("#{project} - #{page.title}")
    +        pdf.alias_nb_pages
    +        pdf.footer_date = format_date(Date.today)
    +        pdf.AddPage
    +        pdf.SetFontStyle('B',11)
    +        pdf.RDMMultiCell(190,5,
    +             "#{project} - #{page.title} - # #{page.content.version}")
    +        pdf.Ln
    +        # Set resize image scale
    +        pdf.SetImageScale(1.6)
    +        pdf.SetFontStyle('',9)
    +        pdf.RDMwriteHTMLCell(190,5,0,0,
    +              page.content.text.to_s, page.attachments, "TLRB")
    +        if page.attachments.any?
    +          pdf.Ln
    +          pdf.SetFontStyle('B',9)
    +          pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
    +          pdf.Ln
    +          for attachment in page.attachments
    +            pdf.SetFontStyle('',8)
    +            pdf.RDMCell(80,5, attachment.filename)
    +            pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
    +            pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
    +            pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
    +            pdf.Ln
    +          end
    +        end
    +        pdf.Output
    +      end
    +
           class RDMPdfEncoding
    -        include Redmine::I18n
    -        def self.rdm_pdf_iconv(ic, txt)
    +        def self.rdm_from_utf8(txt, encoding)
               txt ||= ''
    +          txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
               if txt.respond_to?(:force_encoding)
    -            txt.force_encoding('UTF-8')
    -            if l(:general_pdf_encoding).upcase != 'UTF-8'
    -              txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
    -                               :undef => :replace, :replace => '?')
    -            else
    -              txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
    -            end
                 txt.force_encoding('ASCII-8BIT')
    -          elsif RUBY_PLATFORM == 'java'
    -            begin
    -              ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
    -              txt = ic.iconv(txt)
    -            rescue
    -              txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
    -            end
    -          else
    -            ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
    -            txtar = ""
    -            begin
    -              txtar += ic.iconv(txt)
    -            rescue Iconv::IllegalSequence
    -              txtar += $!.success
    -              txt = '?' + $!.failed[1,$!.failed.length]
    -              retry
    -            rescue
    -              txtar += $!.success
    -            end
    -            txt = txtar
               end
               txt
             end
    +
    +        def self.attach(attachments, filename, encoding)
    +          filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
    +          atta = nil
    +          if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
    +            atta = Attachment.latest_attach(attachments, filename_utf8)
    +          end
    +          if atta && atta.readable? && atta.visible?
    +            return atta
    +          else
    +            return nil
    +          end
    +        end
           end
         end
       end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/helpers/calendar.rb
    --- a/lib/redmine/helpers/calendar.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/helpers/calendar.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -1,34 +1,34 @@
    -# redMine - project management software
    -# Copyright (C) 2006-2007  Jean-Philippe Lang
    +# Redmine - project management software
    +# Copyright (C) 2006-2011  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 Helpers
    -    
    +
         # Simple class to compute the start and end dates of a calendar
         class Calendar
           include Redmine::I18n
           attr_reader :startdt, :enddt
    -      
    +
           def initialize(date, lang = current_language, period = :month)
             @date = date
             @events = []
             @ending_events_by_days = {}
             @starting_events_by_days = {}
    -        set_language_if_valid lang        
    +        set_language_if_valid lang
             case period
             when :month
               @startdt = Date.civil(date.year, date.month, 1)
    @@ -44,24 +44,24 @@
               raise 'Invalid period'
             end
           end
    -      
    +
           # Sets calendar events
           def events=(events)
             @events = events
             @ending_events_by_days = @events.group_by {|event| event.due_date}
             @starting_events_by_days = @events.group_by {|event| event.start_date}
           end
    -      
    +
           # Returns events for the given day
           def events_on(day)
             ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq
           end
    -      
    +
           # Calendar current month
           def month
             @date.month
           end
    -      
    +
           # Return the first day of week
           # 1 = Monday ... 7 = Sunday
           def first_wday
    @@ -76,10 +76,10 @@
               @first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1
             end
           end
    -      
    +
           def last_wday
             @last_dow ||= (first_wday + 5)%7 + 1
           end
    -    end    
    +    end
       end
     end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/helpers/diff.rb
    --- a/lib/redmine/helpers/diff.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/helpers/diff.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -5,12 +5,12 @@
     # 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.
    @@ -22,15 +22,15 @@
           include ActionView::Helpers::TagHelper
           include ActionView::Helpers::TextHelper
           attr_reader :diff, :words
    -      
    +
           def initialize(content_to, content_from)
             @words = content_to.to_s.split(/(\s+)/)
             @words = @words.select {|word| word != ' '}
             words_from = content_from.to_s.split(/(\s+)/)
    -        words_from = words_from.select {|word| word != ' '}    
    +        words_from = words_from.select {|word| word != ' '}
             @diff = words_from.diff @words
           end
    -  
    +
           def to_html
             words = self.words.collect{|word| h(word)}
             words_add = 0
    @@ -41,7 +41,7 @@
               add_at = nil
               add_to = nil
               del_at = nil
    -          deleted = ""      
    +          deleted = ""
               diff.each do |change|
                 pos = change[1]
                 if change[0] == "+"
    @@ -65,7 +65,7 @@
                 words_del = 0
               end
             end
    -        words.join(' ')
    +        words.join(' ').html_safe
           end
         end
       end
    diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/helpers/gantt.rb
    --- a/lib/redmine/helpers/gantt.rb	Fri Feb 24 20:18:25 2012 +0000
    +++ b/lib/redmine/helpers/gantt.rb	Mon Feb 27 13:53:18 2012 +0000
    @@ -260,9 +260,9 @@
           def subject_for_project(project, options)
             case options[:format]
             when :html
    -          subject = ""
    -          subject << view.link_to_project(project)
    -          subject << ''
    +          subject = "".html_safe
    +          subject << view.link_to_project(project).html_safe
    +          subject << ''.html_safe
               html_subject(options, subject, :css => "project-name")
             when :image
               image_subject(options, project.name)
    @@ -298,9 +298,9 @@
           def subject_for_version(version, options)
             case options[:format]
             when :html
    -          subject = ""
    -          subject << view.link_to_version(version)
    -          subject << ''
    +          subject = "".html_safe
    +          subject << view.link_to_version(version).html_safe
    +          subject << ''.html_safe
               html_subject(options, subject, :css => "version-name")
             when :image
               image_subject(options, version.to_s_with_project)
    @@ -347,13 +347,13 @@
               css_classes << ' issue-behind-schedule' if issue.behind_schedule?
               css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to
     
    -          subject = ""
    +          subject = "".html_safe
               if issue.assigned_to.present?
                 assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name
    -            subject << view.avatar(issue.assigned_to, :class => 'gravatar icon-gravatar', :size => 10, :title => assigned_string).to_s
    +            subject << view.avatar(issue.assigned_to, :class => 'gravatar icon-gravatar', :size => 10, :title => assigned_string).to_s.html_safe
               end
    -          subject << view.link_to_issue(issue)
    -          subject << ''
    +          subject << view.link_to_issue(issue).html_safe
    +          subject << ''.html_safe
               html_subject(options, subject, :css => "issue-subject", :title => issue.subject) + "\n"
             when :image
               image_subject(options, issue.subject)
    @@ -737,36 +737,36 @@
             output = ''
             # Renders the task bar, with progress and late
             if coords[:bar_start] && coords[:bar_end]
    -          output << "
     
    " + output << "
     
    ".html_safe if coords[:bar_late_end] - output << "
     
    " + output << "
     
    ".html_safe end if coords[:bar_progress_end] - output << "
     
    " + output << "
     
    ".html_safe end end # Renders the markers if options[:markers] if coords[:start] - output << "
     
    " + output << "
     
    ".html_safe end if coords[:end] - output << "
     
    " + output << "
     
    ".html_safe end end # Renders the label on the right if options[:label] - output << "
    " + output << "
    ".html_safe output << options[:label] - output << "
    " + output << "
    ".html_safe end # Renders the tooltip if options[:issue] && coords[:bar_start] && coords[:bar_end] - output << "
    " - output << '' - output << view.render_issue_tooltip(options[:issue]) - output << "
    " + output << "
    ".html_safe + output << ''.html_safe + output << view.render_issue_tooltip(options[:issue]).html_safe + output << "
    ".html_safe end @lines << output output diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/hook.rb --- a/lib/redmine/hook.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/hook.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -22,7 +22,7 @@ @@listener_classes = [] @@listeners = nil @@hook_listeners = {} - + class << self # Adds a listener class. # Automatically called when a class inherits from Redmine::Hook::Listener. @@ -31,29 +31,29 @@ @@listener_classes << klass clear_listeners_instances end - + # Returns all the listerners instances. def listeners @@listeners ||= @@listener_classes.collect {|listener| listener.instance} end - + # Returns the listeners instances for the given hook. def hook_listeners(hook) @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)} end - + # Clears all the listeners. def clear_listeners @@listener_classes = [] clear_listeners_instances end - + # Clears all the listeners instances. def clear_listeners_instances @@listeners = nil @@hook_listeners = {} end - + # Calls a hook. # Returns the listeners response. def call_hook(hook, context={}) @@ -101,11 +101,11 @@ def self.default_url_options {:only_path => true } end - + # Helper method to directly render a partial using the context: - # + # # class MyHook < Redmine::Hook::ViewListener - # render_on :view_issues_show_details_bottom, :partial => "show_more_data" + # render_on :view_issues_show_details_bottom, :partial => "show_more_data" # end # def self.render_on(hook, options={}) @@ -115,25 +115,25 @@ end end - # Helper module included in ApplicationHelper and ActionControllerso that + # Helper module included in ApplicationHelper and ActionController so that # hooks can be called in views like this: - # + # # <%= call_hook(:some_hook) %> - # <%= call_hook(:another_hook, :foo => 'bar' %> - # + # <%= call_hook(:another_hook, :foo => 'bar') %> + # # Or in controllers like: # call_hook(:some_hook) - # call_hook(:another_hook, :foo => 'bar' - # - # Hooks added to views will be concatenated into a string. Hooks added to + # call_hook(:another_hook, :foo => 'bar') + # + # Hooks added to views will be concatenated into a string. Hooks added to # controllers will return an array of results. # # Several objects are automatically added to the call context: - # + # # * project => current project # * request => Request instance # * controller => current Controller instance - # + # module Helper def call_hook(hook, context={}) if is_a?(ActionController::Base) @@ -142,7 +142,7 @@ else default_context = {:controller => controller, :project => @project, :request => request} Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ') - end + end end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/i18n.rb --- a/lib/redmine/i18n.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/i18n.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,7 +3,7 @@ def self.included(base) base.extend Redmine::I18n end - + def l(*args) case args.size when 1 @@ -25,12 +25,12 @@ k = "#{options[:prefix]}#{s}".to_sym ::I18n.t(k, :default => s.to_s.humanize) end - + def l_hours(hours) hours = hours.to_f l((hours < 2.0 ? :label_f_hour : :label_f_hour_plural), :value => ("%.2f" % hours.to_f)) end - + def ll(lang, str, value=nil) ::I18n.t(str.to_s, :value => value, :locale => lang.to_s.gsub(%r{(.+)\-(.+)$}) { "#{$1}-#{$2.upcase}" }) end @@ -39,7 +39,7 @@ return nil unless date Setting.date_format.blank? ? ::I18n.l(date.to_date) : date.strftime(Setting.date_format) end - + def format_time(time, include_date = true) return nil unless time time = time.to_time if time.is_a?(String) @@ -52,26 +52,26 @@ def day_name(day) ::I18n.t('date.day_names')[day % 7] end - + def month_name(month) ::I18n.t('date.month_names')[month] end - + def valid_languages - @@valid_languages ||= Dir.glob(File.join(RAILS_ROOT, 'config', 'locales', '*.yml')).collect {|f| File.basename(f).split('.').first}.collect(&:to_sym) + @@valid_languages ||= Dir.glob(File.join(Rails.root, 'config', 'locales', '*.yml')).collect {|f| File.basename(f).split('.').first}.collect(&:to_sym) end - + def find_language(lang) @@languages_lookup = valid_languages.inject({}) {|k, v| k[v.to_s.downcase] = v; k } @@languages_lookup[lang.to_s.downcase] end - + def set_language_if_valid(lang) if l = find_language(lang) ::I18n.locale = l end end - + def current_language ::I18n.locale end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/imap.rb --- a/lib/redmine/imap.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/imap.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -25,8 +25,8 @@ port = imap_options[:port] || '143' ssl = !imap_options[:ssl].nil? folder = imap_options[:folder] || 'INBOX' - - imap = Net::IMAP.new(host, port, ssl) + + imap = Net::IMAP.new(host, port, ssl) imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil? imap.select(folder) imap.search(['NOT', 'SEEN']).each do |message_id| @@ -49,9 +49,9 @@ end imap.expunge end - + private - + def logger RAILS_DEFAULT_LOGGER end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/menu_manager.rb --- a/lib/redmine/menu_manager.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/menu_manager.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -22,16 +22,17 @@ def self.included(base) base.class_eval do attr_reader :last_items_count - + alias :old_initilize :initialize def initialize(name, content = nil) old_initilize(name, content) + @childrenHash ||= {} @last_items_count = 0 extend(InstanceMethods) end end end - + module InstanceMethods # Adds the specified child node to the receiver node. The child node's # parent is set to be the receiver. The child is added as the first child in @@ -105,7 +106,7 @@ module MenuManager class MenuError < StandardError #:nodoc: end - + module MenuController def self.included(base) base.extend(ClassMethods) @@ -114,13 +115,13 @@ module ClassMethods @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}} mattr_accessor :menu_items - + # Set the menu item name for a controller or specific actions # Examples: # * menu_item :tickets # => sets the menu name to :tickets for the whole controller # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only - # + # # The default menu item name for a controller is controller_name by default # Eg. the default menu item name for ProjectsController is :projects def menu_item(id, options = {}) @@ -132,17 +133,17 @@ end end end - + def menu_items self.class.menu_items end - + # Returns the menu item name according to the current action def current_menu_item @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] || menu_items[controller_name.to_sym][:default] end - + # Redirects user to the menu item of the given project # Returns false if user is not authorized def redirect_to_project_menu_item(project, name) @@ -154,18 +155,18 @@ false end end - + module MenuHelper # Returns the current menu item name def current_menu_item - @controller.current_menu_item + controller.current_menu_item end - + # Renders the application main menu def render_main_menu(project) render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project) end - + def display_main_menu?(project) menu_name = project && !project.new_record? ? :project_menu : :application_menu Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root @@ -176,7 +177,7 @@ menu_items_for(menu, project) do |node| links << render_menu_node(node, project) end - links.empty? ? nil : content_tag('ul', links.join("\n")) + links.empty? ? nil : content_tag('ul', links.join("\n").html_safe) end def render_menu_node(node, project=nil) @@ -224,7 +225,7 @@ # Tree nodes support #each so we need to do object detection if unattached_children.is_a? Array unattached_children.each do |child| - child_html << content_tag(:li, render_unattached_menu_item(child, project)) + child_html << content_tag(:li, render_unattached_menu_item(child, project)) end else raise MenuError, ":child_menus must be an array of MenuItems" @@ -245,7 +246,7 @@ menu_item.html_options) end end - + def menu_items_for(menu, project=nil) items = [] Redmine::MenuManager.items(menu).root.children.each do |node| @@ -292,7 +293,7 @@ end end end - + class << self def map(menu_name) @items ||= {} @@ -303,21 +304,21 @@ mapper end end - + def items(menu_name) @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {}) end end - + class Mapper def initialize(menu, items) items[menu] ||= Tree::TreeNode.new(:root, {}) @menu = menu @menu_items = items[menu] end - + @@last_items_count = Hash.new {|h,k| h[k] = 0} - + # Adds an item at the end of the menu. Available options: # * param: the parameter name that is used for the project id (default is :id) # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true @@ -364,14 +365,14 @@ else target_root.add(MenuItem.new(name, url, options)) end - + elsif options[:last] # don't delete, needs to be stored target_root.add_last(MenuItem.new(name, url, options)) else target_root.add(MenuItem.new(name, url, options)) end end - + # Removes a menu item def delete(name) if found = self.find(name) @@ -396,11 +397,11 @@ end end end - + class MenuItem < Tree::TreeNode include Redmine::I18n attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last - + def initialize(name, url, options) raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash) @@ -419,7 +420,7 @@ @last = options[:last] || false super @name.to_sym end - + def caption(project=nil) if @caption.is_a?(Proc) c = @caption.call(project).to_s @@ -433,7 +434,7 @@ end end end - + def html_options(options={}) if options[:selected] o = @html_options.dup @@ -443,6 +444,6 @@ @html_options end end - end + end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/mime_type.rb --- a/lib/redmine/mime_type.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/mime_type.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -62,36 +62,36 @@ 'application/zip' => 'zip', 'application/x-gzip' => 'gz', }.freeze - + EXTENSIONS = MIME_TYPES.inject({}) do |map, (type, exts)| exts.split(',').each {|ext| map[ext.strip] = type} map end - + # returns mime type for name or nil if unknown def self.of(name) return nil unless name m = name.to_s.match(/(^|\.)([^\.]+)$/) EXTENSIONS[m[2].downcase] if m end - + # Returns the css class associated to # the mime type of name def self.css_class_of(name) mime = of(name) mime && mime.gsub('/', '-') end - + def self.main_mimetype_of(name) mimetype = of(name) mimetype.split('/').first if mimetype end - + # return true if mime-type for name is type/* # otherwise false def self.is_type?(type, name) main_mimetype = main_mimetype_of(name) type.to_s == main_mimetype - end + end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/notifiable.rb --- a/lib/redmine/notifiable.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/notifiable.rb Mon Feb 27 13:53:18 2012 +0000 @@ -4,7 +4,7 @@ def to_s name end - + # TODO: Plugin API for adding a new notification? def self.all notifications = [] diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/platform.rb --- a/lib/redmine/platform.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/platform.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -19,7 +19,8 @@ module Platform class << self def mswin? - (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i) + (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || + (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i) end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/plugin.rb --- a/lib/redmine/plugin.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/plugin.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,10 +19,10 @@ class PluginNotFound < StandardError; end class PluginRequirementError < StandardError; end - + # Base class for Redmine plugins. # Plugins are registered using the register class method that acts as the public constructor. - # + # # Redmine::Plugin.register :example do # name 'Example plugin' # author 'John Smith' @@ -30,9 +30,9 @@ # version '0.0.1' # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' # end - # + # # === Plugin attributes - # + # # +settings+ is an optional attribute that let the plugin be configurable. # It must be a hash with the following keys: # * :default: default value for the plugin settings @@ -40,7 +40,7 @@ # Example: # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' # In this example, the settings partial will be found here in the plugin directory: app/views/settings/_settings.rhtml. - # + # # When rendered, the plugin settings value is available as the local variable +settings+ class Plugin @registered_plugins = {} @@ -49,9 +49,9 @@ private :new def def_field(*names) - class_eval do + class_eval do names.each do |name| - define_method(name) do |*args| + define_method(name) do |*args| args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args) end end @@ -60,7 +60,7 @@ end def_field :name, :description, :url, :author, :author_url, :version, :settings attr_reader :id - + # Plugin constructor def self.register(id, &block) p = new(id) @@ -69,21 +69,21 @@ p.name(id.to_s.humanize) if p.name.nil? # Adds plugin locales if any # YAML translation files should be found under /config/locales/ - ::I18n.load_path += Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', id.to_s, 'config', 'locales', '*.yml')) + ::I18n.load_path += Dir.glob(File.join(Rails.root, 'vendor', 'plugins', id.to_s, 'config', 'locales', '*.yml')) registered_plugins[id] = p end - - # Returns an array off all registered plugins + + # Returns an array of all registered plugins def self.all registered_plugins.values.sort end - + # Finds a plugin by its id # Returns a PluginNotFound exception if the plugin doesn't exist def self.find(id) registered_plugins[id.to_sym] || raise(PluginNotFound) end - + # Clears the registered plugins hash # It doesn't unload installed plugins def self.clear @@ -96,15 +96,15 @@ def self.installed?(id) registered_plugins[id.to_sym].present? end - + def initialize(id) @id = id.to_sym end - + def <=>(plugin) self.id.to_s <=> plugin.id.to_s end - + # Sets a requirement on Redmine version # Raises a PluginRequirementError exception if the requirement is not met # @@ -119,7 +119,7 @@ def requires_redmine(arg) arg = { :version_or_higher => arg } unless arg.is_a?(Hash) arg.assert_valid_keys(:version, :version_or_higher) - + current = Redmine::VERSION.to_a arg.each do |k, v| v = [] << v unless v.is_a?(Array) @@ -178,39 +178,39 @@ # Adds an item to the given +menu+. # The +id+ parameter (equals to the project id) is automatically added to the url. # menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample' - # + # # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu - # + # def menu(menu, item, url, options={}) Redmine::MenuManager.map(menu).push(item, url, options) end alias :add_menu_item :menu - + # Removes +item+ from the given +menu+. def delete_menu_item(menu, item) Redmine::MenuManager.map(menu).delete(item) end # Defines a permission called +name+ for the given +actions+. - # + # # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array): # permission :destroy_contacts, { :contacts => :destroy } # permission :view_contacts, { :contacts => [:index, :show] } - # + # # The +options+ argument can be used to make the permission public (implicitly given to any user) # or to restrict users the permission can be given to. - # + # # Examples # # A permission that is implicitly given to any user # # This permission won't appear on the Roles & Permissions setup screen # permission :say_hello, { :example => :say_hello }, :public => true - # + # # # A permission that can be given to any user # permission :say_hello, { :example => :say_hello } - # + # # # A permission that can be given to registered users only # permission :say_hello, { :example => :say_hello }, :require => :loggedin - # + # # # A permission that can be given to project members only # permission :say_hello, { :example => :say_hello }, :require => :member def permission(name, actions, options = {}) @@ -220,10 +220,10 @@ Redmine::AccessControl.map {|map| map.permission(name, actions, options)} end end - + # Defines a project module, that can be enabled/disabled for each project. # Permissions defined inside +block+ will be bind to the module. - # + # # project_module :things do # permission :view_contacts, { :contacts => [:list, :show] }, :public => true # permission :destroy_contacts, { :contacts => :destroy } @@ -233,33 +233,33 @@ self.instance_eval(&block) @project_module = nil end - + # Registers an activity provider. # # Options: # * :class_name - one or more model(s) that provide these events (inferred from event_type by default) # * :default - setting this option to false will make the events not displayed by default - # + # # A model can provide several activity event types. - # + # # Examples: # register :news # register :scrums, :class_name => 'Meeting' # register :issues, :class_name => ['Issue', 'Journal'] - # + # # Retrieving events: # Associated model(s) must implement the find_events class method. # ActiveRecord models can use acts_as_activity_provider as a way to implement this class method. - # - # The following call should return all the scrum events visible by current user that occured in the 5 last days: + # + # The following call should return all the scrum events visible by current user that occured in the 5 last days: # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today) # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today, :project => foo) # events for project foo only - # + # # Note that :view_scrums permission is required to view these events in the activity view. def activity_provider(*args) Redmine::Activity.register(*args) end - + # Registers a wiki formatter. # # Parameters: diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/pop3.rb --- a/lib/redmine/pop3.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/pop3.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -51,7 +51,7 @@ end end end - + private def logger diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/safe_attributes.rb --- a/lib/redmine/safe_attributes.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/safe_attributes.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -20,7 +20,7 @@ def self.included(base) base.extend(ClassMethods) end - + module ClassMethods # Declares safe attributes # An optional Proc can be given for conditional inclusion @@ -38,7 +38,7 @@ end end end - + # Returns an array that can be safely set by user or current user # # Example: @@ -53,10 +53,10 @@ end names.uniq end - + # Returns a hash with unsafe attributes removed # from the given attrs hash - # + # # Example: # book.delete_unsafe_attributes({'title' => 'My book', 'foo' => 'bar'}) # # => {'title' => 'My book'} @@ -64,7 +64,7 @@ safe = safe_attribute_names(user) attrs.dup.delete_if {|k,v| !safe.include?(k)} end - + # Sets attributes from attrs that are safe # attrs is a Hash with string keys def safe_attributes=(attrs, user=User.current) diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/abstract_adapter.rb --- a/lib/redmine/scm/adapters/abstract_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/abstract_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -24,11 +24,23 @@ end class AbstractAdapter #:nodoc: + + # raised if scm command exited with error, e.g. unknown revision. + class ScmCommandAborted < CommandFailed; end + class << self def client_command "" end + def shell_quote_command + if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java' + client_command + else + shell_quote(client_command) + end + end + # Returns the version of the scm client # Eg: [1, 5, 0] or [] if unknown def client_version @@ -180,10 +192,14 @@ info ? info.root_url : nil end - def target(path) + def target(path, sq=true) path ||= '' base = path.match(/^\//) ? root_url : url - shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, '')) + str = "#{base}/#{path}".gsub(/[?<>\*]/, '') + if sq + str = shell_quote(str) + end + str end def logger @@ -195,7 +211,7 @@ end def self.logger - RAILS_DEFAULT_LOGGER + Rails.logger end def self.shellout(cmd, &block) @@ -204,7 +220,7 @@ end if Rails.env == 'development' # Capture stderr when running in dev environment - cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log" + cmd = "#{cmd} 2>>#{Rails.root}/log/scm.stderr.log" end begin if RUBY_VERSION < '1.9' @@ -216,7 +232,11 @@ io.close_write block.call(io) if block_given? end - rescue Errno::ENOENT => e + ## If scm command does not exist, + ## Linux JRuby 1.6.2 (ruby-1.8.7-p330) raises java.io.IOException + ## in production environment. + # rescue Errno::ENOENT => e + rescue Exception => e msg = strip_credential(e.message) # The command failed, log it and re-raise logmsg = "SCM command failed, " @@ -313,7 +333,8 @@ class Revision attr_accessor :scmid, :name, :author, :time, :message, - :paths, :revision, :branch, :identifier + :paths, :revision, :branch, :identifier, + :parents def initialize(attributes={}) self.identifier = attributes[:identifier] @@ -325,6 +346,7 @@ self.paths = attributes[:paths] self.revision = attributes[:revision] self.branch = attributes[:branch] + self.parents = attributes[:parents] end # Returns the readable identifier. @@ -354,6 +376,10 @@ lines.empty? end end + + class Branch < String + attr_accessor :revision, :scmid + end end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/bazaar_adapter.rb --- a/lib/redmine/scm/adapters/bazaar_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/bazaar_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -31,7 +31,7 @@ end def sq_bin - @@sq_bin ||= shell_quote(BZR_BIN) + @@sq_bin ||= shell_quote_command end def client_version @@ -59,9 +59,10 @@ # Get info about the repository def info - cmd = "#{self.class.sq_bin} revno #{target('')}" + cmd_args = %w|revno| + cmd_args << bzr_target('') info = nil - shellout(cmd) do |io| + scm_cmd(*cmd_args) do |io| if io.read =~ %r{^(\d+)\r?$} info = Info.new({:root_url => url, :lastrev => Revision.new({ @@ -70,9 +71,8 @@ }) end end - return nil if $? && $?.exitstatus != 0 info - rescue CommandFailed + rescue ScmCommandAborted return nil end @@ -81,11 +81,11 @@ def entries(path=nil, identifier=nil, options={}) path ||= '' entries = Entries.new - cmd = "#{self.class.sq_bin} ls -v --show-ids" identifier = -1 unless identifier && identifier.to_i > 0 - cmd << " -r#{identifier.to_i}" - cmd << " #{target(path)}" - shellout(cmd) do |io| + cmd_args = %w|ls -v --show-ids| + cmd_args << "-r#{identifier.to_i}" + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| prefix = "#{url}/#{path}".gsub('\\', '/') logger.debug "PREFIX: #{prefix}" re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$} @@ -99,9 +99,12 @@ }) end end - return nil if $? && $?.exitstatus != 0 - logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug? + if logger && logger.debug? + logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") + end entries.sort_by_name + rescue ScmCommandAborted + return nil end def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) @@ -109,10 +112,12 @@ identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1' identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1 revisions = Revisions.new - cmd = "#{self.class.sq_bin} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}" - shellout(cmd) do |io| + cmd_args = %w|log -v --show-ids| + cmd_args << "-r#{identifier_to}..#{identifier_from}" + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| revision = nil - parsing = nil + parsing = nil io.each_line do |line| if line =~ /^----/ revisions << revision if revision @@ -160,8 +165,9 @@ end revisions << revision if revision end - return nil if $? && $?.exitstatus != 0 revisions + rescue ScmCommandAborted + return nil end def diff(path, identifier_from, identifier_to=nil) @@ -174,37 +180,39 @@ if identifier_from identifier_from = identifier_from.to_i end - cmd = "#{self.class.sq_bin} diff -r#{identifier_to}..#{identifier_from} #{target(path)}" diff = [] - shellout(cmd) do |io| + cmd_args = %w|diff| + cmd_args << "-r#{identifier_to}..#{identifier_from}" + cmd_args << bzr_target(path) + scm_cmd_no_raise(*cmd_args) do |io| io.each_line do |line| diff << line end end - #return nil if $? && $?.exitstatus != 0 diff end def cat(path, identifier=nil) - cmd = "#{self.class.sq_bin} cat" - cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0 - cmd << " #{target(path)}" cat = nil - shellout(cmd) do |io| + cmd_args = %w|cat| + cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0 + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| io.binmode cat = io.read end - return nil if $? && $?.exitstatus != 0 cat + rescue ScmCommandAborted + return nil end def annotate(path, identifier=nil) - cmd = "#{self.class.sq_bin} annotate --all" - cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0 - cmd << " #{target(path)}" blame = Annotate.new - shellout(cmd) do |io| - author = nil + cmd_args = %w|annotate -q --all| + cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0 + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + author = nil identifier = nil io.each_line do |line| next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$} @@ -217,9 +225,87 @@ )) end end - return nil if $? && $?.exitstatus != 0 blame + rescue ScmCommandAborted + return nil end + + def self.branch_conf_path(path) + bcp = nil + m = path.match(%r{^(.*[/\\])\.bzr.*$}) + if m + bcp = m[1] + else + bcp = path + end + bcp.gsub!(%r{[\/\\]$}, "") + if bcp + bcp = File.join(bcp, ".bzr", "branch", "branch.conf") + end + bcp + end + + def append_revisions_only + return @aro if ! @aro.nil? + @aro = false + bcp = self.class.branch_conf_path(url) + if bcp && File.exist?(bcp) + begin + f = File::open(bcp, "r") + cnt = 0 + f.each_line do |line| + l = line.chomp.to_s + if l =~ /^\s*append_revisions_only\s*=\s*(\w+)\s*$/ + str_aro = $1 + if str_aro.upcase == "TRUE" + @aro = true + cnt += 1 + elsif str_aro.upcase == "FALSE" + @aro = false + cnt += 1 + end + if cnt > 1 + @aro = false + break + end + end + end + ensure + f.close + end + end + @aro + end + + def scm_cmd(*args, &block) + full_args = [] + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "bzr exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd + + def scm_cmd_no_raise(*args, &block) + full_args = [] + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + ret + end + private :scm_cmd_no_raise + + def bzr_target(path) + target(path, false) + end + private :bzr_target end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/cvs_adapter.rb --- a/lib/redmine/scm/adapters/cvs_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/cvs_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -25,16 +25,13 @@ # CVS executable name CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" - # raised if scm command exited with error, e.g. unknown revision. - class ScmCommandAborted < CommandFailed; end - class << self def client_command @@bin ||= CVS_BIN end def sq_bin - @@sq_bin ||= shell_quote(CVS_BIN) + @@sq_bin ||= shell_quote_command end def client_version @@ -379,13 +376,16 @@ end def scm_cmd(*args, &block) - full_args = [CVS_BIN, '-d', root_url] + full_args = ['-d', root_url] full_args += args full_args_locale = [] full_args.map do |e| full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) end - ret = shellout(full_args_locale.map { |e| shell_quote e.to_s }.join(' '), &block) + ret = shellout( + self.class.sq_bin + ' ' + full_args_locale.map { |e| shell_quote e.to_s }.join(' '), + &block + ) if $? && $?.exitstatus != 0 raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}" end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/darcs_adapter.rb --- a/lib/redmine/scm/adapters/darcs_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/darcs_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -31,7 +31,7 @@ end def sq_bin - @@sq_bin ||= shell_quote(DARCS_BIN) + @@sq_bin ||= shell_quote_command end def client_version diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/git_adapter.rb --- a/lib/redmine/scm/adapters/git_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/git_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -25,16 +25,13 @@ # Git executable name GIT_BIN = Redmine::Configuration['scm_git_command'] || "git" - # raised if scm command exited with error, e.g. unknown revision. - class ScmCommandAborted < CommandFailed; end - class << self def client_command @@bin ||= GIT_BIN end def sq_bin - @@sq_bin ||= shell_quote(GIT_BIN) + @@sq_bin ||= shell_quote_command end def client_version @@ -80,10 +77,14 @@ def branches return @branches if @branches @branches = [] - cmd_args = %w|branch --no-color| + cmd_args = %w|branch --no-color --verbose --no-abbrev| scm_cmd(*cmd_args) do |io| io.each_line do |line| - @branches << line.match('\s*\*?\s*(.*)$')[1] + branch_rev = line.match('\s*\*?\s*(.*?)\s*([0-9a-f]{40}).*$') + bran = Branch.new(branch_rev[1]) + bran.revision = branch_rev[2] + bran.scmid = branch_rev[2] + @branches << bran end end @branches.sort! @@ -188,7 +189,7 @@ def revisions(path, identifier_from, identifier_to, options={}) revs = Revisions.new - cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller| + cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents| cmd_args << "--reverse" if options[:reverse] cmd_args << "--all" if options[:all] cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit] @@ -205,9 +206,10 @@ parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files io.each_line do |line| - if line =~ /^commit ([0-9a-f]{40})$/ + if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/ key = "commit" value = $1 + parents_str = $2 if (parsing_descr == 1 || parsing_descr == 2) parsing_descr = 0 revision = Revision.new({ @@ -216,7 +218,8 @@ :author => changeset[:author], :time => Time.parse(changeset[:date]), :message => changeset[:description], - :paths => files + :paths => files, + :parents => changeset[:parents] }) if block_given? yield revision @@ -227,6 +230,9 @@ files = [] end changeset[:commit] = $1 + unless parents_str.nil? or parents_str == "" + changeset[:parents] = parents_str.strip.split(' ') + end elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/ key = $1 value = $2 @@ -266,7 +272,8 @@ :author => changeset[:author], :time => Time.parse(changeset[:date]), :message => changeset[:description], - :paths => files + :paths => files, + :parents => changeset[:parents] }) if block_given? yield revision @@ -359,13 +366,16 @@ def scm_cmd(*args, &block) repo_path = root_url || url - full_args = [GIT_BIN, '--git-dir', repo_path] + full_args = ['--git-dir', repo_path] if self.class.client_version_above?([1, 7, 2]) full_args << '-c' << 'core.quotepath=false' full_args << '-c' << 'log.decorate=no' end full_args += args - ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block) + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) if $? && $?.exitstatus != 0 raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}" end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl --- a/lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl Mon Feb 27 13:53:18 2012 +0000 @@ -1,12 +1,12 @@ changeset = 'This template must be used with --debug option\n' changeset_quiet = 'This template must be used with --debug option\n' changeset_verbose = 'This template must be used with --debug option\n' -changeset_debug = '\n{author|escape}\n{date|isodatesec}\n\n{file_mods}{file_adds}{file_dels}{file_copies}\n{desc|escape}\n{tags}\n\n' +changeset_debug = '\n{author|escape}\n{date|isodatesec}\n\n{file_mods}{file_adds}{file_dels}{file_copies}\n{desc|escape}\n\n{parents}\n\n\n' file_mod = '{file_mod|urlescape}\n' file_add = '{file_add|urlescape}\n' file_del = '{file_del|urlescape}\n' file_copy = '{name|urlescape}\n' -tag = '{tag|escape}\n' +parent = '{node|short}\n' header='\n\n\n' footer='' diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/mercurial/redminehelper.py --- a/lib/redmine/scm/adapters/mercurial/redminehelper.py Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/mercurial/redminehelper.py Mon Feb 27 13:53:18 2012 +0000 @@ -46,7 +46,7 @@ """ import re, time, cgi, urllib -from mercurial import cmdutil, commands, node, error +from mercurial import cmdutil, commands, node, error, hg _x = cgi.escape _u = lambda s: cgi.escape(urllib.quote(s)) @@ -146,7 +146,10 @@ bra = urllib.unquote_plus(opts.pop('rhbranch', None)) from_rev = from_rev.replace('"', '\\"') to_rev = to_rev.replace('"', '\\"') - opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)] + if hg.util.version() >= '1.6': + opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)] + else: + opts['rev'] = ['%s:%s' % (from_rev, to_rev)] opts['branch'] = [bra] return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts) @@ -196,21 +199,21 @@ [ ('r', 'rev', [], 'show the specified revision'), ('b', 'branch', [], - 'show changesets within the given named branch', 'BRANCH'), + 'show changesets within the given named branch'), ('l', 'limit', '', - 'limit number of changes displayed', 'NUM'), + 'limit number of changes displayed'), ('d', 'date', '', - 'show revisions matching date spec', 'DATE'), + 'show revisions matching date spec'), ('u', 'user', [], - 'revisions committed by user', 'USER'), + 'revisions committed by user'), ('', 'from', '', - '', ''), + ''), ('', 'to', '', - '', ''), + ''), ('', 'rhbranch', '', - '', ''), + ''), ('', 'template', '', - 'display with template', 'TEMPLATE')], + 'display with template')], 'hg rhlog [OPTION]... [FILE]'), 'rhmanifest': (rhmanifest, [('r', 'rev', '', 'show the specified revision')], diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/mercurial_adapter.rb --- a/lib/redmine/scm/adapters/mercurial_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -39,7 +39,7 @@ end def sq_bin - @@sq_bin ||= shell_quote(HG_BIN) + @@sq_bin ||= shell_quote_command end def client_version @@ -47,7 +47,7 @@ end def client_available - client_version_above?([0, 9, 5]) + client_version_above?([1, 2]) end def hgversion @@ -72,12 +72,7 @@ end def template_path_for(version) - if ((version <=> [0,9,5]) > 0) || version.empty? - ver = "1.0" - else - ver = "0.9.5" - end - "#{HELPERS_DIR}/#{TEMPLATE_NAME}-#{ver}.#{TEMPLATE_EXTENSION}" + "#{HELPERS_DIR}/#{TEMPLATE_NAME}-1.0.#{TEMPLATE_EXTENSION}" end end @@ -114,7 +109,14 @@ end def branches - as_ary(summary['repository']['branch']).map { |e| e['name'] } + brs = [] + as_ary(summary['repository']['branch']).each do |e| + br = Branch.new(e['name']) + br.revision = e['revision'] + br.scmid = e['node'] + brs << br + end + brs end # Returns map of {'branch' => 'nodeid', ...} @@ -214,12 +216,17 @@ :from_path => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil), :from_revision => (cpmap.member?(p) ? le['node'] : nil)} end.sort { |a, b| a[:path] <=> b[:path] } + parents_ary = [] + as_ary(le['parents']['parent']).map do |par| + parents_ary << par['__content__'] if par['__content__'] != "000000000000" + end yield Revision.new(:revision => le['revision'], :scmid => le['node'], :author => (le['author']['__content__'] rescue ''), :time => Time.parse(le['date']['__content__']), :message => le['msg']['__content__'], - :paths => paths) + :paths => paths, + :parents => parents_ary) end self end @@ -293,11 +300,14 @@ # Runs 'hg' command with the given args def hg(*args, &block) repo_path = root_url || url - full_args = [HG_BIN, '-R', repo_path, '--encoding', 'utf-8'] + full_args = ['-R', repo_path, '--encoding', 'utf-8'] full_args << '--config' << "extensions.redminehelper=#{HG_HELPER_EXT}" full_args << '--config' << 'diff.git=false' full_args += args - ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block) + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) if $? && $?.exitstatus != 0 raise HgCommandAborted, "hg exited with non-zero status: #{$?.exitstatus}" end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/mercurial_adapter.rb.rej --- a/lib/redmine/scm/adapters/mercurial_adapter.rb.rej Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ ---- lib/redmine/scm/adapters/mercurial_adapter.rb -+++ lib/redmine/scm/adapters/mercurial_adapter.rb -@@ -67,19 +67,17 @@ - end - - def info -- cmd = "#{HG_BIN} -R #{target('')} root" -- root_url = nil -- shellout(cmd) do |io| -- root_url = io.gets -- end -- return nil if $? && $?.exitstatus != 0 -- info = Info.new({:root_url => root_url.chomp, -- :lastrev => revisions(nil,nil,nil,{:limit => 1}).last -- }) -- info -- rescue CommandFailed -- return nil -+ tip = summary['tip'].first -+ Info.new(:root_url => summary['root'].first['path'], -+ :lastrev => Revision.new(:identifier => tip['rev'].to_i, -+ :revision => tip['rev'], -+ :scmid => tip['node'])) - end -+ -+ def summary -+ @summary ||= fetchg 'rhsummary' -+ end -+ private :summary - - def entries(path=nil, identifier=nil) - path ||= '' ---- lib/redmine/scm/adapters/mercurial_adapter.rb -+++ lib/redmine/scm/adapters/mercurial_adapter.rb -@@ -74,6 +74,16 @@ - :scmid => tip['node'])) - end - -+ def tags -+ summary['tags'].map { |e| e['name'] } -+ end -+ -+ # Returns map of {'tag' => 'nodeid', ...} -+ def tagmap -+ alist = summary['tags'].map { |e| e.values_at('name', 'node') } -+ Hash[*alist.flatten] -+ end -+ - def summary - @summary ||= fetchg 'rhsummary' - end ---- lib/redmine/scm/adapters/mercurial_adapter.rb -+++ lib/redmine/scm/adapters/mercurial_adapter.rb -@@ -84,6 +84,19 @@ - Hash[*alist.flatten] - end - -+ def branches -+ summary['branches'].map { |e| e['name'] } -+ end -+ -+ # Returns map of {'branch' => 'nodeid', ...} -+ def branchmap -+ alist = summary['branches'].map { |e| e.values_at('name', 'node') } -+ Hash[*alist.flatten] -+ end -+ -+ # NOTE: DO NOT IMPLEMENT default_branch !! -+ # It's used as the default revision by RepositoriesController. -+ - def summary - @summary ||= fetchg 'rhsummary' - end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/scm/adapters/subversion_adapter.rb --- a/lib/redmine/scm/adapters/subversion_adapter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/scm/adapters/subversion_adapter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -32,7 +32,7 @@ end def sq_bin - @@sq_bin ||= shell_quote(SVN_BIN) + @@sq_bin ||= shell_quote_command end def client_version diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/search.rb --- a/lib/redmine/search.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/search.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,39 +1,39 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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 Search - + mattr_accessor :available_search_types - + @@available_search_types = [] class << self def map(&block) yield self end - + # Registers a search provider def register(search_type, options={}) search_type = search_type.to_s @@available_search_types << search_type unless @@available_search_types.include?(search_type) end end - + module Controller def self.included(base) base.extend(ClassMethods) @@ -42,7 +42,7 @@ module ClassMethods @@default_search_scopes = Hash.new {|hash, key| hash[key] = {:default => nil, :actions => {}}} mattr_accessor :default_search_scopes - + # Set the default search scope for a controller or specific actions # Examples: # * search_scope :issues # => sets the search scope to :issues for the whole controller diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/syntax_highlighting.rb --- a/lib/redmine/syntax_highlighting.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/syntax_highlighting.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,27 +1,27 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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 SyntaxHighlighting - + class << self attr_reader :highlighter delegate :highlight_by_filename, :highlight_by_language, :to => :highlighter - + def highlighter=(name) if name.is_a?(Module) @highlighter = name @@ -30,11 +30,11 @@ end end end - + module CodeRay require 'coderay' require 'coderay/helpers/file_type' - + class << self # Highlights +text+ as the content of +filename+ # Should not return line numbers nor outer pre tag @@ -42,15 +42,15 @@ language = ::CodeRay::FileType[filename] language ? ::CodeRay.scan(text, language).html : ERB::Util.h(text) end - + # Highlights +text+ using +language+ syntax # Should not return outer pre tag def highlight_by_language(text, language) - ::CodeRay.scan(text, language).html(:line_numbers => :inline, :wrap => :span) + ::CodeRay.scan(text, language).html(:line_numbers => :inline, :line_number_anchors => false, :wrap => :span) end end end end - + SyntaxHighlighting.highlighter = 'CodeRay' end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/themes.rb --- a/lib/redmine/themes.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/themes.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,37 +1,37 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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 Themes - + # Return an array of installed themes def self.themes @@installed_themes ||= scan_themes end - + # Rescan themes directory def self.rescan @@installed_themes = scan_themes end - + # Return theme for given id, or nil if it's not found def self.theme(id, options={}) return nil if id.blank? - + found = themes.find {|t| t.id == id} if found.nil? && options[:rescan] != false rescan @@ -39,11 +39,11 @@ end found end - + # Class used to represent a theme class Theme attr_reader :path, :name, :dir - + def initialize(path) @path = path @dir = File.basename(path) @@ -51,43 +51,43 @@ @stylesheets = nil @javascripts = nil end - + # Directory name used as the theme id def id; dir end - + def ==(theme) theme.is_a?(Theme) && theme.dir == dir end - + def <=>(theme) name <=> theme.name end - + def stylesheets @stylesheets ||= assets("stylesheets", "css") end - + def javascripts @javascripts ||= assets("javascripts", "js") end - + def stylesheet_path(source) "/themes/#{dir}/stylesheets/#{source}" end - + def javascript_path(source) "/themes/#{dir}/javascripts/#{source}" end - + private - + def assets(dir, ext) Dir.glob("#{path}/#{dir}/*.#{ext}").collect {|f| File.basename(f).gsub(/\.#{ext}$/, '')} end end - + private - + def self.scan_themes dirs = Dir.glob("#{Rails.public_path}/themes/*").select do |f| # A theme should at least override application.css @@ -105,7 +105,7 @@ end @current_theme end - + def stylesheet_path(source) if current_theme && current_theme.stylesheets.include?(source) super current_theme.stylesheet_path(source) @@ -113,11 +113,11 @@ super end end - + def path_to_stylesheet(source) stylesheet_path source end - + # Returns the header tags for the current theme def heads_for_theme if current_theme && current_theme.javascripts.include?('theme') diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/unified_diff.rb --- a/lib/redmine/unified_diff.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/unified_diff.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,7 +19,7 @@ # Class used to parse unified diffs class UnifiedDiff < Array attr_reader :diff_type - + def initialize(diff, options={}) options.assert_valid_keys(:type, :max_lines) diff = diff.split("\n") if diff.is_a?(String) @@ -55,7 +55,7 @@ end # Class that represents a file diff - class DiffTable < Array + class DiffTable < Array attr_reader :file_name # Initialize with a Diff file and the type of Diff View @@ -86,12 +86,12 @@ @line_num_l = $2.to_i @line_num_r = $5.to_i else - parse_line(line, @type) + parse_line(line, @type) end end return true end - + def each_line prev_line_left, prev_line_right = nil, nil each do |line| @@ -116,7 +116,7 @@ def escapeHTML(line) CGI.escapeHTML(line) end - + def diff_for_added_line if @type == 'sbs' && @removed > 0 && @added < @removed self[-(@removed - @added)] @@ -164,7 +164,7 @@ end end end - + def write_offsets if @added > 0 && @added == @removed @added.times do |i| @@ -177,7 +177,7 @@ @added = 0 @removed = 0 end - + def offsets(line_left, line_right) if line_left.present? && line_right.present? && line_left != line_right max = [line_left.size, line_right.size].min @@ -197,7 +197,7 @@ end # A line of diff - class Diff + class Diff attr_accessor :nb_line_left attr_accessor :line_left attr_accessor :nb_line_right @@ -205,7 +205,7 @@ attr_accessor :type_diff_right attr_accessor :type_diff_left attr_accessor :offsets - + def initialize() self.nb_line_left = '' self.nb_line_right = '' @@ -214,15 +214,15 @@ self.type_diff_right = '' self.type_diff_left = '' end - + def type_diff type_diff_right == 'diff_in' ? type_diff_right : type_diff_left end - + def line type_diff_right == 'diff_in' ? line_right : line_left end - + def html_line_left if offsets line_left.dup.insert(offsets.first, '').insert(offsets.last, '') @@ -230,7 +230,7 @@ line_left end end - + def html_line_right if offsets line_right.dup.insert(offsets.first, '').insert(offsets.last, '') @@ -238,7 +238,7 @@ line_right end end - + def html_line if offsets line.dup.insert(offsets.first, '').insert(offsets.last, '') diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/utils.rb --- a/lib/redmine/utils.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/utils.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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 @@ -24,7 +24,7 @@ ActionController::Base.relative_url_root.to_s : ActionController::AbstractRequest.relative_url_root.to_s end - + # Sets the relative root url of the application def relative_url_root=(arg) if ActionController::Base.respond_to?('relative_url_root=') diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/version.rb --- a/lib/redmine/version.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/version.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,7 +3,7 @@ module Redmine module VERSION #:nodoc: MAJOR = 1 - MINOR = 2 + MINOR = 3 TINY = 1 # Branch values: @@ -14,7 +14,7 @@ def self.revision revision = nil - entries_path = "#{RAILS_ROOT}/.svn/entries" + entries_path = "#{Rails.root}/.svn/entries" if File.readable?(entries_path) begin f = File.open(entries_path, 'r') @@ -37,8 +37,8 @@ REVISION = self.revision ARRAY = [MAJOR, MINOR, TINY, BRANCH, REVISION].compact STRING = ARRAY.join('.') - + def self.to_a; ARRAY end - def self.to_s; STRING end + def self.to_s; STRING end end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/api_template_handler.rb --- a/lib/redmine/views/api_template_handler.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/api_template_handler.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -20,7 +20,7 @@ class ApiTemplateHandler < ActionView::TemplateHandler include ActionView::TemplateHandlers::Compilable - def compile(template) + def compile(template) "Redmine::Views::Builders.for(params[:format]) do |api|; #{template.source}; self.output_buffer = api.output; end" end end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/builders.rb --- a/lib/redmine/views/builders.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/builders.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/builders/json.rb --- a/lib/redmine/views/builders/json.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/builders/json.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/builders/structure.rb --- a/lib/redmine/views/builders/structure.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/builders/structure.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -24,7 +24,7 @@ def initialize @struct = [{}] end - + def array(tag, options={}, &block) @struct << [] block.call(self) @@ -32,7 +32,7 @@ @struct.last[tag] = ret @struct.last.merge!(options) if options end - + def method_missing(sym, *args, &block) if args.any? if args.first.is_a?(Hash) @@ -49,7 +49,7 @@ end end end - + if block @struct << (args.first.is_a?(Hash) ? args.first : {}) block.call(self) @@ -65,7 +65,7 @@ end end end - + def output raise "Need to implement #{self.class.name}#output" end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/builders/xml.rb --- a/lib/redmine/views/builders/xml.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/builders/xml.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,11 +23,11 @@ super instruct! end - + def output target! end - + def method_missing(sym, *args, &block) if args.size == 1 && args.first.is_a?(Time) __send__ sym, args.first.xmlschema, &block @@ -35,7 +35,7 @@ super end end - + def array(name, options={}, &block) __send__ name, (options || {}).merge(:type => 'array'), &block end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/my_page/block.rb --- a/lib/redmine/views/my_page/block.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/my_page/block.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -20,7 +20,7 @@ module MyPage module Block def self.additional_blocks - @@additional_blocks ||= Dir.glob("#{RAILS_ROOT}/vendor/plugins/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file| + @@additional_blocks ||= Dir.glob("#{Rails.root}/vendor/plugins/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file| name = File.basename(file).split('.').first.gsub(/^_/, '') h[name] = name.to_sym h diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/views/other_formats_builder.rb --- a/lib/redmine/views/other_formats_builder.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/views/other_formats_builder.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -21,7 +21,7 @@ def initialize(view) @view = view end - + def link_to(name, options={}) url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {}) caption = options.delete(:caption) || name diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/wiki_formatting.rb --- a/lib/redmine/wiki_formatting.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/wiki_formatting.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,49 +1,55 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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 WikiFormatting + class StaleSectionError < Exception; end + @@formatters = {} class << self def map yield self end - + def register(name, formatter, helper) raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_s] @@formatters[name.to_s] = {:formatter => formatter, :helper => helper} end - + + def formatter + formatter_for(Setting.text_formatting) + end + def formatter_for(name) entry = @@formatters[name.to_s] (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter end - + def helper_for(name) entry = @@formatters[name.to_s] (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper end - + def format_names @@formatters.keys.map end - - def to_html(format, text, options = {}, &block) + + def to_html(format, text, options = {}) text = if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, options[:object], options[:attribute]) # Text retrieved from the cache store may be frozen # We need to dup it so we can do in-place substitutions with gsub! @@ -53,75 +59,50 @@ else formatter_for(format).new(text).to_html end - if block_given? - execute_macros(text, block) - end text end + # Returns true if the text formatter supports single section edit + def supports_section_edit? + (formatter.instance_methods & ['update_section', :update_section]).any? + end + # Returns a cache key for the given text +format+, +object+ and +attribute+ or nil if no caching should be done def cache_key_for(format, object, attribute) if object && attribute && !object.new_record? && object.respond_to?(:updated_on) && !format.blank? "formatted_text/#{format}/#{object.class.model_name.cache_key}/#{object.id}-#{attribute}-#{object.updated_on.to_s(:number)}" end end - + # Returns the cache store used to cache HTML output def cache_store ActionController::Base.cache_store end - - MACROS_RE = / - (!)? # escaping - ( - \{\{ # opening tag - ([\w]+) # macro name - (\(([^\}]*)\))? # optional arguments - \}\} # closing tag - ) - /x unless const_defined?(:MACROS_RE) - - # Macros substitution - def execute_macros(text, macros_runner) - text.gsub!(MACROS_RE) do - esc, all, macro = $1, $2, $3.downcase - args = ($5 || '').split(',').each(&:strip) - if esc.nil? - begin - macros_runner.call(macro, args) - rescue => e - "
    Error executing the #{macro} macro (#{e})
    " - end || all - else - all - end - end - end end - + # Default formatter module module NullFormatter class Formatter include ActionView::Helpers::TagHelper include ActionView::Helpers::TextHelper include ActionView::Helpers::UrlHelper - + def initialize(text) @text = text end - + def to_html(*args) simple_format(auto_link(CGI::escapeHTML(@text))) end end - + module Helper def wikitoolbar_for(field_id) end - + def heads_for_wiki_formatter end - + def initial_page_content(page) page.pretty_title.to_s end diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/wiki_formatting/macros.rb --- a/lib/redmine/wiki_formatting/macros.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/wiki_formatting/macros.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ method_name = "macro_#{name}" send(method_name, obj, args) if respond_to?(method_name) end - + def extract_macro_options(args, *keys) options = {} while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym) @@ -33,17 +33,17 @@ return [args, options] end end - + @@available_macros = {} - + class << self # Called with a block to define additional macros. # Macro blocks accept 2 arguments: # * obj: the object that is rendered # * args: macro arguments - # + # # Plugins can use this method to define new macros: - # + # # Redmine::WikiFormatting::Macros.register do # desc "This is my macro" # macro :my_macro do |obj, args| @@ -53,7 +53,7 @@ def register(&block) class_eval(&block) if block_given? end - + private # Defines a new macro with the given name and block. def macro(name, &block) @@ -63,21 +63,21 @@ raise "Can not create a macro without a block!" unless block_given? Definitions.send :define_method, "macro_#{name}".downcase, &block end - + # Sets description for the next macro to be defined def desc(txt) @@desc = txt end end - + # Builtin macros desc "Sample macro." macro :hello_world do |obj, args| "Hello world! Object: #{obj.class.name}, " + (args.empty? ? "Called with no argument." : "Arguments: #{args.join(', ')}") end - + desc "Displays a list of all available macros, including description if available." - macro :macro_list do + macro :macro_list do |obj, args| out = '' @@available_macros.keys.collect(&:to_s).sort.each do |macro| out << content_tag('dt', content_tag('code', macro)) @@ -85,7 +85,7 @@ end content_tag('dl', out) end - + desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" + " !{{child_pages}} -- can be used from a wiki page only\n" + " !{{child_pages(Foo)}} -- lists all children of page Foo\n" + @@ -104,7 +104,7 @@ pages = ([page] + page.descendants).group_by(&:parent_id) render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id) end - + desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" macro :include do |obj, args| page = Wiki.find_page(args.first.to_s, :project => @project) diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/wiki_formatting/textile/formatter.rb --- a/lib/redmine/wiki_formatting/textile/formatter.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/wiki_formatting/textile/formatter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,51 +1,115 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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 'redcloth3' +require 'digest/md5' module Redmine module WikiFormatting module Textile class Formatter < RedCloth3 include ActionView::Helpers::TagHelper - + # auto_link rule after textile rules so that it doesn't break !image_url! tags RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] - + def initialize(*args) super self.hard_breaks=true self.no_span_caps=true self.filter_styles=true end - + def to_html(*rules) @toc = [] super(*RULES).to_s end - + + def get_section(index) + section = extract_sections(index)[1] + hash = Digest::MD5.hexdigest(section) + return section, hash + end + + def update_section(index, update, hash=nil) + t = extract_sections(index) + if hash.present? && hash != Digest::MD5.hexdigest(t[1]) + raise Redmine::WikiFormatting::StaleSectionError + end + t[1] = update unless t[1].blank? + t.reject(&:blank?).join "\n\n" + end + + def extract_sections(index) + @pre_list = [] + text = self.dup + rip_offtags text, false, false + before = '' + s = '' + after = '' + i = 0 + l = 1 + started = false + ended = false + text.scan(/(((?:.*?)(\A|\r?\n\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))? (.*?)$)|.*)/m).each do |all, content, lf, heading, level| + if heading.nil? + if ended + after << all + elsif started + s << all + else + before << all + end + break + end + i += 1 + if ended + after << all + elsif i == index + l = level.to_i + before << content + s << heading + started = true + elsif i > index + s << content + if level.to_i > l + s << heading + else + after << heading + ended = true + end + else + before << all + end + end + sections = [before.strip, s.strip, after.strip] + sections.each {|section| smooth_offtags_without_code_highlighting section} + sections + end + private - + # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. # http://code.whytheluckystiff.net/redcloth/changeset/128 - def hard_break( text ) + def hard_break( text ) text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1
    " ) if hard_breaks end - + + alias :smooth_offtags_without_code_highlighting :smooth_offtags # Patch to add code highlighting support to RedCloth def smooth_offtags( text ) unless @pre_list.empty? @@ -53,18 +117,18 @@ text.gsub!(//) do content = @pre_list[$1.to_i] if content.match(/\s?(.+)/m) - content = "" + + content = "" + Redmine::SyntaxHighlighting.highlight_by_language($2, $1) end content end end end - + AUTO_LINK_RE = %r{ ( # leading text <\w+.*?>| # leading HTML tag, or - [^=<>!:'"/]| # leading punctuation, or + [^=<>!:'"/]| # leading punctuation, or ^ # beginning of line ) ( @@ -79,7 +143,7 @@ ((?:>)?|[^\w\=\/;\(\)]*?) # post (?=<|\s|$) }x unless const_defined?(:AUTO_LINK_RE) - + # Turns all urls into clickable links (code from Rails). def inline_auto_link(text) text.gsub!(AUTO_LINK_RE) do @@ -100,7 +164,7 @@ end end end - + # Turns all email addresses into clickable links (code from Rails). def inline_auto_mailto(text) text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do diff -r 487d96eac004 -r 5e80956cc792 lib/redmine/wiki_formatting/textile/helper.rb --- a/lib/redmine/wiki_formatting/textile/helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/redmine/wiki_formatting/textile/helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -25,14 +25,14 @@ url = "#{Redmine::Utils.relative_url_root}/help/wiki_syntax.html" help_link = link_to(l(:setting_text_formatting), url, :onclick => "window.open(\"#{ url }\", \"\", \"resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\"); return false;") - + javascript_tag("var wikiToolbar = new jsToolBar($('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript help_link}'); wikiToolbar.draw();") end - + def initial_page_content(page) "h1. #{@page.pretty_title}" end - + def heads_for_wiki_formatter unless @heads_for_wiki_formatter_included content_for :header_tags do diff -r 487d96eac004 -r 5e80956cc792 lib/tabular_form_builder.rb --- a/lib/tabular_form_builder.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tabular_form_builder.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,33 +19,29 @@ class TabularFormBuilder < ActionView::Helpers::FormBuilder include Redmine::I18n - - def initialize(object_name, object, template, options, proc) - set_language_if_valid options.delete(:lang) - super - end - - (field_helpers - %w(radio_button hidden_field fields_for) + %w(date_select)).each do |selector| + + (field_helpers.map(&:to_s) - %w(radio_button hidden_field fields_for) + + %w(date_select)).each do |selector| src = <<-END_SRC - def #{selector}(field, options = {}) + def #{selector}(field, options = {}) label_for_field(field, options) + super end END_SRC class_eval src, __FILE__, __LINE__ end - - def select(field, choices, options = {}, html_options = {}) + + def select(field, choices, options = {}, html_options = {}) label_for_field(field, options) + super end - + # Returns a label tag for the given field def label_for_field(field, options = {}) - return '' if options.delete(:no_label) + return ''.html_safe if options.delete(:no_label) text = options[:label].is_a?(Symbol) ? l(options[:label]) : options[:label] text ||= l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) text += @template.content_tag("span", " *", :class => "required") if options.delete(:required) - @template.content_tag("label", text, - :class => (@object && @object.errors[field] ? "error" : nil), + @template.content_tag("label", text.html_safe, + :class => (@object && @object.errors[field] ? "error" : nil), :for => (@object_name.to_s + "_" + field.to_s)) end end diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/email.rake --- a/lib/tasks/email.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/email.rake Mon Feb 27 13:53:18 2012 +0000 @@ -100,14 +100,14 @@ Examples: # No project specified. Emails MUST contain the 'Project' keyword: - rake redmine:email:receive_iamp RAILS_ENV="production" \\ + rake redmine:email:receive_imap RAILS_ENV="production" \\ host=imap.foo.bar username=redmine@example.net password=xxx # Fixed project and default tracker specified, but emails can override # both tracker and priority attributes: - rake redmine:email:receive_iamp RAILS_ENV="production" \\ + rake redmine:email:receive_imap RAILS_ENV="production" \\ host=imap.foo.bar username=redmine@example.net password=xxx ssl=1 \\ project=foo \\ tracker=bug \\ @@ -167,7 +167,7 @@ end desc "Send a test email to the user with the provided login name" - task :test, :login, :needs => :environment do |task, args| + task :test, [:login] => :environment do |task, args| include Redmine::I18n abort l(:notice_email_error, "Please include the user login to test with. Example: rake redmine:email:test[login]") if args[:login].blank? diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/extract_fixtures.rake --- a/lib/tasks/extract_fixtures.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/extract_fixtures.rake Mon Feb 27 13:53:18 2012 +0000 @@ -1,22 +1,22 @@ -desc 'Create YAML test fixtures from data in an existing database. -Defaults to development database. Set RAILS_ENV to override.' - -task :extract_fixtures => :environment do - sql = "SELECT * FROM %s" - skip_tables = ["schema_info"] - ActiveRecord::Base.establish_connection - (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| - i = "000" - File.open("#{RAILS_ROOT}/#{table_name}.yml", 'w' ) do |file| - data = ActiveRecord::Base.connection.select_all(sql % table_name) - file.write data.inject({}) { |hash, record| - # cast extracted values - ActiveRecord::Base.connection.columns(table_name).each { |col| - record[col.name] = col.type_cast(record[col.name]) if record[col.name] - } - hash["#{table_name}_#{i.succ!}"] = record - hash - }.to_yaml - end - end -end +desc 'Create YAML test fixtures from data in an existing database. +Defaults to development database. Set RAILS_ENV to override.' + +task :extract_fixtures => :environment do + sql = "SELECT * FROM %s" + skip_tables = ["schema_info"] + ActiveRecord::Base.establish_connection + (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name| + i = "000" + File.open("#{Rails.root}/#{table_name}.yml", 'w' ) do |file| + data = ActiveRecord::Base.connection.select_all(sql % table_name) + file.write data.inject({}) { |hash, record| + # cast extracted values + ActiveRecord::Base.connection.columns(table_name).each { |col| + record[col.name] = col.type_cast(record[col.name]) if record[col.name] + } + hash["#{table_name}_#{i.succ!}"] = record + hash + }.to_yaml + end + end +end diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/fetch_changesets.rake --- a/lib/tasks/fetch_changesets.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/fetch_changesets.rake Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/initializers.rake --- a/lib/tasks/initializers.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/initializers.rake Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,7 @@ desc 'Generates a configuration file for cookie store sessions.' file 'config/initializers/session_store.rb' do - path = File.join(RAILS_ROOT, 'config', 'initializers', 'session_store.rb') + path = File.join(Rails.root, 'config', 'initializers', 'session_store.rb') secret = ActiveSupport::SecureRandom.hex(40) File.open(path, 'w') do |f| f.write <<"EOF" @@ -10,7 +10,7 @@ # If you have a load-balancing Redmine cluster, you will need to use the # same version of this file on each machine. And be sure to restart your # server when you modify this file. - + # Your secret key for verifying cookie session data integrity. If you # change this key, all old sessions will become invalid! Make sure the # secret is at least 30 characters and all random, no regular words or diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/load_default_data.rake --- a/lib/tasks/load_default_data.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/load_default_data.rake Mon Feb 27 13:53:18 2012 +0000 @@ -4,7 +4,7 @@ task :load_default_data => :environment do include Redmine::I18n set_language_if_valid('en') - + envlang = ENV['REDMINE_LANG'] if !envlang || !set_language_if_valid(envlang) puts @@ -21,7 +21,7 @@ STDOUT.flush puts "====================================" end - + begin Redmine::DefaultData::Loader.load(current_language) puts "Default configuration data loaded." diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/locales.rake --- a/lib/tasks/locales.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/locales.rake Mon Feb 27 13:53:18 2012 +0000 @@ -59,6 +59,9 @@ desc <<-END_DESC Removes a translation string from all locale file (only works for top-level childless non-multiline keys, probably doesn\'t work on windows). +This task does not work on Ruby 1.8.6. +You need to use Ruby 1.8.7 or later. + Options: key=key_1,key_2 Comma-separated list of keys to delete skip=en,de Comma-separated list of locale files to ignore (filename without extension) @@ -113,4 +116,31 @@ end end end + + desc 'Check parsing yaml by psych library on Ruby 1.9.' + + # On Fedora 12 and 13, if libyaml-devel is available, + # in case of installing by rvm, + # Ruby 1.9 default yaml library is psych. + + task :check_parsing_by_psych do + begin + require 'psych' + parser = Psych::Parser.new + dir = ENV['DIR'] || './config/locales' + files = Dir.glob(File.join(dir,'*.yml')) + files.each do |filename| + next if File.directory? filename + puts "parsing #{filename}..." + begin + parser.parse File.open(filename) + rescue Exception => e1 + puts(e1.message) + puts("") + end + end + rescue Exception => e + puts(e.message) + end + end end diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/migrate_from_trac.rake --- a/lib/tasks/migrate_from_trac.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/migrate_from_trac.rake Mon Feb 27 13:53:18 2012 +0000 @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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 @@ -758,10 +758,10 @@ prompt('Trac database encoding', :default => 'UTF-8') {|encoding| TracMigrate.encoding encoding} prompt('Target project identifier') {|identifier| TracMigrate.target_project_identifier identifier} puts - + # Turn off email notifications Setting.notified_events = [] - + TracMigrate.migrate end end diff -r 487d96eac004 -r 5e80956cc792 lib/tasks/testing.rake --- a/lib/tasks/testing.rake Fri Feb 24 20:18:25 2012 +0000 +++ b/lib/tasks/testing.rake Mon Feb 27 13:53:18 2012 +0000 @@ -5,7 +5,7 @@ task :coverage do rm_f "coverage" rm_f "coverage.data" - rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib --html" + rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib --html --exclude gems/" files = Dir.glob("test/**/*_test.rb").join(" ") system("#{rcov} #{files}") system("open coverage/index.html") if PLATFORM['darwin'] @@ -30,16 +30,16 @@ task :create_dir do FileUtils.mkdir_p Rails.root + '/tmp/test' end - + supported_scms = [:subversion, :cvs, :bazaar, :mercurial, :git, :darcs, :filesystem] - + desc "Creates a test subversion repository" task :subversion => :create_dir do repo_path = "tmp/test/subversion_repository" system "svnadmin create #{repo_path}" system "gunzip < test/fixtures/repositories/subversion_repository.dump.gz | svnadmin load #{repo_path}" end - + desc "Creates a test mercurial repository" task :mercurial => :create_dir do repo_path = "tmp/test/mercurial_repository" @@ -47,19 +47,19 @@ system "hg init #{repo_path}" system "hg -R #{repo_path} pull #{bundle_path}" end - + (supported_scms - [:subversion, :mercurial]).each do |scm| desc "Creates a test #{scm} repository" task scm => :create_dir do - # system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test" - system "tar -xvz -C tmp/test -f test/fixtures/repositories/#{scm}_repository.tar.gz" + # system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test" + system "tar -xvz -C tmp/test -f test/fixtures/repositories/#{scm}_repository.tar.gz" end end - + desc "Creates all test repositories" task :all => supported_scms end - + desc "Updates installed test repositories" task :update do require 'fileutils' @@ -68,19 +68,19 @@ scm = $1 next unless fixture = Dir.glob("test/fixtures/repositories/#{scm}_repository.*").first next if File.stat(dir).ctime > File.stat(fixture).mtime - + FileUtils.rm_rf dir Rake::Task["test:scm:setup:#{scm}"].execute end end - + Rake::TestTask.new(:units => "db:test:prepare") do |t| t.libs << "test" t.verbose = true t.test_files = FileList['test/unit/repository*_test.rb'] + FileList['test/unit/lib/redmine/scm/**/*_test.rb'] end Rake::Task['test:scm:units'].comment = "Run the scm unit tests" - + Rake::TestTask.new(:functionals => "db:test:prepare") do |t| t.libs << "test" t.verbose = true diff -r 487d96eac004 -r 5e80956cc792 public/help/wiki_syntax_detailed.html --- a/public/help/wiki_syntax_detailed.html Fri Feb 24 20:18:25 2012 +0000 +++ b/public/help/wiki_syntax_detailed.html Mon Feb 27 13:53:18 2012 +0000 @@ -1,342 +1,343 @@ - - - -RedmineWikiFormatting - - - - - -

    Wiki formatting

    - -

    Links

    - -

    Redmine links

    - -

    Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.

    -
      -
    • Link to an issue: #124 (displays #124, link is striked-through if the issue is closed)
    • -
    • Link to a changeset: r758 (displays r758)
    • -
    • Link to a changeset with a non-numeric hash: commit:c6f4d0fd (displays c6f4d0fd).
    • -
    • Link to a changeset of another project: sandbox:r758 (displays sandbox:r758)
    • -
    • Link to a changeset with a non-numeric hash: sandbox:c6f4d0fd (displays sandbox:c6f4d0fd).
    • -
    - -

    Wiki links:

    - -
      -
    • [[Guide]] displays a link to the page named 'Guide': Guide
    • -
    • [[Guide#further-reading]] takes you to the anchor "further-reading". Headings get automatically assigned anchors so that you can refer to them: Guide
    • -
    • [[Guide|User manual]] displays a link to the same page but with a different text: User manual
    • -
    - -

    You can also link to pages of an other project wiki:

    - -
      -
    • [[sandbox:some page]] displays a link to the page named 'Some page' of the Sandbox wiki
    • -
    • [[sandbox:]] displays a link to the Sandbox wiki main page
    • -
    - -

    Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

    - -

    Links to other resources:

    - -
      -
    • Documents: -
        -
      • document#17 (link to document with id 17)
      • -
      • document:Greetings (link to the document with title "Greetings")
      • -
      • document:"Some document" (double quotes can be used when document title contains spaces)
      • -
      • sandbox:document:"Some document" (link to a document with title "Some document" in other project "sandbox")
      • -
    • -
    - -
      -
    • Versions: -
        -
      • version#3 (link to version with id 3)
      • -
      • version:1.0.0 (link to version named "1.0.0")
      • -
      • version:"1.0 beta 2"
      • -
      • sandbox:version:1.0.0 (link to version "1.0.0" in the project "sandbox")
      • -
    • -
    - -
      -
    • Attachments: -
        -
      • attachment:file.zip (link to the attachment of the current object named file.zip)
      • -
      • For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)
      • -
    • -
    - -
      -
    • Repository files: -
        -
      • source:some/file (link to the file located at /some/file in the project's repository)
      • -
      • source:some/file@52 (link to the file's revision 52)
      • -
      • source:some/file#L120 (link to line 120 of the file)
      • -
      • source:some/file@52#L120 (link to line 120 of the file's revision 52)
      • -
      • source:"some file@52#L120" (use double quotes when the URL contains spaces
      • -
      • export:some/file (force the download of the file)
      • -
      • sandbox:source:some/file (link to the file located at /some/file in the repository of the project "sandbox")
      • -
      • sandbox:export:some/file (force the download of the file)
      • -
    • -
    - -
      -
    • Forum messages: -
        -
      • message#1218 (link to message with id 1218)
      • -
    • -
    - -
      -
    • Projects: -
        -
      • project#3 (link to project with id 3)
      • -
      • project:someproject (link to project named "someproject")
      • -
    • -
    - - -

    Escaping:

    - -
      -
    • You can prevent Redmine links from being parsed by preceding them with an exclamation mark: !
    • -
    - - -

    External links

    - -

    HTTP URLs and email addresses are automatically turned into clickable links:

    - -
    -http://www.redmine.org, someone@foo.bar
    -
    - -

    displays: http://www.redmine.org,

    - -

    If you want to display a specific text instead of the URL, you can use the standard textile syntax:

    - -
    -"Redmine web site":http://www.redmine.org
    -
    - -

    displays: Redmine web site

    - - -

    Text formatting

    - - -

    For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See http://www.textism.com/tools/textile/ for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

    - -

    Font style

    - -
    -* *bold*
    -* _italic_
    -* _*bold italic*_
    -* +underline+
    -* -strike-through-
    -
    - -

    Display:

    - -
      -
    • bold
    • -
    • italic
    • -
    • *bold italic*
    • -
    • underline
    • -
    • strike-through
    • -
    - -

    Inline images

    - -
      -
    • !image_url! displays an image located at image_url (textile syntax)
    • -
    • !>image_url! right floating image
    • -
    • If you have an image attached to your wiki page, it can be displayed inline using its filename: !attached_image.png!
    • -
    - -

    Headings

    - -
    -h1. Heading
    -h2. Subheading
    -h3. Subsubheading
    -
    - -

    Redmine assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.

    - - - - -

    Bullets and Numbering

    - -
    -* First Level Bullet
    -** Second Level Bullet
    -** Another Second Level Bullet
    -*** Third Level Bullet
    -** Back to 2nd Level Bullet
    -* Back to 1st Level Bullet
    -
    - -
      -
    • First Level Bullet
    • -
        -
      • Second Level Bullet
      • -
      • Another Second Level Bullet
      • -
          -
        • Third Level Bullet
        • -
        -
      • Back to 2nd Level Bullet
      • -
      - -
    • Back to 1st Level Bullet
    • -
    - -
    -# First Level Numbering
    -## Second Level Numbering
    -## Another Second Level Numbering
    -### Third Level Numbering
    -## Back to 2nd Level Numbering
    -# Back to 1st Level Numbering
    -
    - -
      -
    1. First Level Numbering
    2. -
        -
      1. Second Level Numbering
      2. -
      3. Another Second Level Numbering
      4. -
          -
        1. Third Level Numbering
        2. -
        -
      5. Back to 2nd Level Numbering
      6. -
      -
    3. Back to 1st Level Numbering
    4. -
    - -
    -# First Level Numbering
    -#* Bullet inside numbering environment
    -#* Another Bullet inside numbering environment
    -# Back to 1st Level Numbering
    -
    - -
      -
    1. First Level Numbering
    2. -
        -
      • Bullet inside numbering environment
      • -
      • Another Bullet inside numbering environment
      • -
      - -
    3. Back to 1st Level Numbering
    4. -
    - - - - - - - -

    Paragraphs

    - -
    -p>. right aligned
    -p=. centered
    -
    - -

    This is a centered paragraph.

    - - -

    Blockquotes

    - -

    Start the paragraph with bq.

    - -
    -bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    -To go live, all you need to add is a database and a web server.
    -
    - -

    Display:

    - -
    -

    Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    To go live, all you need to add is a database and a web server.

    -
    - - -

    Table of content

    - -
    -{{toc}} => left aligned toc
    -{{>toc}} => right aligned toc
    -
    - -

    Macros

    - -

    Redmine has the following builtin macros:

    - -

    hello_world

    Sample macro.

    include

    Include a wiki page. Example:

    - -
    {{include(Foo)}}
    macro_list

    Displays a list of all available macros, including description if available.

    - - -

    Code highlighting

    - -

    Code highlightment relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.

    - -

    You can highlight code in your wiki page using this syntax:

    - -
    -<pre><code class="ruby">
    -  Place you code here.
    -</code></pre>
    -
    - -

    Example:

    - -
     1 # The Greeter class
    - 2 class Greeter
    - 3   def initialize(name)
    - 4     @name = name.capitalize
    - 5   end
    - 6 
    - 7   def salute
    - 8     puts "Hello #{@name}!" 
    - 9   end
    -10 end
    -
    -
    - - + + + +RedmineWikiFormatting + + + + + +

    Wiki formatting

    + +

    Links

    + +

    Redmine links

    + +

    Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.

    +
      +
    • Link to an issue: #124 (displays #124, link is striked-through if the issue is closed)
    • +
    • Link to a changeset: r758 (displays r758)
    • +
    • Link to a changeset with a non-numeric hash: commit:c6f4d0fd (displays c6f4d0fd).
    • +
    • Link to a changeset of another project: sandbox:r758 (displays sandbox:r758)
    • +
    • Link to a changeset with a non-numeric hash: sandbox:c6f4d0fd (displays sandbox:c6f4d0fd).
    • +
    + +

    Wiki links:

    + +
      +
    • [[Guide]] displays a link to the page named 'Guide': Guide
    • +
    • [[Guide#further-reading]] takes you to the anchor "further-reading". Headings get automatically assigned anchors so that you can refer to them: Guide
    • +
    • [[Guide|User manual]] displays a link to the same page but with a different text: User manual
    • +
    + +

    You can also link to pages of an other project wiki:

    + +
      +
    • [[sandbox:some page]] displays a link to the page named 'Some page' of the Sandbox wiki
    • +
    • [[sandbox:]] displays a link to the Sandbox wiki main page
    • +
    + +

    Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

    + +

    Links to other resources:

    + +
      +
    • Documents: +
        +
      • document#17 (link to document with id 17)
      • +
      • document:Greetings (link to the document with title "Greetings")
      • +
      • document:"Some document" (double quotes can be used when document title contains spaces)
      • +
      • sandbox:document:"Some document" (link to a document with title "Some document" in other project "sandbox")
      • +
    • +
    + +
      +
    • Versions: +
        +
      • version#3 (link to version with id 3)
      • +
      • version:1.0.0 (link to version named "1.0.0")
      • +
      • version:"1.0 beta 2"
      • +
      • sandbox:version:1.0.0 (link to version "1.0.0" in the project "sandbox")
      • +
    • +
    + +
      +
    • Attachments: +
        +
      • attachment:file.zip (link to the attachment of the current object named file.zip)
      • +
      • For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)
      • +
    • +
    + +
      +
    • Repository files: +
        +
      • source:some/file (link to the file located at /some/file in the project's repository)
      • +
      • source:some/file@52 (link to the file's revision 52)
      • +
      • source:some/file#L120 (link to line 120 of the file)
      • +
      • source:some/file@52#L120 (link to line 120 of the file's revision 52)
      • +
      • source:"some file@52#L120" (use double quotes when the URL contains spaces
      • +
      • export:some/file (force the download of the file)
      • +
      • sandbox:source:some/file (link to the file located at /some/file in the repository of the project "sandbox")
      • +
      • sandbox:export:some/file (force the download of the file)
      • +
    • +
    + +
      +
    • Forum messages: +
        +
      • message#1218 (link to message with id 1218)
      • +
    • +
    + +
      +
    • Projects: +
        +
      • project#3 (link to project with id 3)
      • +
      • project:someproject (link to project named "someproject")
      • +
    • +
    + + +

    Escaping:

    + +
      +
    • You can prevent Redmine links from being parsed by preceding them with an exclamation mark: !
    • +
    + + +

    External links

    + +

    HTTP URLs and email addresses are automatically turned into clickable links:

    + +
    +http://www.redmine.org, someone@foo.bar
    +
    + +

    displays: http://www.redmine.org,

    + +

    If you want to display a specific text instead of the URL, you can use the standard textile syntax:

    + +
    +"Redmine web site":http://www.redmine.org
    +
    + +

    displays: Redmine web site

    + + +

    Text formatting

    + + +

    For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See http://www.textism.com/tools/textile/ for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

    + +

    Font style

    + +
    +* *bold*
    +* _italic_
    +* _*bold italic*_
    +* +underline+
    +* -strike-through-
    +
    + +

    Display:

    + +
      +
    • bold
    • +
    • italic
    • +
    • *bold italic*
    • +
    • underline
    • +
    • strike-through
    • +
    + +

    Inline images

    + +
      +
    • !image_url! displays an image located at image_url (textile syntax)
    • +
    • !>image_url! right floating image
    • +
    • If you have an image attached to your wiki page, it can be displayed inline using its filename: !attached_image.png!
    • +
    + +

    Headings

    + +
    +h1. Heading
    +h2. Subheading
    +h3. Subsubheading
    +
    + +

    Redmine assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.

    + + + + +

    Bullets and Numbering

    + +
    +* First Level Bullet
    +** Second Level Bullet
    +** Another Second Level Bullet
    +*** Third Level Bullet
    +** Back to 2nd Level Bullet
    +* Back to 1st Level Bullet
    +
    + +
      +
    • First Level Bullet
    • +
        +
      • Second Level Bullet
      • +
      • Another Second Level Bullet
      • +
          +
        • Third Level Bullet
        • +
        +
      • Back to 2nd Level Bullet
      • +
      + +
    • Back to 1st Level Bullet
    • +
    + +
    +# First Level Numbering
    +## Second Level Numbering
    +## Another Second Level Numbering
    +### Third Level Numbering
    +## Back to 2nd Level Numbering
    +# Back to 1st Level Numbering
    +
    + +
      +
    1. First Level Numbering
    2. +
        +
      1. Second Level Numbering
      2. +
      3. Another Second Level Numbering
      4. +
          +
        1. Third Level Numbering
        2. +
        +
      5. Back to 2nd Level Numbering
      6. +
      +
    3. Back to 1st Level Numbering
    4. +
    + +
    +# First Level Numbering
    +#* Bullet inside numbering environment
    +#* Another Bullet inside numbering environment
    +# Back to 1st Level Numbering
    +
    + +
      +
    1. First Level Numbering
    2. +
        +
      • Bullet inside numbering environment
      • +
      • Another Bullet inside numbering environment
      • +
      + +
    3. Back to 1st Level Numbering
    4. +
    + + + + + + + +

    Paragraphs

    + +
    +p>. right aligned
    +p=. centered
    +
    + +

    This is a centered paragraph.

    + + +

    Blockquotes

    + +

    Start the paragraph with bq.

    + +
    +bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    +To go live, all you need to add is a database and a web server.
    +
    + +

    Display:

    + +
    +

    Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    To go live, all you need to add is a database and a web server.

    +
    + + +

    Table of content

    + +
    +{{toc}} => left aligned toc
    +{{>toc}} => right aligned toc
    +
    + +

    Macros

    + +

    Redmine has the following builtin macros:

    + +

    hello_world

    Sample macro.

    include

    Include a wiki page. Example:

    + +
    {{include(Foo)}}
    macro_list

    Displays a list of all available macros, including description if available.

    + + +

    Code highlighting

    + +

    Default code highlightment relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.

    + +

    You can highlight code in your wiki page using this syntax:

    + +
    +<pre><code class="ruby">
    +  Place you code here.
    +</code></pre>
    +
    + +

    Example:

    + +
     1 # The Greeter class
    + 2 class Greeter
    + 3   def initialize(name)
    + 4     @name = name.capitalize
    + 5   end
    + 6 
    + 7   def salute
    + 8     puts "Hello #{@name}!" 
    + 9   end
    +10 end
    +
    + + diff -r 487d96eac004 -r 5e80956cc792 public/images/edit.png Binary file public/images/edit.png has changed diff -r 487d96eac004 -r 5e80956cc792 public/images/textfield_key.png Binary file public/images/textfield_key.png has changed diff -r 487d96eac004 -r 5e80956cc792 public/javascripts/application.js --- a/public/javascripts/application.js Fri Feb 24 20:18:25 2012 +0000 +++ b/public/javascripts/application.js Mon Feb 27 13:53:18 2012 +0000 @@ -86,26 +86,36 @@ var fileFieldCount = 1; function addFileField() { - if (fileFieldCount >= 10) return false - fileFieldCount++; - var f = document.createElement("input"); - f.type = "file"; - f.name = "attachments[" + fileFieldCount + "][file]"; - f.size = 30; - var d = document.createElement("input"); - d.type = "text"; - d.name = "attachments[" + fileFieldCount + "][description]"; - d.size = 60; - var dLabel = new Element('label'); - dLabel.addClassName('inline'); - // Pulls the languge value used for Optional Description - dLabel.update($('attachment_description_label_content').innerHTML) - p = document.getElementById("attachments_fields"); - p.appendChild(document.createElement("br")); - p.appendChild(f); - p.appendChild(dLabel); - dLabel.appendChild(d); + var fields = $('attachments_fields'); + if (fields.childElements().length >= 10) return false; + fileFieldCount++; + var s = new Element('span'); + s.update(fields.down('span').innerHTML); + s.down('input.file').name = "attachments[" + fileFieldCount + "][file]"; + s.down('input.description').name = "attachments[" + fileFieldCount + "][description]"; + fields.appendChild(s); +} +function removeFileField(el) { + var fields = $('attachments_fields'); + var s = Element.up(el, 'span'); + if (fields.childElements().length > 1) { + s.remove(); + } else { + s.update(s.innerHTML); + } +} + +function checkFileSize(el, maxSize, message) { + var files = el.files; + if (files) { + for (var i=0; i maxSize) { + alert(message); + el.value = ""; + } + } + } } function showTab(name) { @@ -188,6 +198,39 @@ } } +function showModal(id, width) { + el = $(id); + if (el == undefined || el.visible()) {return;} + var h = $$('body')[0].getHeight(); + var d = document.createElement("div"); + d.id = 'modalbg'; + $('main').appendChild(d); + $('modalbg').setStyle({ width: '100%', height: h + 'px' }); + $('modalbg').show(); + + var pageWidth = document.viewport.getWidth(); + el.setStyle({'width': width}); + el.setStyle({'left': (((pageWidth - el.getWidth())/2 *100) / pageWidth) + '%'}); + el.addClassName('modal'); + el.show(); + + var submit = el.down("input[type=submit]"); + if (submit) { + submit.focus(); + } +} + +function hideModal(el) { + var modal = Element.up(el, 'div.modal'); + if (modal) { + modal.hide(); + } + var bg = $('modalbg'); + if (bg) { + bg.remove(); + } +} + function collapseScmEntry(id) { var els = document.getElementsByClassName(id, 'browser'); for (var i = 0; i < els.length; i++) { @@ -250,6 +293,7 @@ { minChars: 3, frequency: 0.5, paramName: 'q', + method: 'get', updateElement: function(value) { document.getElementById('issue_parent_issue_id').value = value.id; }}); @@ -262,6 +306,7 @@ { minChars: 3, frequency: 0.5, paramName: 'q', + method: 'get', updateElement: function(value) { document.getElementById('relation_issue_to_id').value = value.id; }, diff -r 487d96eac004 -r 5e80956cc792 public/javascripts/calendar/lang/calendar-ar.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/public/javascripts/calendar/lang/calendar-ar.js Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,125 @@ +// Calendar AR language +// Author: SmartData.com.sa +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("الاحد", + "الاثنين", + "الثلاثاء", + "الاربعاء", + "الخميس", + "الجمعة", + "السبت", + "الاحد"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("أح", + "إث", + "ث", + "أر", + "خ", + "ج", + "س", + "أح"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("كانون الثاني", + "شباط", + "حزيران", + "آذار", + "أيار", + "نيسان", + "تموز", + "آب", + "أيلول", + "تشرين الاول", + "تشرين الثاني", + "كانون الاول"); + +// short month names +Calendar._SMN = new Array +("كانون الثاني", + "شباط", + "حزيران", + "آذار", + "أيار", + "نيسان", + "تموز", + "آب", + "أيلول", + "تشرين الاول", + "تشرين الثاني", + "كانون الاول"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "حول التقويم"; + +Calendar._TT["ABOUT"] = +"اختيار الوقت والتاريخ\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"اختيار التاريخ:\n" + +"- استخدم هذه الازرار \xab, \xbb لاختيار السنة\n" + +"- استخدم هذه الازرار " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " لاختيار الشهر\n" + +"- استمر في النقر فوق الازرار للتظليل السريع."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"اختيار الوقت:\n" + +"- انقر على اي جزء من اجزاء الوقت لزيادته\n" + +"- لانقاصهShiftاو انقر مع الضغط على مفتاح \n" + +"- او انقر واسحب للتظليل السريع."; + +Calendar._TT["PREV_YEAR"] = "السنة السابقة"; +Calendar._TT["PREV_MONTH"] = "الشهر السابق"; +Calendar._TT["GO_TODAY"] = "اذهب لليوم"; +Calendar._TT["NEXT_MONTH"] = "الشهر القادم"; +Calendar._TT["NEXT_YEAR"] = "السنة القادمة"; +Calendar._TT["SEL_DATE"] = "اختر التاريخ"; +Calendar._TT["DRAG_TO_MOVE"] = "اسحب للتتحرك"; +Calendar._TT["PART_TODAY"] = "اليوم"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = " اولا%sاعرض "; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "5,6"; + +Calendar._TT["CLOSE"] = "مغلق"; +Calendar._TT["TODAY"] = "اليوم"; +Calendar._TT["TIME_PART"] = "انقر او اسحب لتغير القيمة"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "رقم الاسبوع"; +Calendar._TT["TIME"] = "الوقت:"; diff -r 487d96eac004 -r 5e80956cc792 public/javascripts/calendar/lang/calendar-hr.js --- a/public/javascripts/calendar/lang/calendar-hr.js Fri Feb 24 20:18:25 2012 +0000 +++ b/public/javascripts/calendar/lang/calendar-hr.js Mon Feb 27 13:53:18 2012 +0000 @@ -18,7 +18,7 @@ "Cetvrtak", "Petak", "Subota", - "Nedjelja"); + "Nedjelja"); // Please note that the following array of short day names (and the same goes // for short month names, _SMN) isn't absolutely necessary. We give it here @@ -51,7 +51,7 @@ Calendar._MN = new Array ("Sijecanj", "Veljaca", - "Oujak", + "Ožujak", "Travanj", "Svibanj", "Lipanj", @@ -66,7 +66,7 @@ Calendar._SMN = new Array ("Sij", "Velj", - "Ou", + "Ožu", "Tra", "Svi", "Lip", @@ -100,7 +100,7 @@ Calendar._TT["PREV_YEAR"] = "Prethodna godina (hold for menu)"; Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (hold for menu)"; -Calendar._TT["GO_TODAY"] = "Na dananji dan"; +Calendar._TT["GO_TODAY"] = "Na današnji dan"; Calendar._TT["NEXT_MONTH"] = "Naredni mjesec (hold for menu)"; Calendar._TT["NEXT_YEAR"] = "Naredna godina (hold for menu)"; Calendar._TT["SEL_DATE"] = "Odaberite datum"; @@ -109,7 +109,7 @@ // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. -Calendar._TT["DAY_FIRST"] = "Prikai %s prvo"; +Calendar._TT["DAY_FIRST"] = "Prikaži %s prvo"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 diff -r 487d96eac004 -r 5e80956cc792 public/javascripts/context_menu.js --- a/public/javascripts/context_menu.js Fri Feb 24 20:18:25 2012 +0000 +++ b/public/javascripts/context_menu.js Mon Feb 27 13:53:18 2012 +0000 @@ -85,9 +85,6 @@ } } } - else{ - this.RightClick(e); - } }, createMenu: function() { diff -r 487d96eac004 -r 5e80956cc792 public/javascripts/jstoolbar/lang/jstoolbar-ar.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ar.js Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings ['Strong'] = 'قوي'; +jsToolBar.strings ['Italic'] = 'مائل'; +jsToolBar.strings ['Underline'] = 'تسطير'; +jsToolBar.strings ['Deleted'] = 'محذوف'; +jsToolBar.strings ['Code'] = 'رمز ضمني'; +jsToolBar.strings ['Heading 1'] = 'عنوان 1'; +jsToolBar.strings ['Heading 2'] = 'عنوان 2'; +jsToolBar.strings ['Heading 3'] = 'عنوان 3'; +jsToolBar.strings ['Unordered list'] = 'قائمة غير مرتبة'; +jsToolBar.strings ['Ordered list'] = 'قائمة مرتبة'; +jsToolBar.strings ['Quote'] = 'اقتباس'; +jsToolBar.strings ['Unquote'] = 'إزالة الاقتباس'; +jsToolBar.strings ['Preformatted text'] = 'نص مسبق التنسيق'; +jsToolBar.strings ['Wiki link'] = 'رابط الى صفحة ويكي'; +jsToolBar.strings ['Image'] = 'صورة'; diff -r 487d96eac004 -r 5e80956cc792 public/javascripts/raphael.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/public/javascripts/raphael.js Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,7 @@ +/* + * Raphael 1.5.2 - JavaScript Vector Library + * + * Copyright (c) 2010 Dmitry Baranovskiy (http://raphaeljs.com) + * Licensed under the MIT (http://raphaeljs.com/license.html) license. + */ +(function(){function cC(a,b,c,d,e,f){function o(a,b){var c,d,e,f,j,k;for(e=a,k=0;k<8;k++){f=m(e)-a;if(B(f)d)return d;while(cf?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cB(b){return function(c,d,e,f){var g={back:b};a.is(e,"function")?f=e:g.rot=e,c&&c.constructor==bN&&(c=c.attrs.path),c&&(g.along=c);return this.animate(g,d,f)}}function cp(){return this.x+q+this.y}function bm(a,b,c){function d(){var g=Array[e].slice.call(arguments,0),h=g[v]("►"),i=d.cache=d.cache||{},j=d.count=d.count||[];if(i[f](h))return c?c(i[h]):i[h];j[w]>=1e3&&delete i[j.shift()],j[L](h),i[h]=a[m](b,g);return c?c(i[h]):i[h]}return d}function bh(){var a=[],b=0;for(;b<32;b++)a[b]=(~~(y.random()*16))[H](16);a[12]=4,a[16]=(a[16]&3|8)[H](16);return"r-"+a[v]("")}function a(){if(a.is(arguments[0],G)){var b=arguments[0],d=bV[m](a,b.splice(0,3+a.is(b[0],E))),e=d.set();for(var g=0,h=b[w];g',bg=bf.firstChild,bg.style.behavior="url(#default#VML)";if(!bg||typeof bg.adj!="object")return a.type=null;bf=null}a.svg=!(a.vml=a.type=="VML"),j[e]=a[e],k=j[e],a._id=0,a._oid=0,a.fn={},a.is=function(a,b){b=x.call(b);if(b=="finite")return!O[f](+a);return b=="null"&&a===null||b==typeof a||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||J.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return((h<0)*180+y.atan(-i/-h)*180/D+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*D/180},a.deg=function(a){return a*180/D%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,G)){var e=b.length;while(e--)if(B(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c},a.setWindow=function(a){h=a,g=h.document};var bi=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),d=e.body}catch(f){d=createPopup().document.body}var h=d.createTextRange();bi=bm(function(a){try{d.style.color=r(a)[Y](c,p);var b=h.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b[H](16)).slice(-6)}catch(e){return"none"}})}else{var i=g.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",g.body[l](i),bi=bm(function(a){i.style.color=a;return g.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bi(b)},bj=function(){return"hsb("+[this.h,this.s,this.b]+")"},bk=function(){return"hsl("+[this.h,this.s,this.l]+")"},bl=function(){return this.hex};a.hsb2rgb=function(b,c,d,e){a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b&&(d=b.b,c=b.s,b=b.h,e=b.o);return a.hsl2rgb(b,c,d/2,e)},a.hsl2rgb=function(b,c,d,e){a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b&&(d=b.l,c=b.s,b=b.h);if(b>1||c>1||d>1)b/=360,c/=100,d/=100;var f={},g=["r","g","b"],h,i,j,k,l,m;if(!c)f={r:d,g:d,b:d};else{d<.5?h=d*(1+c):h=d+c-d*c,i=2*d-h;for(var n=0;n<3;n++)j=b+1/3*-(n-1),j<0&&j++,j>1&&j--,j*6<1?f[g[n]]=i+(h-i)*6*j:j*2<1?f[g[n]]=h:j*3<2?f[g[n]]=i+(h-i)*(2/3-j)*6:f[g[n]]=i}f.r*=255,f.g*=255,f.b*=255,f.hex="#"+(16777216|f.b|f.g<<8|f.r<<16).toString(16).slice(1),a.is(e,"finite")&&(f.opacity=e),f.toString=bl;return f},a.rgb2hsb=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;var f=z(b,c,d),g=A(b,c,d),h,i,j=f;if(g==f)return{h:0,s:0,b:f,toString:bj};var k=f-g;i=k/f,b==f?h=(c-d)/k:c==f?h=2+(d-b)/k:h=4+(b-c)/k,h/=6,h<0&&h++,h>1&&h--;return{h:h,s:i,b:j,toString:bj}},a.rgb2hsl=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,F)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;var f=z(b,c,d),g=A(b,c,d),h,i,j=(f+g)/2,k;if(g==f)k={h:0,s:0,l:j};else{var l=f-g;i=j<.5?l/(f+g):l/(2-f-g),b==f?h=(c-d)/l:c==f?h=2+(d-b)/l:h=4+(b-c)/l,h/=6,h<0&&h++,h>1&&h--,k={h:h,s:i,l:j}}k.toString=bk;return k},a._path2string=function(){return this.join(",")[Y](ba,"$1")},a.getRGB=bm(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none"};!_[f](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bi(b));var c,d,e,g,h,i,j,k=b.match(N);if(k){k[2]&&(g=T(k[2].substring(5),16),e=T(k[2].substring(3,5),16),d=T(k[2].substring(1,3),16)),k[3]&&(g=T((i=k[3].charAt(3))+i,16),e=T((i=k[3].charAt(2))+i,16),d=T((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s]($),d=S(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=S(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),g=S(j[2]),j[2].slice(-1)=="%"&&(g*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=S(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s]($),d=S(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=S(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),g=S(j[2]),j[2].slice(-1)=="%"&&(g*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=S(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,g,h)}if(k[6]){j=k[6][s]($),d=S(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=S(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),g=S(j[2]),j[2].slice(-1)=="%"&&(g*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=S(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,g,h)}k={r:d,g:e,b:g},k.hex="#"+(16777216|g|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1}},a),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=bm(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,G)&&a.is(b[0],G)&&(d=bo(b)),d[w]||r(b)[Y](bb,function(a,b,e){var f=[],g=x.call(b);e[Y](bc,function(a,b){b&&f[L](+b)}),g=="m"&&f[w]>2&&(d[L]([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");while(f[w]>=c[g]){d[L]([b][n](f.splice(0,c[g])));if(!c[g])break}}),d[H]=a._path2string;return d}),a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=C(j,3)*a+C(j,2)*3*i*c+j*3*i*i*e+C(i,3)*g,l=C(j,3)*b+C(j,2)*3*i*d+j*3*i*i*f+C(i,3)*h,m=a+2*i*(c-a)+i*i*(e-2*c+a),n=b+2*i*(d-b)+i*i*(f-2*d+b),o=c+2*i*(e-c)+i*i*(g-2*e+c),p=d+2*i*(f-d)+i*i*(h-2*f+d),q=(1-i)*a+i*c,r=(1-i)*b+i*d,s=(1-i)*e+i*g,t=(1-i)*f+i*h,u=90-y.atan((m-o)/(n-p))*180/D;(m>o||n1&&(x=y.sqrt(x),c=x*c,d=x*d);var z=c*c,A=d*d,C=(f==g?-1:1)*y.sqrt(B((z*A-z*u*u-A*t*t)/(z*u*u+A*t*t))),E=C*c*u/d+(a+h)/2,F=C*-d*t/c+(b+i)/2,G=y.asin(((b-F)/d).toFixed(9)),H=y.asin(((i-F)/d).toFixed(9));G=aH&&(G=G-D*2),!g&&H>G&&(H=H-D*2)}else G=j[0],H=j[1],E=j[2],F=j[3];var I=H-G;if(B(I)>k){var J=H,K=h,L=i;H=G+k*(g&&H>G?1:-1),h=E+c*y.cos(H),i=F+d*y.sin(H),m=bt(h,i,c,d,e,0,g,K,L,[H,J,E,F])}I=H-G;var M=y.cos(G),N=y.sin(G),O=y.cos(H),P=y.sin(H),Q=y.tan(I/4),R=4/3*c*Q,S=4/3*d*Q,T=[a,b],U=[a+R*N,b-S*M],V=[h+R*P,i-S*O],W=[h,i];U[0]=2*T[0]-U[0],U[1]=2*T[1]-U[1];if(j)return[U,V,W][n](m);m=[U,V,W][n](m)[v]()[s](",");var X=[];for(var Y=0,Z=m[w];Y"1e12"&&(l=.5),B(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bu(a,b,c,d,e,f,g,h,l),p[L](q.x),o[L](q.y)),n>0&&n<1&&(q=bu(a,b,c,d,e,f,g,h,n),p[L](q.x),o[L](q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+y.sqrt(j*j-4*i*k))/2/i,n=(-j-y.sqrt(j*j-4*i*k))/2/i,B(l)>"1e12"&&(l=.5),B(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bu(a,b,c,d,e,f,g,h,l),p[L](q.x),o[L](q.y)),n>0&&n<1&&(q=bu(a,b,c,d,e,f,g,h,n),p[L](q.x),o[L](q.y));return{min:{x:A[m](0,p),y:A[m](0,o)},max:{x:z[m](0,p),y:z[m](0,o)}}}),bw=bm(function(a,b){var c=bq(a),d=b&&bq(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bt[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bs(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bs(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](br(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](br(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](br(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](br(b.x,b.y,b.X,b.Y))}return a},h=function(a,b){if(a[b][w]>7){a[b].shift();var e=a[b];while(e[w])a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1),k=z(c[w],d&&d[w]||0)}},i=function(a,b,e,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),e.bx=0,e.by=0,e.x=a[g][1],e.y=a[g][2],k=z(c[w],d&&d[w]||0))};for(var j=0,k=z(c[w],d&&d[w]||0);j.5)*2-1;C(e-.5,2)+C(f-.5,2)>.25&&(f=y.sqrt(.25-C(e-.5,2))*g+.5)&&f!=.5&&(f=f.toFixed(5)-1e-5*g)}return p}),b=b[s](/\s*\-\s*/);if(d=="linear"){var i=b.shift();i=-S(i);if(isNaN(i))return null;var j=[0,0,y.cos(i*D/180),y.sin(i*D/180)],k=1/(z(B(j[2]),B(j[3]))||1);j[2]*=k,j[3]*=k,j[2]<0&&(j[0]=-j[2],j[2]=0),j[3]<0&&(j[1]=-j[3],j[3]=0)}var m=bx(b);if(!m)return null;var n=a.getAttribute(I);n=n.match(/^url\(#(.*)\)$/),n&&c.defs.removeChild(g.getElementById(n[1]));var o=bG(d+"Gradient");o.id=bh(),bG(o,d=="radial"?{fx:e,fy:f}:{x1:j[0],y1:j[1],x2:j[2],y2:j[3]}),c.defs[l](o);for(var q=0,t=m[w];q1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(o),h[R](n,G.hex),n=="stroke"&&G[f]("opacity")&&bG(h,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity});break;case"gradient":(({circle:1,ellipse:1})[f](c.type)||r(o).charAt()!="r")&&bI(h,o,c.paper);break;case"opacity":i.gradient&&!i[f]("stroke-opacity")&&bG(h,{"stroke-opacity":o>1?o/100:o});case"fill-opacity":if(i.gradient){var H=g.getElementById(h.getAttribute(I)[Y](/^url\(#|\)$/g,p));if(H){var J=H.getElementsByTagName("stop");J[J[w]-1][R]("stop-opacity",o)}break};default:n=="font-size"&&(o=T(o,10)+"px");var K=n[Y](/(\-.)/g,function(a){return V.call(a.substring(1))});h.style[K]=o,h[R](n,o)}}bM(c,d),m?c.rotate(m.join(q)):S(j)&&c.rotate(j,!0)},bL=1.2,bM=function(b,c){if(b.type=="text"&&!!(c[f]("text")||c[f]("font")||c[f]("font-size")||c[f]("x")||c[f]("y"))){var d=b.attrs,e=b.node,h=e.firstChild?T(g.defaultView.getComputedStyle(e.firstChild,p).getPropertyValue("font-size"),10):10;if(c[f]("text")){d.text=c.text;while(e.firstChild)e.removeChild(e.firstChild);var i=r(c.text)[s]("\n");for(var j=0,k=i[w];jb.height&&(b.height=f.y+f.height-b.y),f.x+f.width-b.x>b.width&&(b.width=f.x+f.width-b.x)}}a&&this.hide();return b},bN[e].attr=function(b,c){if(this.removed)return this;if(b==null){var d={};for(var e in this.attrs)this.attrs[f](e)&&(d[e]=this.attrs[e]);this._.rt.deg&&(d.rotation=this.rotate()),(this._.sx!=1||this._.sy!=1)&&(d.scale=this.scale()),d.gradient&&d.fill=="none"&&(d.fill=d.gradient)&&delete d.gradient;return d}if(c==null&&a.is(b,F)){if(b=="translation")return cA.call(this);if(b=="rotation")return this.rotate();if(b=="scale")return this.scale();if(b==I&&this.attrs.fill=="none"&&this.attrs.gradient)return this.attrs.gradient;return this.attrs[b]}if(c==null&&a.is(b,G)){var g={};for(var h=0,i=b.length;h")),m.W=h.w=m.paper.span.offsetWidth,m.H=h.h=m.paper.span.offsetHeight,m.X=h.x,m.Y=h.y+Q(m.H/2);switch(h["text-anchor"]){case"start":m.node.style["v-text-align"]="left",m.bbx=Q(m.W/2);break;case"end":m.node.style["v-text-align"]="right",m.bbx=-Q(m.W/2);break;default:m.node.style["v-text-align"]="center"}}},bI=function(a,b){a.attrs=a.attrs||{};var c=a.attrs,d,e="linear",f=".5 .5";a.attrs.gradient=b,b=r(b)[Y](bd,function(a,b,c){e="radial",b&&c&&(b=S(b),c=S(c),C(b-.5,2)+C(c-.5,2)>.25&&(c=y.sqrt(.25-C(b-.5,2))*((c>.5)*2-1)+.5),f=b+q+c);return p}),b=b[s](/\s*\-\s*/);if(e=="linear"){var g=b.shift();g=-S(g);if(isNaN(g))return null}var h=bx(b);if(!h)return null;a=a.shape||a.node,d=a.getElementsByTagName(I)[0]||cd(I),!d.parentNode&&a.appendChild(d);if(h[w]){d.on=!0,d.method="none",d.color=h[0].color,d.color2=h[h[w]-1].color;var i=[];for(var j=0,k=h[w];j')}}catch(ce){cd=function(a){return g.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}bV=function(){var b=by[m](0,arguments),c=b.container,d=b.height,e,f=b.width,h=b.x,i=b.y;if(!c)throw new Error("VML container not found.");var k=new j,n=k.canvas=g.createElement("div"),o=n.style;h=h||0,i=i||0,f=f||512,d=d||342,f==+f&&(f+="px"),d==+d&&(d+="px"),k.width=1e3,k.height=1e3,k.coordsize=b_*1e3+q+b_*1e3,k.coordorigin="0 0",k.span=g.createElement("span"),k.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",n[l](k.span),o.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(g.body[l](n),o.left=h+"px",o.top=i+"px",o.position="absolute"):c.firstChild?c.insertBefore(n,c.firstChild):c[l](n),bz.call(k,k,a.fn);return k},k.clear=function(){this.canvas.innerHTML=p,this.span=g.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas[l](this.span),this.bottom=this.top=null},k.remove=function(){this.canvas.parentNode.removeChild(this.canvas);for(var a in this)this[a]=bF(a);return!0}}var cf=navigator.userAgent.match(/Version\/(.*?)\s/);navigator.vendor=="Apple Computer, Inc."&&(cf&&cf[1]<4||navigator.platform.slice(0,2)=="iP")?k.safari=function(){var a=this.rect(-99,-99,this.width+99,this.height+99).attr({stroke:"none"});h.setTimeout(function(){a.remove()})}:k.safari=function(){};var cg=function(){this.returnValue=!1},ch=function(){return this.originalEvent.preventDefault()},ci=function(){this.cancelBubble=!0},cj=function(){return this.originalEvent.stopPropagation()},ck=function(){if(g.addEventListener)return function(a,b,c,d){var e=o&&u[b]?u[b]:b,g=function(e){if(o&&u[f](b))for(var g=0,h=e.targetTouches&&e.targetTouches.length;g1&&(a=Array[e].splice.call(arguments,0,arguments[w]));return new cD(a)},k.setSize=bU,k.top=k.bottom=null,k.raphael=a,bO.resetScale=function(){if(this.removed)return this;this._.sx=1,this._.sy=1,this.attrs.scale="1 1"},bO.scale=function(a,b,c,d){if(this.removed)return this;if(a==null&&b==null)return{x:this._.sx,y:this._.sy,toString:cp};b=b||a,!+b&&(b=a);var e,f,g,h,i=this.attrs;if(a!=0){var j=this.getBBox(),k=j.x+j.width/2,l=j.y+j.height/2,m=B(a/this._.sx),o=B(b/this._.sy);c=+c||c==0?c:k,d=+d||d==0?d:l;var r=this._.sx>0,s=this._.sy>0,t=~~(a/B(a)),u=~~(b/B(b)),x=m*t,y=o*u,z=this.node.style,A=c+B(k-c)*x*(k>c==r?1:-1),C=d+B(l-d)*y*(l>d==s?1:-1),D=a*t>b*u?o:m;switch(this.type){case"rect":case"image":var E=i.width*m,F=i.height*o;this.attr({height:F,r:i.r*D,width:E,x:A-E/2,y:C-F/2});break;case"circle":case"ellipse":this.attr({rx:i.rx*m,ry:i.ry*o,r:i.r*D,cx:A,cy:C});break;case"text":this.attr({x:A,y:C});break;case"path":var G=bp(i.path),H=!0,I=r?x:m,J=s?y:o;for(var K=0,L=G[w];Kr?p=n.data[r*l]:(p=a.findDotsAtSegment(b,c,d,e,f,g,h,i,r/l),n.data[r]=p),r&&(k+=C(C(o.x-p.x,2)+C(o.y-p.y,2),.5));if(j!=null&&k>=j)return p;o=p}if(j==null)return k},cs=function(b,c){return function(d,e,f){d=bw(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cr(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C",m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M",m.x,m.y+"C",m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]][v](),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cr(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[1],i[2],i[3],i[4],i[5],i[6],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},ct=cs(1),cu=cs(),cv=cs(0,1);bO.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return ct(this.attrs.path)}},bO.getPointAtLength=function(a){if(this.type=="path")return cu(this.attrs.path,a)},bO.getSubpath=function(a,b){if(this.type=="path"){if(B(this.getTotalLength()-b)<"1e-6")return cv(this.attrs.path,a).end;var c=cv(this.attrs.path,b,1);return a?cv(c,a).end:c}},a.easing_formulas={linear:function(a){return a},"<":function(a){return C(a,3)},">":function(a){return C(a-1,3)+1},"<>":function(a){a=a*2;if(a<1)return C(a,3)/2;a-=2;return(C(a,3)+2)/2},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==0||a==1)return a;var b=.3,c=b/4;return C(2,-10*a)*y.sin((a-c)*2*D/b)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};var cw=[],cx=function(){var b=+(new Date);for(var c=0;c 15) { + shortrefs = shortrefs.substr(0,13) + "..."; + } + var t = r.text(x+5,y+5,shortrefs).attr({font: "12px Fontin-Sans, Arial", fill: "#666", + title: longrefs, cursor: "pointer", rotation: "0"}); + + var textbox = t.getBBox(); + t.translate(textbox.width / 2, textbox.height / -3); + } + for (var j = 0, jj = commits[i].parents.length; j < jj; j++) { + var c = comms[commits[i].parents[j][0]]; + var p,arrow; + if (c) { + var cy, cx; + cy = 10 + ystep * (max_rdmid - c.rdmid), + cx = 3 + xstep * c.space; + + if (c.space == commits[i].space) { + p = r.path("M" + x + "," + y + "L" + cx + "," + cy); + } else { + p = r.path(["M", x, y, "C",x,y,x, y+(cy-y)/2,x+(cx-x)/2, y+(cy-y)/2, + "C", x+(cx-x)/2,y+(cy-y)/2, cx, cy-(cy-y)/2, cx, cy]); + } + } else { + p = r.path("M" + x + "," + y + "L" + x + "," + ch); + } + p.attr({stroke: colors[commits[i].space], "stroke-width": 1.5}); + } + (function (c, x, y) { + top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, + cursor: "pointer", href: commits[i].href}) + .hover(function () {}, function () {}) + ); + }(commits[i], x, y)); + } + top.toFront(); + var hw = holder.offsetWidth, + hh = holder.offsetHeight, + drag, + dragger = function (e) { + if (drag) { + e = e || window.event; + holder.scrollLeft = drag.sl - (e.clientX - drag.x); + holder.scrollTop = drag.st - (e.clientY - drag.y); + } + }; + holder.onmousedown = function (e) { + e = e || window.event; + drag = {x: e.clientX, y: e.clientY, st: holder.scrollTop, sl: holder.scrollLeft}; + document.onmousemove = dragger; + }; + document.onmouseup = function () { + drag = false; + document.onmousemove = null; + }; + holder.scrollLeft = cw; +}; + +Raphael.fn.popupit = function (x, y, set, dir, size) { + dir = dir == null ? 2 : dir; + size = size || 5; + x = Math.round(x); + y = Math.round(y); + var bb = set.getBBox(), + w = Math.round(bb.width / 2), + h = Math.round(bb.height / 2), + dx = [0, w + size * 2, 0, -w - size * 2], + dy = [-h * 2 - size * 3, -h - size, 0, -h - size], + p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), + 0, "a", size, size, 0, 0, 1, -size, -size, + "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, + -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, + "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), + 0, "a", size, size, 0, 0, 1, size, size, + "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, + mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, + "l", -mmax(w - size, 0), 0, "z"].join(","), + xy = [{x: x, y: y + size * 2 + h}, + {x: x - size * 2 - w, y: y}, + {x: x, y: y - size * 2 - h}, + {x: x + size * 2 + w, y: y}] + [dir]; + set.translate(xy.x - w - bb.x, xy.y - h - bb.y); + return this.set(this.path(p).attr({fill: "#234", stroke: "none"}) + .insertBefore(set.node ? set : set[0]), set); +}; + +Raphael.fn.popup = function (x, y, text, dir, size) { + dir = dir == null ? 2 : dir > 3 ? 3 : dir; + size = size || 5; + text = text || "$9.99"; + var res = this.set(), + d = 3; + res.push(this.path().attr({fill: "#000", stroke: "#000"})); + res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"})); + res.update = function (X, Y, withAnimation) { + X = X || x; + Y = Y || y; + var bb = this[1].getBBox(), + w = bb.width / 2, + h = bb.height / 2, + dx = [0, w + size * 2, 0, -w - size * 2], + dy = [-h * 2 - size * 3, -h - size, 0, -h - size], + p = ["M", X - dx[dir], Y - dy[dir], "l", -size, (dir == 2) * -size, + -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, + "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, + 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, + "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), + 0, "a", size, size, 0, 0, 1, size, size, + "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, + mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, + "l", -mmax(w - size, 0), 0, "z"].join(","), + xy = [{x: X, y: Y + size * 2 + h}, + {x: X - size * 2 - w, y: Y}, + {x: X, y: Y - size * 2 - h}, + {x: X + size * 2 + w, y: Y}] + [dir]; + xy.path = p; + if (withAnimation) { + this.animate(xy, 500, ">"); + } else { + this.attr(xy); + } + return this; + }; + return res.update(x, y); +}; diff -r 487d96eac004 -r 5e80956cc792 public/stylesheets/application.css --- a/public/stylesheets/application.css Fri Feb 24 20:18:25 2012 +0000 +++ b/public/stylesheets/application.css Mon Feb 27 13:53:18 2012 +0000 @@ -80,7 +80,7 @@ #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} -html>body #content { min-height: 600px; } +html>body #content { min-height: 600px; } * html body #content { height: 600px; } /* IE */ #main.nosidebar #sidebar{ display: none; } @@ -93,6 +93,13 @@ #login-form label {font-weight: bold;} #login-form input#username, #login-form input#password { width: 300px; } +#modalbg {position:absolute; top:0; left:0; width:100%; height:100%; background:#ccc; z-index:49; opacity:0.5;} +html>body #modalbg {position:fixed;} +div.modal { border-radius:5px; position:absolute; top:25%; background:#fff; border:2px solid #759FCF; z-index:50; padding:0px; padding:8px;} +div.modal h3.title {background:#759FCF; color:#fff; border:0; padding-left:8px; margin:-8px; margin-bottom: 1em; border-top-left-radius:2px;border-top-right-radius:2px;} +div.modal p.buttons {text-align:right; margin-bottom:0;} +html>body div.modal {position:fixed;} + input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } @@ -157,8 +164,12 @@ tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} -tr.changeset td.author { text-align: center; width: 15%; } -tr.changeset td.committed_on { text-align: center; width: 15%; } +tr.changeset { height: 20px } +tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } +tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } +tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.comments_nowrap { width: 45%; white-space:nowrap;} table.files tr.file td { text-align: center; } table.files tr.file td.filename { text-align: left; } @@ -281,7 +292,7 @@ li p {margin-top: 0;} div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} -p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } +p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } div.issue div.subject div div { padding-left: 16px; } @@ -302,6 +313,10 @@ fieldset#filters table { border-collapse: collapse; } fieldset#filters table td { padding: 0; vertical-align: middle; } fieldset#filters tr.filter { height: 2em; } +fieldset#filters td.field { width:200px; } +fieldset#filters td.operator { width:170px; } +fieldset#filters td.values { white-space:nowrap; } +fieldset#filters td.values img { vertical-align: bottom; } fieldset#filters td.add-filter { text-align: right; vertical-align: top; } .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } @@ -335,7 +350,7 @@ div#search-results-counts { display: block; padding-left: 0; margin-left: 0; } div#search-results-counts ul { margin-top: 0.5em; padding-left: 0; margin-left: 0; } div#search-results-counts li { display: inline; list-style-type: none; margin-right: 1em; } - + dt.issue { background-image: url(../images/ticket.png); } dt.issue-edit { background-image: url(../images/ticket_edit.png); } dt.issue-closed { background-image: url(../images/ticket_checked.png); } @@ -369,8 +384,9 @@ table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; } table#time-report .hours-dec { font-size: 0.9em; } -form .attributes { margin-bottom: 8px; } -form .attributes p { padding-top: 1px; padding-bottom: 2px; } +div.wiki-page .contextual a {opacity: 0.4} +div.wiki-page .contextual a:hover {opacity: 1} + form .attributes select { width: 60%; } input#issue_subject { width: 99%; } select#issue_done_ratio { width: 95px; } @@ -385,7 +401,7 @@ li.latest { margin-bottom: 0.5em; } #tracker_project_ids ul { margin: 0; padding-left: 1em; } -#tracker_project_ids li { list-style-type:none; } +#tracker_project_ids li { list-style-type:none; } ul.properties {padding:0; font-size: 0.9em; color: #777;} ul.properties li {list-style-type:none;} @@ -395,11 +411,11 @@ .total-hours span.hours-int { font-size: 120%; } .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} -#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select { width: 90%; } +#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; } #workflow_copy_form select { width: 200px; } -textarea#custom_field_possible_values {width: 99%} +textarea#custom_field_possible_values {width: 99%} .pagination {font-size: 90%} p.pagination {margin-top:8px;} @@ -407,8 +423,8 @@ /***** Tabular forms ******/ .tabular p, .tabular ul{ margin: 0; -padding: 5px 0 8px 0; -padding-left: 180px; /*width of left column containing the label elements*/ +padding: 3px 0 3px 0; +padding-left: 180px; /* width of left column containing the label elements */ height: 1%; clear:left; } @@ -422,9 +438,10 @@ font-weight: bold; float: left; text-align: right; -margin-left: -180px; /*width of left column*/ -width: 175px; /*width of labels. Should be smaller than left column to create some right -margin*/ +/* width of left column */ +margin-left: -180px; +/* width of labels. Should be smaller than left column to create some right margin */ +width: 175px; } .tabular .splitcontentleft .box p, .tabular .splitcontentright .box p, .splitcontentleft .tabular p, .splitcontentright .tabular p, .tabular .splitcontentleft .box ul, .tabular .splitcontentright .box ul, .splitcontentleft .tabular ul, .splitcontentright .tabular ul { @@ -458,6 +475,13 @@ width: auto; } +label.no-css { + font-weight: inherit; + float:none; + text-align:left; + margin-left:0px; + width:auto; +} input#time_entry_comments { width: 90%;} #preview fieldset {margin-top: 1em; background: url(../images/draft.png)} @@ -466,9 +490,8 @@ .tabular.settings label{ margin-left: -300px; width: 295px; } .tabular.settings textarea { width: 99%; } -.tabular.settings.enabled_scm table {width:100%} -.tabular.settings.enabled_scm td.scm_name{ font-weight: bold; } -.tabular.settings.enabled_scm p.scm_config{ padding-left: 8px; font-style:italic;} +.settings.enabled_scm table {width:100%} +.settings.enabled_scm td.scm_name{ font-weight: bold; } fieldset.settings label { display: block; } fieldset#notified_events .parent { padding-left: 20px; } @@ -477,6 +500,8 @@ .summary {font-style: italic;} #attachments_fields input[type=text] {margin-left: 8px; } +#attachments_fields span {display:block; white-space:nowrap;} +#attachments_fields img {vertical-align: middle;} div.attachments { margin-top: 12px; } div.attachments p { margin:4px 0 2px 0; } @@ -506,39 +531,39 @@ #errorExplanation, div.flash, .nodata, .warning { padding: 4px 4px 4px 30px; margin-bottom: 12px; - font-size: 1.1em; - border: 2px solid; + font-size: 1.1em; + border: 2px solid; } div.flash {margin-top: 8px;} div.flash.error, #errorExplanation { - background: url(../images/exclamation.png) 8px 50% no-repeat; - background-color: #ffe3e3; - border-color: #dd0000; - color: #880000; + background: url(../images/exclamation.png) 8px 50% no-repeat; + background-color: #ffe3e3; + border-color: #dd0000; + color: #880000; } div.flash.notice { background: url(../images/true.png) 8px 5px no-repeat; - background-color: #dfffdf; - border-color: #9fcf9f; - color: #005f00; + background-color: #dfffdf; + border-color: #9fcf9f; + color: #005f00; } div.flash.warning { background: url(../images/warning.png) 8px 5px no-repeat; - background-color: #FFEBC1; - border-color: #FDBF3B; - color: #A6750C; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; text-align: left; } .nodata, .warning { text-align: center; - background-color: #FFEBC1; - border-color: #FDBF3B; - color: #A6750C; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; } span.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} @@ -558,7 +583,6 @@ text-align:center; padding:0.6em; z-index:100; -filter:alpha(opacity=50); opacity: 0.5; } @@ -665,25 +689,25 @@ div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } button.tab-left, button.tab-right { - font-size: 0.9em; - cursor: pointer; - height:24px; - border: 1px solid #ccc; - border-bottom: 1px solid #bbbbbb; - position:absolute; - padding:4px; - width: 20px; - bottom: -1px; + font-size: 0.9em; + cursor: pointer; + height:24px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + position:absolute; + padding:4px; + width: 20px; + bottom: -1px; } button.tab-left { - right: 20px; - background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; + right: 20px; + background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; } button.tab-right { - right: 0; - background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; + right: 0; + background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; } /***** Auto-complete *****/ @@ -755,6 +779,8 @@ color: #b73535; } +div.wiki ul, div.wiki ol {margin-bottom:1em;} + div.wiki pre { margin: 1em 1em 1em 1.6em; padding: 2px 2px 2px 0; @@ -796,7 +822,7 @@ a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } -div.wiki img { vertical-align: middle; } +div.wiki img { vertical-align: middle; } /***** My page layout *****/ .block-receiver { @@ -860,7 +886,7 @@ .task.label.project, .task.label.version { font-weight: bold; } .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } -.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } +.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} @@ -925,6 +951,7 @@ .icon-issue { background-image: url(../images/ticket.png); } .icon-zoom-in { background-image: url(../images/zoom_in.png); } .icon-zoom-out { background-image: url(../images/zoom_out.png); } +.icon-passwd { background-image: url(../images/textfield_key.png); } .icon-file { background-image: url(../images/files/default.png); } .icon-file.text-plain { background-image: url(../images/files/text.png); } @@ -941,46 +968,46 @@ .icon-file.application-zip { background-image: url(../images/files/zip.png); } .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } -img.gravatar { - padding: 2px; - border: solid 1px #d5d5d5; - background: #fff; +img.gravatar { + padding: 2px; + border: solid 1px #d5d5d5; + background: #fff; } div.issue img.gravatar { - float: right; - margin: 0 0 0 1em; - padding: 5px; + float: right; + margin: 0 0 0 1em; + padding: 5px; } div.issue table img.gravatar { - height: 14px; - width: 14px; - padding: 2px; - float: left; - margin: 0 0.5em 0 0; + height: 14px; + width: 14px; + padding: 2px; + float: left; + margin: 0 0.5em 0 0; } h2 img.gravatar { - padding: 3px; - margin: -2px 4px -4px 0; - vertical-align: top; + padding: 3px; + margin: -2px 4px -4px 0; + vertical-align: top; } h4 img.gravatar { - padding: 3px; - margin: -6px 0 -4px 0; - vertical-align: top; + padding: 3px; + margin: -6px 0 -4px 0; + vertical-align: top; } td.username img.gravatar { - margin: 0 0.5em 0 0; - vertical-align: top; + margin: 0 0.5em 0 0; + vertical-align: top; } #activity dt img.gravatar, #members dt img.gravatar { - float: left; - margin: 0 1em 1em 0; + float: left; + margin: 0 1em 1em 0; } /* Used on 12px Gravatar img tags without the icon background */ @@ -991,11 +1018,11 @@ #activity dt, .journal { - clear: left; + clear: left; } .journal-link { - float: right; + float: right; } h2 img { vertical-align:middle; } @@ -1007,9 +1034,19 @@ #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } #main { background: #fff; } #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} - #wiki_add_attachment { display:none; } + #wiki_add_attachment { display:none; } .hide-when-print { display: none; } - .autoscroll {overflow-x: visible;} - table.list {margin-top:0.5em;} - table.list th, table.list td {border: 1px solid #aaa;} + .autoscroll {overflow-x: visible;} + table.list {margin-top:0.5em;} + table.list th, table.list td {border: 1px solid #aaa;} } + +/* Accessibility specific styles */ +.hidden-for-sighted { + position:absolute; + left:-10000px; + top:auto; + width:1px; + height:1px; + overflow:hidden; +} diff -r 487d96eac004 -r 5e80956cc792 public/stylesheets/context_menu.css --- a/public/stylesheets/context_menu.css Fri Feb 24 20:18:25 2012 +0000 +++ b/public/stylesheets/context_menu.css Mon Feb 27 13:53:18 2012 +0000 @@ -1,27 +1,27 @@ #context-menu { position: absolute; z-index: 40; font-size: 0.9em;} #context-menu ul, #context-menu li, #context-menu a { - display:block; - margin:0; - padding:0; - border:0; + display:block; + margin:0; + padding:0; + border:0; } #context-menu ul { - width:150px; - border-top:1px solid #ddd; - border-left:1px solid #ddd; - border-bottom:1px solid #777; - border-right:1px solid #777; - background:white; - list-style:none; + width:150px; + border-top:1px solid #ddd; + border-left:1px solid #ddd; + border-bottom:1px solid #777; + border-right:1px solid #777; + background:white; + list-style:none; } #context-menu li { - position:relative; - padding:1px; - z-index:39; - border:1px solid white; + position:relative; + padding:1px; + z-index:39; + border:1px solid white; } #context-menu li.folder ul { position:absolute; left:168px; /* IE6 */ top:-2px; max-height:300px; overflow:hidden; overflow-y: auto; } #context-menu li.folder>ul { left:148px; } @@ -31,20 +31,20 @@ #context-menu.reverse-x li.folder>ul { right:148px; } #context-menu a { - text-decoration:none !important; - background-repeat: no-repeat; - background-position: 1px 50%; - padding: 1px 0px 1px 20px; - width:100%; /* IE */ + text-decoration:none !important; + background-repeat: no-repeat; + background-position: 1px 50%; + padding: 1px 0px 1px 20px; + width:100%; /* IE */ } #context-menu li>a { width:auto; } /* others */ #context-menu a.disabled, #context-menu a.disabled:hover {color: #ccc;} #context-menu li a.submenu { background:url("../images/bullet_arrow_right.png") right no-repeat; } #context-menu li:hover { border:1px solid gray; background-color:#eee; } #context-menu a:hover {color:#2A5685;} -#context-menu li.folder:hover { z-index:40; } +#context-menu li.folder:hover { z-index:40; } #context-menu ul ul, #context-menu li:hover ul ul { display:none; } -#context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; } +#context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; } /* selected element */ .context-menu-selection { background-color:#507AAA !important; color:#f8f8f8 !important; } diff -r 487d96eac004 -r 5e80956cc792 public/stylesheets/jstoolbar.css --- a/public/stylesheets/jstoolbar.css Fri Feb 24 20:18:25 2012 +0000 +++ b/public/stylesheets/jstoolbar.css Mon Feb 27 13:53:18 2012 +0000 @@ -1,47 +1,48 @@ .jstEditor { - padding-left: 0px; + padding-left: 0px; } .jstEditor textarea, .jstEditor iframe { - margin: 0; + margin: 0; } .jstHandle { - height: 10px; - font-size: 0.1em; - cursor: s-resize; - /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/ + height: 10px; + font-size: 0.1em; + cursor: s-resize; + /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/ } .jstElements { - padding: 3px 3px; + padding: 3px 3px 3px 0; } .jstElements button { - margin-right : 6px; - width : 24px; - height: 24px; - padding: 4px; - border-style: solid; - border-width: 1px; - border-color: #ddd; - background-color : #f7f7f7; - background-position : 50% 50%; - background-repeat: no-repeat; + margin-right: 4px; + width : 24px; + height: 24px; + padding: 4px; + border-style: solid; + border-width: 1px; + border-color: #ddd; + background-color : #f7f7f7; + background-position : 50% 50%; + background-repeat: no-repeat; } .jstElements button:hover { - border-color : #000; + border-color: #bbb; + background-color: #e5e5e5; } .jstElements button span { - display : none; + display : none; } .jstElements span { - display : inline; + display : inline; } .jstSpacer { - width : 0px; - font-size: 1px; - margin-right: 4px; + width : 0px; + font-size: 1px; + margin-right: 6px; } .jstElements .help { float: right; margin-right: 0.5em; padding-top: 8px; font-size: 0.9em; } @@ -50,47 +51,47 @@ /* Buttons -------------------------------------------------------- */ .jstb_strong { - background-image: url(../images/jstoolbar/bt_strong.png); + background-image: url(../images/jstoolbar/bt_strong.png); } .jstb_em { - background-image: url(../images/jstoolbar/bt_em.png); + background-image: url(../images/jstoolbar/bt_em.png); } .jstb_ins { - background-image: url(../images/jstoolbar/bt_ins.png); + background-image: url(../images/jstoolbar/bt_ins.png); } .jstb_del { - background-image: url(../images/jstoolbar/bt_del.png); + background-image: url(../images/jstoolbar/bt_del.png); } .jstb_code { - background-image: url(../images/jstoolbar/bt_code.png); + background-image: url(../images/jstoolbar/bt_code.png); } .jstb_h1 { - background-image: url(../images/jstoolbar/bt_h1.png); + background-image: url(../images/jstoolbar/bt_h1.png); } .jstb_h2 { - background-image: url(../images/jstoolbar/bt_h2.png); + background-image: url(../images/jstoolbar/bt_h2.png); } .jstb_h3 { - background-image: url(../images/jstoolbar/bt_h3.png); + background-image: url(../images/jstoolbar/bt_h3.png); } .jstb_ul { - background-image: url(../images/jstoolbar/bt_ul.png); + background-image: url(../images/jstoolbar/bt_ul.png); } .jstb_ol { - background-image: url(../images/jstoolbar/bt_ol.png); + background-image: url(../images/jstoolbar/bt_ol.png); } .jstb_bq { - background-image: url(../images/jstoolbar/bt_bq.png); + background-image: url(../images/jstoolbar/bt_bq.png); } .jstb_unbq { - background-image: url(../images/jstoolbar/bt_bq_remove.png); + background-image: url(../images/jstoolbar/bt_bq_remove.png); } .jstb_pre { - background-image: url(../images/jstoolbar/bt_pre.png); + background-image: url(../images/jstoolbar/bt_pre.png); } .jstb_link { - background-image: url(../images/jstoolbar/bt_link.png); + background-image: url(../images/jstoolbar/bt_link.png); } .jstb_img { - background-image: url(../images/jstoolbar/bt_img.png); + background-image: url(../images/jstoolbar/bt_img.png); } diff -r 487d96eac004 -r 5e80956cc792 public/stylesheets/rtl.css --- a/public/stylesheets/rtl.css Fri Feb 24 20:18:25 2012 +0000 +++ b/public/stylesheets/rtl.css Mon Feb 27 13:53:18 2012 +0000 @@ -9,18 +9,18 @@ #top-menu li { float: right; } .tabular label.floating { - margin-right: 0; - margin-left: auto; - text-align: right; + margin-right: 0; + margin-left: auto; + text-align: right; } -.tabular label +.tabular label { - float: right; - margin-left: auto; + float: right; + margin-left: auto; } .tabular p { - clear: right; + clear: right; } .tabular label.block { text-align: right; } .icon @@ -31,9 +31,9 @@ } div#activity dt, #search-results dt { - background-position: 100% 50%; - padding-right: 20px; - padding-left: 0px; + background-position: 100% 50%; + padding-right: 20px; + padding-left: 0px; } #content .tabs ul li { float: right; } #content .tabs ul { padding-left: auto; padding-right: 1em; } diff -r 487d96eac004 -r 5e80956cc792 public/stylesheets/scm.css --- a/public/stylesheets/scm.css Fri Feb 24 20:18:25 2012 +0000 +++ b/public/stylesheets/scm.css Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,15 @@ + +table.revision-info td { + margin: 0px; + padding: 0px; +} div.changeset-changes ul { margin: 0; padding: 0; } div.changeset-changes ul > ul { margin-left: 18px; padding: 0; } -li.change { +li.change { list-style-type:none; - background-image: url(../images/bullet_black.png); + background-image: url(../images/bullet_black.png); background-position: 1px 1px; background-repeat: no-repeat; padding-top: 1px; @@ -29,26 +34,24 @@ table.filecontent { border: 1px solid #ccc; border-collapse: collapse; width:98%; background-color: #fafafa; } table.filecontent th { border: 1px solid #ccc; background-color: #eee; } -table.filecontent th.filename { background-color: #e4e4d4; text-align: left; padding: 0.2em;} +table.filecontent th.filename { background-color: #e4e4d4; text-align: left; padding: 0.2em;} table.filecontent tr.spacing th { text-align:center; } table.filecontent tr.spacing td { height: 0.4em; background: #EAF2F5;} table.filecontent th.line-num { border: 1px solid #d7d7d7; - font-size: 0.8em; - text-align: right; - width: 2%; - padding-right: 3px; - color: #999; + font-size: 0.8em; + text-align: right; + width: 2%; + padding-right: 3px; + color: #999; } table.filecontent th.line-num a { - text-decoration: none; - color: inherit; + text-decoration: none; + color: inherit; } table.filecontent td.line-code pre { margin: 0px; - white-space: pre-wrap; /* CSS2.1 compliant */ - white-space: -moz-pre-wrap; /* Mozilla-based browsers */ - white-space: -o-pre-wrap; /* Opera 7+ */ + white-space: pre-wrap; } /* 12 different colors for the annonate view */ @@ -71,7 +74,7 @@ padding-left: 1em; background: inherit; } - + table.annotate td.author { text-align: center; border-right: 1px solid #d7d7d7; @@ -91,105 +94,94 @@ /************* CodeRay styles *************/ .syntaxhl div {display: inline;} -.syntaxhl .no { padding: 2px 4px 2px 4px; background-color: #eee; margin:0 } +.syntaxhl .line-numbers { padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px; } .syntaxhl .code pre { overflow: auto } .syntaxhl .debug { color:white ! important; background:blue ! important; } -.syntaxhl .af { color:#00C } -.syntaxhl .an { color:#007 } -.syntaxhl .at { color:#f08 } -.syntaxhl .av { color:#700 } -.syntaxhl .aw { color:#C00 } -.syntaxhl .bi { color:#509; font-weight:bold } -.syntaxhl .c { color:#888; } +.syntaxhl .attribute-name { color:#b48 } +.syntaxhl .annotation { color:#007 } +.syntaxhl .attribute-value { color:#700 } +.syntaxhl .binary { color:#509 } -.syntaxhl .ch { color:#04D } -.syntaxhl .ch .k { color:#04D } -.syntaxhl .ch .dl { color:#039 } +.syntaxhl .comment { color:#777 } +.syntaxhl .comment .char { color:#444 } +.syntaxhl .comment .delimiter { color:#444 } -.syntaxhl .cl { color:#B06; font-weight:bold } -.syntaxhl .cm { color:#A08; font-weight:bold } -.syntaxhl .co { color:#036; font-weight:bold } -.syntaxhl .cr { color:#0A0 } -.syntaxhl .cv { color:#369 } -.syntaxhl .de { color:#B0B; } -.syntaxhl .df { color:#099; font-weight:bold } -.syntaxhl .di { color:#088; font-weight:bold } -.syntaxhl .dl { color:black } -.syntaxhl .do { color:#970 } -.syntaxhl .dt { color:#34b } -.syntaxhl .ds { color:#D42; font-weight:bold } -.syntaxhl .e { color:#666; font-weight:bold } -.syntaxhl .en { color:#800; font-weight:bold } -.syntaxhl .er { color:#F00; background-color:#FAA } -.syntaxhl .ex { color:#C00; font-weight:bold } -.syntaxhl .fl { color:#60E; font-weight:bold } -.syntaxhl .fu { color:#06B; font-weight:bold } -.syntaxhl .gv { color:#d70; font-weight:bold } -.syntaxhl .hx { color:#058; font-weight:bold } -.syntaxhl .i { color:#00D; font-weight:bold } -.syntaxhl .ic { color:#B44; font-weight:bold } +.syntaxhl .char { color:#D20 } +.syntaxhl .char .content { color:#D20 } +.syntaxhl .char .delimiter { color:#710 } -.syntaxhl .il { background: #ddd; color: black } -.syntaxhl .il .il { background: #ccc } -.syntaxhl .il .il .il { background: #bbb } -.syntaxhl .il .idl { background: #ddd; font-weight: bold; color: #666 } -.syntaxhl .idl { background-color: #bbb; font-weight: bold; color: #666; } +.syntaxhl .class { color:#B06; font-weight:bold } +.syntaxhl .complex { color:#A08 } +.syntaxhl .constant { color:#036; font-weight:bold } +.syntaxhl .color { color:#0A0 } +.syntaxhl .class-variable { color:#369 } +.syntaxhl .decorator { color:#B0B } +.syntaxhl .definition { color:#099; font-weight:bold } +.syntaxhl .directive { color:#088; font-weight:bold } +.syntaxhl .delimiter { color:black } +.syntaxhl .doc { color:#970 } +.syntaxhl .doctype { color:#34b } +.syntaxhl .doc-string { color:#D42; font-weight:bold } +.syntaxhl .escape { color:#666 } +.syntaxhl .entity { color:#800; font-weight:bold } +.syntaxhl .error { color:#F00; background-color:#FAA } +.syntaxhl .exception { color:#C00; font-weight:bold } +.syntaxhl .float { color:#60E } +.syntaxhl .function { color:#06B; font-weight:bold } +.syntaxhl .global-variable { color:#d70 } +.syntaxhl .hex { color:#02b } +.syntaxhl .integer { color:#00D } +.syntaxhl .include { color:#B44; font-weight:bold } +.syntaxhl .imaginary { color:#f00 } -.syntaxhl .im { color:#f00; } -.syntaxhl .in { color:#B2B; font-weight:bold } -.syntaxhl .iv { color:#33B } -.syntaxhl .la { color:#970; font-weight:bold } -.syntaxhl .lv { color:#963 } -.syntaxhl .oc { color:#40E; font-weight:bold } -.syntaxhl .of { color:#000; font-weight:bold } -.syntaxhl .op { } -.syntaxhl .pc { color:#038; font-weight:bold } -.syntaxhl .pd { color:#369; font-weight:bold } -.syntaxhl .pp { color:#579; } -.syntaxhl .ps { color:#00C; font-weight:bold } -.syntaxhl .pt { color:#074; font-weight:bold } -.syntaxhl .r, .kw { color:#080; font-weight:bold } +.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black } +.syntaxhl .inline-delimiter { font-weight: bold; color: #666 } -.syntaxhl .ke { color: #808; } -.syntaxhl .ke .dl { color: #606; } -.syntaxhl .ke .ch { color: #80f; } -.syntaxhl .vl { color: #088; } +.syntaxhl .instance-variable { color:#33B } +.syntaxhl .label { color:#970; font-weight:bold } +.syntaxhl .local-variable { color:#963 } +.syntaxhl .namespace { color:#707; font-weight:bold } +.syntaxhl .octal { color:#40E } +.syntaxhl .operator { } +.syntaxhl .predefined-constant { color:#069 } +.syntaxhl .predefined { color:#369; font-weight:bold } +.syntaxhl .predefined-type { color:#0a5; font-weight:bold } +.syntaxhl .preprocessor { color:#579 } +.syntaxhl .pseudo-class { color:#00C; font-weight:bold } +.syntaxhl .reserved { color:#080; font-weight:bold } -.syntaxhl .rx { background-color:#fff0ff } -.syntaxhl .rx .k { color:#808 } -.syntaxhl .rx .dl { color:#404 } -.syntaxhl .rx .mod { color:#C2C } -.syntaxhl .rx .fu { color:#404; font-weight: bold } +.syntaxhl .key .char { color: #60f } +.syntaxhl .key .delimiter { color: #404 } +.syntaxhl .key { color: #606 } +.syntaxhl .keyword { color:#080; font-weight:bold } -.syntaxhl .s { background-color:#fff0f0; color: #D20; } -.syntaxhl .s .s { background-color:#ffe0e0 } -.syntaxhl .s .s .s { background-color:#ffd0d0 } -.syntaxhl .s .k { } -.syntaxhl .s .ch { color: #b0b; } -.syntaxhl .s .dl { color: #710; } +.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); } +.syntaxhl .regexp .content { color:#808 } +.syntaxhl .regexp .delimiter { color:#404 } +.syntaxhl .regexp .modifier { color:#C2C } -.syntaxhl .sh { background-color:#f0fff0; color:#2B2 } -.syntaxhl .sh .k { } -.syntaxhl .sh .dl { color:#161 } +.syntaxhl .string { background-color:hsla(0,100%,50%,0.05); } +.syntaxhl .string .content { color: #D20 } +.syntaxhl .string .char { color: #b0b } +.syntaxhl .string .delimiter { color: #710 } +.syntaxhl .string .modifier { color: #E40 } -.syntaxhl .sy { color:#A60 } -.syntaxhl .sy .k { color:#A60 } -.syntaxhl .sy .dl { color:#630 } +.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); } +.syntaxhl .shell .content { color:#2B2 } +.syntaxhl .shell .delimiter { color:#161 } -.syntaxhl .ta { color:#070 } -.syntaxhl .tf { color:#070; font-weight:bold } -.syntaxhl .ts { color:#D70; font-weight:bold } -.syntaxhl .ty { color:#339; font-weight:bold } -.syntaxhl .v { color:#036 } -.syntaxhl .xt { color:#444 } +.syntaxhl .symbol { color:#A60 } +.syntaxhl .symbol .content { color:#A60 } +.syntaxhl .symbol .delimiter { color:#630 } -.syntaxhl .ins { background: #cfc; } -.syntaxhl .del { background: #fcc; } -.syntaxhl .chg { color: #aaf; background: #007; } +.syntaxhl .tag { color:#070 } +.syntaxhl .type { color:#339; font-weight:bold } +.syntaxhl .value { color: #088; } +.syntaxhl .variable { color:#037 } + +.syntaxhl .insert { background: hsla(120,100%,50%,0.12) } +.syntaxhl .delete { background: hsla(0,100%,50%,0.12) } +.syntaxhl .change { color: #bbf; background: #007; } .syntaxhl .head { color: #f8f; background: #505 } - -.syntaxhl .ins .ins { color: #080; font-weight:bold } -.syntaxhl .del .del { color: #800; font-weight:bold } -.syntaxhl .chg .chg { color: #66f; } -.syntaxhl .head .head { color: #f4f; } +.syntaxhl .head .filename { color: white; } diff -r 487d96eac004 -r 5e80956cc792 public/themes/ssamr/images/home.png Binary file public/themes/ssamr/images/home.png has changed diff -r 487d96eac004 -r 5e80956cc792 public/themes/ssamr/images/wrench.png Binary file public/themes/ssamr/images/wrench.png has changed diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/auth_source_exemplar.rb --- a/test/exemplars/auth_source_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/auth_source_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,4 @@ class AuthSource < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Auth0' - def self.next_name - @last_name ||= 'Auth0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/board_exemplar.rb --- a/test/exemplars/board_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/board_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,20 +1,8 @@ class Board < ActiveRecord::Base - generator_for :name, :method => :next_name - generator_for :description, :method => :next_description + generator_for :name, :start => 'A Forum' + generator_for :description, :start => 'Some description here' generator_for :project, :method => :generate_project - def self.next_name - @last_name ||= 'A Forum' - @last_name.succ! - @last_name - end - - def self.next_description - @last_description ||= 'Some description here' - @last_description.succ! - @last_description - end - def self.generate_project Project.generate! end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/change_exemplar.rb --- a/test/exemplars/change_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/change_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,14 +1,8 @@ class Change < ActiveRecord::Base generator_for :action => 'A' - generator_for :path, :method => :next_path + generator_for :path, :start => 'test/dir/aaa0001' generator_for :changeset, :method => :generate_changeset - def self.next_path - @last_path ||= 'test/dir/aaa0001' - @last_path.succ! - @last_path - end - def self.generate_changeset Changeset.generate! end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/changeset_exemplar.rb --- a/test/exemplars/changeset_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/changeset_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,14 +1,8 @@ class Changeset < ActiveRecord::Base - generator_for :revision, :method => :next_revision + generator_for :revision, :start => '1' generator_for :committed_on => Date.today generator_for :repository, :method => :generate_repository - def self.next_revision - @last_revision ||= '1' - @last_revision.succ! - @last_revision - end - def self.generate_repository Repository::Subversion.generate! end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/custom_field_exemplar.rb --- a/test/exemplars/custom_field_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/custom_field_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,5 @@ class CustomField < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'CustomField0' generator_for :field_format => 'string' - def self.next_name - @last_name ||= 'CustomField0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/document_category_exemplar.rb --- a/test/exemplars/document_category_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/document_category_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,5 @@ class DocumentCategory < Enumeration - generator_for :name, :method => :next_name + generator_for :name, :start => 'DocumentCategory0' generator_for :type => 'DocumentCategory' - def self.next_name - @last_name ||= 'DocumentCategory0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/document_exemplar.rb --- a/test/exemplars/document_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/document_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,4 @@ class Document < ActiveRecord::Base - generator_for :title, :method => :next_title + generator_for :title, :start => 'Document001' - def self.next_title - @last_title ||= 'Document001' - @last_title.succ! - @last_title - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/enabled_module_exemplar.rb --- a/test/exemplars/enabled_module_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/enabled_module_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,4 @@ class EnabledModule < ActiveRecord::Base - generator_for :name, :method => :next_name - - def self.next_name - @last_name ||= 'module_001' - @last_name.succ! - @last_name - end + generator_for :name, :start => 'module_001' end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/enumeration_exemplar.rb --- a/test/exemplars/enumeration_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/enumeration_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,5 @@ class Enumeration < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Enumeration0' generator_for :type => 'TimeEntryActivity' - def self.next_name - @last_name ||= 'Enumeration0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/group_exemplar.rb --- a/test/exemplars/group_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/group_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,4 @@ class Group < Principal - generator_for :lastname, :method => :next_lastname - - def self.next_lastname - @last_lastname ||= 'Group' - @last_lastname.succ! - @last_lastname - end + generator_for :lastname, :start => 'Group' end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/issue_category_exemplar.rb --- a/test/exemplars/issue_category_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/issue_category_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,4 @@ class IssueCategory < ActiveRecord::Base - generator_for :name, :method => :next_name - - def self.next_name - @last_name ||= 'Category 0001' - @last_name.succ! - @last_name - end + generator_for :name, :start => 'Category 0001' + end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/issue_exemplar.rb --- a/test/exemplars/issue_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/issue_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,13 +1,7 @@ class Issue < ActiveRecord::Base - generator_for :subject, :method => :next_subject + generator_for :subject, :start => 'Subject 0' generator_for :author, :method => :next_author generator_for :priority, :method => :fetch_priority - - def self.next_subject - @last_subject ||= 'Subject 0' - @last_subject.succ! - @last_subject - end def self.next_author User.generate_with_protected! @@ -16,5 +10,4 @@ def self.fetch_priority IssuePriority.first || IssuePriority.generate! end - end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/issue_priority_exemplar.rb --- a/test/exemplars/issue_priority_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/issue_priority_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,5 @@ class IssuePriority < Enumeration - generator_for :name, :method => :next_name + generator_for :name, :start => 'IssuePriority0' generator_for :type => 'IssuePriority' - def self.next_name - @last_name ||= 'IssuePriority0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/issue_status_exemplar.rb --- a/test/exemplars/issue_status_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/issue_status_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,4 @@ class IssueStatus < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Status 0' - def self.next_name - @last_name ||= 'Status 0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/message_exemplar.rb --- a/test/exemplars/message_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/message_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,20 +1,8 @@ class Message < ActiveRecord::Base - generator_for :subject, :method => :next_subject - generator_for :content, :method => :next_content + generator_for :subject, :start => 'A Message' + generator_for :content, :start => 'Some content here' generator_for :board, :method => :generate_board - def self.next_subject - @last_subject ||= 'A Message' - @last_subject.succ! - @last_subject - end - - def self.next_content - @last_content ||= 'Some content here' - @last_content.succ! - @last_content - end - def self.generate_board Board.generate! end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/news_exemplar.rb --- a/test/exemplars/news_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/news_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,5 @@ class News < ActiveRecord::Base - generator_for :title, :method => :next_title - generator_for :description, :method => :next_description + generator_for :title, :start => 'A New Item' + generator_for :description, :start => 'Some content here' - def self.next_title - @last_title ||= 'A New Item' - @last_title.succ! - @last_title - end - - def self.next_description - @last_description ||= 'Some content here' - @last_description.succ! - @last_description - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/project_exemplar.rb --- a/test/exemplars/project_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/project_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,21 +1,8 @@ class Project < ActiveRecord::Base - generator_for :name, :method => :next_name - generator_for :identifier, :method => :next_identifier_from_object_daddy + generator_for :name, :start => 'Project 0' + generator_for :identifier, :start => 'project-0000' generator_for :enabled_modules, :method => :all_modules generator_for :trackers, :method => :next_tracker - - def self.next_name - @last_name ||= 'Project 0' - @last_name.succ! - @last_name - end - - # Project#next_identifier is defined on Redmine - def self.next_identifier_from_object_daddy - @last_identifier ||= 'project-0000' - @last_identifier.succ! - @last_identifier - end def self.all_modules [].tap do |modules| diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/query_exemplar.rb --- a/test/exemplars/query_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/query_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,4 @@ class Query < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Query 0' - def self.next_name - @last_name ||= 'Query 0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/repository_exemplar.rb --- a/test/exemplars/repository_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/repository_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,11 +1,5 @@ class Repository < ActiveRecord::Base generator_for :type => 'Subversion' - generator_for :url, :method => :next_url - - def self.next_url - @last_url ||= 'file:///test/svn' - @last_url.succ! - @last_url - end + generator_for :url, :start => 'file:///test/svn' end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/role_exemplar.rb --- a/test/exemplars/role_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/role_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,8 +1,4 @@ class Role < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Role0' - def self.next_name - @last_name ||= 'Role0' - @last_name.succ! - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/subversion_repository_exemplar.rb --- a/test/exemplars/subversion_repository_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/subversion_repository_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,11 +1,5 @@ class Repository::Subversion < Repository generator_for :type, :method => 'Subversion' - generator_for :url, :method => :next_url - - def self.next_url - @last_url ||= 'file:///test/svn' - @last_url.succ! - @last_url - end + generator_for :url, :start => 'file:///test/svn' end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/time_entry_activity.rb --- a/test/exemplars/time_entry_activity.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/time_entry_activity.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,10 +1,5 @@ class TimeEntryActivity < Enumeration - generator_for :name, :method => :next_name + generator_for :name, :start => 'TimeEntryActivity0' generator_for :type => 'TimeEntryActivity' - def self.next_name - @last_name ||= 'TimeEntryActivity0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/time_entry_exemplar.rb --- a/test/exemplars/time_entry_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/time_entry_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -6,5 +6,4 @@ def self.generate_user User.generate_with_protected! end - end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/tracker_exemplar.rb --- a/test/exemplars/tracker_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/tracker_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,4 @@ class Tracker < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Tracker 0' - def self.next_name - @last_name ||= 'Tracker 0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/user_exemplar.rb --- a/test/exemplars/user_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/user_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,30 +1,12 @@ class User < Principal - generator_for :login, :method => :next_login + generator_for :login, :start => 'user1' generator_for :mail, :method => :next_email - generator_for :firstname, :method => :next_firstname - generator_for :lastname, :method => :next_lastname - - def self.next_login - @gen_login ||= 'user1' - @gen_login.succ! - @gen_login - end - + generator_for :firstname, :start => 'Bob' + generator_for :lastname, :start => 'Doe' + def self.next_email @last_email ||= 'user1' @last_email.succ! "#{@last_email}@example.com" end - - def self.next_firstname - @last_firstname ||= 'Bob' - @last_firstname.succ! - @last_firstname - end - - def self.next_lastname - @last_lastname ||= 'Doe' - @last_lastname.succ! - @last_lastname - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/version_exemplar.rb --- a/test/exemplars/version_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/version_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,11 +1,5 @@ class Version < ActiveRecord::Base - generator_for :name, :method => :next_name + generator_for :name, :start => 'Version 1.0.0' generator_for :status => 'open' - - def self.next_name - @last_name ||= 'Version 1.0.0' - @last_name.succ! - @last_name - end end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/wiki_page_exemplar.rb --- a/test/exemplars/wiki_page_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/wiki_page_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,13 +1,7 @@ class WikiPage < ActiveRecord::Base - generator_for :title, :method => :next_title + generator_for :title, :start => 'AWikiPage' generator_for :wiki, :method => :generate_wiki - def self.next_title - @last_title ||= 'AWikiPage' - @last_title.succ! - @last_title - end - def self.generate_wiki Wiki.generate! end diff -r 487d96eac004 -r 5e80956cc792 test/exemplars/wiki_redirect_exemplar.rb --- a/test/exemplars/wiki_redirect_exemplar.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/exemplars/wiki_redirect_exemplar.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,20 +1,8 @@ class WikiRedirect < ActiveRecord::Base - generator_for :title, :method => :next_title - generator_for :redirects_to, :method => :next_redirects_to + generator_for :title, :start => 'AWikiPage' + generator_for :redirects_to, :start => '/a/path/000001' generator_for :wiki, :method => :generate_wiki - def self.next_title - @last_title ||= 'AWikiPage' - @last_title.succ! - @last_title - end - - def self.next_redirects_to - @last_redirect ||= '/a/path/000001' - @last_redirect.succ! - @last_redirect - end - def self.generate_wiki Wiki.generate! end diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/attachments.yml --- a/test/fixtures/attachments.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/attachments.yml Mon Feb 27 13:53:18 2012 +0000 @@ -102,7 +102,7 @@ container_type: Version container_id: 1 downloads: 0 - disk_filename: 060719210727_version_file.zip + disk_filename: 060719210727_archive.zip digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 id: 9 filesize: 452 @@ -182,3 +182,55 @@ author_id: 2 content_type: text/x-diff description: attachement of a private issue +attachments_016: + content_type: image/png + downloads: 0 + created_on: 2010-11-23 16:14:50 +09:00 + disk_filename: 101123161450_testfile_1.png + container_id: 14 + digest: 8e0294de2441577c529f170b6fb8f638 + id: 16 + container_type: Issue + description: "" + filename: testfile.png + filesize: 2654 + author_id: 2 +attachments_017: + content_type: image/png + downloads: 0 + created_on: 2010-12-23 16:14:50 +09:00 + disk_filename: 101223161450_testfile_2.png + container_id: 14 + digest: 6bc2963e8d7ea0d3e68d12d1fba3d6ca + id: 17 + container_type: Issue + description: "" + filename: testfile.PNG + filesize: 3582 + author_id: 2 +attachments_018: + content_type: image/png + downloads: 0 + created_on: 2011-01-23 16:14:50 +09:00 + disk_filename: 101123161450_testfile_1.png + container_id: 14 + digest: 8e0294de2441577c529f170b6fb8f638 + id: 18 + container_type: Issue + description: "" + filename: testテスト.png + filesize: 2654 + author_id: 2 +attachments_019: + content_type: image/png + downloads: 0 + created_on: 2011-02-23 16:14:50 +09:00 + disk_filename: 101223161450_testfile_2.png + container_id: 14 + digest: 6bc2963e8d7ea0d3e68d12d1fba3d6ca + id: 19 + container_type: Issue + description: "" + filename: Testテスト.PNG + filesize: 3582 + author_id: 2 diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/diffs/subversion.diff --- a/test/fixtures/diffs/subversion.diff Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/diffs/subversion.diff Mon Feb 27 13:53:18 2012 +0000 @@ -22,7 +22,7 @@ +<% diff.each do |table_file| -%>
    <% if diff_type == 'sbs' -%> - +
    @@ -62,3 +63,5 @@ diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/enumerations.yml --- a/test/fixtures/enumerations.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/enumerations.yml Mon Feb 27 13:53:18 2012 +0000 @@ -81,3 +81,14 @@ type: TimeEntryActivity position: 4 active: false +enumerations_015: + name: Inactive Priority + id: 15 + type: IssuePriority + position: 6 + active: false +enumerations_016: + name: Inactive Document Category + id: 16 + type: DocumentCategory + active: false diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/files/101123161450_testfile_1.png Binary file test/fixtures/files/101123161450_testfile_1.png has changed diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/files/101223161450_testfile_2.png Binary file test/fixtures/files/101223161450_testfile_2.png has changed diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/files/iso8859-1.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/fixtures/files/iso8859-1.txt Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,13 @@ +Index: trunk/app/controllers/issues_controller.rb +=================================================================== +--- trunk/app/controllers/issues_controller.rb (rvision 1483) ++++ trunk/app/controllers/issues_controller.rb (rvision 1484) +@@ -149,7 +149,7 @@ + attach_files(@issue, params[:attachments]) + flash[:notice] = 'Demande cre avec succs' + Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added') +- redirect_to :controller => 'issues', :action => 'show', :id => @issue, :project_id => @project ++ redirect_to :controller => 'issues', :action => 'show', :id => @issue + return + end + end diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/files/japanese-utf-8.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/fixtures/files/japanese-utf-8.txt Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,1 @@ +日本語 diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/mail_handler/apple_mail_with_attachment.eml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/fixtures/mail_handler/apple_mail_with_attachment.eml Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,240 @@ +From JSmith@somenet.foo Mon Jun 27 06:55:56 2011 +Return-Path: +X-Original-To: redmine@somenet.foo +Delivered-To: redmine@somenet.foo +From: John Smith +Mime-Version: 1.0 (Apple Message framework v1084) +Content-Type: multipart/alternative; boundary=Apple-Mail-3-163265085 +Subject: Test attaching images to tickets by HTML mail +Date: Mon, 27 Jun 2011 16:55:46 +0300 +To: redmine@somenet.foo +Message-Id: <7ABE3636-07E8-47C9-90A1-FCB1AA894DA1@somenet.foo> +X-Mailer: Apple Mail (2.1084) + + +--Apple-Mail-3-163265085 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; + charset=us-ascii + +Yet another test! + + +--Apple-Mail-3-163265085 +Content-Type: multipart/related; + type="text/html"; + boundary=Apple-Mail-4-163265085 + + +--Apple-Mail-4-163265085 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; + charset=us-ascii + + +
    = + +--Apple-Mail-4-163265085 +Content-Transfer-Encoding: base64 +Content-Disposition: inline; + filename=paella.jpg +Content-Type: image/jpg; + x-unix-mode=0644; + name="paella.jpg" +Content-Id: <1207F0B5-9F9D-4AB4-B547-AF9033E82111> + +/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU +FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo +KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCACmAMgDASIA +AhEBAxEB/8QAHQAAAgMBAQEBAQAAAAAAAAAABQYABAcDCAIBCf/EADsQAAEDAwMCBQIDBQcFAQAA +AAECAwQABREGEiExQQcTIlFhcYEUMpEVI0Kh0QhSYrHB4fAWJCUzQ3L/xAAaAQADAQEBAQAAAAAA +AAAAAAADBAUCAQYA/8QAKhEAAgIBBAICAgIDAAMAAAAAAQIAAxEEEiExIkEFE1FhMnFCkaEjwdH/ +2gAMAwEAAhEDEQA/ACTUdSsdhRCNE54GTRaBaXHiBtNOVo0wEpSt8BKfmpWCZRPHcVbdZ3X1J9Jx +Tla9OBpIU8Noo7Gjx4qdrCBkfxGupUSck13GJjeT1ObEdthOG04/zpX8SNXjR1njym46ZMmQ+llp +pStuc9T9hRq/X22afhKl3iazEYHdxWCfgDqT9K83eKfiFG1RfIEi3tuC3W9KlNh0YLqyeuO3QV0D +MznM9O2uai4QI8psYQ8gLA9virY615P034xX+zNNslLDsMKOG1J5HuAa3nQPiBZ9WtpUy4lmcE4U +ypXP2rmMHmcI/EealD7te7ZZ2S7dLhGiN9cvOBP+dIF18btHw3C1DkSbi7nATGZJBPwTitTIyZp9 +SsCun9oJaEFUDTy0oyQFyXSOfoB/rQOL466huE9LIagxW1A48tkuKJxwBlQrm4YzNhGPE9Mmua8Y +JrzsrXPiQ42y7+KtsZt4kpS8ltK0p91J5IzXGFr3xFef8pMqE4vJABZT6se3FDNyEZzNCh89Tfbv +aoV2iKj3GO2+0eyh0+h7VkWq/CqTDUqXpp0uJHPkKOFj6HofvQRzxZ1bbwFTG7c+jO0lKeh+cGi8 +bxrebZZVMtjDqljKgw4Rt9uuea5vEIEceoL09ZnHQoyGy3KaOFhxO0j6g0J8QNPr3tzorHmsJSUv +NgdQeprTIuqbfqdtD7MRxh7HO/H6ZHWlnW0e5tQnv2WgupAyEg8p9xUl7WGowpzKCoDXyJ5nvMdK +Uuho4bSv057CqK2stIWrgEZp2kWtE+O5+MC0OKUchHFCbnaWVNeW1KU3tTtwtAUkj6jkfpXoK7gQ +AZLsqYEmJ0mUBlLeCfeqHKl5PqJopNhriupQWyoqPpKeQfpTXYPDW+3ZlEhTTcVpXI8w+oj6Cmty +qMxTazHAi1ZLG/PXuKClv3Ip7t2n4yI3lKZSsEc7hmicXwfu5ThN22fCUH+tXB4QX1KdzN6WVjth +Q/1oDuG/yjCIV/xgWLouQFfiLK/5LqejbnKT9D1FStX05DRaYrTN8K232wEl1aMJV856VKF9hPc3 +9QPM32HEjxEjykBSh/ERSd4s61uGjLbBnQrcie2t4pfClEFKAM8Y704uvtsMrdfcQ20gZUtZAAHu +SawHxt8V7PKt/wCytPp/aLrToW7JAPlNkAjAPfOfpQ0JY4E42B3Nf09ruwXvTQvjM9lmGkfvvOWE +llXdKvn/ADrONZeNwU28zo2Ml1tHpXc5Y2spP+EHlR/5ivOzYkPPKdjMechRDjrCUHy1Ec9Aa1Lw +l0VF10pcy4XJC0RlbTFTgKbHwnokfSibFXkzAJbiJ0tN81jc1yHXplzkEEqkPA7UjvtR2H1/SrOl +rGu6NvP7Q8yhaWkDruVj/n616Lvl20n4Z2cpeS02tSfRHbAU69/t8nivOGoNXzNQSVRbFAbtsFal +FESEjBOepUR1rBs3D8CFVMHjmXNYW+wWtsMrlMvyyOW4h3FB9irpn70lx7k9AeDttW4w70DgWd3+ +1NmlvDi7XpL0iShcWG0dqllO5SlHsB35NG7l4PSRG823z0YbGFqkDaFK+MZx7d6XOu09Z2M8MKHb +OBM1vBuAkJcuUgyHXRu3KfDp+5ycVTaeU36kKUlYOQQcEVrehvC5l1Mh/VClISHFMttIVgL45VnH +TkEH4rQbjpHTbyGWVQIzL7bYabc2AnaMfYnAxk0K35Smo7e/2IRdC7eXUwfT5m6pfbtC/wARIlLW +VNu7yoN9MlQ9h3NO+n9Cwo8rzZU1Sm2Mlx9YLaUkHjaOv3Nc7zd7FoyY5D07HR56SfMl7961ZGNo +9gKXrtd77dnkssoSwt7K9rZG8jHU44Tkc9q0rvbyvipnNgT9kTRLvqKy2JDgS/8AiH3hjecKXjv2 +/SkG8akmRyhqG+hKSQ4dpyofBxxV2w+Hkuda27pMW5tcSpWxati1HJGQTkYp70xoS2MW1pp+ImXN +koJLi+UtfP1FAt1dFPHcPXQ9nPUy+/3pu4usrYZS16MOKCAkuLJypRxX5aG5ExX4VlfC/Vt98e3z +WvL8M9NsNMtyFyVyGx6h5uPMPyMcV9Q9HQbbdWwzHQGFHKVhStw+uTQTr6tu1IQad85M46baVarV +uVkJ/mDVCVqWUll59t4FxlW0ocOA4k+1P8uLGU35UgAhQ2kgdRWUeIMi2WyKqASFLJJbWchQI7Ul +pWWyw5GSYZ1IXA4Ez7U12mR7q95jCWgTuCQeoPsaGqntylbCpIdxnaSM/wBK56lujtydZS4UkNIw +CBzQO4RURywWnUupcQF7knoT1BHYg5r0lFY2DIwZKvYq5x1DjUo26WzJKEuIQoFSFDIP+9bzaL0x ++HZcZcQpC0ggewIrzYzNJQGpGVt+/cUw2PU8+0vqWEJnW8q/9KzgpHslXb6UV6yw4gBZg8z1NZbj +Ek43LQDjkZFMLbkMcJW3+orKvDq86T1SUssrEef3iPq2rz8f3vtTZrtizaR0pOvD8XephOG2959a +ycJH60HBBxDBhjMB+L9/RY7WpT7jam3kkNNJwSs+/NSss0Bpi4+Jmpfxl7kPOQ2k7iCfyI/hQOwz +/vUroqrUnceZ8LnIG2Cdaa61Dq54i7SVJi5ymGwdjSf/ANe/86s6W0TLvkNySp5pcVjBUy0oAD5x +1P1NbDbPALTQjp/aC5bj+OS27tH+VOmjPDqw6QEv9lNPFcpIQ4p5zeSB0A/WtNYoXCwK1nOWgjwk +sFrg2wuJjtKl5IJUBwPakLxDXbNI6/alaGW6b87uL1vjJCmAogjcvHTrnb8DpVnxj1q1oOS7b9PP +j9qSEErA58gHuf8AF7CsStOurpBjKZioQqS6sqU+vlayepPvQytu3cgz/fEPWaXfFjYEfLlo5+bM +/aurr+X33vW6lIJUD/dyen2p80zboMNG6NBEGOygJLy04cdAGRjjn5NYRD1NcjMMme8XpST6Q4Mp +H0HStstF4kO2lMS5vAlTfq9O04PQZ+KifILaqg3PnPodS5o0S3I0q4x2T3Kr+obzH1HsjuFFpeUU +B5s5Snck4ST0z0p502w5HZW86qW5lXLbpSeMfHFZH4gpFutbDlrmNtujlxvzc705HAHfB5qknVSI +VliuWK7STcHVBL7Ticc8c8f70IaMaipWq4z+oo6jT2sr8ma3qCfBky48be4zvcAOB6gR/CMd6EXF +m9EPKhx3Vx92EJdADmOmQKJ2y5xVpiJlW+OzPSj1LbSBtURyoGjFzWqPbHljClFBLbiBnHHUmpeT +WdqiPISuDM/e0bark4YzkEJkJ9RebGF7u+T/AKVeg6DbVdXHJ6U/hi35KAlRGU44zj/WrtpdfSlt +D7m54jKznr/WnOAVKa9Y7cGtDVWodhaH1WnVlD7cZxPhq3NMobbeBeZQnalKlZ47cUQDSGtvlqwn +GEp7AVQdbddWQHkp2dOea6qWHQlPmJSscEE9aET/AJCK/X+JFxUtuKecHnKxx8VXRKiBSkuKII55 +PSvq4yUQmf3qspxwc8is71fqZMeKtTO0AHn3V8UaitrDgdmcdtoyZ215q1USShq0bZClghTYPqFL +Vr0xH1otbt1XKZkpT6cccfOaF6SZkz7q7dZYWHjz0ykJp2Yvi4YaYVHdUXjs2eSUlR7HPt89KoW5 +p8af5D3OVLldz9GLmsNLR1WZiI+oJlRB5aHgBuKe2cdaxd5tVsuy0OJbdWwvkKGUq+or0PqiyXVy +IJ7za1NlIJbz6m/fgdv61lN000qWJ09EWQ8++6lqM01k8geokY5p/wCK1RXK2Nn/AOz75PS1vStt +Y594iCUnOauWi5SLXMDzIQ4g8ONOp3IcT7KHcVduWn7nbWg5OgSI6SopBcQUjPtzXK1RX1OqkMtb +0xcPO9PSkHrzV0WKRkHM86a2BwZqFm0da9c2pdw0asM3JgBT9qdd2uNH+8y51x7A/rSjrXUmq129 +Om9TuyvKhu70NyUYd4GBlX8QofG1hcLbrBF/tZ/DvtqGEDhJQONpA6gjrXq61f8AS/jDo9mXNhNu +nGxxPR2O5jkBXX+tY3bcFhPtoPAin4H6gsMTQgLEhtM7eoyGioBYI4Tx7Yx+pqUr668ILjZXDOtS +XZsdvlMiGkJlND/GgYDg+Rg1KwUDHIM2r7Bgiei5NwiQo635cllllAypbiwAPvWO678c4UJuRH0y +gSHkDBkrHpz2CR3+prHbXJ1L4o6matwkKaYP7xzkhthsdVEf8NLWrzbo94fh2RKjAjqLSHFnKniO +Cs/X/KuLSAcN3OfYW5HUD3SXJutxfnTnVOyn1lbi1HJJNPnh9otyfbJF5lLabjpJQ0FjlZHUis9C +lDOO9bdHkS4WkbXBlIMdaGUnyhwkjqFfU5pf5K566gqe+I98TpBqb9pnB/Q9wu7kdyOGUNNp3oWp +Owq7+3P1r9uQmqllqS+S+ghClFWR+vtT/Z7goWGOopbjodwEltQOcdR16/WrcrTFmW4tyYZHmuDc +dhwkDHSvNvq2BC2+up6PThdIzDvMypelJN2lI8+M9JKxsZS1/Cfcn2+tF9K6Oh6ZeW5fYS5VwKgl +locpR3Cvk0+zJTdtioi2htDe5OVL/KAPcn3r5j3ZtdmkrKFTFJ3EDG7BAzgH9a+XX2sNi8CJXaZW +c3GIN7u0u931+KwhaGGspKQMKcKepVV5UmU1DZZtzspMVKQXm3F5B+gHIH0zQCBImKuiJMeCuEH1 +YCfVkjv+bqSKr6t1U7a7uxEgurS0yMLBASc/arlenBULiSGtOSSY6WKJKXckJU2tplSt6FA7gfvW +gxA/sUBggDGSayGya5ed8tkNqSlXVYOVVpEZydIablRFF6ORgjGFJPyKga3Tuj5Il2rVC6sKT1L9 +tiuPTnDI3eSfc/lqrqWOuHFK4qlF1HIX7j2NWIkyQ8XEApSUcD/Ea5TmZj2SggqUMKSrp9KUByQM +T45U5mSS9UzJMtMZ93GFcqJ7UL8Q3UOOww24Bx6h3V8/Sqev0sx7u4IqkB5w8tJ4KFfNBXG3Fuo/ +FPqLxA3FXXHtXp9PQiBXXiTGZrmIjTo68qh+Y2ygPhYSAlXIBz1rYHp04RkNRnWDOA5KyEgDrgVh +mmSmPcCfQpWCACnINFdRXOW3GQ4+60GgcJKDgr+R70lqdP8AZaAvuUK3woDY4mqyrjeFWppZZUXW +lnzUlYCVp+K+LLeYEoLLG5lGdxQk4wcfyrOourlyIzbDhcKVNhHB7e9XYlxatbam0dVDOAOT96Rf +TEDBHMMpU9dTQpVxiTWXGUqDy1n0hxCSAPvXnfWVtnWO9TI8lpLHnZOGxhKkE54+K1K1XhLj4S4j +GOnxX5qiNZ7wlpd1Di30ZS0hKtu4kdCaN8fqG0luxhwYtrdOtqZXsTA1dTWh+B+unNG6tbTIWTap +hDUhGeE56L+oP8qSbtBXDnyWSB+7WUnadwH3rgYT6IQmEpS0VbU5WNyj8DrXr/F1/ueXIZT1P6Hh +aVoSpJBSoZBB4IqVjPgP4ii72eHZLsSJrCPKadP8YA4B+cfrUpMgg4jK8jMybw5vUfT/AIXatujD +iRc5S24DX95KVAkn/P8ASstODk9asPSXvwZbUEoQpzhtIwkYHt9z1q3NZiO2uNMhFLbif3chkryc +9lAHsabbAbP5i6DI/qctPSokW9w3p0cvsIcBLY7+2fituuVxYvDbAMZ2VIUkeX5I5x3Tgdqznwz0 +xbb/ADZQuy3w2y2FISycHJz3+MVtWnNLwNMb3G0SZDvlgb3DlWPgf86V5/5e+oOAc7l/9y18WLK/ +IdH/AHB+l23bLPLMl0RkyQS22r1eWQO/tR178NEju3GS8ZahyVIc7ewA4qpKKfxzTMOGHCsBZSob +ueveitut+XGo8tpDacEp2DAP69ahNYHO4yo1rMxJgt22RLy0l5bYQ04jckLWfM+o7frVPUMpdg0a +65EfXvaX5XOArnp9hTtGgRbcyhL6PPbaG1ClnJAPvWeeMl0FogwnWGYkqKHSFxnUkpSojgkD79aJ +pQbblr9ZgNRcAhMzli9zZYfS27NkPBIKAFKVnnkn2pf1PaZbMNm4PpkDzeV+c0UEK+p6/WtX8H5M +GXDm3OS22Jq3P/W2AlIHwOgFVPF+VBfjqKi4sEHBKSAVfFegXWsmo+pV4zJZ0wareTFbw71Y1Ab/ +AAjbcNh1Q/8Ae9yaYU33VESW5KdK1wucuMpwgj3FYq4S456E7VDjimGHqa6wYqIS5HmMq42LOQBT +Wo0AYll5z+YCjV7MA+puVmuDkgh7evZt3bsdK46s1uiNZSY6iHwSj82CPnFC7PcbdbdOxkPTiqaB +5iQlXCf61mV9uC79dn39oDIVztGAajafRK9pPoSrZezKAOzKclyXcLgue8VLUo7sHrUaVIfeCloG +T0Uo9qstKdbcBLZUg9DiuzkbY4VDIBGQkdBVkuBxOrRtAwf7naKlyMoqQ4pRI9RHH2qtc1/i/KS+ +p3yWchtKwcIzX7HnoQv1nbgYUR7+9NESXCmR1xdjexxOXCTg9ODSzO1bBiJvCsCBFu3eahwltCnA +O6ATj6082K2rlltyXGSsIGEhzPP1xQa1QJNngLmMuNPMrPKE5BwKuzrw6Yu6JJVGWkZSkHIXn274 +pe8m0+H+51G2DBlu4J/DzFKbWhICiS2EgH7H2FD3JTMuclt7B2ArBzgJPvQNF1lSUFoON5JyST1P +tmgEu5yY0wgJ2uoUd27nPtRKdEzHk8xezVLUnHudtXsRYc4rt8pxZdKvMSpWcH60M07a03W5JZcW +UtgFSj8Dt96orKnVKUQVK6nv966R5b0dCksLLe4gkp68dOatKjBNgPMiM4Z9xHE1fwCkQx4pqYdC +vJcC1RwT0WkZH8s1KVPDm+Psa208ogAtysqWOqyo4JP2qUtanPM2jDEL+OWn49u8R5UK0MbGClDg +bSOApYyQPvSzM0rKt9qiXCRs8uSSlCeQoHnII+1aJ/aAZWjxImL3FILTSwR/+RX7bhqJ561XC5Jj +O20pSnyFYJWMZypJ6djWLdSa1BzxDUaYWnaOzH/RlmZ0nYWPJab9SQqS5t/eLV2+wzj7UfZmouM8 +MNtlsNoKlFZAV8H4FULPfmrmtyCtwJfQjKggFIVx2orHsbUZ1TzCktFwfvVKJJUB05968jqHaxyz +y3t+sBeiJJTLSXA6hAWscFSTjke561yfkAlte4h88BIJwB3q5Hjx297RUpWfUD+YYqs5Gjx3HJJK +ywRylIGM+/vShBMIrDMtpKiyVKcWtvaP3aRnn3HevOfi9eZM/UEiEv8A7eOHgkhfT0jg4+5r0JJu +ENLad0plpWM9c8dqUtTaMtGoJS37gyXH3UANyEHH6iqXx99entD2CK31m1CqmZZomd+HjORbXte8 +hOVLSk4USeTRm4xrvqbTjseUGmozTmVPLH5fgfNNNhYtWmJardbw3tf59XqIwepNM2poyJVpdKEt ++SRuCR/EfemLdWou3oO/cJXVmsI08z3BiFp7UakMuonR0jk47+31oG7iTM/dkNoWvCdx/KCe9P8A +dIzR1PAZfjtI3gx3QsAJHznFKOqbfbbXKSzbriZrwJ8390UJRjpgnrXpdNeLAM9kSDqKDWT+AYcu +1ivcK2x1KdiyYSejrCgSnPZXehTLqou7cghKRkgd6Px9SWp2xsMT23HF7QgpaOCFDoaCxFee4UKC +gCT14P3oKs5B+xccx+kIpG0wlaJKZLB9KglB5Uo9KsLeDj2GzjI+1AjmPLH4ZzCVEApPAIopGCFR +1rSpW4naaFbWB5DqUabMnaYEuTGyc40le4deO1fMZam17krwAOua7yYjyZCiG8hZ65ya57WW3W2y +lS3FDkFW0CmgdygdydZ4MT1HezzUy4iCwVKLKcFtSuD74r9uVtRJabLZ8obckpTlP60ItSLXOeDT +KlR1spG9W7clw/ejN4mXa0MDYA9FLn7olIxtxyFCprVkWbU7/cY+0FNx6/UU70GYDBQw6FrUcAgH +ke9Lq3FHkkk980xXedHuYWt6D5L4A2rQrCQO4xV+yaaiTrW5JL29GRgflUCOoJ5wPmqaOKUy/cl3 +Zufw6itbriuAJHloSVPNlvJ/hB61RCwVAKPHc1YubQZmvNpSlKUqIACtwH371Tzk/FOKAeR7ibEj +g+o06QWy7riziG2pDf4lsJCjknnrUrv4TtIe1/ZQ50Q+Fk/TkfzxUpW7ggQ1a7xmbF/aGsKEX83N +U4IU8wFJZWMbtvBwf04pOieITadOMxXmWRJR6CsD1HHTH2xWx/2irAu9aJTIjJJkQXgsYHJSrg/6 +V5os1rjsynVXOQY8uMsER1t8r+M9j0pSymu1P/J6j+ktatxtE23QtvmwYar3cX0JjyE+hhQ9ROeC +a0CJJaLTe+Uhfm/l7/YUhWKUxfbKxCztdQkJStWdySf7o/rTHZLC7bW3g5M819Y2pLiPy/TmvLak +AsSeCPUp7i1hB6h+Ytbnl+US2AfVx/nXyWg4kpeOQ4CPT2FVX0JacS6qWpASnC0qIINDLlKKGyGp +QaLmADgYA74xzSY7zDpWW4Eq2e0N2yXMdmKS6twlCUO4IQj3+po86RGWzGjtNgO4AATwlPXNAmPK +dLanH15K04SEE5x7GrsGWLnclJ9SHGuCrOCU+1E2s5zNfSE/7mJniFFciyHJ6XEktoIylWBjPPHv +SnC1HKlFK25Kls7cBpSvy4PtWwXHSsCXIUqUt15Tg2qStfpx7kUIc0JZIqHlpGwqTgFJxgZzx809 +XfWE22DJgwQD49TGr0pN2nlL7i2JKjvC1DCc9qUtRR47sjLQWiYkYdbX0PyDWwax09bZpcZtpdbl +FJO5aztJxkD46Vl83TclMT8SlDjh28lIJwfY/NXdDqK8Ag4iGsosYHK8QVKiRIztv/BqccWUhT6l +jASruBVpEoKkOAYLhJO0D9KGIUoqQ2vucYPaidptb0i6lCMNt8lSlq/N8VRcDblz1J9Tbf4CEGYb +rzbjiEBLqQQAtQAzUs7jrqnGFNJy0fUMcA/WjlutUySrLT0dLGw5C08hQ6fbNCrTBuVlubjjkJ58 +pJwU5Lef72B1pQMLFYZGY0bHQggS7KYUw35ivUlXU9xSfdCp5QWltSUp/iPfNaBLtv4KGiVOkYcf +X5imS2dyE9uM8DvjrQc2hyYsg+WGSfSQKxRatfJMLepvXA7iilxtKmlMJcQ4nlSlKzn7U4wbou7Y +RK9SGeUpzjJPciuLmi5ayDF8t3nsrHFfFx0lcbeSptYWhKUlS0EjBP8ADR2votx5DMSFF1eRjiGF +OWuK4mO+y2lTyFIWpw5SCeivgZpNuCzBU4zEmBbTnUtq4UP+ZoxaNIXG6So5ebX5C3NillXQd/pV +zWlmYtEJmEiARLz6XEerf78jrXy3VK4XO4mDsSzbwMYiQI8iQlx5tpa2kfmWBwK4BKVdDiicpq5t +NGItl1DbbYdUgDgAjO40JZSpxwBA5zVBDnn1EnGD+5rn9n+1pXeZlzcQFIYbCEEjoo9x9galN/hp +BFn06wwQA89+9cPfJ7fpUpG072zHql2Libtf225NukRX+WnWyhX0Iry9drM3ar2i4XN0h6BKS28r +O5TiByleD8Yr0ldJyHWtyOD0UKzHW9taloXM8jzkhBbkN4yVt+4HunqPvQXBxkTqH1E2dck2u5wp +9rUW0yiVPKCdwQgkYJx361pca9NSGG3C5kIR6nkD0g/Ws5uMMT4DJtFyZTCdSlAjlsJKTnHpP+hr +hapk+yxP2fNW7+DeSrAIyN3uP0qJfQtij8/9lPTlkznmPNwdh3FgILzgcK/3bqSfUfZQpW1BMuNr +hKeeQlCyrCWeu0DjdXL9oW2NAadjuLbdj4UFBQIWoe6Scg/NEo5cu81h+5JAQtvcgdE++Tmlvr+o +5YZEbpvstyvRlPSGtFvNJjzox4JKHknHP0pq03c2GlTAp5j8Spw7d5CVEYHANL9xsrTbMibHUCUJ +IKEt8JPvxSey4ZylLX/8yOSMbqIK67stXwIT0NxyZubSDKUX1lbawkAZ9u+KHXeez5ja3HwhpPxy +D2HNZu1rG7W5zeqS0EgbUggHA+nvVaNqOXdr5HVNcQhCV71BKQNx7ZzxQxoW7PUIgGcmNs6SqW+W +2hvdc53qRgkHgc0YsdpVGgluSGygrUdqQClJ+TXVu2sSSu4x3PxD20qDa14yccAe2KruPvNw23Lg +z+HDytqh1Chjoo9utAJ9LC22h0CqMRc15omyXhCnLc0mLc0c7mcBKiBnCk/PuKy646YvkCU0qLuL +iWylQUPyE9cH5/WtkRLs0VhTLzqW22sEqLm5xXPTjtV2bLt88sttrCSpQxsOSCPeqGn191ACnyH7 +k27RI/K8TFdFOOYcTcAWENqIcUpJBz23DvTqvWMRElm3uQiUpIQ08BgJV259qdFWjzorsd8RXQ7k +KJHCh7E9yBWWatszVpmsKRuCRgJTn0g5P9KKt9WrtJYYM+q07IgQGWpsNN/lsTH5W7yF7H22+Nqc +ZJz84r8sMda284IRztBHal19yRbslgltMjKVA01abvCmLamK6AprbtGeoo1ysKwF5Eao0TsxK9xu +03BS6hS9gU4DzkUWj26G4osKbSpRysBQJGaE2W822NHDbyngM7s4wM/avmZqdhrelhorSoEbxknn +5qVtctnEOdLZnkQvKjIhuNojNZyraQMYTx1PtXzeYMZtDS30IS4lQWhWMkH4+tIxvz8GT5iQt1Bz +vSoHBPbNVjPvGo33HWnSEsgqTgcE9NtMJpWyGJwJ9dQVGOxAGt9QruazbYxQGMAOOjBUo9hn4pf0 +vYiu7AvEKQ0rcQOh9hX47bJMW5qjlrCyohKSoEgfOKboflWmIhhsb5S+Sfk16SsCmsLX1PLWoXsz +Z2I6QZ3kBKc5dPGPapSw28qMn1q3PK/Mc9PipQ4YVMwyJt2oHV2uZuGVML/mKoKWlwbkHchQ4qkN +ZaevsQxzcmQsj0byUkH71TgOvRVqbeG6Ks+l5PqSD9RXxBioihqTS8Vm7JlNyHGIqlZWWujDmQQr +H9339q/bihUVLqVvh1ak7S6g8KHwO1OshQIIUAoHg96z7VdpkxIEw2chTDqTmOr/AOZ90Ht9KWv0 +7WkYMf0Oqr075sXIgLTkZl7Uy1zZCQhpsuDOOuQOa05NvYkS0J8h1UUDd5w5UOOAfisK026yJZj3 +YOR3i56XRzkn+EitUsN4uEvEeCpDCGlEOL67ldMikfk6HUg54Ef02pS9i6jEcLpcGUMLSW9iU43J +6EjH+VZ9NuLDmQqCIsdxR7e30rQWNPKaebmOTVrdXysq5C+OhFfcm129Y/7ptghJ3JKU8j6VLqtS +rvmNFNx4mNXGMy6jEQqeUF5V8D2oS63JalpaQdrhxjdyQK2O6Ls8SOGm0hO7ohKeVH2FIl205Pdd +cmMskrICkNg+pIz0IqrptWGGDwP3M3VhFye4w2hmVGYaUmUUsrwcpOSn5xTpcpUJu1vOmQpwObUK +S6njfnjjtzWOu6iu3luRnIhQGTtJHBB/pRq1u3G5hhKFlIVneVdz9+lKXaRgdzkCdRxYMg9S9qB+ +A/MS0tpYIVudaZTgOqwAPtUdjTkORXGmhHbKgltKVBJSMd+9Mtv/ABrcWRFLUdxATl0lGFlWOx7/ +AAaEOJhuLZipYdksr6BokraVnnd7VhbOl7xBfWwctnj8T9m39strVFa9aMggZKlK+lLGpXLhc47d +smsKjlSgpJWg5A65B7dfrWk2vTdus8p+clS1vYyEurB2H+pqs9erVc32zJIbeZXtS2oZO8fH+tap +sVH3VrnHucXftIeZf/0zdZDYbKlPlpJWVnkZ7D704WLRhTbkOzg6XVpxsB2+Wfr3p0hzIylPPtth +KEr2uFQxuI7ChV61IhaTGay24okBST0J6GutrLLPACMJY6DxMze/Ldtdzcik7gnlJ+DVJF2KTlVO +0O2M3WK8mQ0h5/HoIOFdepPalq5aTuapziQhptrPUkHA609VZW3i3cbHyRVfKU03RLishXIpfVqe +Q2lyJC/dZWQpfzmqF5f/AGdcSw08hwJxnb3V7CqcNl5qWp6U2lKRnYnOefeqlOjQDcw4kX5D5g2Y +Wn13GOKsQklxR8yU51UecUSt+5GX3vU8rue1CbeypxfnO/YUWB9jRGIHAiVNZc72lgLJVzzUrmg1 +KFiOjjqIwUpPKSR96KWnUl1tLoXCmOt+4CuD9qFlOe9fm3nrT5wexPN5I6msWHxHjzili+Nhlw4A +faGBn5HSmicCI6X2loeiufkeb5Sf6GvPqknrTJpPVs2wPbMh+EvhxhzlKh9KA1XtYZbM9xj1Laos +/K1ICHv74/1qnbryuwBtCIYQgDatbayQv5wehpnu8NiXaBebK6X7csgOIPK4yj/Cr49jSbJXwQel +BesWLseGrsNTbkjx/wBWQ4FvYfdntLW8NwZC8qT9RQ9Gq3bo8ERlBDajgrJ/KPekB1ltLqZCAlK0 +HcCUgjP0NfIuy1Tg+yw2y4kEL8kYSv52nj9KSPxNQ/jyZRr+UYfyGJt+nm7Kje95pflEAFxR6H/C +DQW+OSocpBjL/EFZOHmzyR7GkzSl9ZLr5uE2LFBOPLWlWSPccYFaxpS8WZlP4aEpDri8OKO4KBP+ +lTL9NZQ/kMxg21agBi3MXo9ulOvB1uC8p0j1LV0PH86JQ7QpiSh94mO3tUFBSeMn2zTsJjKFrde8 +g8DbsIJA78VzbuEd6MVLaSWFZSCUZI985pRnJjCviI2nbncJNzXDUhL7aSU5C8J2/OKcbTaodsU7 +K8hLL6zuUndkA/GaU7tM/ZUlQjBlu3bdzbkdHKTnkE+59qU77q+4zISmGY8lbyVH96hKjlPHHFGG +me0+HAM7bcmMxv1V/wCQkLFvcdxzktd6RbNDC71lDgbS2dy3F9sHmh8PVF5ZQtEdteFDar0eof0o +8q7abXHYNxdDEhgYUUnYpffkdxmqFelspGMZz+Io2qQ+51v9/wDw7KkwZflxlElIKgTnPJNcH7mz +Asjbi1smU8QouE/PBH2pd1DreyOwnojMGPIK8+tLe3HGAfrSE9cVrjtJjFfozwv1bfpnj+VOaf40 +so3DETv+RReF5m53LUNis0Bp9ExK3QkAoQ5nPfisq1druXd3CmMVtsDITlXOPn3pcMGS/HW84VKd +zwF9SKFKCs7T27U/pvjqaju7Mm6jW2uMdCE4tsukyI5cmY77sdtYSt4DICuoBNMFoWiapJcVhY6o +V7138N9XK0/JWw42l+BIT5cmMv8AK6jv9COxpi1XpBtE2LctJvfi7bOBdbAI8xrH5krHYj370zaf +R4gqCQwxzOCMJGE9K6A4rm20ttnDysuJ4OBxmq0uWllv08rNIjyOBPRsCg5GJLnODDZQg+s/yqUs +zJKlqUVHJNSmkqGOZOt1TBvGfZIxkVwWsg1KlaEmT8DhxX7u3dqlStTka/D3Ur2nrylKkfiIEr9z +IjK/K4g9fvR/xBsyLDqF+IwsrjqSl5rd1CFjcAfkZqVKHYIZOonyclpZz0oeygoUpWetSpWVmz1O +c6Ol9o9lDoaBIkPMOZS4obTg4URUqUzWAeDE7SVPEYrXrSZb30ORGwhwDG4rUr/M0SXri+SpYcYu +EiMMcJbVx9alSgtpad27aMw6ai0pjdKFz1nqJuSn/wAtIJIznj+lfQu11VueVdJm9weohwjNSpWj +UigYAmfsck8wPPlPKz5jzyz33LJoOt1SieSB7VKlGQQDk5n2w35qwCaYLbEQEBwgY7CpUrlphaAC +3MIkBKc0DuUUKC5CcJIPI96lSh18GH1AyINiI8x9CM4x3Fat4f6okWOY0qKkFv8AKpCgCFp75qVK +xqfUY+MUENmMmv7bHbDV5tqPJjTFcsK6pVgE4+Kz68xy41vZUEKPvUqUovDyufKjmfrVmYbiHd6n +cbis+/WpUqUcMZKdF44n/9k= + +--Apple-Mail-4-163265085-- + +--Apple-Mail-3-163265085-- diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/repositories.yml --- a/test/fixtures/repositories.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/repositories.yml Mon Feb 27 13:53:18 2012 +0000 @@ -1,9 +1,9 @@ --- repositories_001: project_id: 1 - url: file:///<%= RAILS_ROOT.gsub(%r{config\/\.\.}, '') %>/tmp/test/subversion_repository + url: file:///<%= Rails.root %>/tmp/test/subversion_repository id: 10 - root_url: file:///<%= RAILS_ROOT.gsub(%r{config\/\.\.}, '') %>/tmp/test/subversion_repository + root_url: file:///<%= Rails.root %>/tmp/test/subversion_repository password: "" login: "" type: Subversion diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/repositories/bazaar_repository.tar.gz Binary file test/fixtures/repositories/bazaar_repository.tar.gz has changed diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/repositories/mercurial_repository.hg Binary file test/fixtures/repositories/mercurial_repository.hg has changed diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/wiki_content_versions.yml --- a/test/fixtures/wiki_content_versions.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/wiki_content_versions.yml Mon Feb 27 13:53:18 2012 +0000 @@ -53,4 +53,50 @@ version: 1 author_id: 1 comments: +wiki_content_versions_005: + data: |- + h1. Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + + h2. Heading 1 + + @WHATEVER@ + + Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + + Cras ipsum felis, ultrices at porttitor vel, faucibus eu nunc. + + h2. Heading 2 + + Morbi facilisis accumsan orci non pharetra. + updated_on: 2007-03-08 00:16:07 +01:00 + page_id: 11 + wiki_content_id: 11 + id: 5 + version: 2 + author_id: 1 + comments: +wiki_content_versions_006: + data: |- + h1. Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + + h2. Heading 1 + + @WHATEVER@ + + Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + + h2. Heading 2 + + Morbi facilisis accumsan orci non pharetra. + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 11 + wiki_content_id: 11 + id: 6 + version: 3 + author_id: 1 + comments: diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/wiki_contents.yml --- a/test/fixtures/wiki_contents.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/wiki_contents.yml Mon Feb 27 13:53:18 2012 +0000 @@ -103,4 +103,27 @@ version: 1 author_id: 1 comments: - \ No newline at end of file +wiki_contents_011: + text: |- + h1. Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + + h2. Heading 1 + + @WHATEVER@ + + Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + + Cras ipsum felis, ultrices at porttitor vel, faucibus eu nunc. + + h2. Heading 2 + + Morbi facilisis accumsan orci non pharetra. + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 11 + id: 11 + version: 3 + author_id: 1 + comments: + diff -r 487d96eac004 -r 5e80956cc792 test/fixtures/wiki_pages.yml --- a/test/fixtures/wiki_pages.yml Fri Feb 24 20:18:25 2012 +0000 +++ b/test/fixtures/wiki_pages.yml Mon Feb 27 13:53:18 2012 +0000 @@ -69,3 +69,10 @@ wiki_id: 1 protected: false parent_id: +wiki_pages_011: + created_on: 2007-03-08 00:18:07 +01:00 + title: Page_with_sections + id: 11 + wiki_id: 1 + protected: false + parent_id: diff -r 487d96eac004 -r 5e80956cc792 test/functional/account_controller_test.rb --- a/test/functional/account_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/account_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,20 +23,20 @@ class AccountControllerTest < ActionController::TestCase fixtures :users, :roles - + def setup @controller = AccountController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_login_should_redirect_to_back_url_param # request.uri is "test.host" in test environment post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.host%2Fissues%2Fshow%2F1' assert_redirected_to '/issues/show/1' end - + def test_login_should_not_redirect_to_another_host post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.foo%2Ffake' assert_redirected_to '/my/page' @@ -50,9 +50,9 @@ :attributes => { :class => "flash error" }, :content => /Invalid user or password/ end - + if Object.const_defined?(:OpenID) - + def test_login_with_openid_for_existing_user Setting.self_registration = '3' Setting.openid = '1' @@ -73,7 +73,7 @@ post :login, :openid_url => 'http;//openid.example.com/good_user' assert_redirected_to home_url end - + def test_login_with_openid_for_existing_non_active_user Setting.self_registration = '2' Setting.openid = '1' @@ -120,7 +120,7 @@ token = Token.find_by_user_id_and_action(user.id, 'register') assert token end - + def test_login_with_openid_with_new_user_created_with_manual_activation Setting.self_registration = '2' Setting.openid = '1' @@ -130,30 +130,30 @@ assert user assert_equal User::STATUS_REGISTERED, user.status end - + def test_login_with_openid_with_new_user_with_conflict_should_register Setting.self_registration = '3' Setting.openid = '1' existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com') existing_user.login = 'cool_user' assert existing_user.save! - + post :login, :openid_url => 'http://openid.example.com/good_user' assert_response :success assert_template 'register' assert assigns(:user) assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url] end - + def test_setting_openid_should_return_true_when_set_to_true Setting.openid = '1' assert_equal true, Setting.openid? end - + else puts "Skipping openid tests." end - + def test_logout @request.session[:user_id] = 2 get :logout @@ -167,12 +167,12 @@ Setting.self_registration = '3' get :register end - + should_respond_with :success should_render_template :register should_assign_to :user end - + context "with self registration off" do setup do Setting.self_registration = '0' @@ -197,7 +197,7 @@ :mail => 'register@example.com' } end - + should_respond_with :redirect should_assign_to :user should_redirect_to('my page') { {:controller => 'my', :action => 'account'} } @@ -210,7 +210,7 @@ assert_equal User::STATUS_ACTIVE, user.status end end - + context "with self registration off" do setup do Setting.self_registration = '0' @@ -220,5 +220,4 @@ should_redirect_to('/') { home_url } end end - end diff -r 487d96eac004 -r 5e80956cc792 test/functional/activities_controller_test.rb --- a/test/functional/activities_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/activities_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,18 @@ require File.expand_path('../../test_helper', __FILE__) class ActivitiesControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :groups_users, + :enabled_modules, + :workflows, + :auth_sources, + :journals, :journal_details + def test_project_index get :index, :id => 1, :with_subprojects => 0 @@ -21,6 +32,11 @@ } end + def test_project_index_with_invalid_project_id_should_respond_404 + get :index, :id => 299 + assert_response 404 + end + def test_previous_project_index get :index, :id => 1, :from => 3.days.ago.to_date assert_response :success @@ -75,12 +91,24 @@ } end + def test_user_index_with_invalid_user_id_should_respond_404 + get :index, :user_id => 299 + assert_response 404 + end + def test_index_atom_feed get :index, :format => 'atom' assert_response :success - assert_template 'common/feed.atom.rxml' + assert_template 'common/feed.atom' assert_tag :tag => 'entry', :child => { :tag => 'link', :attributes => {:href => 'http://test.host/issues/11'}} end + + def test_index_atom_feed_with_one_item_type + get :index, :format => 'atom', :show_issues => '1' + assert_response :success + assert_template 'common/feed.atom' + assert_tag :tag => 'title', :content => /Issues/ + end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/admin_controller_test.rb --- a/test/functional/admin_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/admin_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ class AdminControllerTest < ActionController::TestCase fixtures :projects, :users, :roles - + def setup @controller = AdminController.new @request = ActionController::TestRequest.new @@ -31,20 +31,20 @@ User.current = nil @request.session[:user_id] = 1 # admin end - + def test_index get :index assert_no_tag :tag => 'div', :attributes => { :class => /nodata/ } end - + def test_index_with_no_configuration_data delete_configuration_data get :index assert_tag :tag => 'div', :attributes => { :class => /nodata/ } end - + def test_projects get :projects assert_response :success @@ -53,7 +53,7 @@ # active projects only assert_nil assigns(:projects).detect {|u| !u.active?} end - + def test_projects_with_name_filter get :projects, :name => 'store', :status => '' assert_response :success @@ -63,7 +63,7 @@ assert_equal 1, projects.size assert_equal 'OnlineStore', projects.first.name end - + def test_load_default_configuration_data delete_configuration_data post :default_configuration, :lang => 'fr' @@ -71,7 +71,7 @@ assert_nil flash[:error] assert IssueStatus.find_by_name('Nouveau') end - + def test_test_email get :test_email assert_redirected_to '/settings/edit?tab=notifications' @@ -80,15 +80,15 @@ user = User.find(1) assert_equal [user.mail], mail.bcc end - + def test_no_plugins Redmine::Plugin.clear - + get :plugins assert_response :success assert_template 'plugins' end - + def test_plugins # Register a few plugins Redmine::Plugin.register :foo do @@ -100,11 +100,11 @@ end Redmine::Plugin.register :bar do end - + get :plugins assert_response :success assert_template 'plugins' - + assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' } assert_tag :td, :child => { :tag => 'span', :content => 'Bar' } end @@ -114,24 +114,24 @@ assert_response :success assert_template 'info' end - + def test_admin_menu_plugin_extension Redmine::MenuManager.map :admin_menu do |menu| menu.push :test_admin_menu_plugin_extension, '/foo/bar', :caption => 'Test' end - + get :index assert_response :success assert_tag :a, :attributes => { :href => '/foo/bar' }, :content => 'Test' - + Redmine::MenuManager.map :admin_menu do |menu| menu.delete :test_admin_menu_plugin_extension end end - + private - + def delete_configuration_data Role.delete_all('builtin = 0') Tracker.delete_all diff -r 487d96eac004 -r 5e80956cc792 test/functional/application_controller_test.rb --- a/test/functional/application_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/application_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -20,7 +20,7 @@ class ApplicationControllerTest < ActionController::TestCase include Redmine::I18n - + def setup @controller = ApplicationController.new @request = ActionController::TestRequest.new @@ -29,30 +29,30 @@ # check that all language files are valid def test_localization - lang_files_count = Dir["#{RAILS_ROOT}/config/locales/*.yml"].size + lang_files_count = Dir["#{Rails.root}/config/locales/*.yml"].size assert_equal lang_files_count, valid_languages.size valid_languages.each do |lang| assert set_language_if_valid(lang) end set_language_if_valid('en') end - + def test_call_hook_mixed_in assert @controller.respond_to?(:call_hook) end - + context "test_api_offset_and_limit" do context "without params" do should "return 0, 25" do assert_equal [0, 25], @controller.api_offset_and_limit({}) end end - + context "with limit" do should "return 0, limit" do assert_equal [0, 30], @controller.api_offset_and_limit({:limit => 30}) end - + should "not exceed 100" do assert_equal [0, 100], @controller.api_offset_and_limit({:limit => 120}) end @@ -61,7 +61,7 @@ assert_equal [0, 25], @controller.api_offset_and_limit({:limit => -10}) end end - + context "with offset" do should "return offset, 25" do assert_equal [10, 25], @controller.api_offset_and_limit({:offset => 10}) @@ -70,14 +70,14 @@ should "not be negative" do assert_equal [0, 25], @controller.api_offset_and_limit({:offset => -10}) end - + context "and limit" do should "return offset, limit" do assert_equal [10, 50], @controller.api_offset_and_limit({:offset => 10, :limit => 50}) end end end - + context "with page" do should "return offset, 25" do assert_equal [0, 25], @controller.api_offset_and_limit({:page => 1}) @@ -88,7 +88,7 @@ assert_equal [0, 25], @controller.api_offset_and_limit({:page => 0}) assert_equal [0, 25], @controller.api_offset_and_limit({:page => -2}) end - + context "and limit" do should "return offset, limit" do assert_equal [0, 100], @controller.api_offset_and_limit({:page => 1, :limit => 100}) diff -r 487d96eac004 -r 5e80956cc792 test/functional/attachments_controller_test.rb --- a/test/functional/attachments_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/attachments_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -23,45 +23,87 @@ # Re-raise errors caught by the controller. class AttachmentsController; def rescue_action(e) raise e end; end - class AttachmentsControllerTest < ActionController::TestCase - fixtures :users, :projects, :roles, :members, :member_roles, :enabled_modules, :issues, :trackers, :attachments, + fixtures :users, :projects, :roles, :members, :member_roles, + :enabled_modules, :issues, :trackers, :attachments, :versions, :wiki_pages, :wikis, :documents def setup @controller = AttachmentsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new - Attachment.storage_path = "#{RAILS_ROOT}/test/fixtures/files" + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" User.current = nil end def test_show_diff - get :show, :id => 14 # 060719210727_changeset_utf8.diff + ['inline', 'sbs'].each do |dt| + # 060719210727_changeset_utf8.diff + get :show, :id => 14, :type => dt + assert_response :success + assert_template 'diff' + assert_equal 'text/html', @response.content_type + assert_tag 'th', + :attributes => {:class => /filename/}, + :content => /issues_controller.rb\t\(révision 1484\)/ + assert_tag 'td', + :attributes => {:class => /line-code/}, + :content => /Demande créée avec succès/ + end + set_tmp_attachments_directory + end + + def test_show_diff_replcace_cannot_convert_content + with_settings :repositories_encodings => 'UTF-8' do + ['inline', 'sbs'].each do |dt| + # 060719210727_changeset_iso8859-1.diff + get :show, :id => 5, :type => dt + assert_response :success + assert_template 'diff' + assert_equal 'text/html', @response.content_type + assert_tag 'th', + :attributes => {:class => "filename"}, + :content => /issues_controller.rb\t\(r\?vision 1484\)/ + assert_tag 'td', + :attributes => {:class => /line-code/}, + :content => /Demande cr\?\?e avec succ\?s/ + end + end + set_tmp_attachments_directory + end + + def test_show_diff_latin_1 + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + ['inline', 'sbs'].each do |dt| + # 060719210727_changeset_iso8859-1.diff + get :show, :id => 5, :type => dt + assert_response :success + assert_template 'diff' + assert_equal 'text/html', @response.content_type + assert_tag 'th', + :attributes => {:class => "filename"}, + :content => /issues_controller.rb\t\(révision 1484\)/ + assert_tag 'td', + :attributes => {:class => /line-code/}, + :content => /Demande créée avec succès/ + end + end + set_tmp_attachments_directory + end + + def test_save_diff_type + @request.session[:user_id] = 1 # admin + user = User.find(1) + get :show, :id => 5 assert_response :success assert_template 'diff' - assert_equal 'text/html', @response.content_type - - assert_tag 'th', - :attributes => {:class => /filename/}, - :content => /issues_controller.rb\t\(révision 1484\)/ - assert_tag 'td', - :attributes => {:class => /line-code/}, - :content => /Demande créée avec succès/ - end - - def test_show_diff_should_strip_non_utf8_content - get :show, :id => 5 # 060719210727_changeset_iso8859-1.diff + user.reload + assert_equal "inline", user.pref[:diff_type] + get :show, :id => 5, :type => 'sbs' assert_response :success assert_template 'diff' - assert_equal 'text/html', @response.content_type - - assert_tag 'th', - :attributes => {:class => /filename/}, - :content => /issues_controller.rb\t\(rvision 1484\)/ - assert_tag 'td', - :attributes => {:class => /line-code/}, - :content => /Demande cre avec succs/ + user.reload + assert_equal "sbs", user.pref[:diff_type] end def test_show_text_file @@ -69,6 +111,68 @@ assert_response :success assert_template 'file' assert_equal 'text/html', @response.content_type + set_tmp_attachments_directory + end + + def test_show_text_file_utf_8 + set_tmp_attachments_directory + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("japanese-utf-8.txt", "text/plain"), + :author => User.find(1)) + assert a.save + assert_equal 'japanese-utf-8.txt', a.filename + + str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" + str_japanese.force_encoding('UTF-8') if str_japanese.respond_to?(:force_encoding) + + get :show, :id => a.id + assert_response :success + assert_template 'file' + assert_equal 'text/html', @response.content_type + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /#{str_japanese}/ } + end + + def test_show_text_file_replcace_cannot_convert_content + set_tmp_attachments_directory + with_settings :repositories_encodings => 'UTF-8' do + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("iso8859-1.txt", "text/plain"), + :author => User.find(1)) + assert a.save + assert_equal 'iso8859-1.txt', a.filename + + get :show, :id => a.id + assert_response :success + assert_template 'file' + assert_equal 'text/html', @response.content_type + assert_tag :tag => 'th', + :content => '7', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /Demande cr\?\?e avec succ\?s/ } + end + end + + def test_show_text_file_latin_1 + set_tmp_attachments_directory + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("iso8859-1.txt", "text/plain"), + :author => User.find(1)) + assert a.save + assert_equal 'iso8859-1.txt', a.filename + + get :show, :id => a.id + assert_response :success + assert_template 'file' + assert_equal 'text/html', @response.content_type + assert_tag :tag => 'th', + :content => '7', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /Demande créée avec succès/ } + end end def test_show_text_file_should_send_if_too_big @@ -78,17 +182,20 @@ get :show, :id => 4 assert_response :success assert_equal 'application/x-ruby', @response.content_type + set_tmp_attachments_directory end def test_show_other get :show, :id => 6 assert_response :success assert_equal 'application/octet-stream', @response.content_type + set_tmp_attachments_directory end def test_show_file_from_private_issue_without_permission get :show, :id => 15 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15' + set_tmp_attachments_directory end def test_show_file_from_private_issue_with_permission @@ -96,12 +203,20 @@ get :show, :id => 15 assert_response :success assert_tag 'h2', :content => /private.diff/ + set_tmp_attachments_directory end def test_download_text_file get :download, :id => 4 assert_response :success assert_equal 'application/x-ruby', @response.content_type + set_tmp_attachments_directory + end + + def test_download_version_file_with_issue_tracking_disabled + Project.find(1).disable_module! :issue_tracking + get :download, :id => 9 + assert_response :success end def test_download_should_assign_content_type_if_blank @@ -110,24 +225,28 @@ get :download, :id => 4 assert_response :success assert_equal 'text/x-ruby', @response.content_type + set_tmp_attachments_directory end def test_download_missing_file get :download, :id => 2 assert_response 404 + set_tmp_attachments_directory end def test_anonymous_on_private_private get :download, :id => 7 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7' + set_tmp_attachments_directory end def test_destroy_issue_attachment + set_tmp_attachments_directory issue = Issue.find(3) @request.session[:user_id] = 2 assert_difference 'issue.attachments.count', -1 do - post :destroy, :id => 1 + delete :destroy, :id => 1 end # no referrer assert_redirected_to '/projects/ecookbook' @@ -139,32 +258,38 @@ end def test_destroy_wiki_page_attachment + set_tmp_attachments_directory @request.session[:user_id] = 2 assert_difference 'Attachment.count', -1 do - post :destroy, :id => 3 + delete :destroy, :id => 3 assert_response 302 end end def test_destroy_project_attachment + set_tmp_attachments_directory @request.session[:user_id] = 2 assert_difference 'Attachment.count', -1 do - post :destroy, :id => 8 + delete :destroy, :id => 8 assert_response 302 end end def test_destroy_version_attachment + set_tmp_attachments_directory @request.session[:user_id] = 2 assert_difference 'Attachment.count', -1 do - post :destroy, :id => 9 + delete :destroy, :id => 9 assert_response 302 end end def test_destroy_without_permission - post :destroy, :id => 3 - assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdestroy%2F3' + set_tmp_attachments_directory + assert_no_difference 'Attachment.count' do + delete :destroy, :id => 3 + end + assert_response 302 assert Attachment.find_by_id(3) end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/auth_sources_controller_test.rb --- a/test/functional/auth_sources_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/auth_sources_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,6 @@ require File.expand_path('../../test_helper', __FILE__) class AuthSourcesControllerTest < ActionController::TestCase - fixtures :all def setup @request.session[:user_id] = 1 @@ -69,7 +68,7 @@ setup do @auth_source = AuthSource.generate!(:name => 'TestEdit') end - + context "without users" do setup do post :destroy, :id => @auth_source.id @@ -79,13 +78,13 @@ should_redirect_to("index") {{:action => 'index'}} should_set_the_flash_to /deletion/i end - + context "with users" do setup do User.generate!(:auth_source => @auth_source) post :destroy, :id => @auth_source.id end - + should_respond_with :redirect should "not destroy the AuthSource" do assert AuthSource.find(@auth_source.id) diff -r 487d96eac004 -r 5e80956cc792 test/functional/auto_completes_controller_test.rb --- a/test/functional/auto_completes_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/auto_completes_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,17 @@ require File.expand_path('../../test_helper', __FILE__) class AutoCompletesControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, :issues, :issue_statuses, + :enumerations, :users, :issue_categories, + :trackers, + :projects_trackers, + :roles, + :member_roles, + :members, + :auth_sources, + :enabled_modules, + :workflows, + :journals, :journal_details def test_issues_should_not_be_case_sensitive get :issues, :project_id => 'ecookbook', :q => 'ReCiPe' @@ -9,14 +19,14 @@ assert_not_nil assigns(:issues) assert assigns(:issues).detect {|issue| issue.subject.match /recipe/} end - + def test_issues_should_return_issue_with_given_id get :issues, :project_id => 'subproject1', :q => '13' assert_response :success assert_not_nil assigns(:issues) assert assigns(:issues).include?(Issue.find(13)) end - + def test_auto_complete_with_scope_all_and_cross_project_relations Setting.cross_project_issue_relations = '1' get :issues, :project_id => 'ecookbook', :q => '13', :scope => 'all' @@ -24,7 +34,7 @@ assert_not_nil assigns(:issues) assert assigns(:issues).include?(Issue.find(13)) end - + def test_auto_complete_with_scope_all_without_cross_project_relations Setting.cross_project_issue_relations = '0' get :issues, :project_id => 'ecookbook', :q => '13', :scope => 'all' diff -r 487d96eac004 -r 5e80956cc792 test/functional/boards_controller_test.rb --- a/test/functional/boards_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/boards_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,14 +23,14 @@ class BoardsControllerTest < ActionController::TestCase fixtures :projects, :users, :members, :member_roles, :roles, :boards, :messages, :enabled_modules - + def setup @controller = BoardsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_index get :index, :project_id => 1 assert_response :success @@ -38,21 +38,21 @@ assert_not_nil assigns(:boards) assert_not_nil assigns(:project) end - + def test_index_not_found get :index, :project_id => 97 assert_response 404 end - + def test_index_should_show_messages_if_only_one_board Project.find(1).boards.slice(1..-1).each(&:destroy) - + get :index, :project_id => 1 assert_response :success assert_template 'show' assert_not_nil assigns(:topics) end - + def test_post_new @request.session[:user_id] = 2 assert_difference 'Board.count' do @@ -60,7 +60,7 @@ end assert_redirected_to '/projects/ecookbook/settings/boards' end - + def test_show get :show, :project_id => 1, :id => 1 assert_response :success @@ -69,7 +69,7 @@ assert_not_nil assigns(:project) assert_not_nil assigns(:topics) end - + def test_show_atom get :show, :project_id => 1, :id => 1, :format => 'atom' assert_response :success @@ -78,7 +78,7 @@ assert_not_nil assigns(:project) assert_not_nil assigns(:messages) end - + def test_post_edit @request.session[:user_id] = 2 assert_no_difference 'Board.count' do @@ -87,7 +87,7 @@ assert_redirected_to '/projects/ecookbook/settings/boards' assert_equal 'Testing', Board.find(2).name end - + def test_post_destroy @request.session[:user_id] = 2 assert_difference 'Board.count', -1 do diff -r 487d96eac004 -r 5e80956cc792 test/functional/calendars_controller_test.rb --- a/test/functional/calendars_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/calendars_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,14 @@ require File.expand_path('../../test_helper', __FILE__) class CalendarsControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, + :trackers, + :projects_trackers, + :roles, + :member_roles, + :members, + :auth_sources, + :enabled_modules def test_calendar get :show, :project_id => 1 @@ -9,7 +16,7 @@ assert_template 'calendar' assert_not_nil assigns(:calendar) end - + def test_cross_project_calendar get :show assert_response :success @@ -20,19 +27,19 @@ context "GET :show" do should "run custom queries" do @query = Query.generate_default!(:is_public => true) - + get :show, :query_id => @query.id assert_response :success end - + end - + def test_week_number_calculation Setting.start_of_week = 7 - + get :show, :month => '1', :year => '2010' assert_response :success - + assert_tag :tag => 'tr', :descendant => {:tag => 'td', :attributes => {:class => 'week-number'}, :content => '53'}, diff -r 487d96eac004 -r 5e80956cc792 test/functional/comments_controller_test.rb --- a/test/functional/comments_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/comments_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,22 +19,22 @@ class CommentsControllerTest < ActionController::TestCase fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :news, :comments - + def setup User.current = nil end - + def test_add_comment @request.session[:user_id] = 2 post :create, :id => 1, :comment => { :comments => 'This is a test comment' } assert_redirected_to '/news/1' - + comment = News.find(1).comments.find(:first, :order => 'created_on DESC') assert_not_nil comment assert_equal 'This is a test comment', comment.comments assert_equal User.find(2), comment.author end - + def test_empty_comment_should_not_be_added @request.session[:user_id] = 2 assert_no_difference 'Comment.count' do @@ -52,6 +52,4 @@ assert_nil Comment.find_by_id(2) assert_equal comments_count - 1, News.find(1).comments.size end - - end diff -r 487d96eac004 -r 5e80956cc792 test/functional/context_menus_controller_test.rb --- a/test/functional/context_menus_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/context_menus_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,20 @@ require File.expand_path('../../test_helper', __FILE__) class ContextMenusControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, + :trackers, + :projects_trackers, + :roles, + :member_roles, + :members, + :auth_sources, + :enabled_modules, + :workflows, + :journals, :journal_details, + :versions, + :issues, :issue_statuses, :issue_categories, + :users, + :enumerations def test_context_menu_one_issue @request.session[:user_id] = 2 @@ -17,6 +30,7 @@ assert_tag :tag => 'a', :content => 'Immediate', :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bpriority_id%5D=8', :class => '' } + assert_no_tag :tag => 'a', :content => 'Inactive Priority' # Versions assert_tag :tag => 'a', :content => '2.0', :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&issue%5Bfixed_version_id%5D=3', @@ -50,7 +64,7 @@ :attributes => { :href => '#', :class => 'icon-del disabled' } end - + def test_context_menu_multiple_issues_of_same_project @request.session[:user_id] = 2 get :issues, :ids => [1, 2] @@ -58,7 +72,7 @@ assert_template 'context_menu' assert_not_nil assigns(:issues) assert_equal [1, 2], assigns(:issues).map(&:id).sort - + ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&') assert_tag :tag => 'a', :content => 'Edit', :attributes => { :href => "/issues/bulk_edit?#{ids}", @@ -90,7 +104,7 @@ assert_template 'context_menu' assert_not_nil assigns(:issues) assert_equal [1, 2, 6], assigns(:issues).map(&:id).sort - + ids = assigns(:issues).map(&:id).map {|i| "ids%5B%5D=#{i}"}.join('&') assert_tag :tag => 'a', :content => 'Edit', :attributes => { :href => "/issues/bulk_edit?#{ids}", @@ -108,11 +122,30 @@ :attributes => { :href => "/issues/destroy?#{ids}", :class => 'icon-del' } end - + def test_context_menu_issue_visibility get :issues, :ids => [1, 4] assert_response :success assert_template 'context_menu' assert_equal [1], assigns(:issues).collect(&:id) end + + def test_time_entries_context_menu + @request.session[:user_id] = 2 + get :time_entries, :ids => [1, 2] + assert_response :success + assert_template 'time_entries' + assert_tag 'a', :content => 'Edit' + assert_no_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/} + end + + def test_time_entries_context_menu_without_edit_permission + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :edit_time_entries + + get :time_entries, :ids => [1, 2] + assert_response :success + assert_template 'time_entries' + assert_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/} + end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/custom_fields_controller_test.rb --- a/test/functional/custom_fields_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/custom_fields_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -22,15 +22,21 @@ class CustomFieldsController; def rescue_action(e) raise e end; end class CustomFieldsControllerTest < ActionController::TestCase - fixtures :custom_fields, :trackers, :users - + fixtures :custom_fields, :custom_values, :trackers, :users + def setup @controller = CustomFieldsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @request.session[:user_id] = 1 end - + + def test_index + get :index + assert_response :success + assert_template 'index' + end + def test_get_new_issue_custom_field get :new, :type => 'IssueCustomField' assert_response :success @@ -50,12 +56,12 @@ :content => 'Version' } end - + def test_get_new_with_invalid_custom_field_class_should_redirect_to_list get :new, :type => 'UnknownCustomField' assert_redirected_to '/custom_fields' end - + def test_post_new_list_custom_field assert_difference 'CustomField.count' do post :new, :type => "IssueCustomField", @@ -71,11 +77,41 @@ :is_required =>"0", :field_format => "list", :tracker_ids => ["1", ""]} - end + end assert_redirected_to '/custom_fields?tab=IssueCustomField' field = IssueCustomField.find_by_name('test_post_new_list') assert_not_nil field assert_equal ["0.1", "0.2"], field.possible_values assert_equal 1, field.trackers.size end + + def test_get_edit + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + assert_tag 'input', :attributes => {:name => 'custom_field[name]', :value => 'Database'} + end + + def test_post_edit + post :edit, :id => 1, :custom_field => {:name => 'New name'} + assert_redirected_to '/custom_fields?tab=IssueCustomField' + + field = CustomField.find(1) + assert_equal 'New name', field.name + end + + def test_destroy + custom_values_count = CustomValue.count(:conditions => {:custom_field_id => 1}) + assert custom_values_count > 0 + + assert_difference 'CustomField.count', -1 do + assert_difference 'CustomValue.count', - custom_values_count do + post :destroy, :id => 1 + end + end + + assert_redirected_to '/custom_fields?tab=IssueCustomField' + assert_nil CustomField.find_by_id(1) + assert_nil CustomValue.find_by_custom_field_id(1) + end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/documents_controller_test.rb --- a/test/functional/documents_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/documents_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -45,6 +45,10 @@ assert_tag :select, :attributes => {:name => 'document[category_id]'}, :child => {:tag => 'option', :attributes => {:selected => 'selected'}, :content => 'Technical documentation'} + + assert ! DocumentCategory.find(16).active? + assert_no_tag :option, :attributes => {:value => '16'}, + :parent => {:tag => 'select', :attributes => {:id => 'document_category_id'} } end def test_index_with_long_description diff -r 487d96eac004 -r 5e80956cc792 test/functional/enumerations_controller_test.rb --- a/test/functional/enumerations_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/enumerations_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,55 +1,95 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) -require 'enumerations_controller' - -# Re-raise errors caught by the controller. -class EnumerationsController; def rescue_action(e) raise e end; end class EnumerationsControllerTest < ActionController::TestCase fixtures :enumerations, :issues, :users - + def setup - @controller = EnumerationsController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new @request.session[:user_id] = 1 # admin end def test_index get :index assert_response :success - assert_template 'list' + assert_template 'index' end - + + def test_new + get :new, :type => 'IssuePriority' + assert_response :success + assert_template 'new' + assert_kind_of IssuePriority, assigns(:enumeration) + end + + def test_create + assert_difference 'IssuePriority.count' do + post :create, :enumeration => {:type => 'IssuePriority', :name => 'Lowest'} + end + assert_redirected_to '/enumerations?type=IssuePriority' + e = IssuePriority.first(:order => 'id DESC') + assert_equal 'Lowest', e.name + end + + def test_create_with_failure + assert_no_difference 'IssuePriority.count' do + post :create, :enumeration => {:type => 'IssuePriority', :name => ''} + end + assert_response :success + assert_template 'new' + end + + def test_edit + get :edit, :id => 6 + assert_response :success + assert_template 'edit' + end + + def test_update + assert_no_difference 'IssuePriority.count' do + post :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => 'New name'} + end + assert_redirected_to '/enumerations?type=IssuePriority' + e = IssuePriority.find(6) + assert_equal 'New name', e.name + end + + def test_update_with_failure + assert_no_difference 'IssuePriority.count' do + post :update, :id => 6, :enumeration => {:type => 'IssuePriority', :name => ''} + end + assert_response :success + assert_template 'edit' + end + def test_destroy_enumeration_not_in_use post :destroy, :id => 7 assert_redirected_to :controller => 'enumerations', :action => 'index' assert_nil Enumeration.find_by_id(7) end - + def test_destroy_enumeration_in_use post :destroy, :id => 4 assert_response :success assert_template 'destroy' assert_not_nil Enumeration.find_by_id(4) end - + def test_destroy_enumeration_in_use_with_reassignment issue = Issue.find(:first, :conditions => {:priority_id => 4}) post :destroy, :id => 4, :reassign_to_id => 6 diff -r 487d96eac004 -r 5e80956cc792 test/functional/files_controller_test.rb --- a/test/functional/files_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/files_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,8 +1,18 @@ require File.expand_path('../../test_helper', __FILE__) class FilesControllerTest < ActionController::TestCase - fixtures :all - + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :journals, :journal_details, + :attachments, + :versions + def setup @controller = FilesController.new @request = ActionController::TestRequest.new @@ -16,11 +26,11 @@ assert_response :success assert_template 'index' assert_not_nil assigns(:containers) - + # file attached to the project assert_tag :a, :content => 'project_file.zip', :attributes => { :href => '/attachments/download/8/project_file.zip' } - + # file attached to a project's version assert_tag :a, :content => 'version_file.zip', :attributes => { :href => '/attachments/download/9/version_file.zip' } @@ -31,7 +41,7 @@ @request.session[:user_id] = 2 Setting.notified_events = ['file_added'] ActionMailer::Base.deliveries.clear - + assert_difference 'Attachment.count' do post :create, :project_id => 1, :version_id => '', :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} @@ -47,12 +57,12 @@ assert_equal "[eCookbook] New file", mail.subject assert mail.body.include?('testfile.txt') end - + def test_create_version_file set_tmp_attachments_directory @request.session[:user_id] = 2 Setting.notified_events = ['file_added'] - + assert_difference 'Attachment.count' do post :create, :project_id => 1, :version_id => '2', :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} @@ -63,5 +73,5 @@ assert_equal 'testfile.txt', a.filename assert_equal Version.find(2), a.container end - + end diff -r 487d96eac004 -r 5e80956cc792 test/functional/gantts_controller_test.rb --- a/test/functional/gantts_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/gantts_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,24 @@ require File.expand_path('../../test_helper', __FILE__) class GanttsControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions context "#gantt" do should "work" do i2 = Issue.find(2) i2.update_attribute(:due_date, 1.month.from_now) - + get :show, :project_id => 1 assert_response :success - assert_template 'show.html.erb' + assert_template 'gantts/show' assert_not_nil assigns(:gantt) # Issue with start and due dates i = Issue.find(1) @@ -20,30 +28,30 @@ i = Issue.find(2) assert_select "div a.issue", /##{i.id}/ end - + should "work without issue due dates" do Issue.update_all("due_date = NULL") - + get :show, :project_id => 1 assert_response :success - assert_template 'show.html.erb' + assert_template 'gantts/show' assert_not_nil assigns(:gantt) end - + should "work without issue and version due dates" do Issue.update_all("due_date = NULL") Version.update_all("effective_date = NULL") - + get :show, :project_id => 1 assert_response :success - assert_template 'show.html.erb' + assert_template 'gantts/show' assert_not_nil assigns(:gantt) end should "work cross project" do get :show assert_response :success - assert_template 'show.html.erb' + assert_template 'gantts/show' assert_not_nil assigns(:gantt) assert_not_nil assigns(:gantt).query assert_nil assigns(:gantt).project @@ -52,8 +60,8 @@ should "not disclose private projects" do get :show assert_response :success - assert_template 'show.html.erb' - + assert_template 'gantts/show' + assert_tag 'a', :content => /eCookbook/ # Root private project assert_no_tag 'a', {:content => /OnlineStore/} @@ -76,7 +84,7 @@ assert @response.body.starts_with?('%PDF') assert_not_nil assigns(:gantt) end - + should "export to png" do get :show, :project_id => 1, :format => 'png' assert_response :success diff -r 487d96eac004 -r 5e80956cc792 test/functional/groups_controller_test.rb --- a/test/functional/groups_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/groups_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,110 +1,168 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) -require 'groups_controller' - -# Re-raise errors caught by the controller. -class GroupsController; def rescue_action(e) raise e end; end class GroupsControllerTest < ActionController::TestCase fixtures :projects, :users, :members, :member_roles, :groups_users - + def setup - @controller = GroupsController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - User.current = nil @request.session[:user_id] = 1 end - + def test_index get :index assert_response :success assert_template 'index' end - + def test_show get :show, :id => 10 assert_response :success assert_template 'show' end - + def test_new get :new assert_response :success assert_template 'new' end - + def test_create assert_difference 'Group.count' do post :create, :group => {:lastname => 'New group'} end assert_redirected_to '/groups' + group = Group.first(:order => 'id DESC') + assert_equal 'New group', group.name + assert_equal [], group.users end - + + def test_create_and_continue + assert_difference 'Group.count' do + post :create, :group => {:lastname => 'New group'}, :continue => 'Create and continue' + end + assert_redirected_to '/groups/new' + group = Group.first(:order => 'id DESC') + assert_equal 'New group', group.name + end + + def test_create_with_failure + assert_no_difference 'Group.count' do + post :create, :group => {:lastname => ''} + end + assert_response :success + assert_template 'new' + end + def test_edit get :edit, :id => 10 assert_response :success assert_template 'edit' + assert_tag 'div', :attributes => {:id => 'tab-content-users'} + assert_tag 'div', :attributes => {:id => 'tab-content-memberships'} end - + def test_update - post :update, :id => 10 + new_name = 'New name' + put :update, :id => 10, :group => {:lastname => new_name} assert_redirected_to '/groups' + group = Group.find(10) + assert_equal new_name, group.name end - + + def test_update_with_failure + put :update, :id => 10, :group => {:lastname => ''} + assert_response :success + assert_template 'edit' + end + def test_destroy assert_difference 'Group.count', -1 do post :destroy, :id => 10 end assert_redirected_to '/groups' end - + def test_add_users assert_difference 'Group.find(10).users.count', 2 do post :add_users, :id => 10, :user_ids => ['2', '3'] end end - + + def test_xhr_add_users + assert_difference 'Group.find(10).users.count', 2 do + xhr :post, :add_users, :id => 10, :user_ids => ['2', '3'] + end + assert_select_rjs :replace_html, 'tab-content-users' + end + def test_remove_user assert_difference 'Group.find(10).users.count', -1 do - post :remove_user, :id => 10, :user_id => '8' + delete :remove_user, :id => 10, :user_id => '8' end end - + + def test_xhr_remove_user + assert_difference 'Group.find(10).users.count', -1 do + xhr :delete, :remove_user, :id => 10, :user_id => '8' + end + assert_select_rjs :replace_html, 'tab-content-users' + end + def test_new_membership assert_difference 'Group.find(10).members.count' do post :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']} end end - + + def test_xhr_new_membership + assert_difference 'Group.find(10).members.count' do + xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']} + end + assert_select_rjs :replace_html, 'tab-content-memberships' + end + + def test_xhr_new_membership_with_failure + assert_no_difference 'Group.find(10).members.count' do + xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 999, :role_ids => ['1', '2']} + end + assert @response.body.match(/alert/i), "Alert message not sent" + end + def test_edit_membership assert_no_difference 'Group.find(10).members.count' do post :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']} end end - + def test_destroy_membership assert_difference 'Group.find(10).members.count', -1 do post :destroy_membership, :id => 10, :membership_id => 6 end end - + + def test_xhr_destroy_membership + assert_difference 'Group.find(10).members.count', -1 do + xhr :post, :destroy_membership, :id => 10, :membership_id => 6 + end + assert_select_rjs :replace_html, 'tab-content-memberships' + end + def test_autocomplete_for_user get :autocomplete_for_user, :id => 10, :q => 'mis' assert_response :success diff -r 487d96eac004 -r 5e80956cc792 test/functional/issue_categories_controller_test.rb --- a/test/functional/issue_categories_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/issue_categories_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ class IssueCategoriesControllerTest < ActionController::TestCase fixtures :projects, :users, :members, :member_roles, :roles, :enabled_modules, :issue_categories - + def setup @controller = IssueCategoriesController.new @request = ActionController::TestRequest.new @@ -31,63 +31,83 @@ User.current = nil @request.session[:user_id] = 2 end - - def test_get_new + + def test_new @request.session[:user_id] = 2 # manager get :new, :project_id => '1' assert_response :success assert_template 'new' end - - def test_post_new + + def test_create @request.session[:user_id] = 2 # manager assert_difference 'IssueCategory.count' do - post :new, :project_id => '1', :category => {:name => 'New category'} + post :create, :project_id => '1', :issue_category => {:name => 'New category'} end assert_redirected_to '/projects/ecookbook/settings/categories' category = IssueCategory.find_by_name('New category') assert_not_nil category assert_equal 1, category.project_id end - - def test_post_edit + + def test_create_failure + @request.session[:user_id] = 2 + post :create, :project_id => '1', :issue_category => {:name => ''} + assert_response :success + assert_template 'new' + end + + def test_edit + @request.session[:user_id] = 2 + get :edit, :id => 2 + assert_response :success + assert_template 'edit' + end + + def test_update assert_no_difference 'IssueCategory.count' do - post :edit, :id => 2, :category => { :name => 'Testing' } + put :update, :id => 2, :issue_category => { :name => 'Testing' } end assert_redirected_to '/projects/ecookbook/settings/categories' assert_equal 'Testing', IssueCategory.find(2).name end - - def test_edit_not_found - post :edit, :id => 97, :category => { :name => 'Testing' } + + def test_update_failure + put :update, :id => 2, :issue_category => { :name => '' } + assert_response :success + assert_template 'edit' + end + + def test_update_not_found + put :update, :id => 97, :issue_category => { :name => 'Testing' } assert_response 404 end - + def test_destroy_category_not_in_use - post :destroy, :id => 2 + delete :destroy, :id => 2 assert_redirected_to '/projects/ecookbook/settings/categories' assert_nil IssueCategory.find_by_id(2) end - + def test_destroy_category_in_use - post :destroy, :id => 1 + delete :destroy, :id => 1 assert_response :success assert_template 'destroy' assert_not_nil IssueCategory.find_by_id(1) end - + def test_destroy_category_in_use_with_reassignment issue = Issue.find(:first, :conditions => {:category_id => 1}) - post :destroy, :id => 1, :todo => 'reassign', :reassign_to_id => 2 + delete :destroy, :id => 1, :todo => 'reassign', :reassign_to_id => 2 assert_redirected_to '/projects/ecookbook/settings/categories' assert_nil IssueCategory.find_by_id(1) # check that the issue was reassign assert_equal 2, issue.reload.category_id end - + def test_destroy_category_in_use_without_reassignment issue = Issue.find(:first, :conditions => {:category_id => 1}) - post :destroy, :id => 1, :todo => 'nullify' + delete :destroy, :id => 1, :todo => 'nullify' assert_redirected_to '/projects/ecookbook/settings/categories' assert_nil IssueCategory.find_by_id(1) # check that the issue category was nullified diff -r 487d96eac004 -r 5e80956cc792 test/functional/issue_moves_controller_test.rb --- a/test/functional/issue_moves_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/issue_moves_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,12 +1,39 @@ require File.expand_path('../../test_helper', __FILE__) class IssueMovesControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :journals, :journal_details def setup User.current = nil end + def test_get_issue_moves_new + @request.session[:user_id] = 2 + get :new, :id => 1 + + assert_tag :tag => 'option', :content => 'eCookbook', + :attributes => { :value => '1', :selected => 'selected' } + %w(new_tracker_id status_id priority_id assigned_to_id).each do |field| + assert_tag :tag => 'option', :content => '(No change)', :attributes => { :value => '' }, + :parent => {:tag => 'select', :attributes => {:id => field}} + assert_no_tag :tag => 'option', :attributes => {:selected => 'selected'}, + :parent => {:tag => 'select', :attributes => {:id => field}} + end + + # Be sure we don't include inactive enumerations + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'priority_id'} } + end + def test_create_one_issue_to_another_project @request.session[:user_id] = 2 post :create, :id => 1, :new_project_id => 2, :tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' @@ -31,7 +58,7 @@ assert_equal 1, Issue.find(1).tracker_id assert_equal 2, Issue.find(2).tracker_id end - + def test_bulk_create_to_another_tracker @request.session[:user_id] = 2 post :create, :ids => [1, 2], :new_tracker_id => 2 @@ -44,7 +71,7 @@ setup do @request.session[:user_id] = 2 end - + should "allow changing the issue priority" do post :create, :ids => [1, 2], :priority_id => 6 @@ -62,7 +89,7 @@ assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes end - + end def test_bulk_copy_to_another_project @@ -81,7 +108,10 @@ issue_before_move = Issue.find(1) assert_difference 'Issue.count', 1 do assert_no_difference 'Project.find(1).issues.count' do - post :create, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' + post :create, :ids => [1], :new_project_id => 2, + :copy_options => {:copy => '1'}, :new_tracker_id => '', + :assigned_to_id => '', :status_id => '', + :start_date => '', :due_date => '' end end issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) @@ -89,16 +119,20 @@ assert_equal issue_before_move.status_id, issue_after_move.status_id assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id end - + should "allow changing the issue's attributes" do # Fixes random test failure with Mysql - # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) doesn't return the expected results + # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) + # doesn't return the expected results Issue.delete_all("project_id=2") - + @request.session[:user_id] = 2 assert_difference 'Issue.count', 2 do assert_no_difference 'Project.find(1).issues.count' do - post :create, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31' + post :create, :ids => [1, 2], :new_project_id => 2, + :copy_options => {:copy => '1'}, :new_tracker_id => '', + :assigned_to_id => 4, :status_id => 3, + :start_date => '2009-12-01', :due_date => '2009-12-31' end end @@ -116,9 +150,12 @@ should "allow adding a note when copying" do @request.session[:user_id] = 2 assert_difference 'Issue.count', 1 do - post :create, :ids => [1], :copy_options => {:copy => '1'}, :notes => 'Copying one issue', :new_tracker_id => '', :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31' + post :create, :ids => [1], :copy_options => {:copy => '1'}, + :notes => 'Copying one issue', :new_tracker_id => '', + :assigned_to_id => 4, :status_id => 3, + :start_date => '2009-12-01', :due_date => '2009-12-31' end - + issue = Issue.first(:order => 'id DESC') assert_equal 1, issue.journals.size journal = issue.journals.first @@ -126,7 +163,7 @@ assert_equal 'Copying one issue', journal.notes end end - + def test_copy_to_another_project_should_follow_when_needed @request.session[:user_id] = 2 post :create, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' diff -r 487d96eac004 -r 5e80956cc792 test/functional/issue_relations_controller_test.rb --- a/test/functional/issue_relations_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/issue_relations_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,3 +1,20 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) require 'issue_relations_controller' @@ -17,27 +34,27 @@ :enabled_modules, :enumerations, :trackers - + def setup @controller = IssueRelationsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - - def test_new + + def test_create assert_difference 'IssueRelation.count' do @request.session[:user_id] = 3 - post :new, :issue_id => 1, + post :create, :issue_id => 1, :relation => {:issue_to_id => '2', :relation_type => 'relates', :delay => ''} end end - - def test_new_xhr + + def test_create_xhr assert_difference 'IssueRelation.count' do @request.session[:user_id] = 3 - xhr :post, :new, - :issue_id => 3, + xhr :post, :create, + :issue_id => 3, :relation => {:issue_to_id => '1', :relation_type => 'relates', :delay => ''} assert_select_rjs 'relations' do assert_select 'table', 1 @@ -45,58 +62,55 @@ end end end - - def test_new_should_accept_id_with_hash + + def test_create_should_accept_id_with_hash assert_difference 'IssueRelation.count' do @request.session[:user_id] = 3 - post :new, :issue_id => 1, + post :create, :issue_id => 1, :relation => {:issue_to_id => '#2', :relation_type => 'relates', :delay => ''} end end - - def test_new_should_not_break_with_non_numerical_id + + def test_create_should_not_break_with_non_numerical_id assert_no_difference 'IssueRelation.count' do assert_nothing_raised do @request.session[:user_id] = 3 - post :new, :issue_id => 1, + post :create, :issue_id => 1, :relation => {:issue_to_id => 'foo', :relation_type => 'relates', :delay => ''} end end end - + def test_should_create_relations_with_visible_issues_only Setting.cross_project_issue_relations = '1' assert_nil Issue.visible(User.find(3)).find_by_id(4) - + assert_no_difference 'IssueRelation.count' do @request.session[:user_id] = 3 - post :new, :issue_id => 1, + post :create, :issue_id => 1, :relation => {:issue_to_id => '4', :relation_type => 'relates', :delay => ''} end end should "prevent relation creation when there's a circular dependency" - + def test_destroy assert_difference 'IssueRelation.count', -1 do @request.session[:user_id] = 3 - post :destroy, :id => '2', :issue_id => '3' + delete :destroy, :id => '2' end end - + def test_destroy_xhr IssueRelation.create!(:relation_type => IssueRelation::TYPE_RELATES) do |r| r.issue_from_id = 3 r.issue_to_id = 1 end - + assert_difference 'IssueRelation.count', -1 do @request.session[:user_id] = 3 - xhr :post, :destroy, :id => '2', :issue_id => '3' - assert_select_rjs 'relations' do - assert_select 'table', 1 - assert_select 'tr', 1 # relation left - end + xhr :delete, :destroy, :id => '2' + assert_select_rjs :remove, 'relation-2' end end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/issue_statuses_controller_test.rb --- a/test/functional/issue_statuses_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/issue_statuses_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -7,7 +7,7 @@ class IssueStatusesControllerTest < ActionController::TestCase fixtures :issue_statuses, :issues - + def setup @controller = IssueStatusesController.new @request = ActionController::TestRequest.new @@ -15,19 +15,31 @@ User.current = nil @request.session[:user_id] = 1 # admin end - + def test_index get :index assert_response :success assert_template 'index' end + def test_index_by_anonymous_should_redirect_to_login_form + @request.session[:user_id] = nil + get :index + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fissue_statuses' + end + + def test_index_by_user_should_respond_with_406 + @request.session[:user_id] = 2 + get :index + assert_response 406 + end + def test_new get :new assert_response :success assert_template 'new' end - + def test_create assert_difference 'IssueStatus.count' do post :create, :issue_status => {:name => 'New status'} @@ -36,35 +48,35 @@ status = IssueStatus.find(:first, :order => 'id DESC') assert_equal 'New status', status.name end - + def test_edit get :edit, :id => '3' assert_response :success assert_template 'edit' end - + def test_update - post :update, :id => '3', :issue_status => {:name => 'Renamed status'} + put :update, :id => '3', :issue_status => {:name => 'Renamed status'} assert_redirected_to :action => 'index' status = IssueStatus.find(3) assert_equal 'Renamed status', status.name end - + def test_destroy Issue.delete_all("status_id = 1") - + assert_difference 'IssueStatus.count', -1 do - post :destroy, :id => '1' + delete :destroy, :id => '1' end assert_redirected_to :action => 'index' assert_nil IssueStatus.find_by_id(1) end - + def test_destroy_should_block_if_status_in_use assert_not_nil Issue.find_by_status_id(1) - + assert_no_difference 'IssueStatus.count' do - post :destroy, :id => '1' + delete :destroy, :id => '1' end assert_redirected_to :action => 'index' assert_not_nil IssueStatus.find_by_id(1) @@ -91,5 +103,5 @@ should_redirect_to('the index') { '/issue_statuses' } end end - + end diff -r 487d96eac004 -r 5e80956cc792 test/functional/issues_controller_test.rb --- a/test/functional/issues_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/issues_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -43,6 +43,8 @@ :journal_details, :queries + include Redmine::I18n + def setup @controller = IssuesController.new @request = ActionController::TestRequest.new @@ -55,7 +57,7 @@ get :index assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_nil assigns(:project) assert_tag :tag => 'a', :content => /Can't print recipes/ @@ -71,18 +73,7 @@ EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") get :index assert_response :success - assert_template 'index.rhtml' - assert_not_nil assigns(:issues) - assert_nil assigns(:project) - assert_no_tag :tag => 'a', :content => /Can't print recipes/ - assert_tag :tag => 'a', :content => /Subproject issue/ - end - - def test_index_should_not_list_issues_when_module_disabled - EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") - get :index - assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_nil assigns(:project) assert_no_tag :tag => 'a', :content => /Can't print recipes/ @@ -100,7 +91,7 @@ Setting.display_subprojects_issues = 0 get :index, :project_id => 1 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_tag :tag => 'a', :content => /Can't print recipes/ assert_no_tag :tag => 'a', :content => /Subproject issue/ @@ -110,7 +101,7 @@ Setting.display_subprojects_issues = 1 get :index, :project_id => 1 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_tag :tag => 'a', :content => /Can't print recipes/ assert_tag :tag => 'a', :content => /Subproject issue/ @@ -122,7 +113,7 @@ Setting.display_subprojects_issues = 1 get :index, :project_id => 1 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_tag :tag => 'a', :content => /Can't print recipes/ assert_tag :tag => 'a', :content => /Subproject issue/ @@ -132,7 +123,7 @@ def test_index_with_project_and_default_filter get :index, :project_id => 1, :set_filter => 1 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) query = assigns(:query) @@ -147,7 +138,7 @@ :op => {'tracker_id' => '='}, :v => {'tracker_id' => ['1']} assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) query = assigns(:query) @@ -155,10 +146,82 @@ assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters) end + def test_index_with_short_filters + + to_test = { + 'status_id' => { + 'o' => { :op => 'o', :values => [''] }, + 'c' => { :op => 'c', :values => [''] }, + '7' => { :op => '=', :values => ['7'] }, + '7|3|4' => { :op => '=', :values => ['7', '3', '4'] }, + '=7' => { :op => '=', :values => ['7'] }, + '!3' => { :op => '!', :values => ['3'] }, + '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }}, + 'subject' => { + 'This is a subject' => { :op => '=', :values => ['This is a subject'] }, + 'o' => { :op => '=', :values => ['o'] }, + '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] }, + '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }}, + 'tracker_id' => { + '3' => { :op => '=', :values => ['3'] }, + '=3' => { :op => '=', :values => ['3'] }}, + 'start_date' => { + '2011-10-12' => { :op => '=', :values => ['2011-10-12'] }, + '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] }, + '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] }, + '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] }, + '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] }, + ' { :op => ' ['2'] }, + '>t+2' => { :op => '>t+', :values => ['2'] }, + 't+2' => { :op => 't+', :values => ['2'] }, + 't' => { :op => 't', :values => [''] }, + 'w' => { :op => 'w', :values => [''] }, + '>t-2' => { :op => '>t-', :values => ['2'] }, + ' { :op => ' ['2'] }, + 't-2' => { :op => 't-', :values => ['2'] }}, + 'created_on' => { + '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] }, + ' { :op => '=', :values => ['t+2' => { :op => '=', :values => ['>t+2'] }, + 't+2' => { :op => 't', :values => ['+2'] }}, + 'cf_1' => { + 'c' => { :op => '=', :values => ['c'] }, + '!c' => { :op => '!', :values => ['c'] }, + '!*' => { :op => '!*', :values => [''] }, + '*' => { :op => '*', :values => [''] }}, + 'estimated_hours' => { + '=13.4' => { :op => '=', :values => ['13.4'] }, + '>=45' => { :op => '>=', :values => ['45'] }, + '<=125' => { :op => '<=', :values => ['125'] }, + '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] }, + '!*' => { :op => '!*', :values => [''] }, + '*' => { :op => '*', :values => [''] }} + } + + default_filter = { 'status_id' => {:operator => 'o', :values => [''] }} + + to_test.each do |field, expression_and_expected| + expression_and_expected.each do |filter_expression, expected| + + get :index, :set_filter => 1, field => filter_expression + + assert_response :success + assert_template 'index' + assert_not_nil assigns(:issues) + + query = assigns(:query) + assert_not_nil query + assert query.has_filter?(field) + assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters) + end + end + + end + def test_index_with_project_and_empty_filters get :index, :project_id => 1, :set_filter => 1, :fields => [''] assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) query = assigns(:query) @@ -170,7 +233,7 @@ def test_index_with_query get :index, :project_id => 1, :query_id => 5 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_nil assigns(:issue_count_by_group) end @@ -178,7 +241,7 @@ def test_index_with_query_grouped_by_tracker get :index, :project_id => 1, :query_id => 6 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_not_nil assigns(:issue_count_by_group) end @@ -186,70 +249,250 @@ def test_index_with_query_grouped_by_list_custom_field get :index, :project_id => 1, :query_id => 9 assert_response :success - assert_template 'index.rhtml' + assert_template 'index' assert_not_nil assigns(:issues) assert_not_nil assigns(:issue_count_by_group) end - + + def test_index_with_query_id_and_project_id_should_set_session_query + get :index, :project_id => 1, :query_id => 4 + assert_response :success + assert_kind_of Hash, session[:query] + assert_equal 4, session[:query][:id] + assert_equal 1, session[:query][:project_id] + end + + def test_index_with_cross_project_query_in_session_should_show_project_issues + q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil) + @request.session[:query] = {:id => q.id, :project_id => 1} + + with_settings :display_subprojects_issues => '0' do + get :index, :project_id => 1 + end + assert_response :success + assert_not_nil assigns(:query) + assert_equal q.id, assigns(:query).id + assert_equal 1, assigns(:query).project_id + assert_equal [1], assigns(:issues).map(&:project_id).uniq + end + def test_private_query_should_not_be_available_to_other_users q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil) @request.session[:user_id] = 3 - + get :index, :query_id => q.id assert_response 403 end - + def test_private_query_should_be_available_to_its_user q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil) @request.session[:user_id] = 2 - - get :index, :query_id => q.id - assert_response :success - end - - def test_public_query_should_be_available_to_other_users - q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil) - @request.session[:user_id] = 3 - + get :index, :query_id => q.id assert_response :success end - def test_index_sort_by_field_not_included_in_columns - Setting.issue_list_default_columns = %w(subject author) - get :index, :sort => 'tracker' + def test_public_query_should_be_available_to_other_users + q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil) + @request.session[:user_id] = 3 + + get :index, :query_id => q.id + assert_response :success end - def test_index_csv_with_project - Setting.default_language = 'en' - + def test_index_csv get :index, :format => 'csv' assert_response :success assert_not_nil assigns(:issues) assert_equal 'text/csv', @response.content_type assert @response.body.starts_with?("#,") + lines = @response.body.chomp.split("\n") + assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size + end + def test_index_csv_with_project get :index, :project_id => 1, :format => 'csv' assert_response :success assert_not_nil assigns(:issues) assert_equal 'text/csv', @response.content_type end - def test_index_pdf - get :index, :format => 'pdf' + def test_index_csv_with_description + get :index, :format => 'csv', :description => '1' assert_response :success assert_not_nil assigns(:issues) - assert_equal 'application/pdf', @response.content_type + assert_equal 'text/csv', @response.content_type + assert @response.body.starts_with?("#,") + lines = @response.body.chomp.split("\n") + assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size + end - get :index, :project_id => 1, :format => 'pdf' + def test_index_csv_with_all_columns + get :index, :format => 'csv', :columns => 'all' assert_response :success assert_not_nil assigns(:issues) - assert_equal 'application/pdf', @response.content_type + assert_equal 'text/csv', @response.content_type + assert @response.body.starts_with?("#,") + lines = @response.body.chomp.split("\n") + assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size + end - get :index, :project_id => 1, :query_id => 6, :format => 'pdf' - assert_response :success - assert_not_nil assigns(:issues) - assert_equal 'application/pdf', @response.content_type + def test_index_csv_big_5 + with_settings :default_language => "zh-TW" do + str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88" + str_big5 = "\xa4@\xa4\xeb" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + str_big5.force_encoding('Big5') + end + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str_utf8) + assert issue.save + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str_utf8], + :format => 'csv' + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + s1 = "\xaa\xac\xbaA" + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert lines[0].include?(s1) + assert lines[1].include?(str_big5) + end + end + + def test_index_csv_cannot_convert_should_be_replaced_big_5 + with_settings :default_language => "zh-TW" do + str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + end + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str_utf8) + assert issue.save + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str_utf8], + :c => ['status', 'subject'], + :format => 'csv', + :set_filter => 1 + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + s1 = "\xaa\xac\xbaA" # status + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert lines[0].include?(s1) + s2 = lines[1].split(",")[2] + if s1.respond_to?(:force_encoding) + s3 = "\xa5H?" # subject + s3.force_encoding('Big5') + assert_equal s3, s2 + elsif RUBY_PLATFORM == 'java' + assert_equal "??", s2 + else + assert_equal "\xa5H???", s2 + end + end + end + + def test_index_csv_tw + with_settings :default_language => "zh-TW" do + str1 = "test_index_csv_tw" + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str1, :estimated_hours => '1234.5') + assert issue.save + assert_equal 1234.5, issue.estimated_hours + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str1], + :c => ['estimated_hours', 'subject'], + :format => 'csv', + :set_filter => 1 + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + assert_equal "#{issue.id},1234.5,#{str1}", lines[1] + + str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)" + if str_tw.respond_to?(:force_encoding) + str_tw.force_encoding('UTF-8') + end + assert_equal str_tw, l(:general_lang_name) + assert_equal ',', l(:general_csv_separator) + assert_equal '.', l(:general_csv_decimal_separator) + end + end + + def test_index_csv_fr + with_settings :default_language => "fr" do + str1 = "test_index_csv_fr" + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => str1, :estimated_hours => '1234.5') + assert issue.save + assert_equal 1234.5, issue.estimated_hours + + get :index, :project_id => 1, + :f => ['subject'], + :op => '=', :values => [str1], + :c => ['estimated_hours', 'subject'], + :format => 'csv', + :set_filter => 1 + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + assert_equal "#{issue.id};1234,5;#{str1}", lines[1] + + str_fr = "Fran\xc3\xa7ais" + if str_fr.respond_to?(:force_encoding) + str_fr.force_encoding('UTF-8') + end + assert_equal str_fr, l(:general_lang_name) + assert_equal ';', l(:general_csv_separator) + assert_equal ',', l(:general_csv_decimal_separator) + end + end + + def test_index_pdf + ["en", "zh", "zh-TW", "ja", "ko"].each do |lang| + with_settings :default_language => lang do + + get :index + assert_response :success + assert_template 'index' + + if lang == "ja" + if RUBY_PLATFORM != 'java' + assert_equal "CP932", l(:general_pdf_encoding) + end + if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932" + next + end + end + + get :index, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'application/pdf', @response.content_type + + get :index, :project_id => 1, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'application/pdf', @response.content_type + + get :index, :project_id => 1, :query_id => 6, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:issues) + assert_equal 'application/pdf', @response.content_type + end + end end def test_index_pdf_with_query_grouped_by_list_custom_field @@ -274,6 +517,49 @@ assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id) end + def test_index_sort_by_field_not_included_in_columns + Setting.issue_list_default_columns = %w(subject author) + get :index, :sort => 'tracker' + end + + def test_index_sort_by_assigned_to + get :index, :sort => 'assigned_to' + assert_response :success + assignees = assigns(:issues).collect(&:assigned_to).compact + assert_equal assignees.sort, assignees + end + + def test_index_sort_by_assigned_to_desc + get :index, :sort => 'assigned_to:desc' + assert_response :success + assignees = assigns(:issues).collect(&:assigned_to).compact + assert_equal assignees.sort.reverse, assignees + end + + def test_index_group_by_assigned_to + get :index, :group_by => 'assigned_to', :sort => 'priority' + assert_response :success + end + + def test_index_sort_by_author + get :index, :sort => 'author' + assert_response :success + authors = assigns(:issues).collect(&:author) + assert_equal authors.sort, authors + end + + def test_index_sort_by_author_desc + get :index, :sort => 'author:desc' + assert_response :success + authors = assigns(:issues).collect(&:author) + assert_equal authors.sort.reverse, authors + end + + def test_index_group_by_author + get :index, :group_by => 'author', :sort => 'priority' + assert_response :success + end + def test_index_with_columns columns = ['tracker', 'subject', 'assigned_to'] get :index, :set_filter => 1, :c => columns @@ -296,6 +582,27 @@ :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } } end + def test_index_without_project_should_implicitly_add_project_column_to_default_columns + Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to'] + get :index, :set_filter => 1 + + # query should use specified columns + query = assigns(:query) + assert_kind_of Query, query + assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name) + end + + def test_index_without_project_and_explicit_default_columns_should_not_add_project_column + Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to'] + columns = ['tracker', 'subject', 'assigned_to'] + get :index, :set_filter => 1, :c => columns + + # query should use specified columns + query = assigns(:query) + assert_kind_of Query, query + assert_equal columns.map(&:to_sym), query.columns.map(&:name) + end + def test_index_with_custom_field_column columns = %w(tracker subject cf_2) get :index, :set_filter => 1, :c => columns @@ -311,10 +618,47 @@ :ancestor => {:tag => 'table', :attributes => {:class => /issues/}} end + def test_index_with_date_column + Issue.find(1).update_attribute :start_date, '1987-08-24' + + with_settings :date_format => '%d/%m/%Y' do + get :index, :set_filter => 1, :c => %w(start_date) + assert_tag 'td', :attributes => {:class => /start_date/}, :content => '24/08/1987' + end + end + + def test_index_with_done_ratio + Issue.find(1).update_attribute :done_ratio, 40 + + get :index, :set_filter => 1, :c => %w(done_ratio) + assert_tag 'td', :attributes => {:class => /done_ratio/}, + :child => {:tag => 'table', :attributes => {:class => 'progress'}, + :descendant => {:tag => 'td', :attributes => {:class => 'closed', :style => 'width: 40%;'}} + } + end + + def test_index_with_fixed_version + get :index, :set_filter => 1, :c => %w(fixed_version) + assert_tag 'td', :attributes => {:class => /fixed_version/}, + :child => {:tag => 'a', :content => '1.0', :attributes => {:href => '/versions/2'}} + end + + def test_index_send_html_if_query_is_invalid + get :index, :f => ['start_date'], :op => {:start_date => '='} + assert_equal 'text/html', @response.content_type + assert_template 'index' + end + + def test_index_send_nothing_if_query_is_invalid + get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv' + assert_equal 'text/csv', @response.content_type + assert @response.body.blank? + end + def test_show_by_anonymous get :show, :id => 1 assert_response :success - assert_template 'show.rhtml' + assert_template 'show' assert_not_nil assigns(:issue) assert_equal Issue.find(1), assigns(:issue) @@ -323,6 +667,8 @@ :descendant => { :tag => 'fieldset', :child => { :tag => 'legend', :content => /Notes/ } } + assert_tag :tag => 'title', + :content => "Bug #1: Can't print recipes - eCookbook - Redmine" end def test_show_by_manager @@ -345,6 +691,28 @@ :content => /Notes/ } } end + def test_update_form_should_not_display_inactive_enumerations + @request.session[:user_id] = 2 + get :show, :id => 1 + assert_response :success + + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_update_form_should_allow_attachment_upload + @request.session[:user_id] = 2 + get :show, :id => 1 + + assert_tag :tag => 'form', + :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'}, + :descendant => { + :tag => 'input', + :attributes => {:type => 'file', :name => 'attachments[1][file]'} + } + end + def test_show_should_deny_anonymous_access_without_permission Role.anonymous.remove_permission!(:view_issues) get :show, :id => 1 @@ -425,7 +793,7 @@ def test_show_atom get :show, :id => 2, :format => 'atom' assert_response :success - assert_template 'journals/index.rxml' + assert_template 'journals/index' # Inline image assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10')) end @@ -446,6 +814,47 @@ assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Default string' } + + # Be sure we don't display inactive IssuePriorities + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_get_new_without_default_start_date_is_creation_date + Setting.default_issue_start_date_to_creation_date = 0 + + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + assert_response :success + assert_template 'new' + + assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]', + :value => nil } + end + + def test_get_new_with_default_start_date_is_creation_date + Setting.default_issue_start_date_to_creation_date = 1 + + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + assert_response :success + assert_template 'new' + + assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]', + :value => Date.today.to_s } + end + + def test_get_new_form_should_allow_attachment_upload + @request.session[:user_id] = 2 + get :new, :project_id => 1, :tracker_id => 1 + + assert_tag :tag => 'form', + :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'}, + :descendant => { + :tag => 'input', + :attributes => {:type => 'file', :name => 'attachments[1][file]'} + } end def test_get_new_without_tracker_id @@ -521,7 +930,31 @@ assert_equal 'Value for field 2', v.value end - def test_post_create_without_start_date + def test_post_new_with_group_assignment + group = Group.find(11) + project = Project.find(1) + project.members << Member.new(:principal => group, :roles => [Role.first]) + + with_settings :issue_group_assignment => '1' do + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => project.id, + :issue => {:tracker_id => 3, + :status_id => 1, + :subject => 'This is the test_new_with_group_assignment issue', + :assigned_to_id => group.id} + end + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue') + assert_not_nil issue + assert_equal group, issue.assigned_to + end + + def test_post_create_without_start_date_and_default_start_date_is_not_creation_date + Setting.default_issue_start_date_to_creation_date = 0 + @request.session[:user_id] = 2 assert_difference 'Issue.count' do post :create, :project_id => 1, @@ -530,7 +963,6 @@ :subject => 'This is the test_new issue', :description => 'This is the description', :priority_id => 5, - :start_date => '', :estimated_hours => '', :custom_field_values => {'2' => 'Value for field 2'}} end @@ -541,15 +973,39 @@ assert_nil issue.start_date end + def test_post_create_without_start_date_and_default_start_date_is_creation_date + Setting.default_issue_start_date_to_creation_date = 1 + + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, + :status_id => 2, + :subject => 'This is the test_new issue', + :description => 'This is the description', + :priority_id => 5, + :estimated_hours => '', + :custom_field_values => {'2' => 'Value for field 2'}} + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new issue') + assert_not_nil issue + assert_equal Date.today, issue.start_date + end + def test_post_create_and_continue @request.session[:user_id] = 2 - post :create, :project_id => 1, - :issue => {:tracker_id => 3, - :subject => 'This is first issue', - :priority_id => 5}, - :continue => '' - assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', - :issue => {:tracker_id => 3} + assert_difference 'Issue.count' do + post :create, :project_id => 1, + :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5}, + :continue => '' + end + + issue = Issue.first(:order => 'id DESC') + assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3} + assert_not_nil flash[:notice], "flash was not set" + assert flash[:notice].include?("##{issue.id}"), "issue link not found in flash: #{flash[:notice]}" end def test_post_create_without_custom_fields_param @@ -633,7 +1089,7 @@ assert_not_nil issue assert_nil issue.parent end - + def test_post_create_private @request.session[:user_id] = 2 @@ -646,12 +1102,12 @@ issue = Issue.first(:order => 'id DESC') assert issue.is_private? end - + def test_post_create_private_with_set_own_issues_private_permission role = Role.find(1) role.remove_permission! :set_issues_private role.add_permission! :set_own_issues_private - + @request.session[:user_id] = 2 assert_difference 'Issue.count' do @@ -715,6 +1171,31 @@ end end + def test_post_create_with_attachment + set_tmp_attachments_directory + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + assert_difference 'Attachment.count' do + post :create, :project_id => 1, + :issue => { :tracker_id => '1', :subject => 'With attachment' }, + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}} + end + end + + issue = Issue.first(:order => 'id DESC') + attachment = Attachment.first(:order => 'id DESC') + + assert_equal issue, attachment.container + assert_equal 2, attachment.author_id + assert_equal 'testfile.txt', attachment.filename + assert_equal 'text/plain', attachment.content_type + assert_equal 'test file', attachment.description + assert_equal 59, attachment.filesize + assert File.exists?(attachment.diskfile) + assert_equal 59, File.size(attachment.diskfile) + end + context "without workflow privilege" do setup do Workflow.delete_all(["role_id = ?", Role.anonymous.id]) @@ -860,6 +1341,27 @@ assert_template 'edit' assert_not_nil assigns(:issue) assert_equal Issue.find(1), assigns(:issue) + + # Be sure we don't display inactive IssuePriorities + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } + end + + def test_get_edit_should_display_the_time_entry_form_with_log_time_permission + @request.session[:user_id] = 2 + Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time] + + get :edit, :id => 1 + assert_tag 'input', :attributes => {:name => 'time_entry[hours]'} + end + + def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :log_time + + get :edit, :id => 1 + assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'} end def test_get_edit_with_params @@ -1047,10 +1549,12 @@ Journal.delete_all # anonymous user - put :update, - :id => 1, - :notes => '', - :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}} + assert_difference 'Attachment.count' do + put :update, :id => 1, + :notes => '', + :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}} + end + assert_redirected_to :action => 'show', :id => '1' j = Issue.find(1).journals.find(:first, :order => 'id DESC') assert j.notes.blank? @@ -1058,6 +1562,16 @@ assert_equal 'testfile.txt', j.details.first.value assert_equal User.anonymous, j.user + attachment = Attachment.first(:order => 'id DESC') + assert_equal Issue.find(1), attachment.container + assert_equal User.anonymous, attachment.author + assert_equal 'testfile.txt', attachment.filename + assert_equal 'text/plain', attachment.content_type + assert_equal 'test file', attachment.description + assert_equal 59, attachment.filesize + assert File.exists?(attachment.diskfile) + assert_equal 59, File.size(attachment.diskfile) + mail = ActionMailer::Base.deliveries.last assert mail.body.include?('testfile.txt') end @@ -1212,6 +1726,11 @@ # System wide custom field assert CustomField.find(1).is_for_all? assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'} + + # Be sure we don't display inactive IssuePriorities + assert ! IssuePriority.find(15).active? + assert_no_tag :option, :attributes => {:value => '15'}, + :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} } end def test_get_bulk_edit_on_different_projects @@ -1258,7 +1777,7 @@ :attributes => {:name => "issue[custom_field_values][#{field.id}]"}, :children => { :only => {:tag => 'option'}, - :count => Project.find(1).versions.count + 1 + :count => Project.find(1).shared_versions.count + 1 } end @@ -1281,6 +1800,22 @@ assert_equal 1, journal.details.size end + def test_bulk_update_with_group_assignee + group = Group.find(11) + project = Project.find(1) + project.members << Member.new(:principal => group, :roles => [Role.first]) + + @request.session[:user_id] = 2 + # update issues assignee + post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing', + :issue => {:priority_id => '', + :assigned_to_id => group.id, + :custom_field_values => {'2' => ''}} + + assert_response 302 + assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to} + end + def test_bulk_update_on_different_projects @request.session[:user_id] = 2 # update issues priority diff -r 487d96eac004 -r 5e80956cc792 test/functional/issues_controller_transaction_test.rb --- a/test/functional/issues_controller_transaction_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/issues_controller_transaction_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -44,14 +44,14 @@ :queries self.use_transactional_fixtures = false - + def setup @controller = IssuesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_put_update_stale_issue issue = Issue.find(2) @request.session[:user_id] = 2 @@ -71,7 +71,7 @@ end end end - + assert_response :success assert_template 'edit' assert_tag :tag => 'div', :attributes => { :id => 'errorExplanation' }, diff -r 487d96eac004 -r 5e80956cc792 test/functional/ldap_auth_sources_controller.rb --- a/test/functional/ldap_auth_sources_controller.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/ldap_auth_sources_controller.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,6 @@ -require 'test_helper' +require File.expand_path('../../test_helper', __FILE__) class LdapAuthSourcesControllerTest < ActionController::TestCase - fixtures :all def setup @request.session[:user_id] = 1 diff -r 487d96eac004 -r 5e80956cc792 test/functional/mail_handler_controller_test.rb --- a/test/functional/mail_handler_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/mail_handler_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,30 +23,30 @@ class MailHandlerControllerTest < ActionController::TestCase fixtures :users, :projects, :enabled_modules, :roles, :members, :member_roles, :issues, :issue_statuses, :trackers, :enumerations - + FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler' - + def setup @controller = MailHandlerController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_should_create_issue # Enable API and set a key Setting.mail_handler_api_enabled = 1 Setting.mail_handler_api_key = 'secret' - + post :index, :key => 'secret', :email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) assert_response 201 end - + def test_should_not_allow # Disable API Setting.mail_handler_api_enabled = 0 Setting.mail_handler_api_key = 'secret' - + post :index, :key => 'secret', :email => IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) assert_response 403 end diff -r 487d96eac004 -r 5e80956cc792 test/functional/members_controller_test.rb --- a/test/functional/members_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/members_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -24,7 +24,7 @@ class MembersControllerTest < ActionController::TestCase fixtures :projects, :members, :member_roles, :roles, :users - + def setup @controller = MembersController.new @request = ActionController::TestRequest.new @@ -32,7 +32,7 @@ User.current = nil @request.session[:user_id] = 2 end - + def test_create assert_difference 'Member.count' do post :new, :id => 1, :member => {:role_ids => [1], :user_id => 7} @@ -40,7 +40,7 @@ assert_redirected_to '/projects/ecookbook/settings/members' assert User.find(7).member_of?(Project.find(1)) end - + def test_create_multiple assert_difference 'Member.count', 3 do post :new, :id => 1, :member => {:role_ids => [1], :user_ids => [7, 8, 9]} @@ -49,47 +49,41 @@ assert User.find(7).member_of?(Project.find(1)) end - context "post :new in JS format" do - context "with successful saves" do - should "add membership for each user" do - post :new, :format => "js", :id => 1, :member => {:role_ids => [1], :user_ids => [7, 8, 9]} + def test_xhr_create + assert_difference 'Member.count', 3 do + post :new, :format => "js", :id => 1, :member => {:role_ids => [1], :user_ids => [7, 8, 9]} + end + assert_select_rjs :replace_html, 'tab-content-members' + assert User.find(7).member_of?(Project.find(1)) + assert User.find(8).member_of?(Project.find(1)) + assert User.find(9).member_of?(Project.find(1)) + end - assert User.find(7).member_of?(Project.find(1)) - assert User.find(8).member_of?(Project.find(1)) - assert User.find(9).member_of?(Project.find(1)) - end - - should "replace the tab with RJS" do - post :new, :format => "js", :id => 1, :member => {:role_ids => [1], :user_ids => [7, 8, 9]} + def test_xhr_create_with_failure + assert_no_difference 'Member.count' do + post :new, :format => "js", :id => 1, :member => {:role_ids => [], :user_ids => [7, 8, 9]} + end + assert_select '#tab-content-members', 0 + assert @response.body.match(/alert/i), "Alert message not sent" + end - assert_select_rjs :replace_html, 'tab-content-members' - end - - end - - context "with a failed save" do - should "not replace the tab with RJS" do - post :new, :format => "js", :id => 1, :member => {:role_ids => [], :user_ids => [7, 8, 9]} - - assert_select '#tab-content-members', 0 - end - - should "open an error message" do - post :new, :format => "js", :id => 1, :member => {:role_ids => [], :user_ids => [7, 8, 9]} - - assert @response.body.match(/alert/i), "Alert message not sent" - end - end - - end - def test_edit assert_no_difference 'Member.count' do post :edit, :id => 2, :member => {:role_ids => [1], :user_id => 3} end assert_redirected_to '/projects/ecookbook/settings/members' end - + + def test_xhr_edit + assert_no_difference 'Member.count' do + xhr :post, :edit, :id => 2, :member => {:role_ids => [1], :user_id => 3} + end + assert_select_rjs :replace_html, 'tab-content-members' + member = Member.find(2) + assert_equal [1], member.role_ids + assert_equal 3, member.user_id + end + def test_destroy assert_difference 'Member.count', -1 do post :destroy, :id => 2 @@ -97,12 +91,19 @@ assert_redirected_to '/projects/ecookbook/settings/members' assert !User.find(3).member_of?(Project.find(1)) end - + + def test_xhr_destroy + assert_difference 'Member.count', -1 do + xhr :post, :destroy, :id => 2 + end + assert_select_rjs :replace_html, 'tab-content-members' + end + def test_autocomplete_for_member get :autocomplete_for_member, :id => 1, :q => 'mis' assert_response :success assert_template 'autocomplete_for_member' - + assert_tag :label, :content => /User Misc/, :child => { :tag => 'input', :attributes => { :name => 'member[user_ids][]', :value => '8' } } end diff -r 487d96eac004 -r 5e80956cc792 test/functional/messages_controller_test.rb --- a/test/functional/messages_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/messages_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,14 @@ class MessagesControllerTest < ActionController::TestCase fixtures :projects, :users, :members, :member_roles, :roles, :boards, :messages, :enabled_modules - + def setup @controller = MessagesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_show get :show, :board_id => 1, :id => 1 assert_response :success @@ -40,10 +40,21 @@ assert_not_nil assigns(:topic) end + def test_show_should_contain_reply_field_tags_for_quoting + @request.session[:user_id] = 2 + get :show, :board_id => 1, :id => 1 + assert_response :success + + # tags required by MessagesController#quote + assert_tag 'input', :attributes => {:id => 'message_subject'} + assert_tag 'textarea', :attributes => {:id => 'message_content'} + assert_tag 'div', :attributes => {:id => 'reply'} + end + def test_show_with_pagination message = Message.find(1) assert_difference 'Message.count', 30 do - 30.times do + 30.times do message.children << Message.new(:subject => 'Reply', :content => 'Reply body', :author_id => 2, :board_id => 1) end end @@ -55,7 +66,7 @@ assert !replies.include?(message.children.first(:order => 'id')) assert replies.include?(message.children.last(:order => 'id')) end - + def test_show_with_reply_permission @request.session[:user_id] = 2 get :show, :board_id => 1, :id => 1 @@ -64,24 +75,24 @@ assert_tag :div, :attributes => { :id => 'reply' }, :descendant => { :tag => 'textarea', :attributes => { :id => 'message_content' } } end - + def test_show_message_not_found get :show, :board_id => 1, :id => 99999 assert_response 404 end - + def test_get_new @request.session[:user_id] = 2 get :new, :board_id => 1 assert_response :success - assert_template 'new' + assert_template 'new' end - + def test_post_new @request.session[:user_id] = 2 ActionMailer::Base.deliveries.clear Setting.notified_events = ['message_posted'] - + post :new, :board_id => 1, :message => { :subject => 'Test created message', :content => 'Message body'} @@ -101,14 +112,14 @@ # project member assert mail.bcc.include?('dlopper@somenet.foo') end - + def test_get_edit @request.session[:user_id] = 2 get :edit, :board_id => 1, :id => 1 assert_response :success - assert_template 'edit' + assert_template 'edit' end - + def test_post_edit @request.session[:user_id] = 2 post :edit, :board_id => 1, :id => 1, @@ -119,7 +130,7 @@ assert_equal 'New subject', message.subject assert_equal 'New body', message.content end - + def test_reply @request.session[:user_id] = 2 post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' } @@ -127,14 +138,14 @@ assert_redirected_to "/boards/1/topics/1?r=#{reply.id}" assert Message.find_by_subject('Test reply') end - + def test_destroy_topic @request.session[:user_id] = 2 post :destroy, :board_id => 1, :id => 1 assert_redirected_to '/projects/ecookbook/boards/1' assert_nil Message.find_by_id(1) end - + def test_quote @request.session[:user_id] = 2 xhr :get, :quote, :board_id => 1, :id => 3 diff -r 487d96eac004 -r 5e80956cc792 test/functional/my_controller_test.rb --- a/test/functional/my_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/my_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ class MyControllerTest < ActionController::TestCase fixtures :users, :user_preferences, :roles, :projects, :issues, :issue_statuses, :trackers, :enumerations, :custom_fields - + def setup @controller = MyController.new @request = ActionController::TestRequest.new @@ -36,30 +36,30 @@ assert_response :success assert_template 'page' end - + def test_page get :page assert_response :success assert_template 'page' end - + def test_my_account_should_show_editable_custom_fields get :account assert_response :success assert_template 'account' assert_equal User.find(2), assigns(:user) - + assert_tag :input, :attributes => { :name => 'user[custom_field_values][4]'} end - + def test_my_account_should_not_show_non_editable_custom_fields UserCustomField.find(4).update_attribute :editable, false - + get :account assert_response :success assert_template 'account' assert_equal User.find(2), assigns(:user) - + assert_no_tag :input, :attributes => { :name => 'user[custom_field_values][4]'} end @@ -72,7 +72,7 @@ :group_ids => ['10'], :custom_field_values => {"4" => "0100562500"} } - + assert_redirected_to '/my/account' user = User.find(2) assert_equal user, assigns(:user) @@ -83,28 +83,28 @@ assert !user.admin? assert user.groups.empty? end - + def test_change_password get :password assert_response :success assert_template 'password' - + # non matching password confirmation - post :password, :password => 'jsmith', + post :password, :password => 'jsmith', :new_password => 'hello', :new_password_confirmation => 'hello2' assert_response :success assert_template 'password' assert_tag :tag => "div", :attributes => { :class => "errorExplanation" } - + # wrong password - post :password, :password => 'wrongpassword', + post :password, :password => 'wrongpassword', :new_password => 'hello', :new_password_confirmation => 'hello' assert_response :success assert_template 'password' assert_equal 'Wrong password', flash[:error] - + # good password post :password, :password => 'jsmith', :new_password => 'hello', @@ -112,13 +112,13 @@ assert_redirected_to '/my/account' assert User.try_to_login('jsmith', 'hello') end - + def test_page_layout get :page_layout assert_response :success assert_template 'page_layout' end - + def test_add_block xhr :post, :add_block, :block => 'issuesreportedbyme' assert_response :success @@ -155,7 +155,7 @@ should_set_the_flash_to /reset/ should_redirect_to('my account') {'/my/account' } end - + context "with no rss_token" do setup do assert_nil User.find(2).rss_token @@ -189,7 +189,7 @@ should_set_the_flash_to /reset/ should_redirect_to('my account') {'/my/account' } end - + context "with no api_token" do setup do assert_nil User.find(2).api_token diff -r 487d96eac004 -r 5e80956cc792 test/functional/news_controller_test.rb --- a/test/functional/news_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/news_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,14 @@ class NewsControllerTest < ActionController::TestCase fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :news, :comments - + def setup @controller = NewsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_index get :index assert_response :success @@ -38,33 +38,33 @@ assert_not_nil assigns(:newss) assert_nil assigns(:project) end - + def test_index_with_project get :index, :project_id => 1 assert_response :success assert_template 'index' assert_not_nil assigns(:newss) end - + def test_show get :show, :id => 1 assert_response :success assert_template 'show' assert_tag :tag => 'h2', :content => /eCookbook first release/ end - + def test_show_not_found get :show, :id => 999 assert_response 404 end - + def test_get_new @request.session[:user_id] = 2 get :new, :project_id => 1 assert_response :success assert_template 'new' end - + def test_post_create ActionMailer::Base.deliveries.clear Setting.notified_events << 'news_added' @@ -74,7 +74,7 @@ :description => 'This is the description', :summary => '' } assert_redirected_to '/projects/ecookbook/news' - + news = News.find_by_title('NewsControllerTest') assert_not_nil news assert_equal 'This is the description', news.description @@ -82,14 +82,14 @@ assert_equal Project.find(1), news.project assert_equal 1, ActionMailer::Base.deliveries.size end - + def test_get_edit @request.session[:user_id] = 2 get :edit, :id => 1 assert_response :success assert_template 'edit' end - + def test_put_update @request.session[:user_id] = 2 put :update, :id => 1, :news => { :description => 'Description changed by test_post_edit' } @@ -110,7 +110,7 @@ assert_tag :tag => 'div', :attributes => { :id => 'errorExplanation' }, :content => /1 error/ end - + def test_destroy @request.session[:user_id] = 2 delete :destroy, :id => 1 diff -r 487d96eac004 -r 5e80956cc792 test/functional/previews_controller_test.rb --- a/test/functional/previews_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/previews_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,7 +18,15 @@ require File.expand_path('../../test_helper', __FILE__) class PreviewsControllerTest < ActionController::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :journals, :journal_details def test_preview_new_issue @request.session[:user_id] = 2 @@ -27,15 +35,17 @@ assert_template 'preview' assert_not_nil assigns(:description) end - + def test_preview_issue_notes @request.session[:user_id] = 2 - post :issue, :project_id => '1', :id => 1, :issue => {:description => Issue.find(1).description}, :notes => 'Foo' + post :issue, :project_id => '1', :id => 1, + :issue => {:description => Issue.find(1).description}, + :notes => 'Foo' assert_response :success assert_template 'preview' assert_not_nil assigns(:notes) end - + def test_preview_journal_notes_for_update @request.session[:user_id] = 2 post :issue, :project_id => '1', :id => 1, :notes => 'Foo' diff -r 487d96eac004 -r 5e80956cc792 test/functional/project_enumerations_controller_test.rb --- a/test/functional/project_enumerations_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/project_enumerations_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,8 +1,18 @@ require File.expand_path('../../test_helper', __FILE__) class ProjectEnumerationsControllerTest < ActionController::TestCase - fixtures :all - + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :custom_fields, :custom_fields_projects, + :custom_fields_trackers, :custom_values, + :time_entries + def setup @request.session[:user_id] = nil Setting.default_language = 'en' @@ -76,7 +86,7 @@ }) assert project_activity_two.save - + put :update, :project_id => 1, :enumerations => { project_activity.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # De-activate project_activity_two.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"} # De-activate @@ -102,7 +112,7 @@ def test_update_when_creating_new_activities_will_convert_existing_data assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size - + @request.session[:user_id] = 2 # manager put :update, :project_id => 1, :enumerations => { "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"} # Design, De-activate @@ -126,7 +136,7 @@ assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size - + @request.session[:user_id] = 2 # manager put :update, :project_id => 1, :enumerations => { "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design @@ -164,7 +174,7 @@ assert_nil TimeEntryActivity.find_by_id(project_activity.id) assert_nil TimeEntryActivity.find_by_id(project_activity_two.id) end - + def test_destroy_should_reassign_time_entries_back_to_the_system_activity @request.session[:user_id] = 2 # manager project_activity = TimeEntryActivity.new({ @@ -176,7 +186,7 @@ assert project_activity.save assert TimeEntry.update_all("activity_id = '#{project_activity.id}'", ["project_id = ? AND activity_id = ?", 1, 9]) assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size - + delete :destroy, :project_id => 1 assert_response :redirect assert_redirected_to '/projects/ecookbook/settings/activities' diff -r 487d96eac004 -r 5e80956cc792 test/functional/projects_controller_test.rb --- a/test/functional/projects_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/projects_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -55,7 +55,7 @@ def test_index_atom get :index, :format => 'atom' assert_response :success - assert_template 'common/feed.atom.rxml' + assert_template 'common/feed.atom' assert_select 'feed>title', :text => 'Redmine: Latest projects' assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_condition(User.current)) end @@ -186,6 +186,13 @@ assert_kind_of Project, project assert_equal Project.find(1), project.parent end + + should "continue" do + assert_difference 'Project.count' do + post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue' + end + assert_redirected_to '/projects/new?' + end end context "by non-admin user with add_project permission" do @@ -231,7 +238,7 @@ assert_response :success project = assigns(:project) assert_kind_of Project, project - assert_not_nil project.errors.on(:parent_id) + assert_not_nil project.errors[:parent_id] end end @@ -266,7 +273,7 @@ assert_response :success project = assigns(:project) assert_kind_of Project, project - assert_not_nil project.errors.on(:parent_id) + assert_not_nil project.errors[:parent_id] end should "fail with unauthorized parent_id" do @@ -283,7 +290,7 @@ assert_response :success project = assigns(:project) assert_kind_of Project, project - assert_not_nil project.errors.on(:parent_id) + assert_not_nil project.errors[:parent_id] end end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/queries_controller_test.rb --- a/test/functional/queries_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/queries_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,14 @@ class QueriesControllerTest < ActionController::TestCase fixtures :projects, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values, :queries - + def setup @controller = QueriesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_get_new_project_query @request.session[:user_id] = 2 get :new, :project_id => 1 @@ -38,72 +38,69 @@ assert_template 'new' assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query[is_public]', - :checked => nil } + :checked => nil } assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query_is_for_all', :checked => nil, :disabled => nil } end - + def test_get_new_global_query @request.session[:user_id] = 2 get :new assert_response :success assert_template 'new' assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', - :name => 'query[is_public]' } + :name => 'query[is_public]' } assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query_is_for_all', :checked => 'checked', :disabled => nil } end - + def test_new_project_public_query @request.session[:user_id] = 2 - post :new, - :project_id => 'ecookbook', - :confirm => '1', + post :create, + :project_id => 'ecookbook', :default_columns => '1', :f => ["status_id", "assigned_to_id"], :op => {"assigned_to_id" => "=", "status_id" => "o"}, :v => { "assigned_to_id" => ["1"], "status_id" => ["1"]}, :query => {"name" => "test_new_project_public_query", "is_public" => "1"} - + q = Query.find_by_name('test_new_project_public_query') assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q assert q.is_public? assert q.has_default_columns? assert q.valid? end - + def test_new_project_private_query @request.session[:user_id] = 3 - post :new, - :project_id => 'ecookbook', - :confirm => '1', + post :create, + :project_id => 'ecookbook', :default_columns => '1', :fields => ["status_id", "assigned_to_id"], :operators => {"assigned_to_id" => "=", "status_id" => "o"}, :values => { "assigned_to_id" => ["1"], "status_id" => ["1"]}, :query => {"name" => "test_new_project_private_query", "is_public" => "1"} - + q = Query.find_by_name('test_new_project_private_query') assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :query_id => q assert !q.is_public? assert q.has_default_columns? assert q.valid? end - + def test_new_global_private_query_with_custom_columns @request.session[:user_id] = 3 - post :new, - :confirm => '1', + post :create, :fields => ["status_id", "assigned_to_id"], :operators => {"assigned_to_id" => "=", "status_id" => "o"}, :values => { "assigned_to_id" => ["me"], "status_id" => ["1"]}, :query => {"name" => "test_new_global_private_query", "is_public" => "1"}, :c => ["", "tracker", "subject", "priority", "category"] - + q = Query.find_by_name('test_new_global_private_query') assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q assert !q.is_public? @@ -111,23 +108,37 @@ assert_equal [:tracker, :subject, :priority, :category], q.columns.collect {|c| c.name} assert q.valid? end - + + def test_new_global_query_with_custom_filters + @request.session[:user_id] = 3 + post :create, + :fields => ["assigned_to_id"], + :operators => {"assigned_to_id" => "="}, + :values => { "assigned_to_id" => ["me"]}, + :query => {"name" => "test_new_global_query"} + + q = Query.find_by_name('test_new_global_query') + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q + assert !q.has_filter?(:status_id) + assert_equal ['assigned_to_id'], q.filters.keys + assert q.valid? + end + def test_new_with_sort @request.session[:user_id] = 1 - post :new, - :confirm => '1', + post :create, :default_columns => '1', :operators => {"status_id" => "o"}, :values => {"status_id" => ["1"]}, :query => {:name => "test_new_with_sort", - :is_public => "1", + :is_public => "1", :sort_criteria => {"0" => ["due_date", "desc"], "1" => ["tracker", ""]}} - + query = Query.find_by_name("test_new_with_sort") assert_not_nil query assert_equal [['due_date', 'desc'], ['tracker', 'asc']], query.sort_criteria end - + def test_get_edit_global_public_query @request.session[:user_id] = 1 get :edit, :id => 4 @@ -135,7 +146,7 @@ assert_template 'edit' assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query[is_public]', - :checked => 'checked' } + :checked => 'checked' } assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query_is_for_all', :checked => 'checked', @@ -144,66 +155,64 @@ def test_edit_global_public_query @request.session[:user_id] = 1 - post :edit, - :id => 4, - :confirm => '1', + put :update, + :id => 4, :default_columns => '1', :fields => ["status_id", "assigned_to_id"], :operators => {"assigned_to_id" => "=", "status_id" => "o"}, :values => { "assigned_to_id" => ["1"], "status_id" => ["1"]}, :query => {"name" => "test_edit_global_public_query", "is_public" => "1"} - + assert_redirected_to :controller => 'issues', :action => 'index', :query_id => 4 q = Query.find_by_name('test_edit_global_public_query') assert q.is_public? assert q.has_default_columns? assert q.valid? end - + def test_get_edit_global_private_query @request.session[:user_id] = 3 get :edit, :id => 3 assert_response :success assert_template 'edit' assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', - :name => 'query[is_public]' } + :name => 'query[is_public]' } assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query_is_for_all', :checked => 'checked', :disabled => 'disabled' } end - + def test_edit_global_private_query @request.session[:user_id] = 3 - post :edit, - :id => 3, - :confirm => '1', + put :update, + :id => 3, :default_columns => '1', :fields => ["status_id", "assigned_to_id"], :operators => {"assigned_to_id" => "=", "status_id" => "o"}, :values => { "assigned_to_id" => ["me"], "status_id" => ["1"]}, :query => {"name" => "test_edit_global_private_query", "is_public" => "1"} - + assert_redirected_to :controller => 'issues', :action => 'index', :query_id => 3 q = Query.find_by_name('test_edit_global_private_query') assert !q.is_public? assert q.has_default_columns? assert q.valid? end - + def test_get_edit_project_private_query @request.session[:user_id] = 3 get :edit, :id => 2 assert_response :success assert_template 'edit' assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', - :name => 'query[is_public]' } + :name => 'query[is_public]' } assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query_is_for_all', :checked => nil, :disabled => nil } end - + def test_get_edit_project_public_query @request.session[:user_id] = 2 get :edit, :id => 1 @@ -212,13 +221,13 @@ assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query[is_public]', :checked => 'checked' - } + } assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'query_is_for_all', :checked => nil, :disabled => 'disabled' } end - + def test_get_edit_sort_criteria @request.session[:user_id] = 1 get :edit, :id => 5 @@ -231,10 +240,10 @@ :child => { :tag => 'option', :attributes => { :value => 'desc', :selected => 'selected' } } end - + def test_destroy @request.session[:user_id] = 2 - post :destroy, :id => 1 + delete :destroy, :id => 1 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :set_filter => 1, :query_id => nil assert_nil Query.find_by_id(1) end diff -r 487d96eac004 -r 5e80956cc792 test/functional/reports_controller_test.rb --- a/test/functional/reports_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/reports_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,15 +23,23 @@ class ReportsControllerTest < ActionController::TestCase - fixtures :all - + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions + def setup @controller = ReportsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + context "GET :issue_report without details" do setup do get :issue_report, :id => 1 @@ -73,7 +81,7 @@ should_respond_with :redirect should_redirect_to('the issue report') {{:controller => 'reports', :action => 'issue_report', :id => 'ecookbook'}} end - + end - + end diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_bazaar_controller_test.rb --- a/test/functional/repositories_bazaar_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_bazaar_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -22,34 +22,28 @@ class RepositoriesController; def rescue_action(e) raise e end; end class RepositoriesBazaarControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/bazaar_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository/trunk').to_s + PRJ_ID = 3 def setup @controller = RepositoriesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil - @project = Project.find(3) + @project = Project.find(PRJ_ID) @repository = Repository::Bazaar.create( - :project => @project, :url => REPOSITORY_PATH, + :project => @project, + :url => REPOSITORY_PATH, :log_encoding => 'UTF-8') assert @repository end if File.directory?(REPOSITORY_PATH) - def test_show - get :show, :id => 3 - assert_response :success - assert_template 'show' - assert_not_nil assigns(:entries) - assert_not_nil assigns(:changesets) - end - def test_browse_root - get :show, :id => 3 + get :show, :id => PRJ_ID assert_response :success assert_template 'show' assert_not_nil assigns(:entries) @@ -59,7 +53,7 @@ end def test_browse_directory - get :show, :id => 3, :path => ['directory'] + get :show, :id => PRJ_ID, :path => ['directory'] assert_response :success assert_template 'show' assert_not_nil assigns(:entries) @@ -69,24 +63,25 @@ assert_equal 'file', entry.kind assert_equal 'directory/edit.png', entry.path end - + def test_browse_at_given_revision - get :show, :id => 3, :path => [], :rev => 3 + get :show, :id => PRJ_ID, :path => [], :rev => 3 assert_response :success assert_template 'show' assert_not_nil assigns(:entries) - assert_equal ['directory', 'doc-deleted.txt', 'doc-ls.txt', 'doc-mkdir.txt'], assigns(:entries).collect(&:name) + assert_equal ['directory', 'doc-deleted.txt', 'doc-ls.txt', 'doc-mkdir.txt'], + assigns(:entries).collect(&:name) end - + def test_changes - get :changes, :id => 3, :path => ['doc-mkdir.txt'] + get :changes, :id => PRJ_ID, :path => ['doc-mkdir.txt'] assert_response :success assert_template 'changes' assert_tag :tag => 'h2', :content => 'doc-mkdir.txt' end - + def test_entry_show - get :entry, :id => 3, :path => ['directory', 'doc-ls.txt'] + get :entry, :id => PRJ_ID, :path => ['directory', 'doc-ls.txt'] assert_response :success assert_template 'entry' # Line 19 @@ -95,16 +90,16 @@ :attributes => { :class => /line-num/ }, :sibling => { :tag => 'td', :content => /Show help message/ } end - + def test_entry_download - get :entry, :id => 3, :path => ['directory', 'doc-ls.txt'], :format => 'raw' + get :entry, :id => PRJ_ID, :path => ['directory', 'doc-ls.txt'], :format => 'raw' assert_response :success # File content assert @response.body.include?('Show help message') end - + def test_directory_entry - get :entry, :id => 3, :path => ['directory'] + get :entry, :id => PRJ_ID, :path => ['directory'] assert_response :success assert_template 'show' assert_not_nil assigns(:entry) @@ -113,27 +108,84 @@ def test_diff # Full diff of changeset 3 - get :diff, :id => 3, :rev => 3 - assert_response :success - assert_template 'diff' - # Line 11 removed - assert_tag :tag => 'th', - :content => /11/, - :sibling => { :tag => 'td', - :attributes => { :class => /diff_out/ }, - :content => /Display more information/ } + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 3, :type => dt + assert_response :success + assert_template 'diff' + # Line 11 removed + assert_tag :tag => 'th', + :content => '11', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /Display more information/ } + end end - + def test_annotate - get :annotate, :id => 3, :path => ['doc-mkdir.txt'] + get :annotate, :id => PRJ_ID, :path => ['doc-mkdir.txt'] assert_response :success assert_template 'annotate' - # Line 2, revision 3 - assert_tag :tag => 'th', :content => /2/, - :sibling => { :tag => 'td', :child => { :tag => 'a', :content => /3/ } }, - :sibling => { :tag => 'td', :content => /jsmith/ }, + assert_tag :tag => 'th', :content => '2', + :sibling => { + :tag => 'td', + :child => { + :tag => 'a', + :content => '3' + } + } + assert_tag :tag => 'th', :content => '2', + :sibling => { :tag => 'td', :content => /jsmith/ } + assert_tag :tag => 'th', :content => '2', + :sibling => { + :tag => 'td', + :child => { + :tag => 'a', + :content => '3' + } + } + assert_tag :tag => 'th', :content => '2', :sibling => { :tag => 'td', :content => /Main purpose/ } end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert @repository.changesets.count > 0 + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert @repository.changesets.count > 0 + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Bazaar.create( + :project => @project, + :url => "/invalid", + :log_encoding => 'UTF-8') + assert @repository + @repository.fetch_changesets + @repository.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end else puts "Bazaar test repository NOT FOUND. Skipping functional tests !!!" def test_fake; assert true end diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_controller_test.rb --- a/test/functional/repositories_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -85,7 +85,7 @@ get :committers, :id => 1 assert_response :success assert_template 'committers' - + assert_tag :td, :content => 'dlopper', :sibling => { :tag => 'td', :child => { :tag => 'select', :attributes => { :name => %r{^committers\[\d+\]\[\]$} }, diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_cvs_controller_test.rb --- a/test/functional/repositories_cvs_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_cvs_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,14 +22,15 @@ class RepositoriesController; def rescue_action(e) raise e end; end class RepositoriesCvsControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? # CVS module MODULE_NAME = 'test' PRJ_ID = 3 + NUM_REV = 7 def setup @controller = RepositoriesController.new @@ -48,8 +49,10 @@ if File.directory?(REPOSITORY_PATH) def test_browse_root + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID assert_response :success assert_template 'show' @@ -63,12 +66,14 @@ assert_equal 'file', entry.kind assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_browse_directory + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'] assert_response :success assert_template 'show' @@ -81,8 +86,10 @@ end def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'], :rev => 1 assert_response :success assert_template 'show' @@ -91,8 +98,10 @@ end def test_entry + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] assert_response :success assert_template 'entry' @@ -103,8 +112,10 @@ def test_entry_at_given_revision # changesets must be loaded + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], :rev => 2 assert_response :success assert_template 'entry' @@ -115,8 +126,10 @@ end def test_entry_not_found + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['sources', 'zzz.c'] assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ }, @@ -124,15 +137,20 @@ end def test_entry_download + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], :format => 'raw' + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], + :format => 'raw' assert_response :success end def test_directory_entry + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['sources'] assert_response :success assert_template 'show' @@ -141,38 +159,48 @@ end def test_diff + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - get :diff, :id => PRJ_ID, :rev => 3, :type => 'inline' - assert_response :success - assert_template 'diff' - assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_out' }, - :content => /before_filter :require_login/ - assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' }, - :content => /with one change/ + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 3, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_out' }, + :content => /before_filter :require_login/ + assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' }, + :content => /with one change/ + end end def test_diff_new_files + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - get :diff, :id => PRJ_ID, :rev => 1, :type => 'inline' - assert_response :success - assert_template 'diff' - assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' }, - :content => /watched.remove_watcher/ - assert_tag :tag => 'th', :attributes => { :class => 'filename' }, - :content => /test\/README/ - assert_tag :tag => 'th', :attributes => { :class => 'filename' }, - :content => /test\/images\/delete.png / - assert_tag :tag => 'th', :attributes => { :class => 'filename' }, - :content => /test\/images\/edit.png/ - assert_tag :tag => 'th', :attributes => { :class => 'filename' }, - :content => /test\/sources\/watchers_controller.rb/ + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 1, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' }, + :content => /watched.remove_watcher/ + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/README/ + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/images\/delete.png / + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/images\/edit.png/ + assert_tag :tag => 'th', :attributes => { :class => 'filename' }, + :content => /test\/sources\/watchers_controller.rb/ + end end def test_annotate + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] assert_response :success assert_template 'annotate' @@ -205,6 +233,48 @@ } } end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Cvs.create( + :project => Project.find(PRJ_ID), + :root_url => "/invalid", + :url => MODULE_NAME, + :log_encoding => 'UTF-8' + ) + assert @repository + @repository.fetch_changesets + @project.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end else puts "CVS test repository NOT FOUND. Skipping functional tests !!!" def test_fake; assert true end diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_darcs_controller_test.rb --- a/test/functional/repositories_darcs_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_darcs_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -22,11 +22,12 @@ class RepositoriesController; def rescue_action(e) raise e end; end class RepositoriesDarcsControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/darcs_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s PRJ_ID = 3 + NUM_REV = 6 def setup @controller = RepositoriesController.new @@ -35,15 +36,19 @@ User.current = nil @project = Project.find(PRJ_ID) @repository = Repository::Darcs.create( - :project => @project, :url => REPOSITORY_PATH, - :log_encoding => 'UTF-8') + :project => @project, + :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8' + ) assert @repository end if File.directory?(REPOSITORY_PATH) def test_browse_root + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID assert_response :success assert_template 'show' @@ -55,8 +60,10 @@ end def test_browse_directory + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'] assert_response :success assert_template 'show' @@ -69,8 +76,10 @@ end def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'], :rev => 1 assert_response :success assert_template 'show' @@ -79,8 +88,10 @@ end def test_changes + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :changes, :id => PRJ_ID, :path => ['images', 'edit.png'] assert_response :success assert_template 'changes' @@ -88,18 +99,63 @@ end def test_diff + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count # Full diff of changeset 5 - get :diff, :id => PRJ_ID, :rev => 5 - assert_response :success - assert_template 'diff' - # Line 22 removed - assert_tag :tag => 'th', - :content => /22/, - :sibling => { :tag => 'td', - :attributes => { :class => /diff_out/ }, - :content => /def remove/ } + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 5, :type => dt + assert_response :success + assert_template 'diff' + # Line 22 removed + assert_tag :tag => 'th', + :content => '22', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /def remove/ } + end + end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Darcs.create( + :project => @project, + :url => "/invalid", + :log_encoding => 'UTF-8' + ) + assert @repository + @repository.fetch_changesets + @project.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository end else puts "Darcs test repository NOT FOUND. Skipping functional tests !!!" diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_filesystem_controller_test.rb --- a/test/functional/repositories_filesystem_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_filesystem_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,10 +22,10 @@ class RepositoriesController; def rescue_action(e) raise e end; end class RepositoriesFilesystemControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/filesystem_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s PRJ_ID = 3 def setup @@ -36,8 +36,9 @@ @response = ActionController::TestResponse.new User.current = nil Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem') + @project = Project.find(PRJ_ID) @repository = Repository::Filesystem.create( - :project => Project.find(PRJ_ID), + :project => @project, :url => REPOSITORY_PATH, :path_encoding => '' ) @@ -115,6 +116,36 @@ assert_equal 'text/plain', @response.content_type end end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Filesystem.create( + :project => Project.find(PRJ_ID), + :url => "/invalid", + :path_encoding => '' + ) + assert @repository + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end else puts "Filesystem test repository NOT FOUND. Skipping functional tests !!!" def test_fake; assert true end diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_git_controller_test.rb --- a/test/functional/repositories_git_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_git_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,13 +22,22 @@ class RepositoriesController; def rescue_action(e) raise e end; end class RepositoriesGitControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? PRJ_ID = 3 CHAR_1_HEX = "\xc3\x9c" + NUM_REV = 21 + + ## Git, Mercurial and CVS path encodings are binary. + ## Subversion supports URL encoding for path. + ## Redmine Mercurial adapter and extension use URL encoding. + ## Git accepts only binary path in command line parameter. + ## So, there is no way to use binary command line parameter in JRuby. + JRUBY_SKIP = (RUBY_PLATFORM == 'java') + JRUBY_SKIP_STR = "TODO: This test fails in JRuby" def setup @ruby19_non_utf8_pass = @@ -38,9 +47,10 @@ @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil + @project = Project.find(PRJ_ID) @repository = Repository::Git.create( - :project => Project.find(3), - :url => REPOSITORY_PATH, + :project => @project, + :url => REPOSITORY_PATH, :path_encoding => 'ISO-8859-1' ) assert @repository @@ -54,8 +64,11 @@ if File.directory?(REPOSITORY_PATH) def test_browse_root + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count + get :show, :id => PRJ_ID assert_response :success assert_template 'show' @@ -71,12 +84,14 @@ assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'} assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'} assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_browse_branch + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :rev => 'test_branch' assert_response :success assert_template 'show' @@ -87,12 +102,14 @@ assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'} assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_browse_tag + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [ "tag00.lightweight", "tag01.annotated", @@ -101,15 +118,17 @@ assert_response :success assert_template 'show' assert_not_nil assigns(:entries) - assigns(:entries).size > 0 + assert assigns(:entries).size > 0 assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end end def test_browse_directory + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'] assert_response :success assert_template 'show' @@ -120,12 +139,14 @@ assert_equal 'file', entry.kind assert_equal 'images/edit.png', entry.path assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'], :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518' assert_response :success @@ -133,7 +154,7 @@ assert_not_nil assigns(:entries) assert_equal ['delete.png'], assigns(:entries).collect(&:name) assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_changes @@ -157,6 +178,8 @@ def test_entry_show_latin_1 if @ruby19_non_utf8_pass puts_ruby19_non_utf8_pass() + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR else with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1| @@ -191,24 +214,33 @@ end def test_diff + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count # Full diff of changeset 2f9c0091 - get :diff, :id => PRJ_ID, :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7' - assert_response :success - assert_template 'diff' - # Line 22 removed - assert_tag :tag => 'th', - :content => /22/, - :sibling => { :tag => 'td', - :attributes => { :class => /diff_out/ }, - :content => /def remove/ } - assert_tag :tag => 'h2', :content => /2f9c0091/ + ['inline', 'sbs'].each do |dt| + get :diff, + :id => PRJ_ID, + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7', + :type => dt + assert_response :success + assert_template 'diff' + # Line 22 removed + assert_tag :tag => 'th', + :content => /22/, + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /def remove/ } + assert_tag :tag => 'h2', :content => /2f9c0091/ + end end def test_diff_truncated + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count Setting.diff_max_lines_displayed = 5 # Truncated diff of changeset 2f9c0091 @@ -228,16 +260,22 @@ end def test_diff_two_revs + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - get :diff, :id => PRJ_ID, - :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1', - :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7' - assert_response :success - assert_template 'diff' - diff = assigns(:diff) - assert_not_nil diff - assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/ + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, + :id => PRJ_ID, + :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1', + :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7', + :type => dt + assert_response :success + assert_template 'diff' + diff = assigns(:diff) + assert_not_nil diff + assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/ + end end def test_diff_latin_1 @@ -246,56 +284,82 @@ else with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1| - get :diff, :id => PRJ_ID, :rev => r1 - assert_response :success - assert_template 'diff' - assert_tag :tag => 'thead', - :descendant => { - :tag => 'th', - :attributes => { :class => 'filename' } , - :content => /latin-1-dir\/test-#{@char_1}.txt/ , - }, - :sibling => { - :tag => 'tbody', + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => r1, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'thead', :descendant => { - :tag => 'td', - :attributes => { :class => /diff_in/ }, - :content => /test-#{@char_1}.txt/ + :tag => 'th', + :attributes => { :class => 'filename' } , + :content => /latin-1-dir\/test-#{@char_1}.txt/ , + }, + :sibling => { + :tag => 'tbody', + :descendant => { + :tag => 'td', + :attributes => { :class => /diff_in/ }, + :content => /test-#{@char_1}.txt/ + } } - } + end end end end end + def test_save_diff_type + @request.session[:user_id] = 1 # admin + user = User.find(1) + get :diff, + :id => PRJ_ID, + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7' + assert_response :success + assert_template 'diff' + user.reload + assert_equal "inline", user.pref[:diff_type] + get :diff, + :id => PRJ_ID, + :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7', + :type => 'sbs' + assert_response :success + assert_template 'diff' + user.reload + assert_equal "sbs", user.pref[:diff_type] + end + def test_annotate get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'] assert_response :success assert_template 'annotate' - # Line 23, changeset 2f9c0091 + # Line 24, changeset 2f9c0091 assert_tag :tag => 'th', :content => '24', :sibling => { :tag => 'td', :child => { :tag => 'a', - :content => /2f9c0091c754a91af7a9c478e36556b4bde8dcf7/ + :content => /2f9c0091/ } - }, + } + assert_tag :tag => 'th', :content => '24', :sibling => { :tag => 'td', :content => /jsmith/ } assert_tag :tag => 'th', :content => '24', :sibling => { :tag => 'td', :child => { :tag => 'a', - :content => /2f9c0091c754a91af7a9c478e36556b4bde8dcf7/ + :content => /2f9c0091/ } - }, + } + assert_tag :tag => 'th', :content => '24', :sibling => { :tag => 'td', :content => /watcher =/ } end def test_annotate_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :annotate, :id => PRJ_ID, :rev => 'deff7', :path => ['sources', 'watchers_controller.rb'] assert_response :success @@ -310,9 +374,24 @@ :content => /cannot be annotated/ end + def test_annotate_error_when_too_big + with_settings :file_max_size_displayed => 1 do + get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'], :rev => 'deff712f' + assert_response 500 + assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ }, + :content => /exceeds the maximum text file size/ + + get :annotate, :id => PRJ_ID, :path => ['README'], :rev => '7234cb2' + assert_response :success + assert_template 'annotate' + end + end + def test_annotate_latin_1 if @ruby19_non_utf8_pass puts_ruby19_non_utf8_pass() + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR else with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1| @@ -329,8 +408,10 @@ end def test_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r| get :revision, :id => PRJ_ID, :rev => r assert_response :success @@ -339,8 +420,10 @@ end def test_empty_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['', ' ', nil].each do |r| get :revision, :id => PRJ_ID, :rev => r assert_response 404 @@ -348,6 +431,47 @@ end end + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Git.create( + :project => @project, + :url => "/invalid", + :path_encoding => 'ISO-8859-1' + ) + assert @repository + @repository.fetch_changesets + @repository.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + private def puts_ruby19_non_utf8_pass diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_mercurial_controller_test.rb --- a/test/functional/repositories_mercurial_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_mercurial_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,13 +22,13 @@ class RepositoriesController; def rescue_action(e) raise e end; end class RepositoriesMercurialControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules + fixtures :projects, :users, :roles, :members, :member_roles, + :repositories, :enabled_modules - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + - '/tmp/test/mercurial_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s CHAR_1_HEX = "\xc3\x9c" PRJ_ID = 3 + NUM_REV = 32 ruby19_non_utf8_pass = (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8') @@ -65,8 +65,10 @@ def test_fake; assert true end elsif File.directory?(REPOSITORY_PATH) def test_show_root + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID assert_response :success assert_template 'show' @@ -76,12 +78,14 @@ assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_show_directory + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['images'] assert_response :success assert_template 'show' @@ -92,12 +96,14 @@ assert_equal 'file', entry.kind assert_equal 'images/edit.png', entry.path assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end def test_show_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [0, '0', '0885933ad4f6'].each do |r1| get :show, :id => PRJ_ID, :path => ['images'], :rev => r1 assert_response :success @@ -105,13 +111,15 @@ assert_not_nil assigns(:entries) assert_equal ['delete.png'], assigns(:entries).collect(&:name) assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end end def test_show_directory_sql_escape_percent + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [13, '13', '3a330eb32958'].each do |r1| get :show, :id => PRJ_ID, :path => ['sql_escape', 'percent%dir'], :rev => r1 @@ -123,14 +131,16 @@ assigns(:entries).collect(&:name) changesets = assigns(:changesets) assert_not_nil changesets - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 assert_equal %w(13 11 10 9), changesets.collect(&:revision) end end def test_show_directory_latin_1_path + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [21, '21', 'adf805632193'].each do |r1| get :show, :id => PRJ_ID, :path => ['latin-1-dir'], :rev => r1 assert_response :success @@ -148,8 +158,10 @@ end def test_show_branch + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [ 'default', @branch_char_1, @@ -164,13 +176,15 @@ assert_not_nil assigns(:entries) assert assigns(:entries).size > 0 assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end end def test_show_tag + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [ @tag_char_1, 'tag_test.00', @@ -182,7 +196,7 @@ assert_not_nil assigns(:entries) assert assigns(:entries).size > 0 assert_not_nil assigns(:changesets) - assigns(:changesets).size > 0 + assert assigns(:changesets).size > 0 end end @@ -257,38 +271,49 @@ end def test_diff + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [4, '4', 'def6d2f1254a'].each do |r1| # Full diff of changeset 4 - get :diff, :id => PRJ_ID, :rev => r1 - assert_response :success - assert_template 'diff' - if @diff_c_support - # Line 22 removed - assert_tag :tag => 'th', - :content => '22', - :sibling => { :tag => 'td', - :attributes => { :class => /diff_out/ }, - :content => /def remove/ } - assert_tag :tag => 'h2', :content => /4:def6d2f1254a/ + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => r1, :type => dt + assert_response :success + assert_template 'diff' + if @diff_c_support + # Line 22 removed + assert_tag :tag => 'th', + :content => '22', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_out/ }, + :content => /def remove/ } + assert_tag :tag => 'h2', :content => /4:def6d2f1254a/ + end end end end def test_diff_two_revs + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [2, '400bb8672109', '400', 400].each do |r1| [4, 'def6d2f1254a'].each do |r2| - get :diff, :id => PRJ_ID, :rev => r1, - :rev_to => r2 - assert_response :success - assert_template 'diff' - - diff = assigns(:diff) - assert_not_nil diff - assert_tag :tag => 'h2', :content => /4:def6d2f1254a 2:400bb8672109/ + ['inline', 'sbs'].each do |dt| + get :diff, + :id => PRJ_ID, + :rev => r1, + :rev_to => r2, + :type => dt + assert_response :success + assert_template 'diff' + diff = assigns(:diff) + assert_not_nil diff + assert_tag :tag => 'h2', + :content => /4:def6d2f1254a 2:400bb8672109/ + end end end end @@ -296,23 +321,25 @@ def test_diff_latin_1_path with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do [21, 'adf805632193'].each do |r1| - get :diff, :id => PRJ_ID, :rev => r1 - assert_response :success - assert_template 'diff' - assert_tag :tag => 'thead', - :descendant => { - :tag => 'th', - :attributes => { :class => 'filename' } , - :content => /latin-1-dir\/test-#{@char_1}-2.txt/ , - }, - :sibling => { - :tag => 'tbody', + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => r1, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'thead', :descendant => { - :tag => 'td', - :attributes => { :class => /diff_in/ }, - :content => /It is written in Python/ + :tag => 'th', + :attributes => { :class => 'filename' } , + :content => /latin-1-dir\/test-#{@char_1}-2.txt/ , + }, + :sibling => { + :tag => 'tbody', + :descendant => { + :tag => 'td', + :attributes => { :class => /diff_in/ }, + :content => /It is written in Python/ + } } - } + end end end end @@ -347,9 +374,10 @@ end def test_annotate_not_in_tip + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert @repository.changesets.size > 0 + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :annotate, :id => PRJ_ID, :path => ['sources', 'welcome_controller.rb'] @@ -358,8 +386,10 @@ end def test_annotate_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count [2, '400bb8672109', '400', 400].each do |r1| get :annotate, :id => PRJ_ID, :rev => r1, :path => ['sources', 'watchers_controller.rb'] @@ -417,8 +447,10 @@ end def test_empty_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['', ' ', nil].each do |r| get :revision, :id => PRJ_ID, :rev => r assert_response 404 @@ -428,9 +460,10 @@ def test_destroy_valid_repository @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert @repository.changesets.count > 0 + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :destroy, :id => PRJ_ID assert_response 302 @@ -440,9 +473,10 @@ def test_destroy_invalid_repository @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert @repository.changesets.count > 0 + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :destroy, :id => PRJ_ID assert_response 302 @@ -456,7 +490,7 @@ ) assert @repository @repository.fetch_changesets - @repository.reload + @project.reload assert_equal 0, @repository.changesets.count get :destroy, :id => PRJ_ID diff -r 487d96eac004 -r 5e80956cc792 test/functional/repositories_subversion_controller_test.rb --- a/test/functional/repositories_subversion_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/repositories_subversion_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -27,6 +27,7 @@ :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers PRJ_ID = 3 + NUM_REV = 11 def setup @controller = RepositoriesController.new @@ -43,8 +44,10 @@ if repository_configured?('subversion') def test_show + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID assert_response :success assert_template 'show' @@ -53,8 +56,10 @@ end def test_browse_root + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID assert_response :success assert_template 'show' @@ -64,14 +69,19 @@ end def test_browse_directory + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['subversion_test'] assert_response :success assert_template 'show' assert_not_nil assigns(:entries) - assert_equal ['[folder_with_brackets]', 'folder', '.project', 'helloworld.c', 'textfile.txt'], - assigns(:entries).collect(&:name) + assert_equal [ + '[folder_with_brackets]', 'folder', '.project', + 'helloworld.c', 'textfile.txt' + ], + assigns(:entries).collect(&:name) entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'} assert_equal 'file', entry.kind assert_equal 'subversion_test/helloworld.c', entry.path @@ -79,8 +89,10 @@ end def test_browse_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :show, :id => PRJ_ID, :path => ['subversion_test'], :rev => 4 assert_response :success assert_template 'show' @@ -90,8 +102,10 @@ end def test_file_changes + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :changes, :id => PRJ_ID, :path => ['subversion_test', 'folder', 'helloworld.rb' ] assert_response :success assert_template 'changes' @@ -112,8 +126,10 @@ end def test_directory_changes + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :changes, :id => PRJ_ID, :path => ['subversion_test', 'folder' ] assert_response :success assert_template 'changes' @@ -124,28 +140,35 @@ end def test_entry + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['subversion_test', 'helloworld.c'] assert_response :success assert_template 'entry' end def test_entry_should_send_if_too_big + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count # no files in the test repo is larger than 1KB... with_settings :file_max_size_displayed => 0 do get :entry, :id => PRJ_ID, :path => ['subversion_test', 'helloworld.c'] assert_response :success assert_template '' - assert_equal 'attachment; filename="helloworld.c"', @response.headers['Content-Disposition'] + assert_equal 'attachment; filename="helloworld.c"', + @response.headers['Content-Disposition'] end end def test_entry_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['subversion_test', 'helloworld.rb'], :rev => 2 assert_response :success assert_template 'entry' @@ -155,16 +178,20 @@ end def test_entry_not_found + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['subversion_test', 'zzz.c'] assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ }, :content => /The entry or revision was not found in the repository/ end def test_entry_download + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['subversion_test', 'helloworld.c'], :format => 'raw' assert_response :success assert_template '' @@ -172,8 +199,10 @@ end def test_directory_entry + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :entry, :id => PRJ_ID, :path => ['subversion_test', 'folder'] assert_response :success assert_template 'show' @@ -183,8 +212,6 @@ # TODO: this test needs fixtures. def test_revision - @repository.fetch_changesets - @repository.reload get :revision, :id => 1, :rev => 2 assert_response :success assert_template 'revision' @@ -203,8 +230,10 @@ end def test_invalid_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :revision, :id => PRJ_ID, :rev => 'something_weird' assert_response 404 assert_error_tag :content => /was not found/ @@ -217,8 +246,10 @@ end def test_empty_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['', ' ', nil].each do |r| get :revision, :id => PRJ_ID, :rev => r assert_response 404 @@ -250,46 +281,97 @@ end def test_revision_diff + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - get :diff, :id => PRJ_ID, :rev => 3 - assert_response :success - assert_template 'diff' - - assert_tag :tag => 'h2', :content => /3/ + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 3, :type => dt + assert_response :success + assert_template 'diff' + assert_tag :tag => 'h2', + :content => / 3/ + end end def test_directory_diff + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - get :diff, :id => PRJ_ID, :rev => 6, :rev_to => 2, :path => ['subversion_test', 'folder'] - assert_response :success - assert_template 'diff' + @project.reload + assert_equal NUM_REV, @repository.changesets.count + ['inline', 'sbs'].each do |dt| + get :diff, :id => PRJ_ID, :rev => 6, :rev_to => 2, + :path => ['subversion_test', 'folder'], :type => dt + assert_response :success + assert_template 'diff' - diff = assigns(:diff) - assert_not_nil diff - # 2 files modified - assert_equal 2, Redmine::UnifiedDiff.new(diff).size - - assert_tag :tag => 'h2', :content => /2:6/ + diff = assigns(:diff) + assert_not_nil diff + # 2 files modified + assert_equal 2, Redmine::UnifiedDiff.new(diff).size + assert_tag :tag => 'h2', :content => /2:6/ + end end def test_annotate + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :annotate, :id => PRJ_ID, :path => ['subversion_test', 'helloworld.c'] assert_response :success assert_template 'annotate' end def test_annotate_at_given_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count get :annotate, :id => PRJ_ID, :rev => 8, :path => ['subversion_test', 'helloworld.c'] assert_response :success assert_template 'annotate' assert_tag :tag => 'h2', :content => /@ 8/ end + + def test_destroy_valid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end + + def test_destroy_invalid_repository + @request.session[:user_id] = 1 # admin + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + + @repository = Repository::Subversion.create( + :project => @project, + :url => "file:///invalid") + assert @repository + @repository.fetch_changesets + @project.reload + assert_equal 0, @repository.changesets.count + + get :destroy, :id => PRJ_ID + assert_response 302 + @project.reload + assert_nil @project.repository + end else puts "Subversion test repository NOT FOUND. Skipping functional tests !!!" def test_fake; assert true end diff -r 487d96eac004 -r 5e80956cc792 test/functional/roles_controller_test.rb --- a/test/functional/roles_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/roles_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ class RolesControllerTest < ActionController::TestCase fixtures :roles, :users, :members, :member_roles, :workflows, :trackers - + def setup @controller = RolesController.new @request = ActionController::TestRequest.new @@ -31,7 +31,7 @@ User.current = nil @request.session[:user_id] = 1 # admin end - + def test_get_index get :index assert_response :success @@ -43,28 +43,28 @@ assert_tag :tag => 'a', :attributes => { :href => '/roles/edit/1' }, :content => 'Manager' end - + def test_get_new get :new assert_response :success assert_template 'new' end - + def test_post_new_with_validaton_failure post :new, :role => {:name => '', :permissions => ['add_issues', 'edit_issues', 'log_time', ''], :assignable => '0'} - + assert_response :success assert_template 'new' assert_tag :tag => 'div', :attributes => { :id => 'errorExplanation' } end - + def test_post_new_without_workflow_copy post :new, :role => {:name => 'RoleWithoutWorkflowCopy', :permissions => ['add_issues', 'edit_issues', 'log_time', ''], :assignable => '0'} - + assert_redirected_to '/roles' role = Role.find_by_name('RoleWithoutWorkflowCopy') assert_not_nil role @@ -77,13 +77,13 @@ :permissions => ['add_issues', 'edit_issues', 'log_time', ''], :assignable => '0'}, :copy_workflow_from => '1' - + assert_redirected_to '/roles' role = Role.find_by_name('RoleWithWorkflowCopy') assert_not_nil role assert_equal Role.find(1).workflows.size, role.workflows.size end - + def test_get_edit get :edit, :id => 1 assert_response :success @@ -96,62 +96,62 @@ :role => {:name => 'Manager', :permissions => ['edit_project', ''], :assignable => '0'} - + assert_redirected_to '/roles' role = Role.find(1) assert_equal [:edit_project], role.permissions end - + def test_destroy r = Role.new(:name => 'ToBeDestroyed', :permissions => [:view_wiki_pages]) assert r.save - + post :destroy, :id => r assert_redirected_to '/roles' assert_nil Role.find_by_id(r.id) end - + def test_destroy_role_in_use post :destroy, :id => 1 assert_redirected_to '/roles' assert flash[:error] == 'This role is in use and cannot be deleted.' assert_not_nil Role.find_by_id(1) end - + def test_get_report get :report assert_response :success assert_template 'report' - + assert_not_nil assigns(:roles) assert_equal Role.find(:all, :order => 'builtin, position'), assigns(:roles) - + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'permissions[3][]', :value => 'add_issues', :checked => 'checked' } - + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'permissions[3][]', :value => 'delete_issues', :checked => nil } end - + def test_post_report post :report, :permissions => { '0' => '', '1' => ['edit_issues'], '3' => ['add_issues', 'delete_issues']} assert_redirected_to '/roles' - + assert_equal [:edit_issues], Role.find(1).permissions assert_equal [:add_issues, :delete_issues], Role.find(3).permissions assert Role.find(2).permissions.empty? end - + def test_clear_all_permissions post :report, :permissions => { '0' => '' } assert_redirected_to '/roles' assert Role.find(1).permissions.empty? end - + def test_move_highest post :edit, :id => 3, :role => {:move_to => 'highest'} assert_redirected_to '/roles' diff -r 487d96eac004 -r 5e80956cc792 test/functional/search_controller_test.rb --- a/test/functional/search_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/search_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -124,7 +124,7 @@ def test_search_content Issue.update_all("description = 'This is a searchkeywordinthecontent'", "id=1") - + get :index, :id => 1, :q => 'searchkeywordinthecontent', :titles_only => '' assert_equal false, assigns(:titles_only) results = assigns(:results) diff -r 487d96eac004 -r 5e80956cc792 test/functional/settings_controller_test.rb --- a/test/functional/settings_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/settings_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -42,6 +42,8 @@ get :edit assert_response :success assert_template 'edit' + + assert_tag 'input', :attributes => {:name => 'settings[enabled_scm][]', :value => ''} end def test_post_edit_notifications diff -r 487d96eac004 -r 5e80956cc792 test/functional/sys_controller_test.rb --- a/test/functional/sys_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/sys_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -24,7 +24,7 @@ class SysControllerTest < ActionController::TestCase fixtures :projects, :repositories, :enabled_modules - + def setup @controller = SysController.new @request = ActionController::TestRequest.new @@ -32,60 +32,72 @@ Setting.sys_api_enabled = '1' Setting.enabled_scm = %w(Subversion Git) end - + def test_projects_with_repository_enabled get :projects assert_response :success assert_equal 'application/xml', @response.content_type with_options :tag => 'projects' do |test| test.assert_tag :children => { :count => Project.active.has_module(:repository).count } + test.assert_tag 'project', :child => {:tag => 'identifier', :sibling => {:tag => 'is-public'}} end + assert_no_tag 'extra-info' + assert_no_tag 'extra_info' end def test_create_project_repository assert_nil Project.find(4).repository - - post :create_project_repository, :id => 4, + + post :create_project_repository, :id => 4, :vendor => 'Subversion', :repository => { :url => 'file:///create/project/repository/subproject2'} assert_response :created - + assert_equal 'application/xml', @response.content_type + r = Project.find(4).repository assert r.is_a?(Repository::Subversion) assert_equal 'file:///create/project/repository/subproject2', r.url + + assert_tag 'repository-subversion', + :child => { + :tag => 'id', :content => r.id.to_s, + :sibling => {:tag => 'url', :content => r.url} + } + assert_no_tag 'extra-info' + assert_no_tag 'extra_info' end - + def test_fetch_changesets Repository::Subversion.any_instance.expects(:fetch_changesets).returns(true) get :fetch_changesets assert_response :success end - + def test_fetch_changesets_one_project Repository::Subversion.any_instance.expects(:fetch_changesets).returns(true) get :fetch_changesets, :id => 'ecookbook' assert_response :success end - + def test_fetch_changesets_unknown_project get :fetch_changesets, :id => 'unknown' assert_response 404 end - + def test_disabled_ws_should_respond_with_403_error with_settings :sys_api_enabled => '0' do get :projects assert_response 403 end end - + def test_api_key with_settings :sys_api_key => 'my_secret_key' do get :projects, :key => 'my_secret_key' assert_response :success end end - + def test_wrong_key_should_respond_with_403_error with_settings :sys_api_enabled => 'my_secret_key' do get :projects, :key => 'wrong_key' diff -r 487d96eac004 -r 5e80956cc792 test/functional/time_entry_reports_controller_test.rb --- a/test/functional/time_entry_reports_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/time_entry_reports_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -2,7 +2,15 @@ require File.expand_path('../../test_helper', __FILE__) class TimeEntryReportsControllerTest < ActionController::TestCase - fixtures :projects, :enabled_modules, :roles, :members, :member_roles, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses, :custom_fields, :custom_values + fixtures :projects, :enabled_modules, :roles, :members, :member_roles, + :issues, :time_entries, :users, :trackers, :enumerations, + :issue_statuses, :custom_fields, :custom_values + + include Redmine::I18n + + def setup + Setting.default_language = "en" + end def test_report_at_project_level get :report, :project_id => 'ecookbook' @@ -11,7 +19,7 @@ assert_tag :form, :attributes => {:action => "/projects/ecookbook/time_entries/report", :id => 'query_form'} end - + def test_report_all_projects get :report assert_response :success @@ -19,7 +27,7 @@ assert_tag :form, :attributes => {:action => "/time_entries/report", :id => 'query_form'} end - + def test_report_all_projects_denied r = Role.anonymous r.permissions.delete(:view_time_entries) @@ -28,7 +36,7 @@ get :report assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport' end - + def test_report_all_projects_one_criteria get :report, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project'] assert_response :success @@ -53,7 +61,7 @@ assert_equal "162.90", "%.2f" % assigns(:total_hours) assert_tag :tag => 'th', :content => '2007-03-12' end - + def test_report_one_criteria get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project'] assert_response :success @@ -61,7 +69,7 @@ assert_not_nil assigns(:total_hours) assert_equal "8.65", "%.2f" % assigns(:total_hours) end - + def test_report_two_criterias get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"] assert_response :success @@ -69,7 +77,7 @@ assert_not_nil assigns(:total_hours) assert_equal "162.90", "%.2f" % assigns(:total_hours) end - + def test_report_one_day get :report, :project_id => 1, :columns => 'day', :from => "2007-03-23", :to => "2007-03-23", :criterias => ["member", "activity"] assert_response :success @@ -77,7 +85,7 @@ assert_not_nil assigns(:total_hours) assert_equal "4.25", "%.2f" % assigns(:total_hours) end - + def test_report_at_issue_level get :report, :project_id => 1, :issue_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"] assert_response :success @@ -87,7 +95,7 @@ assert_tag :form, :attributes => {:action => "/projects/ecookbook/issues/1/time_entries/report", :id => 'query_form'} end - + def test_report_custom_field_criteria get :report, :project_id => 1, :criterias => ['project', 'cf_1', 'cf_7'] assert_response :success @@ -106,7 +114,7 @@ # Second custom field column assert_tag :tag => 'th', :content => 'Billable' end - + def test_report_one_criteria_no_result get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criterias => ['project'] assert_response :success @@ -114,27 +122,177 @@ assert_not_nil assigns(:total_hours) assert_equal "0.00", "%.2f" % assigns(:total_hours) end - + def test_report_all_projects_csv_export - get :report, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criterias => ["project", "member", "activity"], :format => "csv" + get :report, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", + :criterias => ["project", "member", "activity"], :format => "csv" assert_response :success assert_equal 'text/csv', @response.content_type lines = @response.body.chomp.split("\n") # Headers - assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', lines.first + assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', + lines.first # Total row assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last end - + def test_report_csv_export - get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criterias => ["project", "member", "activity"], :format => "csv" + get :report, :project_id => 1, :columns => 'month', + :from => "2007-01-01", :to => "2007-06-30", + :criterias => ["project", "member", "activity"], :format => "csv" assert_response :success assert_equal 'text/csv', @response.content_type lines = @response.body.chomp.split("\n") # Headers - assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', lines.first + assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', + lines.first # Total row assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last end - + + def test_csv_big_5 + Setting.default_language = "zh-TW" + str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88" + str_big5 = "\xa4@\xa4\xeb" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + str_big5.force_encoding('Big5') + end + user = User.find_by_id(3) + user.firstname = str_utf8 + user.lastname = "test-lastname" + assert user.save + comments = "test_csv_big_5" + te1 = TimeEntry.create(:spent_on => '2011-11-11', + :hours => 7.3, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => comments) + + te2 = TimeEntry.find_by_comments(comments) + assert_not_nil te2 + assert_equal 7.3, te2.hours + assert_equal 3, te2.user_id + + get :report, :project_id => 1, :columns => 'day', + :from => "2011-11-11", :to => "2011-11-11", + :criterias => ["member"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + s1 = "\xa6\xa8\xad\xfb,2011-11-11,\xc1`\xadp" + s2 = "\xc1`\xadp" + if s1.respond_to?(:force_encoding) + s1.force_encoding('Big5') + s2.force_encoding('Big5') + end + assert_equal s1, lines.first + # Total row + assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1] + assert_equal "#{s2},7.30,7.30", lines[2] + + str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)" + if str_tw.respond_to?(:force_encoding) + str_tw.force_encoding('UTF-8') + end + assert_equal str_tw, l(:general_lang_name) + assert_equal 'Big5', l(:general_csv_encoding) + assert_equal ',', l(:general_csv_separator) + assert_equal '.', l(:general_csv_decimal_separator) + end + + def test_csv_cannot_convert_should_be_replaced_big_5 + Setting.default_language = "zh-TW" + str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + end + user = User.find_by_id(3) + user.firstname = str_utf8 + user.lastname = "test-lastname" + assert user.save + comments = "test_replaced" + te1 = TimeEntry.create(:spent_on => '2011-11-11', + :hours => 7.3, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => comments) + + te2 = TimeEntry.find_by_comments(comments) + assert_not_nil te2 + assert_equal 7.3, te2.hours + assert_equal 3, te2.user_id + + get :report, :project_id => 1, :columns => 'day', + :from => "2011-11-11", :to => "2011-11-11", + :criterias => ["member"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + s1 = "\xa6\xa8\xad\xfb,2011-11-11,\xc1`\xadp" + if s1.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert_equal s1, lines.first + # Total row + s2 = "" + if s2.respond_to?(:force_encoding) + s2 = "\xa5H?" + s2.force_encoding('Big5') + elsif RUBY_PLATFORM == 'java' + s2 = "??" + else + s2 = "\xa5H???" + end + assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1] + end + + def test_csv_fr + with_settings :default_language => "fr" do + str1 = "test_csv_fr" + user = User.find_by_id(3) + te1 = TimeEntry.create(:spent_on => '2011-11-11', + :hours => 7.3, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => str1) + + te2 = TimeEntry.find_by_comments(str1) + assert_not_nil te2 + assert_equal 7.3, te2.hours + assert_equal 3, te2.user_id + + get :report, :project_id => 1, :columns => 'day', + :from => "2011-11-11", :to => "2011-11-11", + :criterias => ["member"], :format => "csv" + assert_response :success + assert_equal 'text/csv', @response.content_type + lines = @response.body.chomp.split("\n") + # Headers + s1 = "Membre;2011-11-11;Total" + s2 = "Total" + if s1.respond_to?(:force_encoding) + s1.force_encoding('ISO-8859-1') + s2.force_encoding('ISO-8859-1') + end + assert_equal s1, lines.first + # Total row + assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1] + assert_equal "#{s2};7,30;7,30", lines[2] + + str_fr = "Fran\xc3\xa7ais" + if str_fr.respond_to?(:force_encoding) + str_fr.force_encoding('UTF-8') + end + assert_equal str_fr, l(:general_lang_name) + assert_equal 'ISO-8859-1', l(:general_csv_encoding) + assert_equal ';', l(:general_csv_separator) + assert_equal ',', l(:general_csv_decimal_separator) + end + end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/timelog_controller_test.rb --- a/test/functional/timelog_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/timelog_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,19 @@ class TimelogController; def rescue_action(e) raise e end; end class TimelogControllerTest < ActionController::TestCase - fixtures :projects, :enabled_modules, :roles, :members, :member_roles, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses, :custom_fields, :custom_values + fixtures :projects, :enabled_modules, :roles, :members, + :member_roles, :issues, :time_entries, :users, + :trackers, :enumerations, :issue_statuses, + :custom_fields, :custom_values + + include Redmine::I18n def setup @controller = TimelogController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end - + def test_get_new @request.session[:user_id] = 3 get :new, :project_id => 1 @@ -40,14 +45,13 @@ assert_tag :tag => 'option', :attributes => { :selected => 'selected' }, :content => 'Development' end - + def test_get_new_should_only_show_active_time_entry_activities @request.session[:user_id] = 3 get :new, :project_id => 1 assert_response :success assert_template 'edit' assert_no_tag :tag => 'option', :content => 'Inactive Activity' - end def test_get_edit_existing_time @@ -58,7 +62,7 @@ # Default activity selected assert_tag :tag => 'form', :attributes => { :action => '/projects/ecookbook/time_entries/2' } end - + def test_get_edit_with_an_existing_time_entry_with_inactive_activity te = TimeEntry.find(1) te.activity = TimeEntryActivity.find_by_name("Inactive Activity") @@ -71,7 +75,7 @@ # Blank option since nothing is pre-selected assert_tag :tag => 'option', :content => '--- Please select ---' end - + def test_post_create # TODO: should POST to issues’ time log instead of project. change form # and routing @@ -84,7 +88,7 @@ :issue_id => '1', :hours => '7.3'} assert_redirected_to :action => 'index', :project_id => 'ecookbook' - + i = Issue.find(1) t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') assert_not_nil t @@ -107,26 +111,38 @@ :spent_on => '2008-03-14', :hours => '7.3'} assert_redirected_to :action => 'index', :project_id => 'ecookbook' - + t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') assert_not_nil t assert_equal 11, t.activity_id assert_equal 7.3, t.hours assert_equal 3, t.user_id end - + + def test_create_without_log_time_permission_should_be_denied + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :log_time + post :create, :project_id => 1, + :time_entry => {:activity_id => '11', + :issue_id => '', + :spent_on => '2008-03-14', + :hours => '7.3'} + + assert_response 403 + end + def test_update entry = TimeEntry.find(1) assert_equal 1, entry.issue_id assert_equal 2, entry.user_id - + @request.session[:user_id] = 1 put :update, :id => 1, :time_entry => {:issue_id => '2', :hours => '8'} assert_redirected_to :action => 'index', :project_id => 'ecookbook' entry.reload - + assert_equal 8, entry.hours assert_equal 2, entry.issue_id assert_equal 2, entry.user_id @@ -137,7 +153,7 @@ get :bulk_edit, :ids => [1, 2] assert_response :success assert_template 'bulk_edit' - + # System wide custom field assert_tag :select, :attributes => {:name => 'time_entry[custom_field_values][10]'} end @@ -153,7 +169,7 @@ @request.session[:user_id] = 2 # update time entry activity post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9} - + assert_response 302 # check that the issues were updated assert_equal [9, 9], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.activity_id} @@ -161,9 +177,12 @@ def test_bulk_update_on_different_projects @request.session[:user_id] = 2 + # makes user a manager on the other project + Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1]) + # update time entry activity post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 } - + assert_response 302 # check that the issues were updated assert_equal [9, 9, 9], TimeEntry.find_all_by_id([1, 2, 4]).collect {|i| i.activity_id} @@ -182,7 +201,7 @@ def test_bulk_update_custom_field @request.session[:user_id] = 2 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} } - + assert_response 302 assert_equal ["0", "0"], TimeEntry.find_all_by_id([1, 2]).collect {|i| i.custom_value_for(10).value} end @@ -202,7 +221,15 @@ assert_response :redirect assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier end - + + def test_post_bulk_update_without_edit_permission_should_be_denied + @request.session[:user_id] = 2 + Role.find_by_name('Manager').remove_permission! :edit_time_entries + post :bulk_update, :ids => [1,2] + + assert_response 403 + end + def test_destroy @request.session[:user_id] = 2 delete :destroy, :id => 1 @@ -210,7 +237,7 @@ assert_equal I18n.t(:notice_successful_delete), flash[:notice] assert_nil TimeEntry.find_by_id(1) end - + def test_destroy_should_fail # simulate that this fails (e.g. due to a plugin), see #5700 TimeEntry.any_instance.expects(:destroy).returns(false) @@ -221,7 +248,7 @@ assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error] assert_not_nil TimeEntry.find_by_id(1) end - + def test_index_all_projects get :index assert_response :success @@ -231,7 +258,7 @@ assert_tag :form, :attributes => {:action => "/time_entries", :id => 'query_form'} end - + def test_index_at_project_level get :index, :project_id => 'ecookbook' assert_response :success @@ -248,7 +275,7 @@ assert_tag :form, :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} end - + def test_index_at_project_level_with_date_range get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30' assert_response :success @@ -284,7 +311,7 @@ assert_tag :form, :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} end - + def test_index_at_issue_level get :index, :issue_id => 1 assert_response :success @@ -301,7 +328,7 @@ assert_tag :form, :attributes => {:action => "/projects/ecookbook/issues/1/time_entries", :id => 'query_form'} end - + def test_index_atom_feed get :index, :project_id => 1, :format => 'atom' assert_response :success @@ -309,7 +336,7 @@ assert_not_nil assigns(:items) assert assigns(:items).first.is_a?(TimeEntry) end - + def test_index_all_projects_csv_export Setting.date_format = '%m/%d/%Y' get :index, :format => 'csv' @@ -318,7 +345,7 @@ assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n") assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n") end - + def test_index_csv_export Setting.date_format = '%m/%d/%Y' get :index, :project_id => 1, :format => 'csv' @@ -327,4 +354,157 @@ assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment,Overtime\n") assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\",\"\"\n") end + + def test_csv_big_5 + user = User.find_by_id(3) + user.language = "zh-TW" + assert user.save + str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88" + str_big5 = "\xa4@\xa4\xeb" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + str_big5.force_encoding('Big5') + end + @request.session[:user_id] = 3 + post :create, :project_id => 1, + :time_entry => {:comments => str_utf8, + # Not the default activity + :activity_id => '11', + :issue_id => '', + :spent_on => '2011-11-10', + :hours => '7.3'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + + t = TimeEntry.find_by_comments(str_utf8) + assert_not_nil t + assert_equal 11, t.activity_id + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + ar = @response.body.chomp.split("\n") + s1 = "\xa4\xe9\xb4\xc1" + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert ar[0].include?(s1) + assert ar[1].include?(str_big5) + end + + def test_csv_cannot_convert_should_be_replaced_big_5 + user = User.find_by_id(3) + user.language = "zh-TW" + assert user.save + str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85" + if str_utf8.respond_to?(:force_encoding) + str_utf8.force_encoding('UTF-8') + end + @request.session[:user_id] = 3 + post :create, :project_id => 1, + :time_entry => {:comments => str_utf8, + # Not the default activity + :activity_id => '11', + :issue_id => '', + :spent_on => '2011-11-10', + :hours => '7.3'} + assert_redirected_to :action => 'index', :project_id => 'ecookbook' + + t = TimeEntry.find_by_comments(str_utf8) + assert_not_nil t + assert_equal 11, t.activity_id + assert_equal 7.3, t.hours + assert_equal 3, t.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + ar = @response.body.chomp.split("\n") + s1 = "\xa4\xe9\xb4\xc1" + if str_utf8.respond_to?(:force_encoding) + s1.force_encoding('Big5') + end + assert ar[0].include?(s1) + s2 = ar[1].split(",")[8] + if s2.respond_to?(:force_encoding) + s3 = "\xa5H?" + s3.force_encoding('Big5') + assert_equal s3, s2 + elsif RUBY_PLATFORM == 'java' + assert_equal "??", s2 + else + assert_equal "\xa5H???", s2 + end + end + + def test_csv_tw + with_settings :default_language => "zh-TW" do + str1 = "test_csv_tw" + user = User.find_by_id(3) + te1 = TimeEntry.create(:spent_on => '2011-11-10', + :hours => 999.9, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => str1) + te2 = TimeEntry.find_by_comments(str1) + assert_not_nil te2 + assert_equal 999.9, te2.hours + assert_equal 3, te2.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + + ar = @response.body.chomp.split("\n") + s2 = ar[1].split(",")[7] + assert_equal '999.9', s2 + + str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)" + if str_tw.respond_to?(:force_encoding) + str_tw.force_encoding('UTF-8') + end + assert_equal str_tw, l(:general_lang_name) + assert_equal ',', l(:general_csv_separator) + assert_equal '.', l(:general_csv_decimal_separator) + end + end + + def test_csv_fr + with_settings :default_language => "fr" do + str1 = "test_csv_fr" + user = User.find_by_id(3) + te1 = TimeEntry.create(:spent_on => '2011-11-10', + :hours => 999.9, + :project => Project.find(1), + :user => user, + :activity => TimeEntryActivity.find_by_name('Design'), + :comments => str1) + te2 = TimeEntry.find_by_comments(str1) + assert_not_nil te2 + assert_equal 999.9, te2.hours + assert_equal 3, te2.user_id + + get :index, :project_id => 1, :format => 'csv', + :from => '2011-11-10', :to => '2011-11-10' + assert_response :success + assert_equal 'text/csv', @response.content_type + + ar = @response.body.chomp.split("\n") + s2 = ar[1].split(";")[7] + assert_equal '999,9', s2 + + str_fr = "Fran\xc3\xa7ais" + if str_fr.respond_to?(:force_encoding) + str_fr.force_encoding('UTF-8') + end + assert_equal str_fr, l(:general_lang_name) + assert_equal ';', l(:general_csv_separator) + assert_equal ',', l(:general_csv_decimal_separator) + end + end end diff -r 487d96eac004 -r 5e80956cc792 test/functional/trackers_controller_test.rb --- a/test/functional/trackers_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/trackers_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ class TrackersControllerTest < ActionController::TestCase fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields - + def setup @controller = TrackersController.new @request = ActionController::TestRequest.new @@ -31,88 +31,113 @@ User.current = nil @request.session[:user_id] = 1 # admin end - + def test_index get :index assert_response :success assert_template 'index' end - def test_get_new + def test_index_by_anonymous_should_redirect_to_login_form + @request.session[:user_id] = nil + get :index + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftrackers' + end + + def test_index_by_user_should_respond_with_406 + @request.session[:user_id] = 2 + get :index + assert_response 406 + end + + def test_new get :new assert_response :success assert_template 'new' end - def test_post_new - post :new, :tracker => { :name => 'New tracker', :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] } + def test_create + assert_difference 'Tracker.count' do + post :create, :tracker => { :name => 'New tracker', :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] } + end assert_redirected_to :action => 'index' - tracker = Tracker.find_by_name('New tracker') + tracker = Tracker.first(:order => 'id DESC') + assert_equal 'New tracker', tracker.name assert_equal [1], tracker.project_ids.sort assert_equal [1, 6], tracker.custom_field_ids assert_equal 0, tracker.workflows.count end - def test_post_new_with_workflow_copy - post :new, :tracker => { :name => 'New tracker' }, :copy_workflow_from => 1 + def test_create_new_with_workflow_copy + assert_difference 'Tracker.count' do + post :create, :tracker => { :name => 'New tracker' }, :copy_workflow_from => 1 + end assert_redirected_to :action => 'index' tracker = Tracker.find_by_name('New tracker') assert_equal 0, tracker.projects.count assert_equal Tracker.find(1).workflows.count, tracker.workflows.count end - - def test_get_edit + + def test_create_new_failure + assert_no_difference 'Tracker.count' do + post :create, :tracker => { :name => '', :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] } + end + assert_response :success + assert_template 'new' + end + + def test_edit Tracker.find(1).project_ids = [1, 3] - + get :edit, :id => 1 assert_response :success assert_template 'edit' - + assert_tag :input, :attributes => { :name => 'tracker[project_ids][]', :value => '1', :checked => 'checked' } - + assert_tag :input, :attributes => { :name => 'tracker[project_ids][]', :value => '2', :checked => nil } - + assert_tag :input, :attributes => { :name => 'tracker[project_ids][]', :value => '', :type => 'hidden'} end - def test_post_edit - post :edit, :id => 1, :tracker => { :name => 'Renamed', + def test_update + put :update, :id => 1, :tracker => { :name => 'Renamed', :project_ids => ['1', '2', ''] } assert_redirected_to :action => 'index' assert_equal [1, 2], Tracker.find(1).project_ids.sort end - def test_post_edit_without_projects - post :edit, :id => 1, :tracker => { :name => 'Renamed', + def test_update_without_projects + put :update, :id => 1, :tracker => { :name => 'Renamed', :project_ids => [''] } assert_redirected_to :action => 'index' assert Tracker.find(1).project_ids.empty? end - + def test_move_lower tracker = Tracker.find_by_position(1) - post :edit, :id => 1, :tracker => { :move_to => 'lower' } + put :update, :id => 1, :tracker => { :move_to => 'lower' } assert_equal 2, tracker.reload.position end - + def test_destroy tracker = Tracker.create!(:name => 'Destroyable') assert_difference 'Tracker.count', -1 do - post :destroy, :id => tracker.id + delete :destroy, :id => tracker.id end assert_redirected_to :action => 'index' assert_nil flash[:error] end - + def test_destroy_tracker_in_use assert_no_difference 'Tracker.count' do - post :destroy, :id => 1 + delete :destroy, :id => 1 end assert_redirected_to :action => 'index' assert_not_nil flash[:error] diff -r 487d96eac004 -r 5e80956cc792 test/functional/users_controller_test.rb --- a/test/functional/users_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/users_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -23,9 +23,9 @@ class UsersControllerTest < ActionController::TestCase include Redmine::I18n - + fixtures :users, :projects, :members, :member_roles, :roles, :auth_sources, :custom_fields, :custom_values, :groups_users - + def setup @controller = UsersController.new @request = ActionController::TestRequest.new @@ -33,7 +33,7 @@ User.current = nil @request.session[:user_id] = 1 # admin end - + def test_index get :index assert_response :success @@ -48,7 +48,7 @@ # active users only assert_nil assigns(:users).detect {|u| !u.active?} end - + def test_index_with_name_filter get :index, :name => 'john' assert_response :success @@ -58,7 +58,7 @@ assert_equal 1, users.size assert_equal 'John', users.first.firstname end - + def test_index_with_group_filter get :index, :group_id => '10' assert_response :success @@ -67,17 +67,17 @@ assert users.any? assert_equal([], (users - Group.find(10).users)) end - + def test_show @request.session[:user_id] = nil get :show, :id => 2 assert_response :success assert_template 'show' assert_not_nil assigns(:user) - + assert_tag 'li', :content => /Phone number/ end - + def test_show_should_not_display_hidden_custom_fields @request.session[:user_id] = nil UserCustomField.find_by_name('Phone number').update_attribute :visible, false @@ -85,7 +85,7 @@ assert_response :success assert_template 'show' assert_not_nil assigns(:user) - + assert_no_tag 'li', :content => /Phone number/ end @@ -105,20 +105,20 @@ get :show, :id => 5 assert_response 404 end - + def test_show_should_not_reveal_users_with_no_visible_activity_or_project @request.session[:user_id] = nil get :show, :id => 9 assert_response 404 end - + def test_show_inactive_by_admin @request.session[:user_id] = 1 get :show, :id => 5 assert_response 200 assert_not_nil assigns(:user) end - + def test_show_displays_memberships_based_on_project_visibility @request.session[:user_id] = 1 get :show, :id => 2 @@ -128,13 +128,13 @@ project_ids = memberships.map(&:project_id) assert project_ids.include?(2) #private project admin can see end - + def test_show_current_should_require_authentication @request.session[:user_id] = nil get :show, :id => 'current' assert_response 302 end - + def test_show_current @request.session[:user_id] = 2 get :show, :id => 'current' @@ -142,18 +142,18 @@ assert_template 'show' assert_equal User.find(2), assigns(:user) end - + def test_new get :new - + assert_response :success assert_template :new assert assigns(:user) end - + def test_create Setting.bcc_recipients = '1' - + assert_difference 'User.count' do assert_difference 'ActionMailer::Base.deliveries.size' do post :create, @@ -169,35 +169,35 @@ :send_information => '1' end end - + user = User.first(:order => 'id DESC') assert_redirected_to :controller => 'users', :action => 'edit', :id => user.id - + assert_equal 'John', user.firstname assert_equal 'Doe', user.lastname assert_equal 'jdoe', user.login assert_equal 'jdoe@gmail.com', user.mail assert_equal 'none', user.mail_notification assert user.check_password?('secret') - + mail = ActionMailer::Base.deliveries.last assert_not_nil mail assert_equal [user.mail], mail.bcc assert mail.body.include?('secret') end - + def test_create_with_failure assert_no_difference 'User.count' do post :create, :user => {} end - + assert_response :success assert_template 'new' end def test_edit get :edit, :id => 2 - + assert_response :success assert_template 'edit' assert_equal User.find(2), assigns(:user) @@ -219,18 +219,18 @@ assert_no_difference 'User.count' do put :update, :id => 2, :user => {:firstname => ''} end - + assert_response :success assert_template 'edit' end - + def test_update_with_group_ids_should_assign_groups put :update, :id => 2, :user => {:group_ids => ['10']} - + user = User.find(2) assert_equal [10], user.group_ids end - + def test_update_with_activation_should_send_a_notification u = User.new(:firstname => 'Foo', :lastname => 'Bar', :mail => 'foo.bar@somenet.foo', :language => 'fr') u.login = 'foo' @@ -238,7 +238,7 @@ u.save! ActionMailer::Base.deliveries.clear Setting.bcc_recipients = '1' - + put :update, :id => u.id, :user => {:status => User::STATUS_ACTIVE} assert u.reload.active? mail = ActionMailer::Base.deliveries.last @@ -246,15 +246,15 @@ assert_equal ['foo.bar@somenet.foo'], mail.bcc assert mail.body.include?(ll('fr', :notice_account_activated)) end - + def test_update_with_password_change_should_send_a_notification ActionMailer::Base.deliveries.clear Setting.bcc_recipients = '1' - + put :update, :id => 2, :user => {:password => 'newpass', :password_confirmation => 'newpass'}, :send_information => '1' u = User.find(2) assert u.check_password?('newpass') - + mail = ActionMailer::Base.deliveries.last assert_not_nil mail assert_equal [u.mail], mail.bcc @@ -272,7 +272,7 @@ assert_equal nil, u.reload.auth_source assert u.check_password?('newpass') end - + def test_destroy assert_difference 'User.count', -1 do delete :destroy, :id => 2 @@ -290,20 +290,20 @@ def test_destroy_should_be_denied_for_non_admin_users @request.session[:user_id] = 3 - + assert_no_difference 'User.count' do get :destroy, :id => 2 end assert_response 403 end - + def test_edit_membership post :edit_membership, :id => 2, :membership_id => 1, :membership => { :role_ids => [2]} assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships' assert_equal [2], Member.find(1).role_ids end - + def test_destroy_membership post :destroy_membership, :id => 2, :membership_id => 1 assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships' diff -r 487d96eac004 -r 5e80956cc792 test/functional/versions_controller_test.rb --- a/test/functional/versions_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/versions_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -23,14 +23,14 @@ class VersionsControllerTest < ActionController::TestCase fixtures :projects, :versions, :issues, :users, :roles, :members, :member_roles, :enabled_modules, :issue_statuses - + def setup @controller = VersionsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_index get :index, :project_id => 1 assert_response :success @@ -43,7 +43,7 @@ # Context menu on issues assert_select "script", :text => Regexp.new(Regexp.escape("new ContextMenu('/issues/context_menu')")) end - + def test_index_with_completed_versions get :index, :project_id => 1, :completed => 1 assert_response :success @@ -71,10 +71,10 @@ assert_response :success assert_template 'show' assert_not_nil assigns(:version) - + assert_tag :tag => 'h2', :content => /1.0/ end - + def test_create @request.session[:user_id] = 2 # manager assert_difference 'Version.count' do @@ -85,7 +85,7 @@ assert_not_nil version assert_equal 1, version.project_id end - + def test_create_from_issue_form @request.session[:user_id] = 2 # manager assert_difference 'Version.count' do @@ -97,14 +97,14 @@ assert_not_nil version assert_equal 1, version.project_id end - + def test_get_edit @request.session[:user_id] = 2 get :edit, :id => 2 assert_response :success assert_template 'edit' end - + def test_close_completed Version.update_all("status = 'open'") @request.session[:user_id] = 2 @@ -112,22 +112,22 @@ assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' assert_not_nil Version.find_by_status('closed') end - + def test_post_update @request.session[:user_id] = 2 - put :update, :id => 2, - :version => { :name => 'New version name', + put :update, :id => 2, + :version => { :name => 'New version name', :effective_date => Date.today.strftime("%Y-%m-%d")} assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' version = Version.find(2) assert_equal 'New version name', version.name assert_equal Date.today, version.effective_date end - + def test_post_update_with_validation_failure @request.session[:user_id] = 2 - put :update, :id => 2, - :version => { :name => '', + put :update, :id => 2, + :version => { :name => '', :effective_date => Date.today.strftime("%Y-%m-%d")} assert_response :success assert_template 'edit' @@ -139,13 +139,13 @@ assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' assert_nil Version.find_by_id(3) end - + def test_issue_status_by xhr :get, :status_by, :id => 2 assert_response :success assert_template '_issue_counts' end - + def test_issue_status_by_status xhr :get, :status_by, :id => 2, :status_by => 'status' assert_response :success diff -r 487d96eac004 -r 5e80956cc792 test/functional/watchers_controller_test.rb --- a/test/functional/watchers_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/watchers_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -24,20 +24,20 @@ class WatchersControllerTest < ActionController::TestCase fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers - + def setup @controller = WatchersController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_get_watch_should_be_invalid @request.session[:user_id] = 3 get :watch, :object_type => 'issue', :object_id => '1' assert_response 405 end - + def test_watch @request.session[:user_id] = 3 assert_difference('Watcher.count') do @@ -47,7 +47,7 @@ end assert Issue.find(1).watched_by?(User.find(3)) end - + def test_watch_should_be_denied_without_permission Role.find(2).remove_permission! :view_issues @request.session[:user_id] = 3 @@ -56,7 +56,7 @@ assert_response 403 end end - + def test_unwatch @request.session[:user_id] = 3 assert_difference('Watcher.count', -1) do @@ -76,7 +76,7 @@ end assert Issue.find(2).watched_by?(User.find(4)) end - + def test_remove_watcher @request.session[:user_id] = 2 assert_difference('Watcher.count', -1) do diff -r 487d96eac004 -r 5e80956cc792 test/functional/welcome_controller_test.rb --- a/test/functional/welcome_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/welcome_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,14 @@ class WelcomeControllerTest < ActionController::TestCase fixtures :projects, :news - + def setup @controller = WelcomeController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_index get :index assert_response :success @@ -39,53 +39,53 @@ assert_not_nil assigns(:projects) assert !assigns(:projects).include?(Project.find(:first, :conditions => {:is_public => false})) end - + def test_browser_language Setting.default_language = 'en' @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' get :index assert_equal :fr, @controller.current_language end - + def test_browser_language_alternate Setting.default_language = 'en' @request.env['HTTP_ACCEPT_LANGUAGE'] = 'zh-TW' get :index assert_equal :"zh-TW", @controller.current_language end - + def test_browser_language_alternate_not_valid Setting.default_language = 'en' @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr-CA' get :index assert_equal :fr, @controller.current_language end - + def test_robots get :robots assert_response :success assert_equal 'text/plain', @response.content_type assert @response.body.match(%r{^Disallow: /projects/ecookbook/issues\r?$}) end - + def test_warn_on_leaving_unsaved_turn_on user = User.find(2) user.pref.warn_on_leaving_unsaved = '1' user.pref.save! @request.session[:user_id] = 2 - + get :index assert_tag 'script', :attributes => {:type => "text/javascript"}, :content => %r{new WarnLeavingUnsaved} end - + def test_warn_on_leaving_unsaved_turn_off user = User.find(2) user.pref.warn_on_leaving_unsaved = '0' user.pref.save! @request.session[:user_id] = 2 - + get :index assert_no_tag 'script', :attributes => {:type => "text/javascript"}, diff -r 487d96eac004 -r 5e80956cc792 test/functional/wiki_controller_test.rb --- a/test/functional/wiki_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/wiki_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,7 +22,9 @@ class WikiController; def rescue_action(e) raise e end; end class WikiControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments + fixtures :projects, :users, :roles, :members, :member_roles, + :enabled_modules, :wikis, :wiki_pages, :wiki_contents, + :wiki_content_versions, :attachments def setup @controller = WikiController.new @@ -43,6 +45,13 @@ :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, :content => 'Page with an inline image' } } end + + def test_export_link + Role.anonymous.add_permission! :export_wiki_pages + get :show, :project_id => 'ecookbook' + assert_response :success + assert_tag 'a', :attributes => {:href => '/projects/ecookbook/wiki/CookBook_documentation.txt'} + end def test_show_page_with_name get :show, :project_id => 1, :id => 'Another_page' @@ -77,6 +86,38 @@ get :show, :project_id => 1, :id => 'Unexistent page' assert_response 404 end + + def test_show_should_display_section_edit_links + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Page with sections' + assert_no_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=1' + } + assert_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2' + } + assert_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=3' + } + end + + def test_show_current_version_should_display_section_edit_links + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Page with sections', :version => 3 + + assert_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2' + } + end + + def test_show_old_version_should_not_display_section_edit_links + @request.session[:user_id] = 2 + get :show, :project_id => 1, :id => 'Page with sections', :version => 2 + + assert_no_tag 'a', :attributes => { + :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2' + } + end def test_show_unexistent_page_with_edit_right @request.session[:user_id] = 2 @@ -116,6 +157,44 @@ assert_equal 'testfile.txt', page.attachments.first.filename end + def test_edit_page + @request.session[:user_id] = 2 + get :edit, :project_id => 'ecookbook', :id => 'Another_page' + + assert_response :success + assert_template 'edit' + + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => WikiPage.find_by_title('Another_page').content.text + end + + def test_edit_section + @request.session[:user_id] = 2 + get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2 + + assert_response :success + assert_template 'edit' + + page = WikiPage.find_by_title('Page_with_sections') + section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2) + + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => section + assert_tag 'input', + :attributes => { :name => 'section', :type => 'hidden', :value => '2' } + assert_tag 'input', + :attributes => { :name => 'section_hash', :type => 'hidden', :value => hash } + end + + def test_edit_invalid_section_should_respond_with_404 + @request.session[:user_id] = 2 + get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10 + + assert_response 404 + end + def test_update_page @request.session[:user_id] = 2 assert_no_difference 'WikiPage.count' do @@ -198,6 +277,83 @@ assert_equal 2, c.version end + def test_update_section + @request.session[:user_id] = 2 + page = WikiPage.find_by_title('Page_with_sections') + section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2) + text = page.content.text + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, :id => 'Page_with_sections', + :content => { + :text => "New section content", + :version => 3 + }, + :section => 2, + :section_hash => hash + end + end + end + assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections' + assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text + end + + def test_update_section_should_allow_stale_page_update + @request.session[:user_id] = 2 + page = WikiPage.find_by_title('Page_with_sections') + section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2) + text = page.content.text + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, :id => 'Page_with_sections', + :content => { + :text => "New section content", + :version => 2 # Current version is 3 + }, + :section => 2, + :section_hash => hash + end + end + end + assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections' + page.reload + assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text + assert_equal 4, page.content.version + end + + def test_update_section_should_not_allow_stale_section_update + @request.session[:user_id] = 2 + + assert_no_difference 'WikiPage.count' do + assert_no_difference 'WikiContent.count' do + assert_no_difference 'WikiContent::Version.count' do + put :update, :project_id => 1, :id => 'Page_with_sections', + :content => { + :comments => 'My comments', + :text => "Text should not be lost", + :version => 3 + }, + :section => 2, + :section_hash => Digest::MD5.hexdigest("wrong hash") + end + end + end + assert_response :success + assert_template 'edit' + assert_tag :div, + :attributes => { :class => /error/ }, + :content => /Data has been updated by another user/ + assert_tag 'textarea', + :attributes => { :name => 'content[text]' }, + :content => /Text should not be lost/ + assert_tag 'input', + :attributes => { :name => 'content[comments]', :value => 'My comments' } + end + def test_preview @request.session[:user_id] = 2 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation', @@ -250,7 +406,7 @@ get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2 assert_response :success assert_template 'annotate' - + # Line 1 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1', :sibling => { @@ -259,7 +415,7 @@ } } } - + # Line 5 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '5', :sibling => { @@ -492,6 +648,36 @@ assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } end + def test_show_pdf + @request.session[:user_id] = 2 + get :show, :project_id => 1, :format => 'pdf' + assert_response :success + assert_not_nil assigns(:page) + assert_equal 'application/pdf', @response.content_type + assert_equal 'attachment; filename="CookBook_documentation.pdf"', + @response.headers['Content-Disposition'] + end + + def test_show_html + @request.session[:user_id] = 2 + get :show, :project_id => 1, :format => 'html' + assert_response :success + assert_not_nil assigns(:page) + assert_equal 'text/html', @response.content_type + assert_equal 'attachment; filename="CookBook_documentation.html"', + @response.headers['Content-Disposition'] + end + + def test_show_txt + @request.session[:user_id] = 2 + get :show, :project_id => 1, :format => 'txt' + assert_response :success + assert_not_nil assigns(:page) + assert_equal 'text/plain', @response.content_type + assert_equal 'attachment; filename="CookBook_documentation.txt"', + @response.headers['Content-Disposition'] + end + def test_edit_unprotected_page # Non members can edit unprotected wiki pages @request.session[:user_id] = 4 diff -r 487d96eac004 -r 5e80956cc792 test/functional/wikis_controller_test.rb --- a/test/functional/wikis_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/wikis_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,14 @@ class WikisControllerTest < ActionController::TestCase fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis - + def setup @controller = WikisController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_create @request.session[:user_id] = 1 assert_nil Project.find(3).wiki @@ -40,17 +40,17 @@ assert_not_nil wiki assert_equal 'Start page', wiki.start_page end - + def test_destroy @request.session[:user_id] = 1 post :destroy, :id => 1, :confirm => 1 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'ecookbook', :tab => 'wiki' assert_nil Project.find(1).wiki end - + def test_not_found @request.session[:user_id] = 1 post :destroy, :id => 999, :confirm => 1 assert_response 404 end -end +end diff -r 487d96eac004 -r 5e80956cc792 test/functional/workflows_controller_test.rb --- a/test/functional/workflows_controller_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/functional/workflows_controller_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ class WorkflowsControllerTest < ActionController::TestCase fixtures :roles, :trackers, :workflows, :users, :issue_statuses - + def setup @controller = WorkflowsController.new @request = ActionController::TestRequest.new @@ -31,17 +31,17 @@ User.current = nil @request.session[:user_id] = 1 # admin end - + def test_index get :index assert_response :success assert_template 'index' - + count = Workflow.count(:all, :conditions => 'role_id = 1 AND tracker_id = 2') assert_tag :tag => 'a', :content => count.to_s, :attributes => { :href => '/workflows/edit?role_id=1&tracker_id=2' } end - + def test_get_edit get :edit assert_response :success @@ -49,20 +49,20 @@ assert_not_nil assigns(:roles) assert_not_nil assigns(:trackers) end - + def test_get_edit_with_role_and_tracker Workflow.delete_all Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3) Workflow.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5) - + get :edit, :role_id => 2, :tracker_id => 1 assert_response :success assert_template 'edit' - + # used status only assert_not_nil assigns(:statuses) assert_equal [2, 3, 5], assigns(:statuses).collect(&:id) - + # allowed transitions assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'issue_status[3][5][]', @@ -77,23 +77,23 @@ assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'issue_status[1][1][]' } end - + def test_get_edit_with_role_and_tracker_and_all_statuses Workflow.delete_all - + get :edit, :role_id => 2, :tracker_id => 1, :used_statuses_only => '0' assert_response :success assert_template 'edit' - + assert_not_nil assigns(:statuses) assert_equal IssueStatus.count, assigns(:statuses).size - + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'issue_status[1][1][]', :value => 'always', :checked => nil } end - + def test_post_edit post :edit, :role_id => 2, :tracker_id => 1, :issue_status => { @@ -101,12 +101,12 @@ '3' => {'1' => ['always'], '2' => ['always']} } assert_redirected_to '/workflows/edit?role_id=2&tracker_id=1' - + assert_equal 3, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) assert_not_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2}) assert_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4}) end - + def test_post_edit_with_additional_transitions post :edit, :role_id => 2, :tracker_id => 1, :issue_status => { @@ -114,9 +114,9 @@ '3' => {'1' => ['author'], '2' => ['assignee'], '4' => ['author', 'assignee']} } assert_redirected_to '/workflows/edit?role_id=2&tracker_id=1' - + assert_equal 4, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) - + w = Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 4, :new_status_id => 5}) assert ! w.author assert ! w.assignee @@ -130,32 +130,32 @@ assert w.author assert w.assignee end - + def test_clear_workflow assert Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) > 0 post :edit, :role_id => 2, :tracker_id => 1 assert_equal 0, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) end - + def test_get_copy get :copy assert_response :success assert_template 'copy' end - + def test_post_copy_one_to_one source_transitions = status_transitions(:tracker_id => 1, :role_id => 2) - + post :copy, :source_tracker_id => '1', :source_role_id => '2', :target_tracker_ids => ['3'], :target_role_ids => ['1'] assert_response 302 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1) end - + def test_post_copy_one_to_many source_transitions = status_transitions(:tracker_id => 1, :role_id => 2) - + post :copy, :source_tracker_id => '1', :source_role_id => '2', :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3'] assert_response 302 @@ -164,11 +164,11 @@ assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 3) assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 3) end - + def test_post_copy_many_to_many source_t2 = status_transitions(:tracker_id => 2, :role_id => 2) source_t3 = status_transitions(:tracker_id => 3, :role_id => 2) - + post :copy, :source_tracker_id => 'any', :source_role_id => '2', :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3'] assert_response 302 @@ -177,7 +177,7 @@ assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 3) assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 3) end - + # Returns an array of status transitions that can be compared def status_transitions(conditions) Workflow.find(:all, :conditions => conditions, diff -r 487d96eac004 -r 5e80956cc792 test/helper_testcase.rb --- a/test/helper_testcase.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/helper_testcase.rb Mon Feb 27 13:53:18 2012 +0000 @@ -25,7 +25,7 @@ # Fake url rewriter so we can test url_for @controller.url = ActionController::UrlRewriter.new @request, {} - + ActionView::Helpers::AssetTagHelper::reset_javascript_include_default end diff -r 487d96eac004 -r 5e80956cc792 test/integration/account_test.rb --- a/test/integration/account_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/account_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -31,17 +31,17 @@ get "my/page" assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fmy%2Fpage" log_user('jsmith', 'jsmith') - + get "my/account" assert_response :success - assert_template "my/account" + assert_template "my/account" end - + def test_autologin user = User.find(1) Setting.autologin = "7" Token.delete_all - + # User logs in with 'autologin' checked post '/login', :username => user.login, :password => 'admin', :autologin => 1 assert_redirected_to '/my/page' @@ -51,14 +51,14 @@ assert_equal 'autologin', token.action assert_equal user.id, session[:user_id] assert_equal token.value, cookies['autologin'] - + # Session is cleared reset! User.current = nil # Clears user's last login timestamp user.update_attribute :last_login_on, nil assert_nil user.reload.last_login_on - + # User comes back with his autologin cookie cookies[:autologin] = token.value get '/my/page' @@ -68,103 +68,103 @@ assert_not_nil user.reload.last_login_on assert user.last_login_on.utc > 10.second.ago.utc end - + def test_lost_password Token.delete_all - + get "account/lost_password" assert_response :success assert_template "account/lost_password" - + post "account/lost_password", :mail => 'jSmith@somenet.foo' assert_redirected_to "/login" - + token = Token.find(:first) assert_equal 'recovery', token.action assert_equal 'jsmith@somenet.foo', token.user.mail assert !token.expired? - + get "account/lost_password", :token => token.value assert_response :success assert_template "account/password_recovery" - + post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass' assert_redirected_to "/login" assert_equal 'Password was successfully updated.', flash[:notice] - + log_user('jsmith', 'newpass') - assert_equal 0, Token.count + assert_equal 0, Token.count end - + def test_register_with_automatic_activation Setting.self_registration = '3' - + get 'account/register' assert_response :success assert_template 'account/register' - - post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, + + post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, :password => "newpass", :password_confirmation => "newpass" assert_redirected_to '/my/account' follow_redirect! assert_response :success assert_template 'my/account' - + user = User.find_by_login('newuser') assert_not_nil user assert user.active? assert_not_nil user.last_login_on end - + def test_register_with_manual_activation Setting.self_registration = '2' - - post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, + + post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, :password => "newpass", :password_confirmation => "newpass" assert_redirected_to '/login' assert !User.find_by_login('newuser').active? end - + def test_register_with_email_activation Setting.self_registration = '1' Token.delete_all - - post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, + + post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"}, :password => "newpass", :password_confirmation => "newpass" assert_redirected_to '/login' assert !User.find_by_login('newuser').active? - + token = Token.find(:first) assert_equal 'register', token.action assert_equal 'newuser@foo.bar', token.user.mail assert !token.expired? - + get 'account/activate', :token => token.value assert_redirected_to '/login' log_user('newuser', 'newpass') end - + if Object.const_defined?(:Mocha) - + def test_onthefly_registration # disable registration Setting.self_registration = '0' AuthSource.expects(:authenticate).returns({:login => 'foo', :firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com', :auth_source_id => 66}) - + post 'account/login', :username => 'foo', :password => 'bar' assert_redirected_to '/my/page' - + user = User.find_by_login('foo') assert user.is_a?(User) assert_equal 66, user.auth_source_id assert user.hashed_password.blank? end - + def test_onthefly_registration_with_invalid_attributes # disable registration Setting.self_registration = '0' AuthSource.expects(:authenticate).returns({:login => 'foo', :lastname => 'Smith', :auth_source_id => 66}) - + post 'account/login', :username => 'foo', :password => 'bar' assert_response :success assert_template 'account/register' @@ -172,34 +172,34 @@ assert_tag :input, :attributes => { :name => 'user[lastname]', :value => 'Smith' } assert_no_tag :input, :attributes => { :name => 'user[login]' } assert_no_tag :input, :attributes => { :name => 'user[password]' } - + post 'account/register', :user => {:firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com'} assert_redirected_to '/my/account' - + user = User.find_by_login('foo') assert user.is_a?(User) assert_equal 66, user.auth_source_id assert user.hashed_password.blank? end - + def test_login_and_logout_should_clear_session get '/login' sid = session[:session_id] - + post '/login', :username => 'admin', :password => 'admin' assert_redirected_to '/my/page' assert_not_equal sid, session[:session_id], "login should reset session" assert_equal 1, session[:user_id] sid = session[:session_id] - + get '/' assert_equal sid, session[:session_id] - + get '/logout' assert_not_equal sid, session[:session_id], "logout should reset session" assert_nil session[:user_id] end - + else puts 'Mocha is missing. Skipping tests.' end diff -r 487d96eac004 -r 5e80956cc792 test/integration/admin_test.rb --- a/test/integration/admin_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/admin_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,23 +18,34 @@ require File.expand_path('../../test_helper', __FILE__) class AdminTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows def test_add_user log_user("admin", "admin") get "/users/new" assert_response :success assert_template "users/new" - post "/users/create", :user => { :login => "psmith", :firstname => "Paul", :lastname => "Smith", :mail => "psmith@somenet.foo", :language => "en", :password => "psmith09", :password_confirmation => "psmith09" } - + post "/users/create", + :user => { :login => "psmith", :firstname => "Paul", + :lastname => "Smith", :mail => "psmith@somenet.foo", + :language => "en", :password => "psmith09", + :password_confirmation => "psmith09" } + user = User.find_by_login("psmith") assert_kind_of User, user assert_redirected_to "/users/#{ user.id }/edit" - + logged_user = User.try_to_login("psmith", "psmith09") assert_kind_of User, logged_user assert_equal "Paul", logged_user.firstname - + put "users/#{user.id}", :id => user.id, :user => { :status => User::STATUS_LOCKED } assert_redirected_to "/users/#{ user.id }/edit" locked_user = User.try_to_login("psmith", "psmith09") @@ -42,7 +53,9 @@ end test "Add a user as an anonymous user should fail" do - post '/users/create', :user => { :login => 'psmith', :firstname => 'Paul'}, :password => "psmith09", :password_confirmation => "psmith09" + post '/users/create', + :user => { :login => 'psmith', :firstname => 'Paul'}, + :password => "psmith09", :password_confirmation => "psmith09" assert_response :redirect assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fusers" end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/attachments_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/attachments_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,86 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::AttachmentsTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :attachments + + def setup + Setting.rest_api_enabled = '1' + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + end + + context "/attachments/:id" do + context "GET" do + should "return the attachment" do + get '/attachments/7.xml', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'attachment', + :child => { + :tag => 'id', + :content => '7', + :sibling => { + :tag => 'filename', + :content => 'archive.zip', + :sibling => { + :tag => 'content_url', + :content => 'http://www.example.com/attachments/download/7/archive.zip' + } + } + } + end + + should "deny access without credentials" do + get '/attachments/7.xml' + assert_response 401 + set_tmp_attachments_directory + end + end + end + + context "/attachments/download/:id/:filename" do + context "GET" do + should "return the attachment content" do + get '/attachments/download/7/archive.zip', + {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/octet-stream', @response.content_type + set_tmp_attachments_directory + end + + should "deny access without credentials" do + get '/attachments/download/7/archive.zip' + assert_response 302 + set_tmp_attachments_directory + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/disabled_rest_api_test.rb --- a/test/integration/api_test/disabled_rest_api_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/disabled_rest_api_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,14 @@ require File.expand_path('../../../test_helper', __FILE__) class ApiTest::DisabledRestApiTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows def setup Setting.rest_api_enabled = '0' @@ -12,7 +19,7 @@ Setting.rest_api_enabled = '1' Setting.login_required = '0' end - + # Using the NewsController because it's a simple API. context "get /news with the API disabled" do @@ -23,7 +30,7 @@ @token = Token.generate!(:user => @user, :action => 'api') get "/news.xml?key=#{@token.value}" end - + should_respond_with :unauthorized should_respond_with_content_type :xml should "not login as the user" do @@ -37,7 +44,7 @@ @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password') get "/news.xml", nil, :authorization => @authorization end - + should_respond_with :unauthorized should_respond_with_content_type :xml should "not login as the user" do @@ -52,7 +59,7 @@ @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X') get "/news.xml", nil, :authorization => @authorization end - + should_respond_with :unauthorized should_respond_with_content_type :xml should "not login as the user" do @@ -68,7 +75,7 @@ @token = Token.generate!(:user => @user, :action => 'api') get "/news.json?key=#{@token.value}" end - + should_respond_with :unauthorized should_respond_with_content_type :json should "not login as the user" do @@ -82,7 +89,7 @@ @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password') get "/news.json", nil, :authorization => @authorization end - + should_respond_with :unauthorized should_respond_with_content_type :json should "not login as the user" do @@ -104,7 +111,7 @@ assert_equal User.anonymous, User.current end end - - end + + end end end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/http_basic_login_test.rb --- a/test/integration/api_test/http_basic_login_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/http_basic_login_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,14 @@ require File.expand_path('../../../test_helper', __FILE__) class ApiTest::HttpBasicLoginTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows def setup Setting.rest_api_enabled = '1' @@ -12,7 +19,7 @@ Setting.rest_api_enabled = '0' Setting.login_required = '0' end - + # Using the NewsController because it's a simple API. context "get /news" do setup do diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/http_basic_login_with_api_token_test.rb --- a/test/integration/api_test/http_basic_login_with_api_token_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/http_basic_login_with_api_token_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,14 @@ require File.expand_path('../../../test_helper', __FILE__) class ApiTest::HttpBasicLoginWithApiTokenTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows def setup Setting.rest_api_enabled = '1' @@ -12,7 +19,7 @@ Setting.rest_api_enabled = '0' Setting.login_required = '0' end - + # Using the NewsController because it's a simple API. context "get /news" do diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/issue_categories_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/issue_categories_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,127 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::IssueCategoriesTest < ActionController::IntegrationTest + fixtures :projects, :users, :issue_categories, :issues, + :roles, + :member_roles, + :members, + :enabled_modules + + def setup + Setting.rest_api_enabled = '1' + end + + context "GET /projects/:project_id/issue_categories.xml" do + should "return issue categories" do + get '/projects/1/issue_categories.xml', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'issue_categories', + :child => {:tag => 'issue_category', :child => {:tag => 'id', :content => '2'}} + end + end + + context "GET /issue_categories/2.xml" do + should "return requested issue category" do + get '/issue_categories/2.xml', {}, :authorization => credentials('jsmith') + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'issue_category', + :child => {:tag => 'id', :content => '2'} + end + end + + context "POST /projects/:project_id/issue_categories.xml" do + should "return create issue category" do + assert_difference 'IssueCategory.count' do + post '/projects/1/issue_categories.xml', {:issue_category => {:name => 'API'}}, :authorization => credentials('jsmith') + end + assert_response :created + assert_equal 'application/xml', @response.content_type + + category = IssueCategory.first(:order => 'id DESC') + assert_equal 'API', category.name + assert_equal 1, category.project_id + end + + context "with invalid parameters" do + should "return errors" do + assert_no_difference 'IssueCategory.count' do + post '/projects/1/issue_categories.xml', {:issue_category => {:name => ''}}, :authorization => credentials('jsmith') + end + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + + assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"} + end + end + end + + context "PUT /issue_categories/2.xml" do + context "with valid parameters" do + should "update issue category" do + assert_no_difference 'IssueCategory.count' do + put '/issue_categories/2.xml', {:issue_category => {:name => 'API Update'}}, :authorization => credentials('jsmith') + end + assert_response :ok + assert_equal 'API Update', IssueCategory.find(2).name + end + end + + context "with invalid parameters" do + should "return errors" do + assert_no_difference 'IssueCategory.count' do + put '/issue_categories/2.xml', {:issue_category => {:name => ''}}, :authorization => credentials('jsmith') + end + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + + assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"} + end + end + end + + context "DELETE /issue_categories/1.xml" do + should "destroy issue categories" do + assert_difference 'IssueCategory.count', -1 do + delete '/issue_categories/1.xml', {}, :authorization => credentials('jsmith') + end + assert_response :ok + assert_nil IssueCategory.find_by_id(1) + end + + should "reassign issues with :reassign_to_id param" do + issue_count = Issue.count(:conditions => {:category_id => 1}) + assert issue_count > 0 + + assert_difference 'IssueCategory.count', -1 do + assert_difference 'Issue.count(:conditions => {:category_id => 2})', 3 do + delete '/issue_categories/1.xml', {:reassign_to_id => 2}, :authorization => credentials('jsmith') + end + end + assert_response :ok + assert_nil IssueCategory.find_by_id(1) + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/issue_relations_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/issue_relations_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,110 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::IssueRelationsTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :issue_relations + + def setup + Setting.rest_api_enabled = '1' + end + + context "/issues/:issue_id/relations" do + context "GET" do + should "return issue relations" do + get '/issues/9/relations.xml', {}, :authorization => credentials('jsmith') + + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag :tag => 'relations', + :attributes => { :type => 'array' }, + :child => { + :tag => 'relation', + :child => { + :tag => 'id', + :content => '1' + } + } + end + end + + context "POST" do + should "create a relation" do + assert_difference('IssueRelation.count') do + post '/issues/2/relations.xml', {:relation => {:issue_to_id => 7, :relation_type => 'relates'}}, :authorization => credentials('jsmith') + end + + relation = IssueRelation.first(:order => 'id DESC') + assert_equal 2, relation.issue_from_id + assert_equal 7, relation.issue_to_id + assert_equal 'relates', relation.relation_type + + assert_response :created + assert_equal 'application/xml', @response.content_type + assert_tag 'relation', :child => {:tag => 'id', :content => relation.id.to_s} + end + + context "with failure" do + should "return the errors" do + assert_no_difference('IssueRelation.count') do + post '/issues/2/relations.xml', {:relation => {:issue_to_id => 7, :relation_type => 'foo'}}, :authorization => credentials('jsmith') + end + + assert_response :unprocessable_entity + assert_tag :errors, :child => {:tag => 'error', :content => 'relation_type is not included in the list'} + end + end + end + end + + context "/relations/:id" do + context "GET" do + should "return the relation" do + get '/relations/2.xml', {}, :authorization => credentials('jsmith') + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag 'relation', :child => {:tag => 'id', :content => '2'} + end + end + + context "DELETE" do + should "delete the relation" do + assert_difference('IssueRelation.count', -1) do + delete '/relations/2.xml', {}, :authorization => credentials('jsmith') + end + + assert_response :ok + assert_nil IssueRelation.find_by_id(2) + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/issue_statuses_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/issue_statuses_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::IssueStatusesTest < ActionController::IntegrationTest + fixtures :issue_statuses + + def setup + Setting.rest_api_enabled = '1' + end + + context "/issue_statuses" do + context "GET" do + + should "return issue statuses" do + get '/issue_statuses.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'issue_statuses', + :attributes => {:type => 'array'}, + :child => { + :tag => 'issue_status', + :child => { + :tag => 'id', + :content => '2', + :sibling => { + :tag => 'name', + :content => 'Assigned' + } + } + } + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/issues_test.rb --- a/test/integration/api_test/issues_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/issues_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -40,20 +40,21 @@ :time_entries, :journals, :journal_details, - :queries + :queries, + :attachments def setup Setting.rest_api_enabled = '1' end - context "/index.xml" do + context "/issues" do # Use a private project to make sure auth is really working and not just # only showing public issues. should_allow_api_authentication(:get, "/projects/private-child/issues.xml") - + should "contain metadata" do get '/issues.xml' - + assert_tag :tag => 'issues', :attributes => { :type => 'array', @@ -62,11 +63,11 @@ :offset => 0 } end - + context "with offset and limit" do should "use the params" do get '/issues.xml?offset=2&limit=3' - + assert_equal 3, assigns(:limit) assert_equal 2, assigns(:offset) assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}} @@ -76,7 +77,7 @@ context "with nometa param" do should "not contain metadata" do get '/issues.xml?nometa=1' - + assert_tag :tag => 'issues', :attributes => { :type => 'array', @@ -90,7 +91,7 @@ context "with nometa header" do should "not contain metadata" do get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'} - + assert_tag :tag => 'issues', :attributes => { :type => 'array', @@ -100,6 +101,63 @@ } end end + + context "with relations" do + should "display relations" do + get '/issues.xml?include=relations' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag 'relations', + :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}}, + :children => {:count => 1}, + :child => { + :tag => 'relation', + :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'} + } + assert_tag 'relations', + :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}}, + :children => {:count => 0} + end + end + + context "with invalid query params" do + should "return errors" do + get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}} + + assert_response :unprocessable_entity + assert_equal 'application/xml', @response.content_type + assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"} + end + end + + context "with custom field filter" do + should "show only issues with the custom field value" do + get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}} + + expected_ids = Issue.visible.all( + :include => :custom_values, + :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id) + + assert_select 'issues > issue > id', :count => expected_ids.count do |ids| + ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } + end + end + end + + context "with custom field filter (shorthand method)" do + should "show only issues with the custom field value" do + get '/issues.xml', { :cf_1 => 'MySQL' } + + expected_ids = Issue.visible.all( + :include => :custom_values, + :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id) + + assert_select 'issues > issue > id', :count => expected_ids.count do |ids| + ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } + end + end + end end context "/index.json" do @@ -107,19 +165,18 @@ end context "/index.xml with filter" do - should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5") - should "show only issues with the status_id" do get '/issues.xml?status_id=5' - assert_tag :tag => 'issues', - :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}), - :only => { :tag => 'issue' } } + + expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id) + + assert_select 'issues > issue > id', :count => expected_ids.count do |ids| + ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } + end end end context "/index.json with filter" do - should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5") - should "show only issues with the status_id" do get '/issues.json?status_id=5' @@ -139,13 +196,13 @@ context "/issues/6.json" do should_allow_api_authentication(:get, "/issues/6.json") end - + context "GET /issues/:id" do context "with journals" do context ".xml" do should "display journals" do get '/issues/1.xml?include=journals' - + assert_tag :tag => 'issue', :child => { :tag => 'journals', @@ -174,13 +231,13 @@ end end end - + context "with custom fields" do context ".xml" do should "display custom fields" do get '/issues/3.xml' - - assert_tag :tag => 'issue', + + assert_tag :tag => 'issue', :child => { :tag => 'custom_fields', :attributes => { :type => 'array' }, @@ -193,26 +250,51 @@ } } } - + assert_nothing_raised do Hash.from_xml(response.body).to_xml end end end end - + + context "with attachments" do + context ".xml" do + should "display attachments" do + get '/issues/3.xml?include=attachments' + + assert_tag :tag => 'issue', + :child => { + :tag => 'attachments', + :children => {:count => 5}, + :child => { + :tag => 'attachment', + :child => { + :tag => 'filename', + :content => 'source.rb', + :sibling => { + :tag => 'content_url', + :content => 'http://www.example.com/attachments/download/4/source.rb' + } + } + } + } + end + end + end + context "with subtasks" do setup do @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1) @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1) @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id) end - + context ".xml" do should "display children" do get '/issues/1.xml?include=children' - - assert_tag :tag => 'issue', + + assert_tag :tag => 'issue', :child => { :tag => 'children', :children => {:count => 2}, @@ -234,11 +316,11 @@ } } end - + context ".json" do should "display children" do get '/issues/1.json?include=children' - + json = ActiveSupport::JSON.decode(response.body) assert_equal([ { @@ -264,25 +346,20 @@ assert_difference('Issue.count') do post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith') end - + issue = Issue.first(:order => 'id DESC') assert_equal 1, issue.project_id assert_equal 2, issue.tracker_id assert_equal 3, issue.status_id assert_equal 'API test', issue.subject - + assert_response :created assert_equal 'application/xml', @response.content_type assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s} end end - + context "POST /issues.xml with failure" do - should_allow_api_authentication(:post, - '/issues.xml', - {:issue => {:project_id => 1}}, - {:success_code => :unprocessable_entity}) - should "have an errors tag" do assert_no_difference('Issue.count') do post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith') @@ -302,22 +379,17 @@ assert_difference('Issue.count') do post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith') end - + issue = Issue.first(:order => 'id DESC') assert_equal 1, issue.project_id assert_equal 2, issue.tracker_id assert_equal 3, issue.status_id assert_equal 'API test', issue.subject end - + end - + context "POST /issues.json with failure" do - should_allow_api_authentication(:post, - '/issues.json', - {:issue => {:project_id => 1}}, - {:success_code => :unprocessable_entity}) - should "have an errors element" do assert_no_difference('Issue.count') do post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith') @@ -334,7 +406,7 @@ @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}} @headers = { :authorization => credentials('jsmith') } end - + should_allow_api_authentication(:put, '/issues/6.xml', {:issue => {:subject => 'API update', :notes => 'A new note'}}, @@ -354,48 +426,43 @@ should "add the note to the journal" do put '/issues/6.xml', @parameters, @headers - + journal = Journal.last assert_equal "A new note", journal.notes end should "update the issue" do put '/issues/6.xml', @parameters, @headers - + issue = Issue.find(6) assert_equal "API update", issue.subject end - + end - + context "PUT /issues/3.xml with custom fields" do setup do @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}} @headers = { :authorization => credentials('jsmith') } end - + should "update custom fields" do assert_no_difference('Issue.count') do put '/issues/3.xml', @parameters, @headers end - + issue = Issue.find(3) assert_equal '150', issue.custom_value_for(2).value assert_equal 'PostgreSQL', issue.custom_value_for(1).value end end - + context "PUT /issues/6.xml with failed update" do setup do @parameters = {:issue => {:subject => ''}} @headers = { :authorization => credentials('jsmith') } end - should_allow_api_authentication(:put, - '/issues/6.xml', - {:issue => {:subject => ''}}, # Missing subject should fail - {:success_code => :unprocessable_entity}) - should "not create a new issue" do assert_no_difference('Issue.count') do put '/issues/6.xml', @parameters, @headers @@ -420,7 +487,7 @@ @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}} @headers = { :authorization => credentials('jsmith') } end - + should_allow_api_authentication(:put, '/issues/6.json', {:issue => {:subject => 'API update', :notes => 'A new note'}}, @@ -440,31 +507,26 @@ should "add the note to the journal" do put '/issues/6.json', @parameters, @headers - + journal = Journal.last assert_equal "A new note", journal.notes end should "update the issue" do put '/issues/6.json', @parameters, @headers - + issue = Issue.find(6) assert_equal "API update", issue.subject end - + end - + context "PUT /issues/6.json with failed update" do setup do @parameters = {:issue => {:subject => ''}} @headers = { :authorization => credentials('jsmith') } end - should_allow_api_authentication(:put, - '/issues/6.json', - {:issue => {:subject => ''}}, # Missing subject should fail - {:success_code => :unprocessable_entity}) - should "not create a new issue" do assert_no_difference('Issue.count') do put '/issues/6.json', @parameters, @headers @@ -495,7 +557,7 @@ assert_difference('Issue.count',-1) do delete '/issues/6.xml', {}, :authorization => credentials('jsmith') end - + assert_nil Issue.find_by_id(6) end end @@ -510,7 +572,7 @@ assert_difference('Issue.count',-1) do delete '/issues/6.json', {}, :authorization => credentials('jsmith') end - + assert_nil Issue.find_by_id(6) end end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/news_test.rb --- a/test/integration/api_test/news_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/news_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,7 +18,15 @@ require File.expand_path('../../../test_helper', __FILE__) require 'pp' class ApiTest::NewsTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :news def setup Setting.rest_api_enabled = '1' @@ -28,7 +36,7 @@ context ".xml" do should "return news" do get '/news.xml' - + assert_tag :tag => 'news', :attributes => {:type => 'array'}, :child => { @@ -40,11 +48,11 @@ } end end - + context ".json" do should "return news" do get '/news.json' - + json = ActiveSupport::JSON.decode(response.body) assert_kind_of Hash, json assert_kind_of Array, json['news'] @@ -57,10 +65,10 @@ context "GET /projects/:project_id/news" do context ".xml" do should_allow_api_authentication(:get, "/projects/onlinestore/news.xml") - + should "return news" do get '/projects/ecookbook/news.xml' - + assert_tag :tag => 'news', :attributes => {:type => 'array'}, :child => { @@ -72,13 +80,13 @@ } end end - + context ".json" do should_allow_api_authentication(:get, "/projects/onlinestore/news.json") - + should "return news" do get '/projects/ecookbook/news.json' - + json = ActiveSupport::JSON.decode(response.body) assert_kind_of Hash, json assert_kind_of Array, json['news'] @@ -87,7 +95,7 @@ end end end - + def credentials(user, password=nil) ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/projects_test.rb --- a/test/integration/api_test/projects_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/projects_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -20,19 +20,20 @@ class ApiTest::ProjectsTest < ActionController::IntegrationTest fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, - :attachments, :custom_fields, :custom_values, :time_entries + :attachments, :custom_fields, :custom_values, :time_entries, :issue_categories def setup Setting.rest_api_enabled = '1' + set_tmp_attachments_directory end - + context "GET /projects" do context ".xml" do should "return projects" do get '/projects.xml' assert_response :success assert_equal 'application/xml', @response.content_type - + assert_tag :tag => 'projects', :child => {:tag => 'project', :child => {:tag => 'id', :content => '1'}} end @@ -43,7 +44,7 @@ get '/projects.json' assert_response :success assert_equal 'application/json', @response.content_type - + json = ActiveSupport::JSON.decode(response.body) assert_kind_of Hash, json assert_kind_of Array, json['projects'] @@ -52,46 +53,81 @@ end end end - + context "GET /projects/:id" do context ".xml" do # TODO: A private project is needed because should_allow_api_authentication # actually tests that authentication is *required*, not just allowed should_allow_api_authentication(:get, "/projects/2.xml") - + should "return requested project" do get '/projects/1.xml' assert_response :success assert_equal 'application/xml', @response.content_type - + assert_tag :tag => 'project', :child => {:tag => 'id', :content => '1'} assert_tag :tag => 'custom_field', :attributes => {:name => 'Development status'}, :content => 'Stable' + + assert_no_tag 'trackers' + assert_no_tag 'issue_categories' end - + context "with hidden custom fields" do setup do ProjectCustomField.find_by_name('Development status').update_attribute :visible, false end - + should "not display hidden custom fields" do get '/projects/1.xml' assert_response :success assert_equal 'application/xml', @response.content_type - + assert_no_tag 'custom_field', :attributes => {:name => 'Development status'} end end + + should "return categories with include=issue_categories" do + get '/projects/1.xml?include=issue_categories' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag 'issue_categories', + :attributes => {:type => 'array'}, + :child => { + :tag => 'issue_category', + :attributes => { + :id => '2', + :name => 'Recipes' + } + } + end + + should "return trackers with include=trackers" do + get '/projects/1.xml?include=trackers' + assert_response :success + assert_equal 'application/xml', @response.content_type + + assert_tag 'trackers', + :attributes => {:type => 'array'}, + :child => { + :tag => 'tracker', + :attributes => { + :id => '2', + :name => 'Feature request' + } + } + end end context ".json" do should_allow_api_authentication(:get, "/projects/2.json") - + should "return requested project" do get '/projects/1.json' - + json = ActiveSupport::JSON.decode(response.body) assert_kind_of Hash, json assert_kind_of Hash, json['project'] @@ -99,61 +135,61 @@ end end end - + context "POST /projects" do context "with valid parameters" do setup do Setting.default_projects_modules = ['issue_tracking', 'repository'] @parameters = {:project => {:name => 'API test', :identifier => 'api-test'}} end - + context ".xml" do should_allow_api_authentication(:post, '/projects.xml', {:project => {:name => 'API test', :identifier => 'api-test'}}, {:success_code => :created}) - - + + should "create a project with the attributes" do assert_difference('Project.count') do post '/projects.xml', @parameters, :authorization => credentials('admin') end - + project = Project.first(:order => 'id DESC') assert_equal 'API test', project.name assert_equal 'api-test', project.identifier assert_equal ['issue_tracking', 'repository'], project.enabled_module_names.sort assert_equal Tracker.all.size, project.trackers.size - + assert_response :created assert_equal 'application/xml', @response.content_type assert_tag 'project', :child => {:tag => 'id', :content => project.id.to_s} end - + should "accept enabled_module_names attribute" do @parameters[:project].merge!({:enabled_module_names => ['issue_tracking', 'news', 'time_tracking']}) - + assert_difference('Project.count') do post '/projects.xml', @parameters, :authorization => credentials('admin') end - + project = Project.first(:order => 'id DESC') assert_equal ['issue_tracking', 'news', 'time_tracking'], project.enabled_module_names.sort end - + should "accept tracker_ids attribute" do @parameters[:project].merge!({:tracker_ids => [1, 3]}) - + assert_difference('Project.count') do post '/projects.xml', @parameters, :authorization => credentials('admin') end - + project = Project.first(:order => 'id DESC') assert_equal [1, 3], project.trackers.map(&:id).sort end end end - + context "with invalid parameters" do setup do @parameters = {:project => {:name => 'API test'}} @@ -164,7 +200,7 @@ assert_no_difference('Project.count') do post '/projects.xml', @parameters, :authorization => credentials('admin') end - + assert_response :unprocessable_entity assert_equal 'application/xml', @response.content_type assert_tag 'errors', :child => {:tag => 'error', :content => "Identifier can't be blank"} @@ -172,19 +208,19 @@ end end end - + context "PUT /projects/:id" do context "with valid parameters" do setup do @parameters = {:project => {:name => 'API update'}} end - + context ".xml" do should_allow_api_authentication(:put, '/projects/2.xml', {:project => {:name => 'API update'}}, {:success_code => :ok}) - + should "update the project" do assert_no_difference 'Project.count' do put '/projects/2.xml', @parameters, :authorization => credentials('jsmith') @@ -194,10 +230,10 @@ project = Project.find(2) assert_equal 'API update', project.name end - + should "accept enabled_module_names attribute" do @parameters[:project].merge!({:enabled_module_names => ['issue_tracking', 'news', 'time_tracking']}) - + assert_no_difference 'Project.count' do put '/projects/2.xml', @parameters, :authorization => credentials('admin') end @@ -205,10 +241,10 @@ project = Project.find(2) assert_equal ['issue_tracking', 'news', 'time_tracking'], project.enabled_module_names.sort end - + should "accept tracker_ids attribute" do @parameters[:project].merge!({:tracker_ids => [1, 3]}) - + assert_no_difference 'Project.count' do put '/projects/2.xml', @parameters, :authorization => credentials('admin') end @@ -218,18 +254,18 @@ end end end - + context "with invalid parameters" do setup do @parameters = {:project => {:name => ''}} end - + context ".xml" do should "return errors" do assert_no_difference('Project.count') do put '/projects/2.xml', @parameters, :authorization => credentials('admin') end - + assert_response :unprocessable_entity assert_equal 'application/xml', @response.content_type assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"} @@ -237,14 +273,14 @@ end end end - + context "DELETE /projects/:id" do context ".xml" do should_allow_api_authentication(:delete, '/projects/2.xml', {}, {:success_code => :ok}) - + should "delete the project" do assert_difference('Project.count',-1) do delete '/projects/2.xml', {}, :authorization => credentials('admin') @@ -254,7 +290,7 @@ end end end - + def credentials(user, password=nil) ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/queries_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/queries_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,63 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::QueriesTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :queries + + def setup + Setting.rest_api_enabled = '1' + end + + context "/queries" do + context "GET" do + + should "return queries" do + get '/queries.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'queries', + :attributes => {:type => 'array'}, + :child => { + :tag => 'query', + :child => { + :tag => 'id', + :content => '4', + :sibling => { + :tag => 'name', + :content => 'Public query for all projects' + } + } + } + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/time_entries_test.rb --- a/test/integration/api_test/time_entries_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/time_entries_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,12 +18,20 @@ require File.expand_path('../../../test_helper', __FILE__) class ApiTest::TimeEntriesTest < ActionController::IntegrationTest - fixtures :all - + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :time_entries + def setup Setting.rest_api_enabled = '1' end - + context "GET /time_entries.xml" do should "return time entries" do get '/time_entries.xml', {}, :authorization => credentials('jsmith') @@ -32,7 +40,7 @@ assert_tag :tag => 'time_entries', :child => {:tag => 'time_entry', :child => {:tag => 'id', :content => '2'}} end - + context "with limit" do should "return limited results" do get '/time_entries.xml?limit=2', {}, :authorization => credentials('jsmith') @@ -43,7 +51,7 @@ end end end - + context "GET /time_entries/2.xml" do should "return requested time entry" do get '/time_entries/2.xml', {}, :authorization => credentials('jsmith') @@ -53,7 +61,7 @@ :child => {:tag => 'id', :content => '2'} end end - + context "POST /time_entries.xml" do context "with issue_id" do should "return create time entry" do @@ -62,7 +70,7 @@ end assert_response :created assert_equal 'application/xml', @response.content_type - + entry = TimeEntry.first(:order => 'id DESC') assert_equal 'jsmith', entry.user.login assert_equal Issue.find(1), entry.issue @@ -72,7 +80,7 @@ assert_equal TimeEntryActivity.find(11), entry.activity end end - + context "with project_id" do should "return create time entry" do assert_difference 'TimeEntry.count' do @@ -80,7 +88,7 @@ end assert_response :created assert_equal 'application/xml', @response.content_type - + entry = TimeEntry.first(:order => 'id DESC') assert_equal 'jsmith', entry.user.login assert_nil entry.issue @@ -90,7 +98,7 @@ assert_equal TimeEntryActivity.find(11), entry.activity end end - + context "with invalid parameters" do should "return errors" do assert_no_difference 'TimeEntry.count' do @@ -103,7 +111,7 @@ end end end - + context "PUT /time_entries/2.xml" do context "with valid parameters" do should "update time entry" do @@ -127,7 +135,7 @@ end end end - + context "DELETE /time_entries/2.xml" do should "destroy time entry" do assert_difference 'TimeEntry.count', -1 do @@ -137,7 +145,7 @@ assert_nil TimeEntry.find_by_id(2) end end - + def credentials(user, password=nil) ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/token_authentication_test.rb --- a/test/integration/api_test/token_authentication_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/token_authentication_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,14 @@ require File.expand_path('../../../test_helper', __FILE__) class ApiTest::TokenAuthenticationTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows def setup Setting.rest_api_enabled = '1' @@ -12,7 +19,7 @@ Setting.rest_api_enabled = '0' Setting.login_required = '0' end - + # Using the NewsController because it's a simple API. context "get /news" do context "in :xml format" do diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/trackers_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/trackers_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,51 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::TrackersTest < ActionController::IntegrationTest + fixtures :trackers + + def setup + Setting.rest_api_enabled = '1' + end + + context "/trackers" do + context "GET" do + + should "return trackers" do + get '/trackers.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'trackers', + :attributes => {:type => 'array'}, + :child => { + :tag => 'tracker', + :child => { + :tag => 'id', + :content => '2', + :sibling => { + :tag => 'name', + :content => 'Feature request' + } + } + } + end + end + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/users_test.rb --- a/test/integration/api_test/users_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/api_test/users_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -33,7 +33,7 @@ context ".xml" do should "return requested user" do get '/users/2.xml' - + assert_tag :tag => 'user', :child => {:tag => 'id', :content => '2'} end @@ -42,7 +42,7 @@ context ".json" do should "return requested user" do get '/users/2.json' - + json = ActiveSupport::JSON.decode(response.body) assert_kind_of Hash, json assert_kind_of Hash, json['user'] @@ -50,18 +50,18 @@ end end end - + context "GET /users/current" do context ".xml" do should "require authentication" do get '/users/current.xml' - + assert_response 401 end - + should "return current user" do get '/users/current.xml', {}, :authorization => credentials('jsmith') - + assert_tag :tag => 'user', :child => {:tag => 'id', :content => '2'} end @@ -73,18 +73,18 @@ setup do @parameters = {:user => {:login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname', :mail => 'foo@example.net', :password => 'secret', :mail_notification => 'only_assigned'}} end - + context ".xml" do should_allow_api_authentication(:post, '/users.xml', {:user => {:login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname', :mail => 'foo@example.net', :password => 'secret'}}, {:success_code => :created}) - + should "create a user with the attributes" do assert_difference('User.count') do post '/users.xml', @parameters, :authorization => credentials('admin') end - + user = User.first(:order => 'id DESC') assert_equal 'foo', user.login assert_equal 'Firstname', user.firstname @@ -93,31 +93,31 @@ assert_equal 'only_assigned', user.mail_notification assert !user.admin? assert user.check_password?('secret') - + assert_response :created assert_equal 'application/xml', @response.content_type assert_tag 'user', :child => {:tag => 'id', :content => user.id.to_s} end end - + context ".json" do should_allow_api_authentication(:post, '/users.json', {:user => {:login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname', :mail => 'foo@example.net'}}, {:success_code => :created}) - + should "create a user with the attributes" do assert_difference('User.count') do post '/users.json', @parameters, :authorization => credentials('admin') end - + user = User.first(:order => 'id DESC') assert_equal 'foo', user.login assert_equal 'Firstname', user.firstname assert_equal 'Lastname', user.lastname assert_equal 'foo@example.net', user.mail assert !user.admin? - + assert_response :created assert_equal 'application/json', @response.content_type json = ActiveSupport::JSON.decode(response.body) @@ -127,30 +127,30 @@ end end end - + context "with invalid parameters" do setup do @parameters = {:user => {:login => 'foo', :lastname => 'Lastname', :mail => 'foo'}} end - + context ".xml" do should "return errors" do assert_no_difference('User.count') do post '/users.xml', @parameters, :authorization => credentials('admin') end - + assert_response :unprocessable_entity assert_equal 'application/xml', @response.content_type assert_tag 'errors', :child => {:tag => 'error', :content => "First name can't be blank"} end end - + context ".json" do should "return errors" do assert_no_difference('User.count') do post '/users.json', @parameters, :authorization => credentials('admin') end - + assert_response :unprocessable_entity assert_equal 'application/json', @response.content_type json = ActiveSupport::JSON.decode(response.body) @@ -167,75 +167,75 @@ setup do @parameters = {:user => {:login => 'jsmith', :firstname => 'John', :lastname => 'Renamed', :mail => 'jsmith@somenet.foo'}} end - + context ".xml" do should_allow_api_authentication(:put, '/users/2.xml', {:user => {:login => 'jsmith', :firstname => 'John', :lastname => 'Renamed', :mail => 'jsmith@somenet.foo'}}, {:success_code => :ok}) - + should "update user with the attributes" do assert_no_difference('User.count') do put '/users/2.xml', @parameters, :authorization => credentials('admin') end - + user = User.find(2) assert_equal 'jsmith', user.login assert_equal 'John', user.firstname assert_equal 'Renamed', user.lastname assert_equal 'jsmith@somenet.foo', user.mail assert !user.admin? - + assert_response :ok end end - + context ".json" do should_allow_api_authentication(:put, '/users/2.json', {:user => {:login => 'jsmith', :firstname => 'John', :lastname => 'Renamed', :mail => 'jsmith@somenet.foo'}}, {:success_code => :ok}) - + should "update user with the attributes" do assert_no_difference('User.count') do put '/users/2.json', @parameters, :authorization => credentials('admin') end - + user = User.find(2) assert_equal 'jsmith', user.login assert_equal 'John', user.firstname assert_equal 'Renamed', user.lastname assert_equal 'jsmith@somenet.foo', user.mail assert !user.admin? - + assert_response :ok end end end - + context "with invalid parameters" do setup do @parameters = {:user => {:login => 'jsmith', :firstname => '', :lastname => 'Lastname', :mail => 'foo'}} end - + context ".xml" do should "return errors" do assert_no_difference('User.count') do put '/users/2.xml', @parameters, :authorization => credentials('admin') end - + assert_response :unprocessable_entity assert_equal 'application/xml', @response.content_type assert_tag 'errors', :child => {:tag => 'error', :content => "First name can't be blank"} end end - + context ".json" do should "return errors" do assert_no_difference('User.count') do put '/users/2.json', @parameters, :authorization => credentials('admin') end - + assert_response :unprocessable_entity assert_equal 'application/json', @response.content_type json = ActiveSupport::JSON.decode(response.body) @@ -246,39 +246,39 @@ end end end - + context "DELETE /users/2" do context ".xml" do should_allow_api_authentication(:delete, '/users/2.xml', {}, {:success_code => :ok}) - + should "delete user" do assert_difference('User.count', -1) do delete '/users/2.xml', {}, :authorization => credentials('admin') end - + assert_response :ok end end - + context ".json" do should_allow_api_authentication(:delete, '/users/2.xml', {}, {:success_code => :ok}) - + should "delete user" do assert_difference('User.count', -1) do delete '/users/2.json', {}, :authorization => credentials('admin') end - + assert_response :ok end end end - + def credentials(user, password=nil) ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) end diff -r 487d96eac004 -r 5e80956cc792 test/integration/api_test/versions_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/api_test/versions_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,142 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) + +class ApiTest::VersionsTest < ActionController::IntegrationTest + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions + + def setup + Setting.rest_api_enabled = '1' + end + + context "/projects/:project_id/versions" do + context "GET" do + should "return project versions" do + get '/projects/1/versions.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag :tag => 'versions', + :attributes => {:type => 'array'}, + :child => { + :tag => 'version', + :child => { + :tag => 'id', + :content => '2', + :sibling => { + :tag => 'name', + :content => '1.0' + } + } + } + end + end + + context "POST" do + should "create the version" do + assert_difference 'Version.count' do + post '/projects/1/versions.xml', {:version => {:name => 'API test'}}, :authorization => credentials('jsmith') + end + + version = Version.first(:order => 'id DESC') + assert_equal 'API test', version.name + + assert_response :created + assert_equal 'application/xml', @response.content_type + assert_tag 'version', :child => {:tag => 'id', :content => version.id.to_s} + end + + should "create the version with due date" do + assert_difference 'Version.count' do + post '/projects/1/versions.xml', {:version => {:name => 'API test', :due_date => '2012-01-24'}}, :authorization => credentials('jsmith') + end + + version = Version.first(:order => 'id DESC') + assert_equal 'API test', version.name + assert_equal Date.parse('2012-01-24'), version.due_date + + assert_response :created + assert_equal 'application/xml', @response.content_type + assert_tag 'version', :child => {:tag => 'id', :content => version.id.to_s} + end + + context "with failure" do + should "return the errors" do + assert_no_difference('Version.count') do + post '/projects/1/versions.xml', {:version => {:name => ''}}, :authorization => credentials('jsmith') + end + + assert_response :unprocessable_entity + assert_tag :errors, :child => {:tag => 'error', :content => "Name can't be blank"} + end + end + end + end + + context "/versions/:id" do + context "GET" do + should "return the version" do + get '/versions/2.xml' + + assert_response :success + assert_equal 'application/xml', @response.content_type + assert_tag 'version', + :child => { + :tag => 'id', + :content => '2', + :sibling => { + :tag => 'name', + :content => '1.0' + } + } + end + end + + context "PUT" do + should "update the version" do + put '/versions/2.xml', {:version => {:name => 'API update'}}, :authorization => credentials('jsmith') + + assert_response :ok + assert_equal 'API update', Version.find(2).name + end + end + + context "DELETE" do + should "destroy the version" do + assert_difference 'Version.count', -1 do + delete '/versions/3.xml', {}, :authorization => credentials('jsmith') + end + + assert_response :ok + assert_nil Version.find_by_id(3) + end + end + end + + def credentials(user, password=nil) + ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user) + end +end diff -r 487d96eac004 -r 5e80956cc792 test/integration/application_test.rb --- a/test/integration/application_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/application_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,35 +19,42 @@ class ApplicationTest < ActionController::IntegrationTest include Redmine::I18n - - fixtures :all - + + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + def test_set_localization Setting.default_language = 'en' - + # a french user get 'projects', { }, 'Accept-Language' => 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' assert_response :success assert_tag :tag => 'h2', :content => 'Projets' assert_equal :fr, current_language - + # then an italien user get 'projects', { }, 'Accept-Language' => 'it;q=0.8,en-us;q=0.5,en;q=0.3' assert_response :success assert_tag :tag => 'h2', :content => 'Progetti' assert_equal :it, current_language - + # not a supported language: default language should be used get 'projects', { }, 'Accept-Language' => 'zz' assert_response :success assert_tag :tag => 'h2', :content => 'Projects' end - + def test_token_based_access_should_not_start_session # issue of a private project get 'issues/4.atom' assert_response 302 - + rss_key = User.find(2).rss_key get "issues/4.atom?key=#{rss_key}" assert_response 200 diff -r 487d96eac004 -r 5e80956cc792 test/integration/issues_test.rb --- a/test/integration/issues_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/issues_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,7 +18,7 @@ require File.expand_path('../../test_helper', __FILE__) class IssuesTest < ActionController::IntegrationTest - fixtures :projects, + fixtures :projects, :users, :roles, :members, @@ -38,13 +38,13 @@ get 'projects/1/issues/new', :tracker_id => '1' assert_response :success assert_template 'issues/new' - + post 'projects/1/issues', :tracker_id => "1", - :issue => { :start_date => "2006-12-26", - :priority_id => "4", - :subject => "new test issue", - :category_id => "", - :description => "new issue", + :issue => { :start_date => "2006-12-26", + :priority_id => "4", + :subject => "new test issue", + :category_id => "", + :description => "new issue", :done_ratio => "0", :due_date => "", :assigned_to_id => "" }, @@ -58,7 +58,7 @@ follow_redirect! assert_equal issue, assigns(:issue) - # check issue attributes + # check issue attributes assert_equal 'jsmith', issue.author.login assert_equal 1, issue.project.id assert_equal 1, issue.status.id @@ -73,7 +73,7 @@ :notes => 'Some notes', :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}} assert_redirected_to "/issues/1" - + # make sure attachment was saved attachment = Issue.find(1).attachments.find_by_filename("testfile.txt") assert_kind_of Attachment, attachment @@ -83,56 +83,56 @@ #assert_equal file_data_1.length, attachment.filesize # verify that the attachment was written to disk assert File.exist?(attachment.diskfile) - + # remove the attachments Issue.find(1).attachments.each(&:destroy) assert_equal 0, Issue.find(1).attachments.length end - + def test_other_formats_links_on_get_index get '/projects/ecookbook/issues' - + %w(Atom PDF CSV).each do |format| assert_tag :a, :content => format, :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}", :rel => 'nofollow' } end end - + def test_other_formats_links_on_post_index_without_project_id_in_url post '/issues', :project_id => 'ecookbook' - + %w(Atom PDF CSV).each do |format| assert_tag :a, :content => format, :attributes => { :href => "/projects/ecookbook/issues.#{format.downcase}", :rel => 'nofollow' } end end - + def test_pagination_links_on_get_index Setting.per_page_options = '2' get '/projects/ecookbook/issues' - + assert_tag :a, :content => '2', :attributes => { :href => '/projects/ecookbook/issues?page=2' } - + end - + def test_pagination_links_on_post_index_without_project_id_in_url Setting.per_page_options = '2' post '/issues', :project_id => 'ecookbook' - + assert_tag :a, :content => '2', :attributes => { :href => '/projects/ecookbook/issues?page=2' } - + end - + def test_issue_with_user_custom_field @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all) Role.anonymous.add_permission! :add_issues, :edit_issues users = Project.find(1).users tester = users.first - + # Issue form get '/projects/ecookbook/issues/new' assert_response :success @@ -144,10 +144,10 @@ :attributes => {:value => tester.id.to_s}, :content => tester.name } - + # Create issue assert_difference 'Issue.count' do - post '/projects/ecookbook/issues', + post '/projects/ecookbook/issues', :issue => { :tracker_id => '1', :priority_id => '4', @@ -157,7 +157,7 @@ end issue = Issue.first(:order => 'id DESC') assert_response 302 - + # Issue view follow_redirect! assert_tag :th, @@ -174,7 +174,7 @@ :attributes => {:value => tester.id.to_s, :selected => 'selected'}, :content => tester.name } - + # Update issue new_tester = users[1] assert_difference 'Journal.count' do @@ -185,7 +185,7 @@ } end assert_response 302 - + # Issue view follow_redirect! assert_tag :content => 'Tester', diff -r 487d96eac004 -r 5e80956cc792 test/integration/layout_test.rb --- a/test/integration/layout_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/layout_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,7 +1,14 @@ require File.expand_path('../../test_helper', __FILE__) class LayoutTest < ActionController::IntegrationTest - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows test "browsing to a missing page should render the base layout" do get "/users/100000000" @@ -14,7 +21,7 @@ test "browsing to an unauthorized page should render the base layout" do change_user_password('miscuser9', 'test') - + log_user('miscuser9','test') get "/admin" @@ -37,10 +44,10 @@ assert_select "#quick-search" end end - + def test_wiki_formatter_header_tags Role.anonymous.add_permission! :add_issues - + get '/projects/ecookbook/issues/new' assert_tag :script, :attributes => {:src => %r{^/javascripts/jstoolbar/textile.js}}, diff -r 487d96eac004 -r 5e80956cc792 test/integration/lib/redmine/menu_manager_test.rb --- a/test/integration/lib/redmine/menu_manager_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/lib/redmine/menu_manager_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -19,12 +19,19 @@ class MenuManagerTest < ActionController::IntegrationTest include Redmine::I18n - - fixtures :all - + + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows + def test_project_menu_with_specific_locale get 'projects/ecookbook/issues', { }, 'Accept-Language' => 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3' - + assert_tag :div, :attributes => { :id => 'main-menu' }, :descendant => { :tag => 'li', :child => { :tag => 'a', :content => ll('fr', :label_activity), :attributes => { :href => '/projects/ecookbook/activity', @@ -34,7 +41,7 @@ :attributes => { :href => '/projects/ecookbook/issues', :class => 'issues selected' } } } end - + def test_project_menu_with_additional_menu_items Setting.default_language = 'en' assert_no_difference 'Redmine::MenuManager.items(:project_menu).size' do @@ -43,12 +50,12 @@ menu.push :bar, { :controller => 'projects', :action => 'show' }, :before => :activity menu.push :hello, { :controller => 'projects', :action => 'show' }, :caption => Proc.new {|p| p.name.upcase }, :after => :bar end - + get 'projects/ecookbook' assert_tag :div, :attributes => { :id => 'main-menu' }, :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo', :attributes => { :class => 'foo' } } } - + assert_tag :div, :attributes => { :id => 'main-menu' }, :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar', :attributes => { :class => 'bar' } }, @@ -58,7 +65,7 @@ :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK', :attributes => { :class => 'hello' } }, :before => { :tag => 'li', :child => { :tag => 'a', :content => 'Activity' } } } - + # Remove the menu items Redmine::MenuManager.map :project_menu do |menu| menu.delete :foo diff -r 487d96eac004 -r 5e80956cc792 test/integration/lib/redmine/themes_test.rb --- a/test/integration/lib/redmine/themes_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/lib/redmine/themes_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,57 +18,56 @@ require File.expand_path('../../../../test_helper', __FILE__) class ThemesTest < ActionController::IntegrationTest - fixtures :all - + def setup @theme = Redmine::Themes.themes.last Setting.ui_theme = @theme.id end - + def teardown Setting.ui_theme = '' end - + def test_application_css get '/' - + assert_response :success assert_tag :tag => 'link', :attributes => {:href => %r{^/themes/#{@theme.dir}/stylesheets/application.css}} end - + def test_without_theme_js get '/' - + assert_response :success assert_no_tag :tag => 'script', :attributes => {:src => %r{^/themes/#{@theme.dir}/javascripts/theme.js}} end - + def test_with_theme_js # Simulates a theme.js @theme.javascripts << 'theme' get '/' - + assert_response :success assert_tag :tag => 'script', :attributes => {:src => %r{^/themes/#{@theme.dir}/javascripts/theme.js}} - + ensure @theme.javascripts.delete 'theme' end - + def test_with_sub_uri Redmine::Utils.relative_url_root = '/foo' @theme.javascripts << 'theme' get '/' - + assert_response :success assert_tag :tag => 'link', :attributes => {:href => %r{^/foo/themes/#{@theme.dir}/stylesheets/application.css}} assert_tag :tag => 'script', :attributes => {:src => %r{^/foo/themes/#{@theme.dir}/javascripts/theme.js}} - + ensure Redmine::Utils.relative_url_root = '' end diff -r 487d96eac004 -r 5e80956cc792 test/integration/projects_test.rb --- a/test/integration/projects_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/projects_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,7 +19,7 @@ class ProjectsTest < ActionController::IntegrationTest fixtures :projects, :users, :members - + def test_archive_project subproject = Project.find(1).children.first log_user("admin", "admin") @@ -29,16 +29,16 @@ post "projects/archive", :id => 1 assert_redirected_to "/admin/projects" assert !Project.find(1).active? - + get 'projects/1' assert_response 403 get "projects/#{subproject.id}" assert_response 403 - + post "projects/unarchive", :id => 1 assert_redirected_to "/admin/projects" assert Project.find(1).active? get "projects/1" assert_response :success - end + end end diff -r 487d96eac004 -r 5e80956cc792 test/integration/routing_test.rb --- a/test/integration/routing_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/integration/routing_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -25,11 +25,13 @@ context "attachments" do should_route :get, "/attachments/1", :controller => 'attachments', :action => 'show', :id => '1' + should_route :get, "/attachments/1.xml", :controller => 'attachments', :action => 'show', :id => '1', :format => 'xml' + should_route :get, "/attachments/1.json", :controller => 'attachments', :action => 'show', :id => '1', :format => 'json' should_route :get, "/attachments/1/filename.ext", :controller => 'attachments', :action => 'show', :id => '1', :filename => 'filename.ext' should_route :get, "/attachments/download/1", :controller => 'attachments', :action => 'download', :id => '1' should_route :get, "/attachments/download/1/filename.ext", :controller => 'attachments', :action => 'download', :id => '1', :filename => 'filename.ext' end - + context "boards" do should_route :get, "/projects/world_domination/boards", :controller => 'boards', :action => 'index', :project_id => 'world_domination' should_route :get, "/projects/world_domination/boards/new", :controller => 'boards', :action => 'new', :project_id => 'world_domination' @@ -40,7 +42,7 @@ should_route :post, "/projects/world_domination/boards/new", :controller => 'boards', :action => 'new', :project_id => 'world_domination' should_route :post, "/projects/world_domination/boards/44/edit", :controller => 'boards', :action => 'edit', :project_id => 'world_domination', :id => '44' should_route :post, "/projects/world_domination/boards/44/destroy", :controller => 'boards', :action => 'destroy', :project_id => 'world_domination', :id => '44' - + end context "documents" do @@ -54,6 +56,11 @@ should_route :post, "/documents/567/destroy", :controller => 'documents', :action => 'destroy', :id => '567' end + context "groups" do + should_route :post, "/groups/567/users", :controller => 'groups', :action => 'add_users', :id => '567' + should_route :delete, "/groups/567/users/12", :controller => 'groups', :action => 'remove_user', :id => '567', :user_id => '12' + end + context "issues" do # REST actions should_route :get, "/issues", :controller => 'issues', :action => 'index' @@ -72,7 +79,7 @@ should_route :get, "/projects/23/issues/new", :controller => 'issues', :action => 'new', :project_id => '23' should_route :post, "/projects/23/issues", :controller => 'issues', :action => 'create', :project_id => '23' should_route :post, "/issues.xml", :controller => 'issues', :action => 'create', :format => 'xml' - + should_route :get, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64' # TODO: Should use PUT should_route :post, "/issues/64/edit", :controller => 'issues', :action => 'edit', :id => '64' @@ -81,13 +88,13 @@ # TODO: Should use DELETE should_route :post, "/issues/64/destroy", :controller => 'issues', :action => 'destroy', :id => '64' should_route :delete, "/issues/1.xml", :controller => 'issues', :action => 'destroy', :id => '1', :format => 'xml' - + # Extra actions should_route :get, "/projects/23/issues/64/copy", :controller => 'issues', :action => 'new', :project_id => '23', :copy_from => '64' should_route :get, "/issues/move/new", :controller => 'issue_moves', :action => 'new' should_route :post, "/issues/move", :controller => 'issue_moves', :action => 'create' - + should_route :post, "/issues/1/quoted", :controller => 'journals', :action => 'new', :id => '1' should_route :get, "/issues/calendar", :controller => 'calendars', :action => 'show' @@ -112,16 +119,49 @@ end context "issue categories" do - should_route :get, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test' + should_route :get, "/projects/foo/issue_categories", :controller => 'issue_categories', :action => 'index', :project_id => 'foo' + should_route :get, "/projects/foo/issue_categories.xml", :controller => 'issue_categories', :action => 'index', :project_id => 'foo', :format => 'xml' + should_route :get, "/projects/foo/issue_categories.json", :controller => 'issue_categories', :action => 'index', :project_id => 'foo', :format => 'json' - should_route :post, "/projects/test/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'test' + should_route :get, "/projects/foo/issue_categories/new", :controller => 'issue_categories', :action => 'new', :project_id => 'foo' + + should_route :post, "/projects/foo/issue_categories", :controller => 'issue_categories', :action => 'create', :project_id => 'foo' + should_route :post, "/projects/foo/issue_categories.xml", :controller => 'issue_categories', :action => 'create', :project_id => 'foo', :format => 'xml' + should_route :post, "/projects/foo/issue_categories.json", :controller => 'issue_categories', :action => 'create', :project_id => 'foo', :format => 'json' + + should_route :get, "/issue_categories/1", :controller => 'issue_categories', :action => 'show', :id => '1' + should_route :get, "/issue_categories/1.xml", :controller => 'issue_categories', :action => 'show', :id => '1', :format => 'xml' + should_route :get, "/issue_categories/1.json", :controller => 'issue_categories', :action => 'show', :id => '1', :format => 'json' + + should_route :get, "/issue_categories/1/edit", :controller => 'issue_categories', :action => 'edit', :id => '1' + + should_route :put, "/issue_categories/1", :controller => 'issue_categories', :action => 'update', :id => '1' + should_route :put, "/issue_categories/1.xml", :controller => 'issue_categories', :action => 'update', :id => '1', :format => 'xml' + should_route :put, "/issue_categories/1.json", :controller => 'issue_categories', :action => 'update', :id => '1', :format => 'json' + + should_route :delete, "/issue_categories/1", :controller => 'issue_categories', :action => 'destroy', :id => '1' + should_route :delete, "/issue_categories/1.xml", :controller => 'issue_categories', :action => 'destroy', :id => '1', :format => 'xml' + should_route :delete, "/issue_categories/1.json", :controller => 'issue_categories', :action => 'destroy', :id => '1', :format => 'json' end context "issue relations" do - should_route :post, "/issues/1/relations", :controller => 'issue_relations', :action => 'new', :issue_id => '1' - should_route :post, "/issues/1/relations/23/destroy", :controller => 'issue_relations', :action => 'destroy', :issue_id => '1', :id => '23' + should_route :get, "/issues/1/relations", :controller => 'issue_relations', :action => 'index', :issue_id => '1' + should_route :get, "/issues/1/relations.xml", :controller => 'issue_relations', :action => 'index', :issue_id => '1', :format => 'xml' + should_route :get, "/issues/1/relations.json", :controller => 'issue_relations', :action => 'index', :issue_id => '1', :format => 'json' + + should_route :post, "/issues/1/relations", :controller => 'issue_relations', :action => 'create', :issue_id => '1' + should_route :post, "/issues/1/relations.xml", :controller => 'issue_relations', :action => 'create', :issue_id => '1', :format => 'xml' + should_route :post, "/issues/1/relations.json", :controller => 'issue_relations', :action => 'create', :issue_id => '1', :format => 'json' + + should_route :get, "/relations/23", :controller => 'issue_relations', :action => 'show', :id => '23' + should_route :get, "/relations/23.xml", :controller => 'issue_relations', :action => 'show', :id => '23', :format => 'xml' + should_route :get, "/relations/23.json", :controller => 'issue_relations', :action => 'show', :id => '23', :format => 'json' + + should_route :delete, "/relations/23", :controller => 'issue_relations', :action => 'destroy', :id => '23' + should_route :delete, "/relations/23.xml", :controller => 'issue_relations', :action => 'destroy', :id => '23', :format => 'xml' + should_route :delete, "/relations/23.json", :controller => 'issue_relations', :action => 'destroy', :id => '23', :format => 'json' end - + context "issue reports" do should_route :get, "/projects/567/issues/report", :controller => 'reports', :action => 'issue_report', :id => '567' should_route :get, "/projects/567/issues/report/assigned_to", :controller => 'reports', :action => 'issue_report_details', :id => '567', :detail => 'assigned_to' @@ -156,7 +196,7 @@ should_route :get, "/news/234", :controller => 'news', :action => 'show', :id => '234' should_route :get, "/news/567/edit", :controller => 'news', :action => 'edit', :id => '567' should_route :get, "/news/preview", :controller => 'previews', :action => 'news' - + should_route :post, "/projects/567/news", :controller => 'news', :action => 'create', :project_id => '567' should_route :post, "/news/567/comments", :controller => 'comments', :action => 'create', :id => '567' @@ -180,7 +220,7 @@ should_route :get, "/projects/33/roadmap", :controller => 'versions', :action => 'index', :project_id => '33' should_route :get, "/projects/33/activity", :controller => 'activities', :action => 'index', :id => '33' should_route :get, "/projects/33/activity.atom", :controller => 'activities', :action => 'index', :id => '33', :format => 'atom' - + should_route :post, "/projects", :controller => 'projects', :action => 'create' should_route :post, "/projects.xml", :controller => 'projects', :action => 'create', :format => 'xml' should_route :post, "/projects/33/files", :controller => 'files', :action => 'create', :project_id => '33' @@ -195,13 +235,22 @@ should_route :delete, "/projects/1.xml", :controller => 'projects', :action => 'destroy', :id => '1', :format => 'xml' should_route :delete, "/projects/64/enumerations", :controller => 'project_enumerations', :action => 'destroy', :project_id => '64' end - + context "queries" do + should_route :get, "/queries.xml", :controller => 'queries', :action => 'index', :format => 'xml' + should_route :get, "/queries.json", :controller => 'queries', :action => 'index', :format => 'json' + should_route :get, "/queries/new", :controller => 'queries', :action => 'new' should_route :get, "/projects/redmine/queries/new", :controller => 'queries', :action => 'new', :project_id => 'redmine' - - should_route :post, "/queries/new", :controller => 'queries', :action => 'new' - should_route :post, "/projects/redmine/queries/new", :controller => 'queries', :action => 'new', :project_id => 'redmine' + + should_route :post, "/queries", :controller => 'queries', :action => 'create' + should_route :post, "/projects/redmine/queries", :controller => 'queries', :action => 'create', :project_id => 'redmine' + + should_route :get, "/queries/1/edit", :controller => 'queries', :action => 'edit', :id => '1' + + should_route :put, "/queries/1", :controller => 'queries', :action => 'update', :id => '1' + + should_route :delete, "/queries/1", :controller => 'queries', :action => 'destroy', :id => '1' end context "repositories" do @@ -222,8 +271,7 @@ should_route :get, "/projects/redmine/repository/annotate/path/to/file.c", :controller => 'repositories', :action => 'annotate', :id => 'redmine', :path => %w[path to file.c] should_route :get, "/projects/redmine/repository/changes/path/to/file.c", :controller => 'repositories', :action => 'changes', :id => 'redmine', :path => %w[path to file.c] should_route :get, "/projects/redmine/repository/statistics", :controller => 'repositories', :action => 'stats', :id => 'redmine' - - + should_route :post, "/projects/redmine/repository/edit", :controller => 'repositories', :action => 'edit', :id => 'redmine' end @@ -313,16 +361,33 @@ should_route :delete, "/users/44.xml", :controller => 'users', :action => 'destroy', :id => '44', :format => 'xml' end - # TODO: should they all be scoped under /projects/:project_id ? context "versions" do + # /projects/foo/versions is /projects/foo/roadmap + should_route :get, "/projects/foo/versions.xml", :controller => 'versions', :action => 'index', :project_id => 'foo', :format => 'xml' + should_route :get, "/projects/foo/versions.json", :controller => 'versions', :action => 'index', :project_id => 'foo', :format => 'json' + should_route :get, "/projects/foo/versions/new", :controller => 'versions', :action => 'new', :project_id => 'foo' - should_route :get, "/versions/show/1", :controller => 'versions', :action => 'show', :id => '1' - should_route :get, "/versions/edit/1", :controller => 'versions', :action => 'edit', :id => '1' should_route :post, "/projects/foo/versions", :controller => 'versions', :action => 'create', :project_id => 'foo' - should_route :post, "/versions/update/1", :controller => 'versions', :action => 'update', :id => '1' + should_route :post, "/projects/foo/versions.xml", :controller => 'versions', :action => 'create', :project_id => 'foo', :format => 'xml' + should_route :post, "/projects/foo/versions.json", :controller => 'versions', :action => 'create', :project_id => 'foo', :format => 'json' - should_route :delete, "/versions/destroy/1", :controller => 'versions', :action => 'destroy', :id => '1' + should_route :get, "/versions/1", :controller => 'versions', :action => 'show', :id => '1' + should_route :get, "/versions/1.xml", :controller => 'versions', :action => 'show', :id => '1', :format => 'xml' + should_route :get, "/versions/1.json", :controller => 'versions', :action => 'show', :id => '1', :format => 'json' + + should_route :get, "/versions/1/edit", :controller => 'versions', :action => 'edit', :id => '1' + + should_route :put, "/versions/1", :controller => 'versions', :action => 'update', :id => '1' + should_route :put, "/versions/1.xml", :controller => 'versions', :action => 'update', :id => '1', :format => 'xml' + should_route :put, "/versions/1.json", :controller => 'versions', :action => 'update', :id => '1', :format => 'json' + + should_route :delete, "/versions/1", :controller => 'versions', :action => 'destroy', :id => '1' + should_route :delete, "/versions/1.xml", :controller => 'versions', :action => 'destroy', :id => '1', :format => 'xml' + should_route :delete, "/versions/1.json", :controller => 'versions', :action => 'destroy', :id => '1', :format => 'json' + + should_route :put, "/projects/foo/versions/close_completed", :controller => 'versions', :action => 'close_completed', :project_id => 'foo' + should_route :post, "/versions/1/status_by", :controller => 'versions', :action => 'status_by', :id => '1' end context "wiki (singular, project's pages)" do @@ -338,7 +403,7 @@ should_route :get, "/projects/567/wiki/index", :controller => 'wiki', :action => 'index', :project_id => '567' should_route :get, "/projects/567/wiki/date_index", :controller => 'wiki', :action => 'date_index', :project_id => '567' should_route :get, "/projects/567/wiki/export", :controller => 'wiki', :action => 'export', :project_id => '567' - + should_route :post, "/projects/567/wiki/CookBook_documentation/preview", :controller => 'wiki', :action => 'preview', :project_id => '567', :id => 'CookBook_documentation' should_route :post, "/projects/22/wiki/ladida/rename", :controller => 'wiki', :action => 'rename', :project_id => '22', :id => 'ladida' should_route :post, "/projects/22/wiki/ladida/protect", :controller => 'wiki', :action => 'protect', :project_id => '22', :id => 'ladida' diff -r 487d96eac004 -r 5e80956cc792 test/mocks/open_id_authentication_mock.rb --- a/test/mocks/open_id_authentication_mock.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/mocks/open_id_authentication_mock.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Mocks out OpenID # # http://www.northpub.com/articles/2007/04/02/testing-openid-support -module OpenIdAuthentication +module OpenIdAuthentication - EXTENSION_FIELDS = {'email' => 'user@somedomain.com', + EXTENSION_FIELDS = {'email' => 'user@somedomain.com', 'nickname' => 'cool_user', - 'country' => 'US', + 'country' => 'US', 'postcode' => '12345', 'fullname' => 'Cool User', - 'dob' => '1970-04-01', + 'dob' => '1970-04-01', 'language' => 'en', - 'timezone' => 'America/New_York'} + 'timezone' => 'America/New_York'} protected @@ -31,7 +31,7 @@ yield Result[:successful], identity_url , extension_response_fields else - logger.info "OpenID authentication failed: #{identity_url}" + logger.info "OpenID authentication failed: #{identity_url}" yield Result[:failed], identity_url, nil end end diff -r 487d96eac004 -r 5e80956cc792 test/test_helper.rb --- a/test/test_helper.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/test_helper.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,7 +19,7 @@ require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require 'test_help' require File.expand_path(File.dirname(__FILE__) + '/helper_testcase') -require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb') +require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers') include ObjectDaddyHelpers @@ -47,7 +47,7 @@ self.use_instantiated_fixtures = false # Add more helper methods to be used by all tests here... - + def log_user(login, password) User.anonymous get "/login" @@ -57,9 +57,10 @@ post "/login", :username => login, :password => password assert_equal login, User.find(session[:user_id]).login end - + def uploaded_test_file(name, mime) - ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true) + ActionController::TestUploadedFile.new( + ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true) end # Mock out a file @@ -76,19 +77,32 @@ self.class.mock_file end + def mock_file_with_options(options={}) + file = '' + file.stubs(:size).returns(32) + original_filename = options[:original_filename] || nil + file.stubs(:original_filename).returns(original_filename) + content_type = options[:content_type] || nil + file.stubs(:content_type).returns(content_type) + file.stubs(:read).returns(false) + file + end + # Use a temporary directory for attachment related tests def set_tmp_attachments_directory - Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test") - Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments") - Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments" + Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test") + unless File.directory?("#{Rails.root}/tmp/test/attachments") + Dir.mkdir "#{Rails.root}/tmp/test/attachments" + end + Attachment.storage_path = "#{Rails.root}/tmp/test/attachments" end - + def with_settings(options, &block) - saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h} + saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].is_a?(Symbol) ? Setting[k] : Setting[k].dup; h} options.each {|k, v| Setting[k] = v} yield ensure - saved_settings.each {|k, v| Setting[k] = v} + saved_settings.each {|k, v| Setting[k] = v} if saved_settings end def change_user_password(login, new_password) @@ -104,28 +118,32 @@ # LDAP is not listening return nil end - + # Returns the path to the test +vendor+ repository def self.repository_path(vendor) - File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository") + Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s end - + # Returns the url of the subversion test repository def self.subversion_repository_url path = repository_path('subversion') path = '/' + path unless path.starts_with?('/') "file://#{path}" end - + # Returns true if the +vendor+ test repository is configured def self.repository_configured?(vendor) File.directory?(repository_path(vendor)) end - + def assert_error_tag(options={}) assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options)) end + def assert_include(expected, s) + assert s.include?(expected), "\"#{expected}\" not found in \"#{s}\"" + end + # Shoulda macros def self.should_render_404 should_respond_with :not_found @@ -170,7 +188,7 @@ :old_value => @old_value.id, :value => @new_value.id, :prop_key => prop_key) - + assert_match @new_value.name, show_detail(@detail, true) end @@ -179,7 +197,7 @@ :old_value => @old_value.id, :value => @new_value.id, :prop_key => prop_key) - + assert_match @old_value.name, show_detail(@detail, true) end end @@ -223,7 +241,7 @@ def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={}) success_code = options[:success_code] || :success failure_code = options[:failure_code] || :unauthorized - + context "should allow http basic auth using a username and password for #{http_method} #{url}" do context "with a valid HTTP authentication" do setup do @@ -231,7 +249,7 @@ @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password') send(http_method, url, parameters, {:authorization => @authorization}) end - + should_respond_with success_code should_respond_with_content_type_based_on_url(url) should "login as the user" do @@ -245,14 +263,14 @@ @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password') send(http_method, url, parameters, {:authorization => @authorization}) end - + should_respond_with failure_code should_respond_with_content_type_based_on_url(url) should "not login as the user" do assert_equal User.anonymous, User.current end end - + context "without credentials" do setup do send(http_method, url, parameters, {:authorization => ''}) @@ -288,7 +306,7 @@ @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X') send(http_method, url, parameters, {:authorization => @authorization}) end - + should_respond_with success_code should_respond_with_content_type_based_on_url(url) should_be_a_valid_response_string_based_on_url(url) @@ -313,7 +331,7 @@ end end end - + # Test that a request allows full key authentication # # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete) @@ -339,7 +357,7 @@ end send(http_method, request_url, parameters) end - + should_respond_with success_code should_respond_with_content_type_based_on_url(url) should_be_a_valid_response_string_based_on_url(url) @@ -360,7 +378,7 @@ end send(http_method, request_url, parameters) end - + should_respond_with failure_code should_respond_with_content_type_based_on_url(url) should "not login as the user" do @@ -368,14 +386,14 @@ end end end - + context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do setup do @user = User.generate_with_protected!(:admin => true) @token = Token.generate!(:user => @user, :action => 'api') send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s}) end - + should_respond_with success_code should_respond_with_content_type_based_on_url(url) should_be_a_valid_response_string_based_on_url(url) @@ -400,7 +418,7 @@ else raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}" end - + end # Uses the url to assert which format the response should be in @@ -418,9 +436,9 @@ else raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}" end - + end - + # Checks that the response is a valid JSON string def self.should_be_a_valid_json_string should "be a valid JSON string (or empty)" do @@ -434,7 +452,7 @@ assert REXML::Document.new(response.body) end end - + end # Simple module to "namespace" all of the API tests diff -r 487d96eac004 -r 5e80956cc792 test/unit/attachment_test.rb --- a/test/unit/attachment_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/attachment_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,9 +20,22 @@ require File.expand_path('../../test_helper', __FILE__) class AttachmentTest < ActiveSupport::TestCase - fixtures :issues, :users + fixtures :users, :projects, :roles, :members, :member_roles, + :enabled_modules, :issues, :trackers, :attachments + + class MockFile + attr_reader :original_filename, :content_type, :content, :size + + def initialize(attributes) + @original_filename = attributes[:original_filename] + @content_type = attributes[:content_type] + @content = attributes[:content] || "Content" + @size = content.size + end + end def setup + set_tmp_attachments_directory end def test_create @@ -36,6 +49,24 @@ assert_equal 0, a.downloads assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest assert File.exist?(a.diskfile) + assert_equal 59, File.size(a.diskfile) + end + + def test_destroy + a = Attachment.new(:container => Issue.find(1), + :file => uploaded_test_file("testfile.txt", "text/plain"), + :author => User.find(1)) + assert a.save + assert_equal 'testfile.txt', a.filename + assert_equal 59, a.filesize + assert_equal 'text/plain', a.content_type + assert_equal 0, a.downloads + assert_equal '1478adae0d4eb06d35897518540e25d6', a.digest + diskfile = a.diskfile + assert File.exist?(diskfile) + assert_equal 59, File.size(a.diskfile) + assert a.destroy + assert !File.exist?(diskfile) end def test_create_should_auto_assign_content_type @@ -55,6 +86,16 @@ :author => User.find(1)) assert a1.disk_filename != a2.disk_filename end + + def test_filename_should_be_basenamed + a = Attachment.new(:file => MockFile.new(:original_filename => "path/to/the/file")) + assert_equal 'file', a.filename + end + + def test_filename_should_be_sanitized + a = Attachment.new(:file => MockFile.new(:original_filename => "valid:[] invalid:?%*|\"'<>chars")) + assert_equal 'valid_[] invalid_chars', a.filename + end def test_diskfilename assert Attachment.disk_filename("test_file.txt") =~ /^\d{12}_test_file.txt$/ @@ -64,7 +105,27 @@ assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentué.ça")[13..-1] end - context "Attachmnet#attach_files" do + context "Attachmnet.attach_files" do + should "attach the file" do + issue = Issue.first + assert_difference 'Attachment.count' do + Attachment.attach_files(issue, + '1' => { + 'file' => uploaded_test_file('testfile.txt', 'text/plain'), + 'description' => 'test' + }) + end + + attachment = Attachment.first(:order => 'id DESC') + assert_equal issue, attachment.container + assert_equal 'testfile.txt', attachment.filename + assert_equal 59, attachment.filesize + assert_equal 'test', attachment.description + assert_equal 'text/plain', attachment.content_type + assert File.exists?(attachment.diskfile) + assert_equal 59, File.size(attachment.diskfile) + end + should "add unsaved files to the object as unsaved attachments" do # Max size of 0 to force Attachment creation failures with_settings(:attachment_max_size => 0) do @@ -82,4 +143,26 @@ end end end + + def test_latest_attach + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + a1 = Attachment.find(16) + assert_equal "testfile.png", a1.filename + assert a1.readable? + assert (! a1.visible?(User.anonymous)) + assert a1.visible?(User.find(2)) + a2 = Attachment.find(17) + assert_equal "testfile.PNG", a2.filename + assert a2.readable? + assert (! a2.visible?(User.anonymous)) + assert a2.visible?(User.find(2)) + assert a1.created_on < a2.created_on + + la1 = Attachment.latest_attach([a1, a2], "testfile.png") + assert_equal 17, la1.id + la2 = Attachment.latest_attach([a1, a2], "Testfile.PNG") + assert_equal 17, la2.id + + set_tmp_attachments_directory + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/auth_source_ldap_test.rb --- a/test/unit/auth_source_ldap_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/auth_source_ldap_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -19,15 +19,15 @@ class AuthSourceLdapTest < ActiveSupport::TestCase fixtures :auth_sources - + def setup end - + def test_create a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName') assert a.save end - + def test_should_strip_ldap_attributes a = AuthSourceLdap.new(:name => 'My LDAP', :host => 'ldap.example.net', :port => 389, :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', :attr_firstname => 'givenName ') @@ -35,6 +35,15 @@ assert_equal 'givenName', a.reload.attr_firstname end + def test_replace_port_zero_to_389 + a = AuthSourceLdap.new( + :name => 'My LDAP', :host => 'ldap.example.net', :port => 0, + :base_dn => 'dc=example,dc=net', :attr_login => 'sAMAccountName', + :attr_firstname => 'givenName ') + assert a.save + assert_equal 389, a.port + end + if ldap_configured? context '#authenticate' do setup do @@ -72,7 +81,7 @@ assert_equal nil, @auth.authenticate('edavis','') end end - + end else puts '(Test LDAP server not configured)' diff -r 487d96eac004 -r 5e80956cc792 test/unit/board_test.rb --- a/test/unit/board_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/board_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -6,7 +6,7 @@ def setup @project = Project.find(1) end - + def test_create board = Board.new(:project => @project, :name => 'Test board', :description => 'Test board description') assert board.save @@ -20,7 +20,7 @@ # last position assert_equal @project.boards.size, board.position end - + def test_destroy board = Board.find(1) assert_difference 'Message.count', -6 do diff -r 487d96eac004 -r 5e80956cc792 test/unit/changeset_test.rb --- a/test/unit/changeset_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/changeset_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,18 +1,18 @@ # encoding: utf-8 # # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -22,7 +22,7 @@ class ChangesetTest < ActiveSupport::TestCase fixtures :projects, :repositories, :issues, :issue_statuses, :issue_categories, - :changesets, :changes, + :changesets, :changes, :enumerations, :custom_fields, :custom_values, :users, :members, :member_roles, :trackers, @@ -41,9 +41,9 @@ c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => 'New commit (#2). Fixes #1') - c.scan_comment_for_issue_ids - + :comments => 'New commit (#2). Fixes #1', + :revision => '12345') + assert c.save assert_equal [1, 2], c.issue_ids.sort fixed = Issue.find(1) assert fixed.closed? @@ -54,24 +54,22 @@ def test_ref_keywords Setting.commit_ref_keywords = 'refs' Setting.commit_fix_keywords = '' - c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => 'Ignores #2. Refs #1') - c.scan_comment_for_issue_ids - + :comments => 'Ignores #2. Refs #1', + :revision => '12345') + assert c.save assert_equal [1], c.issue_ids.sort end def test_ref_keywords_any_only Setting.commit_ref_keywords = '*' Setting.commit_fix_keywords = '' - c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => 'Ignores #2. Refs #1') - c.scan_comment_for_issue_ids - + :comments => 'Ignores #2. Refs #1', + :revision => '12345') + assert c.save assert_equal [1, 2], c.issue_ids.sort end @@ -123,7 +121,7 @@ Setting.commit_ref_keywords = '*' Setting.commit_fix_keywords = 'fixes , closes' Setting.commit_logtime_enabled = '1' - + c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, :comments => 'This is a comment. Fixes #1 @4.5, #2 @1', @@ -142,43 +140,40 @@ def test_ref_keywords_any_line_start Setting.commit_ref_keywords = '*' - c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => '#1 is the reason of this commit') - c.scan_comment_for_issue_ids - + :comments => '#1 is the reason of this commit', + :revision => '12345') + assert c.save assert_equal [1], c.issue_ids.sort end def test_ref_keywords_allow_brackets_around_a_issue_number Setting.commit_ref_keywords = '*' - c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => '[#1] Worked on this issue') - c.scan_comment_for_issue_ids - + :comments => '[#1] Worked on this issue', + :revision => '12345') + assert c.save assert_equal [1], c.issue_ids.sort end def test_ref_keywords_allow_brackets_around_multiple_issue_numbers Setting.commit_ref_keywords = '*' - c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => '[#1 #2, #3] Worked on these') - c.scan_comment_for_issue_ids - + :comments => '[#1 #2, #3] Worked on these', + :revision => '12345') + assert c.save assert_equal [1,2,3], c.issue_ids.sort end def test_commit_referencing_a_subproject_issue c = Changeset.new(:repository => Project.find(1).repository, :committed_on => Time.now, - :comments => 'refs #5, a subproject issue') - c.scan_comment_for_issue_ids - + :comments => 'refs #5, a subproject issue', + :revision => '12345') + assert c.save assert_equal [5], c.issue_ids.sort assert c.issues.first.project != c.project end @@ -188,12 +183,11 @@ r = Repository::Subversion.create!( :project => Project.find(3), :url => 'svn://localhost/test') - c = Changeset.new(:repository => r, :committed_on => Time.now, - :comments => 'refs #2, an issue of a parent project') - c.scan_comment_for_issue_ids - + :comments => 'refs #2, an issue of a parent project', + :revision => '12345') + assert c.save assert_equal [2], c.issue_ids.sort assert c.issues.first.project != c.project end diff -r 487d96eac004 -r 5e80956cc792 test/unit/comment_test.rb --- a/test/unit/comment_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/comment_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -24,18 +24,18 @@ @jsmith = User.find(2) @news = News.find(1) end - + def test_create comment = Comment.new(:commented => @news, :author => @jsmith, :comments => "my comment") assert comment.save @news.reload assert_equal 2, @news.comments_count end - + def test_create_should_send_notification Setting.notified_events << 'news_comment_added' Watcher.create!(:watchable => @news, :user => @jsmith) - + assert_difference 'ActionMailer::Base.deliveries.size' do Comment.create!(:commented => @news, :author => @jsmith, :comments => "my comment") end @@ -46,7 +46,7 @@ assert !comment.save assert_equal 2, comment.errors.length end - + def test_destroy comment = Comment.find(1) assert comment.destroy diff -r 487d96eac004 -r 5e80956cc792 test/unit/custom_field_test.rb --- a/test/unit/custom_field_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/custom_field_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -19,30 +19,39 @@ class CustomFieldTest < ActiveSupport::TestCase fixtures :custom_fields - + def test_create field = UserCustomField.new(:name => 'Money money money', :field_format => 'float') assert field.save end - + + def test_regexp_validation + field = IssueCustomField.new(:name => 'regexp', :field_format => 'text', :regexp => '[a-z0-9') + assert !field.save + assert_equal I18n.t('activerecord.errors.messages.invalid'), field.errors.on(:regexp) + + field.regexp = '[a-z0-9]' + assert field.save + end + def test_possible_values_should_accept_an_array field = CustomField.new field.possible_values = ["One value", ""] assert_equal ["One value"], field.possible_values end - + def test_possible_values_should_accept_a_string field = CustomField.new field.possible_values = "One value" assert_equal ["One value"], field.possible_values end - + def test_possible_values_should_accept_a_multiline_string field = CustomField.new field.possible_values = "One value\nAnd another one \r\n \n" assert_equal ["One value", "And another one"], field.possible_values end - + def test_destroy field = CustomField.find(1) assert field.destroy diff -r 487d96eac004 -r 5e80956cc792 test/unit/custom_field_user_format_test.rb --- a/test/unit/custom_field_user_format_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/custom_field_user_format_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -19,58 +19,58 @@ class CustomFieldUserFormatTest < ActiveSupport::TestCase fixtures :custom_fields, :projects, :members, :users, :member_roles, :trackers, :issues - + def setup @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user') end - + def test_possible_values_with_no_arguments assert_equal [], @field.possible_values assert_equal [], @field.possible_values(nil) end - + def test_possible_values_with_project_resource project = Project.find(1) possible_values = @field.possible_values(project.issues.first) assert possible_values.any? assert_equal project.users.sort.collect(&:id).map(&:to_s), possible_values end - + def test_possible_values_with_nil_project_resource project = Project.find(1) assert_equal [], @field.possible_values(Issue.new) end - + def test_possible_values_options_with_no_arguments assert_equal [], @field.possible_values_options assert_equal [], @field.possible_values_options(nil) end - + def test_possible_values_options_with_project_resource project = Project.find(1) possible_values_options = @field.possible_values_options(project.issues.first) assert possible_values_options.any? assert_equal project.users.sort.map {|u| [u.name, u.id.to_s]}, possible_values_options end - + def test_possible_values_options_with_array projects = Project.find([1, 2]) possible_values_options = @field.possible_values_options(projects) assert possible_values_options.any? assert_equal (projects.first.users & projects.last.users).sort.map {|u| [u.name, u.id.to_s]}, possible_values_options end - + def test_cast_blank_value assert_equal nil, @field.cast_value(nil) assert_equal nil, @field.cast_value("") end - + def test_cast_valid_value user = @field.cast_value("2") assert_kind_of User, user assert_equal User.find(2), user end - + def test_cast_invalid_value assert_equal nil, @field.cast_value("187") end diff -r 487d96eac004 -r 5e80956cc792 test/unit/custom_field_version_format_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/unit/custom_field_version_format_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,76 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__) + +class CustomFieldVersionFormatTest < ActiveSupport::TestCase + fixtures :custom_fields, :projects, :members, :users, :member_roles, :trackers, :issues, :versions + + def setup + @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'version') + end + + def test_possible_values_with_no_arguments + assert_equal [], @field.possible_values + assert_equal [], @field.possible_values(nil) + end + + def test_possible_values_with_project_resource + project = Project.find(1) + possible_values = @field.possible_values(project.issues.first) + assert possible_values.any? + assert_equal project.shared_versions.sort.collect(&:id).map(&:to_s), possible_values + end + + def test_possible_values_with_nil_project_resource + assert_equal [], @field.possible_values(Issue.new) + end + + def test_possible_values_options_with_no_arguments + assert_equal [], @field.possible_values_options + assert_equal [], @field.possible_values_options(nil) + end + + def test_possible_values_options_with_project_resource + project = Project.find(1) + possible_values_options = @field.possible_values_options(project.issues.first) + assert possible_values_options.any? + assert_equal project.shared_versions.sort.map {|u| [u.name, u.id.to_s]}, possible_values_options + end + + def test_possible_values_options_with_array + projects = Project.find([1, 2]) + possible_values_options = @field.possible_values_options(projects) + assert possible_values_options.any? + assert_equal (projects.first.shared_versions & projects.last.shared_versions).sort.map {|u| [u.name, u.id.to_s]}, possible_values_options + end + + def test_cast_blank_value + assert_equal nil, @field.cast_value(nil) + assert_equal nil, @field.cast_value("") + end + + def test_cast_valid_value + version = @field.cast_value("2") + assert_kind_of Version, version + assert_equal Version.find(2), version + end + + def test_cast_invalid_value + assert_equal nil, @field.cast_value("187") + end +end diff -r 487d96eac004 -r 5e80956cc792 test/unit/custom_value_test.rb --- a/test/unit/custom_value_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/custom_value_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ def test_string_field_validation_with_blank_value f = CustomField.new(:field_format => 'string') v = CustomValue.new(:custom_field => f) - + v.value = nil assert v.valid? v.value = '' @@ -35,7 +35,7 @@ v.value = '' assert !v.valid? end - + def test_string_field_validation_with_min_and_max_lengths f = CustomField.new(:field_format => 'string', :min_length => 2, :max_length => 5) v = CustomValue.new(:custom_field => f, :value => '') @@ -47,7 +47,7 @@ v.value = 'a' * 6 assert !v.valid? end - + def test_string_field_validation_with_regexp f = CustomField.new(:field_format => 'string', :regexp => '^[A-Z0-9]*$') v = CustomValue.new(:custom_field => f, :value => '') @@ -64,6 +64,8 @@ assert v.valid? v.value = 'abc' assert !v.valid? + v.value = '1975-07-33' + assert !v.valid? v.value = '1975-07-14' assert v.valid? end @@ -91,7 +93,7 @@ v.value = '-123' assert v.valid? end - + def test_float_field_validation v = CustomValue.new(:customized => User.find(:first), :custom_field => UserCustomField.find_by_name('Money')) v.value = '11.2' @@ -103,18 +105,18 @@ v.value = '6a' assert !v.save end - + def test_default_value field = CustomField.find_by_default_value('Default string') assert_not_nil field - + v = CustomValue.new(:custom_field => field) assert_equal 'Default string', v.value v = CustomValue.new(:custom_field => field, :value => 'Not empty') assert_equal 'Not empty', v.value end - + def test_sti_polymorphic_association # Rails uses top level sti class for polymorphic association. See #3978. assert !User.find(4).custom_values.empty? diff -r 487d96eac004 -r 5e80956cc792 test/unit/enumeration_test.rb --- a/test/unit/enumeration_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/enumeration_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software +# Redmine - project management software # Copyright (C) 2006-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. @@ -22,60 +22,60 @@ def setup end - + def test_objects_count # low priority assert_equal 6, Enumeration.find(4).objects_count # urgent assert_equal 0, Enumeration.find(7).objects_count end - + def test_in_use # low priority assert Enumeration.find(4).in_use? # urgent assert !Enumeration.find(7).in_use? end - + def test_default e = Enumeration.default assert e.is_a?(Enumeration) assert e.is_default? assert_equal 'Default Enumeration', e.name end - + def test_create e = Enumeration.new(:name => 'Not default', :is_default => false) e.type = 'Enumeration' assert e.save assert_equal 'Default Enumeration', Enumeration.default.name end - + def test_create_as_default e = Enumeration.new(:name => 'Very urgent', :is_default => true) e.type = 'Enumeration' assert e.save assert_equal e, Enumeration.default end - + def test_update_default e = Enumeration.default e.update_attributes(:name => 'Changed', :is_default => true) assert_equal e, Enumeration.default end - + def test_update_default_to_non_default e = Enumeration.default e.update_attributes(:name => 'Changed', :is_default => false) assert_nil Enumeration.default end - + def test_change_default e = Enumeration.find_by_name('Default Enumeration') e.update_attributes(:name => 'Changed Enumeration', :is_default => true) assert_equal e, Enumeration.default end - + def test_destroy_with_reassign Enumeration.find(4).destroy(Enumeration.find(6)) assert_nil Issue.find(:first, :conditions => {:priority_id => 4}) diff -r 487d96eac004 -r 5e80956cc792 test/unit/group_test.rb --- a/test/unit/group_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/group_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,33 +18,59 @@ require File.expand_path('../../test_helper', __FILE__) class GroupTest < ActiveSupport::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :groups_users + + include Redmine::I18n def test_create g = Group.new(:lastname => 'New group') assert g.save end - + + def test_blank_name_error_message + set_language_if_valid 'en' + g = Group.new + assert !g.save + assert_include "Name can't be blank", g.errors.full_messages + end + + def test_blank_name_error_message_fr + set_language_if_valid 'fr' + str = "Nom doit \xc3\xaatre renseign\xc3\xa9(e)" + str.force_encoding('UTF-8') if str.respond_to?(:force_encoding) + g = Group.new + assert !g.save + assert_include str, g.errors.full_messages + end + def test_roles_given_to_new_user group = Group.find(11) user = User.find(9) project = Project.first - + Member.create!(:principal => group, :project => project, :role_ids => [1, 2]) group.users << user assert user.member_of?(project) end - + def test_roles_given_to_existing_user group = Group.find(11) user = User.find(9) project = Project.first - + group.users << user m = Member.create!(:principal => group, :project => project, :role_ids => [1, 2]) assert user.member_of?(project) end - + def test_roles_updated group = Group.find(11) user = User.find(9) @@ -52,13 +78,13 @@ group.users << user m = Member.create!(:principal => group, :project => project, :role_ids => [1]) assert_equal [1], user.reload.roles_for_project(project).collect(&:id).sort - + m.role_ids = [1, 2] assert_equal [1, 2], user.reload.roles_for_project(project).collect(&:id).sort - + m.role_ids = [2] assert_equal [2], user.reload.roles_for_project(project).collect(&:id).sort - + m.role_ids = [1] assert_equal [1], user.reload.roles_for_project(project).collect(&:id).sort end @@ -74,4 +100,14 @@ User.find(8).groups.clear assert !User.find(8).member_of?(Project.find(5)) end + + def test_destroy_should_unassign_issues + group = Group.first + Issue.update_all(["assigned_to_id = ?", group.id], 'id = 1') + + assert group.destroy + assert group.destroyed? + + assert_equal nil, Issue.find(1).assigned_to_id + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/application_helper_test.rb --- a/test/unit/helpers/application_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/application_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -18,17 +18,16 @@ require File.expand_path('../../../test_helper', __FILE__) class ApplicationHelperTest < ActionView::TestCase - fixtures :projects, :roles, :enabled_modules, :users, - :repositories, :changesets, - :trackers, :issue_statuses, :issues, :versions, :documents, - :wikis, :wiki_pages, :wiki_contents, - :boards, :messages, - :attachments, - :enumerations + :repositories, :changesets, + :trackers, :issue_statuses, :issues, :versions, :documents, + :wikis, :wiki_pages, :wiki_contents, + :boards, :messages, :news, + :attachments, :enumerations def setup super + set_tmp_attachments_directory end context "#link_to_if_authorized" do @@ -129,6 +128,84 @@ to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text, :attachments => attachments) } end + def test_attached_images_filename_extension + set_tmp_attachments_directory + a1 = Attachment.new( + :container => Issue.find(1), + :file => mock_file_with_options({:original_filename => "testtest.JPG"}), + :author => User.find(1)) + assert a1.save + assert_equal "testtest.JPG", a1.filename + assert_equal "image/jpeg", a1.content_type + assert a1.image? + + a2 = Attachment.new( + :container => Issue.find(1), + :file => mock_file_with_options({:original_filename => "testtest.jpeg"}), + :author => User.find(1)) + assert a2.save + assert_equal "testtest.jpeg", a2.filename + assert_equal "image/jpeg", a2.content_type + assert a2.image? + + a3 = Attachment.new( + :container => Issue.find(1), + :file => mock_file_with_options({:original_filename => "testtest.JPE"}), + :author => User.find(1)) + assert a3.save + assert_equal "testtest.JPE", a3.filename + assert_equal "image/jpeg", a3.content_type + assert a3.image? + + a4 = Attachment.new( + :container => Issue.find(1), + :file => mock_file_with_options({:original_filename => "Testtest.BMP"}), + :author => User.find(1)) + assert a4.save + assert_equal "Testtest.BMP", a4.filename + assert_equal "image/x-ms-bmp", a4.content_type + assert a4.image? + + to_test = { + 'Inline image: !testtest.jpg!' => + 'Inline image: ', + 'Inline image: !testtest.jpeg!' => + 'Inline image: ', + 'Inline image: !testtest.jpe!' => + 'Inline image: ', + 'Inline image: !testtest.bmp!' => + 'Inline image: ', + } + + attachments = [a1, a2, a3, a4] + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text, :attachments => attachments) } + end + + def test_attached_images_should_read_later + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + a1 = Attachment.find(16) + assert_equal "testfile.png", a1.filename + assert a1.readable? + assert (! a1.visible?(User.anonymous)) + assert a1.visible?(User.find(2)) + a2 = Attachment.find(17) + assert_equal "testfile.PNG", a2.filename + assert a2.readable? + assert (! a2.visible?(User.anonymous)) + assert a2.visible?(User.find(2)) + assert a1.created_on < a2.created_on + + to_test = { + 'Inline image: !testfile.png!' => + 'Inline image: ', + 'Inline image: !Testfile.PNG!' => + 'Inline image: ', + } + attachments = [a1, a2] + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text, :attachments => attachments) } + set_tmp_attachments_directory + end + def test_textile_external_links to_test = { 'This is a "link":http://foo.bar' => 'This is a link', @@ -163,7 +240,11 @@ version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2}, :class => 'version') + board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'} + message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4} + + news_url = {:controller => 'news', :action => 'show', :id => 1} project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'} @@ -198,9 +279,15 @@ 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'), 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'), 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'), + # forum + 'forum#2' => link_to('Discussion', board_url, :class => 'board'), + 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'), # message 'message#4' => link_to('Post 2', message_url, :class => 'message'), 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'), + # news + 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'), + 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'), # project 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'), 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'), @@ -239,7 +326,7 @@ 'invalid:document:"Test document"' => 'invalid:document:"Test document"', # versions 'version:"1.0"' => 'version:"1.0"', - 'ecookbook:version:"1.0"' => '1.0', + 'ecookbook:version:"1.0"' => '1.0', 'invalid:version:"1.0"' => 'invalid:version:"1.0"', # changeset 'r2' => 'r2', @@ -350,6 +437,9 @@ to_test = { '[[CookBook documentation]]' => 'CookBook documentation', '[[Another page|Page]]' => 'Page', + # title content should be formatted + '[[Another page|With _styled_ *title*]]' => 'With styled title', + '[[Another page|With title containing HTML entities & markups]]' => 'With title containing <strong>HTML entities & markups</strong>', # link with anchor '[[CookBook documentation#One-section]]' => 'CookBook documentation', '[[Another page#anchor|Page]]' => 'Page', @@ -371,10 +461,31 @@ '[[unknowproject:Start]]' => '[[unknowproject:Start]]', '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]', } + @project = Project.find(1) to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text) } end + def test_wiki_links_within_local_file_generation_context + + to_test = { + # link to a page + '[[CookBook documentation]]' => 'CookBook documentation', + '[[CookBook documentation|documentation]]' => 'documentation', + '[[CookBook documentation#One-section]]' => 'CookBook documentation', + '[[CookBook documentation#One-section|documentation]]' => 'documentation', + # page that doesn't exist + '[[Unknown page]]' => 'Unknown page', + '[[Unknown page|404]]' => '404', + '[[Unknown page#anchor]]' => 'Unknown page', + '[[Unknown page#anchor|404]]' => '404', + } + + @project = Project.find(1) + + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text, :wiki_links => :local) } + end + def test_html_tags to_test = { "
    content
    " => "

    <div>content</div>

    ", @@ -479,7 +590,7 @@ RAW expected = <<-EXPECTED -
    1 # Some ruby code here
    +
    1# Some ruby code here
     
    EXPECTED @@ -533,6 +644,72 @@ assert_equal expected, textilizable(raw) end + def test_headings_with_special_chars + # This test makes sure that the generated anchor names match the expected + # ones even if the heading text contains unconventional characters + raw = 'h1. Some heading related to version 0.5' + anchor = sanitize_anchor_name("Some-heading-related-to-version-0.5") + expected = %|\n

    Some heading related to version 0.5

    | + + assert_equal expected, textilizable(raw) + end + + def test_wiki_links_within_wiki_page_context + + page = WikiPage.find_by_title('Another_page' ) + + to_test = { + # link to another page + '[[CookBook documentation]]' => 'CookBook documentation', + '[[CookBook documentation|documentation]]' => 'documentation', + '[[CookBook documentation#One-section]]' => 'CookBook documentation', + '[[CookBook documentation#One-section|documentation]]' => 'documentation', + # link to the current page + '[[Another page]]' => 'Another page', + '[[Another page|Page]]' => 'Page', + '[[Another page#anchor]]' => 'Another page', + '[[Another page#anchor|Page]]' => 'Page', + # page that doesn't exist + '[[Unknown page]]' => 'Unknown page', + '[[Unknown page|404]]' => '404', + '[[Unknown page#anchor]]' => 'Unknown page', + '[[Unknown page#anchor|404]]' => '404', + } + + @project = Project.find(1) + + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(WikiContent.generate!( :text => text, :page => page ), :text) } + end + + def test_wiki_links_anchor_option_should_prepend_page_title_to_href + + to_test = { + # link to a page + '[[CookBook documentation]]' => 'CookBook documentation', + '[[CookBook documentation|documentation]]' => 'documentation', + '[[CookBook documentation#One-section]]' => 'CookBook documentation', + '[[CookBook documentation#One-section|documentation]]' => 'documentation', + # page that doesn't exist + '[[Unknown page]]' => 'Unknown page', + '[[Unknown page|404]]' => '404', + '[[Unknown page#anchor]]' => 'Unknown page', + '[[Unknown page#anchor|404]]' => '404', + } + + @project = Project.find(1) + + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text, :wiki_links => :anchor) } + end + + def test_headings_in_wiki_single_page_export_should_be_prepended_with_page_title + page = WikiPage.generate!( :title => 'Page Title' ) + content = WikiContent.generate!( :text => 'h1. Some heading', :page => page ) + + expected = %|\n

    Some heading

    | + + assert_equal expected, textilizable(content, :text, :wiki_links => :anchor ) + end + def test_table_of_content raw = <<-RAW {{toc}} @@ -588,7 +765,7 @@ '' @project = Project.find(1) - assert textilizable(raw).gsub("\n", "").include?(expected), textilizable(raw) + assert textilizable(raw).gsub("\n", "").include?(expected) end def test_table_of_content_should_contain_included_page_headings @@ -675,4 +852,27 @@ assert_equal %(eCookbook), link_to_project(project, {:action => 'settings'}, :class => "project") end + + def test_principals_options_for_select_with_users + users = [User.find(2), User.find(4)] + assert_equal %(), + principals_options_for_select(users) + end + + def test_principals_options_for_select_with_selected + users = [User.find(2), User.find(4)] + assert_equal %(), + principals_options_for_select(users, User.find(4)) + end + + def test_principals_options_for_select_with_users_and_groups + users = [User.find(2), Group.find(11), User.find(4), Group.find(10)] + assert_equal %() + + %(), + principals_options_for_select(users) + end + + def test_principals_options_for_select_with_empty_collection + assert_equal '', principals_options_for_select([]) + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/custom_fields_helper_test.rb --- a/test/unit/helpers/custom_fields_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/custom_fields_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,41 +5,41 @@ # 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.expand_path('../../../test_helper', __FILE__) -class CustomFieldsHelperTest < HelperTestCase +class CustomFieldsHelperTest < ActionView::TestCase include CustomFieldsHelper include Redmine::I18n - + def test_format_boolean_value I18n.locale = 'en' assert_equal 'Yes', format_value('1', 'bool') assert_equal 'No', format_value('0', 'bool') end - + def test_unknow_field_format_should_be_edited_as_string field = CustomField.new(:field_format => 'foo') value = CustomValue.new(:value => 'bar', :custom_field => field) field.id = 52 - + assert_equal '', custom_field_tag('object', value) end - + def test_unknow_field_format_should_be_bulk_edited_as_string field = CustomField.new(:field_format => 'foo') field.id = 52 - + assert_equal '', custom_field_tag_for_bulk_edit('object', field) end diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/issue_moves_helper_test.rb --- a/test/unit/helpers/issue_moves_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/issue_moves_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,4 +1,4 @@ -require 'test_helper' +require File.expand_path('../../../test_helper', __FILE__) class IssueMovesHelperTest < ActionView::TestCase end diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/issues_helper_test.rb --- a/test/unit/helpers/issues_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/issues_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -22,7 +22,14 @@ include IssuesHelper include ActionController::Assertions::SelectorAssertions - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows # Used by assert_select def html_document diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/projects_helper_test.rb --- a/test/unit/helpers/projects_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/projects_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,27 +1,35 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) -class ProjectsHelperTest < HelperTestCase +class ProjectsHelperTest < ActionView::TestCase include ApplicationHelper include ProjectsHelper - - fixtures :all + + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :versions, + :projects_trackers, + :member_roles, + :members, + :groups_users, + :enabled_modules, + :workflows def setup super @@ -32,12 +40,12 @@ def test_link_to_version_within_project @project = Project.find(2) User.current = User.find(1) - assert_equal 'Alpha', link_to_version(Version.find(5)) + assert_equal 'Alpha', link_to_version(Version.find(5)) end def test_link_to_version User.current = User.find(1) - assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5)) + assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5)) end def test_link_to_private_version @@ -47,12 +55,12 @@ def test_link_to_version_invalid_version assert_equal '', link_to_version(Object) end - + def test_format_version_name_within_project @project = Project.find(1) assert_equal "0.1", format_version_name(Version.find(1)) end - + def test_format_version_name assert_equal "eCookbook - 0.1", format_version_name(Version.find(1)) end @@ -60,7 +68,7 @@ def test_format_version_name_for_system_version assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7)) end - + def test_version_options_for_select_with_no_versions assert_equal '', version_options_for_select([]) assert_equal '', version_options_for_select([], Version.find(1)) diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/repository_helper_test.rb --- a/test/unit/helpers/repository_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -# Redmine - project management software -# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) - -class RepositoryHelperTest < HelperTestCase - include RepositoriesHelper - - def test_from_latin1_to_utf8 - with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do - s1 = "Texte encod\xc3\xa9" - s2 = "Texte encod\xe9" - s3 = s2.dup - if s1.respond_to?(:force_encoding) - s1.force_encoding("UTF-8") - s2.force_encoding("ASCII-8BIT") - s3.force_encoding("UTF-8") - end - assert_equal s1, to_utf8(s2) - assert_equal s1, to_utf8(s3) - end - end - - def test_from_euc_jp_to_utf8 - with_settings :repositories_encodings => 'UTF-8,EUC-JP' do - s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3" - s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3" - s3 = s2.dup - if s1.respond_to?(:force_encoding) - s1.force_encoding("UTF-8") - s2.force_encoding("ASCII-8BIT") - s3.force_encoding("UTF-8") - end - assert_equal s1, to_utf8(s2) - assert_equal s1, to_utf8(s3) - end - end - - def test_to_utf8_should_be_converted_all_latin1_to_utf8 - with_settings :repositories_encodings => 'ISO-8859-1' do - s1 = "\xc3\x82\xc2\x80" - s2 = "\xC2\x80" - s3 = s2.dup - if s1.respond_to?(:force_encoding) - s1.force_encoding("UTF-8") - s2.force_encoding("ASCII-8BIT") - s3.force_encoding("UTF-8") - end - assert_equal s1, to_utf8(s2) - assert_equal s1, to_utf8(s3) - end - end - - def test_to_utf8_blank_string - assert_equal "", to_utf8("") - assert_equal nil, to_utf8(nil) - end - - def test_to_utf8_returns_ascii_as_utf8 - s1 = "ASCII" - s2 = s1.dup - if s1.respond_to?(:force_encoding) - s1.force_encoding("UTF-8") - s2.force_encoding("ISO-8859-1") - end - str1 = to_utf8(s1) - str2 = to_utf8(s2) - assert_equal s1, str1 - assert_equal s1, str2 - if s1.respond_to?(:force_encoding) - assert_equal "UTF-8", str1.encoding.to_s - assert_equal "UTF-8", str2.encoding.to_s - end - end - - def test_to_utf8_invalid_utf8_sequences_should_be_stripped - with_settings :repositories_encodings => '' do - # s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") - s1 = "Texte encod\xe9 en ISO-8859-1." - s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding) - str = to_utf8(s1) - if str.respond_to?(:force_encoding) - assert str.valid_encoding? - assert_equal "UTF-8", str.encoding.to_s - end - assert_equal "Texte encod? en ISO-8859-1.", str - end - end - - def test_to_utf8_invalid_utf8_sequences_should_be_stripped_ja_jis - with_settings :repositories_encodings => 'ISO-2022-JP' do - s1 = "test\xb5\xfetest\xb5\xfe" - s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding) - str = to_utf8(s1) - if str.respond_to?(:force_encoding) - assert str.valid_encoding? - assert_equal "UTF-8", str.encoding.to_s - end - assert_equal "test??test??", str - end - end -end diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/search_helper_test.rb --- a/test/unit/helpers/search_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/search_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,44 +1,44 @@ # encoding: utf-8 # # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) -class SearchHelperTest < HelperTestCase +class SearchHelperTest < ActionView::TestCase include SearchHelper - + def test_highlight_single_token assert_equal 'This is a token.', highlight_tokens('This is a token.', %w(token)) end - + def test_highlight_multiple_tokens assert_equal 'This is a token and another token.', highlight_tokens('This is a token and another token.', %w(token another)) end - + def test_highlight_should_not_exceed_maximum_length s = (('1234567890' * 100) + ' token ') * 100 r = highlight_tokens(s, %w(token)) assert r.include?('token') assert r.length <= 1300 end - + def test_highlight_multibyte s = ('й' * 200) + ' token ' + ('й' * 200) r = highlight_tokens(s, %w(token)) diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/sort_helper_test.rb --- a/test/unit/helpers/sort_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/sort_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,83 +1,83 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) -class SortHelperTest < HelperTestCase +class SortHelperTest < ActionView::TestCase include SortHelper - + def setup @session = nil @sort_param = nil end - + def test_default_sort_clause_with_array sort_init 'attr1', 'desc' sort_update(['attr1', 'attr2']) assert_equal 'attr1 DESC', sort_clause end - + def test_default_sort_clause_with_hash sort_init 'attr1', 'desc' sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) assert_equal 'table1.attr1 DESC', sort_clause end - + def test_default_sort_clause_with_multiple_columns sort_init 'attr1', 'desc' sort_update({'attr1' => ['table1.attr1', 'table1.attr2'], 'attr2' => 'table2.attr2'}) assert_equal 'table1.attr1 DESC, table1.attr2 DESC', sort_clause end - + def test_params_sort @sort_param = 'attr1,attr2:desc' - + sort_init 'attr1', 'desc' sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) assert_equal 'table1.attr1, table2.attr2 DESC', sort_clause assert_equal 'attr1,attr2:desc', @session['foo_bar_sort'] end - + def test_invalid_params_sort @sort_param = 'invalid_key' - + sort_init 'attr1', 'desc' sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) assert_equal 'table1.attr1 DESC', sort_clause assert_equal 'attr1:desc', @session['foo_bar_sort'] end - + def test_invalid_order_params_sort @sort_param = 'attr1:foo:bar,attr2' - + sort_init 'attr1', 'desc' sort_update({'attr1' => 'table1.attr1', 'attr2' => 'table2.attr2'}) assert_equal 'table1.attr1, table2.attr2', sort_clause assert_equal 'attr1,attr2', @session['foo_bar_sort'] end - + private - + def controller_name; 'foo'; end def action_name; 'bar'; end def params; {:sort => @sort_param}; end diff -r 487d96eac004 -r 5e80956cc792 test/unit/helpers/timelog_helper_test.rb --- a/test/unit/helpers/timelog_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/helpers/timelog_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,35 +1,35 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../test_helper', __FILE__) -class TimelogHelperTest < HelperTestCase +class TimelogHelperTest < ActionView::TestCase include TimelogHelper include ActionView::Helpers::TextHelper include ActionView::Helpers::DateHelper - + fixtures :projects, :roles, :enabled_modules, :users, - :repositories, :changesets, + :repositories, :changesets, :trackers, :issue_statuses, :issues, :versions, :documents, :wikis, :wiki_pages, :wiki_contents, :boards, :messages, :attachments, :enumerations - + def setup super end @@ -39,7 +39,7 @@ assert activities.include?(["Design", 9]) assert activities.include?(["Development", 10]) end - + def test_activities_collection_for_select_options_should_not_include_inactive_activities activities = activity_collection_for_select_options assert !activities.include?(["Inactive Activity", 14]) diff -r 487d96eac004 -r 5e80956cc792 test/unit/issue_category_test.rb --- a/test/unit/issue_category_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/issue_category_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,14 +23,27 @@ def setup @category = IssueCategory.find(1) end - + + def test_create + assert IssueCategory.new(:project_id => 2, :name => 'New category').save + category = IssueCategory.first(:order => 'id DESC') + assert_equal 'New category', category.name + end + + def test_create_with_group_assignment + assert IssueCategory.new(:project_id => 2, :name => 'Group assignment', :assigned_to_id => 11).save + category = IssueCategory.first(:order => 'id DESC') + assert_kind_of Group, category.assigned_to + assert_equal Group.find(11), category.assigned_to + end + def test_destroy issue = @category.issues.first @category.destroy # Make sure the category was nullified on the issue assert_nil issue.reload.category end - + def test_destroy_with_reassign issue = @category.issues.first reassign_to = IssueCategory.find(2) diff -r 487d96eac004 -r 5e80956cc792 test/unit/issue_nested_set_test.rb --- a/test/unit/issue_nested_set_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/issue_nested_set_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -51,9 +51,10 @@ def test_creating_a_child_in_different_project_should_not_validate issue = create_issue! - child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, :subject => 'child', :parent_issue_id => issue.id) + child = Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, + :subject => 'child', :parent_issue_id => issue.id) assert !child.save - assert_not_nil child.errors.on(:parent_issue_id) + assert_not_nil child.errors[:parent_issue_id] end def test_move_a_root_to_child @@ -178,7 +179,7 @@ child.reload child.parent_issue_id = grandchild.id assert !child.save - assert_not_nil child.errors.on(:parent_issue_id) + assert_not_nil child.errors[:parent_issue_id] end def test_moving_an_issue_should_keep_valid_relations_only @@ -222,6 +223,20 @@ assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt] assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt] end + + def test_destroy_child_should_update_parent + issue = create_issue! + child1 = create_issue!(:parent_issue_id => issue.id) + child2 = create_issue!(:parent_issue_id => issue.id) + + issue.reload + assert_equal [issue.id, 1, 6], [issue.root_id, issue.lft, issue.rgt] + + child2.reload.destroy + + issue.reload + assert_equal [issue.id, 1, 4], [issue.root_id, issue.lft, issue.rgt] + end def test_destroy_parent_issue_updated_during_children_destroy parent = create_issue! @@ -253,6 +268,20 @@ assert root.leaf?, "Root issue is not a leaf (lft: #{root.lft}, rgt: #{root.rgt})" end + def test_destroy_issue_with_grand_child + parent = create_issue! + issue = create_issue!(:parent_issue_id => parent.id) + child = create_issue!(:parent_issue_id => issue.id) + grandchild1 = create_issue!(:parent_issue_id => child.id) + grandchild2 = create_issue!(:parent_issue_id => child.id) + + assert_difference 'Issue.count', -4 do + Issue.find(issue.id).destroy + parent.reload + assert_equal [1, 2], [parent.lft, parent.rgt] + end + end + def test_parent_priority_should_be_the_highest_child_priority parent = create_issue!(:priority => IssuePriority.find_by_name('Normal')) # Create children diff -r 487d96eac004 -r 5e80956cc792 test/unit/issue_priority_test.rb --- a/test/unit/issue_priority_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/issue_priority_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -23,7 +23,7 @@ def test_should_be_an_enumeration assert IssuePriority.ancestors.include?(Enumeration) end - + def test_objects_count # low priority assert_equal 6, IssuePriority.find(4).objects_count diff -r 487d96eac004 -r 5e80956cc792 test/unit/issue_relation_test.rb --- a/test/unit/issue_relation_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/issue_relation_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -23,67 +23,77 @@ def test_create from = Issue.find(1) to = Issue.find(2) - - relation = IssueRelation.new :issue_from => from, :issue_to => to, :relation_type => IssueRelation::TYPE_PRECEDES + + relation = IssueRelation.new :issue_from => from, :issue_to => to, + :relation_type => IssueRelation::TYPE_PRECEDES assert relation.save relation.reload assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type assert_equal from, relation.issue_from assert_equal to, relation.issue_to end - + + def test_create_minimum + relation = IssueRelation.new :issue_from => Issue.find(1), :issue_to => Issue.find(2) + assert relation.save + assert_equal IssueRelation::TYPE_RELATES, relation.relation_type + end + def test_follows_relation_should_be_reversed from = Issue.find(1) to = Issue.find(2) - - relation = IssueRelation.new :issue_from => from, :issue_to => to, :relation_type => IssueRelation::TYPE_FOLLOWS + + relation = IssueRelation.new :issue_from => from, :issue_to => to, + :relation_type => IssueRelation::TYPE_FOLLOWS assert relation.save relation.reload assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type assert_equal to, relation.issue_from assert_equal from, relation.issue_to end - - # TODO : document why it shouldn't be reversed if validation fails : having - # relations reversed before the validation would allow simpler code for the - # validation + def test_follows_relation_should_not_be_reversed_if_validation_fails from = Issue.find(1) to = Issue.find(2) - - relation = IssueRelation.new :issue_from => from, :issue_to => to, :relation_type => IssueRelation::TYPE_FOLLOWS, :delay => 'xx' + + relation = IssueRelation.new :issue_from => from, :issue_to => to, + :relation_type => IssueRelation::TYPE_FOLLOWS, + :delay => 'xx' assert !relation.save assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type assert_equal from, relation.issue_from assert_equal to, relation.issue_to end - + def test_relation_type_for from = Issue.find(1) to = Issue.find(2) - - relation = IssueRelation.new :issue_from => from, :issue_to => to, :relation_type => IssueRelation::TYPE_PRECEDES + + relation = IssueRelation.new :issue_from => from, :issue_to => to, + :relation_type => IssueRelation::TYPE_PRECEDES assert_equal IssueRelation::TYPE_PRECEDES, relation.relation_type_for(from) assert_equal IssueRelation::TYPE_FOLLOWS, relation.relation_type_for(to) end - + def test_set_issue_to_dates_without_issue_to - r = IssueRelation.new(:issue_from => Issue.new(:start_date => Date.today), :relation_type => IssueRelation::TYPE_PRECEDES, :delay => 1) + r = IssueRelation.new(:issue_from => Issue.new(:start_date => Date.today), + :relation_type => IssueRelation::TYPE_PRECEDES, + :delay => 1) assert_nil r.set_issue_to_dates end - + def test_set_issue_to_dates_without_issues r = IssueRelation.new(:relation_type => IssueRelation::TYPE_PRECEDES, :delay => 1) assert_nil r.set_issue_to_dates end - + def test_validates_circular_dependency IssueRelation.delete_all assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES) assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES) r = IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_PRECEDES) assert !r.save - assert_not_nil r.errors.on(:base) + assert_not_nil r.errors[:base] end def test_validates_circular_dependency_on_reverse_relations @@ -92,6 +102,6 @@ assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_BLOCKED) r = IssueRelation.new(:issue_from => Issue.find(2), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_BLOCKED) assert !r.save - assert_not_nil r.errors.on(:base) + assert_not_nil r.errors[:base] end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/issue_status_test.rb --- a/test/unit/issue_status_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/issue_status_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -25,12 +25,12 @@ assert !status.save # status name uniqueness assert_equal 1, status.errors.count - + status.name = "Test Status" assert status.save assert !status.is_default end - + def test_destroy status = IssueStatus.find(3) assert_difference 'IssueStatus.count', -1 do @@ -50,28 +50,28 @@ status = IssueStatus.default assert_kind_of IssueStatus, status end - + def test_change_default status = IssueStatus.find(2) assert !status.is_default status.is_default = true assert status.save status.reload - + assert_equal status, IssueStatus.default assert !IssueStatus.find(1).is_default end - + def test_reorder_should_not_clear_default_status status = IssueStatus.default status.move_to_bottom status.reload assert status.is_default? end - + def test_new_statuses_allowed_to Workflow.delete_all - + Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false) Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3, :author => true, :assignee => false) Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4, :author => false, :assignee => true) @@ -82,13 +82,13 @@ assert_equal [2], status.new_statuses_allowed_to([role], tracker, false, false).map(&:id) assert_equal [2], status.find_new_statuses_allowed_to([role], tracker, false, false).map(&:id) - - assert_equal [2, 3], status.new_statuses_allowed_to([role], tracker, true, false).map(&:id) - assert_equal [2, 3], status.find_new_statuses_allowed_to([role], tracker, true, false).map(&:id) - - assert_equal [2, 4], status.new_statuses_allowed_to([role], tracker, false, true).map(&:id) - assert_equal [2, 4], status.find_new_statuses_allowed_to([role], tracker, false, true).map(&:id) - + + assert_equal [2, 3, 5], status.new_statuses_allowed_to([role], tracker, true, false).map(&:id) + assert_equal [2, 3, 5], status.find_new_statuses_allowed_to([role], tracker, true, false).map(&:id) + + assert_equal [2, 4, 5], status.new_statuses_allowed_to([role], tracker, false, true).map(&:id) + assert_equal [2, 4, 5], status.find_new_statuses_allowed_to([role], tracker, false, true).map(&:id) + assert_equal [2, 3, 4, 5], status.new_statuses_allowed_to([role], tracker, true, true).map(&:id) assert_equal [2, 3, 4, 5], status.find_new_statuses_allowed_to([role], tracker, true, true).map(&:id) end @@ -99,12 +99,12 @@ @issue_status = IssueStatus.find(1) @issue_status.update_attribute(:default_done_ratio, 50) end - + context "with Setting.issue_done_ratio using the issue_field" do setup do Setting.issue_done_ratio = 'issue_field' end - + should "change nothing" do IssueStatus.update_issue_done_ratios @@ -116,10 +116,10 @@ setup do Setting.issue_done_ratio = 'issue_status' end - + should "update all of the issue's done_ratios to match their Issue Status" do IssueStatus.update_issue_done_ratios - + issues = Issue.find([1,3,4,5,6,7,9,10]) issues.each do |issue| assert_equal @issue_status, issue.status diff -r 487d96eac004 -r 5e80956cc792 test/unit/issue_test.rb --- a/test/unit/issue_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/issue_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -29,14 +29,19 @@ :time_entries def test_create - issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :description => 'IssueTest#test_create', :estimated_hours => '1:30') + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'test_create', + :description => 'IssueTest#test_create', :estimated_hours => '1:30') assert issue.save issue.reload assert_equal 1.5, issue.estimated_hours end def test_create_minimal - issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create') + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'test_create') assert issue.save assert issue.description.nil? end @@ -45,7 +50,9 @@ field = IssueCustomField.find_by_name('Database') field.update_attribute(:is_required, true) - issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field') + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :subject => 'test_create', + :description => 'IssueTest#test_create_with_required_custom_field') assert issue.available_custom_fields.include?(field) # No value for the custom field assert !issue.save @@ -65,6 +72,17 @@ assert_equal 'PostgreSQL', issue.custom_value_for(field).value end + def test_create_with_group_assignment + with_settings :issue_group_assignment => '1' do + assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, + :subject => 'Group assignment', + :assigned_to_id => 11).save + issue = Issue.first(:order => 'id DESC') + assert_kind_of Group, issue.assigned_to + assert_equal Group.find(11), issue.assigned_to + end + end + def assert_visibility_match(user, issues) assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort end @@ -80,7 +98,9 @@ def test_visible_scope_for_anonymous_with_own_issues_visibility Role.anonymous.update_attribute :issues_visibility, 'own' - Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => User.anonymous.id, :subject => 'Issue by anonymous') + Issue.create!(:project_id => 1, :tracker_id => 1, + :author_id => User.anonymous.id, + :subject => 'Issue by anonymous') issues = Issue.visible(User.anonymous).all assert issues.any? @@ -140,6 +160,29 @@ assert_visibility_match user, issues end + def test_visible_scope_for_member_with_groups_should_return_assigned_issues + user = User.find(8) + assert user.groups.any? + Member.create!(:principal => user.groups.first, :project_id => 1, :role_ids => [2]) + Role.non_member.remove_permission!(:view_issues) + + issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Assignment test', + :assigned_to => user.groups.first, + :is_private => true) + + Role.find(2).update_attribute :issues_visibility, 'default' + issues = Issue.visible(User.find(8)).all + assert issues.any? + assert issues.include?(issue) + + Role.find(2).update_attribute :issues_visibility, 'own' + issues = Issue.visible(User.find(8)).all + assert issues.any? + assert issues.include?(issue) + end + def test_visible_scope_for_admin user = User.find(1) user.members.each(&:destroy) @@ -176,14 +219,17 @@ def test_errors_full_messages_should_include_custom_fields_errors field = IssueCustomField.find_by_name('Database') - issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field') + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :subject => 'test_create', + :description => 'IssueTest#test_create_with_required_custom_field') assert issue.available_custom_fields.include?(field) # Invalid value issue.custom_field_values = { field.id => 'SQLServer' } assert !issue.valid? assert_equal 1, issue.errors.full_messages.size - assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", issue.errors.full_messages.first + assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", + issue.errors.full_messages.first end def test_update_issue_with_required_custom_field @@ -232,6 +278,22 @@ assert_equal custom_value.id, issue.custom_value_for(field).id end + def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields + issue = Issue.new(:project_id => 1) + issue.attributes = {:tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'Test', :custom_field_values => {'2' => 'Test'}} + issue.save! + + assert !Tracker.find(2).custom_field_ids.include?(2) + + issue = Issue.find(issue.id) + issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}} + + issue = Issue.find(issue.id) + custom_value = issue.custom_value_for(2) + assert_not_nil custom_value + assert_equal 'Test', custom_value.value + end + def test_assigning_tracker_id_should_reload_custom_fields_values issue = Issue.new(:project => Project.find(1)) assert issue.custom_field_values.empty? @@ -269,11 +331,14 @@ issue.tracker_id = 2 issue.subject = 'New subject' assert !issue.save - assert_not_nil issue.errors.on(:tracker_id) + assert_not_nil issue.errors[:tracker_id] end def test_category_based_assignment - issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1) + issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Assignment test', + :description => 'Assignment test', :category_id => 1) assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to end @@ -293,10 +358,10 @@ assert_equal [1, 2], issue.new_statuses_allowed_to(user).map(&:id) issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user) - assert_equal [1, 2, 3], issue.new_statuses_allowed_to(user).map(&:id) + assert_equal [1, 2, 3, 5], issue.new_statuses_allowed_to(user).map(&:id) issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :assigned_to => user) - assert_equal [1, 2, 4], issue.new_statuses_allowed_to(user).map(&:id) + assert_equal [1, 2, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) issue = Issue.generate!(:tracker => tracker, :status => status, :project_id => 1, :author => user, :assigned_to => user) assert_equal [1, 2, 3, 4, 5], issue.new_statuses_allowed_to(user).map(&:id) @@ -324,7 +389,9 @@ def test_should_close_duplicates # Create 3 issues - issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test') + issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Duplicates test', :description => 'Duplicates test') assert issue1.save issue2 = issue1.clone assert issue2.save @@ -351,7 +418,9 @@ def test_should_not_close_duplicated_issue # Create 3 issues - issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test') + issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, + :status_id => 1, :priority => IssuePriority.all.first, + :subject => 'Duplicates test', :description => 'Duplicates test') assert issue1.save issue2 = issue1.clone assert issue2.save @@ -377,13 +446,13 @@ def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') assert !issue.save - assert_not_nil issue.errors.on(:fixed_version_id) + assert_not_nil issue.errors[:fixed_version_id] end def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue') assert !issue.save - assert_not_nil issue.errors.on(:fixed_version_id) + assert_not_nil issue.errors[:fixed_version_id] end def test_should_be_able_to_assign_a_new_issue_to_an_open_version @@ -402,7 +471,7 @@ issue = Issue.find(11) issue.status_id = 1 assert !issue.save - assert_not_nil issue.errors.on_base + assert_not_nil issue.errors[:base] end def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version @@ -580,6 +649,16 @@ assert !copy.recipients.include?(copy.author.mail) end + def test_recipients_should_include_the_assigned_group_members + group_member = User.generate_with_protected! + group = Group.generate! + group.users << group_member + + issue = Issue.find(12) + issue.assigned_to = group + assert issue.recipients.include?(group_member.mail) + end + def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue user = User.find(3) issue = Issue.find(9) @@ -674,6 +753,15 @@ assert issue.assignable_users.include?(non_project_member) end + should "include the current assignee" do + project = Project.find(1) + user = User.generate! + issue = Issue.generate_for_project!(project, :assigned_to => user) + user.lock! + + assert Issue.find(issue.id).assignable_users.include?(user) + end + should "not show the issue author twice" do assignable_user_ids = Issue.find(1).assignable_users.collect(&:id) assert_equal 2, assignable_user_ids.length @@ -682,11 +770,36 @@ assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once" end end + + context "with issue_group_assignment" do + should "include groups" do + issue = Issue.new(:project => Project.find(2)) + + with_settings :issue_group_assignment => '1' do + assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort + assert issue.assignable_users.include?(Group.find(11)) + end + end + end + + context "without issue_group_assignment" do + should "not include groups" do + issue = Issue.new(:project => Project.find(2)) + + with_settings :issue_group_assignment => '0' do + assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort + assert !issue.assignable_users.include?(Group.find(11)) + end + end + end end def test_create_should_send_email_notification ActionMailer::Base.deliveries.clear - issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :estimated_hours => '1:30') + issue = Issue.new(:project_id => 1, :tracker_id => 1, + :author_id => 3, :status_id => 1, + :priority => IssuePriority.all.first, + :subject => 'test_create', :estimated_hours => '1:30') assert issue.save assert_equal 1, ActionMailer::Base.deliveries.size @@ -733,23 +846,23 @@ assert_equal old_description, detail.old_value assert_equal new_description, detail.value end - + def test_blank_descriptions_should_not_be_journalized IssueCustomField.delete_all Issue.update_all("description = NULL", "id=1") - + i = Issue.find(1) i.init_journal(User.find(2)) i.subject = "blank description" i.description = "\r\n" - + assert_difference 'Journal.count', 1 do assert_difference 'JournalDetail.count', 1 do i.save! end end end - + def test_description_eol_should_be_normalized i = Issue.new(:description => "CR \r LF \n CRLF \r\n") assert_equal "CR \r\n LF \r\n CRLF \r\n", i.description @@ -781,31 +894,53 @@ def test_all_dependent_issues IssueRelation.delete_all - assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES) - assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES) - assert IssueRelation.create!(:issue_from => Issue.find(3), :issue_to => Issue.find(8), :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(1), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(2), + :issue_to => Issue.find(3), + :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(3), + :issue_to => Issue.find(8), + :relation_type => IssueRelation::TYPE_PRECEDES) assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort end def test_all_dependent_issues_with_persistent_circular_dependency IssueRelation.delete_all - assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES) - assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(1), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_PRECEDES) + assert IssueRelation.create!(:issue_from => Issue.find(2), + :issue_to => Issue.find(3), + :relation_type => IssueRelation::TYPE_PRECEDES) # Validation skipping - assert IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_PRECEDES).save(false) + assert IssueRelation.new(:issue_from => Issue.find(3), + :issue_to => Issue.find(1), + :relation_type => IssueRelation::TYPE_PRECEDES).save(false) assert_equal [2, 3], Issue.find(1).all_dependent_issues.collect(&:id).sort end def test_all_dependent_issues_with_persistent_multiple_circular_dependencies IssueRelation.delete_all - assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_RELATES) - assert IssueRelation.create!(:issue_from => Issue.find(2), :issue_to => Issue.find(3), :relation_type => IssueRelation::TYPE_RELATES) - assert IssueRelation.create!(:issue_from => Issue.find(3), :issue_to => Issue.find(8), :relation_type => IssueRelation::TYPE_RELATES) + assert IssueRelation.create!(:issue_from => Issue.find(1), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_RELATES) + assert IssueRelation.create!(:issue_from => Issue.find(2), + :issue_to => Issue.find(3), + :relation_type => IssueRelation::TYPE_RELATES) + assert IssueRelation.create!(:issue_from => Issue.find(3), + :issue_to => Issue.find(8), + :relation_type => IssueRelation::TYPE_RELATES) # Validation skipping - assert IssueRelation.new(:issue_from => Issue.find(8), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_RELATES).save(false) - assert IssueRelation.new(:issue_from => Issue.find(3), :issue_to => Issue.find(1), :relation_type => IssueRelation::TYPE_RELATES).save(false) + assert IssueRelation.new(:issue_from => Issue.find(8), + :issue_to => Issue.find(2), + :relation_type => IssueRelation::TYPE_RELATES).save(false) + assert IssueRelation.new(:issue_from => Issue.find(3), + :issue_to => Issue.find(1), + :relation_type => IssueRelation::TYPE_RELATES).save(false) assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/access_control_test.rb --- a/test/unit/lib/redmine/access_control_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/access_control_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,17 +18,17 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::AccessControlTest < ActiveSupport::TestCase - + def setup @access_module = Redmine::AccessControl end - + def test_permissions perms = @access_module.permissions assert perms.is_a?(Array) assert perms.first.is_a?(Redmine::AccessControl::Permission) end - + def test_module_permission perm = @access_module.permission(:view_issues) assert perm.is_a?(Redmine::AccessControl::Permission) @@ -37,7 +37,7 @@ assert perm.actions.is_a?(Array) assert perm.actions.include?('issues/index') end - + def test_no_module_permission perm = @access_module.permission(:edit_project) assert perm.is_a?(Redmine::AccessControl::Permission) diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/ciphering_test.rb --- a/test/unit/lib/redmine/ciphering_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/ciphering_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,7 +18,7 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::CipheringTest < ActiveSupport::TestCase - + def test_password_should_be_encrypted Redmine::Configuration.with 'database_cipher_key' => 'secret' do r = Repository::Subversion.generate!(:password => 'foo') @@ -26,7 +26,7 @@ assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/) end end - + def test_password_should_be_clear_with_blank_key Redmine::Configuration.with 'database_cipher_key' => '' do r = Repository::Subversion.generate!(:password => 'foo') @@ -34,7 +34,7 @@ assert_equal 'foo', r.read_attribute(:password) end end - + def test_password_should_be_clear_with_nil_key Redmine::Configuration.with 'database_cipher_key' => nil do r = Repository::Subversion.generate!(:password => 'foo') @@ -42,25 +42,47 @@ assert_equal 'foo', r.read_attribute(:password) end end - + + def test_blank_password_should_be_clear + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + r = Repository::Subversion.generate!(:password => '') + assert_equal '', r.password + assert_equal '', r.read_attribute(:password) + end + end + def test_unciphered_password_should_be_readable Redmine::Configuration.with 'database_cipher_key' => nil do r = Repository::Subversion.generate!(:password => 'clear') end - + Redmine::Configuration.with 'database_cipher_key' => 'secret' do r = Repository.first(:order => 'id DESC') assert_equal 'clear', r.password end end + def test_ciphered_password_with_no_cipher_key_configured_should_be_returned_ciphered + Redmine::Configuration.with 'database_cipher_key' => 'secret' do + r = Repository::Subversion.generate!(:password => 'clear') + end + + Redmine::Configuration.with 'database_cipher_key' => '' do + r = Repository.first(:order => 'id DESC') + # password can not be deciphered + assert_nothing_raised do + assert r.password.match(/\Aaes-256-cbc:.+\Z/) + end + end + end + def test_encrypt_all Repository.delete_all Redmine::Configuration.with 'database_cipher_key' => nil do Repository::Subversion.generate!(:password => 'foo') Repository::Subversion.generate!(:password => 'bar') end - + Redmine::Configuration.with 'database_cipher_key' => 'secret' do assert Repository.encrypt_all(:password) r = Repository.first(:order => 'id DESC') @@ -68,13 +90,13 @@ assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/) end end - + def test_decrypt_all Repository.delete_all Redmine::Configuration.with 'database_cipher_key' => 'secret' do Repository::Subversion.generate!(:password => 'foo') Repository::Subversion.generate!(:password => 'bar') - + assert Repository.decrypt_all(:password) r = Repository.first(:order => 'id DESC') assert_equal 'bar', r.password diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/codeset_util_test.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/unit/lib/redmine/codeset_util_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,115 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 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.expand_path('../../../../test_helper', __FILE__) + +class Redmine::CodesetUtilTest < ActiveSupport::TestCase + + def test_to_utf8_by_setting_from_latin1 + with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do + s1 = "Texte encod\xc3\xa9" + s2 = "Texte encod\xe9" + s3 = s2.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ASCII-8BIT") + s3.force_encoding("UTF-8") + end + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3) + end + end + + def test_to_utf8_by_setting_from_euc_jp + with_settings :repositories_encodings => 'UTF-8,EUC-JP' do + s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3" + s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3" + s3 = s2.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ASCII-8BIT") + s3.force_encoding("UTF-8") + end + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3) + end + end + + def test_to_utf8_by_setting_should_be_converted_all_latin1 + with_settings :repositories_encodings => 'ISO-8859-1' do + s1 = "\xc3\x82\xc2\x80" + s2 = "\xC2\x80" + s3 = s2.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ASCII-8BIT") + s3.force_encoding("UTF-8") + end + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3) + end + end + + def test_to_utf8_by_setting_blank_string + assert_equal "", Redmine::CodesetUtil.to_utf8_by_setting("") + assert_equal nil, Redmine::CodesetUtil.to_utf8_by_setting(nil) + end + + def test_to_utf8_by_setting_returns_ascii_as_utf8 + s1 = "ASCII" + s2 = s1.dup + if s1.respond_to?(:force_encoding) + s1.force_encoding("UTF-8") + s2.force_encoding("ISO-8859-1") + end + str1 = Redmine::CodesetUtil.to_utf8_by_setting(s1) + str2 = Redmine::CodesetUtil.to_utf8_by_setting(s2) + assert_equal s1, str1 + assert_equal s1, str2 + if s1.respond_to?(:force_encoding) + assert_equal "UTF-8", str1.encoding.to_s + assert_equal "UTF-8", str2.encoding.to_s + end + end + + def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped + with_settings :repositories_encodings => '' do + # s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") + s1 = "Texte encod\xe9 en ISO-8859-1." + s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding) + str = Redmine::CodesetUtil.to_utf8_by_setting(s1) + if str.respond_to?(:force_encoding) + assert str.valid_encoding? + assert_equal "UTF-8", str.encoding.to_s + end + assert_equal "Texte encod? en ISO-8859-1.", str + end + end + + def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped_ja_jis + with_settings :repositories_encodings => 'ISO-2022-JP' do + s1 = "test\xb5\xfetest\xb5\xfe" + s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding) + str = Redmine::CodesetUtil.to_utf8_by_setting(s1) + if str.respond_to?(:force_encoding) + assert str.valid_encoding? + assert_equal "UTF-8", str.encoding.to_s + end + assert_equal "test??test??", str + end + end +end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/configuration_test.rb --- a/test/unit/lib/redmine/configuration_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/configuration_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -25,22 +25,22 @@ def test_empty assert_kind_of Hash, load_conf('empty.yml', 'test') end - + def test_default assert_kind_of Hash, load_conf('default.yml', 'test') assert_equal 'foo', @conf['somesetting'] end - + def test_no_default assert_kind_of Hash, load_conf('no_default.yml', 'test') assert_equal 'foo', @conf['somesetting'] end - + def test_overrides assert_kind_of Hash, load_conf('overrides.yml', 'test') assert_equal 'bar', @conf['somesetting'] end - + def test_with load_conf('default.yml', 'test') assert_equal 'foo', @conf['somesetting'] @@ -49,9 +49,9 @@ end assert_equal 'foo', @conf['somesetting'] end - + private - + def load_conf(file, env) @conf.load( :file => File.join(Rails.root, 'test', 'fixtures', 'configuration', file), diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/export/pdf_test.rb --- a/test/unit/lib/redmine/export/pdf_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/export/pdf_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -19,38 +19,23 @@ require 'iconv' class PdfTest < ActiveSupport::TestCase - include Redmine::I18n + fixtures :users, :projects, :roles, :members, :member_roles, + :enabled_modules, :issues, :trackers, :attachments def test_fix_text_encoding_nil - set_language_if_valid 'ja' - assert_equal 'CP932', l(:general_pdf_encoding) - if RUBY_VERSION < '1.9' - if RUBY_PLATFORM == 'java' - ic = Iconv.new("SJIS", 'UTF-8') - else - ic = Iconv.new(l(:general_pdf_encoding), 'UTF-8') - end - end - assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, nil) + assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(nil, "UTF-8") + assert_equal '', Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(nil, "ISO-8859-1") end def test_rdm_pdf_iconv_cannot_convert_ja_cp932 - set_language_if_valid 'ja' - assert_equal 'CP932', l(:general_pdf_encoding) - if RUBY_VERSION < '1.9' - if RUBY_PLATFORM == 'java' - ic = Iconv.new("SJIS", 'UTF-8') - else - ic = Iconv.new(l(:general_pdf_encoding), 'UTF-8') - end - end + encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" ) utf8_txt_1 = "\xe7\x8b\x80\xe6\x85\x8b" utf8_txt_2 = "\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80" utf8_txt_3 = "\xe7\x8b\x80\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80" if utf8_txt_1.respond_to?(:force_encoding) - txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_1) - txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_2) - txt_3 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_3) + txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding) + txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding) + txt_3 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding) assert_equal "?\x91\xd4", txt_1 assert_equal "?\x91\xd4?", txt_2 assert_equal "??\x91\xd4?", txt_3 @@ -59,33 +44,28 @@ assert_equal "ASCII-8BIT", txt_3.encoding.to_s elsif RUBY_PLATFORM == 'java' assert_equal "??", - Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_1) + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding) assert_equal "???", - Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_2) + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding) assert_equal "????", - Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_3) + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding) else assert_equal "???\x91\xd4", - Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_1) + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding) assert_equal "???\x91\xd4???", - Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_2) + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding) assert_equal "??????\x91\xd4???", - Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, utf8_txt_3) + Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding) end end def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_en - set_language_if_valid 'en' - assert_equal 'UTF-8', l(:general_pdf_encoding) str1 = "Texte encod\xe9 en ISO-8859-1" str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test" str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding) str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding) - if RUBY_VERSION < '1.9' - ic = Iconv.new(l(:general_pdf_encoding), 'UTF-8') - end - txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, str1) - txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, str2) + txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, 'UTF-8') + txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, 'UTF-8') if txt_1.respond_to?(:force_encoding) assert_equal "ASCII-8BIT", txt_1.encoding.to_s assert_equal "ASCII-8BIT", txt_2.encoding.to_s @@ -95,21 +75,13 @@ end def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_ja - set_language_if_valid 'ja' - assert_equal 'CP932', l(:general_pdf_encoding) str1 = "Texte encod\xe9 en ISO-8859-1" str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test" str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding) str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding) - if RUBY_VERSION < '1.9' - if RUBY_PLATFORM == 'java' - ic = Iconv.new("SJIS", 'UTF-8') - else - ic = Iconv.new(l(:general_pdf_encoding), 'UTF-8') - end - end - txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, str1) - txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_pdf_iconv(ic, str2) + encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" ) + txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, encoding) + txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, encoding) if txt_1.respond_to?(:force_encoding) assert_equal "ASCII-8BIT", txt_1.encoding.to_s assert_equal "ASCII-8BIT", txt_2.encoding.to_s @@ -117,4 +89,39 @@ assert_equal "Texte encod? en ISO-8859-1", txt_1 assert_equal "?a?b?c?d?e test", txt_2 end + + def test_attach + Attachment.storage_path = "#{Rails.root}/test/fixtures/files" + + str2 = "\x83e\x83X\x83g" + str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding) + encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" ) + + a1 = Attachment.find(17) + a2 = Attachment.find(19) + + User.current = User.find(1) + assert a1.readable? + assert a1.visible? + assert a2.readable? + assert a2.visible? + + aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8") + assert_equal 17, aa1.id + aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding) + assert_equal 19, aa2.id + + User.current = nil + assert a1.readable? + assert (! a1.visible?) + assert a2.readable? + assert (! a2.visible?) + + aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8") + assert_equal nil, aa1 + aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding) + assert_equal nil, aa2 + + set_tmp_attachments_directory + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/helpers/calendar_test.rb --- a/test/unit/lib/redmine/helpers/calendar_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/helpers/calendar_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,14 +18,14 @@ require File.expand_path('../../../../../test_helper', __FILE__) class CalendarTest < ActiveSupport::TestCase - + def test_monthly c = Redmine::Helpers::Calendar.new(Date.today, :fr, :month) assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday] - + c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :month) - assert_equal ['2007-06-25'.to_date, '2007-08-05'.to_date], [c.startdt, c.enddt] - + assert_equal ['2007-06-25'.to_date, '2007-08-05'.to_date], [c.startdt, c.enddt] + c = Redmine::Helpers::Calendar.new(Date.today, :en, :month) assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday] end @@ -33,14 +33,14 @@ def test_weekly c = Redmine::Helpers::Calendar.new(Date.today, :fr, :week) assert_equal [1, 7], [c.startdt.cwday, c.enddt.cwday] - + c = Redmine::Helpers::Calendar.new('2007-07-14'.to_date, :fr, :week) assert_equal ['2007-07-09'.to_date, '2007-07-15'.to_date], [c.startdt, c.enddt] c = Redmine::Helpers::Calendar.new(Date.today, :en, :week) assert_equal [7, 6], [c.startdt.cwday, c.enddt.cwday] end - + def test_monthly_start_day [1, 6, 7].each do |day| with_settings :start_of_week => day do @@ -50,7 +50,7 @@ end end end - + def test_weekly_start_day [1, 6, 7].each do |day| with_settings :start_of_week => day do diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/helpers/gantt_test.rb --- a/test/unit/lib/redmine/helpers/gantt_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/helpers/gantt_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -26,7 +26,7 @@ include ApplicationHelper include ProjectsHelper include IssuesHelper - + def self.default_url_options {:only_path => true } end @@ -78,7 +78,7 @@ 5.times do Issue.generate_for_project!(p) end - + create_gantt(p) @gantt.render assert_equal 6, @gantt.number_of_rows @@ -109,7 +109,7 @@ version = Version.generate! @project.versions << version @project.issues << Issue.generate_for_project!(@project, :fixed_version => version) - + assert_equal 3, @gantt.number_of_rows_on_project(@project) end end @@ -131,56 +131,56 @@ :done_ratio => 30, :start_date => Date.yesterday, :due_date => 1.week.from_now.to_date) - @project.issues << @issue + @project.issues << @issue end - + context "project" do should "be rendered" do @response.body = @gantt.subjects assert_select "div.project-name a", /#{@project.name}/ end - + should "have an indent of 4" do @response.body = @gantt.subjects assert_select "div.project-name[style*=left:4px]" end end - + context "version" do should "be rendered" do @response.body = @gantt.subjects assert_select "div.version-name a", /#{@version.name}/ end - + should "be indented 24 (one level)" do @response.body = @gantt.subjects assert_select "div.version-name[style*=left:24px]" end - + context "without assigned issues" do setup do @version = Version.generate!(:effective_date => 2.week.from_now.to_date, :sharing => 'none', :name => 'empty_version') @project.versions << @version end - + should "not be rendered" do @response.body = @gantt.subjects assert_select "div.version-name a", :text => /#{@version.name}/, :count => 0 end end end - + context "issue" do should "be rendered" do @response.body = @gantt.subjects assert_select "div.issue-subject", /#{@issue.subject}/ end - + should "be indented 44 (two levels)" do @response.body = @gantt.subjects assert_select "div.issue-subject[style*=left:44px]" end - + context "assigned to a shared version of another project" do setup do p = Project.generate! @@ -189,7 +189,7 @@ @shared_version = Version.generate!(:sharing => 'system') p.versions << @shared_version # Reassign the issue to a shared version of another project - + @issue = Issue.generate!(:fixed_version => @shared_version, :subject => "gantt#assigned_to_shared_version", :tracker => @tracker, @@ -199,13 +199,13 @@ :due_date => 1.week.from_now.to_date) @project.issues << @issue end - + should "be rendered" do @response.body = @gantt.subjects assert_select "div.issue-subject", /#{@issue.subject}/ end end - + context "with subtasks" do setup do attrs = {:project => @project, :tracker => @tracker, :fixed_version => @version} @@ -213,7 +213,7 @@ @child2 = Issue.generate!(attrs.merge(:subject => 'child2', :parent_issue_id => @issue.id, :start_date => Date.today, :due_date => 1.week.from_now.to_date)) @grandchild = Issue.generate!(attrs.merge(:subject => 'grandchild', :parent_issue_id => @child1.id, :start_date => Date.yesterday, :due_date => 2.day.from_now.to_date)) end - + should "indent subtasks" do @response.body = @gantt.subjects # parent task 44px @@ -291,7 +291,7 @@ setup do create_gantt end - + context ":html format" do should "add an absolute positioned div" do @response.body = @gantt.subject_for_project(@project, {:format => :html}) @@ -416,7 +416,7 @@ assert_select "div.project.ending[style*=left:88px]", true, @response.body end end - + context "status content" do should "appear at the far left, even if it's far in the past" do @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) @@ -476,7 +476,7 @@ should "include a link to the version" do @response.body = @gantt.subject_for_version(@version, {:format => :html}) - assert_select 'a[href=?]', Regexp.escape("/versions/show/#{@version.to_param}"), :text => /#{@version.name}/ + assert_select 'a[href=?]', Regexp.escape("/versions/#{@version.to_param}"), :text => /#{@version.name}/ end should "style late versions" do @@ -583,7 +583,7 @@ assert_select "div.version.ending[style*=left:88px]", true, @response.body end end - + context "status content" do should "appear at the far left, even if it's far in the past" do @gantt.instance_variable_set('@date_to', 2.weeks.ago.to_date) @@ -715,12 +715,12 @@ should "not be the total done width if the chart starts after issue start date" do create_gantt(@project, :date_from => 5.days.ago.to_date) - + @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) assert_select "div.task_done[style*=left:0px]", true, @response.body assert_select "div.task_done[style*=width:8px]", true, @response.body end - + context "for completed issue" do setup do @issue.done_ratio = 100 @@ -730,7 +730,7 @@ @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) assert_select "div.task_done[style*=width:58px]", true, @response.body end - + should "be the total width of the issue with due_date=start_date" do @issue.due_date = @issue.start_date @response.body = @gantt.line_for_issue(@issue, {:format => :html, :zoom => 4}) @@ -775,5 +775,5 @@ context "#to_pdf" do should "be tested" end - + end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/hook_test.rb --- a/test/unit/lib/redmine/hook_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/hook_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -20,10 +20,10 @@ class Redmine::Hook::ManagerTest < ActiveSupport::TestCase fixtures :issues - + # Some hooks that are manually registered in these tests class TestHook < Redmine::Hook::ViewListener; end - + class TestHook1 < TestHook def view_layouts_base_html_head(context) 'Test hook 1 listener.' @@ -35,13 +35,13 @@ 'Test hook 2 listener.' end end - + class TestHook3 < TestHook def view_layouts_base_html_head(context) "Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}." end end - + class TestLinkToHook < TestHook def view_layouts_base_html_head(context) link_to('Issues', :controller => 'issues') @@ -51,54 +51,54 @@ class TestHookHelperController < ActionController::Base include Redmine::Hook::Helper end - + class TestHookHelperView < ActionView::Base include Redmine::Hook::Helper end - + Redmine::Hook.clear_listeners - + def setup @hook_module = Redmine::Hook end - + def teardown @hook_module.clear_listeners end - + def test_clear_listeners assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size @hook_module.add_listener(TestHook1) @hook_module.add_listener(TestHook2) assert_equal 2, @hook_module.hook_listeners(:view_layouts_base_html_head).size - + @hook_module.clear_listeners assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size end - + def test_add_listener assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size @hook_module.add_listener(TestHook1) assert_equal 1, @hook_module.hook_listeners(:view_layouts_base_html_head).size end - + def test_call_hook @hook_module.add_listener(TestHook1) assert_equal ['Test hook 1 listener.'], hook_helper.call_hook(:view_layouts_base_html_head) end - + def test_call_hook_with_context @hook_module.add_listener(TestHook3) assert_equal ['Context keys: bar, controller, foo, project, request.'], hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a') end - + def test_call_hook_with_multiple_listeners @hook_module.add_listener(TestHook1) @hook_module.add_listener(TestHook2) assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], hook_helper.call_hook(:view_layouts_base_html_head) end - + # Context: Redmine::Hook::Helper.call_hook default_url def test_call_hook_default_url_options @hook_module.add_listener(TestLinkToHook) @@ -111,27 +111,27 @@ @hook_module.add_listener(TestHook3) assert_match /project/i, hook_helper.call_hook(:view_layouts_base_html_head)[0] end - + def test_call_hook_from_controller_with_controller_added_to_context @hook_module.add_listener(TestHook3) assert_match /controller/i, hook_helper.call_hook(:view_layouts_base_html_head)[0] end - + def test_call_hook_from_controller_with_request_added_to_context @hook_module.add_listener(TestHook3) assert_match /request/i, hook_helper.call_hook(:view_layouts_base_html_head)[0] end - + def test_call_hook_from_view_with_project_added_to_context @hook_module.add_listener(TestHook3) assert_match /project/i, view_hook_helper.call_hook(:view_layouts_base_html_head) end - + def test_call_hook_from_view_with_controller_added_to_context @hook_module.add_listener(TestHook3) assert_match /controller/i, view_hook_helper.call_hook(:view_layouts_base_html_head) end - + def test_call_hook_from_view_with_request_added_to_context @hook_module.add_listener(TestHook3) assert_match /request/i, view_hook_helper.call_hook(:view_layouts_base_html_head) @@ -146,27 +146,27 @@ def test_call_hook_should_not_change_the_default_url_for_email_notifications issue = Issue.find(1) - + ActionMailer::Base.deliveries.clear Mailer.deliver_issue_add(issue) mail = ActionMailer::Base.deliveries.last - + @hook_module.add_listener(TestLinkToHook) hook_helper.call_hook(:view_layouts_base_html_head) - + ActionMailer::Base.deliveries.clear Mailer.deliver_issue_add(issue) mail2 = ActionMailer::Base.deliveries.last - + assert_equal mail.body, mail2.body end - + def hook_helper @hook_helper ||= TestHookHelperController.new end def view_hook_helper - @view_hook_helper ||= TestHookHelperView.new(RAILS_ROOT + '/app/views') + @view_hook_helper ||= TestHookHelperView.new(Rails.root.to_s + '/app/views') end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/menu_manager/mapper_test.rb --- a/test/unit/lib/redmine/menu_manager/mapper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/menu_manager/mapper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -64,9 +64,9 @@ assert_not_nil root.children[position] assert_equal name, root.children[position].name end - + end - + def test_push_before menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) menu_mapper.push :test_first, { :controller => 'projects', :action => 'show'}, {} @@ -81,7 +81,7 @@ assert_not_nil root.children[position] assert_equal name, root.children[position].name end - + end def test_push_after @@ -92,14 +92,13 @@ menu_mapper.push :test_fifth, { :controller => 'projects', :action => 'show'}, {} menu_mapper.push :test_fourth, { :controller => 'projects', :action => 'show'}, {:after => :test_third} - root = menu_mapper.find(:root) assert_equal 5, root.children.size {0 => :test_first, 1 => :test_second, 2 => :test_third, 3 => :test_fourth, 4 => :test_fifth}.each do |position, name| assert_not_nil root.children[position] assert_equal name, root.children[position].name end - + end def test_push_last @@ -116,9 +115,9 @@ assert_not_nil root.children[position] assert_equal name, root.children[position].name end - + end - + def test_exists_for_child_node menu_mapper = Redmine::MenuManager::Mapper.new(:test_menu, {}) menu_mapper.push :test_overview, { :controller => 'projects', :action => 'show'}, {} diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/menu_manager/menu_helper_test.rb --- a/test/unit/lib/redmine/menu_manager/menu_helper_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/menu_manager/menu_helper_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,24 +1,22 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) - - class Redmine::MenuManager::MenuHelperTest < HelperTestCase include Redmine::MenuManager::MenuHelper include ActionController::Assertions::SelectorAssertions @@ -28,16 +26,16 @@ def html_document HTML::Document.new(@response.body) end - + def setup super @response = ActionController::TestResponse.new # Stub the current menu item in the controller - def @controller.current_menu_item + def current_menu_item :index end end - + context "MenuManager#current_menu_item" do should "be tested" @@ -74,7 +72,7 @@ assert_select("a.single-node", "Single node") end end - + def test_render_menu_node_with_nested_items parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { }) parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { }) @@ -98,12 +96,12 @@ end end end - + end def test_render_menu_node_with_children User.current = User.find(2) - + parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { @@ -188,7 +186,7 @@ @response.body = render_menu_node(parent_node, Project.find(1)) end end - + def test_render_menu_node_with_incorrect_children parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', @@ -214,7 +212,7 @@ menu_items_for(menu_name) do |item| items_yielded << item end - + assert_equal 3, items_yielded.size end @@ -239,11 +237,11 @@ end User.current = User.find(2) - + items = menu_items_for(menu_name, Project.find(1)) assert_equal 2, items.size end - + def test_menu_items_for_should_skip_items_that_fail_the_conditions menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions Redmine::MenuManager.map menu_name do |menu| @@ -254,7 +252,7 @@ end User.current = User.find(2) - + items = menu_items_for(menu_name, Project.find(1)) assert_equal 1, items.size end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/menu_manager/menu_item_test.rb --- a/test/unit/lib/redmine/menu_manager/menu_item_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/menu_manager/menu_item_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -32,7 +32,7 @@ menu.push(:child_menu, '/test', { :parent => :parent}) menu.push(:child2_menu, '/test', { :parent => :parent}) end - + context "MenuItem#caption" do should "be tested" end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/menu_manager_test.rb --- a/test/unit/lib/redmine/menu_manager_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/menu_manager_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/mime_type_test.rb --- a/test/unit/lib/redmine/mime_type_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/mime_type_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::MimeTypeTest < ActiveSupport::TestCase - + def test_of to_test = {'test.unk' => nil, 'test.txt' => 'text/plain', @@ -28,7 +28,7 @@ assert_equal expected, Redmine::MimeType.of(name) end end - + def test_css_class_of to_test = {'test.unk' => nil, 'test.txt' => 'text-plain', @@ -38,7 +38,7 @@ assert_equal expected, Redmine::MimeType.css_class_of(name) end end - + def test_main_mimetype_of to_test = {'test.unk' => nil, 'test.txt' => 'text', @@ -48,7 +48,7 @@ assert_equal expected, Redmine::MimeType.main_mimetype_of(name) end end - + def test_is_type to_test = {['text', 'test.unk'] => false, ['text', 'test.txt'] => true, diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/notifiable_test.rb --- a/test/unit/lib/redmine/notifiable_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/notifiable_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/plugin_test.rb --- a/test/unit/lib/redmine/plugin_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/plugin_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -24,11 +24,11 @@ # In case some real plugins are installed @klass.clear end - + def teardown @klass.clear end - + def test_register @klass.register :foo do name 'Foo plugin' @@ -39,9 +39,9 @@ version '0.0.1' settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings' end - + assert_equal 1, @klass.all.size - + plugin = @klass.find('foo') assert plugin.is_a?(Redmine::Plugin) assert_equal :foo, plugin.id @@ -52,11 +52,11 @@ assert_equal 'This is a test plugin', plugin.description assert_equal '0.0.1', plugin.version end - + def test_requires_redmine test = self version = Redmine::VERSION.to_a.slice(0,3).join('.') - + @klass.register :foo do test.assert requires_redmine(:version_or_higher => '0.1.0') test.assert requires_redmine(:version_or_higher => version) @@ -64,7 +64,7 @@ test.assert_raise Redmine::PluginRequirementError do requires_redmine(:version_or_higher => '99.0.0') end - + test.assert requires_redmine(:version => version) test.assert requires_redmine(:version => [version, '99.0.0']) test.assert_raise Redmine::PluginRequirementError do @@ -79,12 +79,12 @@ def test_requires_redmine_plugin test = self other_version = '0.5.0' - + @klass.register :other do name 'Other' version other_version end - + @klass.register :foo do test.assert requires_redmine_plugin(:other, :version_or_higher => '0.1.0') test.assert requires_redmine_plugin(:other, :version_or_higher => other_version) @@ -92,7 +92,7 @@ test.assert_raise Redmine::PluginRequirementError do requires_redmine_plugin(:other, :version_or_higher => '99.0.0') end - + test.assert requires_redmine_plugin(:other, :version => other_version) test.assert requires_redmine_plugin(:other, :version => [other_version, '99.0.0']) test.assert_raise Redmine::PluginRequirementError do @@ -111,7 +111,7 @@ test.assert_raise Redmine::PluginNotFound do requires_redmine_plugin(:missing, :version => '0.1.0') end - + end end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/safe_attributes_test.rb --- a/test/unit/lib/redmine/safe_attributes_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/safe_attributes_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::SafeAttributesTest < ActiveSupport::TestCase - + class Base def attributes=(attrs) attrs.each do |key, value| @@ -26,26 +26,26 @@ end end end - + class Person < Base attr_accessor :firstname, :lastname, :login include Redmine::SafeAttributes safe_attributes :firstname, :lastname safe_attributes :login, :if => lambda {|person, user| user.admin?} end - + class Book < Base attr_accessor :title include Redmine::SafeAttributes safe_attributes :title end - + def test_safe_attribute_names p = Person.new assert_equal ['firstname', 'lastname'], p.safe_attribute_names(User.anonymous) assert_equal ['firstname', 'lastname', 'login'], p.safe_attribute_names(User.find(1)) end - + def test_safe_attribute_names_without_user p = Person.new User.current = nil @@ -53,7 +53,7 @@ User.current = User.find(1) assert_equal ['firstname', 'lastname', 'login'], p.safe_attribute_names end - + def test_set_safe_attributes p = Person.new p.send('safe_attributes=', {'firstname' => 'John', 'lastname' => 'Smith', 'login' => 'jsmith'}, User.anonymous) @@ -68,7 +68,7 @@ assert_equal 'Smith', p.lastname assert_equal 'jsmith', p.login end - + def test_set_safe_attributes_without_user p = Person.new User.current = nil diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,13 +3,14 @@ require 'mocha' class BazaarAdapterTest < ActiveSupport::TestCase - - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/bazaar_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s REPOSITORY_PATH.gsub!(/\/+/, '/') if File.directory?(REPOSITORY_PATH) def setup - @adapter = Redmine::Scm::Adapters::BazaarAdapter.new(REPOSITORY_PATH) + @adapter = Redmine::Scm::Adapters::BazaarAdapter.new( + File.join(REPOSITORY_PATH, "trunk") + ) end def test_scm_version @@ -26,6 +27,23 @@ assert cat =~ /Write the contents of a file as of a given revision to standard output/ end + def test_cat_path_invalid + assert_nil @adapter.cat('invalid') + end + + def test_cat_revision_invalid + assert_nil @adapter.cat('doc-mkdir.txt', '12345678') + end + + def test_diff_path_invalid + assert_equal [], @adapter.diff('invalid', 1) + end + + def test_diff_revision_invalid + assert_equal [], @adapter.diff(nil, 12345678) + assert_equal [], @adapter.diff(nil, 12345678, 87654321) + end + def test_annotate annotate = @adapter.annotate('doc-mkdir.txt') assert_equal 17, annotate.lines.size @@ -34,6 +52,90 @@ assert_equal 'mkdir', annotate.lines[0] end + def test_annotate_path_invalid + assert_nil @adapter.annotate('invalid') + end + + def test_annotate_revision_invalid + assert_nil @adapter.annotate('doc-mkdir.txt', '12345678') + end + + def test_branch_conf_path + p = "c:\\test\\test\\" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "c:\\test\\test\\.bzr" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "c:\\test\\test\\.bzr\\" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "c:\\test\\test" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("c:\\test\\test", ".bzr", "branch", "branch.conf"), bcp + p = "\\\\server\\test\\test\\" + bcp = Redmine::Scm::Adapters::BazaarAdapter.branch_conf_path(p) + assert_equal File.join("\\\\server\\test\\test", ".bzr", "branch", "branch.conf"), bcp + end + + def test_append_revisions_only_true + assert_equal true, @adapter.append_revisions_only + end + + def test_append_revisions_only_false + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + File.join(REPOSITORY_PATH, "empty-branch") + ) + assert_equal false, adpt.append_revisions_only + end + + def test_append_revisions_only_shared_repo + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + REPOSITORY_PATH + ) + assert_equal false, adpt.append_revisions_only + end + + def test_info_not_nil + assert_not_nil @adapter.info + end + + def test_info_nil + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + "/invalid/invalid/" + ) + assert_nil adpt.info + end + + def test_info + info = @adapter.info + assert_equal 4, info.lastrev.identifier.to_i + end + + def test_info_emtpy + adpt = Redmine::Scm::Adapters::BazaarAdapter.new( + File.join(REPOSITORY_PATH, "empty-branch") + ) + assert_equal 0, adpt.info.lastrev.identifier.to_i + end + + def test_entries_path_invalid + assert_equal [], @adapter.entries('invalid') + end + + def test_entries_revision_invalid + assert_nil @adapter.entries(nil, 12345678) + end + + def test_revisions_path_invalid + assert_nil @adapter.revisions('invalid') + end + + def test_revisions_revision_invalid + assert_nil @adapter.revisions(nil, 12345678) + assert_nil @adapter.revisions(nil, 12345678, 87654321) + end + private def test_scm_version_for(scm_command_version, version) diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,8 +3,7 @@ require 'mocha' class CvsAdapterTest < ActiveSupport::TestCase - - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? MODULE_NAME = 'test' diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/darcs_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/darcs_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/darcs_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,8 +3,7 @@ require 'mocha' class DarcsAdapterTest < ActiveSupport::TestCase - - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/darcs_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s if File.directory?(REPOSITORY_PATH) def setup diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/filesystem_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/filesystem_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/filesystem_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -2,8 +2,7 @@ require File.expand_path('../../../../../../test_helper', __FILE__) class FilesystemAdapterTest < ActiveSupport::TestCase - - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/filesystem_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s if File.directory?(REPOSITORY_PATH) def setup diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/git_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -8,7 +8,7 @@ require 'mocha' class GitAdapterTest < ActiveSupport::TestCase - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s FELIX_UTF8 = "Felix Schäfer" FELIX_HEX = "Felix Sch\xC3\xA4fer" @@ -20,6 +20,14 @@ # WINDOWS_PASS = Redmine::Platform.mswin? WINDOWS_PASS = false + ## Git, Mercurial and CVS path encodings are binary. + ## Subversion supports URL encoding for path. + ## Redmine Mercurial adapter and extension use URL encoding. + ## Git accepts only binary path in command line parameter. + ## So, there is no way to use binary command line parameter in JRuby. + JRUBY_SKIP = (RUBY_PLATFORM == 'java') + JRUBY_SKIP_STR = "TODO: This test fails in JRuby" + if File.directory?(REPOSITORY_PATH) def setup adapter_class = Redmine::Scm::Adapters::GitAdapter @@ -53,12 +61,23 @@ end def test_branches - assert_equal [ - 'latin-1-path-encoding', - 'master', - 'test-latin-1', - 'test_branch', - ], @adapter.branches + brs = [] + @adapter.branches.each do |b| + brs << b + end + assert_equal 4, brs.length + assert_equal 'latin-1-path-encoding', brs[0].to_s + assert_equal '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127', brs[0].revision + assert_equal brs[0].scmid, brs[0].revision + assert_equal 'master', brs[1].to_s + assert_equal '83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', brs[1].revision + assert_equal brs[1].scmid, brs[1].revision + assert_equal 'test-latin-1', brs[2].to_s + assert_equal '67e7792ce20ccae2e4bb73eed09bb397819c8834', brs[2].revision + assert_equal brs[2].scmid, brs[2].revision + assert_equal 'test_branch', brs[3].to_s + assert_equal 'fba357b886984ee71185ad2065e65fc0417d9b92', brs[3].revision + assert_equal brs[3].scmid, brs[3].revision end def test_tags @@ -203,6 +222,32 @@ nil, nil, :all => true).length end + def test_parents + revs1 = [] + @adapter.revisions('', + nil, + "master", + {:reverse => true}) do |rev| + revs1 << rev + end + assert_equal 15, revs1.length + assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", + revs1[0].identifier + assert_equal nil, revs1[0].parents + assert_equal "899a15dba03a3b350b89c3f537e4bbe02a03cdc9", + revs1[1].identifier + assert_equal 1, revs1[1].parents.length + assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", + revs1[1].parents[0] + assert_equal "32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf", + revs1[10].identifier + assert_equal 2, revs1[10].parents.length + assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", + revs1[10].parents[0] + assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", + revs1[10].parents[1] + end + def test_getting_revisions_with_leading_and_trailing_spaces_in_filename assert_equal " filename with a leading space.txt ", @adapter.revisions(" filename with a leading space.txt ", @@ -262,6 +307,8 @@ def test_latin_1_path if WINDOWS_PASS # + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR else p2 = "latin-1-dir/test-#{@char_1}-2.txt" ['4fc55c43bf3d3dc2efb66145365ddc17639ce81e', '4fc55c43bf3'].each do |r1| @@ -322,6 +369,8 @@ def test_entries_latin_1_dir if WINDOWS_PASS # + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR else entries1 = @adapter.entries("latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed') @@ -349,6 +398,34 @@ assert_equal "UTF-8", adpt2.path_encoding end + def test_cat_path_invalid + assert_nil @adapter.cat('invalid') + end + + def test_cat_revision_invalid + assert @adapter.cat('README') + assert_nil @adapter.cat('README', 'abcd1234efgh') + end + + def test_diff_path_invalid + assert_equal [], @adapter.diff('invalid', '713f4944648826f5') + end + + def test_diff_revision_invalid + assert_nil @adapter.diff(nil, 'abcd1234efgh') + assert_nil @adapter.diff(nil, '713f4944648826f5', 'abcd1234efgh') + assert_nil @adapter.diff(nil, 'abcd1234efgh', '713f4944648826f5') + end + + def test_annotate_path_invalid + assert_nil @adapter.annotate('invalid') + end + + def test_annotate_revision_invalid + assert @adapter.annotate('README') + assert_nil @adapter.annotate('README', 'abcd1234efgh') + end + private def test_scm_version_for(scm_command_version, version) diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -3,14 +3,11 @@ require 'mocha' class MercurialAdapterTest < ActiveSupport::TestCase - HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + - '/tmp/test/mercurial_repository' - + REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s CHAR_1_HEX = "\xc3\x9c" if File.directory?(REPOSITORY_PATH) @@ -56,12 +53,14 @@ end def test_template_path - to_test = { [0,9,5] => "0.9.5", - [1,0] => "1.0", + to_test = { + [1,2] => "1.0", [] => "1.0", - [1,0,1] => "1.0", + [1,2,1] => "1.0", [1,7] => "1.0", - [1,7,1] => "1.0" } + [1,7,1] => "1.0", + [2,0] => "1.0", + } to_test.each do |v, template| test_template_path_for(v, template) end @@ -73,8 +72,8 @@ adp = Redmine::Scm::Adapters::MercurialAdapter.new(repo) repo_path = adp.info.root_url.gsub(/\\/, "/") assert_equal REPOSITORY_PATH, repo_path - assert_equal '28', adp.info.lastrev.revision - assert_equal '3ae45e2d177d',adp.info.lastrev.scmid + assert_equal '31', adp.info.lastrev.revision + assert_equal '31eeee7395c8',adp.info.lastrev.scmid end end @@ -92,6 +91,21 @@ assert_equal '400bb8672109', revisions[0].scmid end + def test_parents + revs1 = @adapter.revisions(nil, 0, 0) + assert_equal 1, revs1.size + assert_equal [], revs1[0].parents + revs2 = @adapter.revisions(nil, 1, 1) + assert_equal 1, revs2.size + assert_equal 1, revs2[0].parents.size + assert_equal "0885933ad4f6", revs2[0].parents[0] + revs3 = @adapter.revisions(nil, 30, 30) + assert_equal 1, revs3.size + assert_equal 2, revs3[0].parents.size + assert_equal "a94b0528f24f", revs3[0].parents[0] + assert_equal "3a330eb32958", revs3[0].parents[1] + end + def test_diff if @adapter.class.client_version_above?([1, 2]) assert_nil @adapter.diff(nil, '100000') @@ -256,22 +270,41 @@ end def test_branches - assert_equal [ - 'default', - @branch_char_1, - 'branch (1)[2]&,%.-3_4', - @branch_char_0, - 'test_branch.latin-1', - 'test-branch-00', - ], @adapter.branches + brs = [] + @adapter.branches.each do |b| + brs << b + end + assert_equal 7, brs.length + assert_equal 'default', brs[0].to_s + assert_equal '31', brs[0].revision + assert_equal '31eeee7395c8', brs[0].scmid + assert_equal 'test-branch-01', brs[1].to_s + assert_equal '30', brs[1].revision + assert_equal 'ad4dc4f80284', brs[1].scmid + assert_equal @branch_char_1, brs[2].to_s + assert_equal '27', brs[2].revision + assert_equal '7bbf4c738e71', brs[2].scmid + assert_equal 'branch (1)[2]&,%.-3_4', brs[3].to_s + assert_equal '25', brs[3].revision + assert_equal 'afc61e85bde7', brs[3].scmid + assert_equal @branch_char_0, brs[4].to_s + assert_equal '23', brs[4].revision + assert_equal 'c8d3e4887474', brs[4].scmid + assert_equal 'test_branch.latin-1', brs[5].to_s + assert_equal '22', brs[5].revision + assert_equal 'c2ffe7da686a', brs[5].scmid + assert_equal 'test-branch-00', brs[6].to_s + assert_equal '13', brs[6].revision + assert_equal '3a330eb32958', brs[6].scmid end def test_branchmap bm = { - 'default' => '3ae45e2d177d', + 'default' => '31eeee7395c8', 'test_branch.latin-1' => 'c2ffe7da686a', 'branch (1)[2]&,%.-3_4' => 'afc61e85bde7', 'test-branch-00' => '3a330eb32958', + "test-branch-01" => 'ad4dc4f80284', @branch_char_0 => 'c8d3e4887474', @branch_char_1 => '7bbf4c738e71', } @@ -317,17 +350,21 @@ assert_equal 1, nib1.size case bra when 'branch (1)[2]&,%.-3_4' - assert_equal 3, nib0.size - assert_equal nib0[0], 'afc61e85bde7' - nib2 = @adapter.nodes_in_branch(bra, :limit => 2) - assert_equal 2, nib2.size - assert_equal nib2[1], '933ca60293d7' + if @adapter.class.client_version_above?([1, 6]) + assert_equal 3, nib0.size + assert_equal nib0[0], 'afc61e85bde7' + nib2 = @adapter.nodes_in_branch(bra, :limit => 2) + assert_equal 2, nib2.size + assert_equal nib2[1], '933ca60293d7' + end when @branch_char_1 - assert_equal 2, nib0.size - assert_equal nib0[1], '08ff3227303e' - nib2 = @adapter.nodes_in_branch(bra, :limit => 1) - assert_equal 1, nib2.size - assert_equal nib2[0], '7bbf4c738e71' + if @adapter.class.client_version_above?([1, 6]) + assert_equal 2, nib0.size + assert_equal nib0[1], '08ff3227303e' + nib2 = @adapter.nodes_in_branch(bra, :limit => 1) + assert_equal 1, nib2.size + assert_equal nib2[0], '7bbf4c738e71' + end end end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb --- a/test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -42,19 +42,28 @@ end end + def test_info_not_nil + assert_not_nil @adapter.info + end + + def test_info_nil + adpt = Redmine::Scm::Adapters::SubversionAdapter.new( + "file:///invalid/invalid/" + ) + assert_nil adpt.info + end + private def test_scm_version_for(scm_version, version) @adapter.class.expects(:scm_version_from_command_line).returns(scm_version) assert_equal version, @adapter.class.svn_binary_version end - else puts "Subversion test repository NOT FOUND. Skipping unit tests !!!" def test_fake; assert true end end end - rescue LoadError class SubversionMochaFake < ActiveSupport::TestCase def test_fake; assert(false, "Requires mocha to run those tests") end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/themes_test.rb --- a/test/unit/lib/redmine/themes_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/themes_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,42 +18,42 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::ThemesTest < ActiveSupport::TestCase - + def test_themes themes = Redmine::Themes.themes assert_kind_of Array, themes assert_kind_of Redmine::Themes::Theme, themes.first end - + def test_rescan Redmine::Themes.themes.pop - + assert_difference 'Redmine::Themes.themes.size' do Redmine::Themes.rescan end end - + def test_theme_loaded theme = Redmine::Themes.themes.last - + assert_equal theme, Redmine::Themes.theme(theme.id) end - + def test_theme_loaded_without_rescan theme = Redmine::Themes.themes.last - + assert_equal theme, Redmine::Themes.theme(theme.id, :rescan => false) end - + def test_theme_not_loaded theme = Redmine::Themes.themes.pop - + assert_equal theme, Redmine::Themes.theme(theme.id) end - + def test_theme_not_loaded_without_rescan theme = Redmine::Themes.themes.pop - + assert_nil Redmine::Themes.theme(theme.id, :rescan => false) end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/unified_diff_test.rb --- a/test/unit/lib/redmine/unified_diff_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/unified_diff_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,7 +18,7 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::UnifiedDiffTest < ActiveSupport::TestCase - + def setup end @@ -28,58 +28,58 @@ assert_equal 4, diff.size assert diff.detect {|file| file.file_name =~ %r{^config/settings.yml}} end - + def test_truncate_diff diff = Redmine::UnifiedDiff.new(read_diff_fixture('subversion.diff'), :max_lines => 20) assert_equal 2, diff.size end - + def test_inline_partials diff = Redmine::UnifiedDiff.new(read_diff_fixture('partials.diff')) assert_equal 1, diff.size diff = diff.first assert_equal 43, diff.size - + assert_equal [51, -1], diff[0].offsets assert_equal [51, -1], diff[1].offsets assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', diff[0].html_line assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing xx', diff[1].html_line - + assert_nil diff[2].offsets assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[2].html_line - + assert_equal [0, -14], diff[3].offsets assert_equal [0, -14], diff[4].offsets assert_equal 'Ut sed auctor justo', diff[3].html_line assert_equal 'xxx auctor justo', diff[4].html_line - + assert_equal [13, -19], diff[6].offsets assert_equal [13, -19], diff[7].offsets - + assert_equal [24, -8], diff[9].offsets assert_equal [24, -8], diff[10].offsets - + assert_equal [37, -1], diff[12].offsets assert_equal [37, -1], diff[13].offsets - + assert_equal [0, -38], diff[15].offsets assert_equal [0, -38], diff[16].offsets end - + def test_side_by_side_partials diff = Redmine::UnifiedDiff.new(read_diff_fixture('partials.diff'), :type => 'sbs') assert_equal 1, diff.size diff = diff.first assert_equal 32, diff.size - + assert_equal [51, -1], diff[0].offsets assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', diff[0].html_line_left assert_equal 'Lorem ipsum dolor sit amet, consectetur adipiscing xx', diff[0].html_line_right - + assert_nil diff[1].offsets assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[1].html_line_left assert_equal 'Praesent et sagittis dui. Vivamus ac diam diam', diff[1].html_line_right - + assert_equal [0, -14], diff[2].offsets assert_equal 'Ut sed auctor justo', diff[2].html_line_left assert_equal 'xxx auctor justo', diff[2].html_line_right @@ -88,9 +88,9 @@ assert_equal [24, -8], diff[6].offsets assert_equal [37, -1], diff[8].offsets assert_equal [0, -38], diff[10].offsets - + end - + def test_line_starting_with_dashes diff = Redmine::UnifiedDiff.new(<<-DIFF --- old.txt Wed Nov 11 14:24:58 2009 diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/views/builders/json_test.rb --- a/test/unit/lib/redmine/views/builders/json_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/views/builders/json_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,24 +1,24 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../../../../test_helper', __FILE__) -class Redmine::Views::Builders::JsonTest < HelperTestCase - +class Redmine::Views::Builders::JsonTest < ActiveSupport::TestCase + def test_hash assert_json_output({'person' => {'name' => 'Ryan', 'age' => 32}}) do |b| b.person do @@ -27,7 +27,7 @@ end end end - + def test_hash_hash assert_json_output({'person' => {'name' => 'Ryan', 'birth' => {'city' => 'London', 'country' => 'UK'}}}) do |b| b.person do @@ -35,7 +35,7 @@ b.birth :city => 'London', :country => 'UK' end end - + assert_json_output({'person' => {'id' => 1, 'name' => 'Ryan', 'birth' => {'city' => 'London', 'country' => 'UK'}}}) do |b| b.person :id => 1 do b.name 'Ryan' @@ -43,7 +43,7 @@ end end end - + def test_array assert_json_output({'books' => [{'title' => 'Book 1', 'author' => 'B. Smith'}, {'title' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b| b.array :books do |b| @@ -63,7 +63,7 @@ end end end - + def test_array_with_content_tags assert_json_output({'books' => [{'value' => 'Book 1', 'author' => 'B. Smith'}, {'value' => 'Book 2', 'author' => 'G. Cooper'}]}) do |b| b.array :books do |b| @@ -72,7 +72,7 @@ end end end - + def assert_json_output(expected, &block) builder = Redmine::Views::Builders::Json.new block.call(builder) diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/views/builders/xml_test.rb --- a/test/unit/lib/redmine/views/builders/xml_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/views/builders/xml_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,24 +1,24 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../../../../test_helper', __FILE__) -class Redmine::Views::Builders::XmlTest < HelperTestCase - +class Redmine::Views::Builders::XmlTest < ActiveSupport::TestCase + def test_hash assert_xml_output('Ryan32') do |b| b.person do @@ -27,7 +27,7 @@ end end end - + def test_array assert_xml_output('') do |b| b.array :books do |b| @@ -36,7 +36,7 @@ end end end - + def test_array_with_content_tags assert_xml_output('Book 1Book 2') do |b| b.array :books do |b| @@ -45,7 +45,7 @@ end end end - + def assert_xml_output(expected, &block) builder = Redmine::Views::Builders::Xml.new block.call(builder) diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/wiki_formatting.rb --- a/test/unit/lib/redmine/wiki_formatting.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/wiki_formatting.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,17 +18,17 @@ require File.expand_path('../../../../test_helper', __FILE__) class Redmine::WikiFormattingTest < ActiveSupport::TestCase - + def test_textile_formatter assert_equal Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting.formatter_for('textile') assert_equal Redmine::WikiFormatting::Textile::Helper, Redmine::WikiFormatting.helper_for('textile') end - + def test_null_formatter assert_equal Redmine::WikiFormatting::NullFormatter::Formatter, Redmine::WikiFormatting.formatter_for('') assert_equal Redmine::WikiFormatting::NullFormatter::Helper, Redmine::WikiFormatting.helper_for('') end - + def test_should_link_urls_and_email_addresses raw = <<-DIFF This is a sample *text* with a link: http://www.redmine.org @@ -42,4 +42,14 @@ assert_equal expected.gsub(%r{[\r\n\t]}, ''), Redmine::WikiFormatting::NullFormatter::Formatter.new(raw).to_html.gsub(%r{[\r\n\t]}, '') end + + def test_supports_section_edit + with_settings :text_formatting => 'textile' do + assert_equal true, Redmine::WikiFormatting.supports_section_edit? + end + + with_settings :text_formatting => '' do + assert_equal false, Redmine::WikiFormatting.supports_section_edit? + end + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/wiki_formatting/macros_test.rb --- a/test/unit/lib/redmine/wiki_formatting/macros_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/wiki_formatting/macros_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,30 +1,30 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) -class Redmine::WikiFormatting::MacrosTest < HelperTestCase +class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase include ApplicationHelper include ActionView::Helpers::TextHelper include ActionView::Helpers::SanitizeHelper extend ActionView::Helpers::SanitizeHelper::ClassMethods - + fixtures :projects, :roles, :enabled_modules, :users, - :repositories, :changesets, + :repositories, :changesets, :trackers, :issue_statuses, :issues, :versions, :documents, :wikis, :wiki_pages, :wiki_contents, @@ -35,10 +35,10 @@ super @project = nil end - + def teardown end - + def test_macro_hello_world text = "{{hello_world}}" assert textilizable(text).match(/Hello world!/) @@ -46,13 +46,13 @@ text = "!{{hello_world}}" assert_equal '

    {{hello_world}}

    ', textilizable(text) end - + def test_macro_include @project = Project.find(1) # include a page of the current project wiki text = "{{include(Another page)}}" assert textilizable(text).match(/This is a link to a ticket/) - + @project = nil # include a page of a specific project wiki text = "{{include(ecookbook:Another page)}}" @@ -64,23 +64,23 @@ text = "{{include(unknowidentifier:somepage)}}" assert textilizable(text).match(/Page not found/) end - + def test_macro_child_pages expected = "

    \n

    " - + @project = Project.find(1) # child pages of the current wiki page assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content) # child pages of another page assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content) - + @project = Project.find(2) assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content) end - + def test_macro_child_pages_with_option expected = "

    \n\n\n

    " - + @project = Project.find(1) # child pages of the current wiki page assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content) # child pages of another page assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content) - + @project = Project.find(2) assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content) end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb --- a/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,28 +1,29 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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.expand_path('../../../../../test_helper', __FILE__) +require 'digest/md5' -class Redmine::WikiFormatting::TextileFormatterTest < HelperTestCase +class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase def setup @formatter = Redmine::WikiFormatting::Textile::Formatter end - + MODIFIERS = { "*" => 'strong', # bold "_" => 'em', # italic @@ -31,7 +32,7 @@ "^" => 'sup', # superscript "~" => 'sub' # subscript } - + def test_modifiers assert_html_output( '*bold*' => 'bold', @@ -46,7 +47,7 @@ '*(foo)two words*' => 'two words' ) end - + def test_modifiers_combination MODIFIERS.each do |m1, tag1| MODIFIERS.each do |m2, tag2| @@ -57,7 +58,7 @@ end end end - + def test_inline_code assert_html_output( 'this is @some code@' => 'this is some code', @@ -76,14 +77,14 @@ 'h1. 2009\02\09' => '

    2009\02\09

    ' }, false) end - + def test_double_dashes_should_not_strikethrough assert_html_output( 'double -- dashes -- test' => 'double -- dashes -- test', 'double -- *dashes* -- test' => 'double -- dashes -- test' ) end - + def test_acronyms assert_html_output( 'this is an acronym: GPL(General Public License)' => 'this is an acronym: GPL', @@ -91,7 +92,7 @@ 'GPL(This is a double-quoted "title")' => 'GPL' ) end - + def test_blockquote # orig raw text raw = <<-RAW @@ -108,7 +109,7 @@ He's right. RAW - + # expected html expected = <<-EXPECTED

    John said:

    @@ -128,10 +129,10 @@

    He's right.

    EXPECTED - + assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') end - + def test_table raw = <<-RAW This is a table with empty cells: @@ -153,7 +154,7 @@ assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') end - + def test_table_with_line_breaks raw = <<-RAW This is a table with line breaks: @@ -192,20 +193,151 @@ assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') end - + def test_textile_should_not_mangle_brackets assert_equal '

    [msg1][msg2]

    ', to_html('[msg1][msg2]') end + + def test_textile_should_escape_image_urls + # this is onclick="alert('XSS');" in encoded form + raw = '!/images/comment.png"onclick=alert('XSS');"!' + expected = '

    ' + assert_equal expected.gsub(%r{\s+}, ''), to_html(raw).gsub(%r{\s+}, '') + end + + STR_WITHOUT_PRE = [ + # 0 +"h1. Title + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.", + # 1 +"h2. Heading 2 + +Maecenas sed elit sit amet mi accumsan vestibulum non nec velit. Proin porta tincidunt lorem, consequat rhoncus dolor fermentum in. + +Cras ipsum felis, ultrices at porttitor vel, faucibus eu nunc.", + # 2 +"h2. Heading 2 + +Morbi facilisis accumsan orci non pharetra. + +h3. Heading 3 + +Nulla nunc nisi, egestas in ornare vel, posuere ac libero.", + # 3 +"h3. Heading 3 + +Praesent eget turpis nibh, a lacinia nulla.", + # 4 +"h2. Heading 2 + +Ut rhoncus elementum adipiscing."] + + TEXT_WITHOUT_PRE = STR_WITHOUT_PRE.join("\n\n").freeze + + def test_get_section_should_return_the_requested_section_and_its_hash + assert_section_with_hash STR_WITHOUT_PRE[1], TEXT_WITHOUT_PRE, 2 + assert_section_with_hash STR_WITHOUT_PRE[2..3].join("\n\n"), TEXT_WITHOUT_PRE, 3 + assert_section_with_hash STR_WITHOUT_PRE[3], TEXT_WITHOUT_PRE, 5 + assert_section_with_hash STR_WITHOUT_PRE[4], TEXT_WITHOUT_PRE, 6 + + assert_section_with_hash '', TEXT_WITHOUT_PRE, 0 + assert_section_with_hash '', TEXT_WITHOUT_PRE, 10 + end + + def test_update_section_should_update_the_requested_section + replacement = "New text" + + assert_equal [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(2, replacement) + assert_equal [STR_WITHOUT_PRE[0..1], replacement, STR_WITHOUT_PRE[4]].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(3, replacement) + assert_equal [STR_WITHOUT_PRE[0..2], replacement, STR_WITHOUT_PRE[4]].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(5, replacement) + assert_equal [STR_WITHOUT_PRE[0..3], replacement].flatten.join("\n\n"), @formatter.new(TEXT_WITHOUT_PRE).update_section(6, replacement) + + assert_equal TEXT_WITHOUT_PRE, @formatter.new(TEXT_WITHOUT_PRE).update_section(0, replacement) + assert_equal TEXT_WITHOUT_PRE, @formatter.new(TEXT_WITHOUT_PRE).update_section(10, replacement) + end + + def test_update_section_with_hash_should_update_the_requested_section + replacement = "New text" + + assert_equal [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].flatten.join("\n\n"), + @formatter.new(TEXT_WITHOUT_PRE).update_section(2, replacement, Digest::MD5.hexdigest(STR_WITHOUT_PRE[1])) + end + + def test_update_section_with_wrong_hash_should_raise_an_error + assert_raise Redmine::WikiFormatting::StaleSectionError do + @formatter.new(TEXT_WITHOUT_PRE).update_section(2, "New text", Digest::MD5.hexdigest("Old text")) + end + end + + STR_WITH_PRE = [ + # 0 +"h1. Title + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.", + # 1 +"h2. Heading 2 + +
    
    +  def foo
    +  end
    +
    + +
    
    +  Place your code here.
    +
    +
    + +Morbi facilisis accumsan orci non pharetra. + +
    +Pre Content:
    +
    +h2. Inside pre
    +
    + inside pre block
    +
    +Morbi facilisis accumsan orci non pharetra.
    +
    ", + # 2 +"h3. Heading 3 + +Nulla nunc nisi, egestas in ornare vel, posuere ac libero."] + + def test_get_section_should_ignore_pre_content + text = STR_WITH_PRE.join("\n\n") + + assert_section_with_hash STR_WITH_PRE[1..2].join("\n\n"), text, 2 + assert_section_with_hash STR_WITH_PRE[2], text, 3 + end + + def test_update_section_should_not_escape_pre_content_outside_section + text = STR_WITH_PRE.join("\n\n") + replacement = "New text" + + assert_equal [STR_WITH_PRE[0..1], "New text"].flatten.join("\n\n"), + @formatter.new(text).update_section(3, replacement) + end + private - + def assert_html_output(to_test, expect_paragraph = true) to_test.each do |text, expected| assert_equal(( expect_paragraph ? "

    #{expected}

    " : expected ), @formatter.new(text).to_html, "Formatting the following text failed:\n===\n#{text}\n===\n") end end - + def to_html(text) @formatter.new(text).to_html end + + def assert_section_with_hash(expected, text, index) + result = @formatter.new(text).get_section(index) + + assert_kind_of Array, result + assert_equal 2, result.size + assert_equal expected, result.first, "section content did not match" + assert_equal Digest::MD5.hexdigest(expected), result.last, "section hash did not match" + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/lib/redmine_test.rb --- a/test/unit/lib/redmine_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/lib/redmine_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 test/unit/mail_handler_test.rb --- a/test/unit/mail_handler_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/mail_handler_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -110,6 +110,18 @@ assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') end + def test_add_issue_with_group_assignment + with_settings :issue_group_assignment => '1' do + issue = submit_email('ticket_on_given_project.eml') do |email| + email.gsub!('Assigned to: John Smith', 'Assigned to: B Team') + end + assert issue.is_a?(Issue) + assert !issue.new_record? + issue.reload + assert_equal Group.find(11), issue.assigned_to + end + end + def test_add_issue_with_partial_attributes_override issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker']) assert issue.is_a?(Issue) @@ -279,6 +291,16 @@ assert_equal tracker, issue.tracker end + def test_add_issue_from_apple_mail + issue = submit_email('apple_mail_with_attachment.eml', :issue => {:project => 'ecookbook'}) + assert_kind_of Issue, issue + assert_equal 1, issue.attachments.size + + attachment = issue.attachments.first + assert_equal 'paella.jpg', attachment.filename + assert_equal 10790, attachment.filesize + end + def test_should_ignore_emails_from_emission_address Role.anonymous.add_permission!(:add_issues) assert_no_difference 'User.count' do @@ -295,7 +317,7 @@ assert_equal 1, ActionMailer::Base.deliveries.size end - def test_add_issue_note + def test_update_issue journal = submit_email('ticket_reply.eml') assert journal.is_a?(Journal) assert_equal User.find_by_login('jsmith'), journal.user @@ -304,7 +326,7 @@ assert_equal 'Feature request', journal.issue.tracker.name end - def test_add_issue_note_with_attribute_changes + def test_update_issue_with_attribute_changes # This email contains: 'Status: Resolved' journal = submit_email('ticket_reply_with_status.eml') assert journal.is_a?(Journal) @@ -323,14 +345,35 @@ assert !journal.notes.match(/^Start Date:/i) end - def test_add_issue_note_should_send_email_notification + def test_update_issue_with_attachment + assert_difference 'Journal.count' do + assert_difference 'JournalDetail.count' do + assert_difference 'Attachment.count' do + assert_no_difference 'Issue.count' do + journal = submit_email('ticket_with_attachment.eml') do |raw| + raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories' + end + end + end + end + end + journal = Journal.first(:order => 'id DESC') + assert_equal Issue.find(2), journal.journalized + assert_equal 1, journal.details.size + + detail = journal.details.first + assert_equal 'attachment', detail.property + assert_equal 'Paella.jpg', detail.value + end + + def test_update_issue_should_send_email_notification ActionMailer::Base.deliveries.clear journal = submit_email('ticket_reply.eml') assert journal.is_a?(Journal) assert_equal 1, ActionMailer::Base.deliveries.size end - def test_add_issue_note_should_not_set_defaults + def test_update_issue_should_not_set_defaults journal = submit_email('ticket_reply.eml', :issue => {:tracker => 'Support request', :priority => 'High'}) assert journal.is_a?(Journal) assert_match /This is reply/, journal.notes @@ -442,10 +485,51 @@ assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255] end + def test_new_user_from_attributes_should_return_valid_user + to_test = { + # [address, name] => [login, firstname, lastname] + ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'], + ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'], + ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'], + ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'], + ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'], + ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh'], + ['alongemailaddressthatexceedsloginlength@example.net', 'John Smith'] => ['alongemailaddressthatexceedslo', 'John', 'Smith'] + } + + to_test.each do |attrs, expected| + user = MailHandler.new_user_from_attributes(attrs.first, attrs.last) + + assert user.valid? + assert_equal attrs.first, user.mail + assert_equal expected[0], user.login + assert_equal expected[1], user.firstname + assert_equal expected[2], user.lastname + end + end + + def test_new_user_from_attributes_should_respect_minimum_password_length + with_settings :password_min_length => 15 do + user = MailHandler.new_user_from_attributes('jsmith@example.net') + assert user.valid? + assert user.password.length >= 15 + end + end + + def test_new_user_from_attributes_should_use_default_login_if_invalid + MailHandler.new_user_from_attributes('alongemailaddressthatexceedsloginlength-1@example.net').save! + + # another long address that would result in duplicate login + user = MailHandler.new_user_from_attributes('alongemailaddressthatexceedsloginlength-2@example.net') + assert user.valid? + assert user.login =~ /^user[a-f0-9]+$/ + end + private def submit_email(filename, options={}) raw = IO.read(File.join(FIXTURES_PATH, filename)) + yield raw if block_given? MailHandler.receive(raw, options) end diff -r 487d96eac004 -r 5e80956cc792 test/unit/mailer_test.rb --- a/test/unit/mailer_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/mailer_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -20,91 +20,121 @@ class MailerTest < ActiveSupport::TestCase include Redmine::I18n include ActionController::Assertions::SelectorAssertions - fixtures :all - + fixtures :projects, :enabled_modules, :issues, :users, :members, + :member_roles, :roles, :documents, :attachments, :news, + :tokens, :journals, :journal_details, :changesets, :trackers, + :issue_statuses, :enumerations, :messages, :boards, :repositories, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :versions, + :comments + def setup ActionMailer::Base.deliveries.clear Setting.host_name = 'mydomain.foo' Setting.protocol = 'http' Setting.plain_text_mail = '0' end - + def test_generated_links_in_emails Setting.host_name = 'mydomain.foo' Setting.protocol = 'https' - + journal = Journal.find(2) assert Mailer.deliver_issue_edit(journal) - + mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail - + assert_select_email do # link to the main ticket - assert_select "a[href=?]", "https://mydomain.foo/issues/1", :text => "Bug #1: Can't print recipes" + assert_select "a[href=?]", + "https://mydomain.foo/issues/1#change-2", + :text => "Bug #1: Can't print recipes" # link to a referenced ticket - assert_select "a[href=?][title=?]", "https://mydomain.foo/issues/2", "Add ingredients categories (Assigned)", :text => "#2" + assert_select "a[href=?][title=?]", + "https://mydomain.foo/issues/2", + "Add ingredients categories (Assigned)", + :text => "#2" # link to a changeset - assert_select "a[href=?][title=?]", "https://mydomain.foo/projects/ecookbook/repository/revisions/2", "This commit fixes #1, #2 and references #1 & #3", :text => "r2" + assert_select "a[href=?][title=?]", + "https://mydomain.foo/projects/ecookbook/repository/revisions/2", + "This commit fixes #1, #2 and references #1 & #3", + :text => "r2" end end - + def test_generated_links_with_prefix relative_url_root = Redmine::Utils.relative_url_root Setting.host_name = 'mydomain.foo/rdm' Setting.protocol = 'http' Redmine::Utils.relative_url_root = '/rdm' - + journal = Journal.find(2) assert Mailer.deliver_issue_edit(journal) - + mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail assert_select_email do # link to the main ticket - assert_select "a[href=?]", "http://mydomain.foo/rdm/issues/1", :text => "Bug #1: Can't print recipes" + assert_select "a[href=?]", + "http://mydomain.foo/rdm/issues/1#change-2", + :text => "Bug #1: Can't print recipes" # link to a referenced ticket - assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/issues/2", "Add ingredients categories (Assigned)", :text => "#2" + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/issues/2", + "Add ingredients categories (Assigned)", + :text => "#2" # link to a changeset - assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", "This commit fixes #1, #2 and references #1 & #3", :text => "r2" + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", + "This commit fixes #1, #2 and references #1 & #3", + :text => "r2" end ensure # restore it Redmine::Utils.relative_url_root = relative_url_root end - + def test_generated_links_with_prefix_and_no_relative_url_root relative_url_root = Redmine::Utils.relative_url_root Setting.host_name = 'mydomain.foo/rdm' Setting.protocol = 'http' Redmine::Utils.relative_url_root = nil - + journal = Journal.find(2) assert Mailer.deliver_issue_edit(journal) - + mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail assert_select_email do # link to the main ticket - assert_select "a[href=?]", "http://mydomain.foo/rdm/issues/1", :text => "Bug #1: Can't print recipes" + assert_select "a[href=?]", + "http://mydomain.foo/rdm/issues/1#change-2", + :text => "Bug #1: Can't print recipes" # link to a referenced ticket - assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/issues/2", "Add ingredients categories (Assigned)", :text => "#2" + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/issues/2", + "Add ingredients categories (Assigned)", + :text => "#2" # link to a changeset - assert_select "a[href=?][title=?]", "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", "This commit fixes #1, #2 and references #1 & #3", :text => "r2" + assert_select "a[href=?][title=?]", + "http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2", + "This commit fixes #1, #2 and references #1 & #3", + :text => "r2" end ensure # restore it Redmine::Utils.relative_url_root = relative_url_root end - + def test_email_headers issue = Issue.find(1) Mailer.deliver_issue_add(issue) mail = ActionMailer::Base.deliveries.last assert_not_nil mail - assert_equal 'bulk', mail.header_string('Precedence') + assert_equal 'OOF', mail.header_string('X-Auto-Response-Suppress') assert_equal 'auto-generated', mail.header_string('Auto-Submitted') end @@ -126,22 +156,32 @@ assert_equal 2, mail.parts.size assert mail.encoded.include?('href') end - - def test_mail_from_with_phrase + + def test_from_header + with_settings :mail_from => 'redmine@example.net' do + Mailer.deliver_test(User.find(1)) + end + mail = ActionMailer::Base.deliveries.last + assert_not_nil mail + assert_equal 'redmine@example.net', mail.from_addrs.first.address + end + + def test_from_header_with_phrase with_settings :mail_from => 'Redmine app ' do Mailer.deliver_test(User.find(1)) end mail = ActionMailer::Base.deliveries.last assert_not_nil mail + assert_equal 'redmine@example.net', mail.from_addrs.first.address assert_equal 'Redmine app', mail.from_addrs.first.name end - + def test_should_not_send_email_without_recipient news = News.find(:first) user = news.author # Remove members except news author news.project.memberships.each {|m| m.destroy unless m.user == user} - + user.pref[:no_self_notified] = false user.pref.save User.current = user @@ -165,7 +205,7 @@ assert_equal Mailer.message_id_for(issue), mail.message_id assert_nil mail.references end - + def test_issue_edit_message_id journal = Journal.find(1) Mailer.deliver_issue_edit(journal) @@ -173,8 +213,13 @@ assert_not_nil mail assert_equal Mailer.message_id_for(journal), mail.message_id assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s + assert_select_email do + # link to the update + assert_select "a[href=?]", + "http://mydomain.foo/issues/#{journal.journalized_id}#change-#{journal.id}" + end end - + def test_message_posted_message_id message = Message.find(1) Mailer.deliver_message_posted(message) @@ -184,10 +229,12 @@ assert_nil mail.references assert_select_email do # link to the message - assert_select "a[href=?]", "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}", :text => message.subject + assert_select "a[href=?]", + "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.id}", + :text => message.subject end end - + def test_reply_posted_message_id message = Message.find(3) Mailer.deliver_message_posted(message) @@ -197,28 +244,30 @@ assert_equal Mailer.message_id_for(message.parent), mail.references.first.to_s assert_select_email do # link to the reply - assert_select "a[href=?]", "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}", :text => message.subject + assert_select "a[href=?]", + "http://mydomain.foo/boards/#{message.board.id}/topics/#{message.root.id}?r=#{message.id}#message-#{message.id}", + :text => message.subject end end - + context("#issue_add") do setup do ActionMailer::Base.deliveries.clear Setting.bcc_recipients = '1' - @issue = Issue.find(1) + @issue = Issue.find(1) end - + should "notify project members" do assert Mailer.deliver_issue_add(@issue) assert last_email.bcc.include?('dlopper@somenet.foo') end - + should "not notify project members that are not allow to view the issue" do Role.find(2).remove_permission!(:view_issues) assert Mailer.deliver_issue_add(@issue) assert !last_email.bcc.include?('dlopper@somenet.foo') end - + should "notify issue watchers" do user = User.find(9) # minimal email notification options @@ -226,12 +275,12 @@ user.pref.save user.mail_notification = false user.save - + Watcher.create!(:watchable => @issue, :user => user) assert Mailer.deliver_issue_add(@issue) assert last_email.bcc.include?(user.mail) end - + should "not notify watchers not allowed to view the issue" do user = User.find(9) Watcher.create!(:watchable => @issue, :user => user) @@ -240,7 +289,7 @@ assert !last_email.bcc.include?(user.mail) end end - + # test mailer methods for each language def test_issue_add issue = Issue.find(1) @@ -257,7 +306,7 @@ assert Mailer.deliver_issue_edit(journal) end end - + def test_document_added document = Document.find(1) valid_languages.each do |lang| @@ -265,7 +314,7 @@ assert Mailer.deliver_document_added(document) end end - + def test_attachments_added attachements = [ Attachment.find_by_container_type('Document') ] valid_languages.each do |lang| @@ -273,7 +322,7 @@ assert Mailer.deliver_attachments_added(attachements) end end - + def test_version_file_added attachements = [ Attachment.find_by_container_type('Version') ] assert Mailer.deliver_attachments_added(attachements) @@ -283,7 +332,7 @@ assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" end end - + def test_project_file_added attachements = [ Attachment.find_by_container_type('Project') ] assert Mailer.deliver_attachments_added(attachements) @@ -293,7 +342,7 @@ assert_select "a[href=?]", "http://mydomain.foo/projects/ecookbook/files" end end - + def test_news_added news = News.find(:first) valid_languages.each do |lang| @@ -301,7 +350,7 @@ assert Mailer.deliver_news_added(news) end end - + def test_news_comment_added comment = Comment.find(2) valid_languages.each do |lang| @@ -309,7 +358,7 @@ assert Mailer.deliver_news_comment_added(comment) end end - + def test_message_posted message = Message.find(:first) recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} @@ -319,7 +368,7 @@ assert Mailer.deliver_message_posted(message) end end - + def test_wiki_content_added content = WikiContent.find(:first) valid_languages.each do |lang| @@ -329,7 +378,7 @@ end end end - + def test_wiki_content_updated content = WikiContent.find(:first) valid_languages.each do |lang| @@ -339,7 +388,7 @@ end end end - + def test_account_information user = User.find(2) valid_languages.each do |lang| @@ -362,7 +411,7 @@ token = Token.find(1) Setting.host_name = 'redmine.foo' Setting.protocol = 'https' - + valid_languages.each do |lang| token.user.update_attribute :language, lang.to_s token.reload @@ -372,7 +421,7 @@ assert mail.body.include?("https://redmine.foo/account/activate?token=#{token.value}") end end - + def test_test user = User.find(1) valid_languages.each do |lang| @@ -380,7 +429,7 @@ assert Mailer.deliver_test(user) end end - + def test_reminders Mailer.reminders(:days => 42) assert_equal 1, ActionMailer::Base.deliveries.size @@ -389,7 +438,7 @@ assert mail.body.include?('Bug #3: Error 281 when updating a recipe') assert_equal '1 issue(s) due in the next 42 days', mail.subject end - + def test_reminders_for_users Mailer.reminders(:days => 42, :users => ['5']) assert_equal 0, ActionMailer::Base.deliveries.size # No mail for dlopper @@ -399,13 +448,13 @@ assert mail.bcc.include?('dlopper@somenet.foo') assert mail.body.include?('Bug #3: Error 281 when updating a recipe') end - + def last_email mail = ActionMailer::Base.deliveries.last assert_not_nil mail mail end - + def test_mailer_should_not_change_locale Setting.default_language = 'en' # Set current language to italian @@ -416,10 +465,10 @@ Mailer.deliver_account_activated(user) mail = ActionMailer::Base.deliveries.last assert mail.body.include?('Votre compte') - + assert_equal :it, current_language end - + def test_with_deliveries_off Mailer.with_deliveries false do Mailer.deliver_test(User.find(1)) @@ -428,6 +477,14 @@ # should restore perform_deliveries assert ActionMailer::Base.perform_deliveries end + + def test_tmail_to_header_field_should_not_include_blank_lines + mail = TMail::Mail.new + mail.to = ["a.user@example.com", "v.user2@example.com", "e.smith@example.com", "info@example.com", "v.pupkin@example.com", + "b.user@example.com", "w.user2@example.com", "f.smith@example.com", "info2@example.com", "w.pupkin@example.com"] + + assert !mail.encoded.strip.split("\r\n").detect(&:blank?), "#{mail.encoded} malformed" + end context "layout" do should "include the emails_header" do diff -r 487d96eac004 -r 5e80956cc792 test/unit/member_test.rb --- a/test/unit/member_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/member_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,26 +18,39 @@ require File.expand_path('../../test_helper', __FILE__) class MemberTest < ActiveSupport::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :groups_users, + :watchers, + :journals, :journal_details, + :messages, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :boards def setup @jsmith = Member.find(1) end - + def test_create member = Member.new(:project_id => 1, :user_id => 4, :role_ids => [1, 2]) assert member.save member.reload - + assert_equal 2, member.roles.size assert_equal Role.find(1), member.roles.sort.first end - def test_update + def test_update assert_equal "eCookbook", @jsmith.project.name assert_equal "Manager", @jsmith.roles.first.name assert_equal "jsmith", @jsmith.user.login - + @jsmith.mail_notification = !@jsmith.mail_notification assert @jsmith.save end @@ -48,27 +61,27 @@ assert @jsmith.save assert_equal 2, @jsmith.reload.roles.size end - + def test_validate member = Member.new(:project_id => 1, :user_id => 2, :role_ids => [2]) # same use can't have more than one membership for a project assert !member.save - + member = Member.new(:project_id => 1, :user_id => 2, :role_ids => []) # must have one role at least assert !member.save end - + def test_destroy assert_difference 'Member.count', -1 do assert_difference 'MemberRole.count', -1 do @jsmith.destroy end end - + assert_raise(ActiveRecord::RecordNotFound) { Member.find(@jsmith.id) } end - + context "removing permissions" do setup do Watcher.delete_all("user_id = 9") @@ -81,12 +94,12 @@ Watcher.create!(:watchable => Wiki.find(2), :user => user) Watcher.create!(:watchable => WikiPage.find(3), :user => user) end - + context "of user" do setup do @member = Member.create!(:project => Project.find(2), :principal => User.find(9), :role_ids => [1, 2]) end - + context "by deleting membership" do should "prune watchers" do assert_difference 'Watcher.count', -4 do @@ -94,7 +107,7 @@ end end end - + context "by updating roles" do should "prune watchers" do Role.find(2).remove_permission! :view_wiki_pages @@ -107,7 +120,7 @@ end end end - + context "of group" do setup do group = Group.find(10) @@ -121,7 +134,7 @@ @member.destroy end end - end + end context "by updating roles" do should "prune watchers" do diff -r 487d96eac004 -r 5e80956cc792 test/unit/message_test.rb --- a/test/unit/message_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/message_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -24,12 +24,14 @@ @board = Board.find(1) @user = User.find(1) end - + def test_create topics_count = @board.topics_count messages_count = @board.messages_count - - message = Message.new(:board => @board, :subject => 'Test message', :content => 'Test message content', :author => @user) + + message = Message.new(:board => @board, :subject => 'Test message', + :content => 'Test message content', + :author => @user) assert message.save @board.reload # topics count incremented @@ -40,15 +42,17 @@ # author should be watching the message assert message.watched_by?(@user) end - + def test_reply topics_count = @board.topics_count messages_count = @board.messages_count @message = Message.find(1) replies_count = @message.replies_count - + reply_author = User.find(2) - reply = Message.new(:board => @board, :subject => 'Test reply', :content => 'Test reply content', :parent => @message, :author => reply_author) + reply = Message.new(:board => @board, :subject => 'Test reply', + :content => 'Test reply content', + :parent => @message, :author => reply_author) assert reply.save @board.reload # same topics count @@ -63,7 +67,25 @@ # author should be watching the message assert @message.watched_by?(reply_author) end - + + def test_cannot_reply_to_locked_topic + topics_count = @board.topics_count + messages_count = @board.messages_count + @message = Message.find(1) + replies_count = @message.replies_count + assert_equal false, @message.locked + @message.locked = true + assert @message.save + assert_equal true, @message.locked + + reply_author = User.find(2) + reply = Message.new(:board => @board, :subject => 'Test reply', + :content => 'Test reply content', + :parent => @message, :author => reply_author) + reply.save + assert_equal 1, reply.errors.count + end + def test_moving_message_should_update_counters @message = Message.find(1) assert_no_difference 'Message.count' do @@ -80,17 +102,17 @@ end end end - + def test_destroy_topic message = Message.find(1) board = message.board - topics_count, messages_count = board.topics_count, board.messages_count - + topics_count, messages_count = board.topics_count, board.messages_count + assert_difference('Watcher.count', -1) do assert message.destroy end board.reload - + # Replies deleted assert Message.find_all_by_parent_id(1).empty? # Checks counters @@ -98,11 +120,11 @@ assert_equal messages_count - 3, board.messages_count # Watchers removed end - + def test_destroy_reply message = Message.find(5) board = message.board - topics_count, messages_count = board.topics_count, board.messages_count + topics_count, messages_count = board.topics_count, board.messages_count assert message.destroy board.reload @@ -110,25 +132,25 @@ assert_equal topics_count, board.topics_count assert_equal messages_count - 1, board.messages_count end - + def test_editable_by message = Message.find(6) author = message.author assert message.editable_by?(author) - + author.roles_for_project(message.project).first.remove_permission!(:edit_own_messages) assert !message.reload.editable_by?(author.reload) end - + def test_destroyable_by message = Message.find(6) author = message.author assert message.destroyable_by?(author) - + author.roles_for_project(message.project).first.remove_permission!(:delete_own_messages) assert !message.reload.destroyable_by?(author.reload) end - + def test_set_sticky message = Message.new assert_equal 0, message.sticky diff -r 487d96eac004 -r 5e80956cc792 test/unit/news_test.rb --- a/test/unit/news_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/news_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -24,10 +24,9 @@ { :title => 'Test news', :description => 'Lorem ipsum etc', :author => User.find(:first) } end - def setup end - + def test_create_should_send_email_notification ActionMailer::Base.deliveries.clear Setting.notified_events << 'news_added' @@ -36,7 +35,7 @@ assert news.save assert_equal 1, ActionMailer::Base.deliveries.size end - + def test_should_include_news_for_projects_with_news_enabled project = projects(:projects_001) assert project.enabled_modules.any?{ |em| em.name == 'news' } @@ -44,7 +43,7 @@ # News.latest should return news from projects_001 assert News.latest.any? { |news| news.project == project } end - + def test_should_not_include_news_for_projects_with_news_disabled EnabledModule.delete_all(["project_id = ? AND name = ?", 2, 'news']) project = Project.find(2) @@ -55,11 +54,11 @@ # News.latest should not return that new piece of news assert News.latest.include?(news) == false end - + def test_should_only_include_news_from_projects_visibly_to_the_user - assert News.latest(User.anonymous).all? { |news| news.project.is_public? } + assert News.latest(User.anonymous).all? { |news| news.project.is_public? } end - + def test_should_limit_the_amount_of_returned_news # Make sure we have a bunch of news stories 10.times { projects(:projects_001).news.create(valid_news) } diff -r 487d96eac004 -r 5e80956cc792 test/unit/principal_test.rb --- a/test/unit/principal_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/principal_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2009 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -33,7 +33,7 @@ Principal.generate!(:mail => 'mail@example.com') Principal.generate!(:mail => 'mail2@example.com') end - + should "search login" do results = Principal.like('login') @@ -62,5 +62,5 @@ assert results.all? {|u| u.mail.match(/mail/) } end end - + end diff -r 487d96eac004 -r 5e80956cc792 test/unit/project_nested_set_test.rb --- a/test/unit/project_nested_set_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/project_nested_set_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2010 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -18,7 +18,7 @@ require File.expand_path('../../test_helper', __FILE__) class ProjectNestedSetTest < ActiveSupport::TestCase - + context "nested set" do setup do Project.delete_all @@ -28,7 +28,7 @@ @a1.set_parent!(@a) @a2 = Project.create!(:name => 'Project A2', :identifier => 'projecta2') @a2.set_parent!(@a) - + @b = Project.create!(:name => 'Project B', :identifier => 'projectb') @b1 = Project.create!(:name => 'Project B1', :identifier => 'projectb1') @b1.set_parent!(@b) @@ -36,14 +36,14 @@ @b11.set_parent!(@b1) @b2 = Project.create!(:name => 'Project B2', :identifier => 'projectb2') @b2.set_parent!(@b) - + @c = Project.create!(:name => 'Project C', :identifier => 'projectc') @c1 = Project.create!(:name => 'Project C1', :identifier => 'projectc1') @c1.set_parent!(@c) - + [@a, @a1, @a2, @b, @b1, @b11, @b2, @c, @c1].each(&:reload) end - + context "#create" do should "build valid tree" do assert_nested_set_values({ @@ -59,7 +59,7 @@ }) end end - + context "#set_parent!" do should "keep valid tree" do assert_no_difference 'Project.count' do @@ -75,7 +75,7 @@ }) end end - + context "#destroy" do context "a root with children" do should "not mess up the tree" do @@ -91,7 +91,7 @@ }) end end - + context "a child with children" do should "not mess up the tree" do assert_difference 'Project.count', -2 do @@ -107,7 +107,7 @@ end end end - + def assert_nested_set_values(h) assert Project.valid? h.each do |project, expected| diff -r 487d96eac004 -r 5e80956cc792 test/unit/project_test.rb --- a/test/unit/project_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/project_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,14 +18,25 @@ require File.expand_path('../../test_helper', __FILE__) class ProjectTest < ActiveSupport::TestCase - fixtures :all + fixtures :projects, :trackers, :issue_statuses, :issues, + :enumerations, :users, :issue_categories, + :projects_trackers, + :roles, + :member_roles, + :members, + :enabled_modules, + :workflows, + :versions, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :groups_users, + :boards def setup @ecookbook = Project.find(1) @ecookbook_sub1 = Project.find(3) User.current = nil end - + should_validate_presence_of :name should_validate_presence_of :identifier @@ -59,7 +70,7 @@ assert_kind_of Project, @ecookbook assert_equal "eCookbook", @ecookbook.name end - + def test_default_attributes with_settings :default_projects_public => '1' do assert_equal true, Project.new.is_public @@ -84,11 +95,11 @@ with_settings :default_projects_modules => ['issue_tracking', 'repository'] do assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names end - + assert_equal Tracker.all, Project.new.trackers assert_equal Tracker.find(1, 3), Project.new(:tracker_ids => [1, 3]).trackers end - + def test_update assert_equal "eCookbook", @ecookbook.name @ecookbook.name = "eCook" @@ -96,19 +107,19 @@ @ecookbook.reload assert_equal "eCook", @ecookbook.name end - + def test_validate_identifier to_test = {"abc" => true, "ab12" => true, "ab-12" => true, "12" => false, "new" => false} - + to_test.each do |identifier, valid| p = Project.new p.identifier = identifier p.valid? - assert_equal valid, p.errors.on('identifier').nil? + assert_equal valid, p.errors['identifier'].nil? end end @@ -117,18 +128,18 @@ assert_nil project.members.detect {|m| !(m.user.is_a?(User) && m.user.active?) } end end - + def test_users_should_be_active_users Project.all.each do |project| assert_nil project.users.detect {|u| !(u.is_a?(User) && u.active?) } end end - + def test_archive user = @ecookbook.members.first.user @ecookbook.archive @ecookbook.reload - + assert !@ecookbook.active? assert @ecookbook.archived? assert !user.projects.include?(@ecookbook) @@ -136,24 +147,24 @@ assert !@ecookbook.children.empty? assert @ecookbook.descendants.active.empty? end - + def test_archive_should_fail_if_versions_are_used_by_non_descendant_projects # Assign an issue of a project to a version of a child project Issue.find(4).update_attribute :fixed_version_id, 4 - + assert_no_difference "Project.count(:all, :conditions => 'status = #{Project::STATUS_ARCHIVED}')" do assert_equal false, @ecookbook.archive end @ecookbook.reload assert @ecookbook.active? end - + def test_unarchive user = @ecookbook.members.first.user @ecookbook.archive # A subproject of an archived project can not be unarchived assert !@ecookbook_sub1.unarchive - + # Unarchive project assert @ecookbook.unarchive @ecookbook.reload @@ -164,7 +175,7 @@ @ecookbook_sub1.reload assert @ecookbook_sub1.unarchive end - + def test_destroy # 2 active members assert_equal 2, @ecookbook.members.size @@ -172,7 +183,7 @@ assert_equal 3, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size # some boards assert @ecookbook.boards.any? - + @ecookbook.destroy # make sure that the project non longer exists assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) } @@ -181,12 +192,12 @@ assert_nil Board.first(:conditions => {:project_id => @ecookbook.id}) assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id}) end - + def test_destroying_root_projects_should_clear_data Project.roots.each do |root| root.destroy end - + assert_equal 0, Project.count, "Projects were not deleted: #{Project.all.inspect}" assert_equal 0, Member.count, "Members were not deleted: #{Member.all.inspect}" assert_equal 0, MemberRole.count @@ -216,7 +227,7 @@ assert_equal 0, Project.connection.select_all("SELECT * FROM custom_fields_projects").size assert_equal 0, CustomValue.count(:conditions => {:customized_type => ['Project', 'Issue', 'TimeEntry', 'Version']}) end - + def test_move_an_orphan_project_to_a_root_project sub = Project.find(2) sub.set_parent! @ecookbook @@ -224,22 +235,22 @@ @ecookbook.reload assert_equal 4, @ecookbook.children.size end - + def test_move_an_orphan_project_to_a_subproject sub = Project.find(2) assert sub.set_parent!(@ecookbook_sub1) end - + def test_move_a_root_project_to_a_project sub = @ecookbook assert sub.set_parent!(Project.find(2)) end - + def test_should_not_move_a_project_to_its_children sub = @ecookbook assert !(sub.set_parent!(Project.find(3))) end - + def test_set_parent_should_add_roots_in_alphabetical_order ProjectCustomField.delete_all Project.delete_all @@ -247,11 +258,11 @@ Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(nil) Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(nil) Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(nil) - + assert_equal 4, Project.count assert_equal Project.all.sort_by(&:name), Project.all.sort_by(&:lft) end - + def test_set_parent_should_add_children_in_alphabetical_order ProjectCustomField.delete_all parent = Project.create!(:name => 'Parent', :identifier => 'parent') @@ -259,12 +270,12 @@ Project.create!(:name => 'Project B', :identifier => 'project-b').set_parent!(parent) Project.create!(:name => 'Project D', :identifier => 'project-d').set_parent!(parent) Project.create!(:name => 'Project A', :identifier => 'project-a').set_parent!(parent) - + parent.reload assert_equal 4, parent.children.size assert_equal parent.children.sort_by(&:name), parent.children end - + def test_rebuild_should_sort_children_alphabetically ProjectCustomField.delete_all parent = Project.create!(:name => 'Parent', :identifier => 'parent') @@ -272,10 +283,10 @@ Project.create!(:name => 'Project B', :identifier => 'project-b').move_to_child_of(parent) Project.create!(:name => 'Project D', :identifier => 'project-d').move_to_child_of(parent) Project.create!(:name => 'Project A', :identifier => 'project-a').move_to_child_of(parent) - + Project.update_all("lft = NULL, rgt = NULL") Project.rebuild! - + parent.reload assert_equal 4, parent.children.size assert_equal parent.children.sort_by(&:name), parent.children @@ -300,49 +311,49 @@ issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6) issue_with_hierarchy_fixed_version.reload assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id - + # Move project out of the issue's hierarchy moved_project = Project.find(3) moved_project.set_parent!(Project.find(2)) parent_issue.reload issue_with_local_fixed_version.reload issue_with_hierarchy_fixed_version.reload - + assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project" assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in" assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue." end - + def test_parent p = Project.find(6).parent assert p.is_a?(Project) assert_equal 5, p.id end - + def test_ancestors a = Project.find(6).ancestors assert a.first.is_a?(Project) assert_equal [1, 5], a.collect(&:id) end - + def test_root r = Project.find(6).root assert r.is_a?(Project) assert_equal 1, r.id end - + def test_children c = Project.find(1).children assert c.first.is_a?(Project) assert_equal [5, 3, 4], c.collect(&:id) end - + def test_descendants d = Project.find(1).descendants assert d.first.is_a?(Project) assert_equal [5, 6, 3, 4], d.collect(&:id) end - + def test_allowed_parents_should_be_empty_for_non_member_user Role.non_member.add_permission!(:add_project) user = User.find(9) @@ -350,7 +361,7 @@ User.current = user assert Project.new.allowed_parents.compact.empty? end - + def test_allowed_parents_with_add_subprojects_permission Role.find(1).remove_permission!(:add_project) Role.find(1).add_permission!(:add_subprojects) @@ -392,7 +403,7 @@ assert Project.find(3).allowed_parents.include?(Project.find(1)) assert Project.find(3).allowed_parents.include?(nil) end - + def test_users_by_role users_by_role = Project.find(1).users_by_role assert_kind_of Hash, users_by_role @@ -400,29 +411,29 @@ assert_kind_of Array, users_by_role[role] assert users_by_role[role].include?(User.find(2)) end - + def test_rolled_up_trackers parent = Project.find(1) parent.trackers = Tracker.find([1,2]) child = parent.children.find(3) - + assert_equal [1, 2], parent.tracker_ids assert_equal [2, 3], child.trackers.collect(&:id) - + assert_kind_of Tracker, parent.rolled_up_trackers.first assert_equal Tracker.find(1), parent.rolled_up_trackers.first - + assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id) assert_equal [2, 3], child.rolled_up_trackers.collect(&:id) end - + def test_rolled_up_trackers_should_ignore_archived_subprojects parent = Project.find(1) parent.trackers = Tracker.find([1,2]) child = parent.children.find(3) child.trackers = Tracker.find([1,3]) parent.children.each(&:archive) - + assert_equal [1,2], parent.rolled_up_trackers.collect(&:id) end @@ -432,11 +443,11 @@ @parent_version_1 = Version.generate!(:project => @project) @parent_version_2 = Version.generate!(:project => @project) end - + should "include the versions for the current project" do assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions end - + should "include versions for a subproject" do @subproject = Project.generate! @subproject.set_parent!(@project) @@ -448,7 +459,7 @@ @subproject_version ], @project.rolled_up_versions end - + should "include versions for a sub-subproject" do @subproject = Project.generate! @subproject.set_parent!(@project) @@ -465,7 +476,6 @@ ], @project.rolled_up_versions end - should "only check active projects" do @subproject = Project.generate! @subproject.set_parent!(@project) @@ -478,7 +488,7 @@ assert_same_elements [@parent_version_1, @parent_version_2], @project.rolled_up_versions end end - + def test_shared_versions_none_sharing p = Project.find(5) v = Version.create!(:name => 'none_sharing', :project => p, :sharing => 'none') @@ -498,7 +508,7 @@ assert !p.siblings.first.shared_versions.include?(v) assert !p.root.siblings.first.shared_versions.include?(v) end - + def test_shared_versions_hierarchy_sharing p = Project.find(5) v = Version.create!(:name => 'hierarchy_sharing', :project => p, :sharing => 'hierarchy') @@ -533,7 +543,7 @@ parent = Project.find(1) child = parent.children.find(3) private_child = parent.children.find(5) - + assert_equal [1,2,3], parent.version_ids.sort assert_equal [4], child.version_ids assert_equal [6], private_child.version_ids @@ -552,7 +562,7 @@ child = parent.children.find(3) child.archive parent.reload - + assert_equal [1,2,3], parent.version_ids.sort assert_equal [4], child.version_ids assert !parent.shared_versions.collect(&:id).include?(4) @@ -562,12 +572,12 @@ user = User.find(3) parent = Project.find(1) child = parent.children.find(5) - + assert_equal [1,2,3], parent.version_ids.sort assert_equal [6], child.version_ids versions = parent.shared_versions.visible(user) - + assert_equal 4, versions.size versions.each do |version| assert_kind_of Version, version @@ -576,7 +586,6 @@ assert !versions.collect(&:id).include?(6) end - def test_next_identifier ProjectCustomField.delete_all Project.create!(:name => 'last', :identifier => 'p2008040') @@ -587,11 +596,11 @@ Project.delete_all assert_nil Project.next_identifier end - + def test_enabled_module_names with_settings :default_projects_modules => ['issue_tracking', 'repository'] do project = Project.new - + project.enabled_module_names = %w(issue_tracking news) assert_equal %w(issue_tracking news), project.enabled_module_names.sort end @@ -667,7 +676,7 @@ assert copied_project.id.blank? assert copied_project.name.blank? assert copied_project.identifier.blank? - + # Duplicated attributes assert_equal source_project.description, copied_project.description assert_equal source_project.enabled_modules, copied_project.enabled_modules @@ -745,11 +754,11 @@ assert system_activity.active? overridden_activity = TimeEntryActivity.generate!(:project => project, :parent => system_activity, :active => false) assert overridden_activity.save! - + assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity not found" assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override" end - + def test_close_completed_versions Version.update_all("status = 'open'") project = Project.find(1) @@ -787,7 +796,7 @@ assert ! issue.assigned_to.blank? assert_equal @project, issue.project end - + copied_issue = @project.issues.first(:conditions => {:subject => "copy issue status"}) assert copied_issue assert copied_issue.status @@ -804,7 +813,7 @@ :subject => "change the new issues to use the copied version", :tracker_id => 1, :project_id => @source_project.id) - + assert @project.copy(@source_project) @project.reload copied_issue = @project.issues.first(:conditions => {:subject => "change the new issues to use the copied version"}) @@ -861,10 +870,10 @@ assert_equal @project, membership.project end end - + should "copy memberships with groups and additional roles" do group = Group.create!(:lastname => "Copy group") - user = User.find(7) + user = User.find(7) group.users << user # group role Member.create!(:project_id => @source_project.id, :principal => group, :role_ids => [2]) @@ -888,6 +897,7 @@ assert query assert_equal @project, query.project end + assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort end should "copy versions" do @@ -918,7 +928,7 @@ assert_difference 'WikiPage.count', @source_project.wiki.pages.size do assert @project.copy(@source_project) end - + assert @project.wiki assert_equal @source_project.wiki.pages.size, @project.wiki.pages.size @@ -926,7 +936,7 @@ assert wiki_page.content assert !@source_project.wiki.pages.include?(wiki_page) end - + parent = @project.wiki.find_page('Parent_page') child1 = @project.wiki.find_page('Child_page_1') child2 = @project.wiki.find_page('Child_page_2') @@ -964,19 +974,19 @@ assert_not_equal IssueCategory.find(3), issue.category # Different record end end - + should "limit copy with :only option" do assert @project.members.empty? assert @project.issue_categories.empty? assert @source_project.issues.any? - + assert @project.copy(@source_project, :only => ['members', 'issue_categories']) assert @project.members.any? assert @project.issue_categories.any? assert @project.issues.empty? end - + end context "#start_date" do @@ -985,11 +995,11 @@ @project = Project.generate!(:identifier => 'test0') @project.trackers << Tracker.generate! end - + should "be nil if there are no issues on the project" do assert_nil @project.start_date end - + should "be tested when issues have no start date" should "be the earliest start date of it's issues" do @@ -1008,11 +1018,11 @@ @project = Project.generate!(:identifier => 'test0') @project.trackers << Tracker.generate! end - + should "be nil if there are no issues on the project" do assert_nil @project.due_date end - + should "be tested when issues have no due date" should "be the latest due date of it's issues" do @@ -1027,7 +1037,7 @@ future = 7.days.from_now.to_date @project.versions << Version.generate!(:effective_date => future) @project.versions << Version.generate!(:effective_date => Date.today) - + assert_equal future, @project.due_date @@ -1038,7 +1048,7 @@ far_future = 14.days.from_now.to_date Issue.generate_for_project!(@project, :due_date => far_future) @project.versions << Version.generate!(:effective_date => future) - + assert_equal far_future, @project.due_date end @@ -1090,7 +1100,7 @@ setup do @project = Project.generate! @role = Role.generate! - + @user_with_membership_notification = User.generate!(:mail_notification => 'selected') Member.generate!(:project => @project, :roles => [@role], :principal => @user_with_membership_notification, :mail_notification => true) @@ -1109,30 +1119,30 @@ @only_owned_user = User.generate!(:mail_notification => 'only_owner') Member.generate!(:project => @project, :roles => [@role], :principal => @only_owned_user) end - + should "include members with a mail notification" do assert @project.notified_users.include?(@user_with_membership_notification) end - + should "include users with the 'all' notification option" do assert @project.notified_users.include?(@all_events_user) end - + should "not include users with the 'none' notification option" do assert !@project.notified_users.include?(@no_events_user) end - + should "not include users with the 'only_my_events' notification option" do assert !@project.notified_users.include?(@only_my_events_user) end - + should "not include users with the 'only_assigned' notification option" do assert !@project.notified_users.include?(@only_assigned_user) end - + should "not include users with the 'only_owner' notification option" do assert !@project.notified_users.include?(@only_owned_user) end end - + end diff -r 487d96eac004 -r 5e80956cc792 test/unit/query_test.rb --- a/test/unit/query_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/query_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,21 +18,26 @@ require File.expand_path('../../test_helper', __FILE__) class QueryTest < ActiveSupport::TestCase - fixtures :projects, :enabled_modules, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :watchers, :custom_fields, :custom_values, :versions, :queries + fixtures :projects, :enabled_modules, :users, :members, + :member_roles, :roles, :trackers, :issue_statuses, + :issue_categories, :enumerations, :issues, + :watchers, :custom_fields, :custom_values, :versions, + :queries, + :projects_trackers def test_custom_fields_for_all_projects_should_be_available_in_global_queries query = Query.new(:project => nil, :name => '_') assert query.available_filters.has_key?('cf_1') assert !query.available_filters.has_key?('cf_3') end - + def test_system_shared_versions_should_be_available_in_global_queries Version.find(2).update_attribute :sharing, 'system' query = Query.new(:project => nil, :name => '_') assert query.available_filters.has_key?('fixed_version_id') assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'} end - + def test_project_filter_in_global_queries query = Query.new(:project => nil, :name => '_') project_filter = query.available_filters["project_id"] @@ -41,10 +46,10 @@ assert project_ids.include?("1") #public project assert !project_ids.include?("2") #private project user cannot see end - + def find_issues_with_query(query) Issue.find :all, - :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :include => [ :assigned_to, :status, :tracker, :project, :priority ], :conditions => query.statement end @@ -57,6 +62,13 @@ def assert_query_statement_includes(query, condition) assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}" end + + def assert_query_result(expected, query) + assert_nothing_raised do + assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort + assert_equal expected.size, query.issue_count + end + end def test_query_should_allow_shared_versions_for_a_project_query subproject_version = Version.find(4) @@ -65,7 +77,7 @@ assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')") end - + def test_query_with_multiple_custom_fields query = Query.find(1) assert query.valid? @@ -74,7 +86,7 @@ assert_equal 1, issues.length assert_equal Issue.find(3), issues.first end - + def test_operator_none query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('fixed_version_id', '!*', ['']) @@ -83,7 +95,7 @@ assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''") find_issues_with_query(query) end - + def test_operator_none_for_integer query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('estimated_hours', '!*', ['']) @@ -92,6 +104,14 @@ assert issues.all? {|i| !i.estimated_hours} end + def test_operator_none_for_date + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('start_date', '!*', ['']) + issues = find_issues_with_query(query) + assert !issues.empty? + assert issues.all? {|i| i.start_date.nil?} + end + def test_operator_all query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('fixed_version_id', '*', ['']) @@ -100,11 +120,134 @@ assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''") find_issues_with_query(query) end - + + def test_operator_all_for_date + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('start_date', '*', ['']) + issues = find_issues_with_query(query) + assert !issues.empty? + assert issues.all? {|i| i.start_date.present?} + end + + def test_numeric_filter_should_not_accept_non_numeric_values + query = Query.new(:name => '_') + query.add_filter('estimated_hours', '=', ['a']) + + assert query.has_filter?('estimated_hours') + assert !query.valid? + end + + def test_operator_is_on_float + Issue.update_all("estimated_hours = 171.2", "id=2") + + query = Query.new(:name => '_') + query.add_filter('estimated_hours', '=', ['171.20']) + issues = find_issues_with_query(query) + assert_equal 1, issues.size + assert_equal 2, issues.first.id + end + def test_operator_greater_than query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('done_ratio', '>=', ['40']) - assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40") + assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0") + find_issues_with_query(query) + end + + def test_operator_greater_than_a_float + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('estimated_hours', '>=', ['40.5']) + assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5") + find_issues_with_query(query) + end + + def test_operator_greater_than_on_custom_field + f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter("cf_#{f.id}", '>=', ['40']) + assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) >= 40.0") + find_issues_with_query(query) + end + + def test_operator_lesser_than + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('done_ratio', '<=', ['30']) + assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0") + find_issues_with_query(query) + end + + def test_operator_lesser_than_on_custom_field + f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter("cf_#{f.id}", '<=', ['30']) + assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0") + find_issues_with_query(query) + end + + def test_operator_between + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('done_ratio', '><', ['30', '40']) + assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement + find_issues_with_query(query) + end + + def test_operator_between_on_custom_field + f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter("cf_#{f.id}", '><', ['30', '40']) + assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement + find_issues_with_query(query) + end + + def test_date_filter_should_not_accept_non_date_values + query = Query.new(:name => '_') + query.add_filter('created_on', '=', ['a']) + + assert query.has_filter?('created_on') + assert !query.valid? + end + + def test_date_filter_should_not_accept_invalid_date_values + query = Query.new(:name => '_') + query.add_filter('created_on', '=', ['2011-01-34']) + + assert query.has_filter?('created_on') + assert !query.valid? + end + + def test_relative_date_filter_should_not_accept_non_integer_values + query = Query.new(:name => '_') + query.add_filter('created_on', '>t-', ['a']) + + assert query.has_filter?('created_on') + assert !query.valid? + end + + def test_operator_date_equals + query = Query.new(:name => '_') + query.add_filter('due_date', '=', ['2011-07-10']) + assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement + find_issues_with_query(query) + end + + def test_operator_date_lesser_than + query = Query.new(:name => '_') + query.add_filter('due_date', '<=', ['2011-07-10']) + assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement + find_issues_with_query(query) + end + + def test_operator_date_greater_than + query = Query.new(:name => '_') + query.add_filter('due_date', '>=', ['2011-07-10']) + assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement + find_issues_with_query(query) + end + + def test_operator_date_between + query = Query.new(:name => '_') + query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10']) + assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement find_issues_with_query(query) end @@ -124,7 +267,7 @@ assert !issues.empty? issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))} end - + def test_operator_less_than_ago Issue.find(7).update_attribute(:due_date, (Date.today - 3)) query = Query.new(:project => Project.find(1), :name => '_') @@ -133,7 +276,7 @@ assert !issues.empty? issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)} end - + def test_operator_more_than_ago Issue.find(7).update_attribute(:due_date, (Date.today - 10)) query = Query.new(:project => Project.find(1), :name => '_') @@ -190,37 +333,55 @@ assert result.empty? result.each {|issue| assert issue.subject.downcase.include?('unable') } end - + def test_range_for_this_week_with_week_starting_on_monday I18n.locale = :fr assert_equal '1', I18n.t(:general_first_day_of_week) - + Date.stubs(:today).returns(Date.parse('2011-04-29')) - + query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('due_date', 'w', ['']) assert query.statement.match(/issues\.due_date > '2011-04-24 23:59:59(\.9+)?' AND issues\.due_date <= '2011-05-01 23:59:59(\.9+)?/), "range not found in #{query.statement}" I18n.locale = :en end - + def test_range_for_this_week_with_week_starting_on_sunday I18n.locale = :en assert_equal '7', I18n.t(:general_first_day_of_week) - + Date.stubs(:today).returns(Date.parse('2011-04-29')) - + query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('due_date', 'w', ['']) assert query.statement.match(/issues\.due_date > '2011-04-23 23:59:59(\.9+)?' AND issues\.due_date <= '2011-04-30 23:59:59(\.9+)?/), "range not found in #{query.statement}" end - + def test_operator_does_not_contains query = Query.new(:project => Project.find(1), :name => '_') query.add_filter('subject', '!~', ['uNable']) assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'") find_issues_with_query(query) end - + + def test_filter_assigned_to_me + user = User.find(2) + group = Group.find(10) + User.current = user + i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user) + i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group) + i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11)) + group.users << user + + query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}}) + result = query.issues + assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id) + + assert result.include?(i1) + assert result.include?(i2) + assert !result.include?(i3) + end + def test_filter_watched_issues User.current = User.find(1) query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}}) @@ -230,7 +391,7 @@ assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id) User.current = nil end - + def test_filter_unwatched_issues User.current = User.find(1) query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}}) @@ -240,20 +401,20 @@ assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size) User.current = nil end - + def test_statement_should_be_nil_with_no_filters q = Query.new(:name => '_') q.filters = {} - + assert q.valid? assert_nil q.statement end - + def test_default_columns q = Query.new - assert !q.columns.empty? + assert !q.columns.empty? end - + def test_set_column_names q = Query.new q.column_names = ['tracker', :subject, '', 'unknonw_column'] @@ -261,7 +422,7 @@ c = q.columns.first assert q.has_column?(c) end - + def test_groupable_columns_should_include_custom_fields q = Query.new assert q.groupable_columns.detect {|c| c.is_a? QueryCustomFieldColumn} @@ -275,7 +436,7 @@ assert_not_nil q.group_by_statement assert_equal 'status', q.group_by_statement end - + def test_grouped_with_invalid_column q = Query.new(:group_by => 'foo') assert !q.grouped? @@ -283,23 +444,39 @@ assert_nil q.group_by_statement end + def test_sortable_columns_should_sort_assignees_according_to_user_format_setting + with_settings :user_format => 'lastname_coma_firstname' do + q = Query.new + assert q.sortable_columns.has_key?('assigned_to') + assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to'] + end + end + + def test_sortable_columns_should_sort_authors_according_to_user_format_setting + with_settings :user_format => 'lastname_coma_firstname' do + q = Query.new + assert q.sortable_columns.has_key?('author') + assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author'] + end + end + def test_default_sort q = Query.new assert_equal [], q.sort_criteria end - + def test_set_sort_criteria_with_hash q = Query.new q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']} assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria end - + def test_set_sort_criteria_with_array q = Query.new q.sort_criteria = [['priority', 'desc'], 'tracker'] assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria end - + def test_create_query_with_sort q = Query.new(:name => 'Sorted') q.sort_criteria = [['priority', 'desc'], 'tracker'] @@ -307,56 +484,70 @@ q.reload assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria end - + def test_sort_by_string_custom_field_asc q = Query.new c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' } assert c assert c.sortable issues = Issue.find :all, - :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :include => [ :assigned_to, :status, :tracker, :project, :priority ], :conditions => q.statement, :order => "#{c.sortable} ASC" values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s} assert !values.empty? assert_equal values.sort, values end - + def test_sort_by_string_custom_field_desc q = Query.new c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' } assert c assert c.sortable issues = Issue.find :all, - :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :include => [ :assigned_to, :status, :tracker, :project, :priority ], :conditions => q.statement, :order => "#{c.sortable} DESC" values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s} assert !values.empty? assert_equal values.sort.reverse, values end - + def test_sort_by_float_custom_field_asc q = Query.new c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' } assert c assert c.sortable issues = Issue.find :all, - :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :include => [ :assigned_to, :status, :tracker, :project, :priority ], :conditions => q.statement, :order => "#{c.sortable} ASC" values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact assert !values.empty? assert_equal values.sort, values end - + def test_invalid_query_should_raise_query_statement_invalid_error q = Query.new assert_raise Query::StatementInvalid do q.issues(:conditions => "foo = 1") end end - + + def test_issue_count + q = Query.new(:name => '_') + issue_count = q.issue_count + assert_equal q.issues.size, issue_count + end + + def test_issue_count_with_archived_issues + p = Project.generate!( :status => Project::STATUS_ARCHIVED ) + i = Issue.generate!( :project => p, :tracker => p.trackers.first ) + assert !i.visible? + + test_issue_count + end + def test_issue_count_by_association_group q = Query.new(:name => '_', :group_by => 'assigned_to') count_by_group = q.issue_count_by_group @@ -374,7 +565,7 @@ assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq assert count_by_group.has_key?('MySQL') end - + def test_issue_count_by_date_custom_field_group q = Query.new(:name => '_', :group_by => 'cf_8') count_by_group = q.issue_count_by_group @@ -382,17 +573,17 @@ assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq end - + def test_label_for q = Query.new assert_equal 'assigned_to', q.label_for('assigned_to_id') end - + def test_editable_by admin = User.find(1) manager = User.find(2) developer = User.find(3) - + # Public query on project 1 q = Query.find(1) assert q.editable_by?(admin) @@ -418,11 +609,21 @@ assert !q.editable_by?(developer) end + def test_visible_scope + query_ids = Query.visible(User.anonymous).map(&:id) + + assert query_ids.include?(1), 'public query on public project was not visible' + assert query_ids.include?(4), 'public query for all projects was not visible' + assert !query_ids.include?(2), 'private query on public project was visible' + assert !query_ids.include?(3), 'private query for all projects was visible' + assert !query_ids.include?(7), 'public query on private project was visible' + end + context "#available_filters" do setup do @query = Query.new(:name => "_") end - + should "include users of visible projects in cross-project view" do users = @query.available_filters["assigned_to_id"] assert_not_nil users @@ -439,11 +640,11 @@ should "be present" do assert @query.available_filters.keys.include?("member_of_group") end - + should "be an optional list" do assert_equal :list_optional, @query.available_filters["member_of_group"][:type] end - + should "have a list of the groups as values" do Group.destroy_all # No fixtures group1 = Group.generate!.reload @@ -462,11 +663,11 @@ should "be present" do assert @query.available_filters.keys.include?("assigned_to_role") end - + should "be an optional list" do assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type] end - + should "have a list of the Roles as values" do assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1']) assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2']) @@ -490,16 +691,16 @@ @second_user_in_group = User.generate! @user_in_group2 = User.generate! @user_not_in_group = User.generate! - + @group = Group.generate!.reload @group.users << @user_in_group @group.users << @second_user_in_group - + @group2 = Group.generate!.reload @group2.users << @user_in_group2 - + end - + should "search assigned to for users in the group" do @query = Query.new(:name => '_') @query.add_filter('member_of_group', '=', [@group.id.to_s]) @@ -525,83 +726,99 @@ assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}')" assert_find_issues_with_query_is_successful @query end - + should "return an empty set with = empty group" do @empty_group = Group.generate! @query = Query.new(:name => '_') @query.add_filter('member_of_group', '=', [@empty_group.id.to_s]) - + assert_equal [], find_issues_with_query(@query) end - + should "return issues with ! empty group" do @empty_group = Group.generate! @query = Query.new(:name => '_') @query.add_filter('member_of_group', '!', [@empty_group.id.to_s]) - + assert_find_issues_with_query_is_successful @query end end context "with 'assigned_to_role' filter" do setup do - # No fixtures - MemberRole.delete_all - Member.delete_all - Role.delete_all - - @manager_role = Role.generate!(:name => 'Manager') - @developer_role = Role.generate!(:name => 'Developer') + @manager_role = Role.find_by_name('Manager') + @developer_role = Role.find_by_name('Developer') @project = Project.generate! @manager = User.generate! @developer = User.generate! @boss = User.generate! + @guest = User.generate! User.add_to_project(@manager, @project, @manager_role) User.add_to_project(@developer, @project, @developer_role) User.add_to_project(@boss, @project, [@manager_role, @developer_role]) + + @issue1 = Issue.generate_for_project!(@project, :assigned_to_id => @manager.id) + @issue2 = Issue.generate_for_project!(@project, :assigned_to_id => @developer.id) + @issue3 = Issue.generate_for_project!(@project, :assigned_to_id => @boss.id) + @issue4 = Issue.generate_for_project!(@project, :assigned_to_id => @guest.id) + @issue5 = Issue.generate_for_project!(@project) end - + should "search assigned to for users with the Role" do - @query = Query.new(:name => '_') + @query = Query.new(:name => '_', :project => @project) @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s]) - assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@boss.id}')" - assert_find_issues_with_query_is_successful @query + assert_query_result [@issue1, @issue3], @query + end + + should "search assigned to for users with the Role on the issue project" do + other_project = Project.generate! + User.add_to_project(@developer, other_project, @manager_role) + + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s]) + + assert_query_result [@issue1, @issue3], @query + end + + should "return an empty set with empty role" do + @empty_role = Role.generate! + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s]) + + assert_query_result [], @query + end + + should "search assigned to for users without the Role" do + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s]) + + assert_query_result [@issue2, @issue4, @issue5], @query end should "search assigned to for users not assigned to any Role (none)" do - @query = Query.new(:name => '_') + @query = Query.new(:name => '_', :project => @project) @query.add_filter('assigned_to_role', '!*', ['']) - assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')" - assert_find_issues_with_query_is_successful @query + assert_query_result [@issue4, @issue5], @query end should "search assigned to for users assigned to any Role (all)" do - @query = Query.new(:name => '_') + @query = Query.new(:name => '_', :project => @project) @query.add_filter('assigned_to_role', '*', ['']) - assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')" - assert_find_issues_with_query_is_successful @query + assert_query_result [@issue1, @issue2, @issue3], @query end - - should "return an empty set with empty role" do - @empty_role = Role.generate! - @query = Query.new(:name => '_') - @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s]) - - assert_equal [], find_issues_with_query(@query) - end - + should "return issues with ! empty role" do @empty_role = Role.generate! - @query = Query.new(:name => '_') - @query.add_filter('member_of_group', '!', [@empty_role.id.to_s]) - - assert_find_issues_with_query_is_successful @query + @query = Query.new(:name => '_', :project => @project) + @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s]) + + assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query end end end - + end diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_bazaar_test.rb --- a/test/unit/repository_bazaar_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_bazaar_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -20,9 +20,9 @@ class RepositoryBazaarTest < ActiveSupport::TestCase fixtures :projects - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/bazaar_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository/trunk').to_s REPOSITORY_PATH.gsub!(/\/+/, '/') + NUM_REV = 4 def setup @project = Project.find(3) @@ -32,38 +32,43 @@ assert @repository end - if File.directory?(REPOSITORY_PATH) + if File.directory?(REPOSITORY_PATH) def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - - assert_equal 4, @repository.changesets.count + @project.reload + + assert_equal NUM_REV, @repository.changesets.count assert_equal 9, @repository.changes.count assert_equal 'Initial import', @repository.changesets.find_by_revision('1').comments end def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count # Remove changesets with revision > 5 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2} - @repository.reload + @project.reload assert_equal 2, @repository.changesets.count - + @repository.fetch_changesets - assert_equal 4, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count end def test_entries entries = @repository.entries assert_equal 2, entries.size - + assert_equal 'dir', entries[0].kind assert_equal 'directory', entries[0].name - + assert_equal 'file', entries[1].kind assert_equal 'doc-mkdir.txt', entries[1].name end - + def test_entries_in_subdirectory entries = @repository.entries('directory') assert_equal 3, entries.size @@ -73,29 +78,37 @@ end def test_previous + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('3') assert_equal @repository.find_changeset_by_name('2'), changeset.previous end def test_previous_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('1') assert_nil changeset.previous end def test_next + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('2') assert_equal @repository.find_changeset_by_name('3'), changeset.next end def test_next_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('4') assert_nil changeset.next end diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_cvs_test.rb --- a/test/unit/repository_cvs_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_cvs_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,8 +20,7 @@ class RepositoryCvsTest < ActiveSupport::TestCase fixtures :projects - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? # CVS module MODULE_NAME = 'test' @@ -40,7 +39,7 @@ def test_fetch_changesets_from_scratch assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload assert_equal CHANGESETS_NUM, @repository.changesets.count assert_equal 16, @repository.changes.count @@ -83,7 +82,7 @@ def test_deleted_files_should_not_be_listed assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload assert_equal CHANGESETS_NUM, @repository.changesets.count entries = @repository.entries('sources') @@ -92,8 +91,10 @@ end def test_entries_rev3 + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count entries = @repository.entries('', '3') assert_equal 3, entries.size assert_equal entries[2].name, "README" @@ -104,21 +105,27 @@ end def test_entries_invalid_path + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count assert_nil @repository.entries('missing') assert_nil @repository.entries('missing', '3') end def test_entries_invalid_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count assert_nil @repository.entries('', '123') end def test_cat + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count buf = @repository.cat('README') assert buf lines = buf.split("\n") @@ -142,8 +149,10 @@ end def test_annotate + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal CHANGESETS_NUM, @repository.changesets.count ann = @repository.annotate('README') assert ann assert_equal 3, ann.revisions.length diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_darcs_test.rb --- a/test/unit/repository_darcs_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_darcs_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -20,47 +20,59 @@ class RepositoryDarcsTest < ActiveSupport::TestCase fixtures :projects - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/darcs_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s + NUM_REV = 6 def setup @project = Project.find(3) @repository = Repository::Darcs.create( - :project => @project, :url => REPOSITORY_PATH, - :log_encoding => 'UTF-8') + :project => @project, + :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8' + ) assert @repository end - if File.directory?(REPOSITORY_PATH) + if File.directory?(REPOSITORY_PATH) def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload - assert_equal 6, @repository.changesets.count + assert_equal NUM_REV, @repository.changesets.count assert_equal 13, @repository.changes.count assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments end def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + # Remove changesets with revision > 3 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3} - @repository.reload + @project.reload assert_equal 3, @repository.changesets.count - + @repository.fetch_changesets - assert_equal 6, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count end def test_entries_invalid_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count assert_nil @repository.entries('', '123') end def test_deleted_files_should_not_be_listed + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count entries = @repository.entries('sources') assert entries.detect {|e| e.name == 'watchers_controller.rb'} assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'} @@ -68,7 +80,10 @@ def test_cat if @repository.scm.supports_cat? + assert_equal 0, @repository.changesets.count @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count cat = @repository.cat("sources/welcome_controller.rb", 2) assert_not_nil cat assert cat.include?('class WelcomeController < ApplicationController') diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_filesystem_test.rb --- a/test/unit/repository_filesystem_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_filesystem_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,8 +20,7 @@ class RepositoryFilesystemTest < ActiveSupport::TestCase fixtures :projects - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/filesystem_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/filesystem_repository').to_s def setup @project = Project.find(3) @@ -35,8 +34,10 @@ if File.directory?(REPOSITORY_PATH) def test_fetch_changesets + assert_equal 0, @repository.changesets.count + assert_equal 0, @repository.changes.count @repository.fetch_changesets - @repository.reload + @project.reload assert_equal 0, @repository.changesets.count assert_equal 0, @repository.changes.count end diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_git_test.rb --- a/test/unit/repository_git_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_git_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,10 +20,11 @@ class RepositoryGitTest < ActiveSupport::TestCase fixtures :projects, :repositories, :enabled_modules, :users, :roles - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/git_repository' + REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin? + NUM_REV = 21 + FELIX_HEX = "Felix Sch\xC3\xA4fer" CHAR_1_HEX = "\xc3\x9c" @@ -33,6 +34,14 @@ # WINDOWS_PASS = Redmine::Platform.mswin? WINDOWS_PASS = false + ## Git, Mercurial and CVS path encodings are binary. + ## Subversion supports URL encoding for path. + ## Redmine Mercurial adapter and extension use URL encoding. + ## Git accepts only binary path in command line parameter. + ## So, there is no way to use binary command line parameter in JRuby. + JRUBY_SKIP = (RUBY_PLATFORM == 'java') + JRUBY_SKIP_STR = "TODO: This test fails in JRuby" + if File.directory?(REPOSITORY_PATH) def setup klass = Repository::Git @@ -57,10 +66,11 @@ def test_fetch_changesets_from_scratch assert_nil @repository.extra_info + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload - assert_equal 21, @repository.changesets.count + assert_equal NUM_REV, @repository.changesets.count assert_equal 33, @repository.changes.count commit = @repository.changesets.find(:first, :order => 'committed_on ASC') @@ -81,9 +91,10 @@ end def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert_equal 21, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count assert_equal 33, @repository.changes.count extra_info_db = @repository.extra_info["branches"] assert_equal 4, extra_info_db.size @@ -103,7 +114,7 @@ @repository.changesets.each do |rev| rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s } end - @repository.reload + @project.reload cs1 = @repository.changesets assert_equal 15, cs1.count h = @repository.extra_info.dup @@ -111,20 +122,21 @@ "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8" @repository.merge_extra_info(h) @repository.save - @repository.reload + @project.reload extra_info_db_1 = @repository.extra_info["branches"] assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", extra_info_db_1["master"]["last_scmid"] @repository.fetch_changesets - assert_equal 21, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count end def test_fetch_changesets_invalid_rev + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert_equal 21, @repository.changesets.count - assert_equal 33, @repository.changes.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count extra_info_db = @repository.extra_info["branches"] assert_equal 4, extra_info_db.size assert_equal "1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127", @@ -143,7 +155,7 @@ @repository.changesets.each do |rev| rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s } end - @repository.reload + @project.reload cs1 = @repository.changesets assert_equal 15, cs1.count h = @repository.extra_info.dup @@ -151,34 +163,55 @@ "abcd1234efgh" @repository.merge_extra_info(h) @repository.save - @repository.reload + @project.reload extra_info_db_1 = @repository.extra_info["branches"] assert_equal "abcd1234efgh", extra_info_db_1["master"]["last_scmid"] @repository.fetch_changesets + @project.reload assert_equal 15, @repository.changesets.count end + def test_parents + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + r1 = @repository.find_changeset_by_name("7234cb2750b63") + assert_equal [], r1.parents + r2 = @repository.find_changeset_by_name("899a15dba03a3") + assert_equal 1, r2.parents.length + assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", + r2.parents[0].identifier + r3 = @repository.find_changeset_by_name("32ae898b720c2") + assert_equal 2, r3.parents.length + r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort + assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", r4[0] + assert_equal "7e61ac704deecde634b51e59daa8110435dcb3da", r4[1] + end + def test_db_consistent_ordering_init assert_nil @repository.extra_info + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload assert_equal 1, @repository.extra_info["db_consistent"]["ordering"] end def test_db_consistent_ordering_before_1_2 assert_nil @repository.extra_info + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert_equal 21, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count assert_not_nil @repository.extra_info @repository.write_attribute(:extra_info, nil) @repository.save assert_nil @repository.extra_info - assert_equal 21, @repository.changesets.count + assert_equal NUM_REV, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload assert_equal 0, @repository.extra_info["db_consistent"]["ordering"] del_revs = [ @@ -192,7 +225,7 @@ @repository.changesets.each do |rev| rev.destroy if del_revs.detect {|r| r == rev.scmid.to_s } end - @repository.reload + @project.reload cs1 = @repository.changesets assert_equal 15, cs1.count assert_equal 0, @repository.extra_info["db_consistent"]["ordering"] @@ -201,19 +234,21 @@ "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8" @repository.merge_extra_info(h) @repository.save - @repository.reload + @project.reload extra_info_db_1 = @repository.extra_info["branches"] assert_equal "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", extra_info_db_1["master"]["last_scmid"] @repository.fetch_changesets - assert_equal 21, @repository.changesets.count + assert_equal NUM_REV, @repository.changesets.count assert_equal 0, @repository.extra_info["db_consistent"]["ordering"] end def test_latest_changesets + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count # with limit changesets = @repository.latest_changesets('', nil, 2) assert_equal 2, changesets.size @@ -308,27 +343,35 @@ '61b685fbe55ab05b5ac68402d5720c1a6ac973d1', ], changesets.collect(&:revision) - # latin-1 encoding path - changesets = @repository.latest_changesets( - "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89') - assert_equal [ + if JRUBY_SKIP + puts JRUBY_SKIP_STR + else + # latin-1 encoding path + changesets = @repository.latest_changesets( + "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89') + assert_equal [ '64f1f3e89ad1cb57976ff0ad99a107012ba3481d', '4fc55c43bf3d3dc2efb66145365ddc17639ce81e', ], changesets.collect(&:revision) - changesets = @repository.latest_changesets( + changesets = @repository.latest_changesets( "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89', 1) - assert_equal [ + assert_equal [ '64f1f3e89ad1cb57976ff0ad99a107012ba3481d', ], changesets.collect(&:revision) + end end def test_latest_changesets_latin_1_dir if WINDOWS_PASS # + elsif JRUBY_SKIP + puts JRUBY_SKIP_STR else + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changesets = @repository.latest_changesets( "latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed') assert_equal [ @@ -338,8 +381,10 @@ end def test_find_changeset_by_name + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r| assert_equal '7234cb2750b63f47bff735edc50a1c0a433c2518', @repository.find_changeset_by_name(r).revision @@ -347,24 +392,30 @@ end def test_find_changeset_by_empty_name + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['', ' ', nil].each do |r| assert_nil @repository.find_changeset_by_name(r) end end def test_identifier + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c = @repository.changesets.find_by_revision( '7234cb2750b63f47bff735edc50a1c0a433c2518') assert_equal c.scmid, c.identifier end def test_format_identifier + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c = @repository.changesets.find_by_revision( '7234cb2750b63f47bff735edc50a1c0a433c2518') assert_equal '7234cb27', c.format_identifier @@ -381,8 +432,10 @@ end def test_log_utf8 + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count str_felix_hex = FELIX_HEX.dup if str_felix_hex.respond_to?(:force_encoding) str_felix_hex.force_encoding('UTF-8') @@ -393,8 +446,10 @@ end def test_previous + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1| changeset = @repository.find_changeset_by_name(r1) %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2| @@ -404,8 +459,10 @@ end def test_previous_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb2|.each do |r1| changeset = @repository.find_changeset_by_name(r1) assert_nil changeset.previous @@ -413,8 +470,10 @@ end def test_next + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2| changeset = @repository.find_changeset_by_name(r2) %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1| @@ -424,8 +483,10 @@ end def test_next_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|67e7792ce20ccae2e4bb73eed09bb397819c8834 67e7792ce20cca|.each do |r1| changeset = @repository.find_changeset_by_name(r1) assert_nil changeset.next diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_mercurial_test.rb --- a/test/unit/repository_mercurial_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_mercurial_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,13 +20,11 @@ class RepositoryMercurialTest < ActiveSupport::TestCase fixtures :projects - # No '..' in the repository path - REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository' - + REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s + NUM_REV = 32 CHAR_1_HEX = "\xc3\x9c" if File.directory?(REPOSITORY_PATH) - def setup klass = Repository::Mercurial assert_equal "Mercurial", klass.scm_name @@ -34,7 +32,7 @@ assert_not_equal "", klass.scm_command assert_equal true, klass.scm_available - @project = Project.find(3) + @project = Project.find(3) @repository = Repository::Mercurial.create( :project => @project, :url => REPOSITORY_PATH, @@ -54,38 +52,47 @@ end def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - assert_equal 29, @repository.changesets.count - assert_equal 37, @repository.changes.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count + assert_equal 46, @repository.changes.count assert_equal "Initial import.\nThe repository contains 3 files.", @repository.changesets.find_by_revision('0').comments end def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count # Remove changesets with revision > 2 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 2} - @repository.reload + @project.reload assert_equal 3, @repository.changesets.count @repository.fetch_changesets - assert_equal 29, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count end def test_isodatesec # Template keyword 'isodatesec' supported in Mercurial 1.0 and higher if @repository.scm.class.client_version_above?([1, 0]) + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count rev0_committed_on = Time.gm(2007, 12, 14, 9, 22, 52) assert_equal @repository.changesets.find_by_revision('0').committed_on, rev0_committed_on end end def test_changeset_order_by_revision + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c0 = @repository.latest_changeset c1 = @repository.changesets.find_by_revision('0') @@ -95,24 +102,26 @@ end def test_latest_changesets + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count # with_limit changesets = @repository.latest_changesets('', nil, 2) - assert_equal %w|28 27|, changesets.collect(&:revision) + assert_equal %w|31 30|, changesets.collect(&:revision) # with_filepath changesets = @repository.latest_changesets( '/sql_escape/percent%dir/percent%file1.txt', nil) - assert_equal %w|11 10 9|, changesets.collect(&:revision) + assert_equal %w|30 11 10 9|, changesets.collect(&:revision) changesets = @repository.latest_changesets( '/sql_escape/underscore_dir/understrike_file.txt', nil) - assert_equal %w|12 9|, changesets.collect(&:revision) + assert_equal %w|30 12 9|, changesets.collect(&:revision) changesets = @repository.latest_changesets('README', nil) - assert_equal %w|28 17 8 6 1 0|, changesets.collect(&:revision) + assert_equal %w|31 30 28 17 8 6 1 0|, changesets.collect(&:revision) changesets = @repository.latest_changesets('README','8') assert_equal %w|8 6 1 0|, changesets.collect(&:revision) @@ -126,7 +135,7 @@ path = 'sql_escape/percent%dir' changesets = @repository.latest_changesets(path, nil) - assert_equal %w|13 11 10 9|, changesets.collect(&:revision) + assert_equal %w|30 13 11 10 9|, changesets.collect(&:revision) changesets = @repository.latest_changesets(path, '11') assert_equal %w|11 10 9|, changesets.collect(&:revision) @@ -136,7 +145,7 @@ path = 'sql_escape/underscore_dir' changesets = @repository.latest_changesets(path, nil) - assert_equal %w|13 12 9|, changesets.collect(&:revision) + assert_equal %w|30 13 12 9|, changesets.collect(&:revision) changesets = @repository.latest_changesets(path, '12') assert_equal %w|12 9|, changesets.collect(&:revision) @@ -158,16 +167,20 @@ assert_equal %w|4 3|, changesets.collect(&:revision) # named branch - changesets = @repository.latest_changesets('', @branch_char_1) - assert_equal %w|27 26|, changesets.collect(&:revision) + if @repository.scm.class.client_version_above?([1, 6]) + changesets = @repository.latest_changesets('', @branch_char_1) + assert_equal %w|27 26|, changesets.collect(&:revision) + end changesets = @repository.latest_changesets("latin-1-dir/test-#{@char_1}-subdir", @branch_char_1) assert_equal %w|27|, changesets.collect(&:revision) end def test_copied_files + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count cs1 = @repository.changesets.find_by_revision('13') assert_not_nil cs1 @@ -202,41 +215,69 @@ end def test_find_changeset_by_name + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|2 400bb8672109 400|.each do |r| assert_equal '2', @repository.find_changeset_by_name(r).revision end end def test_find_changeset_by_invalid_name + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count assert_nil @repository.find_changeset_by_name('100000') end def test_identifier + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c = @repository.changesets.find_by_revision('2') assert_equal c.scmid, c.identifier end def test_format_identifier + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c = @repository.changesets.find_by_revision('2') assert_equal '2:400bb8672109', c.format_identifier end def test_find_changeset_by_empty_name + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['', ' ', nil].each do |r| assert_nil @repository.find_changeset_by_name(r) end end + def test_parents + assert_equal 0, @repository.changesets.count + @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + r1 = @repository.changesets.find_by_revision('0') + assert_equal [], r1.parents + r2 = @repository.changesets.find_by_revision('1') + assert_equal 1, r2.parents.length + assert_equal "0885933ad4f6", + r2.parents[0].identifier + r3 = @repository.changesets.find_by_revision('30') + assert_equal 2, r3.parents.length + r4 = [r3.parents[0].identifier, r3.parents[1].identifier].sort + assert_equal "3a330eb32958", r4[0] + assert_equal "a94b0528f24f", r4[1] + end + def test_activities c = Changeset.new(:repository => @repository, :committed_on => Time.now, @@ -248,8 +289,10 @@ end def test_previous + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|28 3ae45e2d177d 3ae45|.each do |r1| changeset = @repository.find_changeset_by_name(r1) %w|27 7bbf4c738e71 7bbf|.each do |r2| @@ -259,8 +302,10 @@ end def test_previous_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|0 0885933ad4f6 0885|.each do |r1| changeset = @repository.find_changeset_by_name(r1) assert_nil changeset.previous @@ -268,8 +313,10 @@ end def test_next + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count %w|27 7bbf4c738e71 7bbf|.each do |r2| changeset = @repository.find_changeset_by_name(r2) %w|28 3ae45e2d177d 3ae45|.each do |r1| @@ -279,9 +326,11 @@ end def test_next_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload - %w|28 3ae45e2d177d 3ae45|.each do |r1| + @project.reload + assert_equal NUM_REV, @repository.changesets.count + %w|31 31eeee7395c8 31eee|.each do |r1| changeset = @repository.find_changeset_by_name(r1) assert_nil changeset.next end diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_subversion_test.rb --- a/test/unit/repository_subversion_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_subversion_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -20,6 +20,8 @@ class RepositorySubversionTest < ActiveSupport::TestCase fixtures :projects, :repositories, :enabled_modules, :users, :roles + NUM_REV = 11 + def setup @project = Project.find(3) @repository = Repository::Subversion.create(:project => @project, @@ -29,27 +31,36 @@ if repository_configured?('subversion') def test_fetch_changesets_from_scratch + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload - assert_equal 11, @repository.changesets.count + assert_equal NUM_REV, @repository.changesets.count assert_equal 20, @repository.changes.count assert_equal 'Initial import.', @repository.changesets.find_by_revision('1').comments end def test_fetch_changesets_incremental + assert_equal 0, @repository.changesets.count @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count + # Remove changesets with revision > 5 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 5} - @repository.reload + @project.reload assert_equal 5, @repository.changesets.count @repository.fetch_changesets - assert_equal 11, @repository.changesets.count + @project.reload + assert_equal NUM_REV, @repository.changesets.count end def test_latest_changesets + assert_equal 0, @repository.changesets.count @repository.fetch_changesets + @project.reload + assert_equal NUM_REV, @repository.changesets.count # with limit changesets = @repository.latest_changesets('', nil, 2) @@ -66,8 +77,10 @@ end def test_directory_listing_with_square_brackets_in_path + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count entries = @repository.entries('subversion_test/[folder_with_brackets]') assert_not_nil entries, 'Expect to find entries in folder_with_brackets' @@ -81,8 +94,9 @@ :project => @project, :url => "file:///#{self.class.repository_path('subversion')}/subversion_test/[folder_with_brackets]") + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload assert_equal 1, @repository.changesets.count, 'Expected to see 1 revision' assert_equal 2, @repository.changes.count, 'Expected to see 2 changes, dir add and file add' @@ -94,15 +108,19 @@ end def test_identifier + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c = @repository.changesets.find_by_revision('1') assert_equal c.revision, c.identifier end def test_find_changeset_by_empty_name + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count ['', ' ', nil].each do |r| assert_nil @repository.find_changeset_by_name(r) end @@ -115,8 +133,10 @@ end def test_format_identifier + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count c = @repository.changesets.find_by_revision('1') assert_equal c.format_identifier, c.revision end @@ -160,29 +180,37 @@ end def test_previous + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('3') assert_equal @repository.find_changeset_by_name('2'), changeset.previous end def test_previous_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('1') assert_nil changeset.previous end def test_next + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('2') assert_equal @repository.find_changeset_by_name('3'), changeset.next end def test_next_nil + assert_equal 0, @repository.changesets.count @repository.fetch_changesets - @repository.reload + @project.reload + assert_equal NUM_REV, @repository.changesets.count changeset = @repository.find_changeset_by_name('11') assert_nil changeset.next end diff -r 487d96eac004 -r 5e80956cc792 test/unit/repository_test.rb --- a/test/unit/repository_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/repository_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -138,7 +138,7 @@ changeset.comments ) end - def test_for_urls_strip + def test_for_urls_strip_cvs repository = Repository::Cvs.create( :project => Project.find(4), :url => ' :pserver:login:password@host:/path/to/the/repository', @@ -151,6 +151,24 @@ assert_equal 'foo', repository.root_url end + def test_for_urls_strip_subversion + repository = Repository::Subversion.create( + :project => Project.find(4), + :url => ' file:///dummy ') + assert repository.save + repository.reload + assert_equal 'file:///dummy', repository.url + end + + def test_for_urls_strip_git + repository = Repository::Git.create( + :project => Project.find(4), + :url => ' c:\dummy ') + assert repository.save + repository.reload + assert_equal 'c:\dummy', repository.url + end + def test_manual_user_mapping assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do c = Changeset.create!( diff -r 487d96eac004 -r 5e80956cc792 test/unit/role_test.rb --- a/test/unit/role_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/role_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -23,7 +23,7 @@ def test_copy_workflows source = Role.find(1) assert_equal 90, source.workflows.size - + target = Role.new(:name => 'Target') assert target.save target.workflows.copy(source) @@ -49,7 +49,7 @@ assert ! role.permissions.include?(perm[0]) assert_equal size - 2, role.permissions.size end - + def test_name I18n.locale = 'fr' assert_equal 'Manager', Role.find(1).name diff -r 487d96eac004 -r 5e80956cc792 test/unit/setting_test.rb --- a/test/unit/setting_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/setting_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -42,4 +42,17 @@ assert_equal ['issue_added', 'issue_updated', 'news_added'], Setting.notified_events assert_equal ['issue_added', 'issue_updated', 'news_added'], Setting.find_by_name('notified_events').value end + + def test_setting_should_be_reloaded_after_clear_cache + Setting.app_title = "My title" + assert_equal "My title", Setting.app_title + + s = Setting.find_by_name("app_title") + s.value = 'New title' + s.save! + assert_equal "My title", Setting.app_title + + Setting.clear_cache + assert_equal "New title", Setting.app_title + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/testing_test.rb --- a/test/unit/testing_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/testing_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. diff -r 487d96eac004 -r 5e80956cc792 test/unit/time_entry_activity_test.rb --- a/test/unit/time_entry_activity_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/time_entry_activity_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -72,8 +72,8 @@ # Blanking custom field, save should fail e.custom_field_values = {field.id => ""} assert !e.save - assert e.errors.on(:custom_values) - + assert e.errors[:custom_values] + # Update custom field to valid value, save should succeed e.custom_field_values = {field.id => "0"} assert e.save diff -r 487d96eac004 -r 5e80956cc792 test/unit/time_entry_test.rb --- a/test/unit/time_entry_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/time_entry_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -18,7 +18,15 @@ require File.expand_path('../../test_helper', __FILE__) class TimeEntryTest < ActiveSupport::TestCase - fixtures :issues, :projects, :users, :time_entries + fixtures :issues, :projects, :users, :time_entries, + :members, :roles, :member_roles, :auth_sources, + :trackers, :issue_statuses, + :projects_trackers, + :journals, :journal_details, + :issue_categories, :enumerations, + :groups_users, + :enabled_modules, + :workflows def test_hours_format assertions = { "2" => 2.0, @@ -38,53 +46,86 @@ "3 hours" => 3.0, "12min" => 0.2, } - + assertions.each do |k, v| t = TimeEntry.new(:hours => k) assert_equal v, t.hours, "Converting #{k} failed:" end end - + def test_hours_should_default_to_nil assert_nil TimeEntry.new.hours end - + def test_spent_on_with_blank c = TimeEntry.new c.spent_on = '' assert_nil c.spent_on end - + def test_spent_on_with_nil c = TimeEntry.new c.spent_on = nil assert_nil c.spent_on end - + def test_spent_on_with_string c = TimeEntry.new c.spent_on = "2011-01-14" assert_equal Date.parse("2011-01-14"), c.spent_on end - + def test_spent_on_with_invalid_string c = TimeEntry.new c.spent_on = "foo" assert_nil c.spent_on end - + def test_spent_on_with_date c = TimeEntry.new c.spent_on = Date.today assert_equal Date.today, c.spent_on end - + def test_spent_on_with_time c = TimeEntry.new c.spent_on = Time.now assert_equal Date.today, c.spent_on end + def test_validate_time_entry + anon = User.anonymous + project = Project.find(1) + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => anon.id, :status_id => 1, + :priority => IssuePriority.all.first, :subject => 'test_create', + :description => 'IssueTest#test_create', :estimated_hours => '1:30') + assert issue.save + activity = TimeEntryActivity.find_by_name('Design') + te = TimeEntry.create(:spent_on => '2010-01-01', + :hours => 100000, + :issue => issue, + :project => project, + :user => anon, + :activity => activity) + assert_equal 1, te.errors.count + end + + def test_set_project_if_nil + anon = User.anonymous + project = Project.find(1) + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => anon.id, :status_id => 1, + :priority => IssuePriority.all.first, :subject => 'test_create', + :description => 'IssueTest#test_create', :estimated_hours => '1:30') + assert issue.save + activity = TimeEntryActivity.find_by_name('Design') + te = TimeEntry.create(:spent_on => '2010-01-01', + :hours => 10, + :issue => issue, + :user => anon, + :activity => activity) + assert_equal project.id, te.project.id + end + context "#earilest_date_for_project" do setup do User.current = nil @@ -94,7 +135,7 @@ :issue => @issue, :project => @public_project) end - + context "without a project" do should "return the lowest spent_on value that is visible to the current user" do assert_equal "2007-03-12", TimeEntry.earilest_date_for_project.to_s @@ -106,7 +147,7 @@ assert_equal "2010-01-01", TimeEntry.earilest_date_for_project(@public_project).to_s end end - + end context "#latest_date_for_project" do @@ -131,5 +172,5 @@ assert_equal "2007-04-22", TimeEntry.latest_date_for_project(project).to_s end end - end + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/token_test.rb --- a/test/unit/token_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/token_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -26,7 +26,7 @@ assert_equal 40, token.value.length assert !token.expired? end - + def test_create_should_remove_existing_tokens user = User.find(1) t1 = Token.create(:user => user, :action => 'autologin') diff -r 487d96eac004 -r 5e80956cc792 test/unit/tracker_test.rb --- a/test/unit/tracker_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/tracker_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software +# Redmine - project management software # Copyright (C) 2006-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. @@ -23,25 +23,25 @@ def test_copy_workflows source = Tracker.find(1) assert_equal 89, source.workflows.size - + target = Tracker.new(:name => 'Target') assert target.save target.workflows.copy(source) target.reload assert_equal 89, target.workflows.size end - + def test_issue_statuses tracker = Tracker.find(1) Workflow.delete_all Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3) Workflow.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5) - + assert_kind_of Array, tracker.issue_statuses assert_kind_of IssueStatus, tracker.issue_statuses.first assert_equal [2, 3, 5], Tracker.find(1).issue_statuses.collect(&:id) end - + def test_issue_statuses_empty Workflow.delete_all("tracker_id = 1") assert_equal [], Tracker.find(1).issue_statuses diff -r 487d96eac004 -r 5e80956cc792 test/unit/user_preference_test.rb --- a/test/unit/user_preference_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/user_preference_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -25,18 +25,18 @@ user.login = "newuser" user.password, user.password_confirmation = "password", "password" assert user.save - + assert_kind_of UserPreference, user.pref assert_kind_of Hash, user.pref.others assert user.pref.save end - + def test_update user = User.find(1) assert_equal true, user.pref.hide_mail user.pref['preftest'] = 'value' assert user.pref.save - + user.reload assert_equal 'value', user.pref['preftest'] end diff -r 487d96eac004 -r 5e80956cc792 test/unit/user_test.rb --- a/test/unit/user_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/user_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -5,12 +5,12 @@ # 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. @@ -18,7 +18,15 @@ require File.expand_path('../../test_helper', __FILE__) class UserTest < ActiveSupport::TestCase - fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources + fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources, + :trackers, :issue_statuses, + :projects_trackers, + :watchers, + :issue_categories, :enumerations, :issues, + :journals, :journal_details, + :groups_users, + :enabled_modules, + :workflows def setup @admin = User.find(1) @@ -31,26 +39,33 @@ User.generate_with_protected!(:firstname => 'Testing connection') assert_equal 2, User.count(:all, :conditions => {:firstname => 'Testing connection'}) end - + def test_truth assert_kind_of User, @jsmith end - + def test_mail_should_be_stripped u = User.new u.mail = " foo@bar.com " assert_equal "foo@bar.com", u.mail end + def test_mail_validation + u = User.new + u.mail = '' + assert !u.valid? + assert_equal I18n.translate('activerecord.errors.messages.blank'), u.errors.on(:mail) + end + def test_create user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo") - + user.login = "jsmith" user.password, user.password_confirmation = "password", "password" # login uniqueness assert !user.save assert_equal 1, user.errors.count - + user.login = "newuser" user.password, user.password_confirmation = "passwd", "password" # password confirmation @@ -72,14 +87,14 @@ end end end - + context "User.login" do should "be case-insensitive." do u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo") u.login = 'newuser' u.password, u.password_confirmation = "password", "password" assert u.save - + u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo") u.login = 'NewUser' u.password, u.password_confirmation = "password", "password" @@ -93,7 +108,7 @@ u.login = 'newuser1' u.password, u.password_confirmation = "password", "password" assert u.save - + u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo") u.login = 'newuser2' u.password, u.password_confirmation = "password", "password" @@ -108,70 +123,70 @@ @admin.reload assert_equal "john", @admin.login end - + def test_destroy_should_delete_members_and_roles members = Member.find_all_by_user_id(2) ms = members.size rs = members.collect(&:roles).flatten.size - + assert_difference 'Member.count', - ms do assert_difference 'MemberRole.count', - rs do User.find(2).destroy end end - + assert_nil User.find_by_id(2) assert Member.find_all_by_user_id(2).empty? end - + def test_destroy_should_update_attachments attachment = Attachment.create!(:container => Project.find(1), :file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2) - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, attachment.reload.author end - + def test_destroy_should_update_comments comment = Comment.create!( :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'), :author => User.find(2), :comments => 'foo' ) - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, comment.reload.author end - + def test_destroy_should_update_issues issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo') - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, issue.reload.author end - + def test_destroy_should_unassign_issues issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2) - + User.find(2).destroy assert_nil User.find_by_id(2) assert_nil issue.reload.assigned_to end - + def test_destroy_should_update_journals issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo') issue.init_journal(User.find(2), "update") issue.save! - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, issue.journals.first.reload.user end - + def test_destroy_should_update_journal_details_old_value issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2) issue.init_journal(User.find(1), "update") @@ -181,12 +196,12 @@ end journal_detail = JournalDetail.first(:order => 'id DESC') assert_equal '2', journal_detail.old_value - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value end - + def test_destroy_should_update_journal_details_value issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo') issue.init_journal(User.find(1), "update") @@ -196,79 +211,79 @@ end journal_detail = JournalDetail.first(:order => 'id DESC') assert_equal '2', journal_detail.value - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous.id.to_s, journal_detail.reload.value end - + def test_destroy_should_update_messages board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board') message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo') - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, message.reload.author end - + def test_destroy_should_update_news news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo') - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, news.reload.author end - + def test_destroy_should_delete_private_queries query = Query.new(:name => 'foo', :is_public => false) query.project_id = 1 query.user_id = 2 query.save! - + User.find(2).destroy assert_nil User.find_by_id(2) assert_nil Query.find_by_id(query.id) end - + def test_destroy_should_update_public_queries query = Query.new(:name => 'foo', :is_public => true) query.project_id = 1 query.user_id = 2 query.save! - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, query.reload.user end - + def test_destroy_should_update_time_entries entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo')) entry.project_id = 1 entry.user_id = 2 entry.save! - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, entry.reload.user end - + def test_destroy_should_delete_tokens token = Token.create!(:user_id => 2, :value => 'foo') - + User.find(2).destroy assert_nil User.find_by_id(2) assert_nil Token.find_by_id(token.id) end - + def test_destroy_should_delete_watchers issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo') watcher = Watcher.create!(:user_id => 2, :watchable => issue) - + User.find(2).destroy assert_nil User.find_by_id(2) assert_nil Watcher.find_by_id(watcher.id) end - + def test_destroy_should_update_wiki_contents wiki_content = WikiContent.create!( :text => 'foo', @@ -279,7 +294,7 @@ assert_difference 'WikiContent::Version.count' do wiki_content.save! end - + User.find(2).destroy assert_nil User.find_by_id(2) assert_equal User.anonymous, wiki_content.reload.author @@ -287,15 +302,15 @@ assert_equal User.anonymous, version.reload.author end end - + def test_destroy_should_nullify_issue_categories category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo') - + User.find(2).destroy assert_nil User.find_by_id(2) assert_nil category.reload.assigned_to_id end - + def test_destroy_should_nullify_changesets changeset = Changeset.create!( :repository => Repository::Subversion.create!( @@ -307,31 +322,31 @@ :committer => 'jsmith' ) assert_equal 2, changeset.user_id - + User.find(2).destroy assert_nil User.find_by_id(2) assert_nil changeset.reload.user_id end - + def test_anonymous_user_should_not_be_destroyable assert_no_difference 'User.count' do assert_equal false, User.anonymous.destroy end end - + def test_validate_login_presence @admin.login = "" assert !@admin.save assert_equal 1, @admin.errors.count end - + def test_validate_mail_notification_inclusion u = User.new u.mail_notification = 'foo' u.save - assert_not_nil u.errors.on(:mail_notification) + assert_not_nil u.errors[:mail_notification] end - + context "User#try_to_login" do should "fall-back to case-insensitive if user login is not found as-typed." do user = User.try_to_login("AdMin", "admin") @@ -340,7 +355,9 @@ end should "select the exact matching user first" do - case_sensitive_user = User.generate_with_protected!(:login => 'changed', :password => 'admin', :password_confirmation => 'admin') + case_sensitive_user = User.generate_with_protected!( + :login => 'changed', :password => 'admin', + :password_confirmation => 'admin') # bypass validations to make it appear like existing data case_sensitive_user.update_attribute(:login, 'ADMIN') @@ -357,12 +374,22 @@ assert_equal "admin", user.login user.password = "hello" assert user.save - + user = User.try_to_login("admin", "hello") assert_kind_of User, user assert_equal "admin", user.login end - + + def test_validate_password_length + with_settings :password_min_length => '100' do + user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo") + user.login = "newuser100" + user.password, user.password_confirmation = "password100", "password100" + assert !user.save + assert_equal 1, user.errors.count + end + end + def test_name_format assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname) Setting.user_format = :firstname_lastname @@ -371,17 +398,41 @@ assert_equal 'jsmith', @jsmith.reload.name end + def test_fields_for_order_statement_should_return_fields_according_user_format_setting + with_settings :user_format => 'lastname_coma_firstname' do + assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement + end + end + + def test_fields_for_order_statement_width_table_name_should_prepend_table_name + with_settings :user_format => 'lastname_firstname' do + assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors') + end + end + + def test_fields_for_order_statement_with_blank_format_should_return_default + with_settings :user_format => '' do + assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement + end + end + + def test_fields_for_order_statement_with_invalid_format_should_return_default + with_settings :user_format => 'foo' do + assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement + end + end + def test_lock user = User.try_to_login("jsmith", "jsmith") assert_equal @jsmith, user - + @jsmith.status = User::STATUS_LOCKED assert @jsmith.save - + user = User.try_to_login("jsmith", "jsmith") - assert_equal nil, user + assert_equal nil, user end - + context ".try_to_login" do context "with good credentials" do should "return the user" do @@ -390,21 +441,21 @@ assert_equal "admin", user.login end end - + context "with wrong credentials" do should "return nil" do assert_nil User.try_to_login("admin", "foo") end end end - + if ldap_configured? context "#try_to_login using LDAP" do context "with failed connection to the LDAP server" do should "return nil" do @auth_source = AuthSourceLdap.find(1) AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect') - + assert_equal nil, User.try_to_login('edavis', 'wrong') end end @@ -414,7 +465,7 @@ assert_equal nil, User.try_to_login('edavis', 'wrong') end end - + context "on the fly registration" do setup do @auth_source = AuthSourceLdap.find(1) @@ -427,12 +478,12 @@ assert !user.admin? end end - + should "retrieve existing user" do user = User.try_to_login('edavis', '123456') user.admin = true user.save! - + assert_no_difference('User.count') do user = User.try_to_login('edavis', '123456') assert user.admin? @@ -445,7 +496,7 @@ else puts "Skipping LDAP tests." end - + def test_create_anonymous AnonymousUser.delete_all anon = User.anonymous @@ -453,18 +504,29 @@ assert_kind_of AnonymousUser, anon end + def test_ensure_single_anonymous_user + AnonymousUser.delete_all + anon1 = User.anonymous + assert !anon1.new_record? + assert_kind_of AnonymousUser, anon1 + anon2 = AnonymousUser.create( + :lastname => 'Anonymous', :firstname => '', + :mail => '', :login => '', :status => 0) + assert_equal 1, anon2.errors.count + end + should_have_one :rss_token def test_rss_key assert_nil @jsmith.rss_token key = @jsmith.rss_key assert_equal 40, key.length - + @jsmith.reload assert_equal key, @jsmith.rss_key end - + should_have_one :api_token context "User#api_key" do @@ -483,7 +545,7 @@ token = Token.generate!(:action => 'api') user.api_token = token assert user.save - + assert_equal token.value, user.api_key end end @@ -507,7 +569,7 @@ token = Token.generate!(:action => 'api') user.api_token = token user.save - + assert_equal user, User.find_by_api_key(token.value) end end @@ -517,11 +579,11 @@ roles = @jsmith.roles_for_project(Project.find(1)) assert_kind_of Role, roles.first assert_equal "Manager", roles.first.name - + # user with no role assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?} end - + def test_projects_by_role_for_user_with_role user = User.find(2) assert_kind_of Hash, user.projects_by_role @@ -529,12 +591,12 @@ assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort end - + def test_projects_by_role_for_user_with_no_role user = User.generate! assert_equal({}, user.projects_by_role) end - + def test_projects_by_role_for_anonymous assert_equal({}, User.anonymous.projects_by_role) end @@ -545,13 +607,13 @@ # with memberships assert_equal 6, User.find(2).valid_notification_options.size end - + def test_valid_notification_options_class_method assert_equal 5, User.valid_notification_options.size assert_equal 5, User.valid_notification_options(User.find(7)).size assert_equal 6, User.valid_notification_options(User.find(2)).size end - + def test_mail_notification_all @jsmith.mail_notification = 'all' @jsmith.notified_project_ids = [] @@ -559,7 +621,7 @@ @jsmith.reload assert @jsmith.projects.first.recipients.include?(@jsmith.mail) end - + def test_mail_notification_selected @jsmith.mail_notification = 'selected' @jsmith.notified_project_ids = [1] @@ -567,7 +629,7 @@ @jsmith.reload assert Project.find(1).recipients.include?(@jsmith.mail) end - + def test_mail_notification_only_my_events @jsmith.mail_notification = 'only_my_events' @jsmith.notified_project_ids = [] @@ -575,7 +637,7 @@ @jsmith.reload assert !@jsmith.projects.first.recipients.include?(@jsmith.mail) end - + def test_comments_sorting_preference assert !@jsmith.wants_comments_in_reverse_order? @jsmith.pref.comments_sorting = 'asc' @@ -583,13 +645,13 @@ @jsmith.pref.comments_sorting = 'desc' assert @jsmith.wants_comments_in_reverse_order? end - + def test_find_by_mail_should_be_case_insensitive u = User.find_by_mail('JSmith@somenet.foo') assert_not_nil u assert_equal 'jsmith@somenet.foo', u.mail end - + def test_random_password u = User.new u.random_password @@ -605,7 +667,7 @@ should "delegate to the auth source" do user = User.generate_with_protected! - + allowed_auth_source = AuthSource.generate! def allowed_auth_source.allow_password_changes?; true; end @@ -622,7 +684,7 @@ end end - + context "#allowed_to?" do context "with a unique project" do should "return false if project is archived" do @@ -630,14 +692,14 @@ Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED) assert ! @admin.allowed_to?(:view_issues, Project.find(1)) end - + should "return false if related module is disabled" do project = Project.find(1) project.enabled_module_names = ["issue_tracking"] assert @admin.allowed_to?(:add_issues, project) assert ! @admin.allowed_to?(:view_wiki_pages, project) end - + should "authorize nearly everything for admin users" do project = Project.find(1) assert ! @admin.member_of?(project) @@ -645,7 +707,7 @@ assert @admin.allowed_to?(p.to_sym, project) end end - + should "authorize normal users depending on their roles" do project = Project.find(1) assert @jsmith.allowed_to?(:delete_messages, project) #Manager @@ -657,19 +719,19 @@ should "return false if array is empty" do assert ! @admin.allowed_to?(:view_project, []) end - + should "return true only if user has permission on all these projects" do assert @admin.allowed_to?(:view_project, Project.all) assert ! @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2) assert @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere assert ! @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers end - + should "behave correctly with arrays of 1 project" do assert ! User.anonymous.allowed_to?(:delete_issues, [Project.first]) end end - + context "with options[:global]" do should "authorize if user has at least one role that has this permission" do @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere @@ -682,7 +744,7 @@ end end end - + context "User#notify_about?" do context "Issues" do setup do @@ -696,58 +758,58 @@ @author.update_attribute(:mail_notification, 'all') assert @author.notify_about?(@issue) end - + should "be false for a user with :none" do @author.update_attribute(:mail_notification, 'none') assert ! @author.notify_about?(@issue) end - + should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do @user = User.generate_with_protected!(:mail_notification => 'only_my_events') Member.create!(:user => @user, :project => @project, :role_ids => [1]) assert ! @user.notify_about?(@issue) end - + should "be true for a user with :only_my_events and is the author" do @author.update_attribute(:mail_notification, 'only_my_events') assert @author.notify_about?(@issue) end - + should "be true for a user with :only_my_events and is the assignee" do @assignee.update_attribute(:mail_notification, 'only_my_events') assert @assignee.notify_about?(@issue) end - + should "be true for a user with :only_assigned and is the assignee" do @assignee.update_attribute(:mail_notification, 'only_assigned') assert @assignee.notify_about?(@issue) end - + should "be false for a user with :only_assigned and is not the assignee" do @author.update_attribute(:mail_notification, 'only_assigned') assert ! @author.notify_about?(@issue) end - + should "be true for a user with :only_owner and is the author" do @author.update_attribute(:mail_notification, 'only_owner') assert @author.notify_about?(@issue) end - + should "be false for a user with :only_owner and is not the author" do @assignee.update_attribute(:mail_notification, 'only_owner') assert ! @assignee.notify_about?(@issue) end - + should "be true for a user with :selected and is the author" do @author.update_attribute(:mail_notification, 'selected') assert @author.notify_about?(@issue) end - + should "be true for a user with :selected and is the assignee" do @assignee.update_attribute(:mail_notification, 'selected') assert @assignee.notify_about?(@issue) end - + should "be false for a user with :selected and is not the author or assignee" do @user = User.generate_with_protected!(:mail_notification => 'selected') Member.create!(:user => @user, :project => @project, :role_ids => [1]) @@ -766,9 +828,9 @@ user.salt = nil user.hashed_password = User.hash_password("unsalted") user.save! - + User.salt_unsalted_passwords! - + user.reload # Salt added assert !user.salt.blank? @@ -776,9 +838,9 @@ assert user.check_password?("unsalted") assert_equal user, User.try_to_login(user.login, "unsalted") end - + if Object.const_defined?(:OpenID) - + def test_setting_identity_url normalized_open_id_url = 'http://example.com/' u = User.new( :identity_url => 'http://example.com/' ) @@ -796,18 +858,18 @@ u = User.new( :identity_url => 'example.com' ) assert_equal normalized_open_id_url, u.identity_url end - + def test_setting_blank_identity_url u = User.new( :identity_url => 'example.com' ) u.identity_url = '' assert u.identity_url.blank? end - + def test_setting_invalid_identity_url u = User.new( :identity_url => 'this is not an openid url' ) assert u.identity_url.blank? end - + else puts "Skipping openid tests." end diff -r 487d96eac004 -r 5e80956cc792 test/unit/version_test.rb --- a/test/unit/version_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/version_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -22,26 +22,27 @@ def setup end - + def test_create v = Version.new(:project => Project.find(1), :name => '1.1', :effective_date => '2011-03-25') assert v.save assert_equal 'open', v.status + assert_equal 'none', v.sharing end - + def test_invalid_effective_date_validation v = Version.new(:project => Project.find(1), :name => '1.1', :effective_date => '99999-01-01') assert !v.save assert_equal I18n.translate('activerecord.errors.messages.not_a_date'), v.errors.on(:effective_date) end - + def test_progress_should_be_0_with_no_assigned_issues project = Project.find(1) v = Version.create!(:project => project, :name => 'Progress') assert_equal 0, v.completed_pourcent assert_equal 0, v.closed_pourcent end - + def test_progress_should_be_0_with_unbegun_assigned_issues project = Project.find(1) v = Version.create!(:project => project, :name => 'Progress') @@ -50,7 +51,7 @@ assert_progress_equal 0, v.completed_pourcent assert_progress_equal 0, v.closed_pourcent end - + def test_progress_should_be_100_with_closed_assigned_issues project = Project.find(1) status = IssueStatus.find(:first, :conditions => {:is_closed => true}) @@ -62,7 +63,7 @@ assert_progress_equal 100.0, v.completed_pourcent assert_progress_equal 100.0, v.closed_pourcent end - + def test_progress_should_consider_done_ratio_of_open_assigned_issues project = Project.find(1) v = Version.create!(:project => project, :name => 'Progress') @@ -72,7 +73,7 @@ assert_progress_equal (0.0 + 20.0 + 70.0)/3, v.completed_pourcent assert_progress_equal 0, v.closed_pourcent end - + def test_progress_should_consider_closed_issues_as_completed project = Project.find(1) v = Version.create!(:project => project, :name => 'Progress') @@ -82,7 +83,7 @@ assert_progress_equal (0.0 + 20.0 + 100.0)/3, v.completed_pourcent assert_progress_equal (100.0)/3, v.closed_pourcent end - + def test_progress_should_consider_estimated_hours_to_weigth_issues project = Project.find(1) v = Version.create!(:project => project, :name => 'Progress') @@ -93,7 +94,7 @@ assert_progress_equal (10.0*0 + 20.0*0.3 + 40*0.1 + 25.0*1)/95.0*100, v.completed_pourcent assert_progress_equal 25.0/95.0*100, v.closed_pourcent end - + def test_progress_should_consider_average_estimated_hours_to_weigth_unestimated_issues project = Project.find(1) v = Version.create!(:project => project, :name => 'Progress') @@ -113,7 +114,7 @@ @version = Version.generate!(:project => @project, :effective_date => nil) end - + should "be false if there are no issues assigned" do @version.update_attribute(:effective_date, Date.yesterday) assert_equal false, @version.behind_schedule? @@ -159,22 +160,22 @@ setup do @version = Version.create!(:project_id => 1, :name => '#estimated_hours') end - + should "return 0 with no assigned issues" do assert_equal 0, @version.estimated_hours end - + should "return 0 with no estimated hours" do add_issue(@version) assert_equal 0, @version.estimated_hours end - + should "return the sum of estimated hours" do add_issue(@version, :estimated_hours => 2.5) add_issue(@version, :estimated_hours => 5) assert_equal 7.5, @version.estimated_hours end - + should "return the sum of leaves estimated hours" do parent = add_issue(@version) add_issue(@version, :estimated_hours => 2.5, :parent_issue_id => parent.id) @@ -185,17 +186,17 @@ test "should update all issue's fixed_version associations in case the hierarchy changed XXX" do User.current = User.find(1) # Need the admin's permissions - + @version = Version.find(7) # Separate hierarchy project_1_issue = Issue.find(1) project_1_issue.fixed_version = @version assert project_1_issue.save, project_1_issue.errors.full_messages.to_s - + project_5_issue = Issue.find(6) project_5_issue.fixed_version = @version assert project_5_issue.save - + # Project project_2_issue = Issue.find(4) project_2_issue.fixed_version = @version @@ -208,7 +209,7 @@ # Project 1 now out of the shared scope project_1_issue.reload assert_equal nil, project_1_issue.fixed_version, "Fixed version is still set after changing the Version's sharing" - + # Project 5 now out of the shared scope project_5_issue.reload assert_equal nil, project_5_issue.fixed_version, "Fixed version is still set after changing the Version's sharing" @@ -217,9 +218,9 @@ project_2_issue.reload assert_equal @version, project_2_issue.fixed_version end - + private - + def add_issue(version, attributes={}) Issue.create!({:project => version.project, :fixed_version => version, @@ -227,7 +228,7 @@ :author => User.find(:first), :tracker => version.project.trackers.find(:first)}.merge(attributes)) end - + def assert_progress_equal(expected_float, actual_float, message="") assert_in_delta(expected_float, actual_float, 0.000001, message="") end diff -r 487d96eac004 -r 5e80956cc792 test/unit/watcher_test.rb --- a/test/unit/watcher_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/watcher_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 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. @@ -28,67 +28,67 @@ @user = User.find(1) @issue = Issue.find(1) end - + def test_watch assert @issue.add_watcher(@user) @issue.reload assert @issue.watchers.detect { |w| w.user == @user } end - + def test_cant_watch_twice assert @issue.add_watcher(@user) assert !@issue.add_watcher(@user) end - + def test_watched_by assert @issue.add_watcher(@user) @issue.reload assert @issue.watched_by?(@user) assert Issue.watched_by(@user).include?(@issue) end - + def test_watcher_users watcher_users = Issue.find(2).watcher_users assert_kind_of Array, watcher_users assert_kind_of User, watcher_users.first end - + def test_watcher_users_should_not_validate_user User.update_all("firstname = ''", "id=1") @user.reload assert !@user.valid? - + issue = Issue.new(:project => Project.find(1), :tracker_id => 1, :subject => "test", :author => User.find(2)) issue.watcher_users << @user issue.save! assert issue.watched_by?(@user) end - + def test_watcher_user_ids assert_equal [1, 3], Issue.find(2).watcher_user_ids.sort end - + def test_watcher_user_ids= issue = Issue.new issue.watcher_user_ids = ['1', '3'] assert issue.watched_by?(User.find(1)) end - + def test_addable_watcher_users addable_watcher_users = @issue.addable_watcher_users assert_kind_of Array, addable_watcher_users assert_kind_of User, addable_watcher_users.first end - + def test_addable_watcher_users_should_not_include_user_that_cannot_view_the_object issue = Issue.new(:project => Project.find(1), :is_private => true) assert_nil issue.addable_watcher_users.detect {|user| !issue.visible?(user)} end - + def test_recipients @issue.watchers.delete_all @issue.reload - + assert @issue.watcher_recipients.empty? assert @issue.add_watcher(@user) @@ -102,41 +102,41 @@ @issue.reload assert !@issue.watcher_recipients.include?(@user.mail) end - + def test_unwatch assert @issue.add_watcher(@user) @issue.reload - assert_equal 1, @issue.remove_watcher(@user) + assert_equal 1, @issue.remove_watcher(@user) end - + def test_prune Watcher.delete_all("user_id = 9") user = User.find(9) - + # public Watcher.create!(:watchable => Issue.find(1), :user => user) Watcher.create!(:watchable => Issue.find(2), :user => user) Watcher.create!(:watchable => Message.find(1), :user => user) Watcher.create!(:watchable => Wiki.find(1), :user => user) Watcher.create!(:watchable => WikiPage.find(2), :user => user) - + # private project (id: 2) Member.create!(:project => Project.find(2), :principal => user, :role_ids => [1]) Watcher.create!(:watchable => Issue.find(4), :user => user) Watcher.create!(:watchable => Message.find(7), :user => user) Watcher.create!(:watchable => Wiki.find(2), :user => user) Watcher.create!(:watchable => WikiPage.find(3), :user => user) - + assert_no_difference 'Watcher.count' do Watcher.prune(:user => User.find(9)) end - + Member.delete_all - + assert_difference 'Watcher.count', -4 do Watcher.prune(:user => User.find(9)) end - + assert Issue.find(1).watched_by?(user) assert !Issue.find(4).watched_by?(user) end diff -r 487d96eac004 -r 5e80956cc792 test/unit/wiki_content_test.rb --- a/test/unit/wiki_content_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/wiki_content_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -85,4 +85,11 @@ page.reload assert_equal 500.kilobyte, page.content.text.size end + + def test_current_version + content = WikiContent.find(11) + assert_equal true, content.current_version? + assert_equal true, content.versions.first(:order => 'version DESC').current_version? + assert_equal false, content.versions.first(:order => 'version ASC').current_version? + end end diff -r 487d96eac004 -r 5e80956cc792 test/unit/wiki_redirect_test.rb --- a/test/unit/wiki_redirect_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/wiki_redirect_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -1,16 +1,16 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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. @@ -24,28 +24,28 @@ @wiki = Wiki.find(1) @original = WikiPage.create(:wiki => @wiki, :title => 'Original title') end - + def test_create_redirect @original.title = 'New title' assert @original.save @original.reload - + assert_equal 'New_title', @original.title assert @wiki.redirects.find_by_title('Original_title') assert @wiki.find_page('Original title') assert @wiki.find_page('ORIGINAL title') end - + def test_update_redirect # create a redirect that point to this page assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title') - + @original.title = 'New title' @original.save # make sure the old page now points to the new page assert_equal 'New_title', @wiki.find_page('An old page').title end - + def test_reverse_rename # create a redirect that point to this page assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title') @@ -55,7 +55,7 @@ assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'An_old_page') assert @wiki.redirects.find_by_title_and_redirects_to('Original_title', 'An_old_page') end - + def test_rename_to_already_redirected assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Other_page') @@ -64,10 +64,10 @@ # this redirect have to be removed since 'An old page' page now exists assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'Other_page') end - + def test_redirects_removed_when_deleting_page assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title') - + @original.destroy assert !@wiki.redirects.find(:first) end diff -r 487d96eac004 -r 5e80956cc792 test/unit/workflow_test.rb --- a/test/unit/workflow_test.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/test/unit/workflow_test.rb Mon Feb 27 13:53:18 2012 +0000 @@ -25,11 +25,11 @@ Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :new_status_id => 2) Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :new_status_id => 3, :assignee => true) Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :new_status_id => 4, :author => true) - + assert_difference 'Workflow.count', 3 do Workflow.copy(Tracker.find(2), Role.find(1), Tracker.find(3), Role.find(2)) end - + assert Workflow.first(:conditions => {:role_id => 2, :tracker_id => 3, :old_status_id => 1, :new_status_id => 2, :author => false, :assignee => false}) assert Workflow.first(:conditions => {:role_id => 2, :tracker_id => 3, :old_status_id => 1, :new_status_id => 3, :author => false, :assignee => true}) assert Workflow.first(:conditions => {:role_id => 2, :tracker_id => 3, :old_status_id => 1, :new_status_id => 4, :author => true, :assignee => false}) diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/.specification --- a/vendor/gems/coderay-0.9.7/.specification Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ ---- !ruby/object:Gem::Specification -name: coderay -version: !ruby/object:Gem::Version - hash: 53 - prerelease: false - segments: - - 0 - - 9 - - 7 - version: 0.9.7 -platform: ruby -authors: -- murphy -autorequire: -bindir: bin -cert_chain: [] - -date: 2011-01-15 00:00:00 +01:00 -default_executable: -dependencies: [] - -description: | - Fast and easy syntax highlighting for selected languages, written in Ruby. - Comes with RedCloth integration and LOC counter. - -email: murphy@rubychan.de -executables: -- coderay -- coderay_stylesheet -extensions: [] - -extra_rdoc_files: -- lib/README -- FOLDERS -files: -- ./lib/coderay/duo.rb -- ./lib/coderay/encoder.rb -- ./lib/coderay/encoders/_map.rb -- ./lib/coderay/encoders/comment_filter.rb -- ./lib/coderay/encoders/count.rb -- ./lib/coderay/encoders/debug.rb -- ./lib/coderay/encoders/div.rb -- ./lib/coderay/encoders/filter.rb -- ./lib/coderay/encoders/html/css.rb -- ./lib/coderay/encoders/html/numerization.rb -- ./lib/coderay/encoders/html/output.rb -- ./lib/coderay/encoders/html.rb -- ./lib/coderay/encoders/json.rb -- ./lib/coderay/encoders/lines_of_code.rb -- ./lib/coderay/encoders/null.rb -- ./lib/coderay/encoders/page.rb -- ./lib/coderay/encoders/span.rb -- ./lib/coderay/encoders/statistic.rb -- ./lib/coderay/encoders/term.rb -- ./lib/coderay/encoders/text.rb -- ./lib/coderay/encoders/token_class_filter.rb -- ./lib/coderay/encoders/xml.rb -- ./lib/coderay/encoders/yaml.rb -- ./lib/coderay/for_redcloth.rb -- ./lib/coderay/helpers/file_type.rb -- ./lib/coderay/helpers/gzip_simple.rb -- ./lib/coderay/helpers/plugin.rb -- ./lib/coderay/helpers/word_list.rb -- ./lib/coderay/scanner.rb -- ./lib/coderay/scanners/_map.rb -- ./lib/coderay/scanners/c.rb -- ./lib/coderay/scanners/cpp.rb -- ./lib/coderay/scanners/css.rb -- ./lib/coderay/scanners/debug.rb -- ./lib/coderay/scanners/delphi.rb -- ./lib/coderay/scanners/diff.rb -- ./lib/coderay/scanners/groovy.rb -- ./lib/coderay/scanners/html.rb -- ./lib/coderay/scanners/java/builtin_types.rb -- ./lib/coderay/scanners/java.rb -- ./lib/coderay/scanners/java_script-0.9.6.rb -- ./lib/coderay/scanners/java_script.rb -- ./lib/coderay/scanners/json.rb -- ./lib/coderay/scanners/nitro_xhtml.rb -- ./lib/coderay/scanners/php.rb -- ./lib/coderay/scanners/plaintext.rb -- ./lib/coderay/scanners/python.rb -- ./lib/coderay/scanners/rhtml.rb -- ./lib/coderay/scanners/ruby/patterns.rb -- ./lib/coderay/scanners/ruby.rb -- ./lib/coderay/scanners/scheme.rb -- ./lib/coderay/scanners/sql.rb -- ./lib/coderay/scanners/xml.rb -- ./lib/coderay/scanners/yaml.rb -- ./lib/coderay/style.rb -- ./lib/coderay/styles/_map.rb -- ./lib/coderay/styles/cycnus.rb -- ./lib/coderay/styles/murphy.rb -- ./lib/coderay/token_classes.rb -- ./lib/coderay/tokens.rb -- ./lib/coderay.rb -- ./Rakefile -- ./test/functional/basic.rb -- ./test/functional/basic.rbc -- ./test/functional/for_redcloth.rb -- ./test/functional/for_redcloth.rbc -- ./test/functional/load_plugin_scanner.rb -- ./test/functional/load_plugin_scanner.rbc -- ./test/functional/suite.rb -- ./test/functional/suite.rbc -- ./test/functional/vhdl.rb -- ./test/functional/vhdl.rbc -- ./test/functional/word_list.rb -- ./test/functional/word_list.rbc -- ./lib/README -- ./LICENSE -- lib/README -- FOLDERS -- bin/coderay -- bin/coderay_stylesheet -has_rdoc: true -homepage: http://coderay.rubychan.de -licenses: [] - -post_install_message: -rdoc_options: -- -SNw2 -- -mlib/README -- -t CodeRay Documentation -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 51 - segments: - - 1 - - 8 - - 2 - version: 1.8.2 -required_rubygems_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" -requirements: [] - -rubyforge_project: coderay -rubygems_version: 1.3.7 -signing_key: -specification_version: 3 -summary: Fast syntax highlighting for selected languages. -test_files: -- ./test/functional/suite.rb diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/FOLDERS --- a/vendor/gems/coderay-0.9.7/FOLDERS Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -= CodeRay - Trunk folder structure - -== bench - Benchmarking system - -All benchmarking stuff goes here. - -Test inputs are stored in files named example.. -Test outputs go to bench/test.. - -Run bench/bench.rb to get a usage description. - -Run rake bench to perform an example benchmark. - - -== bin - Scripts - -Executional files for CodeRay. - - -== demo - Demos and functional tests - -Demonstrational scripts to show of CodeRay's features. - -Run them as functional tests with rake test:demos. - - -== etc - Lots of stuff - -Some addidtional files for CodeRay, mainly graphics and Vim scripts. - - -== gem_server - Gem output folder - -For rake gem. - - -== lib - CodeRay library code - -This is the base directory for the CodeRay library. - - -== rake_helpers - Rake helper libraries - -Some files to enhance Rake, including the Autumnal Rdoc template and some scripts. - - -== test - Tests - -Tests for the scanners. - -Each language has its own subfolder and sub-suite. - -Run with rake test. diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/LICENSE --- a/vendor/gems/coderay-0.9.7/LICENSE Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 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. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -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 and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, 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 library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete 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 distribute a copy of this License along with the -Library. - - 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 Library or any portion -of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -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 Library, 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 Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you 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. - - If distribution of 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 satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be 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. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library 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. - - 9. 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 Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -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 with -this License. - - 11. 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 Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library 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 Library. - -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. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library 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. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser 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 Library -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 Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -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 - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. 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 LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. 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. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; 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. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/Rakefile --- a/vendor/gems/coderay-0.9.7/Rakefile Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -require 'rake/rdoctask' - -ROOT = '.' -LIB_ROOT = File.join ROOT, 'lib' -EXTRA_RDOC_FILES = %w(lib/README FOLDERS) - -task :default => :test - -if File.directory? 'rake_tasks' - - # load rake tasks from subfolder - for task_file in Dir['rake_tasks/*.rake'].sort - load task_file - end - -else - - # fallback tasks when rake_tasks folder is not present - desc 'Run CodeRay tests (basic)' - task :test do - ruby './test/functional/suite.rb' - ruby './test/functional/for_redcloth.rb' - end - - desc 'Generate documentation for CodeRay' - Rake::RDocTask.new :doc do |rd| - rd.title = 'CodeRay Documentation' - rd.main = 'lib/README' - rd.rdoc_files.add Dir['lib'] - rd.rdoc_files.add 'lib/README' - rd.rdoc_files.add 'FOLDERS' - rd.rdoc_dir = 'doc' - end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/bin/coderay --- a/vendor/gems/coderay-0.9.7/bin/coderay Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -#!/usr/bin/env ruby -# CodeRay Executable -# -# Version: 0.2 -# Author: murphy - -require 'coderay' - -if ARGV.empty? - $stderr.puts <<-USAGE -CodeRay #{CodeRay::VERSION} (http://coderay.rubychan.de) - -Usage: - coderay file [-] - coderay - [-] [< file] [> output] - -Defaults: - lang: based on file extension - format: ANSI colorized output for terminal, HTML page for files - -Examples: - coderay foo.rb # colorized output to terminal, based on file extension - coderay foo.rb -loc # print LOC count, based on file extension and format - coderay foo.rb > foo.html # HTML page output to file, based on extension - coderay -ruby < foo.rb # colorized output to terminal, based on lang - coderay -ruby -loc < foo.rb # print LOC count, based on lang - coderay -ruby -page foo.rb # HTML page output to terminal, based on lang and format - coderay -ruby -page foo.rb > foo.html # HTML page output to file, based on lang and format - USAGE -end - -first, second = ARGV - -def read - file = ARGV.grep(/^(?!-)/).last - if file - if File.exist?(file) - File.read file - else - $stderr.puts "No such file: #{file}" - end - else - $stdin.read - end -end - -if first - if first[/-(\w+)/] == first - lang = $1 - input = read - tokens = :scan - else - file = first - unless File.exist? file - $stderr.puts "No such file: #{file}" - exit 2 - end - tokens = CodeRay.scan_file file - end -else - $stderr.puts 'No lang/file given.' - exit 1 -end - -if second - if second[/-(\w+)/] == second - format = $1.to_sym - else - raise 'invalid format (must be -xxx)' - end -else - if $stdout.tty? - format = :term - else - $stderr.puts 'No format given; setting to default (HTML Page).' - format = :page - end -end - -if tokens == :scan - output = CodeRay::Duo[lang => format].highlight input -else - output = tokens.encode format -end -out = $stdout -out.puts output diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/bin/coderay_stylesheet --- a/vendor/gems/coderay-0.9.7/bin/coderay_stylesheet Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -#!/usr/bin/env ruby -require 'coderay' - -puts CodeRay::Encoders[:html]::CSS.new.stylesheet diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/README --- a/vendor/gems/coderay-0.9.7/lib/README Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -= CodeRay - -[- Tired of blue'n'gray? Try the original version of this documentation on -coderay.rubychan.de[http://coderay.rubychan.de/doc/] (use Ctrl+Click to open it in its own frame.) -] - -== About -CodeRay is a Ruby library for syntax highlighting. - -Syntax highlighting means: You put your code in, and you get it back colored; -Keywords, strings, floats, comments - all in different colors. -And with line numbers. - -*Syntax* *Highlighting*... -* makes code easier to read and maintain -* lets you detect syntax errors faster -* helps you to understand the syntax of a language -* looks nice -* is what everybody should have on their website -* solves all your problems and makes the girls run after you - -Version: 0.9.7 -Author:: murphy (Kornelius Kalnbach) -Contact:: murphy rubychan de -Website:: coderay.rubychan.de[http://coderay.rubychan.de] -License:: GNU LGPL; see LICENSE file in the main directory. - -== Installation - -You need RubyGems[http://rubyforge.org/frs/?group_id=126]. - - % gem install coderay - - -=== Dependencies - -CodeRay needs Ruby 1.8.6 or later. It also runs with Ruby 1.9.1+ and JRuby 1.1+. - - -== Example Usage -(Forgive me, but this is not highlighted.) - - require 'coderay' - - tokens = CodeRay.scan "puts 'Hello, world!'", :ruby - page = tokens.html :line_numbers => :inline, :wrap => :page - puts page - - -== Documentation - -See CodeRay. - -Please report errors in this documentation to . - - -== Credits - -=== Special Thanks to - -* licenser (Heinz N. Gies) for ending my QBasic career, inventing the Coder - project and the input/output plugin system. - CodeRay would not exist without him. -* bovi (Daniel Bovensiepen) for helping me out on various occasions. - -=== Thanks to - -* Caleb Clausen for writing RubyLexer (see - http://rubyforge.org/projects/rubylexer) and lots of very interesting mail - traffic -* birkenfeld (Georg Brandl) and mitsuhiku (Arnim Ronacher) for PyKleur, now pygments. - You guys rock! -* Jamis Buck for writing Syntax (see http://rubyforge.org/projects/syntax) - I got some useful ideas from it. -* Doug Kearns and everyone else who worked on ruby.vim - it not only helped me - coding CodeRay, but also gave me a wonderful target to reach for the Ruby - scanner. -* everyone who uses CodeBB on http://www.rubyforen.de and http://www.python-forum.de -* iGEL, magichisoka, manveru, WoNáDo and everyone I forgot from rubyforen.de -* Dethix from ruby-mine.de -* zickzackw -* Dookie (who is no longer with us...) and Leonidas from http://www.python-forum.de -* Andreas Schwarz for finding out that CaseIgnoringWordList was not case - ignoring! Such things really make you write tests. -* closure for the first version of the Scheme scanner. -* Stefan Walk for the first version of the JavaScript and PHP scanners. -* Josh Goebel for another version of the JavaScript scanner, a SQL and a Diff scanner. -* Jonathan Younger for pointing out the licence confusion caused by wrong LICENSE file. -* Jeremy Hinegardner for finding the shebang-on-empty-file bug in FileType. -* Charles Oliver Nutter and Yehuda Katz for helping me benchmark CodeRay on JRuby. -* Andreas Neuhaus for pointing out a markup bug in coderay/for_redcloth. -* 0xf30fc7 for the FileType patch concerning Delphi file extensions. -* The folks at redmine.org - thank you for using and fixing CodeRay! -* Keith Pitt for his SQL scanners -* Rob Aldred for the terminal encoder -* Trans for pointing out $DEBUG dependencies -* Flameeyes for finding that Term::ANSIColor was obsolete -* Etienne Massip for reporting a serious bug in JavaScript scanner -* matz and all Ruby gods and gurus -* The inventors of: the computer, the internet, the true color display, HTML & - CSS, VIM, Ruby, pizza, microwaves, guitars, scouting, programming, anime, - manga, coke and green ice tea. - -Where would we be without all those people? - -=== Created using - -* Ruby[http://ruby-lang.org/] -* Chihiro (my Sony VAIO laptop); Henrietta (my old MacBook); - Triella, born Rico (my new MacBook); as well as - Seras and Hikari (my PCs) -* RDE[http://homepage2.nifty.com/sakazuki/rde_e.html], - VIM[http://vim.org] and TextMate[http://macromates.com] -* Subversion[http://subversion.tigris.org/] -* Redmine[http://redmine.org/] -* Firefox[http://www.mozilla.org/products/firefox/], - Firebug[http://getfirebug.com/], Safari[http://www.apple.com/safari/], and - Thunderbird[http://www.mozilla.org/products/thunderbird/] -* RubyGems[http://docs.rubygems.org/] and Rake[http://rake.rubyforge.org/] -* TortoiseSVN[http://tortoisesvn.tigris.org/] using Apache via - XAMPP[http://www.apachefriends.org/en/xampp.html] -* RDoc (though I'm quite unsatisfied with it) -* Microsoft Windows (yes, I confess!) and MacOS X -* GNUWin32, MinGW and some other tools to make the shell under windows a bit - less useless -* Term::ANSIColor[http://term-ansicolor.rubyforge.org/] -* PLEAC[http://pleac.sourceforge.net/] code examples - -=== Free - -* As you can see, CodeRay was created under heavy use of *free* software. -* So CodeRay is also *free*. -* If you use CodeRay to create software, think about making this software - *free*, too. -* Thanks :) diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,322 +0,0 @@ -# = CodeRay Library -# -# CodeRay is a Ruby library for syntax highlighting. -# -# I try to make CodeRay easy to use and intuitive, but at the same time fully featured, complete, -# fast and efficient. -# -# See README. -# -# It consists mainly of -# * the main engine: CodeRay (Scanners::Scanner, Tokens/TokenStream, Encoders::Encoder), PluginHost -# * the scanners in CodeRay::Scanners -# * the encoders in CodeRay::Encoders -# -# Here's a fancy graphic to light up this gray docu: -# -# http://cycnus.de/raindark/coderay/scheme.png -# -# == Documentation -# -# See CodeRay, Encoders, Scanners, Tokens. -# -# == Usage -# -# Remember you need RubyGems to use CodeRay, unless you have it in your load path. Run Ruby with -# -rubygems option if required. -# -# === Highlight Ruby code in a string as html -# -# require 'coderay' -# print CodeRay.scan('puts "Hello, world!"', :ruby).html -# -# # prints something like this: -# puts "Hello, world!" -# -# -# === Highlight C code from a file in a html div -# -# require 'coderay' -# print CodeRay.scan(File.read('ruby.h'), :c).div -# print CodeRay.scan_file('ruby.h').html.div -# -# You can include this div in your page. The used CSS styles can be printed with -# -# % coderay_stylesheet -# -# === Highlight without typing too much -# -# If you are one of the hasty (or lazy, or extremely curious) people, just run this file: -# -# % ruby -rubygems /path/to/coderay/coderay.rb > example.html -# -# and look at the file it created in your browser. -# -# = CodeRay Module -# -# The CodeRay module provides convenience methods for the engine. -# -# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are -# simply lower-case symbols, like :python or :html. -# * All methods take an optional hash as last parameter, +options+, that is send to -# the Encoder / Scanner. -# * Input and language are always sorted in this order: +code+, +lang+. -# (This is in alphabetical order, if you need a mnemonic ;) -# -# You should be able to highlight everything you want just using these methods; -# so there is no need to dive into CodeRay's deep class hierarchy. -# -# The examples in the demo directory demonstrate common cases using this interface. -# -# = Basic Access Ways -# -# Read this to get a general view what CodeRay provides. -# -# == Scanning -# -# Scanning means analysing an input string, splitting it up into Tokens. -# Each Token knows about what type it is: string, comment, class name, etc. -# -# Each +lang+ (language) has its own Scanner; for example, :ruby code is -# handled by CodeRay::Scanners::Ruby. -# -# CodeRay.scan:: Scan a string in a given language into Tokens. -# This is the most common method to use. -# CodeRay.scan_file:: Scan a file and guess the language using FileType. -# -# The Tokens object you get from these methods can encode itself; see Tokens. -# -# == Encoding -# -# Encoding means compiling Tokens into an output. This can be colored HTML or -# LaTeX, a textual statistic or just the number of non-whitespace tokens. -# -# Each Encoder provides output in a specific +format+, so you select Encoders via -# formats like :html or :statistic. -# -# CodeRay.encode:: Scan and encode a string in a given language. -# CodeRay.encode_tokens:: Encode the given tokens. -# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it. -# -# == Streaming -# -# Streaming saves RAM by running Scanner and Encoder in some sort of -# pipe mode; see TokenStream. -# -# CodeRay.scan_stream:: Scan in stream mode. -# -# == All-in-One Encoding -# -# CodeRay.encode:: Highlight a string with a given input and output format. -# -# == Instanciating -# -# You can use an Encoder instance to highlight multiple inputs. This way, the setup -# for this Encoder must only be done once. -# -# CodeRay.encoder:: Create an Encoder instance with format and options. -# CodeRay.scanner:: Create an Scanner instance for lang, with '' as default code. -# -# To make use of CodeRay.scanner, use CodeRay::Scanner::code=. -# -# The scanning methods provide more flexibility; we recommend to use these. -# -# == Reusing Scanners and Encoders -# -# If you want to re-use scanners and encoders (because that is faster), see -# CodeRay::Duo for the most convenient (and recommended) interface. -module CodeRay - - $CODERAY_DEBUG ||= false - - # Version: Major.Minor.Teeny[.Revision] - # Major: 0 for pre-stable, 1 for stable - # Minor: feature milestone - # Teeny: development state, 0 for pre-release - # Revision: Subversion Revision number (generated on rake gem:make) - VERSION = '0.9.7' - - require 'coderay/tokens' - require 'coderay/token_classes' - require 'coderay/scanner' - require 'coderay/encoder' - require 'coderay/duo' - require 'coderay/style' - - - class << self - - # Scans the given +code+ (a String) with the Scanner for +lang+. - # - # This is a simple way to use CodeRay. Example: - # require 'coderay' - # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html - # - # See also demo/demo_simple. - def scan code, lang, options = {}, &block - scanner = Scanners[lang].new code, options, &block - scanner.tokenize - end - - # Scans +filename+ (a path to a code file) with the Scanner for +lang+. - # - # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to - # determine it. If it cannot find out what type it is, it uses - # CodeRay::Scanners::Plaintext. - # - # Calls CodeRay.scan. - # - # Example: - # require 'coderay' - # page = CodeRay.scan_file('some_c_code.c').html - def scan_file filename, lang = :auto, options = {}, &block - file = IO.read filename - if lang == :auto - require 'coderay/helpers/file_type' - lang = FileType.fetch filename, :plaintext, true - end - scan file, lang, options = {}, &block - end - - # Scan the +code+ (a string) with the scanner for +lang+. - # - # Calls scan. - # - # See CodeRay.scan. - def scan_stream code, lang, options = {}, &block - options[:stream] = true - scan code, lang, options, &block - end - - # Encode a string in Streaming mode. - # - # This starts scanning +code+ with the the Scanner for +lang+ - # while encodes the output with the Encoder for +format+. - # +options+ will be passed to the Encoder. - # - # See CodeRay::Encoder.encode_stream - def encode_stream code, lang, format, options = {} - encoder(format, options).encode_stream code, lang, options - end - - # Encode a string. - # - # This scans +code+ with the the Scanner for +lang+ and then - # encodes it with the Encoder for +format+. - # +options+ will be passed to the Encoder. - # - # See CodeRay::Encoder.encode - def encode code, lang, format, options = {} - encoder(format, options).encode code, lang, options - end - - # Highlight a string into a HTML
    . - # - # CSS styles use classes, so you have to include a stylesheet - # in your output. - # - # See encode. - def highlight code, lang, options = { :css => :class }, format = :div - encode code, lang, format, options - end - - # Encode pre-scanned Tokens. - # Use this together with CodeRay.scan: - # - # require 'coderay' - # - # # Highlight a short Ruby code example in a HTML span - # tokens = CodeRay.scan '1 + 2', :ruby - # puts CodeRay.encode_tokens(tokens, :span) - # - def encode_tokens tokens, format, options = {} - encoder(format, options).encode_tokens tokens, options - end - - # Encodes +filename+ (a path to a code file) with the Scanner for +lang+. - # - # See CodeRay.scan_file. - # Notice that the second argument is the output +format+, not the input language. - # - # Example: - # require 'coderay' - # page = CodeRay.encode_file 'some_c_code.c', :html - def encode_file filename, format, options = {} - tokens = scan_file filename, :auto, get_scanner_options(options) - encode_tokens tokens, format, options - end - - # Highlight a file into a HTML
    . - # - # CSS styles use classes, so you have to include a stylesheet - # in your output. - # - # See encode. - def highlight_file filename, options = { :css => :class }, format = :div - encode_file filename, format, options - end - - # Finds the Encoder class for +format+ and creates an instance, passing - # +options+ to it. - # - # Example: - # require 'coderay' - # - # stats = CodeRay.encoder(:statistic) - # stats.encode("puts 17 + 4\n", :ruby) - # - # puts '%d out of %d tokens have the kind :integer.' % [ - # stats.type_stats[:integer].count, - # stats.real_token_count - # ] - # #-> 2 out of 4 tokens have the kind :integer. - def encoder format, options = {} - Encoders[format].new options - end - - # Finds the Scanner class for +lang+ and creates an instance, passing - # +options+ to it. - # - # See Scanner.new. - def scanner lang, options = {} - Scanners[lang].new '', options - end - - # Extract the options for the scanner from the +options+ hash. - # - # Returns an empty Hash if :scanner_options is not set. - # - # This is used if a method like CodeRay.encode has to provide options - # for Encoder _and_ scanner. - def get_scanner_options options - options.fetch :scanner_options, {} - end - - end - - # This Exception is raised when you try to stream with something that is not - # capable of streaming. - class NotStreamableError < Exception - def initialize obj - @obj = obj - end - - def to_s - '%s is not Streamable!' % @obj.class - end - end - - # A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder - # to show that they are able to handle streams. - module Streamable - end - -end - -# Run a test script. -if $0 == __FILE__ - $stderr.print 'Press key to print demo.'; gets - # Just use this file as an example of Ruby code. - code = File.read(__FILE__)[/module CodeRay.*/m] - print CodeRay.scan(code, :ruby).html -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/duo.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/duo.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -module CodeRay - - # = Duo - # - # A Duo is a convenient way to use CodeRay. You just create a Duo, - # giving it a lang (language of the input code) and a format (desired - # output format), and call Duo#highlight with the code. - # - # Duo makes it easy to re-use both scanner and encoder for a repetitive - # task. It also provides a very easy interface syntax: - # - # require 'coderay' - # CodeRay::Duo[:python, :div].highlight 'import this' - # - # Until you want to do uncommon things with CodeRay, I recommend to use - # this method, since it takes care of everything. - class Duo - - attr_accessor :lang, :format, :options - - # Create a new Duo, holding a lang and a format to highlight code. - # - # simple: - # CodeRay::Duo[:ruby, :page].highlight 'bla 42' - # - # streaming: - # CodeRay::Duo[:ruby, :page].highlight 'bar 23', :stream => true - # - # with options: - # CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??' - # - # alternative syntax without options: - # CodeRay::Duo[:ruby => :statistic].encode 'class << self; end' - # - # alternative syntax with options: - # CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc' - # - # The options are forwarded to scanner and encoder - # (see CodeRay.get_scanner_options). - def initialize lang = nil, format = nil, options = {} - if format == nil and lang.is_a? Hash and lang.size == 1 - @lang = lang.keys.first - @format = lang[@lang] - else - @lang = lang - @format = format - end - @options = options - end - - class << self - # To allow calls like Duo[:ruby, :html].highlight. - alias [] new - end - - # The scanner of the duo. Only created once. - def scanner - @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options) - end - - # The encoder of the duo. Only created once. - def encoder - @encoder ||= CodeRay.encoder @format, @options - end - - # Tokenize and highlight the code using +scanner+ and +encoder+. - # - # If the :stream option is set, the Duo will go into streaming mode, - # saving memory for the cost of time. - def encode code, options = { :stream => false } - stream = options.delete :stream - options = @options.merge options - if stream - encoder.encode_stream(code, @lang, options) - else - scanner.code = code - encoder.encode_tokens(scanner.tokenize, options) - end - end - alias highlight encode - - end - -end - diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoder.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoder.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -module CodeRay - - # This module holds the Encoder class and its subclasses. - # For example, the HTML encoder is named CodeRay::Encoders::HTML - # can be found in coderay/encoders/html. - # - # Encoders also provides methods and constants for the register - # mechanism and the [] method that returns the Encoder class - # belonging to the given format. - module Encoders - extend PluginHost - plugin_path File.dirname(__FILE__), 'encoders' - - # = Encoder - # - # The Encoder base class. Together with Scanner and - # Tokens, it forms the highlighting triad. - # - # Encoder instances take a Tokens object and do something with it. - # - # The most common Encoder is surely the HTML encoder - # (CodeRay::Encoders::HTML). It highlights the code in a colorful - # html page. - # If you want the highlighted code in a div or a span instead, - # use its subclasses Div and Span. - class Encoder - extend Plugin - plugin_host Encoders - - attr_reader :token_stream - - class << self - - # Returns if the Encoder can be used in streaming mode. - def streamable? - is_a? Streamable - end - - # If FILE_EXTENSION isn't defined, this method returns the - # downcase class name instead. - def const_missing sym - if sym == :FILE_EXTENSION - plugin_id - else - super - end - end - - end - - # Subclasses are to store their default options in this constant. - DEFAULT_OPTIONS = { :stream => false } - - # The options you gave the Encoder at creating. - attr_accessor :options - - # Creates a new Encoder. - # +options+ is saved and used for all encode operations, as long - # as you don't overwrite it there by passing additional options. - # - # Encoder objects provide three encode methods: - # - encode simply takes a +code+ string and a +lang+ - # - encode_tokens expects a +tokens+ object instead - # - encode_stream is like encode, but uses streaming mode. - # - # Each method has an optional +options+ parameter. These are - # added to the options you passed at creation. - def initialize options = {} - @options = self.class::DEFAULT_OPTIONS.merge options - raise "I am only the basic Encoder class. I can't encode "\ - "anything. :( Use my subclasses." if self.class == Encoder - end - - # Encode a Tokens object. - def encode_tokens tokens, options = {} - options = @options.merge options - setup options - compile tokens, options - finish options - end - - # Encode the given +code+ after tokenizing it using the Scanner - # for +lang+. - def encode code, lang, options = {} - options = @options.merge options - scanner_options = CodeRay.get_scanner_options(options) - tokens = CodeRay.scan code, lang, scanner_options - encode_tokens tokens, options - end - - # You can use highlight instead of encode, if that seems - # more clear to you. - alias highlight encode - - # Encode the given +code+ using the Scanner for +lang+ in - # streaming mode. - def encode_stream code, lang, options = {} - raise NotStreamableError, self unless kind_of? Streamable - options = @options.merge options - setup options - scanner_options = CodeRay.get_scanner_options options - @token_stream = - CodeRay.scan_stream code, lang, scanner_options, &self - finish options - end - - # Behave like a proc. The token method is converted to a proc. - def to_proc - method(:token).to_proc - end - - # Return the default file extension for outputs of this encoder. - def file_extension - self.class::FILE_EXTENSION - end - - protected - - # Called with merged options before encoding starts. - # Sets @out to an empty string. - # - # See the HTML Encoder for an example of option caching. - def setup options - @out = '' - end - - # Called with +content+ and +kind+ of the currently scanned token. - # For simple scanners, it's enougth to implement this method. - # - # By default, it calls text_token or block_token, depending on - # whether +content+ is a String. - def token content, kind - encoded_token = - if content.is_a? ::String - text_token content, kind - elsif content.is_a? ::Symbol - block_token content, kind - else - raise 'Unknown token content type: %p' % [content] - end - append_encoded_token_to_output encoded_token - end - - def append_encoded_token_to_output encoded_token - @out << encoded_token if encoded_token && defined?(@out) && @out - end - - # Called for each text token ([text, kind]), where text is a String. - def text_token text, kind - end - - # Called for each block (non-text) token ([action, kind]), - # where +action+ is a Symbol. - # - # Calls open_token, close_token, begin_line, and end_line according to - # the value of +action+. - def block_token action, kind - case action - when :open - open_token kind - when :close - close_token kind - when :begin_line - begin_line kind - when :end_line - end_line kind - else - raise 'unknown block action: %p' % action - end - end - - # Called for each block token at the start of the block ([:open, kind]). - def open_token kind - end - - # Called for each block token end of the block ([:close, kind]). - def close_token kind - end - - # Called for each line token block at the start of the line ([:begin_line, kind]). - def begin_line kind - end - - # Called for each line token block at the end of the line ([:end_line, kind]). - def end_line kind - end - - # Called with merged options after encoding starts. - # The return value is the result of encoding, typically @out. - def finish options - @out - end - - # Do the encoding. - # - # The already created +tokens+ object must be used; it can be a - # TokenStream or a Tokens object. - if RUBY_VERSION >= '1.9' - def compile tokens, options - for text, kind in tokens - token text, kind - end - end - else - def compile tokens, options - tokens.each(&self) - end - end - - end - - end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/_map.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/_map.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -module CodeRay -module Encoders - - map \ - :loc => :lines_of_code, - :plain => :text, - :stats => :statistic, - :terminal => :term, - :tex => :latex - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/comment_filter.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/comment_filter.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - load :token_class_filter - - class CommentFilter < TokenClassFilter - - register_for :comment_filter - - DEFAULT_OPTIONS = superclass::DEFAULT_OPTIONS.merge \ - :exclude => [:comment] - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class CommentFilterTest < Test::Unit::TestCase - - def test_filtering_comments - tokens = CodeRay.scan <<-RUBY, :ruby -#!/usr/bin/env ruby -# a minimal Ruby program -puts "Hello world!" - RUBY - assert_equal <<-RUBY_FILTERED, tokens.comment_filter.text -#!/usr/bin/env ruby - -puts "Hello world!" - RUBY_FILTERED - end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/count.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/count.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -module CodeRay -module Encoders - - class Count < Encoder - - include Streamable - register_for :count - - protected - - def setup options - @out = 0 - end - - def token text, kind - @out += 1 - end - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/debug.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/debug.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -module CodeRay -module Encoders - - # = Debug Encoder - # - # Fast encoder producing simple debug output. - # - # It is readable and diff-able and is used for testing. - # - # You cannot fully restore the tokens information from the - # output, because consecutive :space tokens are merged. - # Use Tokens#dump for caching purposes. - class Debug < Encoder - - include Streamable - register_for :debug - - FILE_EXTENSION = 'raydebug' - - protected - def text_token text, kind - if kind == :space - text - else - text = text.gsub(/[)\\]/, '\\\\\0') # escape ) and \ - "#{kind}(#{text})" - end - end - - def open_token kind - "#{kind}<" - end - - def close_token kind - ">" - end - - def begin_line kind - "#{kind}[" - end - - def end_line kind - "]" - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/div.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/div.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -module CodeRay -module Encoders - - load :html - - class Div < HTML - - FILE_EXTENSION = 'div.html' - - register_for :div - - DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ - :css => :style, - :wrap => :div - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/filter.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/filter.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - class Filter < Encoder - - register_for :filter - - protected - def setup options - @out = Tokens.new - end - - def text_token text, kind - [text, kind] if include_text_token? text, kind - end - - def include_text_token? text, kind - true - end - - def block_token action, kind - [action, kind] if include_block_token? action, kind - end - - def include_block_token? action, kind - true - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class FilterTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Encoders::Filter < CodeRay::Encoders::Encoder - filter = nil - assert_nothing_raised do - filter = CodeRay.encoder :filter - end - assert_kind_of CodeRay::Encoders::Encoder, filter - end - - def test_filtering_text_tokens - tokens = CodeRay::Tokens.new - 10.times do |i| - tokens << [i.to_s, :index] - end - assert_equal tokens, CodeRay::Encoders::Filter.new.encode_tokens(tokens) - assert_equal tokens, tokens.filter - end - - def test_filtering_block_tokens - tokens = CodeRay::Tokens.new - 10.times do |i| - tokens << [:open, :index] - tokens << [i.to_s, :content] - tokens << [:close, :index] - end - assert_equal tokens, CodeRay::Encoders::Filter.new.encode_tokens(tokens) - assert_equal tokens, tokens.filter - end - -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,309 +0,0 @@ -require 'set' - -module CodeRay -module Encoders - - # = HTML Encoder - # - # This is CodeRay's most important highlighter: - # It provides save, fast XHTML generation and CSS support. - # - # == Usage - # - # require 'coderay' - # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page - # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) - # #-> Some /code/ - # puts CodeRay.scan('Some /code/', :ruby).span #-> the same - # - # puts CodeRay.scan('Some code', :ruby).html( - # :wrap => nil, - # :line_numbers => :inline, - # :css => :style - # ) - # #-> 1 Some code - # - # == Options - # - # === :tab_width - # Convert \t characters to +n+ spaces (a number.) - # Default: 8 - # - # === :css - # How to include the styles; can be :class or :style. - # - # Default: :class - # - # === :wrap - # Wrap in :page, :div, :span or nil. - # - # You can also use Encoders::Div and Encoders::Span. - # - # Default: nil - # - # === :title - # - # The title of the HTML page (works only when :wrap is set to :page.) - # - # Default: 'CodeRay output' - # - # === :line_numbers - # Include line numbers in :table, :inline, :list or nil (no line numbers) - # - # Default: nil - # - # === :line_number_start - # Where to start with line number counting. - # - # Default: 1 - # - # === :bold_every - # Make every +n+-th number appear bold. - # - # Default: 10 - # - # === :highlight_lines - # - # Highlights certain line numbers. - # Can be any Enumerable, typically just an Array or Range, of numbers. - # - # Bolding is deactivated when :highlight_lines is set. It only makes sense - # in combination with :line_numbers. - # - # Default: nil - # - # === :hint - # Include some information into the output using the title attribute. - # Can be :info (show token type on mouse-over), :info_long (with full path) - # or :debug (via inspect). - # - # Default: false - class HTML < Encoder - - include Streamable - register_for :html - - FILE_EXTENSION = 'html' - - DEFAULT_OPTIONS = { - :tab_width => 8, - - :css => :class, - - :style => :cycnus, - :wrap => nil, - :title => 'CodeRay output', - - :line_numbers => nil, - :line_number_start => 1, - :bold_every => 10, - :highlight_lines => nil, - - :hint => false, - } - - helper :output, :css - - attr_reader :css - - protected - - HTML_ESCAPE = { #:nodoc: - '&' => '&', - '"' => '"', - '>' => '>', - '<' => '<', - } - - # This was to prevent illegal HTML. - # Strange chars should still be avoided in codes. - evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s] - evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' } - #ansi_chars = Array(0x7f..0xff) - #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i } - # \x9 (\t) and \xA (\n) not included - #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/ - HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/ - - TOKEN_KIND_TO_INFO = Hash.new { |h, kind| - h[kind] = - case kind - when :pre_constant - 'Predefined constant' - else - kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } - end - } - - TRANSPARENT_TOKEN_KINDS = [ - :delimiter, :modifier, :content, :escape, :inline_delimiter, - ].to_set - - # Generate a hint about the given +classes+ in a +hint+ style. - # - # +hint+ may be :info, :info_long or :debug. - def self.token_path_to_hint hint, classes - title = - case hint - when :info - TOKEN_KIND_TO_INFO[classes.first] - when :info_long - classes.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') - when :debug - classes.inspect - end - title ? " title=\"#{title}\"" : '' - end - - def setup options - super - - @HTML_ESCAPE = HTML_ESCAPE.dup - @HTML_ESCAPE["\t"] = ' ' * options[:tab_width] - - @opened = [nil] - @css = CSS.new options[:style] - - hint = options[:hint] - if hint and not [:debug, :info, :info_long].include? hint - raise ArgumentError, "Unknown value %p for :hint; \ - expected :info, :debug, false, or nil." % hint - end - - case options[:css] - - when :class - @css_style = Hash.new do |h, k| - c = CodeRay::Tokens::ClassOfKind[k.first] - if c == :NO_HIGHLIGHT and not hint - h[k.dup] = false - else - title = if hint - HTML.token_path_to_hint(hint, k[1..-1] << k.first) - else - '' - end - if c == :NO_HIGHLIGHT - h[k.dup] = '' % [title] - else - h[k.dup] = '' % [title, c] - end - end - end - - when :style - @css_style = Hash.new do |h, k| - if k.is_a? ::Array - styles = k.dup - else - styles = [k] - end - type = styles.first - classes = styles.map { |c| Tokens::ClassOfKind[c] } - if classes.first == :NO_HIGHLIGHT and not hint - h[k] = false - else - styles.shift if TRANSPARENT_TOKEN_KINDS.include? styles.first - title = HTML.token_path_to_hint hint, styles - style = @css[*classes] - h[k] = - if style - '' % [title, style] - else - false - end - end - end - - else - raise ArgumentError, "Unknown value %p for :css." % options[:css] - - end - end - - def finish options - not_needed = @opened.shift - @out << '' * @opened.size - unless @opened.empty? - warn '%d tokens still open: %p' % [@opened.size, @opened] - end - - @out.extend Output - @out.css = @css - @out.numerize! options[:line_numbers], options - @out.wrap! options[:wrap] - @out.apply_title! options[:title] - - super - end - - def token text, type = :plain - case text - - when nil - # raise 'Token with nil as text was given: %p' % [[text, type]] - - when String - if text =~ /#{HTML_ESCAPE_PATTERN}/o - text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } - end - @opened[0] = type - if text != "\n" && style = @css_style[@opened] - @out << style << text << '' - else - @out << text - end - - - # token groups, eg. strings - when :open - @opened[0] = type - @out << (@css_style[@opened] || '') - @opened << type - when :close - if @opened.empty? - # nothing to close - else - if $CODERAY_DEBUG and (@opened.size == 1 or @opened.last != type) - raise 'Malformed token stream: Trying to close a token (%p) \ - that is not open. Open are: %p.' % [type, @opened[1..-1]] - end - @out << '' - @opened.pop - end - - # whole lines to be highlighted, eg. a deleted line in a diff - when :begin_line - @opened[0] = type - if style = @css_style[@opened] - if style['class="'] - @out << style.sub('class="', 'class="line ') - else - @out << style.sub('>', ' class="line">') - end - else - @out << '' - end - @opened << type - when :end_line - if @opened.empty? - # nothing to close - else - if $CODERAY_DEBUG and (@opened.size == 1 or @opened.last != type) - raise 'Malformed token stream: Trying to close a line (%p) \ - that is not open. Open are: %p.' % [type, @opened[1..-1]] - end - @out << '' - @opened.pop - end - - else - raise 'unknown token kind: %p' % [text] - - end - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/css.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/css.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -module CodeRay -module Encoders - - class HTML - class CSS - - attr :stylesheet - - def CSS.load_stylesheet style = nil - CodeRay::Styles[style] - end - - def initialize style = :default - @classes = Hash.new - style = CSS.load_stylesheet style - @stylesheet = [ - style::CSS_MAIN_STYLES, - style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ') - ].join("\n") - parse style::TOKEN_COLORS - end - - def [] *styles - cl = @classes[styles.first] - return '' unless cl - style = '' - 1.upto(styles.size) do |offset| - break if style = cl[styles[offset .. -1]] - end - # warn 'Style not found: %p' % [styles] if style.empty? - return style - end - - private - - CSS_CLASS_PATTERN = / - ( # $1 = selectors - (?: - (?: \s* \. [-\w]+ )+ - \s* ,? - )+ - ) - \s* \{ \s* - ( [^\}]+ )? # $2 = style - \s* \} \s* - | - ( . ) # $3 = error - /mx - def parse stylesheet - stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error| - raise "CSS parse error: '#{error.inspect}' not recognized" if error - for selector in selectors.split(',') - classes = selector.scan(/[-\w]+/) - cl = classes.pop - @classes[cl] ||= Hash.new - @classes[cl][classes] = style.to_s.strip.delete(' ').chomp(';') - end - end - end - - end - end - -end -end - -if $0 == __FILE__ - require 'pp' - pp CodeRay::Encoders::HTML::CSS.new -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/numerization.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/numerization.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -module CodeRay -module Encoders - - class HTML - - module Output - - def numerize *args - clone.numerize!(*args) - end - -=begin NUMERIZABLE_WRAPPINGS = { - :table => [:div, :page, nil], - :inline => :all, - :list => [:div, :page, nil] - } - NUMERIZABLE_WRAPPINGS.default = :all -=end - def numerize! mode = :table, options = {} - return self unless mode - - options = DEFAULT_OPTIONS.merge options - - start = options[:line_number_start] - unless start.is_a? Integer - raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start - end - - #allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode] - #unless allowed_wrappings == :all or allowed_wrappings.include? options[:wrap] - # raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]] - #end - - bold_every = options[:bold_every] - highlight_lines = options[:highlight_lines] - bolding = - if bold_every == false && highlight_lines == nil - proc { |line| line.to_s } - elsif highlight_lines.is_a? Enumerable - highlight_lines = highlight_lines.to_set - proc do |line| - if highlight_lines.include? line - "#{line}" # highlighted line numbers in bold - else - line.to_s - end - end - elsif bold_every.is_a? Integer - raise ArgumentError, ":bolding can't be 0." if bold_every == 0 - proc do |line| - if line % bold_every == 0 - "#{line}" # every bold_every-th number in bold - else - line.to_s - end - end - else - raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every - end - - case mode - when :inline - max_width = (start + line_count).to_s.size - line_number = start - gsub!(/^/) do - line_number_text = bolding.call line_number - indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x) - res = "#{indent}#{line_number_text} " - line_number += 1 - res - end - - when :table - # This is really ugly. - # Because even monospace fonts seem to have different heights when bold, - # I make the newline bold, both in the code and the line numbers. - # FIXME Still not working perfect for Mr. Internet Exploder - line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n") - line_numbers << "\n" # also for Mr. MS Internet Exploder :-/ - line_numbers.gsub!(/\n/) { "\n" } - - line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers) - gsub!("
    \n", '
    ') - gsub!("\n", "\n") - wrap_in! line_numbers_table_tpl - @wrapped_in = :div - - when :list - opened_tags = [] - gsub!(/^.*$\n?/) do |line| - line.chomp! - - open = opened_tags.join - line.scan(%r!<(/)?span[^>]*>?!) do |close,| - if close - opened_tags.pop - else - opened_tags << $& - end - end - close = '' * opened_tags.size - - "
  • #{open}#{line}#{close}
  • \n" - end - chomp!("\n") - wrap_in! LIST - @wrapped_in = :div - - else - raise ArgumentError, 'Unknown value %p for mode: expected one of %p' % - [mode, [:table, :list, :inline]] - end - - self - end - - def line_count - line_count = count("\n") - position_of_last_newline = rindex(?\n) - if position_of_last_newline - after_last_newline = self[position_of_last_newline + 1 .. -1] - ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/] - line_count += 1 if not ends_with_newline - end - line_count - end - - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/output.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/output.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -module CodeRay -module Encoders - - class HTML - - # This module is included in the output String from thew HTML Encoder. - # - # It provides methods like wrap, div, page etc. - # - # Remember to use #clone instead of #dup to keep the modules the object was - # extended with. - # - # TODO: more doc. - module Output - - require 'coderay/encoders/html/numerization.rb' - - attr_accessor :css - - class << self - - # This makes Output look like a class. - # - # Example: - # - # a = Output.new 'Code' - # a.wrap! :page - def new string, css = CSS.new, element = nil - output = string.clone.extend self - output.wrapped_in = element - output.css = css - output - end - - # Raises an exception if an object that doesn't respond to to_str is extended by Output, - # to prevent users from misuse. Use Module#remove_method to disable. - def extended o - warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str - end - - def make_stylesheet css, in_tag = false - sheet = css.stylesheet - sheet = <<-CSS if in_tag - - CSS - sheet - end - - def page_template_for_css css - sheet = make_stylesheet css - PAGE.apply 'CSS', sheet - end - - # Define a new wrapper. This is meta programming. - def wrapper *wrappers - wrappers.each do |wrapper| - define_method wrapper do |*args| - wrap wrapper, *args - end - define_method "#{wrapper}!".to_sym do |*args| - wrap! wrapper, *args - end - end - end - - end - - wrapper :div, :span, :page - - def wrapped_in? element - wrapped_in == element - end - - def wrapped_in - @wrapped_in ||= nil - end - attr_writer :wrapped_in - - def wrap_in template - clone.wrap_in! template - end - - def wrap_in! template - Template.wrap! self, template, 'CONTENT' - self - end - - def apply_title! title - self.sub!(/()(<\/title>)/) { $1 + title + $2 } - self - end - - def wrap! element, *args - return self if not element or element == wrapped_in - case element - when :div - raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil - wrap_in! DIV - when :span - raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil - wrap_in! SPAN - when :page - wrap! :div if wrapped_in? nil - raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div - wrap_in! Output.page_template_for_css(@css) - if args.first.is_a?(Hash) && title = args.first[:title] - apply_title! title - end - self - when nil - return self - else - raise "Unknown value %p for :wrap" % element - end - @wrapped_in = element - self - end - - def wrap *args - clone.wrap!(*args) - end - - def stylesheet in_tag = false - Output.make_stylesheet @css, in_tag - end - - class Template < String - - def self.wrap! str, template, target - target = Regexp.new(Regexp.escape("<%#{target}%>")) - if template =~ target - str[0,0] = $` - str << $' - else - raise "Template target <%%%p%%> not found" % target - end - end - - def apply target, replacement - target = Regexp.new(Regexp.escape("<%#{target}%>")) - if self =~ target - Template.new($` + replacement + $') - else - raise "Template target <%%%p%%> not found" % target - end - end - - module Simple - def ` str #` <-- for stupid editors - Template.new str - end - end - end - - extend Template::Simple - -#-- don't include the templates in docu - - SPAN = `<span class="CodeRay"><%CONTENT%></span>` - - DIV = <<-`DIV` -<div class="CodeRay"> - <div class="code"><pre><%CONTENT%></pre></div> -</div> - DIV - - TABLE = <<-`TABLE` -<table class="CodeRay"><tr> - <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td> - <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><%CONTENT%></pre></td> -</tr></table> - TABLE - # title="double click to expand" - - LIST = <<-`LIST` -<ol class="CodeRay"> -<%CONTENT%> -</ol> - LIST - - PAGE = <<-`PAGE` -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="de"> -<head> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <title> - - - - -<%CONTENT%> - - - PAGE - - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/json.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/json.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - # = JSON Encoder - class JSON < Encoder - - register_for :json - FILE_EXTENSION = 'json' - - protected - def setup options - begin - require 'json' - rescue LoadError - require 'rubygems' - require 'json' - end - @out = [] - end - - def text_token text, kind - { :type => 'text', :text => text, :kind => kind } - end - - def block_token action, kind - { :type => 'block', :action => action, :kind => kind } - end - - def finish options - @out.to_json - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' -$:.delete '.' -require 'rubygems' if RUBY_VERSION < '1.9' - -class JSONEncoderTest < Test::Unit::TestCase - - def test_json_output - tokens = CodeRay.scan <<-RUBY, :ruby -puts "Hello world!" - RUBY - require 'json' - assert_equal [ - {"type"=>"text", "text"=>"puts", "kind"=>"ident"}, - {"type"=>"text", "text"=>" ", "kind"=>"space"}, - {"type"=>"block", "action"=>"open", "kind"=>"string"}, - {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, - {"type"=>"text", "text"=>"Hello world!", "kind"=>"content"}, - {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, - {"type"=>"block", "action"=>"close", "kind"=>"string"}, - {"type"=>"text", "text"=>"\n", "kind"=>"space"} - ], JSON.load(tokens.json) - end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/lines_of_code.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/lines_of_code.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - # Counts the LoC (Lines of Code). Returns an Integer >= 0. - # - # Alias: :loc - # - # Everything that is not comment, markup, doctype/shebang, or an empty line, - # is considered to be code. - # - # For example, - # * HTML files not containing JavaScript have 0 LoC - # * in a Java class without comments, LoC is the number of non-empty lines - # - # A Scanner class should define the token kinds that are not code in the - # KINDS_NOT_LOC constant, which defaults to [:comment, :doctype]. - class LinesOfCode < Encoder - - register_for :lines_of_code - - NON_EMPTY_LINE = /^\s*\S.*$/ - - def compile tokens, options - if scanner = tokens.scanner - kinds_not_loc = scanner.class::KINDS_NOT_LOC - else - warn ArgumentError, 'Tokens have no scanner.' if $VERBOSE - kinds_not_loc = CodeRay::Scanners::Scanner::KINDS_NOT_LOC - end - code = tokens.token_class_filter :exclude => kinds_not_loc - @loc = code.text.scan(NON_EMPTY_LINE).size - end - - def finish options - @loc - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class LinesOfCodeTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Encoders::LinesOfCode < CodeRay::Encoders::Encoder - filter = nil - assert_nothing_raised do - filter = CodeRay.encoder :loc - end - assert_kind_of CodeRay::Encoders::LinesOfCode, filter - assert_nothing_raised do - filter = CodeRay.encoder :lines_of_code - end - assert_kind_of CodeRay::Encoders::LinesOfCode, filter - end - - def test_lines_of_code - tokens = CodeRay.scan <<-RUBY, :ruby -#!/usr/bin/env ruby - -# a minimal Ruby program -puts "Hello world!" - RUBY - assert_equal 1, CodeRay::Encoders::LinesOfCode.new.encode_tokens(tokens) - assert_equal 1, tokens.lines_of_code - assert_equal 1, tokens.loc - end - - def test_filtering_block_tokens - tokens = CodeRay::Tokens.new - tokens << ["Hello\n", :world] - tokens << ["Hello\n", :space] - tokens << ["Hello\n", :comment] - assert_equal 2, CodeRay::Encoders::LinesOfCode.new.encode_tokens(tokens) - assert_equal 2, tokens.lines_of_code - assert_equal 2, tokens.loc - end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/null.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/null.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -module CodeRay -module Encoders - - # = Null Encoder - # - # Does nothing and returns an empty string. - class Null < Encoder - - include Streamable - register_for :null - - # Defined for faster processing - def to_proc - proc {} - end - - protected - - def token(*) - # do nothing - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/page.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/page.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -module CodeRay -module Encoders - - load :html - - class Page < HTML - - FILE_EXTENSION = 'html' - - register_for :page - - DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ - :css => :class, - :wrap => :page, - :line_numbers => :table - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/span.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/span.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -module CodeRay -module Encoders - - load :html - - class Span < HTML - - FILE_EXTENSION = 'span.html' - - register_for :span - - DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ - :css => :style, - :wrap => :span - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/statistic.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/statistic.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -module CodeRay -module Encoders - - # Makes a statistic for the given tokens. - class Statistic < Encoder - - include Streamable - register_for :stats, :statistic - - attr_reader :type_stats, :real_token_count - - protected - - TypeStats = Struct.new :count, :size - - def setup options - @type_stats = Hash.new { |h, k| h[k] = TypeStats.new 0, 0 } - @real_token_count = 0 - end - - def generate tokens, options - @tokens = tokens - super - end - - def text_token text, kind - @real_token_count += 1 unless kind == :space - @type_stats[kind].count += 1 - @type_stats[kind].size += text.size - @type_stats['TOTAL'].size += text.size - @type_stats['TOTAL'].count += 1 - end - - # TODO Hierarchy handling - def block_token action, kind - @type_stats['TOTAL'].count += 1 - @type_stats['open/close'].count += 1 - end - - STATS = <<-STATS - -Code Statistics - -Tokens %8d - Non-Whitespace %8d -Bytes Total %8d - -Token Types (%d): - type count ratio size (average) -------------------------------------------------------------- -%s - STATS -# space 12007 33.81 % 1.7 - TOKEN_TYPES_ROW = <<-TKR - %-20s %8d %6.2f %% %5.1f - TKR - - def finish options - all = @type_stats['TOTAL'] - all_count, all_size = all.count, all.size - @type_stats.each do |type, stat| - stat.size /= stat.count.to_f - end - types_stats = @type_stats.sort_by { |k, v| [-v.count, k.to_s] }.map do |k, v| - TOKEN_TYPES_ROW % [k, v.count, 100.0 * v.count / all_count, v.size] - end.join - STATS % [ - all_count, @real_token_count, all_size, - @type_stats.delete_if { |k, v| k.is_a? String }.size, - types_stats - ] - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/term.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/term.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -# encoders/term.rb -# By Rob Aldred (http://robaldred.co.uk) -# Based on idea by Nathan Weizenbaum (http://nex-3.com) -# MIT License (http://www.opensource.org/licenses/mit-license.php) -# -# A CodeRay encoder that outputs code highlighted for a color terminal. -# Check out http://robaldred.co.uk - -module CodeRay - module Encoders - class Term < Encoder - register_for :term - - TOKEN_COLORS = { - :annotation => '35', - :attribute_name => '33', - :attribute_name_fat => '33', - :attribute_value => '31', - :attribute_value_fat => '31', - :bin => '1;35', - :char => {:self => '36', :delimiter => '34'}, - :class => '1;35', - :class_variable => '36', - :color => '32', - :comment => '37', - :complex => '34', - :constant => ['34', '4'], - :decoration => '35', - :definition => '1;32', - :directive => ['32', '4'], - :doc => '46', - :doctype => '1;30', - :doc_string => ['31', '4'], - :entity => '33', - :error => ['1;33', '41'], - :exception => '1;31', - :float => '1;35', - :function => '1;34', - :global_variable => '42', - :hex => '1;36', - :important => '1;31', - :include => '33', - :integer => '1;34', - :interpreted => '1;35', - :key => '35', - :label => '1;4', - :local_variable => '33', - :oct => '1;35', - :operator_name => '1;29', - :pre_constant => '1;36', - :pre_type => '1;30', - :predefined => ['4', '1;34'], - :preprocessor => '36', - :pseudo_class => '34', - :regexp => { - :content => '31', - :delimiter => '1;29', - :modifier => '35', - :function => '1;29' - }, - :reserved => '1;31', - :shell => { - :self => '42', - :content => '1;29', - :delimiter => '37', - }, - :string => { - :self => '32', - :modifier => '1;32', - :escape => '1;36', - :delimiter => '1;32', - }, - :symbol => '1;32', - :tag => '34', - :tag_fat => '1;34', - :tag_special => ['34', '4'], - :type => '1;34', - :value => '36', - :variable => '34', - :insert => '42', - :delete => '41', - :change => '44', - :head => '45', - } - TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved] - TOKEN_COLORS[:method] = TOKEN_COLORS[:function] - TOKEN_COLORS[:imaginary] = TOKEN_COLORS[:complex] - TOKEN_COLORS[:open] = TOKEN_COLORS[:close] = TOKEN_COLORS[:nesting_delimiter] = TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter] - - protected - - def setup(options) - @out = '' - @opened = [nil] - @subcolors = nil - end - - def finish(options) - super - end - - def token text, type = :plain - case text - - when nil - # raise 'Token with nil as text was given: %p' % [[text, type]] - - when String - - if color = (@subcolors || TOKEN_COLORS)[type] - color = color[:self] || return if Hash === color - - @out << col(color) + text.gsub("\n", col(0) + "\n" + col(color)) + col(0) - @out << col(@subcolors[:self]) if @subcolors && @subcolors[:self] - else - @out << text - end - - # token groups, eg. strings - when :open - @opened[0] = type - if color = TOKEN_COLORS[type] - if Hash === color - @subcolors = color - @out << col(color[:self]) if color[:self] - else - @subcolors = {} - @out << col(color) - end - end - @opened << type - when :close - if @opened.empty? - # nothing to close - else - @out << col(0) if (@subcolors || {})[:self] - @subcolors = nil - @opened.pop - end - - # whole lines to be highlighted, eg. a added/modified/deleted lines in a diff - when :begin_line - - when :end_line - - else - raise 'unknown token kind: %p' % [text] - end - end - - private - - def col(color) - Array(color).map { |c| "\e[#{c}m" }.join - end - end - end -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/text.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/text.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -module CodeRay -module Encoders - - class Text < Encoder - - include Streamable - register_for :text - - FILE_EXTENSION = 'txt' - - DEFAULT_OPTIONS = { - :separator => '' - } - - protected - def setup options - super - @sep = options[:separator] - end - - def text_token text, kind - text + @sep - end - - def finish options - super.chomp @sep - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/token_class_filter.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/token_class_filter.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - load :filter - - class TokenClassFilter < Filter - - include Streamable - register_for :token_class_filter - - DEFAULT_OPTIONS = { - :exclude => [], - :include => :all - } - - protected - def setup options - super - @exclude = options[:exclude] - @exclude = Array(@exclude) unless @exclude == :all - @include = options[:include] - @include = Array(@include) unless @include == :all - end - - def include_text_token? text, kind - (@include == :all || @include.include?(kind)) && - !(@exclude == :all || @exclude.include?(kind)) - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class TokenClassFilterTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Encoders::TokenClassFilter < CodeRay::Encoders::Encoder - assert CodeRay::Encoders::TokenClassFilter < CodeRay::Encoders::Filter - filter = nil - assert_nothing_raised do - filter = CodeRay.encoder :token_class_filter - end - assert_instance_of CodeRay::Encoders::TokenClassFilter, filter - end - - def test_filtering_text_tokens - tokens = CodeRay::Tokens.new - for i in 1..10 - tokens << [i.to_s, :index] - tokens << [' ', :space] if i < 10 - end - assert_equal 10, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :exclude => :space).size - assert_equal 10, tokens.token_class_filter(:exclude => :space).size - assert_equal 9, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :include => :space).size - assert_equal 9, tokens.token_class_filter(:include => :space).size - assert_equal 0, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :exclude => :all).size - assert_equal 0, tokens.token_class_filter(:exclude => :all).size - end - - def test_filtering_block_tokens - tokens = CodeRay::Tokens.new - 10.times do |i| - tokens << [:open, :index] - tokens << [i.to_s, :content] - tokens << [:close, :index] - end - assert_equal 20, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :include => :blubb).size - assert_equal 20, tokens.token_class_filter(:include => :blubb).size - assert_equal 30, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :exclude => :index).size - assert_equal 30, tokens.token_class_filter(:exclude => :index).size - end - -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/xml.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/xml.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -module CodeRay -module Encoders - - # = XML Encoder - # - # Uses REXML. Very slow. - class XML < Encoder - - include Streamable - register_for :xml - - FILE_EXTENSION = 'xml' - - require 'rexml/document' - - DEFAULT_OPTIONS = { - :tab_width => 8, - :pretty => -1, - :transitive => false, - } - - protected - - def setup options - @doc = REXML::Document.new - @doc << REXML::XMLDecl.new - @tab_width = options[:tab_width] - @root = @node = @doc.add_element('coderay-tokens') - end - - def finish options - @out = '' - @doc.write @out, options[:pretty], options[:transitive], true - @out - end - - def text_token text, kind - if kind == :space - token = @node - else - token = @node.add_element kind.to_s - end - text.scan(/(\x20+)|(\t+)|(\n)|[^\x20\t\n]+/) do |space, tab, nl| - case - when space - token << REXML::Text.new(space, true) - when tab - token << REXML::Text.new(tab, true) - when nl - token << REXML::Text.new(nl, true) - else - token << REXML::Text.new($&) - end - end - end - - def open_token kind - @node = @node.add_element kind.to_s - end - - def close_token kind - if @node == @root - raise 'no token to close!' - end - @node = @node.parent - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/encoders/yaml.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/yaml.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -module CodeRay -module Encoders - - # = YAML Encoder - # - # Slow. - class YAML < Encoder - - register_for :yaml - - FILE_EXTENSION = 'yaml' - - protected - def compile tokens, options - require 'yaml' - @out = tokens.to_a.to_yaml - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/for_redcloth.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/for_redcloth.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -module CodeRay - - # A little hack to enable CodeRay highlighting in RedCloth. - # - # Usage: - # require 'coderay' - # require 'coderay/for_redcloth' - # RedCloth.new('@[ruby]puts "Hello, World!"@').to_html - # - # Make sure you have RedCloth 4.0.3 activated, for example by calling - # require 'rubygems' - # before RedCloth is loaded and before calling CodeRay.for_redcloth. - module ForRedCloth - - def self.install - gem 'RedCloth', '>= 4.0.3' if defined? gem - require 'redcloth' - unless RedCloth::VERSION.to_s >= '4.0.3' - if defined? gem - raise 'CodeRay.for_redcloth needs RedCloth version 4.0.3 or later. ' + - "You have #{RedCloth::VERSION}. Please gem install RedCloth." - else - $".delete 'redcloth.rb' # sorry, but it works - require 'rubygems' - return install # retry - end - end - unless RedCloth::VERSION.to_s >= '4.2.2' - warn 'CodeRay.for_redcloth works best with RedCloth version 4.2.2 or later.' - end - RedCloth::TextileDoc.send :include, ForRedCloth::TextileDoc - RedCloth::Formatters::HTML.module_eval do - def unescape(html) - replacements = { - '&' => '&', - '"' => '"', - '>' => '>', - '<' => '<', - } - html.gsub(/&(?:amp|quot|[gl]t);/) { |entity| replacements[entity] } - end - undef code, bc_open, bc_close, escape_pre - def code(opts) # :nodoc: - opts[:block] = true - if !opts[:lang] && RedCloth::VERSION.to_s >= '4.2.0' - # simulating pre-4.2 behavior - if opts[:text].sub!(/\A\[(\w+)\]/, '') - if CodeRay::Scanners[$1].plugin_id == 'plaintext' - opts[:text] = $& + opts[:text] - else - opts[:lang] = $1 - end - end - end - if opts[:lang] && !filter_coderay - require 'coderay' - @in_bc ||= nil - format = @in_bc ? :div : :span - opts[:text] = unescape(opts[:text]) unless @in_bc - highlighted_code = CodeRay.encode opts[:text], opts[:lang], format, :stream => true - highlighted_code.sub!(/\A<(span|div)/) { |m| m + pba(@in_bc || opts) } - highlighted_code - else - "#{opts[:text]}
    " - end - end - def bc_open(opts) # :nodoc: - opts[:block] = true - @in_bc = opts - opts[:lang] ? '' : "" - end - def bc_close(opts) # :nodoc: - opts = @in_bc - @in_bc = nil - opts[:lang] ? '' : "
    \n" - end - def escape_pre(text) - if @in_bc ||= nil - text - else - html_esc(text, :html_escape_preformatted) - end - end - end - end - - module TextileDoc # :nodoc: - attr_accessor :filter_coderay - end - - end - -end - -CodeRay::ForRedCloth.install \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/helpers/file_type.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/file_type.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,255 +0,0 @@ -#!/usr/bin/env ruby -module CodeRay - -# = FileType -# -# A simple filetype recognizer. -# -# Copyright (c) 2006 by murphy (Kornelius Kalnbach) -# -# License:: LGPL / ask the author -# Version:: 0.1 (2005-09-01) -# -# == Documentation -# -# # determine the type of the given -# lang = FileType[ARGV.first] -# -# # return :plaintext if the file type is unknown -# lang = FileType.fetch ARGV.first, :plaintext -# -# # try the shebang line, too -# lang = FileType.fetch ARGV.first, :plaintext, true -module FileType - - UnknownFileType = Class.new Exception - - class << self - - # Try to determine the file type of the file. - # - # +filename+ is a relative or absolute path to a file. - # - # The file itself is only accessed when +read_shebang+ is set to true. - # That means you can get filetypes from files that don't exist. - def [] filename, read_shebang = false - name = File.basename filename - ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot - ext2 = filename.to_s[/\.(.*)/, 1] # from first dot - - type = - TypeFromExt[ext] || - TypeFromExt[ext.downcase] || - (TypeFromExt[ext2] if ext2) || - (TypeFromExt[ext2.downcase] if ext2) || - TypeFromName[name] || - TypeFromName[name.downcase] - type ||= shebang(filename) if read_shebang - - type - end - - def shebang filename - begin - File.open filename, 'r' do |f| - if first_line = f.gets - if type = first_line[TypeFromShebang] - type.to_sym - end - end - end - rescue IOError - nil - end - end - - # This works like Hash#fetch. - # - # If the filetype cannot be found, the +default+ value - # is returned. - def fetch filename, default = nil, read_shebang = false - if default and block_given? - warn 'block supersedes default value argument' - end - - unless type = self[filename, read_shebang] - return yield if block_given? - return default if default - raise UnknownFileType, 'Could not determine type of %p.' % filename - end - type - end - - end - - TypeFromExt = { - 'c' => :c, - 'css' => :css, - 'diff' => :diff, - 'dpr' => :delphi, - 'groovy' => :groovy, - 'gvy' => :groovy, - 'h' => :c, - 'htm' => :html, - 'html' => :html, - 'html.erb' => :rhtml, - 'java' => :java, - 'js' => :java_script, - 'json' => :json, - 'mab' => :ruby, - 'pas' => :delphi, - 'patch' => :diff, - 'php' => :php, - 'php3' => :php, - 'php4' => :php, - 'php5' => :php, - 'py' => :python, - 'py3' => :python, - 'pyw' => :python, - 'rake' => :ruby, - 'raydebug' => :debug, - 'rb' => :ruby, - 'rbw' => :ruby, - 'rhtml' => :rhtml, - 'rxml' => :ruby, - 'sch' => :scheme, - 'sql' => :sql, - 'ss' => :scheme, - 'xhtml' => :xhtml, - 'xml' => :xml, - 'yaml' => :yaml, - 'yml' => :yaml, - } - for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu] - TypeFromExt[cpp_alias] = :cpp - end - - TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/ - - TypeFromName = { - 'Rakefile' => :ruby, - 'Rantfile' => :ruby, - } - -end - -end - -if $0 == __FILE__ - $VERBOSE = true - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class FileTypeTests < Test::Unit::TestCase - - include CodeRay - - def test_fetch - assert_raise FileType::UnknownFileType do - FileType.fetch '' - end - - assert_throws :not_found do - FileType.fetch '.' do - throw :not_found - end - end - - assert_equal :default, FileType.fetch('c', :default) - - stderr, fake_stderr = $stderr, Object.new - $err = '' - def fake_stderr.write x - $err << x - end - $stderr = fake_stderr - FileType.fetch('c', :default) { } - assert_equal "block supersedes default value argument\n", $err - $stderr = stderr - end - - def test_ruby - assert_equal :ruby, FileType['test.rb'] - assert_equal :ruby, FileType['test.java.rb'] - assert_equal :java, FileType['test.rb.java'] - assert_equal :ruby, FileType['C:\\Program Files\\x\\y\\c\\test.rbw'] - assert_equal :ruby, FileType['/usr/bin/something/Rakefile'] - assert_equal :ruby, FileType['~/myapp/gem/Rantfile'] - assert_equal :ruby, FileType['./lib/tasks\repository.rake'] - assert_not_equal :ruby, FileType['test_rb'] - assert_not_equal :ruby, FileType['Makefile'] - assert_not_equal :ruby, FileType['set.rb/set'] - assert_not_equal :ruby, FileType['~/projects/blabla/rb'] - end - - def test_c - assert_equal :c, FileType['test.c'] - assert_equal :c, FileType['C:\\Program Files\\x\\y\\c\\test.h'] - assert_not_equal :c, FileType['test_c'] - assert_not_equal :c, FileType['Makefile'] - assert_not_equal :c, FileType['set.h/set'] - assert_not_equal :c, FileType['~/projects/blabla/c'] - end - - def test_cpp - assert_equal :cpp, FileType['test.c++'] - assert_equal :cpp, FileType['test.cxx'] - assert_equal :cpp, FileType['test.hh'] - assert_equal :cpp, FileType['test.hpp'] - assert_equal :cpp, FileType['test.cu'] - assert_equal :cpp, FileType['test.C'] - assert_not_equal :cpp, FileType['test.c'] - assert_not_equal :cpp, FileType['test.h'] - end - - def test_html - assert_equal :html, FileType['test.htm'] - assert_equal :xhtml, FileType['test.xhtml'] - assert_equal :xhtml, FileType['test.html.xhtml'] - assert_equal :rhtml, FileType['_form.rhtml'] - assert_equal :rhtml, FileType['_form.html.erb'] - end - - def test_yaml - assert_equal :yaml, FileType['test.yml'] - assert_equal :yaml, FileType['test.yaml'] - assert_equal :yaml, FileType['my.html.yaml'] - assert_not_equal :yaml, FileType['YAML'] - end - - def test_pathname - require 'pathname' - pn = Pathname.new 'test.rb' - assert_equal :ruby, FileType[pn] - dir = Pathname.new '/etc/var/blubb' - assert_equal :ruby, FileType[dir + pn] - assert_equal :cpp, FileType[dir + 'test.cpp'] - end - - def test_no_shebang - dir = './test' - if File.directory? dir - Dir.chdir dir do - assert_equal :c, FileType['test.c'] - end - end - end - - def test_shebang_empty_file - require 'tmpdir' - tmpfile = File.join(Dir.tmpdir, 'bla') - File.open(tmpfile, 'w') { } # touch - assert_equal nil, FileType[tmpfile] - end - - def test_shebang - require 'tmpdir' - tmpfile = File.join(Dir.tmpdir, 'bla') - File.open(tmpfile, 'w') { |f| f.puts '#!/usr/bin/env ruby' } - assert_equal :ruby, FileType[tmpfile, true] - end - -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/helpers/gzip_simple.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/gzip_simple.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -# =GZip Simple -# -# A simplified interface to the gzip library +zlib+ (from the Ruby Standard Library.) -# -# Author: murphy (mail to murphy rubychan de) -# -# Version: 0.2 (2005.may.28) -# -# ==Documentation -# -# See +GZip+ module and the +String+ extensions. -# -module GZip - - require 'zlib' - - # The default zipping level. 7 zips good and fast. - DEFAULT_GZIP_LEVEL = 7 - - # Unzips the given string +s+. - # - # Example: - # require 'gzip_simple' - # print GZip.gunzip(File.read('adresses.gz')) - def GZip.gunzip s - Zlib::Inflate.inflate s - end - - # Zips the given string +s+. - # - # Example: - # require 'gzip_simple' - # File.open('adresses.gz', 'w') do |file - # file.write GZip.gzip('Mum: 0123 456 789', 9) - # end - # - # If you provide a +level+, you can control how strong - # the string is compressed: - # - 0: no compression, only convert to gzip format - # - 1: compress fast - # - 7: compress more, but still fast (default) - # - 8: compress more, slower - # - 9: compress best, very slow - def GZip.gzip s, level = DEFAULT_GZIP_LEVEL - Zlib::Deflate.new(level).deflate s, Zlib::FINISH - end -end - - -# String extensions to use the GZip module. -# -# The methods gzip and gunzip provide an even more simple -# interface to the ZLib: -# -# # create a big string -# x = 'a' * 1000 -# -# # zip it -# x_gz = x.gzip -# -# # test the result -# puts 'Zipped %d bytes to %d bytes.' % [x.size, x_gz.size] -# #-> Zipped 1000 bytes to 19 bytes. -# -# # unzipping works -# p x_gz.gunzip == x #-> true -class String - # Returns the string, unzipped. - # See GZip.gunzip - def gunzip - GZip.gunzip self - end - # Replaces the string with its unzipped value. - # See GZip.gunzip - def gunzip! - replace gunzip - end - - # Returns the string, zipped. - # +level+ is the gzip compression level, see GZip.gzip. - def gzip level = GZip::DEFAULT_GZIP_LEVEL - GZip.gzip self, level - end - # Replaces the string with its zipped value. - # See GZip.gzip. - def gzip!(*args) - replace gzip(*args) - end -end - -if $0 == __FILE__ - eval DATA.read, nil, $0, __LINE__+4 -end - -__END__ -#CODE - -# Testing / Benchmark -x = 'a' * 1000 -x_gz = x.gzip -puts 'Zipped %d bytes to %d bytes.' % [x.size, x_gz.size] #-> Zipped 1000 bytes to 19 bytes. -p x_gz.gunzip == x #-> true - -require 'benchmark' - -INFO = 'packed to %0.3f%%' # :nodoc: - -x = Array.new(100000) { rand(255).chr + 'aaaaaaaaa' + rand(255).chr }.join -Benchmark.bm(10) do |bm| - for level in 0..9 - bm.report "zip #{level}" do - $x = x.gzip level - end - puts INFO % [100.0 * $x.size / x.size] - end - bm.report 'zip' do - $x = x.gzip - end - puts INFO % [100.0 * $x.size / x.size] - bm.report 'unzip' do - $x.gunzip - end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/helpers/plugin.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/plugin.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,349 +0,0 @@ -module CodeRay - -# = PluginHost -# -# A simple subclass plugin system. -# -# Example: -# class Generators < PluginHost -# plugin_path 'app/generators' -# end -# -# class Generator -# extend Plugin -# PLUGIN_HOST = Generators -# end -# -# class FancyGenerator < Generator -# register_for :fancy -# end -# -# Generators[:fancy] #-> FancyGenerator -# # or -# CodeRay.require_plugin 'Generators/fancy' -module PluginHost - - # Raised if Encoders::[] fails because: - # * a file could not be found - # * the requested Encoder is not registered - PluginNotFound = Class.new Exception - HostNotFound = Class.new Exception - - PLUGIN_HOSTS = [] - PLUGIN_HOSTS_BY_ID = {} # dummy hash - - # Loads all plugins using list and load. - def load_all - for plugin in list - load plugin - end - end - - # Returns the Plugin for +id+. - # - # Example: - # yaml_plugin = MyPluginHost[:yaml] - def [] id, *args, &blk - plugin = validate_id(id) - begin - plugin = plugin_hash.[] plugin, *args, &blk - end while plugin.is_a? Symbol - plugin - end - - # Alias for +[]+. - alias load [] - - def require_helper plugin_id, helper_name - path = path_to File.join(plugin_id, helper_name) - require path - end - - class << self - - # Adds the module/class to the PLUGIN_HOSTS list. - def extended mod - PLUGIN_HOSTS << mod - end - - # Warns you that you should not #include this module. - def included mod - warn "#{name} should not be included. Use extend." - end - - # Find the PluginHost for host_id. - def host_by_id host_id - unless PLUGIN_HOSTS_BY_ID.default_proc - ph = Hash.new do |h, a_host_id| - for host in PLUGIN_HOSTS - h[host.host_id] = host - end - h.fetch a_host_id, nil - end - PLUGIN_HOSTS_BY_ID.replace ph - end - PLUGIN_HOSTS_BY_ID[host_id] - end - - end - - # The path where the plugins can be found. - def plugin_path *args - unless args.empty? - @plugin_path = File.expand_path File.join(*args) - load_map - end - @plugin_path - end - - # The host's ID. - # - # If PLUGIN_HOST_ID is not set, it is simply the class name. - def host_id - if self.const_defined? :PLUGIN_HOST_ID - self::PLUGIN_HOST_ID - else - name - end - end - - # Map a plugin_id to another. - # - # Usage: Put this in a file plugin_path/_map.rb. - # - # class MyColorHost < PluginHost - # map :navy => :dark_blue, - # :maroon => :brown, - # :luna => :moon - # end - def map hash - for from, to in hash - from = validate_id from - to = validate_id to - plugin_hash[from] = to unless plugin_hash.has_key? from - end - end - - # Define the default plugin to use when no plugin is found - # for a given id. - # - # See also map. - # - # class MyColorHost < PluginHost - # map :navy => :dark_blue - # default :gray - # end - def default id = nil - if id - id = validate_id id - plugin_hash[nil] = id - else - plugin_hash[nil] - end - end - - # Every plugin must register itself for one or more - # +ids+ by calling register_for, which calls this method. - # - # See Plugin#register_for. - def register plugin, *ids - for id in ids - unless id.is_a? Symbol - raise ArgumentError, - "id must be a Symbol, but it was a #{id.class}" - end - plugin_hash[validate_id(id)] = plugin - end - end - - # A Hash of plugion_id => Plugin pairs. - def plugin_hash - @plugin_hash ||= create_plugin_hash - end - - # Returns an array of all .rb files in the plugin path. - # - # The extension .rb is not included. - def list - Dir[path_to('*')].select do |file| - File.basename(file)[/^(?!_)\w+\.rb$/] - end.map do |file| - File.basename file, '.rb' - end - end - - # Makes a map of all loaded plugins. - def inspect - map = plugin_hash.dup - map.each do |id, plugin| - map[id] = plugin.to_s[/(?>\w+)$/] - end - "#{name}[#{host_id}]#{map.inspect}" - end - -protected - # Created a new plugin list and stores it to @plugin_hash. - def create_plugin_hash - @plugin_hash = - Hash.new do |h, plugin_id| - id = validate_id(plugin_id) - path = path_to id - begin - require path - rescue LoadError => boom - if h.has_key? nil # default plugin - h[id] = h[nil] - else - raise PluginNotFound, 'Could not load plugin %p: %s' % [id, boom] - end - else - # Plugin should have registered by now - unless h.has_key? id - raise PluginNotFound, - "No #{self.name} plugin for #{id.inspect} found in #{path}." - end - end - h[id] - end - end - - # Loads the map file (see map). - # - # This is done automatically when plugin_path is called. - def load_map - mapfile = path_to '_map' - if File.exist? mapfile - require mapfile - elsif $VERBOSE - warn 'no _map.rb found for %s' % name - end - end - - # Returns the Plugin for +id+. - # Use it like Hash#fetch. - # - # Example: - # yaml_plugin = MyPluginHost[:yaml, :default] - def fetch id, *args, &blk - plugin_hash.fetch validate_id(id), *args, &blk - end - - # Returns the expected path to the plugin file for the given id. - def path_to plugin_id - File.join plugin_path, "#{plugin_id}.rb" - end - - # Converts +id+ to a Symbol if it is a String, - # or returns +id+ if it already is a Symbol. - # - # Raises +ArgumentError+ for all other objects, or if the - # given String includes non-alphanumeric characters (\W). - def validate_id id - if id.is_a? Symbol or id.nil? - id - elsif id.is_a? String - if id[/\w+/] == id - id.downcase.to_sym - else - raise ArgumentError, "Invalid id: '#{id}' given." - end - else - raise ArgumentError, - "String or Symbol expected, but #{id.class} given." - end - end - -end - - -# = Plugin -# -# Plugins have to include this module. -# -# IMPORTANT: use extend for this module. -# -# Example: see PluginHost. -module Plugin - - def included mod - warn "#{name} should not be included. Use extend." - end - - # Register this class for the given langs. - # Example: - # class MyPlugin < PluginHost::BaseClass - # register_for :my_id - # ... - # end - # - # See PluginHost.register. - def register_for *ids - plugin_host.register self, *ids - end - - # Returns the title of the plugin, or sets it to the - # optional argument +title+. - def title title = nil - if title - @title = title.to_s - else - @title ||= name[/([^:]+)$/, 1] - end - end - - # The host for this Plugin class. - def plugin_host host = nil - if host and not host.is_a? PluginHost - raise ArgumentError, - "PluginHost expected, but #{host.class} given." - end - self.const_set :PLUGIN_HOST, host if host - self::PLUGIN_HOST - end - - # Require some helper files. - # - # Example: - # - # class MyPlugin < PluginHost::BaseClass - # register_for :my_id - # helper :my_helper - # - # The above example loads the file myplugin/my_helper.rb relative to the - # file in which MyPlugin was defined. - # - # You can also load a helper from a different plugin: - # - # helper 'other_plugin/helper_name' - def helper *helpers - for helper in helpers - if helper.is_a?(String) && helper[/\//] - self::PLUGIN_HOST.require_helper $`, $' - else - self::PLUGIN_HOST.require_helper plugin_id, helper.to_s - end - end - end - - # Returns the pulgin id used by the engine. - def plugin_id - name[/\w+$/].downcase - end - -end - -# Convenience method for plugin loading. -# The syntax used is: -# -# CodeRay.require_plugin '/' -# -# Returns the loaded plugin. -def self.require_plugin path - host_id, plugin_id = path.split '/', 2 - host = PluginHost.host_by_id(host_id) - raise PluginHost::HostNotFound, - "No host for #{host_id.inspect} found." unless host - host.load plugin_id -end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/helpers/word_list.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/word_list.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -module CodeRay - -# = WordList -# -# A Hash subclass designed for mapping word lists to token types. -# -# Copyright (c) 2006 by murphy (Kornelius Kalnbach) -# -# License:: LGPL / ask the author -# Version:: 1.1 (2006-Oct-19) -# -# A WordList is a Hash with some additional features. -# It is intended to be used for keyword recognition. -# -# WordList is highly optimized to be used in Scanners, -# typically to decide whether a given ident is a special token. -# -# For case insensitive words use CaseIgnoringWordList. -# -# Example: -# -# # define word arrays -# RESERVED_WORDS = %w[ -# asm break case continue default do else -# ... -# ] -# -# PREDEFINED_TYPES = %w[ -# int long short char void -# ... -# ] -# -# PREDEFINED_CONSTANTS = %w[ -# EOF NULL ... -# ] -# -# # make a WordList -# IDENT_KIND = WordList.new(:ident). -# add(RESERVED_WORDS, :reserved). -# add(PREDEFINED_TYPES, :pre_type). -# add(PREDEFINED_CONSTANTS, :pre_constant) -# -# ... -# -# def scan_tokens tokens, options -# ... -# -# elsif scan(/[A-Za-z_][A-Za-z_0-9]*/) -# # use it -# kind = IDENT_KIND[match] -# ... -class WordList < Hash - - # Creates a new WordList with +default+ as default value. - # - # You can activate +caching+ to store the results for every [] request. - # - # With caching, methods like +include?+ or +delete+ may no longer behave - # as you expect. Therefore, it is recommended to use the [] method only. - def initialize default = false, caching = false, &block - if block - raise ArgumentError, 'Can\'t combine block with caching.' if caching - super(&block) - else - if caching - super() do |h, k| - h[k] = h.fetch k, default - end - else - super default - end - end - end - - # Add words to the list and associate them with +kind+. - # - # Returns +self+, so you can concat add calls. - def add words, kind = true - words.each do |word| - self[word] = kind - end - self - end - -end - - -# A CaseIgnoringWordList is like a WordList, only that -# keys are compared case-insensitively. -# -# Ignoring the text case is realized by sending the +downcase+ message to -# all keys. -# -# Caching usually makes a CaseIgnoringWordList faster, but it has to be -# activated explicitely. -class CaseIgnoringWordList < WordList - - # Creates a new case-insensitive WordList with +default+ as default value. - # - # You can activate caching to store the results for every [] request. - # This speeds up subsequent lookups for the same word, but also - # uses memory. - def initialize default = false, caching = false - if caching - super(default, false) do |h, k| - h[k] = h.fetch k.downcase, default - end - else - super(default, false) - extend Uncached - end - end - - module Uncached # :nodoc: - def [] key - super(key.downcase) - end - end - - # Add +words+ to the list and associate them with +kind+. - def add words, kind = true - words.each do |word| - self[word.downcase] = kind - end - self - end - -end - -end - -__END__ -# check memory consumption -END { - ObjectSpace.each_object(CodeRay::CaseIgnoringWordList) do |wl| - p wl.inject(0) { |memo, key, value| memo + key.size + 24 } - end -} \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanner.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanner.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,298 +0,0 @@ -module CodeRay - - require 'coderay/helpers/plugin' - - # = Scanners - # - # This module holds the Scanner class and its subclasses. - # For example, the Ruby scanner is named CodeRay::Scanners::Ruby - # can be found in coderay/scanners/ruby. - # - # Scanner also provides methods and constants for the register - # mechanism and the [] method that returns the Scanner class - # belonging to the given lang. - # - # See PluginHost. - module Scanners - extend PluginHost - plugin_path File.dirname(__FILE__), 'scanners' - - require 'strscan' - - # = Scanner - # - # The base class for all Scanners. - # - # It is a subclass of Ruby's great +StringScanner+, which - # makes it easy to access the scanning methods inside. - # - # It is also +Enumerable+, so you can use it like an Array of - # Tokens: - # - # require 'coderay' - # - # c_scanner = CodeRay::Scanners[:c].new "if (*p == '{') nest++;" - # - # for text, kind in c_scanner - # puts text if kind == :operator - # end - # - # # prints: (*==)++; - # - # OK, this is a very simple example :) - # You can also use +map+, +any?+, +find+ and even +sort_by+, - # if you want. - class Scanner < StringScanner - - extend Plugin - plugin_host Scanners - - # Raised if a Scanner fails while scanning - ScanError = Class.new(Exception) - - require 'coderay/helpers/word_list' - - # The default options for all scanner classes. - # - # Define @default_options for subclasses. - DEFAULT_OPTIONS = { :stream => false } - - KINDS_NOT_LOC = [:comment, :doctype] - - class << self - - # Returns if the Scanner can be used in streaming mode. - def streamable? - is_a? Streamable - end - - def normify code - code = code.to_s - if code.respond_to?(:encoding) && (code.encoding.name != 'UTF-8' || !code.valid_encoding?) - code = code.dup - original_encoding = code.encoding - code.force_encoding 'Windows-1252' - unless code.valid_encoding? - code.force_encoding original_encoding - if code.encoding.name == 'UTF-8' - code.encode! 'UTF-16BE', :invalid => :replace, :undef => :replace, :replace => '?' - end - code.encode! 'UTF-8', :invalid => :replace, :undef => :replace, :replace => '?' - end - end - code.to_unix - end - - def file_extension extension = nil - if extension - @file_extension = extension.to_s - else - @file_extension ||= plugin_id.to_s - end - end - - end - -=begin -## Excluded for speed reasons; protected seems to make methods slow. - - # Save the StringScanner methods from being called. - # This would not be useful for highlighting. - strscan_public_methods = - StringScanner.instance_methods - - StringScanner.ancestors[1].instance_methods - protected(*strscan_public_methods) -=end - - # Create a new Scanner. - # - # * +code+ is the input String and is handled by the superclass - # StringScanner. - # * +options+ is a Hash with Symbols as keys. - # It is merged with the default options of the class (you can - # overwrite default options here.) - # * +block+ is the callback for streamed highlighting. - # - # If you set :stream to +true+ in the options, the Scanner uses a - # TokenStream with the +block+ as callback to handle the tokens. - # - # Else, a Tokens object is used. - def initialize code='', options = {}, &block - raise "I am only the basic Scanner class. I can't scan "\ - "anything. :( Use my subclasses." if self.class == Scanner - - @options = self.class::DEFAULT_OPTIONS.merge options - - super Scanner.normify(code) - - @tokens = options[:tokens] - if @options[:stream] - warn "warning in CodeRay::Scanner.new: :stream is set, "\ - "but no block was given" unless block_given? - raise NotStreamableError, self unless kind_of? Streamable - @tokens ||= TokenStream.new(&block) - else - warn "warning in CodeRay::Scanner.new: Block given, "\ - "but :stream is #{@options[:stream]}" if block_given? - @tokens ||= Tokens.new - end - @tokens.scanner = self - - setup - end - - def reset - super - reset_instance - end - - def string= code - code = Scanner.normify(code) - if defined?(RUBY_DESCRIPTION) && RUBY_DESCRIPTION['rubinius 1.0.1'] - reset_state - @string = code - else - super code - end - reset_instance - end - - # More mnemonic accessor name for the input string. - alias code string - alias code= string= - - # Returns the Plugin ID for this scanner. - def lang - self.class.plugin_id - end - - # Scans the code and returns all tokens in a Tokens object. - def tokenize new_string=nil, options = {} - options = @options.merge(options) - self.string = new_string if new_string - @cached_tokens = - if @options[:stream] # :stream must have been set already - reset unless new_string - scan_tokens @tokens, options - @tokens - else - scan_tokens @tokens, options - end - end - - def tokens - @cached_tokens ||= tokenize - end - - # Whether the scanner is in streaming mode. - def streaming? - !!@options[:stream] - end - - # Traverses the tokens. - def each &block - raise ArgumentError, - 'Cannot traverse TokenStream.' if @options[:stream] - tokens.each(&block) - end - include Enumerable - - # The current line position of the scanner. - # - # Beware, this is implemented inefficiently. It should be used - # for debugging only. - def line - string[0..pos].count("\n") + 1 - end - - def column pos = self.pos - return 0 if pos <= 0 - string = string() - if string.respond_to?(:bytesize) && (defined?(@bin_string) || string.bytesize != string.size) - @bin_string ||= string.dup.force_encoding('binary') - string = @bin_string - end - pos - (string.rindex(?\n, pos) || 0) - end - - def marshal_dump - @options - end - - def marshal_load options - @options = options - end - - protected - - # Can be implemented by subclasses to do some initialization - # that has to be done once per instance. - # - # Use reset for initialization that has to be done once per - # scan. - def setup - end - - # This is the central method, and commonly the only one a - # subclass implements. - # - # Subclasses must implement this method; it must return +tokens+ - # and must only use Tokens#<< for storing scanned tokens! - def scan_tokens tokens, options - raise NotImplementedError, - "#{self.class}#scan_tokens not implemented." - end - - def reset_instance - @tokens.clear unless @options[:keep_tokens] - @cached_tokens = nil - @bin_string = nil if defined? @bin_string - end - - # Scanner error with additional status information - def raise_inspect msg, tokens, state = 'No state given!', ambit = 30 - raise ScanError, <<-EOE % [ - - -***ERROR in %s: %s (after %d tokens) - -tokens: -%s - -current line: %d column: %d pos: %d -matched: %p state: %p -bol? = %p, eos? = %p - -surrounding code: -%p ~~ %p - - -***ERROR*** - - EOE - File.basename(caller[0]), - msg, - tokens.size, - tokens.last(10).map { |t| t.inspect }.join("\n"), - line, column, pos, - matched, state, bol?, eos?, - string[pos - ambit, ambit], - string[pos, ambit], - ] - end - - end - - end -end - -class String - # I love this hack. It seems to silence all dos/unix/mac newline problems. - def to_unix - if index ?\r - gsub(/\r\n?/, "\n") - else - self - end - end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/_map.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/_map.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -module CodeRay -module Scanners - - map \ - :h => :c, - :cplusplus => :cpp, - :'c++' => :cpp, - :ecma => :java_script, - :ecmascript => :java_script, - :ecma_script => :java_script, - :irb => :ruby, - :javascript => :java_script, - :js => :java_script, - :nitro => :nitro_xhtml, - :pascal => :delphi, - :plain => :plaintext, - :xhtml => :html, - :yml => :yaml - - default :plain - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/c.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/c.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -module CodeRay -module Scanners - - class C < Scanner - - include Streamable - - register_for :c - file_extension 'c' - - RESERVED_WORDS = [ - 'asm', 'break', 'case', 'continue', 'default', 'do', - 'else', 'enum', 'for', 'goto', 'if', 'return', - 'sizeof', 'struct', 'switch', 'typedef', 'union', 'while', - 'restrict', # added in C99 - ] - - PREDEFINED_TYPES = [ - 'int', 'long', 'short', 'char', - 'signed', 'unsigned', 'float', 'double', - 'bool', 'complex', # added in C99 - ] - - PREDEFINED_CONSTANTS = [ - 'EOF', 'NULL', - 'true', 'false', # added in C99 - ] - DIRECTIVES = [ - 'auto', 'extern', 'register', 'static', 'void', - 'const', 'volatile', # added in C89 - 'inline', # added in C99 - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(DIRECTIVES, :directive). - add(PREDEFINED_CONSTANTS, :pre_constant) - - ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - def scan_tokens tokens, options - - state = :initial - label_expected = true - case_expected = false - label_expected_before_preproc_line = nil - in_preproc_line = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - if in_preproc_line && match != "\\\n" && match.index(?\n) - in_preproc_line = false - label_expected = label_expected_before_preproc_line - end - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - kind = :comment - - elsif match = scan(/ \# \s* if \s* 0 /x) - match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? - kind = :comment - - elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) - label_expected = match =~ /[;\{\}]/ - if case_expected - label_expected = true if match == ':' - case_expected = false - end - kind = :operator - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = IDENT_KIND[match] - if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) - kind = :label - match << matched - else - label_expected = false - if kind == :reserved - case match - when 'case', 'default' - case_expected = true - end - end - end - - elsif scan(/\$/) - kind = :ident - - elsif match = scan(/L?"/) - tokens << [:open, :string] - if match[0] == ?L - tokens << ['L', :modifier] - match = '"' - end - state = :string - kind = :delimiter - - elsif scan(/#[ \t]*(\w*)/) - kind = :preprocessor - in_preproc_line = true - label_expected_before_preproc_line = label_expected - state = :include_expected if self[1] == 'include' - - elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) - label_expected = false - kind = :char - - elsif scan(/0[xX][0-9A-Fa-f]+/) - label_expected = false - kind = :hex - - elsif scan(/(?:0[0-7]+)(?![89.eEfF])/) - label_expected = false - kind = :oct - - elsif scan(/(?:\d+)(?![.eEfF])L?L?/) - label_expected = false - kind = :integer - - elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - label_expected = false - kind = :float - - else - getch - kind = :error - - end - - when :string - if scan(/[^\\\n"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - label_expected = false - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - label_expected = false - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - when :include_expected - if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) - kind = :include - state = :initial - - elsif match = scan(/\s+/) - kind = :space - state = :initial if match.index ?\n - - else - state = :initial - next - - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/cpp.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/cpp.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -module CodeRay -module Scanners - - class CPlusPlus < Scanner - - include Streamable - - register_for :cpp - file_extension 'cpp' - title 'C++' - - # http://www.cppreference.com/wiki/keywords/start - RESERVED_WORDS = [ - 'and', 'and_eq', 'asm', 'bitand', 'bitor', 'break', - 'case', 'catch', 'class', 'compl', 'const_cast', - 'continue', 'default', 'delete', 'do', 'dynamic_cast', 'else', - 'enum', 'export', 'for', 'goto', 'if', 'namespace', 'new', - 'not', 'not_eq', 'or', 'or_eq', 'reinterpret_cast', 'return', - 'sizeof', 'static_cast', 'struct', 'switch', 'template', - 'throw', 'try', 'typedef', 'typeid', 'typename', 'union', - 'while', 'xor', 'xor_eq' - ] - - PREDEFINED_TYPES = [ - 'bool', 'char', 'double', 'float', 'int', 'long', - 'short', 'signed', 'unsigned', 'wchar_t', 'string' - ] - PREDEFINED_CONSTANTS = [ - 'false', 'true', - 'EOF', 'NULL', - ] - PREDEFINED_VARIABLES = [ - 'this' - ] - DIRECTIVES = [ - 'auto', 'const', 'explicit', 'extern', 'friend', 'inline', 'mutable', 'operator', - 'private', 'protected', 'public', 'register', 'static', 'using', 'virtual', 'void', - 'volatile' - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_VARIABLES, :local_variable). - add(DIRECTIVES, :directive). - add(PREDEFINED_CONSTANTS, :pre_constant) - - ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - def scan_tokens tokens, options - - state = :initial - label_expected = true - case_expected = false - label_expected_before_preproc_line = nil - in_preproc_line = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - if in_preproc_line && match != "\\\n" && match.index(?\n) - in_preproc_line = false - label_expected = label_expected_before_preproc_line - end - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - kind = :comment - - elsif match = scan(/ \# \s* if \s* 0 /x) - match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? - kind = :comment - - elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) - label_expected = match =~ /[;\{\}]/ - if case_expected - label_expected = true if match == ':' - case_expected = false - end - kind = :operator - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = IDENT_KIND[match] - if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) - kind = :label - match << matched - else - label_expected = false - if kind == :reserved - case match - when 'class' - state = :class_name_expected - when 'case', 'default' - case_expected = true - end - end - end - - elsif scan(/\$/) - kind = :ident - - elsif match = scan(/L?"/) - tokens << [:open, :string] - if match[0] == ?L - tokens << ['L', :modifier] - match = '"' - end - state = :string - kind = :delimiter - - elsif scan(/#[ \t]*(\w*)/) - kind = :preprocessor - in_preproc_line = true - label_expected_before_preproc_line = label_expected - state = :include_expected if self[1] == 'include' - - elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) - label_expected = false - kind = :char - - elsif scan(/0[xX][0-9A-Fa-f]+/) - label_expected = false - kind = :hex - - elsif scan(/(?:0[0-7]+)(?![89.eEfF])/) - label_expected = false - kind = :oct - - elsif scan(/(?:\d+)(?![.eEfF])L?L?/) - label_expected = false - kind = :integer - - elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - label_expected = false - kind = :float - - else - getch - kind = :error - - end - - when :string - if scan(/[^\\"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - label_expected = false - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - label_expected = false - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - when :include_expected - if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) - kind = :include - state = :initial - - elsif match = scan(/\s+/) - kind = :space - state = :initial if match.index ?\n - - else - state = :initial - next - - end - - when :class_name_expected - if scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = :class - state = :initial - - elsif match = scan(/\s+/) - kind = :space - - else - getch - kind = :error - state = :initial - - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/css.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/css.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +0,0 @@ -module CodeRay -module Scanners - - class CSS < Scanner - - register_for :css - - KINDS_NOT_LOC = [ - :comment, - :class, :pseudo_class, :type, - :constant, :directive, - :key, :value, :operator, :color, :float, - :error, :important, - ] - - module RE - Hex = /[0-9a-fA-F]/ - Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too - Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/ - NMChar = /[-_a-zA-Z0-9]|#{Escape}/ - NMStart = /[_a-zA-Z]|#{Escape}/ - NL = /\r\n|\r|\n|\f/ - String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # FIXME: buggy regexp - String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # FIXME: buggy regexp - String = /#{String1}|#{String2}/ - - HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/ - Color = /#{HexColor}/ - - Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/ - Name = /#{NMChar}+/ - Ident = /-?#{NMStart}#{NMChar}*/ - AtKeyword = /@#{Ident}/ - Percentage = /#{Num}%/ - - reldimensions = %w[em ex px] - absdimensions = %w[in cm mm pt pc] - Unit = Regexp.union(*(reldimensions + absdimensions)) - - Dimension = /#{Num}#{Unit}/ - - Comment = %r! /\* (?: .*? \*/ | .* ) !mx - Function = /(?:url|alpha)\((?:[^)\n\r\f]|\\\))*\)?/ - - Id = /##{Name}/ - Class = /\.#{Name}/ - PseudoClass = /:#{Name}/ - AttributeSelector = /\[[^\]]*\]?/ - - end - - def scan_tokens tokens, options - - value_expected = nil - states = [:initial] - - until eos? - - kind = nil - match = nil - - if scan(/\s+/) - kind = :space - - elsif case states.last - when :initial, :media - if scan(/(?>#{RE::Ident})(?!\()|\*/ox) - kind = :type - elsif scan RE::Class - kind = :class - elsif scan RE::Id - kind = :constant - elsif scan RE::PseudoClass - kind = :pseudo_class - elsif match = scan(RE::AttributeSelector) - # TODO: Improve highlighting inside of attribute selectors. - tokens << [:open, :string] - tokens << [match[0,1], :delimiter] - tokens << [match[1..-2], :content] if match.size > 2 - tokens << [match[-1,1], :delimiter] if match[-1] == ?] - tokens << [:close, :string] - next - elsif match = scan(/@media/) - kind = :directive - states.push :media_before_name - end - - when :block - if scan(/(?>#{RE::Ident})(?!\()/ox) - if value_expected - kind = :value - else - kind = :key - end - end - - when :media_before_name - if scan RE::Ident - kind = :type - states[-1] = :media_after_name - end - - when :media_after_name - if scan(/\{/) - kind = :operator - states[-1] = :media - end - - when :comment - if scan(/(?:[^*\s]|\*(?!\/))+/) - kind = :comment - elsif scan(/\*\//) - kind = :comment - states.pop - elsif scan(/\s+/) - kind = :space - end - - else - raise_inspect 'Unknown state', tokens - - end - - elsif scan(/\/\*/) - kind = :comment - states.push :comment - - elsif scan(/\{/) - value_expected = false - kind = :operator - states.push :block - - elsif scan(/\}/) - value_expected = false - if states.last == :block || states.last == :media - kind = :operator - states.pop - else - kind = :error - end - - elsif match = scan(/#{RE::String}/o) - tokens << [:open, :string] - tokens << [match[0, 1], :delimiter] - tokens << [match[1..-2], :content] if match.size > 2 - tokens << [match[-1, 1], :delimiter] if match.size >= 2 - tokens << [:close, :string] - next - - elsif match = scan(/#{RE::Function}/o) - tokens << [:open, :string] - start = match[/^\w+\(/] - tokens << [start, :delimiter] - if match[-1] == ?) - tokens << [match[start.size..-2], :content] - tokens << [')', :delimiter] - else - tokens << [match[start.size..-1], :content] - end - tokens << [:close, :string] - next - - elsif scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) - kind = :float - - elsif scan(/#{RE::Color}/o) - kind = :color - - elsif scan(/! *important/) - kind = :important - - elsif scan(/rgb\([^()\n]*\)?/) - kind = :color - - elsif scan(/#{RE::AtKeyword}/o) - kind = :directive - - elsif match = scan(/ [+>:;,.=()\/] /x) - if match == ':' - value_expected = true - elsif match == ';' - value_expected = false - end - kind = :operator - - else - getch - kind = :error - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/debug.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/debug.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -module CodeRay -module Scanners - - # = Debug Scanner - class Debug < Scanner - - include Streamable - register_for :debug - file_extension 'raydebug' - title 'CodeRay Token Dump' - - protected - def scan_tokens tokens, options - - opened_tokens = [] - - until eos? - - kind = nil - match = nil - - if scan(/\s+/) - tokens << [matched, :space] - next - - elsif scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) \) /x) - kind = self[1].to_sym - match = self[2].gsub(/\\(.)/, '\1') - - elsif scan(/ (\w+) < /x) - kind = self[1].to_sym - opened_tokens << kind - match = :open - - elsif !opened_tokens.empty? && scan(/ > /x) - kind = opened_tokens.pop || :error - match = :close - - else - kind = :error - getch - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/delphi.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/delphi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -module CodeRay -module Scanners - - class Delphi < Scanner - - register_for :delphi - file_extension 'pas' - - RESERVED_WORDS = [ - 'and', 'array', 'as', 'at', 'asm', 'at', 'begin', 'case', 'class', - 'const', 'constructor', 'destructor', 'dispinterface', 'div', 'do', - 'downto', 'else', 'end', 'except', 'exports', 'file', 'finalization', - 'finally', 'for', 'function', 'goto', 'if', 'implementation', 'in', - 'inherited', 'initialization', 'inline', 'interface', 'is', 'label', - 'library', 'mod', 'nil', 'not', 'object', 'of', 'or', 'out', 'packed', - 'procedure', 'program', 'property', 'raise', 'record', 'repeat', - 'resourcestring', 'set', 'shl', 'shr', 'string', 'then', 'threadvar', - 'to', 'try', 'type', 'unit', 'until', 'uses', 'var', 'while', 'with', - 'xor', 'on' - ] - - DIRECTIVES = [ - 'absolute', 'abstract', 'assembler', 'at', 'automated', 'cdecl', - 'contains', 'deprecated', 'dispid', 'dynamic', 'export', - 'external', 'far', 'forward', 'implements', 'local', - 'near', 'nodefault', 'on', 'overload', 'override', - 'package', 'pascal', 'platform', 'private', 'protected', 'public', - 'published', 'read', 'readonly', 'register', 'reintroduce', - 'requires', 'resident', 'safecall', 'stdcall', 'stored', 'varargs', - 'virtual', 'write', 'writeonly' - ] - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(DIRECTIVES, :directive) - - NAME_FOLLOWS = CaseIgnoringWordList.new(false). - add(%w(procedure function .)) - - private - def scan_tokens tokens, options - - state = :initial - last_token = '' - - until eos? - - kind = nil - match = nil - - if state == :initial - - if scan(/ \s+ /x) - tokens << [matched, :space] - next - - elsif scan(%r! \{ \$ [^}]* \}? | \(\* \$ (?: .*? \*\) | .* ) !mx) - tokens << [matched, :preprocessor] - next - - elsif scan(%r! // [^\n]* | \{ [^}]* \}? | \(\* (?: .*? \*\) | .* ) !mx) - tokens << [matched, :comment] - next - - elsif match = scan(/ <[>=]? | >=? | :=? | [-+=*\/;,@\^|\(\)\[\]] | \.\. /x) - kind = :operator - - elsif match = scan(/\./) - kind = :operator - if last_token == 'end' - tokens << [match, kind] - next - end - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = NAME_FOLLOWS[last_token] ? :ident : IDENT_KIND[match] - - elsif match = scan(/ ' ( [^\n']|'' ) (?:'|$) /x) - tokens << [:open, :char] - tokens << ["'", :delimiter] - tokens << [self[1], :content] - tokens << ["'", :delimiter] - tokens << [:close, :char] - next - - elsif match = scan(/ ' /x) - tokens << [:open, :string] - state = :string - kind = :delimiter - - elsif scan(/ \# (?: \d+ | \$[0-9A-Fa-f]+ ) /x) - kind = :char - - elsif scan(/ \$ [0-9A-Fa-f]+ /x) - kind = :hex - - elsif scan(/ (?: \d+ ) (?![eE]|\.[^.]) /x) - kind = :integer - - elsif scan(/ \d+ (?: \.\d+ (?: [eE][+-]? \d+ )? | [eE][+-]? \d+ ) /x) - kind = :float - - else - kind = :error - getch - - end - - elsif state == :string - if scan(/[^\n']+/) - kind = :content - elsif scan(/''/) - kind = :char - elsif scan(/'/) - tokens << ["'", :delimiter] - tokens << [:close, :string] - state = :initial - next - elsif scan(/\n/) - tokens << [:close, :string] - kind = :error - state = :initial - else - raise "else case \' reached; %p not handled." % peek(1), tokens - end - - else - raise 'else-case reached', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens unless match - - last_token = match - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/diff.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/diff.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -module CodeRay -module Scanners - - class Diff < Scanner - - register_for :diff - title 'diff output' - - def scan_tokens tokens, options - - line_kind = nil - state = :initial - - until eos? - kind = match = nil - - if match = scan(/\n/) - if line_kind - tokens << [:end_line, line_kind] - line_kind = nil - end - tokens << [match, :space] - next - end - - case state - - when :initial - if match = scan(/--- |\+\+\+ |=+|_+/) - tokens << [:begin_line, line_kind = :head] - tokens << [match, :head] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/Index: |Property changes on: /) - tokens << [:begin_line, line_kind = :head] - tokens << [match, :head] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/Added: /) - tokens << [:begin_line, line_kind = :head] - tokens << [match, :head] - next unless match = scan(/.+/) - kind = :plain - state = :added - elsif match = scan(/\\ /) - tokens << [:begin_line, line_kind = :change] - tokens << [match, :change] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/@@(?>[^@\n]*)@@/) - if check(/\n|$/) - tokens << [:begin_line, line_kind = :change] - else - tokens << [:open, :change] - end - tokens << [match[0,2], :change] - tokens << [match[2...-2], :plain] - tokens << [match[-2,2], :change] - tokens << [:close, :change] unless line_kind - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/\+/) - tokens << [:begin_line, line_kind = :insert] - tokens << [match, :insert] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/-/) - tokens << [:begin_line, line_kind = :delete] - tokens << [match, :delete] - next unless match = scan(/.+/) - kind = :plain - elsif scan(/ .*/) - kind = :comment - elsif scan(/.+/) - tokens << [:begin_line, line_kind = :comment] - kind = :plain - else - raise_inspect 'else case rached' - end - - when :added - if match = scan(/ \+/) - tokens << [:begin_line, line_kind = :insert] - tokens << [match, :insert] - next unless match = scan(/.+/) - kind = :plain - else - state = :initial - next - end - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - end - - tokens << [:end_line, line_kind] if line_kind - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/groovy.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/groovy.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -module CodeRay -module Scanners - - load :java - - class Groovy < Java - - include Streamable - register_for :groovy - - # TODO: Check this! - GROOVY_KEYWORDS = %w[ - as assert def in - ] - KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ - case instanceof new return throw typeof while as assert in - ] - GROOVY_MAGIC_VARIABLES = %w[ it ] - - IDENT_KIND = Java::IDENT_KIND.dup. - add(GROOVY_KEYWORDS, :keyword). - add(GROOVY_MAGIC_VARIABLES, :local_variable) - - ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # no 4-byte unicode chars? U[a-fA-F0-9]{8} - REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x - - # TODO: interpretation inside ', ", / - STRING_CONTENT_PATTERN = { - "'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/, - '"' => /[^\\$"\n]+/, - "'''" => /(?>[^\\']+|'(?!''))+/, - '"""' => /(?>[^\\$"]+|"(?!""))+/, - '/' => /[^\\$\/\n]+/, - } - - def scan_tokens tokens, options - - state = :initial - inline_block_stack = [] - inline_block_paren_depth = nil - string_delimiter = nil - import_clause = class_name_follows = last_token = after_def = false - value_expected = true - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - tokens << [match, :space] - if match.index ?\n - import_clause = after_def = false - value_expected = true unless value_expected - end - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - value_expected = true - after_def = false - kind = :comment - - elsif bol? && scan(/ \#!.* /x) - kind = :doctype - - elsif import_clause && scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox) - after_def = value_expected = false - kind = :include - - elsif match = scan(/ #{IDENT} | \[\] /ox) - kind = IDENT_KIND[match] - value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] - if last_token == '.' - kind = :ident - elsif class_name_follows - kind = :class - class_name_follows = false - elsif after_def && check(/\s*[({]/) - kind = :method - after_def = false - elsif kind == :ident && last_token != '?' && check(/:/) - kind = :key - else - class_name_follows = true if match == 'class' || (import_clause && match == 'as') - import_clause = match == 'import' - after_def = true if match == 'def' - end - - elsif scan(/;/) - import_clause = after_def = false - value_expected = true - kind = :operator - - elsif scan(/\{/) - class_name_follows = after_def = false - value_expected = true - kind = :operator - if !inline_block_stack.empty? - inline_block_paren_depth += 1 - end - - # TODO: ~'...', ~"..." and ~/.../ style regexps - elsif match = scan(/ \.\.] | \+\+ | - && | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<>>?=? /x) - value_expected = true - value_expected = :regexp if match == '~' - after_def = false - kind = :operator - - elsif match = scan(/ [)\]}] /x) - value_expected = after_def = false - if !inline_block_stack.empty? && match == '}' - inline_block_paren_depth -= 1 - if inline_block_paren_depth == 0 # closing brace of inline block reached - tokens << [match, :inline_delimiter] - tokens << [:close, :inline] - state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop - next - end - end - kind = :operator - - elsif check(/[\d.]/) - after_def = value_expected = false - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) - kind = :float - elsif scan(/\d+[lLgG]?/) - kind = :integer - end - - elsif match = scan(/'''|"""/) - after_def = value_expected = false - state = :multiline_string - tokens << [:open, :string] - string_delimiter = match - kind = :delimiter - - # TODO: record.'name' - elsif match = scan(/["']/) - after_def = value_expected = false - state = match == '/' ? :regexp : :string - tokens << [:open, state] - string_delimiter = match - kind = :delimiter - - elsif value_expected && (match = scan(/\//)) - after_def = value_expected = false - tokens << [:open, :regexp] - state = :regexp - string_delimiter = '/' - kind = :delimiter - - elsif scan(/ @ #{IDENT} /ox) - after_def = value_expected = false - kind = :annotation - - elsif scan(/\//) - after_def = false - value_expected = true - kind = :operator - - else - getch - kind = :error - - end - - when :string, :regexp, :multiline_string - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - - elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/) - tokens << [match, :delimiter] - if state == :regexp - # TODO: regexp modifiers? s, m, x, i? - modifiers = scan(/[ix]+/) - tokens << [modifiers, :modifier] if modifiers && !modifiers.empty? - end - state = :string if state == :multiline_string - tokens << [:close, state] - string_delimiter = nil - after_def = value_expected = false - state = :initial - next - - elsif (state == :string || state == :multiline_string) && - (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif state == :regexp && scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - - elsif match = scan(/ \$ #{IDENT} /mox) - tokens << [:open, :inline] - tokens << ['$', :inline_delimiter] - match = match[1..-1] - tokens << [match, IDENT_KIND[match]] - tokens << [:close, :inline] - next - elsif match = scan(/ \$ \{ /x) - tokens << [:open, :inline] - tokens << ['${', :inline_delimiter] - inline_block_stack << [state, string_delimiter, inline_block_paren_depth] - inline_block_paren_depth = 1 - state = :initial - next - - elsif scan(/ \$ /mx) - kind = :content - - elsif scan(/ \\. /mx) - kind = :content - - elsif scan(/ \\ | \n /x) - tokens << [:close, state] - kind = :error - after_def = value_expected = false - state = :initial - - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - last_token = match unless [:space, :comment, :doctype].include? kind - - tokens << [match, kind] - - end - - if [:multiline_string, :string, :regexp].include? state - tokens << [:close, state] - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/html.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/html.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -module CodeRay -module Scanners - - # HTML Scanner - class HTML < Scanner - - include Streamable - register_for :html - - KINDS_NOT_LOC = [ - :comment, :doctype, :preprocessor, - :tag, :attribute_name, :operator, - :attribute_value, :delimiter, :content, - :plain, :entity, :error - ] - - ATTR_NAME = /[\w.:-]+/ - ATTR_VALUE_UNQUOTED = ATTR_NAME - TAG_END = /\/?>/ - HEX = /[0-9a-fA-F]/ - ENTITY = / - & - (?: - \w+ - | - \# - (?: - \d+ - | - x#{HEX}+ - ) - ) - ; - /ox - - PLAIN_STRING_CONTENT = { - "'" => /[^&'>\n]+/, - '"' => /[^&">\n]+/, - } - - def reset - super - @state = :initial - end - - private - def setup - @state = :initial - @plain_string_content = nil - end - - def scan_tokens tokens, options - - state = @state - plain_string_content = @plain_string_content - - until eos? - - kind = nil - match = nil - - if scan(/\s+/m) - kind = :space - - else - - case state - - when :initial - if scan(//m) - kind = :comment - elsif scan(//m) - kind = :doctype - elsif scan(/<\?xml.*?\?>/m) - kind = :preprocessor - elsif scan(/<\?.*?\?>|<%.*?%>/m) - kind = :comment - elsif scan(/<\/[-\w.:]*>/m) - kind = :tag - elsif match = scan(/<[-\w.:]+>?/m) - kind = :tag - state = :attribute unless match[-1] == ?> - elsif scan(/[^<>&]+/) - kind = :plain - elsif scan(/#{ENTITY}/ox) - kind = :entity - elsif scan(/[<>&]/) - kind = :error - else - raise_inspect '[BUG] else-case reached with state %p' % [state], tokens - end - - when :attribute - if scan(/#{TAG_END}/o) - kind = :tag - state = :initial - elsif scan(/#{ATTR_NAME}/o) - kind = :attribute_name - state = :attribute_equal - else - kind = :error - getch - end - - when :attribute_equal - if scan(/=/) - kind = :operator - state = :attribute_value - elsif scan(/#{ATTR_NAME}/o) - kind = :attribute_name - elsif scan(/#{TAG_END}/o) - kind = :tag - state = :initial - elsif scan(/./) - kind = :error - state = :attribute - end - - when :attribute_value - if scan(/#{ATTR_VALUE_UNQUOTED}/o) - kind = :attribute_value - state = :attribute - elsif match = scan(/["']/) - tokens << [:open, :string] - state = :attribute_value_string - plain_string_content = PLAIN_STRING_CONTENT[match] - kind = :delimiter - elsif scan(/#{TAG_END}/o) - kind = :tag - state = :initial - else - kind = :error - getch - end - - when :attribute_value_string - if scan(plain_string_content) - kind = :content - elsif scan(/['"]/) - tokens << [matched, :delimiter] - tokens << [:close, :string] - state = :attribute - next - elsif scan(/#{ENTITY}/ox) - kind = :entity - elsif scan(/&/) - kind = :content - elsif scan(/[\n>]/) - tokens << [:close, :string] - kind = :error - state = :initial - end - - else - raise_inspect 'Unknown state: %p' % [state], tokens - - end - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - end - - if options[:keep_state] - @state = state - @plain_string_content = plain_string_content - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -module CodeRay -module Scanners - - class Java < Scanner - - include Streamable - register_for :java - helper :builtin_types - - # http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html - KEYWORDS = %w[ - assert break case catch continue default do else - finally for if instanceof import new package - return switch throw try typeof while - debugger export - ] - RESERVED = %w[ const goto ] - CONSTANTS = %w[ false null true ] - MAGIC_VARIABLES = %w[ this super ] - TYPES = %w[ - boolean byte char class double enum float int interface long - short void - ] << '[]' # because int[] should be highlighted as a type - DIRECTIVES = %w[ - abstract extends final implements native private protected public - static strictfp synchronized throws transient volatile - ] - - IDENT_KIND = WordList.new(:ident). - add(KEYWORDS, :keyword). - add(RESERVED, :reserved). - add(CONSTANTS, :pre_constant). - add(MAGIC_VARIABLES, :local_variable). - add(TYPES, :type). - add(BuiltinTypes::List, :pre_type). - add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception). - add(DIRECTIVES, :directive) - - ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - STRING_CONTENT_PATTERN = { - "'" => /[^\\']+/, - '"' => /[^\\"]+/, - '/' => /[^\\\/]+/, - } - IDENT = /[a-zA-Z_][A-Za-z_0-9]*/ - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - import_clause = class_name_follows = last_token_dot = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - tokens << [match, :space] - next - - elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - tokens << [match, :comment] - next - - elsif import_clause && scan(/ #{IDENT} (?: \. #{IDENT} )* /ox) - kind = :include - - elsif match = scan(/ #{IDENT} | \[\] /ox) - kind = IDENT_KIND[match] - if last_token_dot - kind = :ident - elsif class_name_follows - kind = :class - class_name_follows = false - else - import_clause = true if match == 'import' - class_name_follows = true if match == 'class' || match == 'interface' - end - - elsif scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<>>?=? /x) - kind = :operator - - elsif scan(/;/) - import_clause = false - kind = :operator - - elsif scan(/\{/) - class_name_follows = false - kind = :operator - - elsif check(/[\d.]/) - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) - kind = :float - elsif scan(/\d+[lL]?/) - kind = :integer - end - - elsif match = scan(/["']/) - tokens << [:open, :string] - state = :string - string_delimiter = match - kind = :delimiter - - elsif scan(/ @ #{IDENT} /ox) - kind = :annotation - - else - getch - kind = :error - - end - - when :string - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - elsif match = scan(/["'\/]/) - tokens << [match, :delimiter] - tokens << [:close, state] - string_delimiter = nil - state = :initial - next - elsif state == :string && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - last_token_dot = match == '.' - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, state] - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java/builtin_types.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java/builtin_types.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,419 +0,0 @@ -module CodeRay -module Scanners - - module Java::BuiltinTypes # :nodoc: - - List = %w[ - AbstractAction AbstractBorder AbstractButton AbstractCellEditor AbstractCollection - AbstractColorChooserPanel AbstractDocument AbstractExecutorService AbstractInterruptibleChannel - AbstractLayoutCache AbstractList AbstractListModel AbstractMap AbstractMethodError AbstractPreferences - AbstractQueue AbstractQueuedSynchronizer AbstractSelectableChannel AbstractSelectionKey AbstractSelector - AbstractSequentialList AbstractSet AbstractSpinnerModel AbstractTableModel AbstractUndoableEdit - AbstractWriter AccessControlContext AccessControlException AccessController AccessException Accessible - AccessibleAction AccessibleAttributeSequence AccessibleBundle AccessibleComponent AccessibleContext - AccessibleEditableText AccessibleExtendedComponent AccessibleExtendedTable AccessibleExtendedText - AccessibleHyperlink AccessibleHypertext AccessibleIcon AccessibleKeyBinding AccessibleObject - AccessibleRelation AccessibleRelationSet AccessibleResourceBundle AccessibleRole AccessibleSelection - AccessibleState AccessibleStateSet AccessibleStreamable AccessibleTable AccessibleTableModelChange - AccessibleText AccessibleTextSequence AccessibleValue AccountException AccountExpiredException - AccountLockedException AccountNotFoundException Acl AclEntry AclNotFoundException Action ActionEvent - ActionListener ActionMap ActionMapUIResource Activatable ActivateFailedException ActivationDesc - ActivationException ActivationGroup ActivationGroupDesc ActivationGroupID ActivationGroup_Stub - ActivationID ActivationInstantiator ActivationMonitor ActivationSystem Activator ActiveEvent - ActivityCompletedException ActivityRequiredException Adjustable AdjustmentEvent AdjustmentListener - Adler32 AffineTransform AffineTransformOp AlgorithmParameterGenerator AlgorithmParameterGeneratorSpi - AlgorithmParameters AlgorithmParameterSpec AlgorithmParametersSpi AllPermission AlphaComposite - AlreadyBoundException AlreadyConnectedException AncestorEvent AncestorListener AnnotatedElement - Annotation AnnotationFormatError AnnotationTypeMismatchException AppConfigurationEntry Appendable Applet - AppletContext AppletInitializer AppletStub Arc2D Area AreaAveragingScaleFilter ArithmeticException Array - ArrayBlockingQueue ArrayIndexOutOfBoundsException ArrayList Arrays ArrayStoreException ArrayType - AssertionError AsyncBoxView AsynchronousCloseException AtomicBoolean AtomicInteger AtomicIntegerArray - AtomicIntegerFieldUpdater AtomicLong AtomicLongArray AtomicLongFieldUpdater AtomicMarkableReference - AtomicReference AtomicReferenceArray AtomicReferenceFieldUpdater AtomicStampedReference Attribute - AttributeChangeNotification AttributeChangeNotificationFilter AttributedCharacterIterator - AttributedString AttributeException AttributeInUseException AttributeList AttributeModificationException - AttributeNotFoundException Attributes AttributeSet AttributeSetUtilities AttributeValueExp AudioClip - AudioFileFormat AudioFileReader AudioFileWriter AudioFormat AudioInputStream AudioPermission AudioSystem - AuthenticationException AuthenticationNotSupportedException Authenticator AuthorizeCallback - AuthPermission AuthProvider Autoscroll AWTError AWTEvent AWTEventListener AWTEventListenerProxy - AWTEventMulticaster AWTException AWTKeyStroke AWTPermission BackingStoreException - BadAttributeValueExpException BadBinaryOpValueExpException BadLocationException BadPaddingException - BadStringOperationException BandCombineOp BandedSampleModel BaseRowSet BasicArrowButton BasicAttribute - BasicAttributes BasicBorders BasicButtonListener BasicButtonUI BasicCheckBoxMenuItemUI BasicCheckBoxUI - BasicColorChooserUI BasicComboBoxEditor BasicComboBoxRenderer BasicComboBoxUI BasicComboPopup - BasicControl BasicDesktopIconUI BasicDesktopPaneUI BasicDirectoryModel BasicEditorPaneUI - BasicFileChooserUI BasicFormattedTextFieldUI BasicGraphicsUtils BasicHTML BasicIconFactory - BasicInternalFrameTitlePane BasicInternalFrameUI BasicLabelUI BasicListUI BasicLookAndFeel - BasicMenuBarUI BasicMenuItemUI BasicMenuUI BasicOptionPaneUI BasicPanelUI BasicPasswordFieldUI - BasicPermission BasicPopupMenuSeparatorUI BasicPopupMenuUI BasicProgressBarUI BasicRadioButtonMenuItemUI - BasicRadioButtonUI BasicRootPaneUI BasicScrollBarUI BasicScrollPaneUI BasicSeparatorUI BasicSliderUI - BasicSpinnerUI BasicSplitPaneDivider BasicSplitPaneUI BasicStroke BasicTabbedPaneUI BasicTableHeaderUI - BasicTableUI BasicTextAreaUI BasicTextFieldUI BasicTextPaneUI BasicTextUI BasicToggleButtonUI - BasicToolBarSeparatorUI BasicToolBarUI BasicToolTipUI BasicTreeUI BasicViewportUI BatchUpdateException - BeanContext BeanContextChild BeanContextChildComponentProxy BeanContextChildSupport - BeanContextContainerProxy BeanContextEvent BeanContextMembershipEvent BeanContextMembershipListener - BeanContextProxy BeanContextServiceAvailableEvent BeanContextServiceProvider - BeanContextServiceProviderBeanInfo BeanContextServiceRevokedEvent BeanContextServiceRevokedListener - BeanContextServices BeanContextServicesListener BeanContextServicesSupport BeanContextSupport - BeanDescriptor BeanInfo Beans BevelBorder Bidi BigDecimal BigInteger BinaryRefAddr BindException Binding - BitSet Blob BlockingQueue BlockView BMPImageWriteParam Book Boolean BooleanControl Border BorderFactory - BorderLayout BorderUIResource BoundedRangeModel Box BoxLayout BoxView BreakIterator - BrokenBarrierException Buffer BufferCapabilities BufferedImage BufferedImageFilter BufferedImageOp - BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter BufferOverflowException - BufferStrategy BufferUnderflowException Button ButtonGroup ButtonModel ButtonUI Byte - ByteArrayInputStream ByteArrayOutputStream ByteBuffer ByteChannel ByteLookupTable ByteOrder CachedRowSet - CacheRequest CacheResponse Calendar Callable CallableStatement Callback CallbackHandler - CancelablePrintJob CancellationException CancelledKeyException CannotProceedException - CannotRedoException CannotUndoException Canvas CardLayout Caret CaretEvent CaretListener CellEditor - CellEditorListener CellRendererPane Certificate CertificateEncodingException CertificateException - CertificateExpiredException CertificateFactory CertificateFactorySpi CertificateNotYetValidException - CertificateParsingException CertPath CertPathBuilder CertPathBuilderException CertPathBuilderResult - CertPathBuilderSpi CertPathParameters CertPathTrustManagerParameters CertPathValidator - CertPathValidatorException CertPathValidatorResult CertPathValidatorSpi CertSelector CertStore - CertStoreException CertStoreParameters CertStoreSpi ChangedCharSetException ChangeEvent ChangeListener - Channel Channels Character CharacterCodingException CharacterIterator CharArrayReader CharArrayWriter - CharBuffer CharConversionException CharSequence Charset CharsetDecoder CharsetEncoder CharsetProvider - Checkbox CheckboxGroup CheckboxMenuItem CheckedInputStream CheckedOutputStream Checksum Choice - ChoiceCallback ChoiceFormat Chromaticity Cipher CipherInputStream CipherOutputStream CipherSpi Class - ClassCastException ClassCircularityError ClassDefinition ClassDesc ClassFileTransformer ClassFormatError - ClassLoader ClassLoaderRepository ClassLoadingMXBean ClassNotFoundException Clip Clipboard - ClipboardOwner Clob Cloneable CloneNotSupportedException Closeable ClosedByInterruptException - ClosedChannelException ClosedSelectorException CMMException CoderMalfunctionError CoderResult CodeSigner - CodeSource CodingErrorAction CollationElementIterator CollationKey Collator Collection - CollectionCertStoreParameters Collections Color ColorChooserComponentFactory ColorChooserUI - ColorConvertOp ColorModel ColorSelectionModel ColorSpace ColorSupported ColorType ColorUIResource - ComboBoxEditor ComboBoxModel ComboBoxUI ComboPopup CommunicationException Comparable Comparator - CompilationMXBean Compiler CompletionService Component ComponentAdapter ComponentColorModel - ComponentEvent ComponentInputMap ComponentInputMapUIResource ComponentListener ComponentOrientation - ComponentSampleModel ComponentUI ComponentView Composite CompositeContext CompositeData - CompositeDataSupport CompositeName CompositeType CompositeView CompoundBorder CompoundControl - CompoundEdit CompoundName Compression ConcurrentHashMap ConcurrentLinkedQueue ConcurrentMap - ConcurrentModificationException Condition Configuration ConfigurationException ConfirmationCallback - ConnectException ConnectIOException Connection ConnectionEvent ConnectionEventListener - ConnectionPendingException ConnectionPoolDataSource ConsoleHandler Constructor Container - ContainerAdapter ContainerEvent ContainerListener ContainerOrderFocusTraversalPolicy ContentHandler - ContentHandlerFactory ContentModel Context ContextNotEmptyException ContextualRenderedImageFactory - Control ControlFactory ControllerEventListener ConvolveOp CookieHandler Copies CopiesSupported - CopyOnWriteArrayList CopyOnWriteArraySet CountDownLatch CounterMonitor CounterMonitorMBean CRC32 - CredentialException CredentialExpiredException CredentialNotFoundException CRL CRLException CRLSelector - CropImageFilter CSS CubicCurve2D Currency Cursor Customizer CyclicBarrier DatabaseMetaData DataBuffer - DataBufferByte DataBufferDouble DataBufferFloat DataBufferInt DataBufferShort DataBufferUShort - DataFlavor DataFormatException DatagramChannel DatagramPacket DatagramSocket DatagramSocketImpl - DatagramSocketImplFactory DataInput DataInputStream DataLine DataOutput DataOutputStream DataSource - DataTruncation DatatypeConfigurationException DatatypeConstants DatatypeFactory Date DateFormat - DateFormatSymbols DateFormatter DateTimeAtCompleted DateTimeAtCreation DateTimeAtProcessing - DateTimeSyntax DebugGraphics DecimalFormat DecimalFormatSymbols DefaultBoundedRangeModel - DefaultButtonModel DefaultCaret DefaultCellEditor DefaultColorSelectionModel DefaultComboBoxModel - DefaultDesktopManager DefaultEditorKit DefaultFocusManager DefaultFocusTraversalPolicy DefaultFormatter - DefaultFormatterFactory DefaultHighlighter DefaultKeyboardFocusManager DefaultListCellRenderer - DefaultListModel DefaultListSelectionModel DefaultLoaderRepository DefaultMenuLayout DefaultMetalTheme - DefaultMutableTreeNode DefaultPersistenceDelegate DefaultSingleSelectionModel DefaultStyledDocument - DefaultTableCellRenderer DefaultTableColumnModel DefaultTableModel DefaultTextUI DefaultTreeCellEditor - DefaultTreeCellRenderer DefaultTreeModel DefaultTreeSelectionModel Deflater DeflaterOutputStream Delayed - DelayQueue DelegationPermission Deprecated Descriptor DescriptorAccess DescriptorSupport DESedeKeySpec - DesignMode DESKeySpec DesktopIconUI DesktopManager DesktopPaneUI Destination Destroyable - DestroyFailedException DGC DHGenParameterSpec DHKey DHParameterSpec DHPrivateKey DHPrivateKeySpec - DHPublicKey DHPublicKeySpec Dialog Dictionary DigestException DigestInputStream DigestOutputStream - Dimension Dimension2D DimensionUIResource DirContext DirectColorModel DirectoryManager DirObjectFactory - DirStateFactory DisplayMode DnDConstants Doc DocAttribute DocAttributeSet DocFlavor DocPrintJob Document - DocumentBuilder DocumentBuilderFactory Documented DocumentEvent DocumentFilter DocumentListener - DocumentName DocumentParser DomainCombiner DOMLocator DOMResult DOMSource Double DoubleBuffer - DragGestureEvent DragGestureListener DragGestureRecognizer DragSource DragSourceAdapter - DragSourceContext DragSourceDragEvent DragSourceDropEvent DragSourceEvent DragSourceListener - DragSourceMotionListener Driver DriverManager DriverPropertyInfo DropTarget DropTargetAdapter - DropTargetContext DropTargetDragEvent DropTargetDropEvent DropTargetEvent DropTargetListener DSAKey - DSAKeyPairGenerator DSAParameterSpec DSAParams DSAPrivateKey DSAPrivateKeySpec DSAPublicKey - DSAPublicKeySpec DTD DTDConstants DuplicateFormatFlagsException Duration DynamicMBean ECField ECFieldF2m - ECFieldFp ECGenParameterSpec ECKey ECParameterSpec ECPoint ECPrivateKey ECPrivateKeySpec ECPublicKey - ECPublicKeySpec EditorKit Element ElementIterator ElementType Ellipse2D EllipticCurve EmptyBorder - EmptyStackException EncodedKeySpec Encoder EncryptedPrivateKeyInfo Entity Enum - EnumConstantNotPresentException EnumControl Enumeration EnumMap EnumSet EnumSyntax EOFException Error - ErrorListener ErrorManager EtchedBorder Event EventContext EventDirContext EventHandler EventListener - EventListenerList EventListenerProxy EventObject EventQueue EventSetDescriptor Exception - ExceptionInInitializerError ExceptionListener Exchanger ExecutionException Executor - ExecutorCompletionService Executors ExecutorService ExemptionMechanism ExemptionMechanismException - ExemptionMechanismSpi ExpandVetoException ExportException Expression ExtendedRequest ExtendedResponse - Externalizable FactoryConfigurationError FailedLoginException FeatureDescriptor Fidelity Field - FieldPosition FieldView File FileCacheImageInputStream FileCacheImageOutputStream FileChannel - FileChooserUI FileDescriptor FileDialog FileFilter FileHandler FileImageInputStream - FileImageOutputStream FileInputStream FileLock FileLockInterruptionException FilenameFilter FileNameMap - FileNotFoundException FileOutputStream FilePermission FileReader FileSystemView FileView FileWriter - Filter FilteredImageSource FilteredRowSet FilterInputStream FilterOutputStream FilterReader FilterWriter - Finishings FixedHeightLayoutCache FlatteningPathIterator FlavorEvent FlavorException FlavorListener - FlavorMap FlavorTable Float FloatBuffer FloatControl FlowLayout FlowView Flushable FocusAdapter - FocusEvent FocusListener FocusManager FocusTraversalPolicy Font FontFormatException FontMetrics - FontRenderContext FontUIResource Format FormatConversionProvider FormatFlagsConversionMismatchException - Formattable FormattableFlags Formatter FormatterClosedException FormSubmitEvent FormView Frame Future - FutureTask GapContent GarbageCollectorMXBean GatheringByteChannel GaugeMonitor GaugeMonitorMBean - GeneralPath GeneralSecurityException GenericArrayType GenericDeclaration GenericSignatureFormatError - GlyphJustificationInfo GlyphMetrics GlyphVector GlyphView GradientPaint GraphicAttribute Graphics - Graphics2D GraphicsConfigTemplate GraphicsConfiguration GraphicsDevice GraphicsEnvironment GrayFilter - GregorianCalendar GridBagConstraints GridBagLayout GridLayout Group Guard GuardedObject GZIPInputStream - GZIPOutputStream Handler HandshakeCompletedEvent HandshakeCompletedListener HasControls HashAttributeSet - HashDocAttributeSet HashMap HashPrintJobAttributeSet HashPrintRequestAttributeSet - HashPrintServiceAttributeSet HashSet Hashtable HeadlessException HierarchyBoundsAdapter - HierarchyBoundsListener HierarchyEvent HierarchyListener Highlighter HostnameVerifier HTML HTMLDocument - HTMLEditorKit HTMLFrameHyperlinkEvent HTMLWriter HttpRetryException HttpsURLConnection HttpURLConnection - HyperlinkEvent HyperlinkListener ICC_ColorSpace ICC_Profile ICC_ProfileGray ICC_ProfileRGB Icon - IconUIResource IconView Identity IdentityHashMap IdentityScope IIOByteBuffer IIOException IIOImage - IIOInvalidTreeException IIOMetadata IIOMetadataController IIOMetadataFormat IIOMetadataFormatImpl - IIOMetadataNode IIOParam IIOParamController IIOReadProgressListener IIOReadUpdateListener - IIOReadWarningListener IIORegistry IIOServiceProvider IIOWriteProgressListener IIOWriteWarningListener - IllegalAccessError IllegalAccessException IllegalArgumentException IllegalBlockingModeException - IllegalBlockSizeException IllegalCharsetNameException IllegalClassFormatException - IllegalComponentStateException IllegalFormatCodePointException IllegalFormatConversionException - IllegalFormatException IllegalFormatFlagsException IllegalFormatPrecisionException - IllegalFormatWidthException IllegalMonitorStateException IllegalPathStateException - IllegalSelectorException IllegalStateException IllegalThreadStateException Image ImageCapabilities - ImageConsumer ImageFilter ImageGraphicAttribute ImageIcon ImageInputStream ImageInputStreamImpl - ImageInputStreamSpi ImageIO ImageObserver ImageOutputStream ImageOutputStreamImpl ImageOutputStreamSpi - ImageProducer ImageReader ImageReaderSpi ImageReaderWriterSpi ImageReadParam ImageTranscoder - ImageTranscoderSpi ImageTypeSpecifier ImageView ImageWriteParam ImageWriter ImageWriterSpi - ImagingOpException IncompatibleClassChangeError IncompleteAnnotationException IndexColorModel - IndexedPropertyChangeEvent IndexedPropertyDescriptor IndexOutOfBoundsException Inet4Address Inet6Address - InetAddress InetSocketAddress Inflater InflaterInputStream InheritableThreadLocal Inherited - InitialContext InitialContextFactory InitialContextFactoryBuilder InitialDirContext InitialLdapContext - InlineView InputContext InputEvent InputMap InputMapUIResource InputMethod InputMethodContext - InputMethodDescriptor InputMethodEvent InputMethodHighlight InputMethodListener InputMethodRequests - InputMismatchException InputStream InputStreamReader InputSubset InputVerifier Insets InsetsUIResource - InstanceAlreadyExistsException InstanceNotFoundException InstantiationError InstantiationException - Instrument Instrumentation InsufficientResourcesException IntBuffer Integer IntegerSyntax InternalError - InternalFrameAdapter InternalFrameEvent InternalFrameFocusTraversalPolicy InternalFrameListener - InternalFrameUI InternationalFormatter InterruptedException InterruptedIOException - InterruptedNamingException InterruptibleChannel IntrospectionException Introspector - InvalidActivityException InvalidAlgorithmParameterException InvalidApplicationException - InvalidAttributeIdentifierException InvalidAttributesException InvalidAttributeValueException - InvalidClassException InvalidDnDOperationException InvalidKeyException InvalidKeySpecException - InvalidMarkException InvalidMidiDataException InvalidNameException InvalidObjectException - InvalidOpenTypeException InvalidParameterException InvalidParameterSpecException - InvalidPreferencesFormatException InvalidPropertiesFormatException InvalidRelationIdException - InvalidRelationServiceException InvalidRelationTypeException InvalidRoleInfoException - InvalidRoleValueException InvalidSearchControlsException InvalidSearchFilterException - InvalidTargetObjectTypeException InvalidTransactionException InvocationEvent InvocationHandler - InvocationTargetException IOException ItemEvent ItemListener ItemSelectable Iterable Iterator - IvParameterSpec JApplet JarEntry JarException JarFile JarInputStream JarOutputStream JarURLConnection - JButton JCheckBox JCheckBoxMenuItem JColorChooser JComboBox JComponent JdbcRowSet JDesktopPane JDialog - JEditorPane JFileChooser JFormattedTextField JFrame JInternalFrame JLabel JLayeredPane JList JMenu - JMenuBar JMenuItem JMException JMRuntimeException JMXAuthenticator JMXConnectionNotification - JMXConnector JMXConnectorFactory JMXConnectorProvider JMXConnectorServer JMXConnectorServerFactory - JMXConnectorServerMBean JMXConnectorServerProvider JMXPrincipal JMXProviderException - JMXServerErrorException JMXServiceURL JobAttributes JobHoldUntil JobImpressions JobImpressionsCompleted - JobImpressionsSupported JobKOctets JobKOctetsProcessed JobKOctetsSupported JobMediaSheets - JobMediaSheetsCompleted JobMediaSheetsSupported JobMessageFromOperator JobName JobOriginatingUserName - JobPriority JobPrioritySupported JobSheets JobState JobStateReason JobStateReasons Joinable JoinRowSet - JOptionPane JPanel JPasswordField JPEGHuffmanTable JPEGImageReadParam JPEGImageWriteParam JPEGQTable - JPopupMenu JProgressBar JRadioButton JRadioButtonMenuItem JRootPane JScrollBar JScrollPane JSeparator - JSlider JSpinner JSplitPane JTabbedPane JTable JTableHeader JTextArea JTextComponent JTextField - JTextPane JToggleButton JToolBar JToolTip JTree JViewport JWindow KerberosKey KerberosPrincipal - KerberosTicket Kernel Key KeyAdapter KeyAgreement KeyAgreementSpi KeyAlreadyExistsException - KeyboardFocusManager KeyEvent KeyEventDispatcher KeyEventPostProcessor KeyException KeyFactory - KeyFactorySpi KeyGenerator KeyGeneratorSpi KeyListener KeyManagementException KeyManager - KeyManagerFactory KeyManagerFactorySpi Keymap KeyPair KeyPairGenerator KeyPairGeneratorSpi KeyRep - KeySpec KeyStore KeyStoreBuilderParameters KeyStoreException KeyStoreSpi KeyStroke Label LabelUI - LabelView LanguageCallback LastOwnerException LayeredHighlighter LayoutFocusTraversalPolicy - LayoutManager LayoutManager2 LayoutQueue LDAPCertStoreParameters LdapContext LdapName - LdapReferralException Lease Level LimitExceededException Line Line2D LineBorder LineBreakMeasurer - LineEvent LineListener LineMetrics LineNumberInputStream LineNumberReader LineUnavailableException - LinkageError LinkedBlockingQueue LinkedHashMap LinkedHashSet LinkedList LinkException LinkLoopException - LinkRef List ListCellRenderer ListDataEvent ListDataListener ListenerNotFoundException ListIterator - ListModel ListResourceBundle ListSelectionEvent ListSelectionListener ListSelectionModel ListUI ListView - LoaderHandler Locale LocateRegistry Lock LockSupport Logger LoggingMXBean LoggingPermission LoginContext - LoginException LoginModule LogManager LogRecord LogStream Long LongBuffer LookAndFeel LookupOp - LookupTable Mac MacSpi MalformedInputException MalformedLinkException MalformedObjectNameException - MalformedParameterizedTypeException MalformedURLException ManagementFactory ManagementPermission - ManageReferralControl ManagerFactoryParameters Manifest Map MappedByteBuffer MarshalException - MarshalledObject MaskFormatter Matcher MatchResult Math MathContext MatteBorder MBeanAttributeInfo - MBeanConstructorInfo MBeanException MBeanFeatureInfo MBeanInfo MBeanNotificationInfo MBeanOperationInfo - MBeanParameterInfo MBeanPermission MBeanRegistration MBeanRegistrationException MBeanServer - MBeanServerBuilder MBeanServerConnection MBeanServerDelegate MBeanServerDelegateMBean MBeanServerFactory - MBeanServerForwarder MBeanServerInvocationHandler MBeanServerNotification MBeanServerNotificationFilter - MBeanServerPermission MBeanTrustPermission Media MediaName MediaPrintableArea MediaSize MediaSizeName - MediaTracker MediaTray Member MemoryCacheImageInputStream MemoryCacheImageOutputStream MemoryHandler - MemoryImageSource MemoryManagerMXBean MemoryMXBean MemoryNotificationInfo MemoryPoolMXBean MemoryType - MemoryUsage Menu MenuBar MenuBarUI MenuComponent MenuContainer MenuDragMouseEvent MenuDragMouseListener - MenuElement MenuEvent MenuItem MenuItemUI MenuKeyEvent MenuKeyListener MenuListener MenuSelectionManager - MenuShortcut MessageDigest MessageDigestSpi MessageFormat MetaEventListener MetalBorders MetalButtonUI - MetalCheckBoxIcon MetalCheckBoxUI MetalComboBoxButton MetalComboBoxEditor MetalComboBoxIcon - MetalComboBoxUI MetalDesktopIconUI MetalFileChooserUI MetalIconFactory MetalInternalFrameTitlePane - MetalInternalFrameUI MetalLabelUI MetalLookAndFeel MetalMenuBarUI MetalPopupMenuSeparatorUI - MetalProgressBarUI MetalRadioButtonUI MetalRootPaneUI MetalScrollBarUI MetalScrollButton - MetalScrollPaneUI MetalSeparatorUI MetalSliderUI MetalSplitPaneUI MetalTabbedPaneUI MetalTextFieldUI - MetalTheme MetalToggleButtonUI MetalToolBarUI MetalToolTipUI MetalTreeUI MetaMessage Method - MethodDescriptor MGF1ParameterSpec MidiChannel MidiDevice MidiDeviceProvider MidiEvent MidiFileFormat - MidiFileReader MidiFileWriter MidiMessage MidiSystem MidiUnavailableException MimeTypeParseException - MinimalHTMLWriter MissingFormatArgumentException MissingFormatWidthException MissingResourceException - Mixer MixerProvider MLet MLetMBean ModelMBean ModelMBeanAttributeInfo ModelMBeanConstructorInfo - ModelMBeanInfo ModelMBeanInfoSupport ModelMBeanNotificationBroadcaster ModelMBeanNotificationInfo - ModelMBeanOperationInfo ModificationItem Modifier Monitor MonitorMBean MonitorNotification - MonitorSettingException MouseAdapter MouseDragGestureRecognizer MouseEvent MouseInfo MouseInputAdapter - MouseInputListener MouseListener MouseMotionAdapter MouseMotionListener MouseWheelEvent - MouseWheelListener MultiButtonUI MulticastSocket MultiColorChooserUI MultiComboBoxUI MultiDesktopIconUI - MultiDesktopPaneUI MultiDoc MultiDocPrintJob MultiDocPrintService MultiFileChooserUI - MultiInternalFrameUI MultiLabelUI MultiListUI MultiLookAndFeel MultiMenuBarUI MultiMenuItemUI - MultiOptionPaneUI MultiPanelUI MultiPixelPackedSampleModel MultipleDocumentHandling MultipleMaster - MultiPopupMenuUI MultiProgressBarUI MultiRootPaneUI MultiScrollBarUI MultiScrollPaneUI MultiSeparatorUI - MultiSliderUI MultiSpinnerUI MultiSplitPaneUI MultiTabbedPaneUI MultiTableHeaderUI MultiTableUI - MultiTextUI MultiToolBarUI MultiToolTipUI MultiTreeUI MultiViewportUI MutableAttributeSet - MutableComboBoxModel MutableTreeNode Name NameAlreadyBoundException NameCallback NameClassPair - NameNotFoundException NameParser NamespaceChangeListener NamespaceContext Naming NamingEnumeration - NamingEvent NamingException NamingExceptionEvent NamingListener NamingManager NamingSecurityException - NavigationFilter NegativeArraySizeException NetPermission NetworkInterface NoClassDefFoundError - NoConnectionPendingException NodeChangeEvent NodeChangeListener NoInitialContextException - NoninvertibleTransformException NonReadableChannelException NonWritableChannelException - NoPermissionException NoRouteToHostException NoSuchAlgorithmException NoSuchAttributeException - NoSuchElementException NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException - NoSuchObjectException NoSuchPaddingException NoSuchProviderException NotActiveException - NotBoundException NotCompliantMBeanException NotContextException Notification NotificationBroadcaster - NotificationBroadcasterSupport NotificationEmitter NotificationFilter NotificationFilterSupport - NotificationListener NotificationResult NotOwnerException NotSerializableException NotYetBoundException - NotYetConnectedException NullCipher NullPointerException Number NumberFormat NumberFormatException - NumberFormatter NumberOfDocuments NumberOfInterveningJobs NumberUp NumberUpSupported NumericShaper - OAEPParameterSpec Object ObjectChangeListener ObjectFactory ObjectFactoryBuilder ObjectInput - ObjectInputStream ObjectInputValidation ObjectInstance ObjectName ObjectOutput ObjectOutputStream - ObjectStreamClass ObjectStreamConstants ObjectStreamException ObjectStreamField ObjectView ObjID - Observable Observer OceanTheme OpenDataException OpenMBeanAttributeInfo OpenMBeanAttributeInfoSupport - OpenMBeanConstructorInfo OpenMBeanConstructorInfoSupport OpenMBeanInfo OpenMBeanInfoSupport - OpenMBeanOperationInfo OpenMBeanOperationInfoSupport OpenMBeanParameterInfo - OpenMBeanParameterInfoSupport OpenType OperatingSystemMXBean Operation OperationNotSupportedException - OperationsException Option OptionalDataException OptionPaneUI OrientationRequested OutOfMemoryError - OutputDeviceAssigned OutputKeys OutputStream OutputStreamWriter OverlappingFileLockException - OverlayLayout Override Owner Pack200 Package PackedColorModel Pageable PageAttributes - PagedResultsControl PagedResultsResponseControl PageFormat PageRanges PagesPerMinute PagesPerMinuteColor - Paint PaintContext PaintEvent Panel PanelUI Paper ParagraphView ParameterBlock ParameterDescriptor - ParameterizedType ParameterMetaData ParseException ParsePosition Parser ParserConfigurationException - ParserDelegator PartialResultException PasswordAuthentication PasswordCallback PasswordView Patch - PathIterator Pattern PatternSyntaxException PBEKey PBEKeySpec PBEParameterSpec PDLOverrideSupported - Permission PermissionCollection Permissions PersistenceDelegate PersistentMBean PhantomReference Pipe - PipedInputStream PipedOutputStream PipedReader PipedWriter PixelGrabber PixelInterleavedSampleModel - PKCS8EncodedKeySpec PKIXBuilderParameters PKIXCertPathBuilderResult PKIXCertPathChecker - PKIXCertPathValidatorResult PKIXParameters PlainDocument PlainView Point Point2D PointerInfo Policy - PolicyNode PolicyQualifierInfo Polygon PooledConnection Popup PopupFactory PopupMenu PopupMenuEvent - PopupMenuListener PopupMenuUI Port PortableRemoteObject PortableRemoteObjectDelegate - PortUnreachableException Position Predicate PreferenceChangeEvent PreferenceChangeListener Preferences - PreferencesFactory PreparedStatement PresentationDirection Principal Printable PrinterAbortException - PrinterException PrinterGraphics PrinterInfo PrinterIOException PrinterIsAcceptingJobs PrinterJob - PrinterLocation PrinterMakeAndModel PrinterMessageFromOperator PrinterMoreInfo - PrinterMoreInfoManufacturer PrinterName PrinterResolution PrinterState PrinterStateReason - PrinterStateReasons PrinterURI PrintEvent PrintException PrintGraphics PrintJob PrintJobAdapter - PrintJobAttribute PrintJobAttributeEvent PrintJobAttributeListener PrintJobAttributeSet PrintJobEvent - PrintJobListener PrintQuality PrintRequestAttribute PrintRequestAttributeSet PrintService - PrintServiceAttribute PrintServiceAttributeEvent PrintServiceAttributeListener PrintServiceAttributeSet - PrintServiceLookup PrintStream PrintWriter PriorityBlockingQueue PriorityQueue PrivateClassLoader - PrivateCredentialPermission PrivateKey PrivateMLet PrivilegedAction PrivilegedActionException - PrivilegedExceptionAction Process ProcessBuilder ProfileDataException ProgressBarUI ProgressMonitor - ProgressMonitorInputStream Properties PropertyChangeEvent PropertyChangeListener - PropertyChangeListenerProxy PropertyChangeSupport PropertyDescriptor PropertyEditor - PropertyEditorManager PropertyEditorSupport PropertyPermission PropertyResourceBundle - PropertyVetoException ProtectionDomain ProtocolException Provider ProviderException Proxy ProxySelector - PSource PSSParameterSpec PublicKey PushbackInputStream PushbackReader QName QuadCurve2D Query QueryEval - QueryExp Queue QueuedJobCount Random RandomAccess RandomAccessFile Raster RasterFormatException RasterOp - RC2ParameterSpec RC5ParameterSpec Rdn Readable ReadableByteChannel Reader ReadOnlyBufferException - ReadWriteLock RealmCallback RealmChoiceCallback Receiver Rectangle Rectangle2D RectangularShape - ReentrantLock ReentrantReadWriteLock Ref RefAddr Reference Referenceable ReferenceQueue - ReferenceUriSchemesSupported ReferralException ReflectionException ReflectPermission Refreshable - RefreshFailedException Region RegisterableService Registry RegistryHandler RejectedExecutionException - RejectedExecutionHandler Relation RelationException RelationNotFoundException RelationNotification - RelationService RelationServiceMBean RelationServiceNotRegisteredException RelationSupport - RelationSupportMBean RelationType RelationTypeNotFoundException RelationTypeSupport Remote RemoteCall - RemoteException RemoteObject RemoteObjectInvocationHandler RemoteRef RemoteServer RemoteStub - RenderableImage RenderableImageOp RenderableImageProducer RenderContext RenderedImage - RenderedImageFactory Renderer RenderingHints RepaintManager ReplicateScaleFilter RequestingUserName - RequiredModelMBean RescaleOp ResolutionSyntax Resolver ResolveResult ResourceBundle ResponseCache Result - ResultSet ResultSetMetaData Retention RetentionPolicy ReverbType RGBImageFilter RMIClassLoader - RMIClassLoaderSpi RMIClientSocketFactory RMIConnection RMIConnectionImpl RMIConnectionImpl_Stub - RMIConnector RMIConnectorServer RMIFailureHandler RMIIIOPServerImpl RMIJRMPServerImpl - RMISecurityException RMISecurityManager RMIServer RMIServerImpl RMIServerImpl_Stub - RMIServerSocketFactory RMISocketFactory Robot Role RoleInfo RoleInfoNotFoundException RoleList - RoleNotFoundException RoleResult RoleStatus RoleUnresolved RoleUnresolvedList RootPaneContainer - RootPaneUI RoundingMode RoundRectangle2D RowMapper RowSet RowSetEvent RowSetInternal RowSetListener - RowSetMetaData RowSetMetaDataImpl RowSetReader RowSetWarning RowSetWriter RSAKey RSAKeyGenParameterSpec - RSAMultiPrimePrivateCrtKey RSAMultiPrimePrivateCrtKeySpec RSAOtherPrimeInfo RSAPrivateCrtKey - RSAPrivateCrtKeySpec RSAPrivateKey RSAPrivateKeySpec RSAPublicKey RSAPublicKeySpec RTFEditorKit - RuleBasedCollator Runnable Runtime RuntimeErrorException RuntimeException RuntimeMBeanException - RuntimeMXBean RuntimeOperationsException RuntimePermission SampleModel Sasl SaslClient SaslClientFactory - SaslException SaslServer SaslServerFactory Savepoint SAXParser SAXParserFactory SAXResult SAXSource - SAXTransformerFactory Scanner ScatteringByteChannel ScheduledExecutorService ScheduledFuture - ScheduledThreadPoolExecutor Schema SchemaFactory SchemaFactoryLoader SchemaViolationException Scrollable - Scrollbar ScrollBarUI ScrollPane ScrollPaneAdjustable ScrollPaneConstants ScrollPaneLayout ScrollPaneUI - SealedObject SearchControls SearchResult SecretKey SecretKeyFactory SecretKeyFactorySpi SecretKeySpec - SecureCacheResponse SecureClassLoader SecureRandom SecureRandomSpi Security SecurityException - SecurityManager SecurityPermission Segment SelectableChannel SelectionKey Selector SelectorProvider - Semaphore SeparatorUI Sequence SequenceInputStream Sequencer SerialArray SerialBlob SerialClob - SerialDatalink SerialException Serializable SerializablePermission SerialJavaObject SerialRef - SerialStruct ServerCloneException ServerError ServerException ServerNotActiveException ServerRef - ServerRuntimeException ServerSocket ServerSocketChannel ServerSocketFactory ServiceNotFoundException - ServicePermission ServiceRegistry ServiceUI ServiceUIFactory ServiceUnavailableException Set - SetOfIntegerSyntax Severity Shape ShapeGraphicAttribute SheetCollate Short ShortBuffer - ShortBufferException ShortLookupTable ShortMessage Sides Signature SignatureException SignatureSpi - SignedObject Signer SimpleAttributeSet SimpleBeanInfo SimpleDateFormat SimpleDoc SimpleFormatter - SimpleTimeZone SimpleType SinglePixelPackedSampleModel SingleSelectionModel Size2DSyntax - SizeLimitExceededException SizeRequirements SizeSequence Skeleton SkeletonMismatchException - SkeletonNotFoundException SliderUI Socket SocketAddress SocketChannel SocketException SocketFactory - SocketHandler SocketImpl SocketImplFactory SocketOptions SocketPermission SocketSecurityException - SocketTimeoutException SoftBevelBorder SoftReference SortControl SortedMap SortedSet - SortingFocusTraversalPolicy SortKey SortResponseControl Soundbank SoundbankReader SoundbankResource - Source SourceDataLine SourceLocator SpinnerDateModel SpinnerListModel SpinnerModel SpinnerNumberModel - SpinnerUI SplitPaneUI Spring SpringLayout SQLData SQLException SQLInput SQLInputImpl SQLOutput - SQLOutputImpl SQLPermission SQLWarning SSLContext SSLContextSpi SSLEngine SSLEngineResult SSLException - SSLHandshakeException SSLKeyException SSLPeerUnverifiedException SSLPermission SSLProtocolException - SslRMIClientSocketFactory SslRMIServerSocketFactory SSLServerSocket SSLServerSocketFactory SSLSession - SSLSessionBindingEvent SSLSessionBindingListener SSLSessionContext SSLSocket SSLSocketFactory Stack - StackOverflowError StackTraceElement StandardMBean StartTlsRequest StartTlsResponse StateEdit - StateEditable StateFactory Statement StreamCorruptedException StreamHandler StreamPrintService - StreamPrintServiceFactory StreamResult StreamSource StreamTokenizer StrictMath String StringBuffer - StringBufferInputStream StringBuilder StringCharacterIterator StringContent - StringIndexOutOfBoundsException StringMonitor StringMonitorMBean StringReader StringRefAddr - StringSelection StringTokenizer StringValueExp StringWriter Stroke Struct Stub StubDelegate - StubNotFoundException Style StyleConstants StyleContext StyledDocument StyledEditorKit StyleSheet - Subject SubjectDelegationPermission SubjectDomainCombiner SupportedValuesAttribute SuppressWarnings - SwingConstants SwingPropertyChangeSupport SwingUtilities SyncFactory SyncFactoryException - SyncFailedException SynchronousQueue SyncProvider SyncProviderException SyncResolver SynthConstants - SynthContext Synthesizer SynthGraphicsUtils SynthLookAndFeel SynthPainter SynthStyle SynthStyleFactory - SysexMessage System SystemColor SystemFlavorMap TabableView TabbedPaneUI TabExpander TableCellEditor - TableCellRenderer TableColumn TableColumnModel TableColumnModelEvent TableColumnModelListener - TableHeaderUI TableModel TableModelEvent TableModelListener TableUI TableView TabSet TabStop TabularData - TabularDataSupport TabularType TagElement Target TargetDataLine TargetedNotification Templates - TemplatesHandler TextAction TextArea TextAttribute TextComponent TextEvent TextField TextHitInfo - TextInputCallback TextLayout TextListener TextMeasurer TextOutputCallback TextSyntax TextUI TexturePaint - Thread ThreadDeath ThreadFactory ThreadGroup ThreadInfo ThreadLocal ThreadMXBean ThreadPoolExecutor - Throwable Tie TileObserver Time TimeLimitExceededException TimeoutException Timer - TimerAlarmClockNotification TimerMBean TimerNotification TimerTask Timestamp TimeUnit TimeZone - TitledBorder ToolBarUI Toolkit ToolTipManager ToolTipUI TooManyListenersException Track - TransactionalWriter TransactionRequiredException TransactionRolledbackException Transferable - TransferHandler TransformAttribute Transformer TransformerConfigurationException TransformerException - TransformerFactory TransformerFactoryConfigurationError TransformerHandler Transmitter Transparency - TreeCellEditor TreeCellRenderer TreeExpansionEvent TreeExpansionListener TreeMap TreeModel - TreeModelEvent TreeModelListener TreeNode TreePath TreeSelectionEvent TreeSelectionListener - TreeSelectionModel TreeSet TreeUI TreeWillExpandListener TrustAnchor TrustManager TrustManagerFactory - TrustManagerFactorySpi Type TypeInfoProvider TypeNotPresentException Types TypeVariable UID UIDefaults - UIManager UIResource UndeclaredThrowableException UndoableEdit UndoableEditEvent UndoableEditListener - UndoableEditSupport UndoManager UnexpectedException UnicastRemoteObject UnknownError - UnknownFormatConversionException UnknownFormatFlagsException UnknownGroupException UnknownHostException - UnknownObjectException UnknownServiceException UnmappableCharacterException UnmarshalException - UnmodifiableClassException UnmodifiableSetException UnrecoverableEntryException - UnrecoverableKeyException Unreferenced UnresolvedAddressException UnresolvedPermission - UnsatisfiedLinkError UnsolicitedNotification UnsolicitedNotificationEvent - UnsolicitedNotificationListener UnsupportedAddressTypeException UnsupportedAudioFileException - UnsupportedCallbackException UnsupportedCharsetException UnsupportedClassVersionError - UnsupportedEncodingException UnsupportedFlavorException UnsupportedLookAndFeelException - UnsupportedOperationException URI URIException URIResolver URISyntax URISyntaxException URL - URLClassLoader URLConnection URLDecoder URLEncoder URLStreamHandler URLStreamHandlerFactory - UTFDataFormatException Util UtilDelegate Utilities UUID Validator ValidatorHandler ValueExp ValueHandler - ValueHandlerMultiFormat VariableHeightLayoutCache Vector VerifyError VetoableChangeListener - VetoableChangeListenerProxy VetoableChangeSupport View ViewFactory ViewportLayout ViewportUI - VirtualMachineError Visibility VMID VoiceStatus Void VolatileImage WeakHashMap WeakReference WebRowSet - WildcardType Window WindowAdapter WindowConstants WindowEvent WindowFocusListener WindowListener - WindowStateListener WrappedPlainView WritableByteChannel WritableRaster WritableRenderedImage - WriteAbortedException Writer X500Principal X500PrivateCredential X509Certificate X509CertSelector - X509CRL X509CRLEntry X509CRLSelector X509EncodedKeySpec X509ExtendedKeyManager X509Extension - X509KeyManager X509TrustManager XAConnection XADataSource XAException XAResource Xid XMLConstants - XMLDecoder XMLEncoder XMLFormatter XMLGregorianCalendar XMLParseException XmlReader XmlWriter XPath - XPathConstants XPathException XPathExpression XPathExpressionException XPathFactory - XPathFactoryConfigurationException XPathFunction XPathFunctionException XPathFunctionResolver - XPathVariableResolver ZipEntry ZipException ZipFile ZipInputStream ZipOutputStream ZoneView - ] - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script-0.9.6.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script-0.9.6.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -module CodeRay -module Scanners - - class JavaScript < Scanner - - include Streamable - - register_for :java_script - file_extension 'js' - - # The actual JavaScript keywords. - KEYWORDS = %w[ - break case catch continue default delete do else - finally for function if in instanceof new - return switch throw try typeof var void while with - ] - PREDEFINED_CONSTANTS = %w[ - false null true undefined - ] - - MAGIC_VARIABLES = %w[ this arguments ] # arguments was introduced in JavaScript 1.4 - - KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ - case delete in instanceof new return throw typeof with - ] - - # Reserved for future use. - RESERVED_WORDS = %w[ - abstract boolean byte char class debugger double enum export extends - final float goto implements import int interface long native package - private protected public short static super synchronized throws transient - volatile - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_CONSTANTS, :pre_constant). - add(MAGIC_VARIABLES, :local_variable). - add(KEYWORDS, :keyword) - - ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - REGEXP_ESCAPE = / [bBdDsSwW] /x - STRING_CONTENT_PATTERN = { - "'" => /[^\\']+/, - '"' => /[^\\"]+/, - '/' => /[^\\\/]+/, - } - KEY_CHECK_PATTERN = { - "'" => / [^\\']* (?: \\.? [^\\']* )* '? \s* : /x, - '"' => / [^\\"]* (?: \\.? [^\\"]* )* "? \s* : /x, - } - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - value_expected = true - key_expected = false - function_expected = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - value_expected = true if !value_expected && match.index(?\n) - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - value_expected = true - kind = :comment - - elsif check(/\.?\d/) - key_expected = value_expected = false - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - kind = :float - elsif scan(/\d+/) - kind = :integer - end - - elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim) - # FIXME: scan over nested tags - xml_scanner.tokenize match - value_expected = false - next - - elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x) - value_expected = true - last_operator = match[-1] - key_expected = (last_operator == ?{) || (last_operator == ?,) - function_expected = false - kind = :operator - - elsif scan(/ [)\]}]+ /x) - function_expected = key_expected = value_expected = false - kind = :operator - - elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x) - kind = IDENT_KIND[match] - value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] - # TODO: labels - if kind == :ident - if match.index(?$) # $ allowed inside an identifier - kind = :predefined - elsif function_expected - kind = :function - elsif check(/\s*[=:]\s*function\b/) - kind = :function - elsif key_expected && check(/\s*:/) - kind = :key - end - end - function_expected = (kind == :keyword) && (match == 'function') - key_expected = false - - elsif match = scan(/["']/) - if key_expected && check(KEY_CHECK_PATTERN[match]) - state = :key - else - state = :string - end - tokens << [:open, state] - string_delimiter = match - kind = :delimiter - - elsif value_expected && (match = scan(/\/(?=\S)/)) - tokens << [:open, :regexp] - state = :regexp - string_delimiter = '/' - kind = :delimiter - - elsif scan(/ \/ /x) - value_expected = true - key_expected = false - kind = :operator - - else - getch - kind = :error - - end - - when :string, :regexp, :key - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - elsif match = scan(/["'\/]/) - tokens << [match, :delimiter] - if state == :regexp - modifiers = scan(/[gim]+/) - tokens << [modifiers, :modifier] if modifiers && !modifiers.empty? - end - tokens << [:close, state] - string_delimiter = nil - key_expected = value_expected = false - state = :initial - next - elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif state == :regexp && scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - key_expected = value_expected = false - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if [:string, :regexp].include? state - tokens << [:close, state] - end - - tokens - end - - protected - - def reset_instance - super - @xml_scanner.reset if defined? @xml_scanner - end - - def xml_scanner - @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -module CodeRay -module Scanners - - class JavaScript < Scanner - - include Streamable - - register_for :java_script - file_extension 'js' - - # The actual JavaScript keywords. - KEYWORDS = %w[ - break case catch continue default delete do else - finally for function if in instanceof new - return switch throw try typeof var void while with - ] - PREDEFINED_CONSTANTS = %w[ - false null true undefined - ] - - MAGIC_VARIABLES = %w[ this arguments ] # arguments was introduced in JavaScript 1.4 - - KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ - case delete in instanceof new return throw typeof with - ] - - # Reserved for future use. - RESERVED_WORDS = %w[ - abstract boolean byte char class debugger double enum export extends - final float goto implements import int interface long native package - private protected public short static super synchronized throws transient - volatile - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_CONSTANTS, :pre_constant). - add(MAGIC_VARIABLES, :local_variable). - add(KEYWORDS, :keyword) - - ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - REGEXP_ESCAPE = / [bBdDsSwW] /x - STRING_CONTENT_PATTERN = { - "'" => /[^\\']+/, - '"' => /[^\\"]+/, - '/' => /[^\\\/]+/, - } - KEY_CHECK_PATTERN = { - "'" => / (?> [^\\']* (?: \\. [^\\']* )* ) ' \s* : /mx, - '"' => / (?> [^\\"]* (?: \\. [^\\"]* )* ) " \s* : /mx, - } - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - value_expected = true - key_expected = false - function_expected = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - value_expected = true if !value_expected && match.index(?\n) - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - value_expected = true - kind = :comment - - elsif check(/\.?\d/) - key_expected = value_expected = false - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - kind = :float - elsif scan(/\d+/) - kind = :integer - end - - elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim) - # FIXME: scan over nested tags - xml_scanner.tokenize match - value_expected = false - next - - elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x) - value_expected = true - last_operator = match[-1] - key_expected = (last_operator == ?{) || (last_operator == ?,) - function_expected = false - kind = :operator - - elsif scan(/ [)\]}]+ /x) - function_expected = key_expected = value_expected = false - kind = :operator - - elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x) - kind = IDENT_KIND[match] - value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] - # TODO: labels - if kind == :ident - if match.index(?$) # $ allowed inside an identifier - kind = :predefined - elsif function_expected - kind = :function - elsif check(/\s*[=:]\s*function\b/) - kind = :function - elsif key_expected && check(/\s*:/) - kind = :key - end - end - function_expected = (kind == :keyword) && (match == 'function') - key_expected = false - - elsif match = scan(/["']/) - if key_expected && check(KEY_CHECK_PATTERN[match]) - state = :key - else - state = :string - end - tokens << [:open, state] - string_delimiter = match - kind = :delimiter - - elsif value_expected && (match = scan(/\/(?=\S)/)) - tokens << [:open, :regexp] - state = :regexp - string_delimiter = '/' - kind = :delimiter - - elsif scan(/ \/ /x) - value_expected = true - key_expected = false - kind = :operator - - else - getch - kind = :error - - end - - when :string, :regexp, :key - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - elsif match = scan(/["'\/]/) - tokens << [match, :delimiter] - if state == :regexp - modifiers = scan(/[gim]+/) - tokens << [modifiers, :modifier] if modifiers && !modifiers.empty? - end - tokens << [:close, state] - string_delimiter = nil - key_expected = value_expected = false - state = :initial - next - elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif state == :regexp && scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - key_expected = value_expected = false - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if [:string, :regexp].include? state - tokens << [:close, state] - end - - tokens - end - - protected - - def reset_instance - super - @xml_scanner.reset if defined? @xml_scanner - end - - def xml_scanner - @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -module CodeRay -module Scanners - - class JSON < Scanner - - include Streamable - - register_for :json - file_extension 'json' - - KINDS_NOT_LOC = [ - :float, :char, :content, :delimiter, - :error, :integer, :operator, :value, - ] - - ESCAPE = / [bfnrt\\"\/] /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x - - def scan_tokens tokens, options - - state = :initial - stack = [] - key_expected = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - if match = scan(/ \s+ | \\\n /x) - tokens << [match, :space] - next - elsif match = scan(/ [:,\[{\]}] /x) - kind = :operator - case match - when '{' then stack << :object; key_expected = true - when '[' then stack << :array - when ':' then key_expected = false - when ',' then key_expected = true if stack.last == :object - when '}', ']' then stack.pop # no error recovery, but works for valid JSON - end - elsif match = scan(/ true | false | null /x) - kind = :value - elsif match = scan(/-?(?:0|[1-9]\d*)/) - kind = :integer - if scan(/\.\d+(?:[eE][-+]?\d+)?|[eE][-+]?\d+/) - match << matched - kind = :float - end - elsif match = scan(/"/) - state = key_expected ? :key : :string - tokens << [:open, state] - kind = :delimiter - else - getch - kind = :error - end - - when :string, :key - if scan(/[^\\"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, state] - state = :initial - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if [:string, :key].include? state - tokens << [:close, state] - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/nitro_xhtml.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/nitro_xhtml.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -module CodeRay -module Scanners - - load :html - load :ruby - - # Nitro XHTML Scanner - class NitroXHTML < Scanner - - include Streamable - register_for :nitro_xhtml - file_extension :xhtml - title 'Nitro XHTML' - - KINDS_NOT_LOC = HTML::KINDS_NOT_LOC - - NITRO_RUBY_BLOCK = / - <\?r - (?> - [^\?]* - (?> \?(?!>) [^\?]* )* - ) - (?: \?> )? - | - - (?> - [^<]* - (?> <(?!\/ruby>) [^<]* )* - ) - (?: <\/ruby> )? - | - <% - (?> - [^%]* - (?> %(?!>) [^%]* )* - ) - (?: %> )? - /mx - - NITRO_VALUE_BLOCK = / - \# - (?: - \{ - [^{}]* - (?> - \{ [^}]* \} - (?> [^{}]* ) - )* - \}? - | \| [^|]* \|? - | \( [^)]* \)? - | \[ [^\]]* \]? - | \\ [^\\]* \\? - ) - /x - - NITRO_ENTITY = / - % (?: \#\d+ | \w+ ) ; - / - - START_OF_RUBY = / - (?=[<\#%]) - < (?: \?r | % | ruby> ) - | \# [{(|] - | % (?: \#\d+ | \w+ ) ; - /x - - CLOSING_PAREN = Hash.new do |h, p| - h[p] = p - end.update( { - '(' => ')', - '[' => ']', - '{' => '}', - } ) - - private - - def setup - @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true - @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true - end - - def reset_instance - super - @html_scanner.reset - end - - def scan_tokens tokens, options - - until eos? - - if (match = scan_until(/(?=#{START_OF_RUBY})/o) || scan_until(/\z/)) and not match.empty? - @html_scanner.tokenize match - - elsif match = scan(/#{NITRO_VALUE_BLOCK}/o) - start_tag = match[0,2] - delimiter = CLOSING_PAREN[start_tag[1,1]] - end_tag = match[-1,1] == delimiter ? delimiter : '' - tokens << [:open, :inline] - tokens << [start_tag, :inline_delimiter] - code = match[start_tag.size .. -1 - end_tag.size] - @ruby_scanner.tokenize code - tokens << [end_tag, :inline_delimiter] unless end_tag.empty? - tokens << [:close, :inline] - - elsif match = scan(/#{NITRO_RUBY_BLOCK}/o) - start_tag = '' ? '?>' : '' - tokens << [:open, :inline] - tokens << [start_tag, :inline_delimiter] - code = match[start_tag.size .. -(end_tag.size)-1] - @ruby_scanner.tokenize code - tokens << [end_tag, :inline_delimiter] unless end_tag.empty? - tokens << [:close, :inline] - - elsif entity = scan(/#{NITRO_ENTITY}/o) - tokens << [entity, :entity] - - elsif scan(/%/) - tokens << [matched, :error] - - else - raise_inspect 'else-case reached!', tokens - - end - - end - - tokens - - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/php.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/php.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,533 +0,0 @@ -module CodeRay -module Scanners - - load :html - - # Original by Stefan Walk. - class PHP < Scanner - - register_for :php - file_extension 'php' - - KINDS_NOT_LOC = HTML::KINDS_NOT_LOC - - def setup - @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true - end - - def reset_instance - super - @html_scanner.reset - end - - module Words - - # according to http://www.php.net/manual/en/reserved.keywords.php - KEYWORDS = %w[ - abstract and array as break case catch class clone const continue declare default do else elseif - enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global - goto if implements interface instanceof namespace new or private protected public static switch - throw try use var while xor - cfunction old_function - ] - - TYPES = %w[ int integer float double bool boolean string array object resource ] - - LANGUAGE_CONSTRUCTS = %w[ - die echo empty exit eval include include_once isset list - require require_once return print unset - ] - - CLASSES = %w[ Directory stdClass __PHP_Incomplete_Class exception php_user_filter Closure ] - - # according to http://php.net/quickref.php on 2009-04-21; - # all functions with _ excluded (module functions) and selected additional functions - BUILTIN_FUNCTIONS = %w[ - abs acos acosh addcslashes addslashes aggregate array arsort ascii2ebcdic asin asinh asort assert atan atan2 - atanh basename bcadd bccomp bcdiv bcmod bcmul bcpow bcpowmod bcscale bcsqrt bcsub bin2hex bindec - bindtextdomain bzclose bzcompress bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite - calculhmac ceil chdir checkdate checkdnsrr chgrp chmod chop chown chr chroot clearstatcache closedir closelog - compact constant copy cos cosh count crc32 crypt current date dcgettext dcngettext deaggregate decbin dechex - decoct define defined deg2rad delete dgettext die dirname diskfreespace dl dngettext doubleval each - ebcdic2ascii echo empty end ereg eregi escapeshellarg escapeshellcmd eval exec exit exp explode expm1 extract - fclose feof fflush fgetc fgetcsv fgets fgetss file fileatime filectime filegroup fileinode filemtime fileowner - fileperms filepro filesize filetype floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv - fputs fread frenchtojd fscanf fseek fsockopen fstat ftell ftok ftruncate fwrite getallheaders getcwd getdate - getenv gethostbyaddr gethostbyname gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid - getmyuid getopt getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext - gettimeofday gettype glob gmdate gmmktime gmstrftime gregoriantojd gzclose gzcompress gzdecode gzdeflate - gzencode gzeof gzfile gzgetc gzgets gzgetss gzinflate gzopen gzpassthru gzputs gzread gzrewind gzseek gztell - gzuncompress gzwrite hash header hebrev hebrevc hexdec htmlentities htmlspecialchars hypot iconv idate - implode include intval ip2long iptcembed iptcparse isset - jddayofweek jdmonthname jdtofrench jdtogregorian jdtojewish jdtojulian jdtounix jewishtojd join jpeg2wbmp - juliantojd key krsort ksort lcfirst lchgrp lchown levenshtein link linkinfo list localeconv localtime log - log10 log1p long2ip lstat ltrim mail main max md5 metaphone mhash microtime min mkdir mktime msql natcasesort - natsort next ngettext nl2br nthmac octdec opendir openlog - ord overload pack passthru pathinfo pclose pfsockopen phpcredits phpinfo phpversion pi png2wbmp popen pos pow - prev print printf putenv quotemeta rad2deg rand range rawurldecode rawurlencode readdir readfile readgzfile - readline readlink realpath recode rename require reset rewind rewinddir rmdir round rsort rtrim scandir - serialize setcookie setlocale setrawcookie settype sha1 shuffle signeurlpaiement sin sinh sizeof sleep snmpget - snmpgetnext snmprealwalk snmpset snmpwalk snmpwalkoid sort soundex split spliti sprintf sqrt srand sscanf stat - strcasecmp strchr strcmp strcoll strcspn strftime stripcslashes stripos stripslashes stristr strlen - strnatcasecmp strnatcmp strncasecmp strncmp strpbrk strpos strptime strrchr strrev strripos strrpos strspn - strstr strtok strtolower strtotime strtoupper strtr strval substr symlink syslog system tan tanh tempnam - textdomain time tmpfile touch trim uasort ucfirst ucwords uksort umask uniqid unixtojd unlink unpack - unserialize unset urldecode urlencode usleep usort vfprintf virtual vprintf vsprintf wordwrap - array_change_key_case array_chunk array_combine array_count_values array_diff array_diff_assoc - array_diff_key array_diff_uassoc array_diff_ukey array_fill array_fill_keys array_filter array_flip - array_intersect array_intersect_assoc array_intersect_key array_intersect_uassoc array_intersect_ukey - array_key_exists array_keys array_map array_merge array_merge_recursive array_multisort array_pad - array_pop array_product array_push array_rand array_reduce array_reverse array_search array_shift - array_slice array_splice array_sum array_udiff array_udiff_assoc array_udiff_uassoc array_uintersect - array_uintersect_assoc array_uintersect_uassoc array_unique array_unshift array_values array_walk - array_walk_recursive - assert_options base_convert base64_decode base64_encode - chunk_split class_exists class_implements class_parents - count_chars debug_backtrace debug_print_backtrace debug_zval_dump - error_get_last error_log error_reporting extension_loaded - file_exists file_get_contents file_put_contents load_file - func_get_arg func_get_args func_num_args function_exists - get_browser get_called_class get_cfg_var get_class get_class_methods get_class_vars - get_current_user get_declared_classes get_declared_interfaces get_defined_constants - get_defined_functions get_defined_vars get_extension_funcs get_headers get_html_translation_table - get_include_path get_included_files get_loaded_extensions get_magic_quotes_gpc get_magic_quotes_runtime - get_meta_tags get_object_vars get_parent_class get_required_filesget_resource_type - gc_collect_cycles gc_disable gc_enable gc_enabled - halt_compiler headers_list headers_sent highlight_file highlight_string - html_entity_decode htmlspecialchars_decode - in_array include_once inclued_get_data - is_a is_array is_binary is_bool is_buffer is_callable is_dir is_double is_executable is_file is_finite - is_float is_infinite is_int is_integer is_link is_long is_nan is_null is_numeric is_object is_readable - is_real is_resource is_scalar is_soap_fault is_string is_subclass_of is_unicode is_uploaded_file - is_writable is_writeable - locale_get_default locale_set_default - number_format override_function parse_str parse_url - php_check_syntax php_ini_loaded_file php_ini_scanned_files php_logo_guid php_sapi_name - php_strip_whitespace php_uname - preg_filter preg_grep preg_last_error preg_match preg_match_all preg_quote preg_replace - preg_replace_callback preg_split print_r - require_once register_shutdown_function register_tick_function - set_error_handler set_exception_handler set_file_buffer set_include_path - set_magic_quotes_runtime set_time_limit shell_exec - str_getcsv str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split str_word_count - strip_tags substr_compare substr_count substr_replace - time_nanosleep time_sleep_until - token_get_all token_name trigger_error - unregister_tick_function use_soap_error_handler user_error - utf8_decode utf8_encode var_dump var_export - version_compare - zend_logo_guid zend_thread_id zend_version - create_function call_user_func_array - posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid - posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups - posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid - posix_getpwnam posix_getpwuid posix_getrlimit posix_getsid posix_getuid - posix_initgroups posix_isatty posix_kill posix_mkfifo posix_mknod - posix_setegid posix_seteuid posix_setgid posix_setpgid posix_setsid - posix_setuid posix_strerror posix_times posix_ttyname posix_uname - pcntl_alarm pcntl_exec pcntl_fork pcntl_getpriority pcntl_setpriority - pcntl_signal pcntl_signal_dispatch pcntl_sigprocmask pcntl_sigtimedwait - pcntl_sigwaitinfo pcntl_wait pcntl_waitpid pcntl_wexitstatus pcntl_wifexited - pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig - ] - # TODO: more built-in PHP functions? - - EXCEPTIONS = %w[ - E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING - E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT - ] - - CONSTANTS = %w[ - null true false self parent - __LINE__ __DIR__ __FILE__ __LINE__ - __CLASS__ __NAMESPACE__ __METHOD__ __FUNCTION__ - PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION PHP_ZTS - PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_SIZE DEFAULT_INCLUDE_PATH - PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_LIBDIR PHP_DATADIR - PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX - PHP_OUTPUT_HANDLER_START PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END - __COMPILER_HALT_OFFSET__ - EXTR_OVERWRITE EXTR_SKIP EXTR_PREFIX_SAME EXTR_PREFIX_ALL EXTR_PREFIX_INVALID EXTR_PREFIX_IF_EXISTS - EXTR_IF_EXISTS SORT_ASC SORT_DESC SORT_REGULAR SORT_NUMERIC SORT_STRING CASE_LOWER CASE_UPPER COUNT_NORMAL - COUNT_RECURSIVE ASSERT_ACTIVE ASSERT_CALLBACK ASSERT_BAIL ASSERT_WARNING ASSERT_QUIET_EVAL CONNECTION_ABORTED - CONNECTION_NORMAL CONNECTION_TIMEOUT INI_USER INI_PERDIR INI_SYSTEM INI_ALL M_E M_LOG2E M_LOG10E M_LN2 M_LN10 - M_PI M_PI_2 M_PI_4 M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2 CRYPT_SALT_LENGTH CRYPT_STD_DES CRYPT_EXT_DES - CRYPT_MD5 CRYPT_BLOWFISH DIRECTORY_SEPARATOR SEEK_SET SEEK_CUR SEEK_END LOCK_SH LOCK_EX LOCK_UN LOCK_NB - HTML_SPECIALCHARS HTML_ENTITIES ENT_COMPAT ENT_QUOTES ENT_NOQUOTES INFO_GENERAL INFO_CREDITS - INFO_CONFIGURATION INFO_MODULES INFO_ENVIRONMENT INFO_VARIABLES INFO_LICENSE INFO_ALL CREDITS_GROUP - CREDITS_GENERAL CREDITS_SAPI CREDITS_MODULES CREDITS_DOCS CREDITS_FULLPAGE CREDITS_QA CREDITS_ALL STR_PAD_LEFT - STR_PAD_RIGHT STR_PAD_BOTH PATHINFO_DIRNAME PATHINFO_BASENAME PATHINFO_EXTENSION PATH_SEPARATOR CHAR_MAX - LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_ALL LC_MESSAGES ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 - ABDAY_6 ABDAY_7 DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 ABMON_1 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 - ABMON_7 ABMON_8 ABMON_9 ABMON_10 ABMON_11 ABMON_12 MON_1 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 - MON_10 MON_11 MON_12 AM_STR PM_STR D_T_FMT D_FMT T_FMT T_FMT_AMPM ERA ERA_YEAR ERA_D_T_FMT ERA_D_FMT ERA_T_FMT - ALT_DIGITS INT_CURR_SYMBOL CURRENCY_SYMBOL CRNCYSTR MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING - POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES - N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN DECIMAL_POINT RADIXCHAR THOUSANDS_SEP THOUSEP GROUPING YESEXPR NOEXPR - YESSTR NOSTR CODESET LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG LOG_KERN - LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_LOCAL0 - LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_PID LOG_CONS LOG_ODELAY - LOG_NDELAY LOG_NOWAIT LOG_PERROR - ] - - PREDEFINED = %w[ - $GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV - $_COOKIE $php_errormsg $HTTP_RAW_POST_DATA $http_response_header - $argc $argv - ] - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(KEYWORDS, :reserved). - add(TYPES, :pre_type). - add(LANGUAGE_CONSTRUCTS, :reserved). - add(BUILTIN_FUNCTIONS, :predefined). - add(CLASSES, :pre_constant). - add(EXCEPTIONS, :exception). - add(CONSTANTS, :pre_constant) - - VARIABLE_KIND = WordList.new(:local_variable). - add(PREDEFINED, :predefined) - end - - module RE - - PHP_START = / - ]*?language\s*=\s*"php"[^>]*?> | - ]*?language\s*=\s*'php'[^>]*?> | - <\?php\d? | - <\?(?!xml) - /xi - - PHP_END = %r! - | - \?> - !xi - - HTML_INDICATOR = / ]/i - - IDENTIFIER = /[a-z_\x7f-\xFF][a-z0-9_\x7f-\xFF]*/i - VARIABLE = /\$#{IDENTIFIER}/ - - OPERATOR = / - \.(?!\d)=? | # dot that is not decimal point, string concatenation - && | \|\| | # logic - :: | -> | => | # scope, member, dictionary - \\(?!\n) | # namespace - \+\+ | -- | # increment, decrement - [,;?:()\[\]{}] | # simple delimiters - [-+*\/%&|^]=? | # ordinary math, binary logic, assignment shortcuts - [~$] | # whatever - =& | # reference assignment - [=!]=?=? | <> | # comparison and assignment - <<=? | >>=? | [<>]=? # comparison and shift - /x - - end - - def scan_tokens tokens, options - if string.respond_to?(:encoding) - unless string.encoding == Encoding::ASCII_8BIT - self.string = string.encode Encoding::ASCII_8BIT, - :invalid => :replace, :undef => :replace, :replace => '?' - end - end - - if check(RE::PHP_START) || # starts with #{RE::IDENTIFIER}/o) - tokens << [:open, :inline] - tokens << [match, :local_variable] - tokens << [scan(/->/), :operator] - tokens << [scan(/#{RE::IDENTIFIER}/o), :ident] - tokens << [:close, :inline] - next - elsif check(/->/) - match << scan(/->/) - kind = :error - end - elsif match = scan(/\{/) - if check(/\$/) - kind = :delimiter - states[-1] = [states.last, delimiter] - delimiter = nil - states.push :php - tokens << [:open, :inline] - else - kind = :string - end - elsif scan(/\$\{#{RE::IDENTIFIER}\}/o) - kind = :local_variable - elsif scan(/\$/) - kind = :content - end - - when :class_expected - if scan(/\s+/) - kind = :space - elsif match = scan(/#{RE::IDENTIFIER}/o) - kind = :class - states.pop - else - states.pop - next - end - - when :function_expected - if scan(/\s+/) - kind = :space - elsif scan(/&/) - kind = :operator - elsif match = scan(/#{RE::IDENTIFIER}/o) - kind = :function - states.pop - else - states.pop - next - end - - else - raise_inspect 'Unknown state!', tokens, states - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, states - end - raise_inspect 'Empty token', tokens, states unless match - - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/plaintext.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/plaintext.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -module CodeRay -module Scanners - - class Plaintext < Scanner - - register_for :plaintext, :plain - title 'Plain text' - - include Streamable - - KINDS_NOT_LOC = [:plain] - - def scan_tokens tokens, options - text = (scan_until(/\z/) || '') - tokens << [text, :plain] - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/python.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/python.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -module CodeRay -module Scanners - - # Bases on pygments' PythonLexer, see - # http://dev.pocoo.org/projects/pygments/browser/pygments/lexers/agile.py. - class Python < Scanner - - include Streamable - - register_for :python - file_extension 'py' - - KEYWORDS = [ - 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', - 'del', 'elif', 'else', 'except', 'finally', 'for', - 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', - 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', - 'nonlocal', # new in Python 3 - ] - - OLD_KEYWORDS = [ - 'exec', 'print', # gone in Python 3 - ] - - PREDEFINED_METHODS_AND_TYPES = %w[ - __import__ abs all any apply basestring bin bool buffer - bytearray bytes callable chr classmethod cmp coerce compile - complex delattr dict dir divmod enumerate eval execfile exit - file filter float frozenset getattr globals hasattr hash hex id - input int intern isinstance issubclass iter len list locals - long map max min next object oct open ord pow property range - raw_input reduce reload repr reversed round set setattr slice - sorted staticmethod str sum super tuple type unichr unicode - vars xrange zip - ] - - PREDEFINED_EXCEPTIONS = %w[ - ArithmeticError AssertionError AttributeError - BaseException DeprecationWarning EOFError EnvironmentError - Exception FloatingPointError FutureWarning GeneratorExit IOError - ImportError ImportWarning IndentationError IndexError KeyError - KeyboardInterrupt LookupError MemoryError NameError - NotImplemented NotImplementedError OSError OverflowError - OverflowWarning PendingDeprecationWarning ReferenceError - RuntimeError RuntimeWarning StandardError StopIteration - SyntaxError SyntaxWarning SystemError SystemExit TabError - TypeError UnboundLocalError UnicodeDecodeError - UnicodeEncodeError UnicodeError UnicodeTranslateError - UnicodeWarning UserWarning ValueError Warning ZeroDivisionError - ] - - PREDEFINED_VARIABLES_AND_CONSTANTS = [ - 'False', 'True', 'None', # "keywords" since Python 3 - 'self', 'Ellipsis', 'NotImplemented', - ] - - IDENT_KIND = WordList.new(:ident). - add(KEYWORDS, :keyword). - add(OLD_KEYWORDS, :old_keyword). - add(PREDEFINED_METHODS_AND_TYPES, :predefined). - add(PREDEFINED_VARIABLES_AND_CONSTANTS, :pre_constant). - add(PREDEFINED_EXCEPTIONS, :exception) - - NAME = / [^\W\d] \w* /x - ESCAPE = / [abfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} | N\{[-\w ]+\} /x - - OPERATOR = / - \.\.\. | # ellipsis - \.(?!\d) | # dot but not decimal point - [,;:()\[\]{}] | # simple delimiters - \/\/=? | \*\*=? | # special math - [-+*\/%&|^]=? | # ordinary math and binary logic - [~`] | # binary complement and inspection - <<=? | >>=? | [<>=]=? | != # comparison and assignment - /x - - STRING_DELIMITER_REGEXP = Hash.new do |h, delimiter| - h[delimiter] = Regexp.union delimiter - end - - STRING_CONTENT_REGEXP = Hash.new do |h, delimiter| - h[delimiter] = / [^\\\n]+? (?= \\ | $ | #{Regexp.escape(delimiter)} ) /x - end - - DEF_NEW_STATE = WordList.new(:initial). - add(%w(def), :def_expected). - add(%w(import from), :include_expected). - add(%w(class), :class_expected) - - DESCRIPTOR = / - #{NAME} - (?: \. #{NAME} )* - | \* - /x - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - string_raw = false - import_clause = class_name_follows = last_token_dot = false - unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' - from_import_state = [] - - until eos? - - kind = nil - match = nil - - if state == :string - if scan(STRING_DELIMITER_REGEXP[string_delimiter]) - tokens << [matched, :delimiter] - tokens << [:close, :string] - state = :initial - next - elsif string_delimiter.size == 3 && scan(/\n/) - kind = :content - elsif scan(STRING_CONTENT_REGEXP[string_delimiter]) - kind = :content - elsif !string_raw && scan(/ \\ #{ESCAPE} /ox) - kind = :char - elsif scan(/ \\ #{UNICODE_ESCAPE} /ox) - kind = :char - elsif scan(/ \\ . /x) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens, state - end - - elsif match = scan(/ [ \t]+ | \\\n /x) - tokens << [match, :space] - next - - elsif match = scan(/\n/) - tokens << [match, :space] - state = :initial if state == :include_expected - next - - elsif match = scan(/ \# [^\n]* /mx) - tokens << [match, :comment] - next - - elsif state == :initial - - if scan(/#{OPERATOR}/o) - kind = :operator - - elsif match = scan(/(u?r?|b)?("""|"|'''|')/i) - tokens << [:open, :string] - string_delimiter = self[2] - string_raw = false - modifiers = self[1] - unless modifiers.empty? - string_raw = !!modifiers.index(?r) - tokens << [modifiers, :modifier] - match = string_delimiter - end - state = :string - kind = :delimiter - - # TODO: backticks - - elsif match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) - kind = IDENT_KIND[match] - # TODO: keyword arguments - kind = :ident if last_token_dot - if kind == :old_keyword - kind = check(/\(/) ? :ident : :keyword - elsif kind == :predefined && check(/ *=/) - kind = :ident - elsif kind == :keyword - state = DEF_NEW_STATE[match] - from_import_state << match.to_sym if state == :include_expected - end - - elsif scan(/@[a-zA-Z0-9_.]+[lL]?/) - kind = :decorator - - elsif scan(/0[xX][0-9A-Fa-f]+[lL]?/) - kind = :hex - - elsif scan(/0[bB][01]+[lL]?/) - kind = :bin - - elsif match = scan(/(?:\d*\.\d+|\d+\.\d*)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) - kind = :float - if scan(/[jJ]/) - match << matched - kind = :imaginary - end - - elsif scan(/0[oO][0-7]+|0[0-7]+(?![89.eE])[lL]?/) - kind = :oct - - elsif match = scan(/\d+([lL])?/) - kind = :integer - if self[1] == nil && scan(/[jJ]/) - match << matched - kind = :imaginary - end - - else - getch - kind = :error - - end - - elsif state == :def_expected - state = :initial - if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) - kind = :method - else - next - end - - elsif state == :class_expected - state = :initial - if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) - kind = :class - else - next - end - - elsif state == :include_expected - if match = scan(unicode ? /#{DESCRIPTOR}/uo : /#{DESCRIPTOR}/o) - kind = :include - if match == 'as' - kind = :keyword - from_import_state << :as - elsif from_import_state.first == :from && match == 'import' - kind = :keyword - from_import_state << :import - elsif from_import_state.last == :as - # kind = match[0,1][unicode ? /[[:upper:]]/u : /[[:upper:]]/] ? :class : :method - kind = :ident - from_import_state.pop - elsif IDENT_KIND[match] == :keyword - unscan - match = nil - state = :initial - next - end - elsif match = scan(/,/) - from_import_state.pop if from_import_state.last == :as - kind = :operator - else - from_import_state = [] - state = :initial - next - end - - else - raise_inspect 'Unknown state', tokens, state - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens, state unless match - - last_token_dot = match == '.' - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/rhtml.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/rhtml.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -module CodeRay -module Scanners - - load :html - load :ruby - - # RHTML Scanner - class RHTML < Scanner - - include Streamable - register_for :rhtml - title 'HTML ERB Template' - - KINDS_NOT_LOC = HTML::KINDS_NOT_LOC - - ERB_RUBY_BLOCK = / - <%(?!%)[=-]? - (?> - [^\-%]* # normal* - (?> # special - (?: %(?!>) | -(?!%>) ) - [^\-%]* # normal* - )* - ) - (?: -?%> )? - /x - - START_OF_ERB = / - <%(?!%) - /x - - private - - def setup - @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true - @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true - end - - def reset_instance - super - @html_scanner.reset - end - - def scan_tokens tokens, options - - until eos? - - if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_until(/\z/)) and not match.empty? - @html_scanner.tokenize match - - elsif match = scan(/#{ERB_RUBY_BLOCK}/o) - start_tag = match[/\A<%[-=#]?/] - end_tag = match[/-?%?>?\z/] - tokens << [:open, :inline] - tokens << [start_tag, :inline_delimiter] - code = match[start_tag.size .. -1 - end_tag.size] - if start_tag == '<%#' - tokens << [code, :comment] - else - @ruby_scanner.tokenize code - end - tokens << [end_tag, :inline_delimiter] unless end_tag.empty? - tokens << [:close, :inline] - - else - raise_inspect 'else-case reached!', tokens - end - - end - - tokens - - end - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,444 +0,0 @@ -# encoding: utf-8 -module CodeRay -module Scanners - - # This scanner is really complex, since Ruby _is_ a complex language! - # - # It tries to highlight 100% of all common code, - # and 90% of strange codes. - # - # It is optimized for HTML highlighting, and is not very useful for - # parsing or pretty printing. - # - # For now, I think it's better than the scanners in VIM or Syntax, or - # any highlighter I was able to find, except Caleb's RubyLexer. - # - # I hope it's also better than the rdoc/irb lexer. - class Ruby < Scanner - - include Streamable - - register_for :ruby - file_extension 'rb' - - helper :patterns - - if not defined? EncodingError - EncodingError = Class.new Exception - end - - private - def scan_tokens tokens, options - if string.respond_to?(:encoding) - unless string.encoding == Encoding::UTF_8 - self.string = string.encode Encoding::UTF_8, - :invalid => :replace, :undef => :replace, :replace => '?' - end - unicode = false - else - unicode = exist?(/[^\x00-\x7f]/) - end - - last_token_dot = false - value_expected = true - heredocs = nil - last_state = nil - state = :initial - depth = nil - inline_block_stack = [] - - - patterns = Patterns # avoid constant lookup - - until eos? - match = nil - kind = nil - - if state.instance_of? patterns::StringState -# {{{ - match = scan_until(state.pattern) || scan_until(/\z/) - tokens << [match, :content] unless match.empty? - break if eos? - - if state.heredoc and self[1] # end of heredoc - match = getch.to_s - match << scan_until(/$/) unless eos? - tokens << [match, :delimiter] - tokens << [:close, state.type] - state = state.next_state - next - end - - case match = getch - - when state.delim - if state.paren - state.paren_depth -= 1 - if state.paren_depth > 0 - tokens << [match, :nesting_delimiter] - next - end - end - tokens << [match, :delimiter] - if state.type == :regexp and not eos? - modifiers = scan(/#{patterns::REGEXP_MODIFIERS}/ox) - tokens << [modifiers, :modifier] unless modifiers.empty? - end - tokens << [:close, state.type] - value_expected = false - state = state.next_state - - when '\\' - if state.interpreted - if esc = scan(/ #{patterns::ESCAPE} /ox) - tokens << [match + esc, :char] - else - tokens << [match, :error] - end - else - case m = getch - when state.delim, '\\' - tokens << [match + m, :char] - when nil - tokens << [match, :error] - else - tokens << [match + m, :content] - end - end - - when '#' - case peek(1) - when '{' - inline_block_stack << [state, depth, heredocs] - value_expected = true - state = :initial - depth = 1 - tokens << [:open, :inline] - tokens << [match + getch, :inline_delimiter] - when '$', '@' - tokens << [match, :escape] - last_state = state # scan one token as normal code, then return here - state = :initial - else - raise_inspect 'else-case # reached; #%p not handled' % peek(1), tokens - end - - when state.paren - state.paren_depth += 1 - tokens << [match, :nesting_delimiter] - - when /#{patterns::REGEXP_SYMBOLS}/ox - tokens << [match, :function] - - else - raise_inspect 'else-case " reached; %p not handled, state = %p' % [match, state], tokens - - end - next -# }}} - else -# {{{ - if match = scan(/[ \t\f]+/) - kind = :space - match << scan(/\s*/) unless eos? || heredocs - value_expected = true if match.index(?\n) - tokens << [match, kind] - next - - elsif match = scan(/\\?\n/) - kind = :space - if match == "\n" - value_expected = true - state = :initial if state == :undef_comma_expected - end - if heredocs - unscan # heredoc scanning needs \n at start - state = heredocs.shift - tokens << [:open, state.type] - heredocs = nil if heredocs.empty? - next - else - match << scan(/\s*/) unless eos? - end - tokens << [match, kind] - next - - elsif bol? && match = scan(/\#!.*/) - tokens << [match, :doctype] - next - - elsif match = scan(/\#.*/) or - ( bol? and match = scan(/#{patterns::RUBYDOC_OR_DATA}/o) ) - kind = :comment - tokens << [match, kind] - next - - elsif state == :initial - - # IDENTS # - if match = scan(unicode ? /#{patterns::METHOD_NAME}/uo : - /#{patterns::METHOD_NAME}/o) - if last_token_dot - kind = if match[/^[A-Z]/] and not match?(/\(/) then :constant else :ident end - else - if value_expected != :expect_colon && scan(/:(?= )/) - tokens << [match, :key] - match = ':' - kind = :operator - else - kind = patterns::IDENT_KIND[match] - if kind == :ident - if match[/\A[A-Z]/] and not match[/[!?]$/] and not match?(/\(/) - kind = :constant - end - elsif kind == :reserved - state = patterns::DEF_NEW_STATE[match] - value_expected = :set if patterns::KEYWORDS_EXPECTING_VALUE[match] - end - end - end - value_expected = :set if check(/#{patterns::VALUE_FOLLOWS}/o) - - elsif last_token_dot and match = scan(/#{patterns::METHOD_NAME_OPERATOR}|\(/o) - kind = :ident - value_expected = :set if check(unicode ? /#{patterns::VALUE_FOLLOWS}/uo : - /#{patterns::VALUE_FOLLOWS}/o) - - # OPERATORS # - elsif not last_token_dot and match = scan(/ \.\.\.? | (?:\.|::)() | [,\(\)\[\]\{\}] | ==?=? /x) - if match !~ / [.\)\]\}] /x or match =~ /\.\.\.?/ - value_expected = :set - end - last_token_dot = :set if self[1] - kind = :operator - unless inline_block_stack.empty? - case match - when '{' - depth += 1 - when '}' - depth -= 1 - if depth == 0 # closing brace of inline block reached - state, depth, heredocs = inline_block_stack.pop - heredocs = nil if heredocs && heredocs.empty? - tokens << [match, :inline_delimiter] - kind = :inline - match = :close - end - end - end - - elsif match = scan(/ ['"] /mx) - tokens << [:open, :string] - kind = :delimiter - state = patterns::StringState.new :string, match == '"', match # important for streaming - - elsif match = scan(unicode ? /#{patterns::INSTANCE_VARIABLE}/uo : - /#{patterns::INSTANCE_VARIABLE}/o) - kind = :instance_variable - - elsif value_expected and match = scan(/\//) - tokens << [:open, :regexp] - kind = :delimiter - interpreted = true - state = patterns::StringState.new :regexp, interpreted, match - - # elsif match = scan(/[-+]?#{patterns::NUMERIC}/o) - elsif match = value_expected ? scan(/[-+]?#{patterns::NUMERIC}/o) : scan(/#{patterns::NUMERIC}/o) - kind = self[1] ? :float : :integer - - elsif match = scan(unicode ? /#{patterns::SYMBOL}/uo : - /#{patterns::SYMBOL}/o) - case delim = match[1] - when ?', ?" - tokens << [:open, :symbol] - tokens << [':', :symbol] - match = delim.chr - kind = :delimiter - state = patterns::StringState.new :symbol, delim == ?", match - else - kind = :symbol - end - - elsif match = scan(/ -[>=]? | [+!~^]=? | [*|&]{1,2}=? | >>? /x) - value_expected = :set - kind = :operator - - elsif value_expected and match = scan(unicode ? /#{patterns::HEREDOC_OPEN}/uo : - /#{patterns::HEREDOC_OPEN}/o) - indented = self[1] == '-' - quote = self[3] - delim = self[quote ? 4 : 2] - kind = patterns::QUOTE_TO_TYPE[quote] - tokens << [:open, kind] - tokens << [match, :delimiter] - match = :close - heredoc = patterns::StringState.new kind, quote != '\'', delim, (indented ? :indented : :linestart ) - heredocs ||= [] # create heredocs if empty - heredocs << heredoc - - elsif value_expected and match = scan(/#{patterns::FANCY_START_CORRECT}/o) - kind, interpreted = *patterns::FancyStringType.fetch(self[1]) do - raise_inspect 'Unknown fancy string: %%%p' % k, tokens - end - tokens << [:open, kind] - state = patterns::StringState.new kind, interpreted, self[2] - kind = :delimiter - - elsif value_expected and match = scan(unicode ? /#{patterns::CHARACTER}/uo : - /#{patterns::CHARACTER}/o) - kind = :integer - - elsif match = scan(/ [\/%]=? | <(?:<|=>?)? | [?:;] /x) - value_expected = :set - kind = :operator - - elsif match = scan(/`/) - if last_token_dot - kind = :operator - else - tokens << [:open, :shell] - kind = :delimiter - state = patterns::StringState.new :shell, true, match - end - - elsif match = scan(unicode ? /#{patterns::GLOBAL_VARIABLE}/uo : - /#{patterns::GLOBAL_VARIABLE}/o) - kind = :global_variable - - elsif match = scan(unicode ? /#{patterns::CLASS_VARIABLE}/uo : - /#{patterns::CLASS_VARIABLE}/o) - kind = :class_variable - - else - if !unicode && !string.respond_to?(:encoding) - # check for unicode - debug, $DEBUG = $DEBUG, false - begin - if check(/./mu).size > 1 - # seems like we should try again with unicode - unicode = true - end - rescue - # bad unicode char; use getch - ensure - $DEBUG = debug - end - next if unicode - end - kind = :error - match = scan(unicode ? /./mu : /./m) - - end - - elsif state == :def_expected - state = :initial - if scan(/self\./) - tokens << ['self', :pre_constant] - tokens << ['.', :operator] - end - if match = scan(unicode ? /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : - /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) - kind = :method - else - next - end - - elsif state == :module_expected - if match = scan(/< 1 - state = this_block.first - tokens << [:close, state.type] - end - - tokens - end - - end - -end -end - -# vim:fdm=marker diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby/patterns.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby/patterns.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,252 +0,0 @@ -# encoding: utf-8 -module CodeRay -module Scanners - - module Ruby::Patterns # :nodoc: - - RESERVED_WORDS = %w[ - and def end in or unless begin - defined? ensure module redo super until - BEGIN break do next rescue then - when END case else for retry - while alias class elsif if not return - undef yield - ] - - DEF_KEYWORDS = %w[ def ] - UNDEF_KEYWORDS = %w[ undef ] - ALIAS_KEYWORDS = %w[ alias ] - MODULE_KEYWORDS = %w[ class module ] - DEF_NEW_STATE = WordList.new(:initial). - add(DEF_KEYWORDS, :def_expected). - add(UNDEF_KEYWORDS, :undef_expected). - add(ALIAS_KEYWORDS, :alias_expected). - add(MODULE_KEYWORDS, :module_expected) - - PREDEFINED_CONSTANTS = %w[ - nil true false self - DATA ARGV ARGF - __FILE__ __LINE__ __ENCODING__ - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_CONSTANTS, :pre_constant) - - if /\w/u === '∑' - # MRI 1.8.6, 1.8.7 - IDENT = /[^\W\d]\w*/ - else - if //.respond_to? :encoding - # MRI 1.9.1, 1.9.2 - IDENT = Regexp.new '[\p{L}\p{M}\p{Pc}\p{Sm}&&[^\x00-\x40\x5b-\x5e\x60\x7b-\x7f]][\p{L}\p{M}\p{N}\p{Pc}\p{Sm}&&[^\x00-\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\x7f]]*' - else - # JRuby, Rubinius - IDENT = /[^\x00-\x40\x5b-\x5e\x60\x7b-\x7f][^\x00-\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\x7f]*/ - end - end - - METHOD_NAME = / #{IDENT} [?!]? /ox - METHOD_NAME_OPERATOR = / - \*\*? # multiplication and power - | [-+~]@? # plus, minus, tilde with and without at sign - | [\/%&|^`] # division, modulo or format strings, and, or, xor, system - | \[\]=? # array getter and setter - | << | >> # append or shift left, shift right - | <=?>? | >=? # comparison, rocket operator - | ===? | =~ # simple equality, case equality, match - | ![~=@]? # negation with and without at sign, not-equal and not-match - /ox - METHOD_NAME_EX = / #{IDENT} (?:[?!]|=(?!>))? | #{METHOD_NAME_OPERATOR} /ox - INSTANCE_VARIABLE = / @ #{IDENT} /ox - CLASS_VARIABLE = / @@ #{IDENT} /ox - OBJECT_VARIABLE = / @@? #{IDENT} /ox - GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox - PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox - VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox - - QUOTE_TO_TYPE = { - '`' => :shell, - '/'=> :regexp, - } - QUOTE_TO_TYPE.default = :string - - REGEXP_MODIFIERS = /[mixounse]*/ - REGEXP_SYMBOLS = /[|?*+(){}\[\].^$]/ - - DECIMAL = /\d+(?:_\d+)*/ - OCTAL = /0_?[0-7]+(?:_[0-7]+)*/ - HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/ - BINARY = /0b[01]+(?:_[01]+)*/ - - EXPONENT = / [eE] [+-]? #{DECIMAL} /ox - FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox - FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox - NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox - - SYMBOL = / - : - (?: - #{METHOD_NAME_EX} - | #{PREFIX_VARIABLE} - | ['"] - ) - /ox - METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox - - SIMPLE_ESCAPE = / - [abefnrstv] - | [0-7]{1,3} - | x[0-9A-Fa-f]{1,2} - | .? - /mx - - CONTROL_META_ESCAPE = / - (?: M-|C-|c ) - (?: \\ (?: M-|C-|c ) )* - (?: [^\\] | \\ #{SIMPLE_ESCAPE} )? - /mox - - ESCAPE = / - #{CONTROL_META_ESCAPE} | #{SIMPLE_ESCAPE} - /mox - - CHARACTER = / - \? - (?: - [^\s\\] - | \\ #{ESCAPE} - ) - /mox - - # NOTE: This is not completely correct, but - # nobody needs heredoc delimiters ending with \n. - # Also, delimiters starting with numbers are allowed. - # but they are more often than not a false positive. - HEREDOC_OPEN = / - << (-)? # $1 = float - (?: - ( #{IDENT} ) # $2 = delim - | - ( ["'`\/] ) # $3 = quote, type - ( [^\n]*? ) \3 # $4 = delim - ) - /mx - - RUBYDOC = / - =begin (?!\S) - .*? - (?: \Z | ^=end (?!\S) [^\n]* ) - /mx - - DATA = / - __END__$ - .*? - (?: \Z | (?=^\#CODE) ) - /mx - - # Checks for a valid value to follow. This enables - # value_expected in method calls without parentheses. - VALUE_FOLLOWS = / - (?>[ \t\f\v]+) - (?: - [%\/][^\s=] - | <<-?\S - | [-+] \d - | #{CHARACTER} - ) - /x - KEYWORDS_EXPECTING_VALUE = WordList.new.add(%w[ - and end in or unless begin - defined? ensure redo super until - break do next rescue then - when case else for retry - while elsif if not return - yield - ]) - - RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo - - RDOC_DATA_START = / ^=begin (?!\S) | ^__END__$ /x - - FANCY_START_CORRECT = / % ( [qQwWxsr] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /mx - - FancyStringType = { - 'q' => [:string, false], - 'Q' => [:string, true], - 'r' => [:regexp, true], - 's' => [:symbol, false], - 'x' => [:shell, true] - } - FancyStringType['w'] = FancyStringType['q'] - FancyStringType['W'] = FancyStringType[''] = FancyStringType['Q'] - - class StringState < Struct.new :type, :interpreted, :delim, :heredoc, - :paren, :paren_depth, :pattern, :next_state - - CLOSING_PAREN = Hash[ *%w[ - ( ) - [ ] - < > - { } - ] ] - - CLOSING_PAREN.each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with << - OPENING_PAREN = CLOSING_PAREN.invert - - STRING_PATTERN = Hash.new do |h, k| - delim, interpreted = *k - delim_pattern = Regexp.escape(delim.dup) # dup: workaround for old Ruby - if closing_paren = CLOSING_PAREN[delim] - delim_pattern = delim_pattern[0..-1] if defined? JRUBY_VERSION # JRuby fix - delim_pattern << Regexp.escape(closing_paren) - end - delim_pattern << '\\\\' unless delim == '\\' - - special_escapes = - case interpreted - when :regexp_symbols - '| ' + REGEXP_SYMBOLS.source - when :words - '| \s' - end - - h[k] = - if interpreted and not delim == '#' - / (?= [#{delim_pattern}] | \# [{$@] #{special_escapes} ) /mx - else - / (?= [#{delim_pattern}] #{special_escapes} ) /mx - end - end - - HEREDOC_PATTERN = Hash.new do |h, k| - delim, interpreted, indented = *k - delim_pattern = Regexp.escape(delim.dup) # dup: workaround for old Ruby - delim_pattern = / \n #{ '(?>[\ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x - h[k] = - if interpreted - / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc - else - / (?= #{delim_pattern}() | \\ ) /mx - end - end - - def initialize kind, interpreted, delim, heredoc = false - if heredoc - pattern = HEREDOC_PATTERN[ [delim, interpreted, heredoc == :indented] ] - delim = nil - else - pattern = STRING_PATTERN[ [delim, interpreted] ] - if paren = CLOSING_PAREN[delim] - delim, paren = paren, delim - paren_depth = 1 - end - end - super kind, interpreted, delim, heredoc, paren, paren_depth, pattern, :initial - end - end unless defined? StringState - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/scheme.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/scheme.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -module CodeRay - module Scanners - - # Scheme scanner for CodeRay (by closure). - # Thanks to murphy for putting CodeRay into public. - class Scheme < Scanner - - # TODO: function defs - # TODO: built-in functions - - register_for :scheme - file_extension 'scm' - - CORE_FORMS = %w[ - lambda let let* letrec syntax-case define-syntax let-syntax - letrec-syntax begin define quote if or and cond case do delay - quasiquote set! cons force call-with-current-continuation call/cc - ] - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(CORE_FORMS, :reserved) - - #IDENTIFIER_INITIAL = /[a-z!@\$%&\*\/\:<=>\?~_\^]/i - #IDENTIFIER_SUBSEQUENT = /#{IDENTIFIER_INITIAL}|\d|\.|\+|-/ - #IDENTIFIER = /#{IDENTIFIER_INITIAL}#{IDENTIFIER_SUBSEQUENT}*|\+|-|\.{3}/ - IDENTIFIER = /[a-zA-Z!@$%&*\/:<=>?~_^][\w!@$%&*\/:<=>?~^.+\-]*|[+-]|\.\.\./ - DIGIT = /\d/ - DIGIT10 = DIGIT - DIGIT16 = /[0-9a-f]/i - DIGIT8 = /[0-7]/ - DIGIT2 = /[01]/ - RADIX16 = /\#x/i - RADIX8 = /\#o/i - RADIX2 = /\#b/i - RADIX10 = /\#d/i - EXACTNESS = /#i|#e/i - SIGN = /[\+-]?/ - EXP_MARK = /[esfdl]/i - EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/ - SUFFIX = /#{EXP}?/ - PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/ - PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/ - PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/ - PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/ - UINT10 = /#{DIGIT10}+#*/ - UINT16 = /#{DIGIT16}+#*/ - UINT8 = /#{DIGIT8}+#*/ - UINT2 = /#{DIGIT2}+#*/ - DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/ - UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/ - UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/ - UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/ - UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/ - REAL10 = /#{SIGN}#{UREAL10}/ - REAL16 = /#{SIGN}#{UREAL16}/ - REAL8 = /#{SIGN}#{UREAL8}/ - REAL2 = /#{SIGN}#{UREAL2}/ - IMAG10 = /i|#{UREAL10}i/ - IMAG16 = /i|#{UREAL16}i/ - IMAG8 = /i|#{UREAL8}i/ - IMAG2 = /i|#{UREAL2}i/ - COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/ - COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/ - COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/ - COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/ - NUM10 = /#{PREFIX10}?#{COMPLEX10}/ - NUM16 = /#{PREFIX16}#{COMPLEX16}/ - NUM8 = /#{PREFIX8}#{COMPLEX8}/ - NUM2 = /#{PREFIX2}#{COMPLEX2}/ - NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/ - - private - def scan_tokens tokens,options - - state = :initial - ident_kind = IDENT_KIND - - until eos? - kind = match = nil - - case state - when :initial - if scan(/ \s+ | \\\n /x) - kind = :space - elsif scan(/['\(\[\)\]]|#\(/) - kind = :operator_fat - elsif scan(/;.*/) - kind = :comment - elsif scan(/#\\(?:newline|space|.?)/) - kind = :char - elsif scan(/#[ft]/) - kind = :pre_constant - elsif scan(/#{IDENTIFIER}/o) - kind = ident_kind[matched] - elsif scan(/\./) - kind = :operator - elsif scan(/"/) - tokens << [:open, :string] - state = :string - tokens << ['"', :delimiter] - next - elsif scan(/#{NUM}/o) and not matched.empty? - kind = :integer - elsif getch - kind = :error - end - - when :string - if scan(/[^"\\]+/) or scan(/\\.?/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - next - else - raise_inspect "else case \" reached; %p not handled." % peek(1), - tokens, state - end - - else - raise "else case reached" - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens, state unless match - - tokens << [match, kind] - - end # until eos - - if state == :string - tokens << [:close, :string] - end - - tokens - - end #scan_tokens - end #class - end #module scanners -end #module coderay \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -module CodeRay module Scanners - - # by Josh Goebel - class SQL < Scanner - - register_for :sql - - RESERVED_WORDS = %w( - create database table index trigger drop primary key set select - insert update delete replace into - on from values before and or if exists case when - then else as group order by avg where - join inner outer union engine not - like end using collate show columns begin - ) - - PREDEFINED_TYPES = %w( - char varchar enum binary text tinytext mediumtext - longtext blob tinyblob mediumblob longblob timestamp - date time datetime year double decimal float int - integer tinyint mediumint bigint smallint unsigned bit - bool boolean hex bin oct - ) - - PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg ) - - DIRECTIVES = %w( auto_increment unique default charset ) - - PREDEFINED_CONSTANTS = %w( null true false ) - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_CONSTANTS, :pre_constant). - add(PREDEFINED_FUNCTIONS, :predefined). - add(DIRECTIVES, :directive) - - ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - STRING_PREFIXES = /[xnb]|_\w+/i - - def scan_tokens tokens, options - - state = :initial - string_type = nil - string_content = '' - - until eos? - - kind = nil - match = nil - - if state == :initial - - if scan(/ \s+ | \\\n /x) - kind = :space - - elsif scan(/(?:--\s?|#).*/) - kind = :comment - - elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx) - kind = :comment - - elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x) - kind = :operator - - elsif scan(/(#{STRING_PREFIXES})?([`"'])/o) - prefix = self[1] - string_type = self[2] - tokens << [:open, :string] - tokens << [prefix, :modifier] if prefix - match = string_type - state = :string - kind = :delimiter - - elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x) - kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase] - - elsif scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - - elsif scan(/0[0-7]+(?![89.eEfF])/) - kind = :oct - - elsif scan(/(?>\d+)(?![.eEfF])/) - kind = :integer - - elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) - kind = :float - - else - getch - kind = :error - - end - - elsif state == :string - if match = scan(/[^\\"'`]+/) - string_content << match - next - elsif match = scan(/["'`]/) - if string_type == match - if peek(1) == string_type # doubling means escape - string_content << string_type << getch - next - end - unless string_content.empty? - tokens << [string_content, :content] - string_content = '' - end - tokens << [matched, :delimiter] - tokens << [:close, :string] - state = :initial - string_type = nil - next - else - string_content << match - end - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - unless string_content.empty? - tokens << [string_content, :content] - string_content = '' - end - kind = :char - elsif match = scan(/ \\ . /mox) - string_content << match - next - elsif scan(/ \\ | $ /x) - unless string_content.empty? - tokens << [string_content, :content] - string_content = '' - end - kind = :error - state = :initial - else - raise "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise 'else-case reached', tokens - - end - - match ||= matched - unless kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - tokens - - end - - end - -end end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/xml.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/xml.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -module CodeRay -module Scanners - - load :html - - # XML Scanner - # - # Currently this is the same scanner as Scanners::HTML. - class XML < HTML - - register_for :xml - file_extension 'xml' - - end - -end -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/scanners/yaml.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/yaml.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -module CodeRay -module Scanners - - # YAML Scanner - # - # Based on the YAML scanner from Syntax by Jamis Buck. - class YAML < Scanner - - register_for :yaml - file_extension 'yml' - - KINDS_NOT_LOC = :all - - def scan_tokens tokens, options - - value_expected = nil - state = :initial - key_indent = indent = 0 - - until eos? - - kind = nil - match = nil - key_indent = nil if bol? - - if match = scan(/ +[\t ]*/) - kind = :space - - elsif match = scan(/\n+/) - kind = :space - state = :initial if match.index(?\n) - - elsif match = scan(/#.*/) - kind = :comment - - elsif bol? and case - when match = scan(/---|\.\.\./) - tokens << [:open, :head] - tokens << [match, :head] - tokens << [:close, :head] - next - when match = scan(/%.*/) - tokens << [match, :doctype] - next - end - - elsif state == :value and case - when !check(/(?:"[^"]*")(?=: |:$)/) && scan(/"/) - tokens << [:open, :string] - tokens << [matched, :delimiter] - tokens << [matched, :content] if scan(/ [^"\\]* (?: \\. [^"\\]* )* /mx) - tokens << [matched, :delimiter] if scan(/"/) - tokens << [:close, :string] - next - when match = scan(/[|>][-+]?/) - tokens << [:open, :string] - tokens << [match, :delimiter] - string_indent = key_indent || column(pos - match.size - 1) - tokens << [matched, :content] if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) - tokens << [:close, :string] - next - when match = scan(/(?![!"*&]).+?(?=$|\s+#)/) - tokens << [match, :string] - string_indent = key_indent || column(pos - match.size - 1) - tokens << [matched, :string] if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) - next - end - - elsif case - when match = scan(/[-:](?= |$)/) - state = :value if state == :colon && (match == ':' || match == '-') - state = :value if state == :initial && match == '-' - kind = :operator - when match = scan(/[,{}\[\]]/) - kind = :operator - when state == :initial && match = scan(/[\w.() ]*\S(?=: |:$)/) - kind = :key - key_indent = column(pos - match.size - 1) - # tokens << [key_indent.inspect, :debug] - state = :colon - when match = scan(/(?:"[^"\n]*"|'[^'\n]*')(?=: |:$)/) - tokens << [:open, :key] - tokens << [match[0,1], :delimiter] - tokens << [match[1..-2], :content] - tokens << [match[-1,1], :delimiter] - tokens << [:close, :key] - key_indent = column(pos - match.size - 1) - # tokens << [key_indent.inspect, :debug] - state = :colon - next - when scan(/(![\w\/]+)(:([\w:]+))?/) - tokens << [self[1], :type] - if self[2] - tokens << [':', :operator] - tokens << [self[3], :class] - end - next - when scan(/&\S+/) - kind = :variable - when scan(/\*\w+/) - kind = :global_variable - when scan(/< 'at', - :attribute_name => 'an', - :attribute_name_fat => 'af', - :attribute_value => 'av', - :attribute_value_fat => 'aw', - :bin => 'bi', - :char => 'ch', - :class => 'cl', - :class_variable => 'cv', - :color => 'cr', - :comment => 'c', - :complex => 'cm', - :constant => 'co', - :content => 'k', - :decorator => 'de', - :definition => 'df', - :delimiter => 'dl', - :directive => 'di', - :doc => 'do', - :doctype => 'dt', - :doc_string => 'ds', - :entity => 'en', - :error => 'er', - :escape => 'e', - :exception => 'ex', - :float => 'fl', - :function => 'fu', - :global_variable => 'gv', - :hex => 'hx', - :imaginary => 'cm', - :important => 'im', - :include => 'ic', - :inline => 'il', - :inline_delimiter => 'idl', - :instance_variable => 'iv', - :integer => 'i', - :interpreted => 'in', - :keyword => 'kw', - :key => 'ke', - :label => 'la', - :local_variable => 'lv', - :modifier => 'mod', - :oct => 'oc', - :operator_fat => 'of', - :pre_constant => 'pc', - :pre_type => 'pt', - :predefined => 'pd', - :preprocessor => 'pp', - :pseudo_class => 'ps', - :regexp => 'rx', - :reserved => 'r', - :shell => 'sh', - :string => 's', - :symbol => 'sy', - :tag => 'ta', - :tag_fat => 'tf', - :tag_special => 'ts', - :type => 'ty', - :variable => 'v', - :value => 'vl', - :xml_text => 'xt', - - :insert => 'ins', - :delete => 'del', - :change => 'chg', - :head => 'head', - - :ident => :NO_HIGHLIGHT, # 'id' - #:operator => 'op', - :operator => :NO_HIGHLIGHT, # 'op' - :space => :NO_HIGHLIGHT, # 'sp' - :plain => :NO_HIGHLIGHT, - } - ClassOfKind[:method] = ClassOfKind[:function] - ClassOfKind[:open] = ClassOfKind[:close] = ClassOfKind[:delimiter] - ClassOfKind[:nesting_delimiter] = ClassOfKind[:delimiter] - ClassOfKind[:escape] = ClassOfKind[:delimiter] - #ClassOfKind.default = ClassOfKind[:error] or raise 'no class found for :error!' - end -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/lib/coderay/tokens.rb --- a/vendor/gems/coderay-0.9.7/lib/coderay/tokens.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,390 +0,0 @@ -module CodeRay - - # = Tokens - # - # The Tokens class represents a list of tokens returnd from - # a Scanner. - # - # A token is not a special object, just a two-element Array - # consisting of - # * the _token_ _text_ (the original source of the token in a String) or - # a _token_ _action_ (:open, :close, :begin_line, :end_line) - # * the _token_ _kind_ (a Symbol representing the type of the token) - # - # A token looks like this: - # - # ['# It looks like this', :comment] - # ['3.1415926', :float] - # ['$^', :error] - # - # Some scanners also yield sub-tokens, represented by special - # token actions, namely :open and :close. - # - # The Ruby scanner, for example, splits "a string" into: - # - # [ - # [:open, :string], - # ['"', :delimiter], - # ['a string', :content], - # ['"', :delimiter], - # [:close, :string] - # ] - # - # Tokens is the interface between Scanners and Encoders: - # The input is split and saved into a Tokens object. The Encoder - # then builds the output from this object. - # - # Thus, the syntax below becomes clear: - # - # CodeRay.scan('price = 2.59', :ruby).html - # # the Tokens object is here -------^ - # - # See how small it is? ;) - # - # Tokens gives you the power to handle pre-scanned code very easily: - # You can convert it to a webpage, a YAML file, or dump it into a gzip'ed string - # that you put in your DB. - # - # It also allows you to generate tokens directly (without using a scanner), - # to load them from a file, and still use any Encoder that CodeRay provides. - # - # Tokens' subclass TokenStream allows streaming to save memory. - class Tokens < Array - - # The Scanner instance that created the tokens. - attr_accessor :scanner - - # Whether the object is a TokenStream. - # - # Returns false. - def stream? - false - end - - # Iterates over all tokens. - # - # If a filter is given, only tokens of that kind are yielded. - def each kind_filter = nil, &block - unless kind_filter - super(&block) - else - super() do |text, kind| - next unless kind == kind_filter - yield text, kind - end - end - end - - # Iterates over all text tokens. - # Range tokens like [:open, :string] are left out. - # - # Example: - # tokens.each_text_token { |text, kind| text.replace html_escape(text) } - def each_text_token - each do |text, kind| - next unless text.is_a? ::String - yield text, kind - end - end - - # Encode the tokens using encoder. - # - # encoder can be - # * a symbol like :html oder :statistic - # * an Encoder class - # * an Encoder object - # - # options are passed to the encoder. - def encode encoder, options = {} - unless encoder.is_a? Encoders::Encoder - unless encoder.is_a? Class - encoder_class = Encoders[encoder] - end - encoder = encoder_class.new options - end - encoder.encode_tokens self, options - end - - - # Turn into a string using Encoders::Text. - # - # +options+ are passed to the encoder if given. - def to_s options = {} - encode :text, options - end - - # Redirects unknown methods to encoder calls. - # - # For example, if you call +tokens.html+, the HTML encoder - # is used to highlight the tokens. - def method_missing meth, options = {} - Encoders[meth].new(options).encode_tokens self - end - - # Returns the tokens compressed by joining consecutive - # tokens of the same kind. - # - # This can not be undone, but should yield the same output - # in most Encoders. It basically makes the output smaller. - # - # Combined with dump, it saves space for the cost of time. - # - # If the scanner is written carefully, this is not required - - # for example, consecutive //-comment lines could already be - # joined in one comment token by the Scanner. - def optimize - last_kind = last_text = nil - new = self.class.new - for text, kind in self - if text.is_a? String - if kind == last_kind - last_text << text - else - new << [last_text, last_kind] if last_kind - last_text = text - last_kind = kind - end - else - new << [last_text, last_kind] if last_kind - last_kind = last_text = nil - new << [text, kind] - end - end - new << [last_text, last_kind] if last_kind - new - end - - # Compact the object itself; see optimize. - def optimize! - replace optimize - end - - # Ensure that all :open tokens have a correspondent :close one. - # - # TODO: Test this! - def fix - tokens = self.class.new - # Check token nesting using a stack of kinds. - opened = [] - for type, kind in self - case type - when :open - opened.push [:close, kind] - when :begin_line - opened.push [:end_line, kind] - when :close, :end_line - expected = opened.pop - if [type, kind] != expected - # Unexpected :close; decide what to do based on the kind: - # - token was never opened: delete the :close (just skip it) - next unless opened.rindex expected - # - token was opened earlier: also close tokens in between - tokens << token until (token = opened.pop) == expected - end - end - tokens << [type, kind] - end - # Close remaining opened tokens - tokens << token while token = opened.pop - tokens - end - - def fix! - replace fix - end - - # TODO: Scanner#split_into_lines - # - # Makes sure that: - # - newlines are single tokens - # (which means all other token are single-line) - # - there are no open tokens at the end the line - # - # This makes it simple for encoders that work line-oriented, - # like HTML with list-style numeration. - def split_into_lines - raise NotImplementedError - end - - def split_into_lines! - replace split_into_lines - end - - # Dumps the object into a String that can be saved - # in files or databases. - # - # The dump is created with Marshal.dump; - # In addition, it is gzipped using GZip.gzip. - # - # The returned String object includes Undumping - # so it has an #undump method. See Tokens.load. - # - # You can configure the level of compression, - # but the default value 7 should be what you want - # in most cases as it is a good compromise between - # speed and compression rate. - # - # See GZip module. - def dump gzip_level = 7 - require 'coderay/helpers/gzip_simple' - dump = Marshal.dump self - dump = dump.gzip gzip_level - dump.extend Undumping - end - - # The total size of the tokens. - # Should be equal to the input size before - # scanning. - def text_size - size = 0 - each_text_token do |t, k| - size + t.size - end - size - end - - # Return all text tokens joined into a single string. - def text - map { |t, k| t if t.is_a? ::String }.join - end - - # Include this module to give an object an #undump - # method. - # - # The string returned by Tokens.dump includes Undumping. - module Undumping - # Calls Tokens.load with itself. - def undump - Tokens.load self - end - end - - # Undump the object using Marshal.load, then - # unzip it using GZip.gunzip. - # - # The result is commonly a Tokens object, but - # this is not guaranteed. - def Tokens.load dump - require 'coderay/helpers/gzip_simple' - dump = dump.gunzip - @dump = Marshal.load dump - end - - end - - - # = TokenStream - # - # The TokenStream class is a fake Array without elements. - # - # It redirects the method << to a block given at creation. - # - # This allows scanners and Encoders to use streaming (no - # tokens are saved, the input is highlighted the same time it - # is scanned) with the same code. - # - # See CodeRay.encode_stream and CodeRay.scan_stream - class TokenStream < Tokens - - # Whether the object is a TokenStream. - # - # Returns true. - def stream? - true - end - - # The Array is empty, but size counts the tokens given by <<. - attr_reader :size - - # Creates a new TokenStream that calls +block+ whenever - # its << method is called. - # - # Example: - # - # require 'coderay' - # - # token_stream = CodeRay::TokenStream.new do |text, kind| - # puts 'kind: %s, text size: %d.' % [kind, text.size] - # end - # - # token_stream << ['/\d+/', :regexp] - # #-> kind: rexpexp, text size: 5. - # - def initialize &block - raise ArgumentError, 'Block expected for streaming.' unless block - @callback = block - @size = 0 - end - - # Calls +block+ with +token+ and increments size. - # - # Returns self. - def << token - @callback.call(*token) - @size += 1 - self - end - - # This method is not implemented due to speed reasons. Use Tokens. - def text_size - raise NotImplementedError, - 'This method is not implemented due to speed reasons.' - end - - # A TokenStream cannot be dumped. Use Tokens. - def dump - raise NotImplementedError, 'A TokenStream cannot be dumped.' - end - - # A TokenStream cannot be optimized. Use Tokens. - def optimize - raise NotImplementedError, 'A TokenStream cannot be optimized.' - end - - end - -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class TokensTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Tokens < Array - tokens = nil - assert_nothing_raised do - tokens = CodeRay::Tokens.new - end - assert_kind_of Array, tokens - end - - def test_adding_tokens - tokens = CodeRay::Tokens.new - assert_nothing_raised do - tokens << ['string', :type] - tokens << ['()', :operator] - end - assert_equal tokens.size, 2 - end - - def test_dump_undump - tokens = CodeRay::Tokens.new - assert_nothing_raised do - tokens << ['string', :type] - tokens << ['()', :operator] - end - tokens2 = nil - assert_nothing_raised do - tokens2 = tokens.dump.undump - end - assert_equal tokens, tokens2 - end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/basic.rb --- a/vendor/gems/coderay-0.9.7/test/functional/basic.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -require 'test/unit' -require 'coderay' - -class BasicTest < Test::Unit::TestCase - - def test_version - assert_nothing_raised do - assert_match(/\A\d\.\d\.\d\z/, CodeRay::VERSION) - end - end - - RUBY_TEST_CODE = 'puts "Hello, World!"' - - RUBY_TEST_TOKENS = [ - ['puts', :ident], - [' ', :space], - [:open, :string], - ['"', :delimiter], - ['Hello, World!', :content], - ['"', :delimiter], - [:close, :string] - ] - def test_simple_scan - assert_nothing_raised do - assert_equal RUBY_TEST_TOKENS, CodeRay.scan(RUBY_TEST_CODE, :ruby).to_ary - end - end - - RUBY_TEST_HTML = 'puts "' + - 'Hello, World!"' - def test_simple_highlight - assert_nothing_raised do - assert_equal RUBY_TEST_HTML, CodeRay.scan(RUBY_TEST_CODE, :ruby).html - end - end - - def test_duo - assert_equal(RUBY_TEST_CODE, - CodeRay::Duo[:plain, :plain].highlight(RUBY_TEST_CODE)) - assert_equal(RUBY_TEST_CODE, - CodeRay::Duo[:plain => :plain].highlight(RUBY_TEST_CODE)) - end - - def test_duo_stream - assert_equal(RUBY_TEST_CODE, - CodeRay::Duo[:plain, :plain].highlight(RUBY_TEST_CODE, :stream => true)) - end - - def test_comment_filter - assert_equal <<-EXPECTED, CodeRay.scan(<<-INPUT, :ruby).comment_filter.text -#!/usr/bin/env ruby - -code - -more code - EXPECTED -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - INPUT - end - - def test_lines_of_code - assert_equal 2, CodeRay.scan(<<-INPUT, :ruby).lines_of_code -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - INPUT - rHTML = <<-RHTML - - - - - - <%= controller.controller_name.titleize %>: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

    <%= flash[:notice] %>

    - -
    - <%= yield %> -
    - - - - RHTML - assert_equal 0, CodeRay.scan(rHTML, :html).lines_of_code - assert_equal 0, CodeRay.scan(rHTML, :php).lines_of_code - assert_equal 0, CodeRay.scan(rHTML, :yaml).lines_of_code - assert_equal 4, CodeRay.scan(rHTML, :rhtml).lines_of_code - end - - def test_rubygems_not_loaded - assert_equal nil, defined? Gem - end if ENV['check_rubygems'] && RUBY_VERSION < '1.9' - - def test_list_of_encoders - assert_kind_of(Array, CodeRay::Encoders.list) - assert CodeRay::Encoders.list.include?('count') - end - - def test_list_of_scanners - assert_kind_of(Array, CodeRay::Scanners.list) - assert CodeRay::Scanners.list.include?('plaintext') - end - - def test_scan_a_frozen_string - CodeRay.scan RUBY_VERSION, :ruby - end - -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/basic.rbc --- a/vendor/gems/coderay-0.9.7/test/functional/basic.rbc Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2022 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -53 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -47 -49 -1 -1 -15 -99 -7 -3 -45 -4 -5 -43 -6 -43 -7 -65 -49 -8 -3 -13 -99 -12 -7 -9 -12 -7 -10 -12 -65 -12 -49 -11 -4 -15 -49 -9 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -12 -s -9 -test/unit -x -7 -require -s -7 -coderay -x -9 -BasicTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -9 -BasicTest -i -263 -5 -66 -99 -7 -0 -7 -1 -65 -67 -49 -2 -0 -49 -3 -4 -15 -65 -7 -4 -7 -5 -64 -49 -6 -2 -15 -65 -7 -7 -7 -8 -64 -7 -9 -35 -2 -7 -10 -64 -7 -11 -35 -2 -7 -12 -7 -13 -35 -2 -7 -14 -64 -7 -15 -35 -2 -7 -16 -64 -7 -17 -35 -2 -7 -14 -64 -7 -15 -35 -2 -7 -18 -7 -13 -35 -2 -35 -7 -49 -6 -2 -15 -99 -7 -19 -7 -20 -65 -67 -49 -2 -0 -49 -3 -4 -15 -65 -7 -21 -7 -22 -64 -7 -23 -64 -81 -24 -49 -6 -2 -15 -99 -7 -25 -7 -26 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -27 -7 -28 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -29 -7 -30 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -31 -7 -32 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -33 -7 -34 -65 -67 -49 -2 -0 -49 -3 -4 -15 -45 -35 -36 -7 -37 -64 -49 -38 -1 -13 -9 -202 -15 -45 -39 -40 -7 -41 -64 -84 -42 -9 -219 -99 -7 -43 -7 -44 -65 -67 -49 -2 -0 -49 -3 -4 -8 -220 -1 -15 -99 -7 -45 -7 -46 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -47 -7 -48 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -49 -7 -50 -65 -67 -49 -2 -0 -49 -3 -4 -11 -I -a -I -0 -I -0 -I -0 -n -p -51 -x -12 -test_version -M -1 -n -n -x -12 -test_version -i -8 -5 -56 -0 -47 -50 -1 -0 -11 -I -2 -I -0 -I -0 -I -0 -n -p -2 -M -1 -p -2 -x -9 -for_block -t -n -x -12 -test_version -i -29 -5 -7 -0 -13 -70 -9 -19 -15 -44 -43 -1 -7 -2 -78 -49 -3 -2 -6 -0 -45 -4 -5 -43 -6 -47 -49 -7 -2 -11 -I -5 -I -0 -I -0 -I -0 -I --2 -p -8 -n -x -6 -Regexp -s -14 -\A\d\.\d\.\d\z -x -3 -new -x -7 -CodeRay -n -x -7 -VERSION -x -12 -assert_match -p -5 -I -0 -I -7 -I -0 -I -8 -I -1d -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -assert_nothing_raised -p -5 -I -0 -I -6 -I -0 -I -7 -I -8 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -x -14 -RUBY_TEST_CODE -s -20 -puts "Hello, World!" -x -9 -const_set -x -16 -RUBY_TEST_TOKENS -s -4 -puts -x -5 -ident -s -1 - -x -5 -space -x -4 -open -x -6 -string -s -1 -" -x -9 -delimiter -s -13 -Hello, World! -x -7 -content -x -5 -close -x -16 -test_simple_scan -M -1 -n -n -x -16 -test_simple_scan -i -8 -5 -56 -0 -47 -50 -1 -0 -11 -I -2 -I -0 -I -0 -I -0 -n -p -2 -M -1 -p -2 -x -9 -for_block -t -n -x -16 -test_simple_scan -i -23 -5 -45 -0 -1 -45 -2 -3 -45 -4 -5 -7 -6 -49 -7 -2 -49 -8 -0 -47 -49 -9 -2 -11 -I -6 -I -0 -I -0 -I -0 -I --2 -p -10 -x -16 -RUBY_TEST_TOKENS -n -x -7 -CodeRay -n -x -14 -RUBY_TEST_CODE -n -x -4 -ruby -x -4 -scan -x -6 -to_ary -x -12 -assert_equal -p -5 -I -0 -I -18 -I -0 -I -19 -I -17 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -assert_nothing_raised -p -5 -I -0 -I -17 -I -0 -I -18 -I -8 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -14 -RUBY_TEST_HTML -s -51 -puts " -s -73 -Hello, World!" -x -1 -+ -x -21 -test_simple_highlight -M -1 -n -n -x -21 -test_simple_highlight -i -8 -5 -56 -0 -47 -50 -1 -0 -11 -I -2 -I -0 -I -0 -I -0 -n -p -2 -M -1 -p -2 -x -9 -for_block -t -n -x -21 -test_simple_highlight -i -23 -5 -45 -0 -1 -45 -2 -3 -45 -4 -5 -7 -6 -49 -7 -2 -49 -8 -0 -47 -49 -9 -2 -11 -I -6 -I -0 -I -0 -I -0 -I --2 -p -10 -x -14 -RUBY_TEST_HTML -n -x -7 -CodeRay -n -x -14 -RUBY_TEST_CODE -n -x -4 -ruby -x -4 -scan -x -4 -html -x -12 -assert_equal -p -5 -I -0 -I -20 -I -0 -I -21 -I -17 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -assert_nothing_raised -p -5 -I -0 -I -1f -I -0 -I -20 -I -8 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -8 -test_duo -M -1 -n -n -x -8 -test_duo -i -66 -5 -45 -0 -1 -45 -2 -3 -43 -4 -7 -5 -7 -5 -49 -6 -2 -45 -0 -7 -49 -8 -1 -47 -49 -9 -2 -15 -5 -45 -0 -10 -45 -2 -11 -43 -4 -44 -43 -12 -79 -49 -13 -1 -13 -7 -5 -7 -5 -49 -14 -2 -15 -49 -6 -1 -45 -0 -15 -49 -8 -1 -47 -49 -9 -2 -11 -I -7 -I -0 -I -0 -I -0 -n -p -16 -x -14 -RUBY_TEST_CODE -n -x -7 -CodeRay -n -x -3 -Duo -x -5 -plain -x -2 -[] -n -x -9 -highlight -x -12 -assert_equal -n -n -x -4 -Hash -x -16 -new_from_literal -x -3 -[]= -n -p -15 -I -0 -I -25 -I -0 -I -26 -I -4 -I -27 -I -16 -I -26 -I -1b -I -28 -I -1f -I -29 -I -3d -I -28 -I -42 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -15 -test_duo_stream -M -1 -n -n -x -15 -test_duo_stream -i -42 -5 -45 -0 -1 -45 -2 -3 -43 -4 -7 -5 -7 -5 -49 -6 -2 -45 -0 -7 -44 -43 -8 -79 -49 -9 -1 -13 -7 -10 -2 -49 -11 -2 -15 -49 -12 -2 -47 -49 -13 -2 -11 -I -8 -I -0 -I -0 -I -0 -n -p -14 -x -14 -RUBY_TEST_CODE -n -x -7 -CodeRay -n -x -3 -Duo -x -5 -plain -x -2 -[] -n -x -4 -Hash -x -16 -new_from_literal -x -6 -stream -x -3 -[]= -x -9 -highlight -x -12 -assert_equal -p -9 -I -0 -I -2c -I -0 -I -2d -I -4 -I -2e -I -25 -I -2d -I -2a -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -19 -test_comment_filter -M -1 -n -n -x -19 -test_comment_filter -i -26 -5 -7 -0 -64 -45 -1 -2 -7 -3 -64 -7 -4 -49 -5 -2 -49 -6 -0 -49 -7 -0 -47 -49 -8 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -9 -s -39 -#!/usr/bin/env ruby - -code - -more code - -x -7 -CodeRay -n -s -127 -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - -x -4 -ruby -x -4 -scan -x -14 -comment_filter -x -4 -text -x -12 -assert_equal -p -5 -I -0 -I -31 -I -0 -I -32 -I -1a -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -18 -test_lines_of_code -M -1 -n -n -x -18 -test_lines_of_code -i -108 -5 -80 -45 -0 -1 -7 -2 -64 -7 -3 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -7 -7 -64 -19 -0 -15 -5 -78 -45 -0 -8 -20 -0 -7 -9 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -5 -78 -45 -0 -10 -20 -0 -7 -11 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -5 -78 -45 -0 -12 -20 -0 -7 -13 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -5 -4 -4 -45 -0 -14 -20 -0 -7 -15 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -11 -I -6 -I -1 -I -0 -I -0 -n -p -16 -x -7 -CodeRay -n -s -127 -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - -x -4 -ruby -x -4 -scan -x -13 -lines_of_code -x -12 -assert_equal -s -514 - - - - - - <%= controller.controller_name.titleize %>: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

    <%= flash[:notice] %>

    - -
    - <%= yield %> -
    - - - - -n -x -4 -html -n -x -3 -php -n -x -4 -yaml -n -x -5 -rhtml -p -15 -I -0 -I -43 -I -0 -I -44 -I -15 -I -4d -I -1b -I -62 -I -2f -I -63 -I -43 -I -64 -I -57 -I -65 -I -6c -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -1 -x -5 -rHTML -x -3 -ENV -n -s -14 -check_rubygems -x -2 -[] -x -12 -RUBY_VERSION -n -s -3 -1.9 -x -1 -< -x -24 -test_rubygems_not_loaded -M -1 -n -n -x -24 -test_rubygems_not_loaded -i -34 -5 -1 -26 -93 -0 -15 -29 -17 -0 -7 -0 -98 -1 -1 -30 -8 -23 -25 -92 -0 -27 -8 -28 -15 -7 -2 -8 -29 -1 -47 -49 -3 -2 -11 -I -4 -I -0 -I -0 -I -0 -n -p -4 -x -3 -Gem -x -16 -vm_const_defined -s -8 -constant -x -12 -assert_equal -p -5 -I -0 -I -68 -I -0 -I -69 -I -22 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -test_list_of_encoders -M -1 -n -n -x -21 -test_list_of_encoders -i -37 -5 -45 -0 -1 -45 -2 -3 -43 -4 -49 -5 -0 -47 -49 -6 -2 -15 -5 -45 -2 -7 -43 -4 -49 -5 -0 -7 -8 -64 -49 -9 -1 -47 -49 -10 -1 -11 -I -3 -I -0 -I -0 -I -0 -n -p -11 -x -5 -Array -n -x -7 -CodeRay -n -x -8 -Encoders -x -4 -list -x -14 -assert_kind_of -n -s -5 -count -x -8 -include? -x -6 -assert -p -7 -I -0 -I -6c -I -0 -I -6d -I -11 -I -6e -I -25 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -test_list_of_scanners -M -1 -n -n -x -21 -test_list_of_scanners -i -37 -5 -45 -0 -1 -45 -2 -3 -43 -4 -49 -5 -0 -47 -49 -6 -2 -15 -5 -45 -2 -7 -43 -4 -49 -5 -0 -7 -8 -64 -49 -9 -1 -47 -49 -10 -1 -11 -I -3 -I -0 -I -0 -I -0 -n -p -11 -x -5 -Array -n -x -7 -CodeRay -n -x -8 -Scanners -x -4 -list -x -14 -assert_kind_of -n -s -9 -plaintext -x -8 -include? -x -6 -assert -p -7 -I -0 -I -71 -I -0 -I -72 -I -11 -I -73 -I -25 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -25 -test_scan_a_frozen_string -M -1 -n -n -x -25 -test_scan_a_frozen_string -i -12 -45 -0 -1 -45 -2 -3 -7 -4 -49 -5 -2 -11 -I -3 -I -0 -I -0 -I -0 -n -p -6 -x -7 -CodeRay -n -x -12 -RUBY_VERSION -n -x -4 -ruby -x -4 -scan -p -5 -I -0 -I -76 -I -0 -I -77 -I -c -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -p -51 -I -2 -I -6 -I -10 -I -c -I -1a -I -e -I -1d -I -f -I -24 -I -10 -I -2b -I -11 -I -31 -I -12 -I -38 -I -13 -I -3f -I -14 -I -46 -I -15 -I -52 -I -17 -I -60 -I -1d -I -63 -I -1d -I -66 -I -1e -I -6f -I -1f -I -7d -I -25 -I -8b -I -2c -I -99 -I -31 -I -a7 -I -43 -I -b5 -I -6a -I -cc -I -68 -I -db -I -6a -I -dd -I -6c -I -eb -I -71 -I -f9 -I -76 -I -107 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -13 -attach_method -p -7 -I -0 -I -1 -I -9 -I -2 -I -12 -I -4 -I -35 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rb --- a/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -require 'test/unit' -$:.unshift 'lib' -require 'coderay' - -begin - require 'rubygems' unless defined? Gem - gem 'RedCloth', '>= 4.0.3' rescue nil - require 'redcloth' -rescue LoadError - warn 'RedCloth not found - skipping for_redcloth tests.' -end - -class BasicTest < Test::Unit::TestCase - - def test_for_redcloth - require 'coderay/for_redcloth' - assert_equal "

    puts "Hello, World!"

    ", - RedCloth.new('@[ruby]puts "Hello, World!"@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    -
    puts "Hello, World!"
    -
    - BLOCKCODE - RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html - end - - def test_for_redcloth_no_lang - require 'coderay/for_redcloth' - assert_equal "

    puts \"Hello, World!\"

    ", - RedCloth.new('@puts "Hello, World!"@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    puts \"Hello, World!\"
    - BLOCKCODE - RedCloth.new('bc. puts "Hello, World!"').to_html - end - - def test_for_redcloth_style - require 'coderay/for_redcloth' - assert_equal <<-BLOCKCODE.chomp, -
    puts \"Hello, World!\"
    - BLOCKCODE - RedCloth.new('bc{color: red}. puts "Hello, World!"').to_html - end - - def test_for_redcloth_escapes - require 'coderay/for_redcloth' - assert_equal '

    >

    ', - RedCloth.new('@[ruby]>@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    -
    &
    -
    - BLOCKCODE - RedCloth.new('bc[ruby]. &').to_html - end - - def test_for_redcloth_escapes2 - require 'coderay/for_redcloth' - assert_equal "

    #include <test.h>

    ", - RedCloth.new('@[c]#include @').to_html - end - - # See http://jgarber.lighthouseapp.com/projects/13054/tickets/124-code-markup-does-not-allow-brackets. - def test_for_redcloth_false_positive - require 'coderay/for_redcloth' - assert_equal '

    [project]_dff.skjd

    ', - RedCloth.new('@[project]_dff.skjd@').to_html - # false positive, but expected behavior / known issue - assert_equal "

    _dff.skjd

    ", - RedCloth.new('@[ruby]_dff.skjd@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    [project]_dff.skjd
    - BLOCKCODE - RedCloth.new('bc. [project]_dff.skjd').to_html - end - -end if defined? RedCloth \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rbc --- a/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rbc Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1708 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -249 -5 -7 -0 -64 -47 -49 -1 -1 -15 -99 -43 -2 -7 -3 -49 -4 -1 -7 -5 -64 -49 -6 -1 -15 -5 -7 -7 -64 -47 -49 -1 -1 -15 -26 -93 -0 -15 -29 -144 -0 -26 -93 -1 -15 -29 -55 -0 -7 -8 -98 -9 -1 -30 -8 -61 -25 -92 -1 -27 -8 -66 -15 -7 -10 -8 -67 -1 -9 -72 -1 -8 -80 -5 -7 -11 -64 -47 -49 -1 -1 -15 -26 -93 -2 -15 -29 -102 -0 -5 -7 -12 -64 -7 -13 -64 -47 -49 -14 -2 -30 -8 -129 -26 -93 -3 -15 -24 -13 -45 -15 -16 -12 -49 -17 -1 -10 -119 -8 -124 -15 -1 -25 -8 -129 -15 -92 -3 -27 -34 -92 -2 -27 -15 -5 -7 -18 -64 -47 -49 -1 -1 -30 -8 -178 -26 -93 -4 -15 -24 -13 -45 -19 -20 -12 -49 -17 -1 -10 -161 -8 -173 -15 -5 -7 -21 -64 -47 -49 -22 -1 -25 -8 -178 -15 -92 -4 -27 -34 -92 -0 -27 -15 -26 -93 -5 -15 -29 -197 -0 -7 -23 -98 -9 -1 -30 -8 -203 -25 -92 -5 -27 -8 -208 -15 -7 -10 -8 -209 -1 -9 -245 -99 -7 -24 -45 -25 -26 -43 -27 -43 -28 -65 -49 -29 -3 -13 -99 -12 -7 -30 -12 -7 -31 -12 -65 -12 -49 -32 -4 -15 -49 -30 -0 -8 -246 -1 -15 -2 -11 -I -c -I -0 -I -0 -I -0 -n -p -33 -s -9 -test/unit -x -7 -require -x -7 -Globals -x -2 -$: -x -2 -[] -s -3 -lib -x -2 -<< -s -7 -coderay -x -3 -Gem -x -16 -vm_const_defined -s -8 -constant -s -8 -rubygems -s -8 -RedCloth -s -8 ->= 4.0.3 -x -3 -gem -x -13 -StandardError -n -x -3 -=== -s -8 -redcloth -x -9 -LoadError -n -s -49 -RedCloth not found - skipping for_redcloth tests. -x -4 -warn -x -8 -RedCloth -x -9 -BasicTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -9 -BasicTest -i -86 -5 -66 -99 -7 -0 -7 -1 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -4 -7 -5 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -6 -7 -7 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -8 -7 -9 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -10 -7 -11 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -12 -7 -13 -65 -67 -49 -2 -0 -49 -3 -4 -11 -I -5 -I -0 -I -0 -I -0 -n -p -14 -x -17 -test_for_redcloth -M -1 -n -n -x -17 -test_for_redcloth -i -96 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -49 -12 -0 -45 -3 -13 -13 -71 -5 -47 -9 -82 -47 -49 -6 -0 -13 -7 -14 -64 -47 -49 -8 -1 -15 -8 -88 -7 -14 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -15 -s -20 -coderay/for_redcloth -x -7 -require -s -221 -

    puts "Hello, World!"

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -28 -@[ruby]puts "Hello, World!"@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -252 -
    -
    puts "Hello, World!"
    -
    - -x -5 -chomp -n -s -30 -bc[ruby]. puts "Hello, World!" -p -17 -I -0 -I -f -I -0 -I -10 -I -9 -I -11 -I -d -I -12 -I -2e -I -11 -I -33 -I -13 -I -3a -I -18 -I -5b -I -13 -I -60 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -x -25 -test_for_redcloth_no_lang -M -1 -n -n -x -25 -test_for_redcloth_no_lang -i -96 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -49 -12 -0 -45 -3 -13 -13 -71 -5 -47 -9 -82 -47 -49 -6 -0 -13 -7 -14 -64 -47 -49 -8 -1 -15 -8 -88 -7 -14 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -15 -s -20 -coderay/for_redcloth -x -7 -require -s -40 -

    puts "Hello, World!"

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -22 -@puts "Hello, World!"@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -45 -
    puts "Hello, World!"
    - -x -5 -chomp -n -s -24 -bc. puts "Hello, World!" -p -17 -I -0 -I -1b -I -0 -I -1c -I -9 -I -1d -I -d -I -1e -I -2e -I -1d -I -33 -I -1f -I -3a -I -22 -I -5b -I -1f -I -60 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -23 -test_for_redcloth_style -M -1 -n -n -x -23 -test_for_redcloth_style -i -54 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -49 -3 -0 -45 -4 -5 -13 -71 -6 -47 -9 -40 -47 -49 -7 -0 -13 -7 -8 -64 -47 -49 -9 -1 -15 -8 -46 -7 -8 -64 -49 -6 -1 -49 -10 -0 -47 -49 -11 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -12 -s -20 -coderay/for_redcloth -x -7 -require -s -85 -
    puts "Hello, World!"
    - -x -5 -chomp -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -36 -bc{color: red}. puts "Hello, World!" -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -p -11 -I -0 -I -25 -I -0 -I -26 -I -9 -I -27 -I -10 -I -2a -I -31 -I -27 -I -36 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -25 -test_for_redcloth_escapes -M -1 -n -n -x -25 -test_for_redcloth_escapes -i -96 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -49 -12 -0 -45 -3 -13 -13 -71 -5 -47 -9 -82 -47 -49 -6 -0 -13 -7 -14 -64 -47 -49 -8 -1 -15 -8 -88 -7 -14 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -15 -s -20 -coderay/for_redcloth -x -7 -require -s -52 -

    >

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -9 -@[ruby]>@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -84 -
    -
    &
    -
    - -x -5 -chomp -n -s -11 -bc[ruby]. & -p -17 -I -0 -I -2d -I -0 -I -2e -I -9 -I -2f -I -d -I -30 -I -2e -I -2f -I -33 -I -31 -I -3a -I -36 -I -5b -I -31 -I -60 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -26 -test_for_redcloth_escapes2 -M -1 -n -n -x -26 -test_for_redcloth_escapes2 -i -51 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -11 -s -20 -coderay/for_redcloth -x -7 -require -s -149 -

    #include <test.h>

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -22 -@[c]#include @ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -p -11 -I -0 -I -39 -I -0 -I -3a -I -9 -I -3b -I -d -I -3c -I -2e -I -3b -I -33 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -32 -test_for_redcloth_false_positive -M -1 -n -n -x -32 -test_for_redcloth_false_positive -i -138 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -45 -3 -12 -13 -71 -5 -47 -9 -79 -47 -49 -6 -0 -13 -7 -13 -64 -47 -49 -8 -1 -15 -8 -85 -7 -13 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -14 -64 -49 -15 -0 -45 -3 -16 -13 -71 -5 -47 -9 -124 -47 -49 -6 -0 -13 -7 -17 -64 -47 -49 -8 -1 -15 -8 -130 -7 -17 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -18 -s -20 -coderay/for_redcloth -x -7 -require -s -38 -

    [project]_dff.skjd

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -20 -@[project]_dff.skjd@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -57 -

    _dff.skjd

    -n -s -17 -@[ruby]_dff.skjd@ -s -43 -
    [project]_dff.skjd
    - -x -5 -chomp -n -s -22 -bc. [project]_dff.skjd -p -23 -I -0 -I -40 -I -0 -I -41 -I -9 -I -42 -I -d -I -43 -I -2e -I -42 -I -33 -I -45 -I -37 -I -46 -I -58 -I -45 -I -5d -I -47 -I -64 -I -4a -I -85 -I -47 -I -8a -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -p -13 -I -2 -I -f -I -10 -I -1b -I -1e -I -25 -I -2c -I -2d -I -3a -I -39 -I -48 -I -40 -I -56 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -13 -attach_method -p -23 -I -0 -I -1 -I -9 -I -2 -I -18 -I -3 -I -21 -I -6 -I -51 -I -7 -I -85 -I -8 -I -95 -I -9 -I -a2 -I -a -I -b6 -I -4d -I -d3 -I -d -I -f5 -I -4d -I -f9 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rb --- a/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -require 'test/unit' -require 'coderay' - -class PluginScannerTest < Test::Unit::TestCase - - def test_load - require File.join(File.dirname(__FILE__), 'vhdl') - assert_equal 'VHDL', CodeRay.scanner(:vhdl).class.name - end - -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rbc --- a/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rbc Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -53 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -47 -49 -1 -1 -15 -99 -7 -3 -45 -4 -5 -43 -6 -43 -7 -65 -49 -8 -3 -13 -99 -12 -7 -9 -12 -7 -10 -12 -65 -12 -49 -11 -4 -15 -49 -9 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -12 -s -9 -test/unit -x -7 -require -s -7 -coderay -x -17 -PluginScannerTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -17 -PluginScannerTest -i -16 -5 -66 -99 -7 -0 -7 -1 -65 -67 -49 -2 -0 -49 -3 -4 -11 -I -5 -I -0 -I -0 -I -0 -n -p -4 -x -9 -test_load -M -1 -n -n -x -9 -test_load -i -48 -5 -45 -0 -1 -45 -0 -2 -65 -49 -3 -0 -49 -4 -1 -7 -5 -64 -49 -6 -2 -47 -49 -7 -1 -15 -5 -7 -8 -64 -45 -9 -10 -7 -11 -49 -12 -1 -49 -13 -0 -49 -14 -0 -47 -49 -15 -2 -11 -I -4 -I -0 -I -0 -I -0 -n -p -16 -x -4 -File -n -n -x -11 -active_path -x -7 -dirname -s -4 -vhdl -x -4 -join -x -7 -require -s -4 -VHDL -x -7 -CodeRay -n -x -4 -vhdl -x -7 -scanner -x -5 -class -x -4 -name -x -12 -assert_equal -p -7 -I -0 -I -6 -I -0 -I -7 -I -19 -I -8 -I -30 -x -69 -/Users/murphy/ruby/coderay-0.9/test/functional/load_plugin_scanner.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -p -3 -I -2 -I -6 -I -10 -x -69 -/Users/murphy/ruby/coderay-0.9/test/functional/load_plugin_scanner.rb -p -0 -x -13 -attach_method -p -7 -I -0 -I -1 -I -9 -I -2 -I -12 -I -4 -I -35 -x -69 -/Users/murphy/ruby/coderay-0.9/test/functional/load_plugin_scanner.rb -p -0 diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/suite.rb --- a/vendor/gems/coderay-0.9.7/test/functional/suite.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -require 'test/unit' - -MYDIR = File.dirname(__FILE__) - -$:.unshift 'lib' -require 'coderay' -puts "Running basic CodeRay #{CodeRay::VERSION} tests..." - -suite = %w(basic load_plugin_scanner word_list) -for test_case in suite - load File.join(MYDIR, test_case + '.rb') -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/suite.rbc --- a/vendor/gems/coderay-0.9.7/test/functional/suite.rbc Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,322 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -95 -5 -7 -0 -64 -47 -49 -1 -1 -15 -65 -7 -2 -45 -3 -4 -65 -49 -5 -0 -49 -6 -1 -49 -7 -2 -15 -99 -43 -8 -7 -9 -49 -10 -1 -7 -11 -64 -49 -12 -1 -15 -5 -7 -13 -64 -47 -49 -1 -1 -15 -5 -7 -14 -45 -15 -16 -43 -17 -47 -49 -18 -0 -7 -19 -63 -3 -47 -49 -20 -1 -15 -7 -21 -64 -7 -22 -64 -7 -23 -64 -35 -3 -19 -0 -15 -20 -0 -56 -24 -50 -25 -0 -15 -2 -11 -I -6 -I -2 -I -0 -I -0 -n -p -26 -s -9 -test/unit -x -7 -require -x -5 -MYDIR -x -4 -File -n -x -11 -active_path -x -7 -dirname -x -9 -const_set -x -7 -Globals -x -2 -$: -x -2 -[] -s -3 -lib -x -2 -<< -s -7 -coderay -s -22 -Running basic CodeRay -x -7 -CodeRay -n -x -7 -VERSION -x -4 -to_s -s -9 - tests... -x -4 -puts -s -5 -basic -s -19 -load_plugin_scanner -s -9 -word_list -M -1 -p -2 -x -9 -for_block -t -n -x -9 -__block__ -i -28 -57 -22 -1 -1 -15 -5 -45 -0 -1 -45 -2 -3 -21 -1 -1 -7 -4 -64 -81 -5 -49 -6 -2 -47 -49 -7 -1 -11 -I -6 -I -0 -I -1 -I -1 -n -p -8 -x -4 -File -n -x -5 -MYDIR -n -s -3 -.rb -x -1 -+ -x -4 -join -x -4 -load -p -5 -I -0 -I -a -I -5 -I -b -I -1c -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/suite.rb -p -0 -x -4 -each -p -15 -I -0 -I -1 -I -9 -I -3 -I -1a -I -5 -I -29 -I -6 -I -32 -I -7 -I -47 -I -9 -I -55 -I -a -I -5f -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/suite.rb -p -2 -x -5 -suite -x -9 -test_case diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/vhdl.rb --- a/vendor/gems/coderay-0.9.7/test/functional/vhdl.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -class VHDL < CodeRay::Scanners::Scanner - - register_for :vhdl - - RESERVED_WORDS = [ - 'access','after','alias','all','assert','architecture','begin', - 'block','body','buffer','bus','case','component','configuration','constant', - 'disconnect','downto','else','elsif','end','entity','exit','file','for', - 'function','generate','generic','group','guarded','if','impure','in', - 'inertial','inout','is','label','library','linkage','literal','loop', - 'map','new','next','null','of','on','open','others','out','package', - 'port','postponed','procedure','process','pure','range','record','register', - 'reject','report','return','select','severity','signal','shared','subtype', - 'then','to','transport','type','unaffected','units','until','use','variable', - 'wait','when','while','with','note','warning','error','failure','and', - 'or','xor','not','nor', - 'array' - ] - - PREDEFINED_TYPES = [ - 'bit','bit_vector','character','boolean','integer','real','time','string', - 'severity_level','positive','natural','signed','unsigned','line','text', - 'std_logic','std_logic_vector','std_ulogic','std_ulogic_vector','qsim_state', - 'qsim_state_vector','qsim_12state','qsim_12state_vector','qsim_strength', - 'mux_bit','mux_vector','reg_bit','reg_vector','wor_bit','wor_vector' - ] - - PREDEFINED_CONSTANTS = [ - - ] - - IDENT_KIND = CodeRay::CaseIgnoringWordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_CONSTANTS, :pre_constant) - - ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - def scan_tokens tokens, options - - state = :initial - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if scan(/ \s+ | \\\n /x) - kind = :space - - elsif scan(/-- .*/x) - kind = :comment - - elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x) - kind = :operator - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = IDENT_KIND[match.downcase] - - elsif match = scan(/[a-z]?"/i) - tokens << [:open, :string] - state = :string - kind = :delimiter - - elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) - kind = :char - - elsif scan(/(?:\d+)(?![.eEfF])/) - kind = :integer - - elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - kind = :float - - else - getch - kind = :error - - end - - when :string - if scan(/[^\\\n"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - -end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/vhdl.rbc --- a/vendor/gems/coderay-0.9.7/test/functional/vhdl.rbc Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2334 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -35 -99 -7 -0 -45 -1 -2 -43 -3 -43 -4 -65 -49 -5 -3 -13 -99 -12 -7 -6 -12 -7 -7 -12 -65 -12 -49 -8 -4 -15 -49 -6 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -9 -x -4 -VHDL -x -7 -CodeRay -n -x -8 -Scanners -x -7 -Scanner -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -4 -VHDL -i -519 -5 -66 -5 -7 -0 -47 -49 -1 -1 -15 -65 -7 -2 -7 -3 -64 -7 -4 -64 -7 -5 -64 -7 -6 -64 -7 -7 -64 -7 -8 -64 -7 -9 -64 -7 -10 -64 -7 -11 -64 -7 -12 -64 -7 -13 -64 -7 -14 -64 -7 -15 -64 -7 -16 -64 -7 -17 -64 -7 -18 -64 -7 -19 -64 -7 -20 -64 -7 -21 -64 -7 -22 -64 -7 -23 -64 -7 -24 -64 -7 -25 -64 -7 -26 -64 -7 -27 -64 -7 -28 -64 -7 -29 -64 -7 -30 -64 -7 -31 -64 -7 -32 -64 -7 -33 -64 -7 -34 -64 -7 -35 -64 -7 -36 -64 -7 -37 -64 -7 -38 -64 -7 -39 -64 -7 -40 -64 -7 -41 -64 -7 -42 -64 -7 -43 -64 -7 -44 -64 -7 -45 -64 -7 -46 -64 -7 -47 -64 -7 -48 -64 -7 -49 -64 -7 -50 -64 -7 -51 -64 -7 -52 -64 -7 -53 -64 -7 -54 -64 -7 -55 -64 -7 -56 -64 -7 -57 -64 -7 -58 -64 -7 -59 -64 -7 -60 -64 -7 -61 -64 -7 -62 -64 -7 -63 -64 -7 -64 -64 -7 -65 -64 -7 -66 -64 -7 -67 -64 -7 -68 -64 -7 -69 -64 -7 -70 -64 -7 -71 -64 -7 -72 -64 -7 -73 -64 -7 -74 -64 -7 -75 -64 -7 -76 -64 -7 -77 -64 -7 -78 -64 -7 -79 -64 -7 -80 -64 -7 -81 -64 -7 -82 -64 -7 -83 -64 -7 -84 -64 -7 -85 -64 -7 -86 -64 -7 -87 -64 -7 -88 -64 -7 -89 -64 -7 -90 -64 -7 -91 -64 -35 -89 -49 -92 -2 -15 -65 -7 -93 -7 -94 -64 -7 -95 -64 -7 -96 -64 -7 -97 -64 -7 -98 -64 -7 -99 -64 -7 -100 -64 -7 -101 -64 -7 -102 -64 -7 -103 -64 -7 -104 -64 -7 -105 -64 -7 -106 -64 -7 -107 -64 -7 -108 -64 -7 -109 -64 -7 -110 -64 -7 -111 -64 -7 -112 -64 -7 -113 -64 -7 -114 -64 -7 -115 -64 -7 -116 -64 -7 -117 -64 -7 -118 -64 -7 -119 -64 -7 -120 -64 -7 -121 -64 -7 -122 -64 -7 -123 -64 -35 -30 -49 -92 -2 -15 -65 -7 -124 -35 -0 -49 -92 -2 -15 -65 -7 -125 -45 -126 -127 -43 -128 -13 -71 -129 -47 -9 -422 -47 -49 -130 -0 -13 -7 -131 -47 -49 -132 -1 -15 -8 -427 -7 -131 -49 -129 -1 -45 -2 -133 -7 -134 -49 -135 -2 -45 -93 -136 -7 -137 -49 -135 -2 -45 -124 -138 -7 -139 -49 -135 -2 -49 -92 -2 -15 -65 -7 -140 -7 -141 -13 -70 -9 -476 -15 -44 -43 -142 -7 -143 -80 -49 -129 -2 -6 -141 -49 -92 -2 -15 -65 -7 -144 -7 -145 -13 -70 -9 -501 -15 -44 -43 -142 -7 -146 -80 -49 -129 -2 -6 -145 -49 -92 -2 -15 -99 -7 -147 -7 -148 -65 -67 -49 -149 -0 -49 -150 -4 -11 -I -5b -I -0 -I -0 -I -0 -n -p -151 -x -4 -vhdl -x -12 -register_for -x -14 -RESERVED_WORDS -s -6 -access -s -5 -after -s -5 -alias -s -3 -all -s -6 -assert -s -12 -architecture -s -5 -begin -s -5 -block -s -4 -body -s -6 -buffer -s -3 -bus -s -4 -case -s -9 -component -s -13 -configuration -s -8 -constant -s -10 -disconnect -s -6 -downto -s -4 -else -s -5 -elsif -s -3 -end -s -6 -entity -s -4 -exit -s -4 -file -s -3 -for -s -8 -function -s -8 -generate -s -7 -generic -s -5 -group -s -7 -guarded -s -2 -if -s -6 -impure -s -2 -in -s -8 -inertial -s -5 -inout -s -2 -is -s -5 -label -s -7 -library -s -7 -linkage -s -7 -literal -s -4 -loop -s -3 -map -s -3 -new -s -4 -next -s -4 -null -s -2 -of -s -2 -on -s -4 -open -s -6 -others -s -3 -out -s -7 -package -s -4 -port -s -9 -postponed -s -9 -procedure -s -7 -process -s -4 -pure -s -5 -range -s -6 -record -s -8 -register -s -6 -reject -s -6 -report -s -6 -return -s -6 -select -s -8 -severity -s -6 -signal -s -6 -shared -s -7 -subtype -s -4 -then -s -2 -to -s -9 -transport -s -4 -type -s -10 -unaffected -s -5 -units -s -5 -until -s -3 -use -s -8 -variable -s -4 -wait -s -4 -when -s -5 -while -s -4 -with -s -4 -note -s -7 -warning -s -5 -error -s -7 -failure -s -3 -and -s -2 -or -s -3 -xor -s -3 -not -s -3 -nor -s -5 -array -x -9 -const_set -x -16 -PREDEFINED_TYPES -s -3 -bit -s -10 -bit_vector -s -9 -character -s -7 -boolean -s -7 -integer -s -4 -real -s -4 -time -s -6 -string -s -14 -severity_level -s -8 -positive -s -7 -natural -s -6 -signed -s -8 -unsigned -s -4 -line -s -4 -text -s -9 -std_logic -s -16 -std_logic_vector -s -10 -std_ulogic -s -17 -std_ulogic_vector -s -10 -qsim_state -s -17 -qsim_state_vector -s -12 -qsim_12state -s -19 -qsim_12state_vector -s -13 -qsim_strength -s -7 -mux_bit -s -10 -mux_vector -s -7 -reg_bit -s -10 -reg_vector -s -7 -wor_bit -s -10 -wor_vector -x -20 -PREDEFINED_CONSTANTS -x -10 -IDENT_KIND -x -7 -CodeRay -n -x -20 -CaseIgnoringWordList -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -n -x -8 -reserved -x -3 -add -n -x -8 -pre_type -n -x -12 -pre_constant -x -6 -ESCAPE -n -x -6 -Regexp -s -49 - [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} -x -14 -UNICODE_ESCAPE -n -s -35 - u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} -x -11 -scan_tokens -M -1 -n -n -x -11 -scan_tokens -i -688 -7 -0 -19 -2 -15 -5 -47 -49 -1 -0 -10 -660 -1 -19 -3 -15 -1 -19 -4 -15 -20 -2 -13 -7 -0 -12 -49 -2 -1 -9 -331 -15 -5 -7 -3 -13 -70 -9 -51 -15 -44 -43 -4 -7 -5 -80 -49 -6 -2 -6 -3 -47 -49 -7 -1 -9 -63 -7 -8 -19 -3 -8 -329 -5 -7 -9 -13 -70 -9 -82 -15 -44 -43 -4 -7 -10 -80 -49 -6 -2 -6 -9 -47 -49 -7 -1 -9 -94 -7 -11 -19 -3 -8 -329 -5 -7 -12 -13 -70 -9 -113 -15 -44 -43 -4 -7 -13 -80 -49 -6 -2 -6 -12 -47 -49 -7 -1 -9 -125 -7 -14 -19 -3 -8 -329 -5 -7 -15 -13 -70 -9 -144 -15 -44 -43 -4 -7 -16 -80 -49 -6 -2 -6 -15 -47 -49 -7 -1 -19 -4 -9 -167 -45 -17 -18 -20 -4 -49 -19 -0 -49 -20 -1 -19 -3 -8 -329 -5 -7 -21 -13 -70 -9 -186 -15 -44 -43 -4 -7 -22 -79 -49 -6 -2 -6 -21 -47 -49 -7 -1 -19 -4 -9 -217 -20 -0 -7 -23 -7 -24 -35 -2 -49 -25 -1 -15 -7 -24 -19 -2 -15 -7 -26 -19 -3 -8 -329 -5 -7 -27 -13 -70 -9 -247 -15 -44 -43 -4 -7 -28 -45 -29 -30 -47 -49 -31 -0 -7 -32 -63 -3 -80 -49 -6 -2 -6 -27 -47 -49 -7 -1 -9 -259 -7 -33 -19 -3 -8 -329 -5 -7 -34 -13 -70 -9 -278 -15 -44 -43 -4 -7 -35 -78 -49 -6 -2 -6 -34 -47 -49 -7 -1 -9 -290 -7 -36 -19 -3 -8 -329 -5 -7 -37 -13 -70 -9 -309 -15 -44 -43 -4 -7 -38 -78 -49 -6 -2 -6 -37 -47 -49 -7 -1 -9 -321 -7 -39 -19 -3 -8 -329 -5 -48 -40 -15 -7 -41 -19 -3 -8 -564 -13 -7 -24 -12 -49 -2 -1 -9 -553 -15 -5 -7 -42 -13 -70 -9 -360 -15 -44 -43 -4 -7 -43 -78 -49 -6 -2 -6 -42 -47 -49 -7 -1 -9 -372 -7 -44 -19 -3 -8 -551 -5 -7 -45 -13 -70 -9 -391 -15 -44 -43 -4 -7 -46 -78 -49 -6 -2 -6 -45 -47 -49 -7 -1 -9 -432 -20 -0 -7 -46 -64 -7 -26 -35 -2 -49 -25 -1 -15 -20 -0 -7 -47 -7 -24 -35 -2 -49 -25 -1 -15 -7 -0 -19 -2 -15 -1 -8 -656 -8 -551 -5 -7 -48 -13 -70 -9 -472 -15 -44 -43 -4 -7 -49 -45 -29 -50 -47 -49 -31 -0 -7 -51 -45 -52 -53 -47 -49 -31 -0 -7 -54 -63 -5 -4 -6 -49 -6 -2 -6 -48 -47 -49 -7 -1 -9 -484 -7 -33 -19 -3 -8 -551 -5 -7 -55 -13 -70 -9 -503 -15 -44 -43 -4 -7 -56 -80 -49 -6 -2 -6 -55 -47 -49 -7 -1 -9 -532 -20 -0 -7 -47 -7 -24 -35 -2 -49 -25 -1 -15 -7 -41 -19 -3 -15 -7 -0 -19 -2 -8 -551 -5 -7 -57 -64 -5 -79 -47 -49 -58 -1 -49 -59 -1 -20 -0 -47 -49 -60 -2 -8 -564 -15 -5 -7 -61 -64 -20 -0 -47 -49 -60 -2 -15 -20 -4 -13 -10 -576 -15 -5 -48 -62 -19 -4 -15 -99 -43 -63 -7 -64 -49 -20 -1 -13 -9 -597 -15 -20 -3 -10 -596 -2 -8 -597 -3 -9 -625 -5 -7 -65 -64 -20 -4 -20 -3 -35 -2 -5 -48 -66 -35 -2 -49 -59 -1 -20 -0 -47 -49 -60 -2 -8 -626 -1 -15 -20 -4 -9 -634 -1 -8 -644 -5 -7 -67 -64 -20 -0 -47 -49 -60 -2 -15 -20 -0 -20 -4 -20 -3 -35 -2 -49 -25 -1 -15 -68 -8 -5 -1 -15 -20 -2 -7 -24 -83 -68 -9 -683 -20 -0 -7 -47 -7 -24 -35 -2 -49 -25 -1 -8 -684 -1 -15 -20 -0 -11 -I -c -I -5 -I -2 -I -2 -n -p -69 -x -7 -initial -x -4 -eos? -x -3 -=== -n -x -6 -Regexp -s -12 - \s+ | \\\n -x -3 -new -x -4 -scan -x -5 -space -n -s -5 --- .* -x -7 -comment -n -s -42 - [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) -x -8 -operator -n -s -24 - [A-Za-z_][A-Za-z_0-9]* -x -10 -IDENT_KIND -n -x -8 -downcase -x -2 -[] -n -s -7 -[a-z]?" -x -4 -open -x -6 -string -x -2 -<< -x -9 -delimiter -n -s -24 - L?' (?: [^\'\n\\] | \\ -x -6 -ESCAPE -n -x -4 -to_s -s -7 - )? '? -x -4 -char -n -s -18 -(?:\d+)(?![.eEfF]) -x -7 -integer -n -s -59 -\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]? -x -5 -float -x -5 -getch -x -5 -error -n -s -9 -[^\\\n"]+ -x -7 -content -n -s -1 -" -x -5 -close -n -s -8 - \\ (?: -n -s -3 - | -x -14 -UNICODE_ESCAPE -n -s -3 - ) -n -s -8 - \\ | $ -s -36 -else case " reached; %p not handled. -x -4 -peek -x -1 -% -x -13 -raise_inspect -s -13 -Unknown state -x -7 -matched -x -7 -Globals -x -6 -$DEBUG -s -25 -Error token %p in line %d -x -4 -line -s -11 -Empty token -x -2 -== -p -111 -I -0 -I -28 -I -0 -I -2a -I -5 -I -2c -I -c -I -2e -I -10 -I -2f -I -14 -I -31 -I -17 -I -33 -I -20 -I -35 -I -39 -I -36 -I -3f -I -38 -I -58 -I -39 -I -5e -I -3b -I -77 -I -3c -I -7d -I -3e -I -98 -I -3f -I -a7 -I -41 -I -c2 -I -42 -I -ce -I -43 -I -d3 -I -44 -I -d9 -I -46 -I -fd -I -47 -I -103 -I -49 -I -11c -I -4a -I -122 -I -4c -I -13b -I -4d -I -141 -I -50 -I -145 -I -51 -I -14c -I -55 -I -155 -I -56 -I -16e -I -57 -I -174 -I -58 -I -18d -I -59 -I -19a -I -5a -I -1a6 -I -5b -I -1ab -I -5c -I -1b0 -I -5d -I -1de -I -5e -I -1e4 -I -5f -I -1fd -I -60 -I -209 -I -61 -I -20e -I -62 -I -214 -I -64 -I -22a -I -68 -I -235 -I -6c -I -241 -I -6d -I -257 -I -6f -I -258 -I -6e -I -25b -I -6f -I -271 -I -6d -I -273 -I -71 -I -285 -I -73 -I -296 -I -77 -I -29e -I -78 -I -2ab -I -77 -I -2ad -I -7b -I -2b0 -x -54 -/Users/murphy/ruby/coderay-0.9/test/functional/vhdl.rb -p -5 -x -6 -tokens -x -7 -options -x -5 -state -x -4 -kind -x -5 -match -x -17 -method_visibility -x -15 -add_defn_method -p -65 -I -2 -I -3 -I -a -I -5 -I -d -I -6 -I -22 -I -7 -I -3a -I -8 -I -55 -I -9 -I -6d -I -a -I -85 -I -b -I -a3 -I -c -I -bb -I -d -I -d3 -I -e -I -ee -I -f -I -109 -I -10 -I -115 -I -11 -I -11e -I -14 -I -121 -I -15 -I -139 -I -16 -I -14e -I -17 -I -15d -I -18 -I -169 -I -19 -I -181 -I -1c -I -184 -I -1e -I -18a -I -20 -I -1ab -I -21 -I -1b0 -I -20 -I -1b3 -I -22 -I -1b8 -I -20 -I -1bb -I -23 -I -1c0 -I -20 -I -1c7 -I -25 -I -1e0 -I -26 -I -1f9 -I -28 -I -207 -x -54 -/Users/murphy/ruby/coderay-0.9/test/functional/vhdl.rb -p -0 -x -13 -attach_method -p -3 -I -0 -I -1 -I -23 -x -54 -/Users/murphy/ruby/coderay-0.9/test/functional/vhdl.rb -p -0 diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/word_list.rb --- a/vendor/gems/coderay-0.9.7/test/functional/word_list.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -require 'test/unit' -require 'coderay' - -class WordListTest < Test::Unit::TestCase - - include CodeRay - - # define word arrays - RESERVED_WORDS = %w[ - asm break case continue default do else - ... - ] - - PREDEFINED_TYPES = %w[ - int long short char void - ... - ] - - PREDEFINED_CONSTANTS = %w[ - EOF NULL ... - ] - - # make a WordList - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_CONSTANTS, :pre_constant) - - def test_word_list_example - assert_equal :pre_type, IDENT_KIND['void'] - # assert_equal :pre_constant, IDENT_KIND['...'] # not specified - end - - def test_word_list - list = WordList.new(:ident).add(['foobar'], :reserved) - assert_equal :reserved, list['foobar'] - assert_equal :ident, list['FooBar'] - end - - def test_word_list_cached - list = WordList.new(:ident, true).add(['foobar'], :reserved) - assert_equal :reserved, list['foobar'] - assert_equal :ident, list['FooBar'] - end - - def test_case_ignoring_word_list - list = CaseIgnoringWordList.new(:ident).add(['foobar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - - list = CaseIgnoringWordList.new(:ident).add(['FooBar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - end - - def test_case_ignoring_word_list_cached - list = CaseIgnoringWordList.new(:ident, true).add(['foobar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - - list = CaseIgnoringWordList.new(:ident, true).add(['FooBar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - end - - def test_dup - list = WordList.new(:ident).add(['foobar'], :reserved) - assert_equal :reserved, list['foobar'] - list2 = list.dup - list2.add(%w[foobar], :keyword) - assert_equal :keyword, list2['foobar'] - assert_equal :reserved, list['foobar'] - end - -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-0.9.7/test/functional/word_list.rbc --- a/vendor/gems/coderay-0.9.7/test/functional/word_list.rbc Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1763 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -53 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -47 -49 -1 -1 -15 -99 -7 -3 -45 -4 -5 -43 -6 -43 -7 -65 -49 -8 -3 -13 -99 -12 -7 -9 -12 -7 -10 -12 -65 -12 -49 -11 -4 -15 -49 -9 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -12 -s -9 -test/unit -x -7 -require -s -7 -coderay -x -12 -WordListTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -12 -WordListTest -i -232 -5 -66 -5 -45 -0 -1 -47 -49 -2 -1 -15 -65 -7 -3 -7 -4 -64 -7 -5 -64 -7 -6 -64 -7 -7 -64 -7 -8 -64 -7 -9 -64 -7 -10 -64 -7 -11 -64 -35 -8 -49 -12 -2 -15 -65 -7 -13 -7 -14 -64 -7 -15 -64 -7 -16 -64 -7 -17 -64 -7 -18 -64 -7 -11 -64 -35 -6 -49 -12 -2 -15 -65 -7 -19 -7 -20 -64 -7 -21 -64 -7 -11 -64 -35 -3 -49 -12 -2 -15 -65 -7 -22 -45 -23 -24 -13 -71 -25 -47 -9 -115 -47 -49 -26 -0 -13 -7 -27 -47 -49 -28 -1 -15 -8 -120 -7 -27 -49 -25 -1 -45 -3 -29 -7 -30 -49 -31 -2 -45 -13 -32 -7 -33 -49 -31 -2 -45 -19 -34 -7 -35 -49 -31 -2 -49 -12 -2 -15 -99 -7 -36 -7 -37 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -40 -7 -41 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -42 -7 -43 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -44 -7 -45 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -46 -7 -47 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -48 -7 -49 -65 -67 -49 -38 -0 -49 -39 -4 -11 -I -a -I -0 -I -0 -I -0 -n -p -50 -x -7 -CodeRay -n -x -7 -include -x -14 -RESERVED_WORDS -s -3 -asm -s -5 -break -s -4 -case -s -8 -continue -s -7 -default -s -2 -do -s -4 -else -s -3 -... -x -9 -const_set -x -16 -PREDEFINED_TYPES -s -3 -int -s -4 -long -s -5 -short -s -4 -char -s -4 -void -x -20 -PREDEFINED_CONSTANTS -s -3 -EOF -s -4 -NULL -x -10 -IDENT_KIND -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -n -x -8 -reserved -x -3 -add -n -x -8 -pre_type -n -x -12 -pre_constant -x -22 -test_word_list_example -M -1 -n -n -x -22 -test_word_list_example -i -17 -5 -7 -0 -45 -1 -2 -7 -3 -64 -49 -4 -1 -47 -49 -5 -2 -11 -I -4 -I -0 -I -0 -I -0 -n -p -6 -x -8 -pre_type -x -10 -IDENT_KIND -n -s -4 -void -x -2 -[] -x -12 -assert_equal -p -5 -I -0 -I -1d -I -0 -I -1e -I -11 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -x -14 -test_word_list -M -1 -n -n -x -14 -test_word_list -i -73 -45 -0 -1 -13 -71 -2 -47 -9 -23 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -28 -7 -4 -49 -2 -1 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -5 -7 -4 -20 -0 -7 -11 -64 -49 -9 -1 -47 -49 -10 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -12 -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -p -9 -I -0 -I -22 -I -0 -I -23 -I -29 -I -24 -I -39 -I -25 -I -49 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -21 -test_word_list_cached -M -1 -n -n -x -21 -test_word_list_cached -i -75 -45 -0 -1 -13 -71 -2 -47 -9 -24 -47 -49 -3 -0 -13 -7 -4 -2 -47 -49 -5 -2 -15 -8 -30 -7 -4 -2 -49 -2 -2 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -5 -7 -4 -20 -0 -7 -11 -64 -49 -9 -1 -47 -49 -10 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -12 -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -p -9 -I -0 -I -28 -I -0 -I -29 -I -2b -I -2a -I -3b -I -2b -I -4b -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -28 -test_case_ignoring_word_list -M -1 -n -n -x -28 -test_case_ignoring_word_list -i -178 -45 -0 -1 -13 -71 -2 -47 -9 -23 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -28 -7 -4 -49 -2 -1 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -15 -45 -0 -13 -13 -71 -2 -47 -9 -112 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -117 -7 -4 -49 -2 -1 -7 -12 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -14 -x -20 -CaseIgnoringWordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -s -3 -foo -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -n -p -19 -I -0 -I -2e -I -0 -I -2f -I -29 -I -30 -I -39 -I -31 -I -49 -I -32 -I -59 -I -34 -I -82 -I -35 -I -92 -I -36 -I -a2 -I -37 -I -b2 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -35 -test_case_ignoring_word_list_cached -M -1 -n -n -x -35 -test_case_ignoring_word_list_cached -i -182 -45 -0 -1 -13 -71 -2 -47 -9 -24 -47 -49 -3 -0 -13 -7 -4 -2 -47 -49 -5 -2 -15 -8 -30 -7 -4 -2 -49 -2 -2 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -15 -45 -0 -13 -13 -71 -2 -47 -9 -115 -47 -49 -3 -0 -13 -7 -4 -2 -47 -49 -5 -2 -15 -8 -121 -7 -4 -2 -49 -2 -2 -7 -12 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -14 -x -20 -CaseIgnoringWordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -s -3 -foo -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -n -p -19 -I -0 -I -3a -I -0 -I -3b -I -2b -I -3c -I -3b -I -3d -I -4b -I -3e -I -5b -I -40 -I -86 -I -41 -I -96 -I -42 -I -a6 -I -43 -I -b6 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -8 -test_dup -M -1 -n -n -x -8 -test_dup -i -110 -45 -0 -1 -13 -71 -2 -47 -9 -23 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -28 -7 -4 -49 -2 -1 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -20 -0 -49 -11 -0 -19 -1 -15 -20 -1 -7 -6 -64 -35 -1 -7 -12 -49 -8 -2 -15 -5 -7 -12 -20 -1 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -11 -I -6 -I -2 -I -0 -I -0 -n -p -13 -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -x -2 -[] -x -12 -assert_equal -x -3 -dup -x -7 -keyword -p -15 -I -0 -I -46 -I -0 -I -47 -I -29 -I -48 -I -39 -I -49 -I -41 -I -4a -I -4e -I -4b -I -5e -I -4c -I -6e -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -2 -x -4 -list -x -5 -list2 -p -45 -I -2 -I -6 -I -b -I -9 -I -e -I -a -I -23 -I -b -I -2c -I -e -I -2f -I -f -I -3e -I -10 -I -47 -I -13 -I -4a -I -14 -I -59 -I -18 -I -78 -I -19 -I -7d -I -18 -I -80 -I -1a -I -85 -I -18 -I -88 -I -1b -I -8d -I -18 -I -94 -I -1d -I -a2 -I -22 -I -b0 -I -28 -I -be -I -2e -I -cc -I -3a -I -da -I -46 -I -e8 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -0 -x -13 -attach_method -p -7 -I -0 -I -1 -I -9 -I -2 -I -12 -I -4 -I -35 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -0 diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/.specification --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/.specification Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,78 @@ +--- !ruby/object:Gem::Specification +name: coderay +version: !ruby/object:Gem::Version + hash: 23 + prerelease: + segments: + - 1 + - 0 + - 0 + version: 1.0.0 +platform: ruby +authors: +- Kornelius Kalnbach +autorequire: +bindir: bin +cert_chain: [] + +date: 2011-09-21 00:00:00 Z +default_executable: coderay +dependencies: [] + +description: Fast and easy syntax highlighting for selected languages, written in Ruby. Comes with RedCloth integration and LOC counter. +email: +- murphy@rubychan.de +executables: +- coderay +extensions: [] + +extra_rdoc_files: [] + +files: +- test/functional/basic.rb +- test/functional/examples.rb +- test/functional/for_redcloth.rb +- test/functional/suite.rb +- bin/coderay +has_rdoc: true +homepage: http://coderay.rubychan.de +licenses: [] + +post_install_message: +rdoc_options: [] + +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 59 + segments: + - 1 + - 8 + - 6 + version: 1.8.6 +required_rubygems_version: !ruby/object:Gem::Requirement + none: false + requirements: + - - ">=" + - !ruby/object:Gem::Version + hash: 3 + segments: + - 0 + version: "0" +requirements: [] + +rubyforge_project: coderay +rubygems_version: 1.6.2 +signing_key: +specification_version: 3 +summary: Fast syntax highlighting for selected languages. +test_files: +- test/functional/basic.rb +- test/functional/examples.rb +- test/functional/for_redcloth.rb +- test/functional/suite.rb + diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/LICENSE Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/README_INDEX.rdoc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/README_INDEX.rdoc Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,123 @@ += CodeRay + +Tired of blue'n'gray? Try the original version of this documentation on +coderay.rubychan.de[http://coderay.rubychan.de/doc/] :-) + +== About + +CodeRay is a Ruby library for syntax highlighting. + +You put your code in, and you get it back colored; Keywords, strings, +floats, comments - all in different colors. And with line numbers. + +*Syntax* *Highlighting*... +* makes code easier to read and maintain +* lets you detect syntax errors faster +* helps you to understand the syntax of a language +* looks nice +* is what everybody wants to have on their website +* solves all your problems and makes the girls run after you + + +== Installation + + % gem install coderay + + +=== Dependencies + +CodeRay needs Ruby 1.8.7+ or 1.9.2+. It also runs on Rubinius and JRuby. + + +== Example Usage + + require 'coderay' + + html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table) + + +== Documentation + +See CodeRay. + + +== Credits + +=== Special Thanks to + +* licenser (Heinz N. Gies) for ending my QBasic career, inventing the Coder + project and the input/output plugin system. + CodeRay would not exist without him. +* bovi (Daniel Bovensiepen) for helping me out on various occasions. + +=== Thanks to + +* Caleb Clausen for writing RubyLexer (see + http://rubyforge.org/projects/rubylexer) and lots of very interesting mail + traffic +* birkenfeld (Georg Brandl) and mitsuhiku (Arnim Ronacher) for PyKleur, now pygments. + You guys rock! +* Jamis Buck for writing Syntax (see http://rubyforge.org/projects/syntax) + I got some useful ideas from it. +* Doug Kearns and everyone else who worked on ruby.vim - it not only helped me + coding CodeRay, but also gave me a wonderful target to reach for the Ruby + scanner. +* everyone who uses CodeBB on http://www.rubyforen.de and http://www.python-forum.de +* iGEL, magichisoka, manveru, WoNáDo and everyone I forgot from rubyforen.de +* Dethix from ruby-mine.de +* zickzackw +* Dookie (who is no longer with us...) and Leonidas from http://www.python-forum.de +* Andreas Schwarz for finding out that CaseIgnoringWordList was not case + ignoring! Such things really make you write tests. +* closure for the first version of the Scheme scanner. +* Stefan Walk for the first version of the JavaScript and PHP scanners. +* Josh Goebel for another version of the JavaScript scanner, a SQL and a Diff scanner. +* Jonathan Younger for pointing out the licence confusion caused by wrong LICENSE file. +* Jeremy Hinegardner for finding the shebang-on-empty-file bug in FileType. +* Charles Oliver Nutter and Yehuda Katz for helping me benchmark CodeRay on JRuby. +* Andreas Neuhaus for pointing out a markup bug in coderay/for_redcloth. +* 0xf30fc7 for the FileType patch concerning Delphi file extensions. +* The folks at redmine.org - thank you for using and fixing CodeRay! +* Keith Pitt for his SQL scanners +* Rob Aldred for the terminal encoder +* Trans for pointing out $DEBUG dependencies +* Flameeyes for finding that Term::ANSIColor was obsolete +* matz and all Ruby gods and gurus +* The inventors of: the computer, the internet, the true color display, HTML & + CSS, VIM, Ruby, pizza, microwaves, guitars, scouting, programming, anime, + manga, coke and green ice tea. + +Where would we be without all those people? + +=== Created using + +* Ruby[http://ruby-lang.org/] +* Chihiro (my Sony VAIO laptop); Henrietta (my old MacBook); + Triella, born Rico (my new MacBook); as well as + Seras and Hikari (my PCs) +* RDE[http://homepage2.nifty.com/sakazuki/rde_e.html], + VIM[http://vim.org] and TextMate[http://macromates.com] +* Subversion[http://subversion.tigris.org/] +* Redmine[http://redmine.org/] +* Firefox[http://www.mozilla.org/products/firefox/], + Firebug[http://getfirebug.com/], Safari[http://www.apple.com/safari/], and + Thunderbird[http://www.mozilla.org/products/thunderbird/] +* RubyGems[http://docs.rubygems.org/] and Rake[http://rake.rubyforge.org/] +* TortoiseSVN[http://tortoisesvn.tigris.org/] using Apache via + XAMPP[http://www.apachefriends.org/en/xampp.html] +* RDoc (though I'm quite unsatisfied with it) +* Microsoft Windows (yes, I confess!) and MacOS X +* GNUWin32, MinGW and some other tools to make the shell under windows a bit + less useless +* Term::ANSIColor[http://term-ansicolor.rubyforge.org/] +* PLEAC[http://pleac.sourceforge.net/] code examples +* Github +* Travis CI (http://travis-ci.org/rubychan/github) + +=== Free + +* As you can see, CodeRay was created under heavy use of *free* software. +* So CodeRay is also *free*. +* If you use CodeRay to create software, think about making this software + *free*, too. +* Thanks :) diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/Rakefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/Rakefile Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,35 @@ +$:.unshift File.dirname(__FILE__) unless $:.include? '.' + +ROOT = '.' +LIB_ROOT = File.join ROOT, 'lib' + +task :default => :test + +if File.directory? 'rake_tasks' + + # load rake tasks from subfolder + for task_file in Dir['rake_tasks/*.rake'].sort + load task_file + end + +else + + # fallback tasks when rake_tasks folder is not present (eg. in the distribution package) + desc 'Run CodeRay tests (basic)' + task :test do + ruby './test/functional/suite.rb' + ruby './test/functional/for_redcloth.rb' + end + + gem 'rdoc' if defined? gem + require 'rdoc/task' + desc 'Generate documentation for CodeRay' + Rake::RDocTask.new :doc do |rd| + rd.title = 'CodeRay Documentation' + rd.main = 'README_INDEX.rdoc' + rd.rdoc_files.add Dir['lib'] + rd.rdoc_files.add rd.main + rd.rdoc_dir = 'doc' + end + +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/bin/coderay --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/bin/coderay Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,215 @@ +#!/usr/bin/env ruby +require 'coderay' + +$options, args = ARGV.partition { |arg| arg[/^-[hv]$|--\w+/] } +subcommand = args.first if /^\w/ === args.first +subcommand = nil if subcommand && File.exist?(subcommand) +args.delete subcommand + +def option? *options + !($options & options).empty? +end + +def tty? + $stdout.tty? || option?('--tty') +end + +def version + puts <<-USAGE +CodeRay #{CodeRay::VERSION} + USAGE +end + +def help + puts <<-HELP +This is CodeRay #{CodeRay::VERSION}, a syntax highlighting tool for selected languages. + +usage: + coderay [-language] [input] [-format] [output] + +defaults: + language detect from input file name or shebang; fall back to plain text + input STDIN + format detect from output file name or use terminal; fall back to HTML + output STDOUT + +common: + coderay file.rb # highlight file to terminal + coderay file.rb > file.html # highlight file to HTML page + coderay file.rb -div > file.html # highlight file to HTML snippet + +configure output: + coderay file.py output.json # output tokens as JSON + coderay file.py -loc # count lines of code in Python file + +configure input: + coderay -python file # specify the input language + coderay -ruby # take input from STDIN + +more: + coderay stylesheet [style] # print CSS stylesheet + HELP +end + +def commands + puts <<-COMMANDS + general: + highlight code highlighting (default command, optional) + stylesheet print the CSS stylesheet with the given name (aliases: style, css) + + about: + list [of] list all available plugins (or just the scanners|encoders|styles|filetypes) + commands print this list + help show some help + version print CodeRay version + COMMANDS +end + +def print_list_of plugin_host + plugins = plugin_host.all_plugins.map do |plugin| + info = " #{plugin.plugin_id}: #{plugin.title}" + + aliases = (plugin.aliases - [:default]).map { |key| "-#{key}" }.sort_by { |key| key.size } + if plugin.respond_to?(:file_extension) || !aliases.empty? + additional_info = [] + additional_info << aliases.join(', ') unless aliases.empty? + info << " (#{additional_info.join('; ')})" + end + + info << ' <-- default' if plugin.aliases.include? :default + + info + end + puts plugins.sort +end + +if option? '-v', '--version' + version +end + +if option? '-h', '--help' + help +end + +case subcommand +when 'highlight', nil + if ARGV.empty? + version + help + else + signature = args.map { |arg| arg[/^-/] ? '-' : 'f' }.join + names = args.map { |arg| arg.sub(/^-/, '') } + case signature + when /^$/ + exit + when /^ff?$/ + input_file, output_file, = *names + when /^f-f?$/ + input_file, output_format, output_file, = *names + when /^-ff?$/ + input_lang, input_file, output_file, = *names + when /^-f-f?$/ + input_lang, input_file, output_format, output_file, = *names + when /^--?f?$/ + input_lang, output_format, output_file, = *names + else + $stdout = $stderr + help + puts + puts "Unknown parameter order: #{args.join ' '}, expected: [-language] [input] [-format] [output]" + exit 1 + end + + if input_file + input_lang ||= CodeRay::FileType.fetch input_file, :text, true + end + + if output_file + output_format ||= CodeRay::FileType[output_file] + else + output_format ||= :terminal + end + + output_format = :page if output_format.to_s == 'html' + + if input_file + input = File.read input_file + else + input = $stdin.read + end + + begin + file = + if output_file + File.open output_file, 'w' + else + $stdout.sync = true + $stdout + end + CodeRay.encode(input, input_lang, output_format, :out => file) + file.puts + rescue CodeRay::PluginHost::PluginNotFound => boom + $stdout = $stderr + if boom.message[/CodeRay::(\w+)s could not load plugin :?(.*?): /] + puts "I don't know the #$1 \"#$2\"." + else + puts boom.message + end + # puts "I don't know this plugin: #{boom.message[/Could not load plugin (.*?): /, 1]}." + rescue CodeRay::Scanners::Scanner::ScanError # FIXME: rescue Errno::EPIPE + # this is sometimes raised by pagers; ignore [TODO: wtf?] + ensure + file.close if output_file + end + end +when 'li', 'list' + arg = args.first && args.first.downcase + if [nil, 's', 'sc', 'scanner', 'scanners'].include? arg + puts 'input languages (Scanners):' + print_list_of CodeRay::Scanners + end + + if [nil, 'e', 'en', 'enc', 'encoder', 'encoders'].include? arg + puts 'output formats (Encoders):' + print_list_of CodeRay::Encoders + end + + if [nil, 'st', 'style', 'styles'].include? arg + puts 'CSS themes for HTML output (Styles):' + print_list_of CodeRay::Styles + end + + if [nil, 'f', 'ft', 'file', 'filetype', 'filetypes'].include? arg + puts 'recognized file types:' + + filetypes = Hash.new { |h, k| h[k] = [] } + CodeRay::FileType::TypeFromExt.inject filetypes do |types, (ext, type)| + types[type.to_s] << ".#{ext}" + types + end + CodeRay::FileType::TypeFromName.inject filetypes do |types, (name, type)| + types[type.to_s] << name + types + end + + filetypes.sort.each do |type, exts| + puts " #{type}: #{exts.sort_by { |ext| ext.size }.join(', ')}" + end + end +when 'stylesheet', 'style', 'css' + puts CodeRay::Encoders[:html]::CSS.new(args.first).stylesheet +when 'commands' + commands +when 'help' + help +else + $stdout = $stderr + help + puts + if subcommand[/\A\w+\z/] + puts "Unknown command: #{subcommand}" + else + puts "File not found: #{subcommand}" + end + exit 1 +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,278 @@ +# encoding: utf-8 +# Encoding.default_internal = 'UTF-8' + +# = CodeRay Library +# +# CodeRay is a Ruby library for syntax highlighting. +# +# I try to make CodeRay easy to use and intuitive, but at the same time fully +# featured, complete, fast and efficient. +# +# See README. +# +# It consists mainly of +# * the main engine: CodeRay (Scanners::Scanner, Tokens, Encoders::Encoder) +# * the plugin system: PluginHost, Plugin +# * the scanners in CodeRay::Scanners +# * the encoders in CodeRay::Encoders +# * the styles in CodeRay::Styles +# +# Here's a fancy graphic to light up this gray docu: +# +# http://cycnus.de/raindark/coderay/scheme.png +# +# == Documentation +# +# See CodeRay, Encoders, Scanners, Tokens. +# +# == Usage +# +# Remember you need RubyGems to use CodeRay, unless you have it in your load +# path. Run Ruby with -rubygems option if required. +# +# === Highlight Ruby code in a string as html +# +# require 'coderay' +# print CodeRay.scan('puts "Hello, world!"', :ruby).html +# +# # prints something like this: +# puts "Hello, world!" +# +# +# === Highlight C code from a file in a html div +# +# require 'coderay' +# print CodeRay.scan(File.read('ruby.h'), :c).div +# print CodeRay.scan_file('ruby.h').html.div +# +# You can include this div in your page. The used CSS styles can be printed with +# +# % coderay_stylesheet +# +# === Highlight without typing too much +# +# If you are one of the hasty (or lazy, or extremely curious) people, just run this file: +# +# % ruby -rubygems /path/to/coderay/coderay.rb > example.html +# +# and look at the file it created in your browser. +# +# = CodeRay Module +# +# The CodeRay module provides convenience methods for the engine. +# +# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are +# simply lower-case symbols, like :python or :html. +# * All methods take an optional hash as last parameter, +options+, that is send to +# the Encoder / Scanner. +# * Input and language are always sorted in this order: +code+, +lang+. +# (This is in alphabetical order, if you need a mnemonic ;) +# +# You should be able to highlight everything you want just using these methods; +# so there is no need to dive into CodeRay's deep class hierarchy. +# +# The examples in the demo directory demonstrate common cases using this interface. +# +# = Basic Access Ways +# +# Read this to get a general view what CodeRay provides. +# +# == Scanning +# +# Scanning means analysing an input string, splitting it up into Tokens. +# Each Token knows about what type it is: string, comment, class name, etc. +# +# Each +lang+ (language) has its own Scanner; for example, :ruby code is +# handled by CodeRay::Scanners::Ruby. +# +# CodeRay.scan:: Scan a string in a given language into Tokens. +# This is the most common method to use. +# CodeRay.scan_file:: Scan a file and guess the language using FileType. +# +# The Tokens object you get from these methods can encode itself; see Tokens. +# +# == Encoding +# +# Encoding means compiling Tokens into an output. This can be colored HTML or +# LaTeX, a textual statistic or just the number of non-whitespace tokens. +# +# Each Encoder provides output in a specific +format+, so you select Encoders via +# formats like :html or :statistic. +# +# CodeRay.encode:: Scan and encode a string in a given language. +# CodeRay.encode_tokens:: Encode the given tokens. +# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it. +# +# == All-in-One Encoding +# +# CodeRay.encode:: Highlight a string with a given input and output format. +# +# == Instanciating +# +# You can use an Encoder instance to highlight multiple inputs. This way, the setup +# for this Encoder must only be done once. +# +# CodeRay.encoder:: Create an Encoder instance with format and options. +# CodeRay.scanner:: Create an Scanner instance for lang, with '' as default code. +# +# To make use of CodeRay.scanner, use CodeRay::Scanner::code=. +# +# The scanning methods provide more flexibility; we recommend to use these. +# +# == Reusing Scanners and Encoders +# +# If you want to re-use scanners and encoders (because that is faster), see +# CodeRay::Duo for the most convenient (and recommended) interface. +module CodeRay + + $CODERAY_DEBUG ||= false + + require 'coderay/version' + + # helpers + autoload :FileType, 'coderay/helpers/file_type' + + # Tokens + autoload :Tokens, 'coderay/tokens' + autoload :TokensProxy, 'coderay/tokens_proxy' + autoload :TokenKinds, 'coderay/token_kinds' + + # Plugin system + autoload :PluginHost, 'coderay/helpers/plugin' + autoload :Plugin, 'coderay/helpers/plugin' + + # Plugins + autoload :Scanners, 'coderay/scanner' + autoload :Encoders, 'coderay/encoder' + autoload :Styles, 'coderay/style' + + # Convenience access and reusable Encoder/Scanner pair + autoload :Duo, 'coderay/duo' + + class << self + + # Scans the given +code+ (a String) with the Scanner for +lang+. + # + # This is a simple way to use CodeRay. Example: + # require 'coderay' + # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html + # + # See also demo/demo_simple. + def scan code, lang, options = {}, &block + # FIXME: return a proxy for direct-stream encoding + TokensProxy.new code, lang, options, block + end + + # Scans +filename+ (a path to a code file) with the Scanner for +lang+. + # + # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to + # determine it. If it cannot find out what type it is, it uses + # CodeRay::Scanners::Text. + # + # Calls CodeRay.scan. + # + # Example: + # require 'coderay' + # page = CodeRay.scan_file('some_c_code.c').html + def scan_file filename, lang = :auto, options = {}, &block + lang = FileType.fetch filename, :text, true if lang == :auto + code = File.read filename + scan code, lang, options, &block + end + + # Encode a string. + # + # This scans +code+ with the the Scanner for +lang+ and then + # encodes it with the Encoder for +format+. + # +options+ will be passed to the Encoder. + # + # See CodeRay::Encoder.encode. + def encode code, lang, format, options = {} + encoder(format, options).encode code, lang, options + end + + # Encode pre-scanned Tokens. + # Use this together with CodeRay.scan: + # + # require 'coderay' + # + # # Highlight a short Ruby code example in a HTML span + # tokens = CodeRay.scan '1 + 2', :ruby + # puts CodeRay.encode_tokens(tokens, :span) + # + def encode_tokens tokens, format, options = {} + encoder(format, options).encode_tokens tokens, options + end + + # Encodes +filename+ (a path to a code file) with the Scanner for +lang+. + # + # See CodeRay.scan_file. + # Notice that the second argument is the output +format+, not the input language. + # + # Example: + # require 'coderay' + # page = CodeRay.encode_file 'some_c_code.c', :html + def encode_file filename, format, options = {} + tokens = scan_file filename, :auto, get_scanner_options(options) + encode_tokens tokens, format, options + end + + # Highlight a string into a HTML
    . + # + # CSS styles use classes, so you have to include a stylesheet + # in your output. + # + # See encode. + def highlight code, lang, options = { :css => :class }, format = :div + encode code, lang, format, options + end + + # Highlight a file into a HTML
    . + # + # CSS styles use classes, so you have to include a stylesheet + # in your output. + # + # See encode. + def highlight_file filename, options = { :css => :class }, format = :div + encode_file filename, format, options + end + + # Finds the Encoder class for +format+ and creates an instance, passing + # +options+ to it. + # + # Example: + # require 'coderay' + # + # stats = CodeRay.encoder(:statistic) + # stats.encode("puts 17 + 4\n", :ruby) + # + # puts '%d out of %d tokens have the kind :integer.' % [ + # stats.type_stats[:integer].count, + # stats.real_token_count + # ] + # #-> 2 out of 4 tokens have the kind :integer. + def encoder format, options = {} + Encoders[format].new options + end + + # Finds the Scanner class for +lang+ and creates an instance, passing + # +options+ to it. + # + # See Scanner.new. + def scanner lang, options = {}, &block + Scanners[lang].new '', options, &block + end + + # Extract the options for the scanner from the +options+ hash. + # + # Returns an empty Hash if :scanner_options is not set. + # + # This is used if a method like CodeRay.encode has to provide options + # for Encoder _and_ scanner. + def get_scanner_options options + options.fetch :scanner_options, {} + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/duo.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/duo.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,81 @@ +module CodeRay + + # = Duo + # + # A Duo is a convenient way to use CodeRay. You just create a Duo, + # giving it a lang (language of the input code) and a format (desired + # output format), and call Duo#highlight with the code. + # + # Duo makes it easy to re-use both scanner and encoder for a repetitive + # task. It also provides a very easy interface syntax: + # + # require 'coderay' + # CodeRay::Duo[:python, :div].highlight 'import this' + # + # Until you want to do uncommon things with CodeRay, I recommend to use + # this method, since it takes care of everything. + class Duo + + attr_accessor :lang, :format, :options + + # Create a new Duo, holding a lang and a format to highlight code. + # + # simple: + # CodeRay::Duo[:ruby, :html].highlight 'bla 42' + # + # with options: + # CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??' + # + # alternative syntax without options: + # CodeRay::Duo[:ruby => :statistic].encode 'class << self; end' + # + # alternative syntax with options: + # CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc' + # + # The options are forwarded to scanner and encoder + # (see CodeRay.get_scanner_options). + def initialize lang = nil, format = nil, options = {} + if format.nil? && lang.is_a?(Hash) && lang.size == 1 + @lang = lang.keys.first + @format = lang[@lang] + else + @lang = lang + @format = format + end + @options = options + end + + class << self + # To allow calls like Duo[:ruby, :html].highlight. + alias [] new + end + + # The scanner of the duo. Only created once. + def scanner + @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options) + end + + # The encoder of the duo. Only created once. + def encoder + @encoder ||= CodeRay.encoder @format, @options + end + + # Tokenize and highlight the code using +scanner+ and +encoder+. + def encode code, options = {} + options = @options.merge options + encoder.encode(code, @lang, options) + end + alias highlight encode + + # Allows to use Duo like a proc object: + # + # CodeRay::Duo[:python => :yaml].call(code) + # + # or, in Ruby 1.9 and later: + # + # CodeRay::Duo[:python => :yaml].(code) + alias call encode + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoder.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoder.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,201 @@ +module CodeRay + + # This module holds the Encoder class and its subclasses. + # For example, the HTML encoder is named CodeRay::Encoders::HTML + # can be found in coderay/encoders/html. + # + # Encoders also provides methods and constants for the register + # mechanism and the [] method that returns the Encoder class + # belonging to the given format. + module Encoders + + extend PluginHost + plugin_path File.dirname(__FILE__), 'encoders' + + # = Encoder + # + # The Encoder base class. Together with Scanner and + # Tokens, it forms the highlighting triad. + # + # Encoder instances take a Tokens object and do something with it. + # + # The most common Encoder is surely the HTML encoder + # (CodeRay::Encoders::HTML). It highlights the code in a colorful + # html page. + # If you want the highlighted code in a div or a span instead, + # use its subclasses Div and Span. + class Encoder + extend Plugin + plugin_host Encoders + + class << self + + # If FILE_EXTENSION isn't defined, this method returns the + # downcase class name instead. + def const_missing sym + if sym == :FILE_EXTENSION + (defined?(@plugin_id) && @plugin_id || name[/\w+$/].downcase).to_s + else + super + end + end + + # The default file extension for output file of this encoder class. + def file_extension + self::FILE_EXTENSION + end + + end + + # Subclasses are to store their default options in this constant. + DEFAULT_OPTIONS = { } + + # The options you gave the Encoder at creating. + attr_accessor :options, :scanner + + # Creates a new Encoder. + # +options+ is saved and used for all encode operations, as long + # as you don't overwrite it there by passing additional options. + # + # Encoder objects provide three encode methods: + # - encode simply takes a +code+ string and a +lang+ + # - encode_tokens expects a +tokens+ object instead + # + # Each method has an optional +options+ parameter. These are + # added to the options you passed at creation. + def initialize options = {} + @options = self.class::DEFAULT_OPTIONS.merge options + @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = false + end + + # Encode a Tokens object. + def encode_tokens tokens, options = {} + options = @options.merge options + @scanner = tokens.scanner if tokens.respond_to? :scanner + setup options + compile tokens, options + finish options + end + + # Encode the given +code+ using the Scanner for +lang+. + def encode code, lang, options = {} + options = @options.merge options + @scanner = Scanners[lang].new code, CodeRay.get_scanner_options(options).update(:tokens => self) + setup options + @scanner.tokenize + finish options + end + + # You can use highlight instead of encode, if that seems + # more clear to you. + alias highlight encode + + # The default file extension for this encoder. + def file_extension + self.class.file_extension + end + + def << token + unless @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN + warn 'Using old Tokens#<< interface.' + @@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN = true + end + self.token(*token) + end + + # Called with +content+ and +kind+ of the currently scanned token. + # For simple scanners, it's enougth to implement this method. + # + # By default, it calls text_token, begin_group, end_group, begin_line, + # or end_line, depending on the +content+. + def token content, kind + case content + when String + text_token content, kind + when :begin_group + begin_group kind + when :end_group + end_group kind + when :begin_line + begin_line kind + when :end_line + end_line kind + else + raise ArgumentError, 'Unknown token content type: %p, kind = %p' % [content, kind] + end + end + + # Called for each text token ([text, kind]), where text is a String. + def text_token text, kind + @out << text + end + + # Starts a token group with the given +kind+. + def begin_group kind + end + + # Ends a token group with the given +kind+. + def end_group kind + end + + # Starts a new line token group with the given +kind+. + def begin_line kind + end + + # Ends a new line token group with the given +kind+. + def end_line kind + end + + protected + + # Called with merged options before encoding starts. + # Sets @out to an empty string. + # + # See the HTML Encoder for an example of option caching. + def setup options + @out = get_output(options) + end + + def get_output options + options[:out] || '' + end + + # Append data.to_s to the output. Returns the argument. + def output data + @out << data.to_s + data + end + + # Called with merged options after encoding starts. + # The return value is the result of encoding, typically @out. + def finish options + @out + end + + # Do the encoding. + # + # The already created +tokens+ object must be used; it must be a + # Tokens object. + def compile tokens, options = {} + content = nil + for item in tokens + if item.is_a? Array + raise ArgumentError, 'Two-element array tokens are no longer supported.' + end + if content + token content, item + content = nil + else + content = item + end + end + raise 'odd number list for Tokens' if content + end + + alias tokens compile + public :tokens + + end + + end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/_map.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/_map.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +module CodeRay +module Encoders + + map \ + :loc => :lines_of_code, + :plain => :text, + :plaintext => :text, + :remove_comments => :comment_filter, + :stats => :statistic, + :term => :terminal, + :tty => :terminal, + :yml => :yaml + + # No default because Tokens#nonsense should raise NoMethodError. + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/comment_filter.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/comment_filter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,25 @@ +module CodeRay +module Encoders + + load :token_kind_filter + + # A simple Filter that removes all tokens of the :comment kind. + # + # Alias: +remove_comments+ + # + # Usage: + # CodeRay.scan('print # foo', :ruby).comment_filter.text + # #-> "print " + # + # See also: TokenKindFilter, LinesOfCode + class CommentFilter < TokenKindFilter + + register_for :comment_filter + + DEFAULT_OPTIONS = superclass::DEFAULT_OPTIONS.merge \ + :exclude => [:comment, :docstring] + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/count.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/count.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,39 @@ +module CodeRay +module Encoders + + # Returns the number of tokens. + # + # Text and block tokens are counted. + class Count < Encoder + + register_for :count + + protected + + def setup options + super + + @count = 0 + end + + def finish options + output @count + end + + public + + def text_token text, kind + @count += 1 + end + + def begin_group kind + @count += 1 + end + alias end_group begin_group + alias begin_line begin_group + alias end_line begin_group + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/debug.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/debug.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,61 @@ +module CodeRay +module Encoders + + # = Debug Encoder + # + # Fast encoder producing simple debug output. + # + # It is readable and diff-able and is used for testing. + # + # You cannot fully restore the tokens information from the + # output, because consecutive :space tokens are merged. + # Use Tokens#dump for caching purposes. + # + # See also: Scanners::Debug + class Debug < Encoder + + register_for :debug + + FILE_EXTENSION = 'raydebug' + + def initialize options = {} + super + @opened = [] + end + + def text_token text, kind + if kind == :space + @out << text + else + # TODO: Escape ( + text = text.gsub(/[)\\]/, '\\\\\0') # escape ) and \ + @out << kind.to_s << '(' << text << ')' + end + end + + def begin_group kind + @opened << kind + @out << kind.to_s << '<' + end + + def end_group kind + if @opened.last != kind + puts @out + raise "we are inside #{@opened.inspect}, not #{kind}" + end + @opened.pop + @out << '>' + end + + def begin_line kind + @out << kind.to_s << '[' + end + + def end_line kind + @out << ']' + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/div.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/div.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +module CodeRay +module Encoders + + load :html + + # Wraps HTML output into a DIV element, using inline styles by default. + # + # See Encoders::HTML for available options. + class Div < HTML + + FILE_EXTENSION = 'div.html' + + register_for :div + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :style, + :wrap => :div, + :line_numbers => false + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/filter.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/filter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,58 @@ +module CodeRay +module Encoders + + # A Filter encoder has another Tokens instance as output. + # It can be subclass to select, remove, or modify tokens in the stream. + # + # Subclasses of Filter are called "Filters" and can be chained. + # + # == Options + # + # === :tokens + # + # The Tokens object which will receive the output. + # + # Default: Tokens.new + # + # See also: TokenKindFilter + class Filter < Encoder + + register_for :filter + + protected + def setup options + super + + @tokens = options[:tokens] || Tokens.new + end + + def finish options + output @tokens + end + + public + + def text_token text, kind # :nodoc: + @tokens.text_token text, kind + end + + def begin_group kind # :nodoc: + @tokens.begin_group kind + end + + def begin_line kind # :nodoc: + @tokens.begin_line kind + end + + def end_group kind # :nodoc: + @tokens.end_group kind + end + + def end_line kind # :nodoc: + @tokens.end_line kind + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/html.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/html.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,302 @@ +require 'set' + +module CodeRay +module Encoders + + # = HTML Encoder + # + # This is CodeRay's most important highlighter: + # It provides save, fast XHTML generation and CSS support. + # + # == Usage + # + # require 'coderay' + # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page + # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) + # #-> Some /code/ + # puts CodeRay.scan('Some /code/', :ruby).span #-> the same + # + # puts CodeRay.scan('Some code', :ruby).html( + # :wrap => nil, + # :line_numbers => :inline, + # :css => :style + # ) + # + # == Options + # + # === :tab_width + # Convert \t characters to +n+ spaces (a number.) + # + # Default: 8 + # + # === :css + # How to include the styles; can be :class or :style. + # + # Default: :class + # + # === :wrap + # Wrap in :page, :div, :span or nil. + # + # You can also use Encoders::Div and Encoders::Span. + # + # Default: nil + # + # === :title + # + # The title of the HTML page (works only when :wrap is set to :page.) + # + # Default: 'CodeRay output' + # + # === :line_numbers + # Include line numbers in :table, :inline, or nil (no line numbers) + # + # Default: nil + # + # === :line_number_anchors + # Adds anchors and links to the line numbers. Can be false (off), true (on), + # or a prefix string that will be prepended to the anchor name. + # + # The prefix must consist only of letters, digits, and underscores. + # + # Default: true, default prefix name: "line" + # + # === :line_number_start + # Where to start with line number counting. + # + # Default: 1 + # + # === :bold_every + # Make every +n+-th number appear bold. + # + # Default: 10 + # + # === :highlight_lines + # + # Highlights certain line numbers. + # Can be any Enumerable, typically just an Array or Range, of numbers. + # + # Bolding is deactivated when :highlight_lines is set. It only makes sense + # in combination with :line_numbers. + # + # Default: nil + # + # === :hint + # Include some information into the output using the title attribute. + # Can be :info (show token kind on mouse-over), :info_long (with full path) + # or :debug (via inspect). + # + # Default: false + class HTML < Encoder + + register_for :html + + FILE_EXTENSION = 'snippet.html' + + DEFAULT_OPTIONS = { + :tab_width => 8, + + :css => :class, + :style => :alpha, + :wrap => nil, + :title => 'CodeRay output', + + :line_numbers => nil, + :line_number_anchors => 'n', + :line_number_start => 1, + :bold_every => 10, + :highlight_lines => nil, + + :hint => false, + } + + autoload :Output, 'coderay/encoders/html/output' + autoload :CSS, 'coderay/encoders/html/css' + autoload :Numbering, 'coderay/encoders/html/numbering' + + attr_reader :css + + protected + + HTML_ESCAPE = { #:nodoc: + '&' => '&', + '"' => '"', + '>' => '>', + '<' => '<', + } + + # This was to prevent illegal HTML. + # Strange chars should still be avoided in codes. + evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s] + evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' } + #ansi_chars = Array(0x7f..0xff) + #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i } + # \x9 (\t) and \xA (\n) not included + #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/ + HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/ + + TOKEN_KIND_TO_INFO = Hash.new do |h, kind| + h[kind] = kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } + end + + TRANSPARENT_TOKEN_KINDS = Set[ + :delimiter, :modifier, :content, :escape, :inline_delimiter, + ] + + # Generate a hint about the given +kinds+ in a +hint+ style. + # + # +hint+ may be :info, :info_long or :debug. + def self.token_path_to_hint hint, kinds + kinds = Array kinds + title = + case hint + when :info + kinds = kinds[1..-1] if TRANSPARENT_TOKEN_KINDS.include? kinds.first + TOKEN_KIND_TO_INFO[kinds.first] + when :info_long + kinds.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') + when :debug + kinds.inspect + end + title ? " title=\"#{title}\"" : '' + end + + def setup options + super + + if options[:wrap] || options[:line_numbers] + @real_out = @out + @out = '' + end + + @HTML_ESCAPE = HTML_ESCAPE.dup + @HTML_ESCAPE["\t"] = ' ' * options[:tab_width] + + @opened = [] + @last_opened = nil + @css = CSS.new options[:style] + + hint = options[:hint] + if hint && ![:debug, :info, :info_long].include?(hint) + raise ArgumentError, "Unknown value %p for :hint; \ + expected :info, :info_long, :debug, false, or nil." % hint + end + + css_classes = TokenKinds + case options[:css] + when :class + @span_for_kind = Hash.new do |h, k| + if k.is_a? ::Symbol + kind = k_dup = k + else + kind = k.first + k_dup = k.dup + end + if kind != :space && (hint || css_class = css_classes[kind]) + title = HTML.token_path_to_hint hint, k if hint + css_class ||= css_classes[kind] + h[k_dup] = "" + else + h[k_dup] = nil + end + end + when :style + @span_for_kind = Hash.new do |h, k| + kind = k.is_a?(Symbol) ? k : k.first + h[k.is_a?(Symbol) ? k : k.dup] = + if kind != :space && (hint || css_classes[kind]) + title = HTML.token_path_to_hint hint, k if hint + style = @css.get_style Array(k).map { |c| css_classes[c] } + "" + end + end + else + raise ArgumentError, "Unknown value %p for :css." % options[:css] + end + + @set_last_opened = options[:hint] || options[:css] == :style + end + + def finish options + unless @opened.empty? + warn '%d tokens still open: %p' % [@opened.size, @opened] if $CODERAY_DEBUG + @out << '' while @opened.pop + @last_opened = nil + end + + @out.extend Output + @out.css = @css + if options[:line_numbers] + Numbering.number! @out, options[:line_numbers], options + end + @out.wrap! options[:wrap] + @out.apply_title! options[:title] + + if defined?(@real_out) && @real_out + @real_out << @out + @out = @real_out + end + + super + end + + public + + def text_token text, kind + if text =~ /#{HTML_ESCAPE_PATTERN}/o + text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } + end + if style = @span_for_kind[@last_opened ? [kind, *@opened] : kind] + @out << style << text << '' + else + @out << text + end + end + + # token groups, eg. strings + def begin_group kind + @out << (@span_for_kind[@last_opened ? [kind, *@opened] : kind] || '') + @opened << kind + @last_opened = kind if @set_last_opened + end + + def end_group kind + if $CODERAY_DEBUG && (@opened.empty? || @opened.last != kind) + warn 'Malformed token stream: Trying to close a token (%p) ' \ + 'that is not open. Open are: %p.' % [kind, @opened[1..-1]] + end + if @opened.pop + @out << '' + @last_opened = @opened.last if @last_opened + end + end + + # whole lines to be highlighted, eg. a deleted line in a diff + def begin_line kind + if style = @span_for_kind[@last_opened ? [kind, *@opened] : kind] + if style['class="'] + @out << style.sub('class="', 'class="line ') + else + @out << style.sub('>', ' class="line">') + end + else + @out << '' + end + @opened << kind + @last_opened = kind if @options[:css] == :style + end + + def end_line kind + if $CODERAY_DEBUG && (@opened.empty? || @opened.last != kind) + warn 'Malformed token stream: Trying to close a line (%p) ' \ + 'that is not open. Open are: %p.' % [kind, @opened[1..-1]] + end + if @opened.pop + @out << '' + @last_opened = @opened.last if @last_opened + end + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/html/css.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/html/css.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,65 @@ +module CodeRay +module Encoders + + class HTML + class CSS # :nodoc: + + attr :stylesheet + + def CSS.load_stylesheet style = nil + CodeRay::Styles[style] + end + + def initialize style = :default + @classes = Hash.new + style = CSS.load_stylesheet style + @stylesheet = [ + style::CSS_MAIN_STYLES, + style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ') + ].join("\n") + parse style::TOKEN_COLORS + end + + def get_style styles + cl = @classes[styles.first] + return '' unless cl + style = '' + 1.upto styles.size do |offset| + break if style = cl[styles[offset .. -1]] + end + # warn 'Style not found: %p' % [styles] if style.empty? + return style + end + + private + + CSS_CLASS_PATTERN = / + ( # $1 = selectors + (?: + (?: \s* \. [-\w]+ )+ + \s* ,? + )+ + ) + \s* \{ \s* + ( [^\}]+ )? # $2 = style + \s* \} \s* + | + ( [^\n]+ ) # $3 = error + /mx + def parse stylesheet + stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error| + raise "CSS parse error: '#{error.inspect}' not recognized" if error + for selector in selectors.split(',') + classes = selector.scan(/[-\w]+/) + cl = classes.pop + @classes[cl] ||= Hash.new + @classes[cl][classes] = style.to_s.strip.delete(' ').chomp(';') + end + end + end + + end + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/html/numbering.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/html/numbering.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,115 @@ +module CodeRay +module Encoders + + class HTML + + module Numbering # :nodoc: + + def self.number! output, mode = :table, options = {} + return self unless mode + + options = DEFAULT_OPTIONS.merge options + + start = options[:line_number_start] + unless start.is_a? Integer + raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start + end + + anchor_prefix = options[:line_number_anchors] + anchor_prefix = 'line' if anchor_prefix == true + anchor_prefix = anchor_prefix.to_s[/\w+/] if anchor_prefix + anchoring = + if anchor_prefix + proc do |line| + line = line.to_s + anchor = anchor_prefix + line + "#{line}" + end + else + proc { |line| line.to_s } # :to_s.to_proc in Ruby 1.8.7+ + end + + bold_every = options[:bold_every] + highlight_lines = options[:highlight_lines] + bolding = + if bold_every == false && highlight_lines == nil + anchoring + elsif highlight_lines.is_a? Enumerable + highlight_lines = highlight_lines.to_set + proc do |line| + if highlight_lines.include? line + "#{anchoring[line]}" # highlighted line numbers in bold + else + anchoring[line] + end + end + elsif bold_every.is_a? Integer + raise ArgumentError, ":bolding can't be 0." if bold_every == 0 + proc do |line| + if line % bold_every == 0 + "#{anchoring[line]}" # every bold_every-th number in bold + else + anchoring[line] + end + end + else + raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every + end + + line_count = output.count("\n") + position_of_last_newline = output.rindex(RUBY_VERSION >= '1.9' ? /\n/ : ?\n) + if position_of_last_newline + after_last_newline = output[position_of_last_newline + 1 .. -1] + ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/] + line_count += 1 if not ends_with_newline + end + + case mode + when :inline + max_width = (start + line_count).to_s.size + line_number = start + nesting = [] + output.gsub!(/^.*$\n?/) do |line| + line.chomp! + open = nesting.join + line.scan(%r!<(/)?span[^>]*>?!) do |close,| + if close + nesting.pop + else + nesting << $& + end + end + close = '' * nesting.size + + line_number_text = bolding.call line_number + indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x) + line_number += 1 + "#{indent}#{line_number_text}#{open}#{line}#{close}\n" + end + + when :table + line_numbers = (start ... start + line_count).map(&bolding).join("\n") + line_numbers << "\n" + line_numbers_table_template = Output::TABLE.apply('LINE_NUMBERS', line_numbers) + + output.gsub!(/<\/div>\n/, '
    ') + output.wrap_in! line_numbers_table_template + output.wrapped_in = :div + + when :list + raise NotImplementedError, 'The :list option is no longer available. Use :table.' + + else + raise ArgumentError, 'Unknown value %p for mode: expected one of %p' % + [mode, [:table, :inline]] + end + + output + end + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/html/output.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/html/output.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,158 @@ +module CodeRay +module Encoders + + class HTML + + # This module is included in the output String of the HTML Encoder. + # + # It provides methods like wrap, div, page etc. + # + # Remember to use #clone instead of #dup to keep the modules the object was + # extended with. + # + # TODO: Rewrite this without monkey patching. + module Output + + attr_accessor :css + + class << self + + # Raises an exception if an object that doesn't respond to to_str is extended by Output, + # to prevent users from misuse. Use Module#remove_method to disable. + def extended o # :nodoc: + warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str + end + + def make_stylesheet css, in_tag = false # :nodoc: + sheet = css.stylesheet + sheet = <<-'CSS' if in_tag + + CSS + sheet + end + + def page_template_for_css css # :nodoc: + sheet = make_stylesheet css + PAGE.apply 'CSS', sheet + end + + end + + def wrapped_in? element + wrapped_in == element + end + + def wrapped_in + @wrapped_in ||= nil + end + attr_writer :wrapped_in + + def wrap_in! template + Template.wrap! self, template, 'CONTENT' + self + end + + def apply_title! title + self.sub!(/()(<\/title>)/) { $1 + title + $2 } + self + end + + def wrap! element, *args + return self if not element or element == wrapped_in + case element + when :div + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! DIV + when :span + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil + wrap_in! SPAN + when :page + wrap! :div if wrapped_in? nil + raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div + wrap_in! Output.page_template_for_css(@css) + if args.first.is_a?(Hash) && title = args.first[:title] + apply_title! title + end + self + when nil + return self + else + raise "Unknown value %p for :wrap" % element + end + @wrapped_in = element + self + end + + def stylesheet in_tag = false + Output.make_stylesheet @css, in_tag + end + +#-- don't include the templates in docu + + class Template < String # :nodoc: + + def self.wrap! str, template, target + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if template =~ target + str[0,0] = $` + str << $' + else + raise "Template target <%%%p%%> not found" % target + end + end + + def apply target, replacement + target = Regexp.new(Regexp.escape("<%#{target}%>")) + if self =~ target + Template.new($` + replacement + $') + else + raise "Template target <%%%p%%> not found" % target + end + end + + end + + SPAN = Template.new '<span class="CodeRay"><%CONTENT%></span>' + + DIV = Template.new <<-DIV +<div class="CodeRay"> + <div class="code"><pre><%CONTENT%></pre></div> +</div> + DIV + + TABLE = Template.new <<-TABLE +<table class="CodeRay"><tr> + <td class="line-numbers" title="double click to toggle" ondblclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td> + <td class="code"><pre><%CONTENT%></pre></td> +</tr></table> + TABLE + + PAGE = Template.new <<-PAGE +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title> + + + + +<%CONTENT%> + + + PAGE + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/json.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/json.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,83 @@ +module CodeRay +module Encoders + + # A simple JSON Encoder. + # + # Example: + # CodeRay.scan('puts "Hello world!"', :ruby).json + # yields + # [ + # {"type"=>"text", "text"=>"puts", "kind"=>"ident"}, + # {"type"=>"text", "text"=>" ", "kind"=>"space"}, + # {"type"=>"block", "action"=>"open", "kind"=>"string"}, + # {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, + # {"type"=>"text", "text"=>"Hello world!", "kind"=>"content"}, + # {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, + # {"type"=>"block", "action"=>"close", "kind"=>"string"}, + # ] + class JSON < Encoder + + begin + require 'json' + rescue LoadError + begin + require 'rubygems' unless defined? Gem + gem 'json' + require 'json' + rescue LoadError + $stderr.puts "The JSON encoder needs the JSON library.\n" \ + "Please gem install json." + raise + end + end + + register_for :json + FILE_EXTENSION = 'json' + + protected + def setup options + super + + @first = true + @out << '[' + end + + def finish options + @out << ']' + end + + def append data + if @first + @first = false + else + @out << ',' + end + + @out << data.to_json + end + + public + def text_token text, kind + append :type => 'text', :text => text, :kind => kind + end + + def begin_group kind + append :type => 'block', :action => 'open', :kind => kind + end + + def end_group kind + append :type => 'block', :action => 'close', :kind => kind + end + + def begin_line kind + append :type => 'block', :action => 'begin_line', :kind => kind + end + + def end_line kind + append :type => 'block', :action => 'end_line', :kind => kind + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/lines_of_code.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/lines_of_code.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,45 @@ +module CodeRay +module Encoders + + # Counts the LoC (Lines of Code). Returns an Integer >= 0. + # + # Alias: +loc+ + # + # Everything that is not comment, markup, doctype/shebang, or an empty line, + # is considered to be code. + # + # For example, + # * HTML files not containing JavaScript have 0 LoC + # * in a Java class without comments, LoC is the number of non-empty lines + # + # A Scanner class should define the token kinds that are not code in the + # KINDS_NOT_LOC constant, which defaults to [:comment, :doctype]. + class LinesOfCode < TokenKindFilter + + register_for :lines_of_code + + NON_EMPTY_LINE = /^\s*\S.*$/ + + protected + + def setup options + if scanner + kinds_not_loc = scanner.class::KINDS_NOT_LOC + else + warn "Tokens have no associated scanner, counting all nonempty lines." if $VERBOSE + kinds_not_loc = CodeRay::Scanners::Scanner::KINDS_NOT_LOC + end + + options[:exclude] = kinds_not_loc + + super options + end + + def finish options + output @tokens.text.scan(NON_EMPTY_LINE).size + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/null.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/null.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,18 @@ +module CodeRay +module Encoders + + # = Null Encoder + # + # Does nothing and returns an empty string. + class Null < Encoder + + register_for :null + + def text_token text, kind + # do nothing + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/page.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/page.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +module CodeRay +module Encoders + + load :html + + # Wraps the output into a HTML page, using CSS classes and + # line numbers in the table format by default. + # + # See Encoders::HTML for available options. + class Page < HTML + + FILE_EXTENSION = 'html' + + register_for :page + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :class, + :wrap => :page, + :line_numbers => :table + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/span.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/span.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,23 @@ +module CodeRay +module Encoders + + load :html + + # Wraps HTML output into a SPAN element, using inline styles by default. + # + # See Encoders::HTML for available options. + class Span < HTML + + FILE_EXTENSION = 'span.html' + + register_for :span + + DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ + :css => :style, + :wrap => :span, + :line_numbers => false + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/statistic.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/statistic.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,96 @@ +module CodeRay +module Encoders + + # Makes a statistic for the given tokens. + # + # Alias: +stats+ + class Statistic < Encoder + + register_for :statistic + + attr_reader :type_stats, :real_token_count # :nodoc: + + TypeStats = Struct.new :count, :size # :nodoc: + + protected + + def setup options + super + + @type_stats = Hash.new { |h, k| h[k] = TypeStats.new 0, 0 } + @real_token_count = 0 + end + + STATS = <<-STATS # :nodoc: + +Code Statistics + +Tokens %8d + Non-Whitespace %8d +Bytes Total %8d + +Token Types (%d): + type count ratio size (average) +------------------------------------------------------------- +%s + STATS + + TOKEN_TYPES_ROW = <<-TKR # :nodoc: + %-20s %8d %6.2f %% %5.1f + TKR + + def finish options + all = @type_stats['TOTAL'] + all_count, all_size = all.count, all.size + @type_stats.each do |type, stat| + stat.size /= stat.count.to_f + end + types_stats = @type_stats.sort_by { |k, v| [-v.count, k.to_s] }.map do |k, v| + TOKEN_TYPES_ROW % [k, v.count, 100.0 * v.count / all_count, v.size] + end.join + @out << STATS % [ + all_count, @real_token_count, all_size, + @type_stats.delete_if { |k, v| k.is_a? String }.size, + types_stats + ] + + super + end + + public + + def text_token text, kind + @real_token_count += 1 unless kind == :space + @type_stats[kind].count += 1 + @type_stats[kind].size += text.size + @type_stats['TOTAL'].size += text.size + @type_stats['TOTAL'].count += 1 + end + + # TODO Hierarchy handling + def begin_group kind + block_token ':begin_group', kind + end + + def end_group kind + block_token ':end_group', kind + end + + def begin_line kind + block_token ':begin_line', kind + end + + def end_line kind + block_token ':end_line', kind + end + + def block_token action, kind + @type_stats['TOTAL'].count += 1 + @type_stats[action].count += 1 + @type_stats[kind].count += 1 + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/terminal.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/terminal.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,179 @@ +module CodeRay + module Encoders + + # Outputs code highlighted for a color terminal. + # + # Note: This encoder is in beta. It currently doesn't use the Styles. + # + # Alias: +term+ + # + # == Authors & License + # + # By Rob Aldred (http://robaldred.co.uk) + # + # Based on idea by Nathan Weizenbaum (http://nex-3.com) + # + # MIT License (http://www.opensource.org/licenses/mit-license.php) + class Terminal < Encoder + + register_for :terminal + + TOKEN_COLORS = { + :annotation => '35', + :attribute_name => '33', + :attribute_value => '31', + :binary => '1;35', + :char => { + :self => '36', :delimiter => '34' + }, + :class => '1;35', + :class_variable => '36', + :color => '32', + :comment => '37', + :complex => '34', + :constant => ['34', '4'], + :decoration => '35', + :definition => '1;32', + :directive => ['32', '4'], + :doc => '46', + :doctype => '1;30', + :doc_string => ['31', '4'], + :entity => '33', + :error => ['1;33', '41'], + :exception => '1;31', + :float => '1;35', + :function => '1;34', + :global_variable => '42', + :hex => '1;36', + :include => '33', + :integer => '1;34', + :key => '35', + :label => '1;15', + :local_variable => '33', + :octal => '1;35', + :operator_name => '1;29', + :predefined_constant => '1;36', + :predefined_type => '1;30', + :predefined => ['4', '1;34'], + :preprocessor => '36', + :pseudo_class => '34', + :regexp => { + :self => '31', + :content => '31', + :delimiter => '1;29', + :modifier => '35', + :function => '1;29' + }, + :reserved => '1;31', + :shell => { + :self => '42', + :content => '1;29', + :delimiter => '37', + }, + :string => { + :self => '32', + :modifier => '1;32', + :escape => '1;36', + :delimiter => '1;32', + }, + :symbol => '1;32', + :tag => '34', + :type => '1;34', + :value => '36', + :variable => '34', + + :insert => '42', + :delete => '41', + :change => '44', + :head => '45' + } + TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved] + TOKEN_COLORS[:method] = TOKEN_COLORS[:function] + TOKEN_COLORS[:imaginary] = TOKEN_COLORS[:complex] + TOKEN_COLORS[:begin_group] = TOKEN_COLORS[:end_group] = + TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter] + + protected + + def setup(options) + super + @opened = [] + @subcolors = nil + end + + public + + def text_token text, kind + if color = (@subcolors || TOKEN_COLORS)[kind] + if Hash === color + if color[:self] + color = color[:self] + else + @out << text + return + end + end + + @out << ansi_colorize(color) + @out << text.gsub("\n", ansi_clear + "\n" + ansi_colorize(color)) + @out << ansi_clear + @out << ansi_colorize(@subcolors[:self]) if @subcolors && @subcolors[:self] + else + @out << text + end + end + + def begin_group kind + @opened << kind + @out << open_token(kind) + end + alias begin_line begin_group + + def end_group kind + if @opened.empty? + # nothing to close + else + @opened.pop + @out << ansi_clear + @out << open_token(@opened.last) + end + end + + def end_line kind + if @opened.empty? + # nothing to close + else + @opened.pop + # whole lines to be highlighted, + # eg. added/modified/deleted lines in a diff + @out << "\t" * 100 + ansi_clear + @out << open_token(@opened.last) + end + end + + private + + def open_token kind + if color = TOKEN_COLORS[kind] + if Hash === color + @subcolors = color + ansi_colorize(color[:self]) if color[:self] + else + @subcolors = {} + ansi_colorize(color) + end + else + @subcolors = nil + '' + end + end + + def ansi_colorize(color) + Array(color).map { |c| "\e[#{c}m" }.join + end + def ansi_clear + ansi_colorize(0) + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/text.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/text.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,46 @@ +module CodeRay +module Encoders + + # Concats the tokens into a single string, resulting in the original + # code string if no tokens were removed. + # + # Alias: +plain+, +plaintext+ + # + # == Options + # + # === :separator + # A separator string to join the tokens. + # + # Default: empty String + class Text < Encoder + + register_for :text + + FILE_EXTENSION = 'txt' + + DEFAULT_OPTIONS = { + :separator => nil + } + + def text_token text, kind + super + + if @first + @first = false + else + @out << @sep + end if @sep + end + + protected + def setup options + super + + @first = true + @sep = options[:separator] + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/token_kind_filter.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/token_kind_filter.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,111 @@ +module CodeRay +module Encoders + + load :filter + + # A Filter that selects tokens based on their token kind. + # + # == Options + # + # === :exclude + # + # One or many symbols (in an Array) which shall be excluded. + # + # Default: [] + # + # === :include + # + # One or many symbols (in an array) which shall be included. + # + # Default: :all, which means all tokens are included. + # + # Exclusion wins over inclusion. + # + # See also: CommentFilter + class TokenKindFilter < Filter + + register_for :token_kind_filter + + DEFAULT_OPTIONS = { + :exclude => [], + :include => :all + } + + protected + def setup options + super + + @group_excluded = false + @exclude = options[:exclude] + @exclude = Array(@exclude) unless @exclude == :all + @include = options[:include] + @include = Array(@include) unless @include == :all + end + + def include_text_token? text, kind + include_group? kind + end + + def include_group? kind + (@include == :all || @include.include?(kind)) && + !(@exclude == :all || @exclude.include?(kind)) + end + + public + + # Add the token to the output stream if +kind+ matches the conditions. + def text_token text, kind + super if !@group_excluded && include_text_token?(text, kind) + end + + # Add the token group to the output stream if +kind+ matches the + # conditions. + # + # If it does not, all tokens inside the group are excluded from the + # stream, even if their kinds match. + def begin_group kind + if @group_excluded + @group_excluded += 1 + elsif include_group? kind + super + else + @group_excluded = 1 + end + end + + # See +begin_group+. + def begin_line kind + if @group_excluded + @group_excluded += 1 + elsif include_group? kind + super + else + @group_excluded = 1 + end + end + + # Take care of re-enabling the delegation of tokens to the output stream + # if an exluded group has ended. + def end_group kind + if @group_excluded + @group_excluded -= 1 + @group_excluded = false if @group_excluded.zero? + else + super + end + end + + # See +end_group+. + def end_line kind + if @group_excluded + @group_excluded -= 1 + @group_excluded = false if @group_excluded.zero? + else + super + end + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/xml.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/xml.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,72 @@ +module CodeRay +module Encoders + + # = XML Encoder + # + # Uses REXML. Very slow. + class XML < Encoder + + register_for :xml + + FILE_EXTENSION = 'xml' + + autoload :REXML, 'rexml/document' + + DEFAULT_OPTIONS = { + :tab_width => 8, + :pretty => -1, + :transitive => false, + } + + protected + def setup options + super + + @doc = REXML::Document.new + @doc << REXML::XMLDecl.new + @tab_width = options[:tab_width] + @root = @node = @doc.add_element('coderay-tokens') + end + + def finish options + @doc.write @out, options[:pretty], options[:transitive], true + + super + end + + public + def text_token text, kind + if kind == :space + token = @node + else + token = @node.add_element kind.to_s + end + text.scan(/(\x20+)|(\t+)|(\n)|[^\x20\t\n]+/) do |space, tab, nl| + case + when space + token << REXML::Text.new(space, true) + when tab + token << REXML::Text.new(tab, true) + when nl + token << REXML::Text.new(nl, true) + else + token << REXML::Text.new($&) + end + end + end + + def begin_group kind + @node = @node.add_element kind.to_s + end + + def end_group kind + if @node == @root + raise 'no token to close!' + end + @node = @node.parent + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/encoders/yaml.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/encoders/yaml.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,50 @@ +autoload :YAML, 'yaml' + +module CodeRay +module Encoders + + # = YAML Encoder + # + # Slow. + class YAML < Encoder + + register_for :yaml + + FILE_EXTENSION = 'yaml' + + protected + def setup options + super + + @data = [] + end + + def finish options + output ::YAML.dump(@data) + end + + public + def text_token text, kind + @data << [text, kind] + end + + def begin_group kind + @data << [:begin_group, kind] + end + + def end_group kind + @data << [:end_group, kind] + end + + def begin_line kind + @data << [:begin_line, kind] + end + + def end_line kind + @data << [:end_line, kind] + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/for_redcloth.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/for_redcloth.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +module CodeRay + + # A little hack to enable CodeRay highlighting in RedCloth. + # + # Usage: + # require 'coderay' + # require 'coderay/for_redcloth' + # RedCloth.new('@[ruby]puts "Hello, World!"@').to_html + # + # Make sure you have RedCloth 4.0.3 activated, for example by calling + # require 'rubygems' + # before RedCloth is loaded and before calling CodeRay.for_redcloth. + module ForRedCloth + + def self.install + gem 'RedCloth', '>= 4.0.3' if defined? gem + require 'redcloth' + unless RedCloth::VERSION.to_s >= '4.0.3' + if defined? gem + raise 'CodeRay.for_redcloth needs RedCloth version 4.0.3 or later. ' + + "You have #{RedCloth::VERSION}. Please gem install RedCloth." + else + $".delete 'redcloth.rb' # sorry, but it works + require 'rubygems' + return install # retry + end + end + unless RedCloth::VERSION.to_s >= '4.2.2' + warn 'CodeRay.for_redcloth works best with RedCloth version 4.2.2 or later.' + end + RedCloth::TextileDoc.send :include, ForRedCloth::TextileDoc + RedCloth::Formatters::HTML.module_eval do + def unescape(html) # :nodoc: + replacements = { + '&' => '&', + '"' => '"', + '>' => '>', + '<' => '<', + } + html.gsub(/&(?:amp|quot|[gl]t);/) { |entity| replacements[entity] } + end + undef code, bc_open, bc_close, escape_pre + def code(opts) # :nodoc: + opts[:block] = true + if !opts[:lang] && RedCloth::VERSION.to_s >= '4.2.0' + # simulating pre-4.2 behavior + if opts[:text].sub!(/\A\[(\w+)\]/, '') + if CodeRay::Scanners[$1].lang == :text + opts[:text] = $& + opts[:text] + else + opts[:lang] = $1 + end + end + end + if opts[:lang] && !filter_coderay + require 'coderay' + @in_bc ||= nil + format = @in_bc ? :div : :span + opts[:text] = unescape(opts[:text]) unless @in_bc + highlighted_code = CodeRay.encode opts[:text], opts[:lang], format + highlighted_code.sub!(/\A<(span|div)/) { |m| m + pba(@in_bc || opts) } + highlighted_code + else + "#{opts[:text]}" + end + end + def bc_open(opts) # :nodoc: + opts[:block] = true + @in_bc = opts + opts[:lang] ? '' : "" + end + def bc_close(opts) # :nodoc: + opts = @in_bc + @in_bc = nil + opts[:lang] ? '' : "\n" + end + def escape_pre(text) # :nodoc: + if @in_bc ||= nil + text + else + html_esc(text, :html_escape_preformatted) + end + end + end + end + + module TextileDoc # :nodoc: + attr_accessor :filter_coderay + end + + end + +end + +CodeRay::ForRedCloth.install \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/helpers/file_type.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/helpers/file_type.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,141 @@ +module CodeRay + + # = FileType + # + # A simple filetype recognizer. + # + # == Usage + # + # # determine the type of the given + # lang = FileType[file_name] + # + # # return :text if the file type is unknown + # lang = FileType.fetch file_name, :text + # + # # try the shebang line, too + # lang = FileType.fetch file_name, :text, true + module FileType + + UnknownFileType = Class.new Exception + + class << self + + # Try to determine the file type of the file. + # + # +filename+ is a relative or absolute path to a file. + # + # The file itself is only accessed when +read_shebang+ is set to true. + # That means you can get filetypes from files that don't exist. + def [] filename, read_shebang = false + name = File.basename filename + ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot + ext2 = filename.to_s[/\.(.*)/, 1] # from first dot + + type = + TypeFromExt[ext] || + TypeFromExt[ext.downcase] || + (TypeFromExt[ext2] if ext2) || + (TypeFromExt[ext2.downcase] if ext2) || + TypeFromName[name] || + TypeFromName[name.downcase] + type ||= shebang(filename) if read_shebang + + type + end + + # This works like Hash#fetch. + # + # If the filetype cannot be found, the +default+ value + # is returned. + def fetch filename, default = nil, read_shebang = false + if default && block_given? + warn 'Block supersedes default value argument; use either.' + end + + if type = self[filename, read_shebang] + type + else + return yield if block_given? + return default if default + raise UnknownFileType, 'Could not determine type of %p.' % filename + end + end + + protected + + def shebang filename + return unless File.exist? filename + File.open filename, 'r' do |f| + if first_line = f.gets + if type = first_line[TypeFromShebang] + type.to_sym + end + end + end + end + + end + + TypeFromExt = { + 'c' => :c, + 'cfc' => :xml, + 'cfm' => :xml, + 'clj' => :clojure, + 'css' => :css, + 'diff' => :diff, + 'dpr' => :delphi, + 'gemspec' => :ruby, + 'groovy' => :groovy, + 'gvy' => :groovy, + 'h' => :c, + 'haml' => :haml, + 'htm' => :page, + 'html' => :page, + 'html.erb' => :erb, + 'java' => :java, + 'js' => :java_script, + 'json' => :json, + 'mab' => :ruby, + 'pas' => :delphi, + 'patch' => :diff, + 'php' => :php, + 'php3' => :php, + 'php4' => :php, + 'php5' => :php, + 'prawn' => :ruby, + 'py' => :python, + 'py3' => :python, + 'pyw' => :python, + 'rake' => :ruby, + 'raydebug' => :raydebug, + 'rb' => :ruby, + 'rbw' => :ruby, + 'rhtml' => :erb, + 'rjs' => :ruby, + 'rpdf' => :ruby, + 'ru' => :ruby, + 'rxml' => :ruby, + # 'sch' => :scheme, + 'sql' => :sql, + # 'ss' => :scheme, + 'xhtml' => :page, + 'xml' => :xml, + 'yaml' => :yaml, + 'yml' => :yaml, + } + for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu] + TypeFromExt[cpp_alias] = :cpp + end + + TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/ + + TypeFromName = { + 'Capfile' => :ruby, + 'Rakefile' => :ruby, + 'Rantfile' => :ruby, + 'Gemfile' => :ruby, + } + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/helpers/gzip.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/helpers/gzip.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,41 @@ +module CodeRay + + # A simplified interface to the gzip library +zlib+ (from the Ruby Standard Library.) + module GZip + + require 'zlib' + + # The default zipping level. 7 zips good and fast. + DEFAULT_GZIP_LEVEL = 7 + + # Unzips the given string +s+. + # + # Example: + # require 'gzip_simple' + # print GZip.gunzip(File.read('adresses.gz')) + def GZip.gunzip s + Zlib::Inflate.inflate s + end + + # Zips the given string +s+. + # + # Example: + # require 'gzip_simple' + # File.open('adresses.gz', 'w') do |file + # file.write GZip.gzip('Mum: 0123 456 789', 9) + # end + # + # If you provide a +level+, you can control how strong + # the string is compressed: + # - 0: no compression, only convert to gzip format + # - 1: compress fast + # - 7: compress more, but still fast (default) + # - 8: compress more, slower + # - 9: compress best, very slow + def GZip.gzip s, level = DEFAULT_GZIP_LEVEL + Zlib::Deflate.new(level).deflate s, Zlib::FINISH + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/helpers/plugin.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/helpers/plugin.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,284 @@ +module CodeRay + + # = PluginHost + # + # A simple subclass/subfolder plugin system. + # + # Example: + # class Generators + # extend PluginHost + # plugin_path 'app/generators' + # end + # + # class Generator + # extend Plugin + # PLUGIN_HOST = Generators + # end + # + # class FancyGenerator < Generator + # register_for :fancy + # end + # + # Generators[:fancy] #-> FancyGenerator + # # or + # CodeRay.require_plugin 'Generators/fancy' + # # or + # Generators::Fancy + module PluginHost + + # Raised if Encoders::[] fails because: + # * a file could not be found + # * the requested Plugin is not registered + PluginNotFound = Class.new LoadError + HostNotFound = Class.new LoadError + + PLUGIN_HOSTS = [] + PLUGIN_HOSTS_BY_ID = {} # dummy hash + + # Loads all plugins using list and load. + def load_all + for plugin in list + load plugin + end + end + + # Returns the Plugin for +id+. + # + # Example: + # yaml_plugin = MyPluginHost[:yaml] + def [] id, *args, &blk + plugin = validate_id(id) + begin + plugin = plugin_hash.[] plugin, *args, &blk + end while plugin.is_a? Symbol + plugin + end + + alias load [] + + # Tries to +load+ the missing plugin by translating +const+ to the + # underscore form (eg. LinesOfCode becomes lines_of_code). + def const_missing const + id = const.to_s. + gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). + gsub(/([a-z\d])([A-Z])/,'\1_\2'). + downcase + load id + end + + class << self + + # Adds the module/class to the PLUGIN_HOSTS list. + def extended mod + PLUGIN_HOSTS << mod + end + + end + + # The path where the plugins can be found. + def plugin_path *args + unless args.empty? + @plugin_path = File.expand_path File.join(*args) + end + @plugin_path ||= '' + end + + # Map a plugin_id to another. + # + # Usage: Put this in a file plugin_path/_map.rb. + # + # class MyColorHost < PluginHost + # map :navy => :dark_blue, + # :maroon => :brown, + # :luna => :moon + # end + def map hash + for from, to in hash + from = validate_id from + to = validate_id to + plugin_hash[from] = to unless plugin_hash.has_key? from + end + end + + # Define the default plugin to use when no plugin is found + # for a given id, or return the default plugin. + # + # See also map. + # + # class MyColorHost < PluginHost + # map :navy => :dark_blue + # default :gray + # end + # + # MyColorHost.default # loads and returns the Gray plugin + def default id = nil + if id + id = validate_id id + raise "The default plugin can't be named \"default\"." if id == :default + plugin_hash[:default] = id + else + load :default + end + end + + # Every plugin must register itself for +id+ by calling register_for, + # which calls this method. + # + # See Plugin#register_for. + def register plugin, id + plugin_hash[validate_id(id)] = plugin + end + + # A Hash of plugion_id => Plugin pairs. + def plugin_hash + @plugin_hash ||= make_plugin_hash + end + + # Returns an array of all .rb files in the plugin path. + # + # The extension .rb is not included. + def list + Dir[path_to('*')].select do |file| + File.basename(file)[/^(?!_)\w+\.rb$/] + end.map do |file| + File.basename(file, '.rb').to_sym + end + end + + # Returns an array of all Plugins. + # + # Note: This loads all plugins using load_all. + def all_plugins + load_all + plugin_hash.values.grep(Class) + end + + # Loads the map file (see map). + # + # This is done automatically when plugin_path is called. + def load_plugin_map + mapfile = path_to '_map' + @plugin_map_loaded = true + if File.exist? mapfile + require mapfile + true + else + false + end + end + + protected + + # Return a plugin hash that automatically loads plugins. + def make_plugin_hash + @plugin_map_loaded ||= false + Hash.new do |h, plugin_id| + id = validate_id(plugin_id) + path = path_to id + begin + raise LoadError, "#{path} not found" unless File.exist? path + require path + rescue LoadError => boom + if @plugin_map_loaded + if h.has_key?(:default) + warn '%p could not load plugin %p; falling back to %p' % [self, id, h[:default]] + h[:default] + else + raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom] + end + else + load_plugin_map + h[plugin_id] + end + else + # Plugin should have registered by now + if h.has_key? id + h[id] + else + raise PluginNotFound, "No #{self.name} plugin for #{id.inspect} found in #{path}." + end + end + end + end + + # Returns the expected path to the plugin file for the given id. + def path_to plugin_id + File.join plugin_path, "#{plugin_id}.rb" + end + + # Converts +id+ to a Symbol if it is a String, + # or returns +id+ if it already is a Symbol. + # + # Raises +ArgumentError+ for all other objects, or if the + # given String includes non-alphanumeric characters (\W). + def validate_id id + if id.is_a? Symbol or id.nil? + id + elsif id.is_a? String + if id[/\w+/] == id + id.downcase.to_sym + else + raise ArgumentError, "Invalid id given: #{id}" + end + else + raise ArgumentError, "String or Symbol expected, but #{id.class} given." + end + end + + end + + + # = Plugin + # + # Plugins have to include this module. + # + # IMPORTANT: Use extend for this module. + # + # See CodeRay::PluginHost for examples. + module Plugin + + attr_reader :plugin_id + + # Register this class for the given +id+. + # + # Example: + # class MyPlugin < PluginHost::BaseClass + # register_for :my_id + # ... + # end + # + # See PluginHost.register. + def register_for id + @plugin_id = id + plugin_host.register self, id + end + + # Returns the title of the plugin, or sets it to the + # optional argument +title+. + def title title = nil + if title + @title = title.to_s + else + @title ||= name[/([^:]+)$/, 1] + end + end + + # The PluginHost for this Plugin class. + def plugin_host host = nil + if host.is_a? PluginHost + const_set :PLUGIN_HOST, host + end + self::PLUGIN_HOST + end + + def aliases + plugin_host.load_plugin_map + plugin_host.plugin_hash.inject [] do |aliases, (key, _)| + aliases << key if plugin_host[key] == self + aliases + end + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/helpers/word_list.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/helpers/word_list.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,77 @@ +module CodeRay + + # = WordList + # + # A Hash subclass designed for mapping word lists to token types. + # + # Copyright (c) 2006-2011 by murphy (Kornelius Kalnbach) + # + # License:: LGPL / ask the author + # Version:: 2.0 (2011-05-08) + # + # A WordList is a Hash with some additional features. + # It is intended to be used for keyword recognition. + # + # WordList is optimized to be used in Scanners, + # typically to decide whether a given ident is a special token. + # + # For case insensitive words use WordList::CaseIgnoring. + # + # Example: + # + # # define word arrays + # RESERVED_WORDS = %w[ + # asm break case continue default do else + # ] + # + # PREDEFINED_TYPES = %w[ + # int long short char void + # ] + # + # # make a WordList + # IDENT_KIND = WordList.new(:ident). + # add(RESERVED_WORDS, :reserved). + # add(PREDEFINED_TYPES, :predefined_type) + # + # ... + # + # def scan_tokens tokens, options + # ... + # + # elsif scan(/[A-Za-z_][A-Za-z_0-9]*/) + # # use it + # kind = IDENT_KIND[match] + # ... + class WordList < Hash + + # Create a new WordList with +default+ as default value. + def initialize default = false + super default + end + + # Add words to the list and associate them with +value+. + # + # Returns +self+, so you can concat add calls. + def add words, value = true + words.each { |word| self[word] = value } + self + end + + end + + + # A CaseIgnoring WordList is like a WordList, only that + # keys are compared case-insensitively (normalizing keys using +downcase+). + class WordList::CaseIgnoring < WordList + + def [] key + super key.downcase + end + + def []= key, value + super key.downcase, value + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanner.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanner.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,323 @@ +# encoding: utf-8 +require 'strscan' + +module CodeRay + + autoload :WordList, 'coderay/helpers/word_list' + + # = Scanners + # + # This module holds the Scanner class and its subclasses. + # For example, the Ruby scanner is named CodeRay::Scanners::Ruby + # can be found in coderay/scanners/ruby. + # + # Scanner also provides methods and constants for the register + # mechanism and the [] method that returns the Scanner class + # belonging to the given lang. + # + # See PluginHost. + module Scanners + extend PluginHost + plugin_path File.dirname(__FILE__), 'scanners' + + + # = Scanner + # + # The base class for all Scanners. + # + # It is a subclass of Ruby's great +StringScanner+, which + # makes it easy to access the scanning methods inside. + # + # It is also +Enumerable+, so you can use it like an Array of + # Tokens: + # + # require 'coderay' + # + # c_scanner = CodeRay::Scanners[:c].new "if (*p == '{') nest++;" + # + # for text, kind in c_scanner + # puts text if kind == :operator + # end + # + # # prints: (*==)++; + # + # OK, this is a very simple example :) + # You can also use +map+, +any?+, +find+ and even +sort_by+, + # if you want. + class Scanner < StringScanner + + extend Plugin + plugin_host Scanners + + # Raised if a Scanner fails while scanning + ScanError = Class.new StandardError + + # The default options for all scanner classes. + # + # Define @default_options for subclasses. + DEFAULT_OPTIONS = { } + + KINDS_NOT_LOC = [:comment, :doctype, :docstring] + + attr_accessor :state + + class << self + + # Normalizes the given code into a string with UNIX newlines, in the + # scanner's internal encoding, with invalid and undefined charachters + # replaced by placeholders. Always returns a new object. + def normalize code + # original = code + code = code.to_s unless code.is_a? ::String + return code if code.empty? + + if code.respond_to? :encoding + code = encode_with_encoding code, self.encoding + else + code = to_unix code + end + # code = code.dup if code.eql? original + code + end + + # The typical filename suffix for this scanner's language. + def file_extension extension = lang + @file_extension ||= extension.to_s + end + + # The encoding used internally by this scanner. + def encoding name = 'UTF-8' + @encoding ||= defined?(Encoding.find) && Encoding.find(name) + end + + # The lang of this Scanner class, which is equal to its Plugin ID. + def lang + @plugin_id + end + + protected + + def encode_with_encoding code, target_encoding + if code.encoding == target_encoding + if code.valid_encoding? + return to_unix(code) + else + source_encoding = guess_encoding code + end + else + source_encoding = code.encoding + end + # print "encode_with_encoding from #{source_encoding} to #{target_encoding}" + code.encode target_encoding, source_encoding, :universal_newline => true, :undef => :replace, :invalid => :replace + end + + def to_unix code + code.index(?\r) ? code.gsub(/\r\n?/, "\n") : code + end + + def guess_encoding s + #:nocov: + IO.popen("file -b --mime -", "w+") do |file| + file.write s[0, 1024] + file.close_write + begin + Encoding.find file.gets[/charset=([-\w]+)/, 1] + rescue ArgumentError + Encoding::BINARY + end + end + #:nocov: + end + + end + + # Create a new Scanner. + # + # * +code+ is the input String and is handled by the superclass + # StringScanner. + # * +options+ is a Hash with Symbols as keys. + # It is merged with the default options of the class (you can + # overwrite default options here.) + # + # Else, a Tokens object is used. + def initialize code = '', options = {} + if self.class == Scanner + raise NotImplementedError, "I am only the basic Scanner class. I can't scan anything. :( Use my subclasses." + end + + @options = self.class::DEFAULT_OPTIONS.merge options + + super self.class.normalize(code) + + @tokens = options[:tokens] || Tokens.new + @tokens.scanner = self if @tokens.respond_to? :scanner= + + setup + end + + # Sets back the scanner. Subclasses should redefine the reset_instance + # method instead of this one. + def reset + super + reset_instance + end + + # Set a new string to be scanned. + def string= code + code = self.class.normalize(code) + super code + reset_instance + end + + # the Plugin ID for this scanner + def lang + self.class.lang + end + + # the default file extension for this scanner + def file_extension + self.class.file_extension + end + + # Scan the code and returns all tokens in a Tokens object. + def tokenize source = nil, options = {} + options = @options.merge(options) + @tokens = options[:tokens] || @tokens || Tokens.new + @tokens.scanner = self if @tokens.respond_to? :scanner= + case source + when Array + self.string = self.class.normalize(source.join) + when nil + reset + else + self.string = self.class.normalize(source) + end + + begin + scan_tokens @tokens, options + rescue => e + message = "Error in %s#scan_tokens, initial state was: %p" % [self.class, defined?(state) && state] + raise_inspect e.message, @tokens, message, 30, e.backtrace + end + + @cached_tokens = @tokens + if source.is_a? Array + @tokens.split_into_parts(*source.map { |part| part.size }) + else + @tokens + end + end + + # Cache the result of tokenize. + def tokens + @cached_tokens ||= tokenize + end + + # Traverse the tokens. + def each &block + tokens.each(&block) + end + include Enumerable + + # The current line position of the scanner, starting with 1. + # See also: #column. + # + # Beware, this is implemented inefficiently. It should be used + # for debugging only. + def line pos = self.pos + return 1 if pos <= 0 + binary_string[0...pos].count("\n") + 1 + end + + # The current column position of the scanner, starting with 1. + # See also: #line. + def column pos = self.pos + return 1 if pos <= 0 + pos - (binary_string.rindex(?\n, pos - 1) || -1) + end + + # The string in binary encoding. + # + # To be used with #pos, which is the index of the byte the scanner + # will scan next. + def binary_string + @binary_string ||= + if string.respond_to?(:bytesize) && string.bytesize != string.size + #:nocov: + string.dup.force_encoding('binary') + #:nocov: + else + string + end + end + + protected + + # Can be implemented by subclasses to do some initialization + # that has to be done once per instance. + # + # Use reset for initialization that has to be done once per + # scan. + def setup # :doc: + end + + # This is the central method, and commonly the only one a + # subclass implements. + # + # Subclasses must implement this method; it must return +tokens+ + # and must only use Tokens#<< for storing scanned tokens! + def scan_tokens tokens, options # :doc: + raise NotImplementedError, "#{self.class}#scan_tokens not implemented." + end + + # Resets the scanner. + def reset_instance + @tokens.clear if @tokens.respond_to?(:clear) && !@options[:keep_tokens] + @cached_tokens = nil + @binary_string = nil if defined? @binary_string + end + + # Scanner error with additional status information + def raise_inspect msg, tokens, state = self.state || 'No state given!', ambit = 30, backtrace = caller + raise ScanError, <<-EOE % [ + + +***ERROR in %s: %s (after %d tokens) + +tokens: +%s + +current line: %d column: %d pos: %d +matched: %p state: %p +bol? = %p, eos? = %p + +surrounding code: +%p ~~ %p + + +***ERROR*** + + EOE + File.basename(caller[0]), + msg, + tokens.respond_to?(:size) ? tokens.size : 0, + tokens.respond_to?(:last) ? tokens.last(10).map { |t| t.inspect }.join("\n") : '', + line, column, pos, + matched, state, bol?, eos?, + binary_string[pos - ambit, ambit], + binary_string[pos, ambit], + ], backtrace + end + + # Shorthand for scan_until(/\z/). + # This method also avoids a JRuby 1.9 mode bug. + def scan_rest + rest = self.rest + terminate + rest + end + + end + + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/_map.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/_map.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,24 @@ +module CodeRay +module Scanners + + map \ + :'c++' => :cpp, + :cplusplus => :cpp, + :ecmascript => :java_script, + :ecma_script => :java_script, + :rhtml => :erb, + :eruby => :erb, + :irb => :ruby, + :javascript => :java_script, + :js => :java_script, + :pascal => :delphi, + :patch => :diff, + :plain => :text, + :plaintext => :text, + :xhtml => :html, + :yml => :yaml + + default :text + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/c.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/c.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,189 @@ +module CodeRay +module Scanners + + # Scanner for C. + class C < Scanner + + register_for :c + file_extension 'c' + + KEYWORDS = [ + 'asm', 'break', 'case', 'continue', 'default', 'do', + 'else', 'enum', 'for', 'goto', 'if', 'return', + 'sizeof', 'struct', 'switch', 'typedef', 'union', 'while', + 'restrict', # added in C99 + ] # :nodoc: + + PREDEFINED_TYPES = [ + 'int', 'long', 'short', 'char', + 'signed', 'unsigned', 'float', 'double', + 'bool', 'complex', # added in C99 + ] # :nodoc: + + PREDEFINED_CONSTANTS = [ + 'EOF', 'NULL', + 'true', 'false', # added in C99 + ] # :nodoc: + DIRECTIVES = [ + 'auto', 'extern', 'register', 'static', 'void', + 'const', 'volatile', # added in C89 + 'inline', # added in C99 + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_TYPES, :predefined_type). + add(DIRECTIVES, :directive). + add(PREDEFINED_CONSTANTS, :predefined_constant) # :nodoc: + + ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + label_expected = true + case_expected = false + label_expected_before_preproc_line = nil + in_preproc_line = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + if in_preproc_line && match != "\\\n" && match.index(?\n) + in_preproc_line = false + label_expected = label_expected_before_preproc_line + end + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + + elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) + label_expected = match =~ /[;\{\}]/ + if case_expected + label_expected = true if match == ':' + case_expected = false + end + encoder.text_token match, :operator + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + kind = IDENT_KIND[match] + if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) + kind = :label + match << matched + else + label_expected = false + if kind == :keyword + case match + when 'case', 'default' + case_expected = true + end + end + end + encoder.text_token match, kind + + elsif match = scan(/L?"/) + encoder.begin_group :string + if match[0] == ?L + encoder.text_token 'L', :modifier + match = '"' + end + encoder.text_token match, :delimiter + state = :string + + elsif match = scan(/ \# \s* if \s* 0 /x) + match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? + encoder.text_token match, :comment + + elsif match = scan(/#[ \t]*(\w*)/) + encoder.text_token match, :preprocessor + in_preproc_line = true + label_expected_before_preproc_line = label_expected + state = :include_expected if self[1] == 'include' + + elsif match = scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) + label_expected = false + encoder.text_token match, :char + + elsif match = scan(/\$/) + encoder.text_token match, :ident + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + label_expected = false + encoder.text_token match, :hex + + elsif match = scan(/(?:0[0-7]+)(?![89.eEfF])/) + label_expected = false + encoder.text_token match, :octal + + elsif match = scan(/(?:\d+)(?![.eEfF])L?L?/) + label_expected = false + encoder.text_token match, :integer + + elsif match = scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + label_expected = false + encoder.text_token match, :float + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(/[^\\\n"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + label_expected = false + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ | $ /x) + encoder.end_group :string + encoder.text_token match, :error + state = :initial + label_expected = false + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + when :include_expected + if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) + encoder.text_token match, :include + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + state = :initial if match.index ?\n + + else + state = :initial + + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if state == :string + encoder.end_group :string + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/clojure.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/clojure.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,217 @@ +# encoding: utf-8 +module CodeRay + module Scanners + + # Clojure scanner by Licenser. + class Clojure < Scanner + + register_for :clojure + file_extension 'clj' + + SPECIAL_FORMS = %w[ + def if do let quote var fn loop recur throw try catch monitor-enter monitor-exit . + new + ] # :nodoc: + + CORE_FORMS = %w[ + + - -> ->> .. / * <= < = == >= > accessor aclone add-classpath add-watch + agent agent-error agent-errors aget alength alias all-ns alter alter-meta! + alter-var-root amap ancestors and apply areduce array-map aset aset-boolean + aset-byte aset-char aset-double aset-float aset-int aset-long aset-short + assert assoc assoc! assoc-in associative? atom await await-for bases bean + bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or + bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array + booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char + char-array char-escape-string char-name-string char? chars class class? + clear-agent-errors clojure-version coll? comment commute comp comparator + compare compare-and-set! compile complement concat cond condp conj conj! + cons constantly construct-proxy contains? count counted? create-ns + create-struct cycle dec decimal? declare definline defmacro defmethod defmulti + defn defn- defonce defprotocol defrecord defstruct deftype delay delay? + deliver denominator deref derive descendants disj disj! dissoc dissoc! + distinct distinct? doall doc dorun doseq dosync dotimes doto double + double-array doubles drop drop-last drop-while empty empty? ensure + enumeration-seq error-handler error-mode eval even? every? extend + extend-protocol extend-type extenders extends? false? ffirst file-seq + filter find find-doc find-ns find-var first float float-array float? + floats flush fn fn? fnext for force format future future-call future-cancel + future-cancelled? future-done? future? gen-class gen-interface gensym get + get-in get-method get-proxy-class get-thread-bindings get-validator hash + hash-map hash-set identical? identity if-let if-not ifn? import in-ns + inc init-proxy instance? int int-array integer? interleave intern + interpose into into-array ints io! isa? iterate iterator-seq juxt key + keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* + list? load load-file load-reader load-string loaded-libs locking long + long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy + map map? mapcat max max-key memfn memoize merge merge-with meta methods + min min-key mod name namespace neg? newline next nfirst nil? nnext not + not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns + ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth + nthnext num number? numerator object-array odd? or parents partial + partition pcalls peek persistent! pmap pop pop! pop-thread-bindings + pos? pr pr-str prefer-method prefers print print-namespace-doc + print-str printf println println-str prn prn-str promise proxy + proxy-mappings proxy-super push-thread-bindings pvalues quot rand + rand-int range ratio? rationalize re-find re-groups re-matcher + re-matches re-pattern re-seq read read-line read-string reduce ref + ref-history-count ref-max-history ref-min-history ref-set refer + refer-clojure reify release-pending-sends rem remove remove-all-methods + remove-method remove-ns remove-watch repeat repeatedly replace replicate + require reset! reset-meta! resolve rest restart-agent resultset-seq + reverse reversible? rseq rsubseq satisfies? second select-keys send + send-off seq seq? seque sequence sequential? set set-error-handler! + set-error-mode! set-validator! set? short short-array shorts + shutdown-agents slurp some sort sort-by sorted-map sorted-map-by + sorted-set sorted-set-by sorted? special-form-anchor special-symbol? + split-at split-with str string? struct struct-map subs subseq subvec + supers swap! symbol symbol? sync syntax-symbol-anchor take take-last + take-nth take-while test the-ns thread-bound? time to-array to-array-2d + trampoline transient tree-seq true? type unchecked-add unchecked-dec + unchecked-divide unchecked-inc unchecked-multiply unchecked-negate + unchecked-remainder unchecked-subtract underive update-in update-proxy + use val vals var-get var-set var? vary-meta vec vector vector-of vector? + when when-first when-let when-not while with-bindings with-bindings* + with-in-str with-local-vars with-meta with-open with-out-str + with-precision xml-seq zero? zipmap + ] # :nodoc: + + PREDEFINED_CONSTANTS = %w[ + true false nil *1 *2 *3 *agent* *clojure-version* *command-line-args* + *compile-files* *compile-path* *e *err* *file* *flush-on-newline* + *in* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* + *print-readably* *read-eval* *warn-on-reflection* + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(SPECIAL_FORMS, :keyword). + add(CORE_FORMS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant) + + KEYWORD_NEXT_TOKEN_KIND = WordList.new(nil). + add(%w[ def defn defn- definline defmacro defmulti defmethod defstruct defonce declare ], :function). + add(%w[ ns ], :namespace). + add(%w[ defprotocol defrecord ], :class) + + BASIC_IDENTIFIER = /[a-zA-Z$%*\/_+!?&<>\-=]=?[a-zA-Z0-9$&*+!\/_?<>\-\#]*/ + IDENTIFIER = /(?!-\d)(?:(?:#{BASIC_IDENTIFIER}\.)*#{BASIC_IDENTIFIER}(?:\/#{BASIC_IDENTIFIER})?\.?)|\.\.?/ + SYMBOL = /::?#{IDENTIFIER}/o + DIGIT = /\d/ + DIGIT10 = DIGIT + DIGIT16 = /[0-9a-f]/i + DIGIT8 = /[0-7]/ + DIGIT2 = /[01]/ + RADIX16 = /\#x/i + RADIX8 = /\#o/i + RADIX2 = /\#b/i + RADIX10 = /\#d/i + EXACTNESS = /#i|#e/i + SIGN = /[\+-]?/ + EXP_MARK = /[esfdl]/i + EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/ + SUFFIX = /#{EXP}?/ + PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/ + PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/ + PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/ + PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/ + UINT10 = /#{DIGIT10}+#*/ + UINT16 = /#{DIGIT16}+#*/ + UINT8 = /#{DIGIT8}+#*/ + UINT2 = /#{DIGIT2}+#*/ + DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/ + UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/ + UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/ + UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/ + UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/ + REAL10 = /#{SIGN}#{UREAL10}/ + REAL16 = /#{SIGN}#{UREAL16}/ + REAL8 = /#{SIGN}#{UREAL8}/ + REAL2 = /#{SIGN}#{UREAL2}/ + IMAG10 = /i|#{UREAL10}i/ + IMAG16 = /i|#{UREAL16}i/ + IMAG8 = /i|#{UREAL8}i/ + IMAG2 = /i|#{UREAL2}i/ + COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/ + COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/ + COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/ + COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/ + NUM10 = /#{PREFIX10}?#{COMPLEX10}/ + NUM16 = /#{PREFIX16}#{COMPLEX16}/ + NUM8 = /#{PREFIX8}#{COMPLEX8}/ + NUM2 = /#{PREFIX2}#{COMPLEX2}/ + NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/ + + protected + + def scan_tokens encoder, options + + state = :initial + kind = nil + + until eos? + + case state + when :initial + if match = scan(/ \s+ | \\\n | , /x) + encoder.text_token match, :space + elsif match = scan(/['`\(\[\)\]\{\}]|\#[({]|~@?|[@\^]/) + encoder.text_token match, :operator + elsif match = scan(/;.*/) + encoder.text_token match, :comment # TODO: recognize (comment ...) too + elsif match = scan(/\#?\\(?:newline|space|.?)/) + encoder.text_token match, :char + elsif match = scan(/\#[ft]/) + encoder.text_token match, :predefined_constant + elsif match = scan(/#{IDENTIFIER}/o) + kind = IDENT_KIND[match] + encoder.text_token match, kind + if rest? && kind == :keyword + if kind = KEYWORD_NEXT_TOKEN_KIND[match] + encoder.text_token match, :space if match = scan(/\s+/o) + encoder.text_token match, kind if match = scan(/#{IDENTIFIER}/o) + end + end + elsif match = scan(/#{SYMBOL}/o) + encoder.text_token match, :symbol + elsif match = scan(/\./) + encoder.text_token match, :operator + elsif match = scan(/ \# \^ #{IDENTIFIER} /ox) + encoder.text_token match, :type + elsif match = scan(/ (\#)? " /x) + state = self[1] ? :regexp : :string + encoder.begin_group state + encoder.text_token match, :delimiter + elsif match = scan(/#{NUM}/o) and not matched.empty? + encoder.text_token match, match[/[.e\/]/i] ? :float : :integer + else + encoder.text_token getch, :error + end + + when :string, :regexp + if match = scan(/[^"\\]+|\\.?/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), + encoder, state + end + + else + raise 'else case reached' + + end + + end + + if [:string, :regexp].include? state + encoder.end_group state + end + + encoder + + end + end + end +end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/cpp.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/cpp.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,215 @@ +module CodeRay +module Scanners + + # Scanner for C++. + # + # Aliases: +cplusplus+, c++ + class CPlusPlus < Scanner + + register_for :cpp + file_extension 'cpp' + title 'C++' + + #-- http://www.cppreference.com/wiki/keywords/start + KEYWORDS = [ + 'and', 'and_eq', 'asm', 'bitand', 'bitor', 'break', + 'case', 'catch', 'class', 'compl', 'const_cast', + 'continue', 'default', 'delete', 'do', 'dynamic_cast', 'else', + 'enum', 'export', 'for', 'goto', 'if', 'namespace', 'new', + 'not', 'not_eq', 'or', 'or_eq', 'reinterpret_cast', 'return', + 'sizeof', 'static_cast', 'struct', 'switch', 'template', + 'throw', 'try', 'typedef', 'typeid', 'typename', 'union', + 'while', 'xor', 'xor_eq', + ] # :nodoc: + + PREDEFINED_TYPES = [ + 'bool', 'char', 'double', 'float', 'int', 'long', + 'short', 'signed', 'unsigned', 'wchar_t', 'string', + ] # :nodoc: + PREDEFINED_CONSTANTS = [ + 'false', 'true', + 'EOF', 'NULL', + ] # :nodoc: + PREDEFINED_VARIABLES = [ + 'this', + ] # :nodoc: + DIRECTIVES = [ + 'auto', 'const', 'explicit', 'extern', 'friend', 'inline', 'mutable', 'operator', + 'private', 'protected', 'public', 'register', 'static', 'using', 'virtual', 'void', + 'volatile', + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_TYPES, :predefined_type). + add(PREDEFINED_VARIABLES, :local_variable). + add(DIRECTIVES, :directive). + add(PREDEFINED_CONSTANTS, :predefined_constant) # :nodoc: + + ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + label_expected = true + case_expected = false + label_expected_before_preproc_line = nil + in_preproc_line = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + if in_preproc_line && match != "\\\n" && match.index(?\n) + in_preproc_line = false + label_expected = label_expected_before_preproc_line + end + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + + elsif match = scan(/ \# \s* if \s* 0 /x) + match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? + encoder.text_token match, :comment + + elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) + label_expected = match =~ /[;\{\}]/ + if case_expected + label_expected = true if match == ':' + case_expected = false + end + encoder.text_token match, :operator + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + kind = IDENT_KIND[match] + if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) + kind = :label + match << matched + else + label_expected = false + if kind == :keyword + case match + when 'class' + state = :class_name_expected + when 'case', 'default' + case_expected = true + end + end + end + encoder.text_token match, kind + + elsif match = scan(/\$/) + encoder.text_token match, :ident + + elsif match = scan(/L?"/) + encoder.begin_group :string + if match[0] == ?L + encoder.text_token match, 'L', :modifier + match = '"' + end + state = :string + encoder.text_token match, :delimiter + + elsif match = scan(/#[ \t]*(\w*)/) + encoder.text_token match, :preprocessor + in_preproc_line = true + label_expected_before_preproc_line = label_expected + state = :include_expected if self[1] == 'include' + + elsif match = scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) + label_expected = false + encoder.text_token match, :char + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + label_expected = false + encoder.text_token match, :hex + + elsif match = scan(/(?:0[0-7]+)(?![89.eEfF])/) + label_expected = false + encoder.text_token match, :octal + + elsif match = scan(/(?:\d+)(?![.eEfF])L?L?/) + label_expected = false + encoder.text_token match, :integer + + elsif match = scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + label_expected = false + encoder.text_token match, :float + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(/[^\\"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + label_expected = false + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/ \\ | $ /x) + encoder.end_group :string + encoder.text_token match, :error + state = :initial + label_expected = false + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + when :include_expected + if match = scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) + encoder.text_token match, :include + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + state = :initial if match.index ?\n + + else + state = :initial + + end + + when :class_name_expected + if match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + encoder.text_token match, :class + state = :initial + + elsif match = scan(/\s+/) + encoder.text_token match, :space + + else + encoder.text_token getch, :error + state = :initial + + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if state == :string + encoder.end_group :string + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/css.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/css.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,192 @@ +module CodeRay +module Scanners + + class CSS < Scanner + + register_for :css + + KINDS_NOT_LOC = [ + :comment, + :class, :pseudo_class, :type, + :constant, :directive, + :key, :value, :operator, :color, :float, :string, + :error, :important, + ] # :nodoc: + + module RE # :nodoc: + Hex = /[0-9a-fA-F]/ + Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too + Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/ + NMChar = /[-_a-zA-Z0-9]|#{Escape}/ + NMStart = /[_a-zA-Z]|#{Escape}/ + NL = /\r\n|\r|\n|\f/ + String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # TODO: buggy regexp + String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # TODO: buggy regexp + String = /#{String1}|#{String2}/ + + HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/ + Color = /#{HexColor}/ + + Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/ + Name = /#{NMChar}+/ + Ident = /-?#{NMStart}#{NMChar}*/ + AtKeyword = /@#{Ident}/ + Percentage = /#{Num}%/ + + reldimensions = %w[em ex px] + absdimensions = %w[in cm mm pt pc] + Unit = Regexp.union(*(reldimensions + absdimensions)) + + Dimension = /#{Num}#{Unit}/ + + Comment = %r! /\* (?: .*? \*/ | .* ) !mx + Function = /(?:url|alpha|attr|counters?)\((?:[^)\n\r\f]|\\\))*\)?/ + + Id = /##{Name}/ + Class = /\.#{Name}/ + PseudoClass = /:#{Name}/ + AttributeSelector = /\[[^\]]*\]?/ + end + + protected + + def scan_tokens encoder, options + + value_expected = nil + states = [:initial] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif case states.last + when :initial, :media + if match = scan(/(?>#{RE::Ident})(?!\()|\*/ox) + encoder.text_token match, :type + next + elsif match = scan(RE::Class) + encoder.text_token match, :class + next + elsif match = scan(RE::Id) + encoder.text_token match, :constant + next + elsif match = scan(RE::PseudoClass) + encoder.text_token match, :pseudo_class + next + elsif match = scan(RE::AttributeSelector) + # TODO: Improve highlighting inside of attribute selectors. + encoder.text_token match[0,1], :operator + encoder.text_token match[1..-2], :attribute_name if match.size > 2 + encoder.text_token match[-1,1], :operator if match[-1] == ?] + next + elsif match = scan(/@media/) + encoder.text_token match, :directive + states.push :media_before_name + next + end + + when :block + if match = scan(/(?>#{RE::Ident})(?!\()/ox) + if value_expected + encoder.text_token match, :value + else + encoder.text_token match, :key + end + next + end + + when :media_before_name + if match = scan(RE::Ident) + encoder.text_token match, :type + states[-1] = :media_after_name + next + end + + when :media_after_name + if match = scan(/\{/) + encoder.text_token match, :operator + states[-1] = :media + next + end + + else + #:nocov: + raise_inspect 'Unknown state', encoder + #:nocov: + + end + + elsif match = scan(/\/\*(?:.*?\*\/|\z)/m) + encoder.text_token match, :comment + + elsif match = scan(/\{/) + value_expected = false + encoder.text_token match, :operator + states.push :block + + elsif match = scan(/\}/) + value_expected = false + if states.last == :block || states.last == :media + encoder.text_token match, :operator + states.pop + else + encoder.text_token match, :error + end + + elsif match = scan(/#{RE::String}/o) + encoder.begin_group :string + encoder.text_token match[0, 1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1, 1], :delimiter if match.size >= 2 + encoder.end_group :string + + elsif match = scan(/#{RE::Function}/o) + encoder.begin_group :string + start = match[/^\w+\(/] + encoder.text_token start, :delimiter + if match[-1] == ?) + encoder.text_token match[start.size..-2], :content + encoder.text_token ')', :delimiter + else + encoder.text_token match[start.size..-1], :content + end + encoder.end_group :string + + elsif match = scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) + encoder.text_token match, :float + + elsif match = scan(/#{RE::Color}/o) + encoder.text_token match, :color + + elsif match = scan(/! *important/) + encoder.text_token match, :important + + elsif match = scan(/(?:rgb|hsl)a?\([^()\n]*\)?/) + encoder.text_token match, :color + + elsif match = scan(RE::AtKeyword) + encoder.text_token match, :directive + + elsif match = scan(/ [+>:;,.=()\/] /x) + if match == ':' + value_expected = true + elsif match == ';' + value_expected = false + end + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/debug.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/debug.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,65 @@ +module CodeRay +module Scanners + + # = Debug Scanner + # + # Interprets the output of the Encoders::Debug encoder. + class Debug < Scanner + + register_for :debug + title 'CodeRay Token Dump Import' + + protected + + def scan_tokens encoder, options + + opened_tokens = [] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif match = scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) \)? /x) + kind = self[1].to_sym + match = self[2].gsub(/\\(.)/m, '\1') + unless TokenKinds.has_key? kind + kind = :error + match = matched + end + encoder.text_token match, kind + + elsif match = scan(/ (\w+) ([<\[]) /x) + kind = self[1].to_sym + opened_tokens << kind + case self[2] + when '<' + encoder.begin_group kind + when '[' + encoder.begin_line kind + else + raise 'CodeRay bug: This case should not be reached.' + end + + elsif !opened_tokens.empty? && match = scan(/ > /x) + encoder.end_group opened_tokens.pop + + elsif !opened_tokens.empty? && match = scan(/ \] /x) + encoder.end_line opened_tokens.pop + + else + encoder.text_token getch, :space + + end + + end + + encoder.end_group opened_tokens.pop until opened_tokens.empty? + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/delphi.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/delphi.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,144 @@ +module CodeRay +module Scanners + + # Scanner for the Delphi language (Object Pascal). + # + # Alias: +pascal+ + class Delphi < Scanner + + register_for :delphi + file_extension 'pas' + + KEYWORDS = [ + 'and', 'array', 'as', 'at', 'asm', 'at', 'begin', 'case', 'class', + 'const', 'constructor', 'destructor', 'dispinterface', 'div', 'do', + 'downto', 'else', 'end', 'except', 'exports', 'file', 'finalization', + 'finally', 'for', 'function', 'goto', 'if', 'implementation', 'in', + 'inherited', 'initialization', 'inline', 'interface', 'is', 'label', + 'library', 'mod', 'nil', 'not', 'object', 'of', 'or', 'out', 'packed', + 'procedure', 'program', 'property', 'raise', 'record', 'repeat', + 'resourcestring', 'set', 'shl', 'shr', 'string', 'then', 'threadvar', + 'to', 'try', 'type', 'unit', 'until', 'uses', 'var', 'while', 'with', + 'xor', 'on', + ] # :nodoc: + + DIRECTIVES = [ + 'absolute', 'abstract', 'assembler', 'at', 'automated', 'cdecl', + 'contains', 'deprecated', 'dispid', 'dynamic', 'export', + 'external', 'far', 'forward', 'implements', 'local', + 'near', 'nodefault', 'on', 'overload', 'override', + 'package', 'pascal', 'platform', 'private', 'protected', 'public', + 'published', 'read', 'readonly', 'register', 'reintroduce', + 'requires', 'resident', 'safecall', 'stdcall', 'stored', 'varargs', + 'virtual', 'write', 'writeonly', + ] # :nodoc: + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(DIRECTIVES, :directive) # :nodoc: + + NAME_FOLLOWS = WordList::CaseIgnoring.new(false). + add(%w(procedure function .)) # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + last_token = '' + + until eos? + + if state == :initial + + if match = scan(/ \s+ /x) + encoder.text_token match, :space + next + + elsif match = scan(%r! \{ \$ [^}]* \}? | \(\* \$ (?: .*? \*\) | .* ) !mx) + encoder.text_token match, :preprocessor + next + + elsif match = scan(%r! // [^\n]* | \{ [^}]* \}? | \(\* (?: .*? \*\) | .* ) !mx) + encoder.text_token match, :comment + next + + elsif match = scan(/ <[>=]? | >=? | :=? | [-+=*\/;,@\^|\(\)\[\]] | \.\. /x) + encoder.text_token match, :operator + + elsif match = scan(/\./) + encoder.text_token match, :operator + next if last_token == 'end' + + elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) + encoder.text_token match, NAME_FOLLOWS[last_token] ? :ident : IDENT_KIND[match] + + elsif match = skip(/ ' ( [^\n']|'' ) (?:'|$) /x) + encoder.begin_group :char + encoder.text_token "'", :delimiter + encoder.text_token self[1], :content + encoder.text_token "'", :delimiter + encoder.end_group :char + next + + elsif match = scan(/ ' /x) + encoder.begin_group :string + encoder.text_token match, :delimiter + state = :string + + elsif match = scan(/ \# (?: \d+ | \$[0-9A-Fa-f]+ ) /x) + encoder.text_token match, :char + + elsif match = scan(/ \$ [0-9A-Fa-f]+ /x) + encoder.text_token match, :hex + + elsif match = scan(/ (?: \d+ ) (?![eE]|\.[^.]) /x) + encoder.text_token match, :integer + + elsif match = scan(/ \d+ (?: \.\d+ (?: [eE][+-]? \d+ )? | [eE][+-]? \d+ ) /x) + encoder.text_token match, :float + + else + encoder.text_token getch, :error + next + + end + + elsif state == :string + if match = scan(/[^\n']+/) + encoder.text_token match, :content + elsif match = scan(/''/) + encoder.text_token match, :char + elsif match = scan(/'/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + next + elsif match = scan(/\n/) + encoder.end_group :string + encoder.text_token match, :space + state = :initial + else + raise "else case \' reached; %p not handled." % peek(1), encoder + end + + else + raise 'else-case reached', encoder + + end + + last_token = match + + end + + if state == :string + encoder.end_group state + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/diff.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/diff.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,201 @@ +module CodeRay +module Scanners + + # Scanner for output of the diff command. + # + # Alias: +patch+ + class Diff < Scanner + + register_for :diff + title 'diff output' + + DEFAULT_OPTIONS = { + :highlight_code => true, + :inline_diff => true, + } + + protected + + require 'coderay/helpers/file_type' + + def scan_tokens encoder, options + + line_kind = nil + state = :initial + deleted_lines = 0 + scanners = Hash.new do |h, lang| + h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true + end + content_scanner = scanners[:plain] + content_scanner_entry_state = nil + + until eos? + + if match = scan(/\n/) + deleted_lines = 0 unless line_kind == :delete + if line_kind + encoder.end_line line_kind + line_kind = nil + end + encoder.text_token match, :space + next + end + + case state + + when :initial + if match = scan(/--- |\+\+\+ |=+|_+/) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + if match = scan(/.*?(?=$|[\t\n\x00]| \(revision)/) + encoder.text_token match, :filename + if options[:highlight_code] + file_type = FileType.fetch(match, :text) + file_type = :text if file_type == :diff + content_scanner = scanners[file_type] + content_scanner_entry_state = nil + end + end + next unless match = scan(/.+/) + encoder.text_token match, :plain + elsif match = scan(/Index: |Property changes on: /) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + next unless match = scan(/.+/) + encoder.text_token match, :plain + elsif match = scan(/Added: /) + encoder.begin_line line_kind = :head + encoder.text_token match, :head + next unless match = scan(/.+/) + encoder.text_token match, :plain + state = :added + elsif match = scan(/\\ .*/) + encoder.text_token match, :comment + elsif match = scan(/@@(?>[^@\n]*)@@/) + content_scanner.state = :initial unless match?(/\n\+/) + content_scanner_entry_state = nil + if check(/\n|$/) + encoder.begin_line line_kind = :change + else + encoder.begin_group :change + end + encoder.text_token match[0,2], :change + encoder.text_token match[2...-2], :plain + encoder.text_token match[-2,2], :change + encoder.end_group :change unless line_kind + next unless match = scan(/.+/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/\+/) + encoder.begin_line line_kind = :insert + encoder.text_token match, :insert + next unless match = scan(/.+/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/-/) + deleted_lines += 1 + encoder.begin_line line_kind = :delete + encoder.text_token match, :delete + if options[:inline_diff] && deleted_lines == 1 && check(/(?>.*)\n\+(?>.*)$(?!\n\+)/) + content_scanner_entry_state = content_scanner.state + skip(/(.*)\n\+(.*)$/) + head, deletion, insertion, tail = diff self[1], self[2] + pre, deleted, post = content_scanner.tokenize [head, deletion, tail], :tokens => Tokens.new + encoder.tokens pre + unless deleted.empty? + encoder.begin_group :eyecatcher + encoder.tokens deleted + encoder.end_group :eyecatcher + end + encoder.tokens post + encoder.end_line line_kind + encoder.text_token "\n", :space + encoder.begin_line line_kind = :insert + encoder.text_token '+', :insert + content_scanner.state = content_scanner_entry_state || :initial + pre, inserted, post = content_scanner.tokenize [head, insertion, tail], :tokens => Tokens.new + encoder.tokens pre + unless inserted.empty? + encoder.begin_group :eyecatcher + encoder.tokens inserted + encoder.end_group :eyecatcher + end + encoder.tokens post + elsif match = scan(/.*/) + if options[:highlight_code] + if deleted_lines == 1 + content_scanner_entry_state = content_scanner.state + end + content_scanner.tokenize match, :tokens => encoder unless match.empty? + if !match?(/\n-/) + if match?(/\n\+/) + content_scanner.state = content_scanner_entry_state || :initial + end + content_scanner_entry_state = nil + end + else + encoder.text_token match, :plain + end + end + next + elsif match = scan(/ .*/) + if options[:highlight_code] + content_scanner.tokenize match, :tokens => encoder + else + encoder.text_token match, :plain + end + next + elsif match = scan(/.+/) + encoder.begin_line line_kind = :comment + encoder.text_token match, :plain + else + raise_inspect 'else case rached' + end + + when :added + if match = scan(/ \+/) + encoder.begin_line line_kind = :insert + encoder.text_token match, :insert + next unless match = scan(/.+/) + encoder.text_token match, :plain + else + state = :initial + next + end + end + + end + + encoder.end_line line_kind if line_kind + + encoder + end + + private + + def diff a, b + # i will be the index of the leftmost difference from the left. + i_max = [a.size, b.size].min + i = 0 + i += 1 while i < i_max && a[i] == b[i] + # j_min will be the index of the leftmost difference from the right. + j_min = i - i_max + # j will be the index of the rightmost difference from the right which + # does not precede the leftmost one from the left. + j = -1 + j -= 1 while j >= j_min && a[j] == b[j] + return a[0...i], a[i..j], b[i..j], (j < -1) ? a[j+1..-1] : '' + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/erb.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/erb.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,81 @@ +module CodeRay +module Scanners + + load :html + load :ruby + + # Scanner for HTML ERB templates. + class ERB < Scanner + + register_for :erb + title 'HTML ERB Template' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + ERB_RUBY_BLOCK = / + (<%(?!%)[-=\#]?) + ((?> + [^\-%]* # normal* + (?> # special + (?: %(?!>) | -(?!%>) ) + [^\-%]* # normal* + )* + )) + ((?: -?%> )?) + /x # :nodoc: + + START_OF_ERB = / + <%(?!%) + /x # :nodoc: + + protected + + def setup + @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true + end + + def reset_instance + super + @html_scanner.reset + end + + def scan_tokens encoder, options + + until eos? + + if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_rest) and not match.empty? + @html_scanner.tokenize match, :tokens => encoder + + elsif match = scan(/#{ERB_RUBY_BLOCK}/o) + start_tag = self[1] + code = self[2] + end_tag = self[3] + + encoder.begin_group :inline + encoder.text_token start_tag, :inline_delimiter + + if start_tag == '<%#' + encoder.text_token code, :comment + else + @ruby_scanner.tokenize code, :tokens => encoder + end unless code.empty? + + encoder.text_token end_tag, :inline_delimiter unless end_tag.empty? + encoder.end_group :inline + + else + raise_inspect 'else-case reached!', encoder + + end + + end + + encoder + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/groovy.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/groovy.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,255 @@ +module CodeRay +module Scanners + + load :java + + # Scanner for Groovy. + class Groovy < Java + + register_for :groovy + + # TODO: check list of keywords + GROOVY_KEYWORDS = %w[ + as assert def in + ] # :nodoc: + KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ + case instanceof new return throw typeof while as assert in + ] # :nodoc: + GROOVY_MAGIC_VARIABLES = %w[ it ] # :nodoc: + + IDENT_KIND = Java::IDENT_KIND.dup. + add(GROOVY_KEYWORDS, :keyword). + add(GROOVY_MAGIC_VARIABLES, :local_variable) # :nodoc: + + ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: no 4-byte unicode chars? U[a-fA-F0-9]{8} + REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x # :nodoc: + + # TODO: interpretation inside ', ", / + STRING_CONTENT_PATTERN = { + "'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/, + '"' => /[^\\$"\n]+/, + "'''" => /(?>[^\\']+|'(?!''))+/, + '"""' => /(?>[^\\$"]+|"(?!""))+/, + '/' => /[^\\$\/\n]+/, + } # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + inline_block_stack = [] + inline_block_paren_depth = nil + string_delimiter = nil + import_clause = class_name_follows = last_token = after_def = false + value_expected = true + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + if match.index ?\n + import_clause = after_def = false + value_expected = true unless value_expected + end + next + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + value_expected = true + after_def = false + encoder.text_token match, :comment + + elsif bol? && match = scan(/ \#!.* /x) + encoder.text_token match, :doctype + + elsif import_clause && match = scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox) + after_def = value_expected = false + encoder.text_token match, :include + + elsif match = scan(/ #{IDENT} | \[\] /ox) + kind = IDENT_KIND[match] + value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] + if last_token == '.' + kind = :ident + elsif class_name_follows + kind = :class + class_name_follows = false + elsif after_def && check(/\s*[({]/) + kind = :method + after_def = false + elsif kind == :ident && last_token != '?' && check(/:/) + kind = :key + else + class_name_follows = true if match == 'class' || (import_clause && match == 'as') + import_clause = match == 'import' + after_def = true if match == 'def' + end + encoder.text_token match, kind + + elsif match = scan(/;/) + import_clause = after_def = false + value_expected = true + encoder.text_token match, :operator + + elsif match = scan(/\{/) + class_name_follows = after_def = false + value_expected = true + encoder.text_token match, :operator + if !inline_block_stack.empty? + inline_block_paren_depth += 1 + end + + # TODO: ~'...', ~"..." and ~/.../ style regexps + elsif match = scan(/ \.\.] | \+\+ | + && | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<>>?=? /x) + value_expected = true + value_expected = :regexp if match == '~' + after_def = false + encoder.text_token match, :operator + + elsif match = scan(/ [)\]}] /x) + value_expected = after_def = false + if !inline_block_stack.empty? && match == '}' + inline_block_paren_depth -= 1 + if inline_block_paren_depth == 0 # closing brace of inline block reached + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop + next + end + end + encoder.text_token match, :operator + + elsif check(/[\d.]/) + after_def = value_expected = false + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) + encoder.text_token match, :float + elsif match = scan(/\d+[lLgG]?/) + encoder.text_token match, :integer + end + + elsif match = scan(/'''|"""/) + after_def = value_expected = false + state = :multiline_string + encoder.begin_group :string + string_delimiter = match + encoder.text_token match, :delimiter + + # TODO: record.'name' syntax + elsif match = scan(/["']/) + after_def = value_expected = false + state = match == '/' ? :regexp : :string + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif value_expected && match = scan(/\//) + after_def = value_expected = false + encoder.begin_group :regexp + state = :regexp + string_delimiter = '/' + encoder.text_token match, :delimiter + + elsif match = scan(/ @ #{IDENT} /ox) + after_def = value_expected = false + encoder.text_token match, :annotation + + elsif match = scan(/\//) + after_def = false + value_expected = true + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + when :string, :regexp, :multiline_string + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + + elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/) + encoder.text_token match, :delimiter + if state == :regexp + # TODO: regexp modifiers? s, m, x, i? + modifiers = scan(/[ix]+/) + encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty? + end + state = :string if state == :multiline_string + encoder.end_group state + string_delimiter = nil + after_def = value_expected = false + state = :initial + next + + elsif (state == :string || state == :multiline_string) && + (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif state == :regexp && match = scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + + elsif match = scan(/ \$ #{IDENT} /mox) + encoder.begin_group :inline + encoder.text_token '$', :inline_delimiter + match = match[1..-1] + encoder.text_token match, IDENT_KIND[match] + encoder.end_group :inline + next + elsif match = scan(/ \$ \{ /x) + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + inline_block_stack << [state, string_delimiter, inline_block_paren_depth] + inline_block_paren_depth = 1 + state = :initial + next + + elsif match = scan(/ \$ /mx) + encoder.text_token match, :content + + elsif match = scan(/ \\. /mx) + encoder.text_token match, :content # TODO: Shouldn't this be :error? + + elsif match = scan(/ \\ | \n /x) + encoder.end_group state + encoder.text_token match, :error + after_def = value_expected = false + state = :initial + + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + + end + + else + raise_inspect 'Unknown state', encoder + + end + + last_token = match unless [:space, :comment, :doctype].include? kind + + end + + if [:multiline_string, :string, :regexp].include? state + encoder.end_group state + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/haml.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/haml.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,168 @@ +module CodeRay +module Scanners + + load :ruby + load :html + load :java_script + + class HAML < Scanner + + register_for :haml + title 'HAML Template' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + protected + + def setup + super + @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true + @embedded_ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true, :state => @ruby_scanner.interpreted_string_state + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true + end + + def scan_tokens encoder, options + + match = nil + code = '' + + until eos? + + if bol? + if match = scan(/!!!.*/) + encoder.text_token match, :doctype + next + end + + if match = scan(/(?>( *)(\/(?!\[if)|-\#|:javascript|:ruby|:\w+) *)(?=\n)/) + encoder.text_token match, :comment + + code = self[2] + if match = scan(/(?:\n+#{self[1]} .*)+/) + case code + when '/', '-#' + encoder.text_token match, :comment + when ':javascript' + # TODO: recognize #{...} snippets inside JavaScript + @java_script_scanner ||= CodeRay.scanner :java_script, :tokens => @tokens, :keep_tokens => true + @java_script_scanner.tokenize match, :tokens => encoder + when ':ruby' + @ruby_scanner.tokenize match, :tokens => encoder + when /:\w+/ + encoder.text_token match, :comment + else + raise 'else-case reached: %p' % [code] + end + end + end + + if match = scan(/ +/) + encoder.text_token match, :space + end + + if match = scan(/\/.*/) + encoder.text_token match, :comment + next + end + + if match = scan(/\\/) + encoder.text_token match, :plain + if match = scan(/.+/) + @html_scanner.tokenize match, :tokens => encoder + end + next + end + + tag = false + + if match = scan(/%[\w:]+\/?/) + encoder.text_token match, :tag + # if match = scan(/( +)(.+)/) + # encoder.text_token self[1], :space + # @embedded_ruby_scanner.tokenize self[2], :tokens => encoder + # end + tag = true + end + + while match = scan(/([.#])[-\w]*\w/) + encoder.text_token match, self[1] == '#' ? :constant : :class + tag = true + end + + if tag && match = scan(/(\()([^)]+)?(\))?/) + # TODO: recognize title=@title, class="widget_#{@widget.number}" + encoder.text_token self[1], :plain + @html_scanner.tokenize self[2], :tokens => encoder, :state => :attribute if self[2] + encoder.text_token self[3], :plain if self[3] + end + + if tag && match = scan(/\{/) + encoder.text_token match, :plain + + code = '' + level = 1 + while true + code << scan(/([^\{\},\n]|, *\n?)*/) + case match = getch + when '{' + level += 1 + code << match + when '}' + level -= 1 + if level > 0 + code << match + else + break + end + when "\n", ",", nil + break + end + end + @ruby_scanner.tokenize code, :tokens => encoder unless code.empty? + + encoder.text_token match, :plain if match + end + + if tag && match = scan(/(\[)([^\]\n]+)?(\])?/) + encoder.text_token self[1], :plain + @ruby_scanner.tokenize self[2], :tokens => encoder if self[2] + encoder.text_token self[3], :plain if self[3] + end + + if tag && match = scan(/\//) + encoder.text_token match, :tag + end + + if scan(/(>? encoder + else + @ruby_scanner.tokenize self[4], :tokens => encoder + end + end + elsif match = scan(/((?:<|> encoder if self[2] + end + + elsif match = scan(/.+/) + @html_scanner.tokenize match, :tokens => encoder + + end + + if match = scan(/\n/) + encoder.text_token match, :space + end + end + + encoder + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/html.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/html.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,253 @@ +module CodeRay +module Scanners + + # HTML Scanner + # + # Alias: +xhtml+ + # + # See also: Scanners::XML + class HTML < Scanner + + register_for :html + + KINDS_NOT_LOC = [ + :comment, :doctype, :preprocessor, + :tag, :attribute_name, :operator, + :attribute_value, :string, + :plain, :entity, :error, + ] # :nodoc: + + EVENT_ATTRIBUTES = %w( + onabort onafterprint onbeforeprint onbeforeunload onblur oncanplay + oncanplaythrough onchange onclick oncontextmenu oncuechange ondblclick + ondrag ondragdrop ondragend ondragenter ondragleave ondragover + ondragstart ondrop ondurationchange onemptied onended onerror onfocus + onformchange onforminput onhashchange oninput oninvalid onkeydown + onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart + onmessage onmousedown onmousemove onmouseout onmouseover onmouseup + onmousewheel onmove onoffline ononline onpagehide onpageshow onpause + onplay onplaying onpopstate onprogress onratechange onreadystatechange + onredo onreset onresize onscroll onseeked onseeking onselect onshow + onstalled onstorage onsubmit onsuspend ontimeupdate onundo onunload + onvolumechange onwaiting + ) + + IN_ATTRIBUTE = WordList::CaseIgnoring.new(nil). + add(EVENT_ATTRIBUTES, :script) + + ATTR_NAME = /[\w.:-]+/ # :nodoc: + TAG_END = /\/?>/ # :nodoc: + HEX = /[0-9a-fA-F]/ # :nodoc: + ENTITY = / + & + (?: + \w+ + | + \# + (?: + \d+ + | + x#{HEX}+ + ) + ) + ; + /ox # :nodoc: + + PLAIN_STRING_CONTENT = { + "'" => /[^&'>\n]+/, + '"' => /[^&">\n]+/, + } # :nodoc: + + def reset + super + @state = :initial + @plain_string_content = nil + end + + protected + + def setup + @state = :initial + @plain_string_content = nil + end + + def scan_java_script encoder, code + if code && !code.empty? + @java_script_scanner ||= Scanners::JavaScript.new '', :keep_tokens => true + # encoder.begin_group :inline + @java_script_scanner.tokenize code, :tokens => encoder + # encoder.end_group :inline + end + end + + def scan_tokens encoder, options + state = options[:state] || @state + plain_string_content = @plain_string_content + in_tag = in_attribute = nil + + encoder.begin_group :string if state == :attribute_value_string + + until eos? + + if state != :in_special_tag && match = scan(/\s+/m) + encoder.text_token match, :space + + else + + case state + + when :initial + if match = scan(/|.*)/m) + encoder.text_token match, :comment + elsif match = scan(/|.*)/m) + encoder.text_token match, :doctype + elsif match = scan(/<\?xml(?:.*?\?>|.*)/m) + encoder.text_token match, :preprocessor + elsif match = scan(/<\?(?:.*?\?>|.*)/m) + encoder.text_token match, :comment + elsif match = scan(/<\/[-\w.:]*>?/m) + in_tag = nil + encoder.text_token match, :tag + elsif match = scan(/<(?:(script)|[-\w.:]+)(>)?/m) + encoder.text_token match, :tag + in_tag = self[1] + if self[2] + state = :in_special_tag if in_tag + else + state = :attribute + end + elsif match = scan(/[^<>&]+/) + encoder.text_token match, :plain + elsif match = scan(/#{ENTITY}/ox) + encoder.text_token match, :entity + elsif match = scan(/[<>&]/) + in_tag = nil + encoder.text_token match, :error + else + raise_inspect '[BUG] else-case reached with state %p' % [state], encoder + end + + when :attribute + if match = scan(/#{TAG_END}/o) + encoder.text_token match, :tag + in_attribute = nil + if in_tag + state = :in_special_tag + else + state = :initial + end + elsif match = scan(/#{ATTR_NAME}/o) + in_attribute = IN_ATTRIBUTE[match] + encoder.text_token match, :attribute_name + state = :attribute_equal + else + in_tag = nil + encoder.text_token getch, :error + end + + when :attribute_equal + if match = scan(/=/) #/ + encoder.text_token match, :operator + state = :attribute_value + elsif scan(/#{ATTR_NAME}/o) || scan(/#{TAG_END}/o) + state = :attribute + next + else + encoder.text_token getch, :error + state = :attribute + end + + when :attribute_value + if match = scan(/#{ATTR_NAME}/o) + encoder.text_token match, :attribute_value + state = :attribute + elsif match = scan(/["']/) + if in_attribute == :script + encoder.begin_group :inline + encoder.text_token match, :inline_delimiter + if scan(/javascript:[ \t]*/) + encoder.text_token matched, :comment + end + code = scan_until(match == '"' ? /(?="|\z)/ : /(?='|\z)/) + scan_java_script encoder, code + match = scan(/["']/) + encoder.text_token match, :inline_delimiter if match + encoder.end_group :inline + state = :attribute + in_attribute = nil + else + encoder.begin_group :string + state = :attribute_value_string + plain_string_content = PLAIN_STRING_CONTENT[match] + encoder.text_token match, :delimiter + end + elsif match = scan(/#{TAG_END}/o) + encoder.text_token match, :tag + state = :initial + else + encoder.text_token getch, :error + end + + when :attribute_value_string + if match = scan(plain_string_content) + encoder.text_token match, :content + elsif match = scan(/['"]/) + encoder.text_token match, :delimiter + encoder.end_group :string + state = :attribute + elsif match = scan(/#{ENTITY}/ox) + encoder.text_token match, :entity + elsif match = scan(/&/) + encoder.text_token match, :content + elsif match = scan(/[\n>]/) + encoder.end_group :string + state = :initial + encoder.text_token match, :error + end + + when :in_special_tag + case in_tag + when 'script' + encoder.text_token match, :space if match = scan(/[ \t]*\n/) + if scan(/(\s*)|(.*))/m) + code = self[2] || self[4] + closing = self[3] + encoder.text_token self[1], :comment + else + code = scan_until(/(?=(?:\n\s*)?<\/script>)|\z/) + closing = false + end + unless code.empty? + encoder.begin_group :inline + scan_java_script encoder, code + encoder.end_group :inline + end + encoder.text_token closing, :comment if closing + state = :initial + else + raise 'unknown special tag: %p' % [in_tag] + end + + else + raise_inspect 'Unknown state: %p' % [state], encoder + + end + + end + + end + + if options[:keep_state] + @state = state + @plain_string_content = plain_string_content + end + + encoder.end_group :string if state == :attribute_value_string + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/java.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/java.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,174 @@ +module CodeRay +module Scanners + + # Scanner for Java. + class Java < Scanner + + register_for :java + + autoload :BuiltinTypes, 'coderay/scanners/java/builtin_types' + + # http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html + KEYWORDS = %w[ + assert break case catch continue default do else + finally for if instanceof import new package + return switch throw try typeof while + debugger export + ] # :nodoc: + RESERVED = %w[ const goto ] # :nodoc: + CONSTANTS = %w[ false null true ] # :nodoc: + MAGIC_VARIABLES = %w[ this super ] # :nodoc: + TYPES = %w[ + boolean byte char class double enum float int interface long + short void + ] << '[]' # :nodoc: because int[] should be highlighted as a type + DIRECTIVES = %w[ + abstract extends final implements native private protected public + static strictfp synchronized throws transient volatile + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(RESERVED, :reserved). + add(CONSTANTS, :predefined_constant). + add(MAGIC_VARIABLES, :local_variable). + add(TYPES, :type). + add(BuiltinTypes::List, :predefined_type). + add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception). + add(DIRECTIVES, :directive) # :nodoc: + + ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + STRING_CONTENT_PATTERN = { + "'" => /[^\\']+/, + '"' => /[^\\"]+/, + '/' => /[^\\\/]+/, + } # :nodoc: + IDENT = /[a-zA-Z_][A-Za-z_0-9]*/ # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + package_name_expected = false + class_name_follows = false + last_token_dot = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + next + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + encoder.text_token match, :comment + next + + elsif package_name_expected && match = scan(/ #{IDENT} (?: \. #{IDENT} )* /ox) + encoder.text_token match, package_name_expected + + elsif match = scan(/ #{IDENT} | \[\] /ox) + kind = IDENT_KIND[match] + if last_token_dot + kind = :ident + elsif class_name_follows + kind = :class + class_name_follows = false + else + case match + when 'import' + package_name_expected = :include + when 'package' + package_name_expected = :namespace + when 'class', 'interface' + class_name_follows = true + end + end + encoder.text_token match, kind + + elsif match = scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<>>?=? /x) + encoder.text_token match, :operator + + elsif match = scan(/;/) + package_name_expected = false + encoder.text_token match, :operator + + elsif match = scan(/\{/) + class_name_follows = false + encoder.text_token match, :operator + + elsif check(/[\d.]/) + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) + encoder.text_token match, :float + elsif match = scan(/\d+[lL]?/) + encoder.text_token match, :integer + end + + elsif match = scan(/["']/) + state = :string + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif match = scan(/ @ #{IDENT} /ox) + encoder.text_token match, :annotation + + else + encoder.text_token getch, :error + + end + + when :string + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + elsif match = scan(/["'\/]/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + string_delimiter = nil + elsif state == :string && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + state = :initial + encoder.text_token match, :error + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state', encoder + + end + + last_token_dot = match == '.' + + end + + if state == :string + encoder.end_group state + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/java/builtin_types.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/java/builtin_types.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,421 @@ +module CodeRay +module Scanners + + module Java::BuiltinTypes # :nodoc: + + #:nocov: + List = %w[ + AbstractAction AbstractBorder AbstractButton AbstractCellEditor AbstractCollection + AbstractColorChooserPanel AbstractDocument AbstractExecutorService AbstractInterruptibleChannel + AbstractLayoutCache AbstractList AbstractListModel AbstractMap AbstractMethodError AbstractPreferences + AbstractQueue AbstractQueuedSynchronizer AbstractSelectableChannel AbstractSelectionKey AbstractSelector + AbstractSequentialList AbstractSet AbstractSpinnerModel AbstractTableModel AbstractUndoableEdit + AbstractWriter AccessControlContext AccessControlException AccessController AccessException Accessible + AccessibleAction AccessibleAttributeSequence AccessibleBundle AccessibleComponent AccessibleContext + AccessibleEditableText AccessibleExtendedComponent AccessibleExtendedTable AccessibleExtendedText + AccessibleHyperlink AccessibleHypertext AccessibleIcon AccessibleKeyBinding AccessibleObject + AccessibleRelation AccessibleRelationSet AccessibleResourceBundle AccessibleRole AccessibleSelection + AccessibleState AccessibleStateSet AccessibleStreamable AccessibleTable AccessibleTableModelChange + AccessibleText AccessibleTextSequence AccessibleValue AccountException AccountExpiredException + AccountLockedException AccountNotFoundException Acl AclEntry AclNotFoundException Action ActionEvent + ActionListener ActionMap ActionMapUIResource Activatable ActivateFailedException ActivationDesc + ActivationException ActivationGroup ActivationGroupDesc ActivationGroupID ActivationGroup_Stub + ActivationID ActivationInstantiator ActivationMonitor ActivationSystem Activator ActiveEvent + ActivityCompletedException ActivityRequiredException Adjustable AdjustmentEvent AdjustmentListener + Adler32 AffineTransform AffineTransformOp AlgorithmParameterGenerator AlgorithmParameterGeneratorSpi + AlgorithmParameters AlgorithmParameterSpec AlgorithmParametersSpi AllPermission AlphaComposite + AlreadyBoundException AlreadyConnectedException AncestorEvent AncestorListener AnnotatedElement + Annotation AnnotationFormatError AnnotationTypeMismatchException AppConfigurationEntry Appendable Applet + AppletContext AppletInitializer AppletStub Arc2D Area AreaAveragingScaleFilter ArithmeticException Array + ArrayBlockingQueue ArrayIndexOutOfBoundsException ArrayList Arrays ArrayStoreException ArrayType + AssertionError AsyncBoxView AsynchronousCloseException AtomicBoolean AtomicInteger AtomicIntegerArray + AtomicIntegerFieldUpdater AtomicLong AtomicLongArray AtomicLongFieldUpdater AtomicMarkableReference + AtomicReference AtomicReferenceArray AtomicReferenceFieldUpdater AtomicStampedReference Attribute + AttributeChangeNotification AttributeChangeNotificationFilter AttributedCharacterIterator + AttributedString AttributeException AttributeInUseException AttributeList AttributeModificationException + AttributeNotFoundException Attributes AttributeSet AttributeSetUtilities AttributeValueExp AudioClip + AudioFileFormat AudioFileReader AudioFileWriter AudioFormat AudioInputStream AudioPermission AudioSystem + AuthenticationException AuthenticationNotSupportedException Authenticator AuthorizeCallback + AuthPermission AuthProvider Autoscroll AWTError AWTEvent AWTEventListener AWTEventListenerProxy + AWTEventMulticaster AWTException AWTKeyStroke AWTPermission BackingStoreException + BadAttributeValueExpException BadBinaryOpValueExpException BadLocationException BadPaddingException + BadStringOperationException BandCombineOp BandedSampleModel BaseRowSet BasicArrowButton BasicAttribute + BasicAttributes BasicBorders BasicButtonListener BasicButtonUI BasicCheckBoxMenuItemUI BasicCheckBoxUI + BasicColorChooserUI BasicComboBoxEditor BasicComboBoxRenderer BasicComboBoxUI BasicComboPopup + BasicControl BasicDesktopIconUI BasicDesktopPaneUI BasicDirectoryModel BasicEditorPaneUI + BasicFileChooserUI BasicFormattedTextFieldUI BasicGraphicsUtils BasicHTML BasicIconFactory + BasicInternalFrameTitlePane BasicInternalFrameUI BasicLabelUI BasicListUI BasicLookAndFeel + BasicMenuBarUI BasicMenuItemUI BasicMenuUI BasicOptionPaneUI BasicPanelUI BasicPasswordFieldUI + BasicPermission BasicPopupMenuSeparatorUI BasicPopupMenuUI BasicProgressBarUI BasicRadioButtonMenuItemUI + BasicRadioButtonUI BasicRootPaneUI BasicScrollBarUI BasicScrollPaneUI BasicSeparatorUI BasicSliderUI + BasicSpinnerUI BasicSplitPaneDivider BasicSplitPaneUI BasicStroke BasicTabbedPaneUI BasicTableHeaderUI + BasicTableUI BasicTextAreaUI BasicTextFieldUI BasicTextPaneUI BasicTextUI BasicToggleButtonUI + BasicToolBarSeparatorUI BasicToolBarUI BasicToolTipUI BasicTreeUI BasicViewportUI BatchUpdateException + BeanContext BeanContextChild BeanContextChildComponentProxy BeanContextChildSupport + BeanContextContainerProxy BeanContextEvent BeanContextMembershipEvent BeanContextMembershipListener + BeanContextProxy BeanContextServiceAvailableEvent BeanContextServiceProvider + BeanContextServiceProviderBeanInfo BeanContextServiceRevokedEvent BeanContextServiceRevokedListener + BeanContextServices BeanContextServicesListener BeanContextServicesSupport BeanContextSupport + BeanDescriptor BeanInfo Beans BevelBorder Bidi BigDecimal BigInteger BinaryRefAddr BindException Binding + BitSet Blob BlockingQueue BlockView BMPImageWriteParam Book Boolean BooleanControl Border BorderFactory + BorderLayout BorderUIResource BoundedRangeModel Box BoxLayout BoxView BreakIterator + BrokenBarrierException Buffer BufferCapabilities BufferedImage BufferedImageFilter BufferedImageOp + BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter BufferOverflowException + BufferStrategy BufferUnderflowException Button ButtonGroup ButtonModel ButtonUI Byte + ByteArrayInputStream ByteArrayOutputStream ByteBuffer ByteChannel ByteLookupTable ByteOrder CachedRowSet + CacheRequest CacheResponse Calendar Callable CallableStatement Callback CallbackHandler + CancelablePrintJob CancellationException CancelledKeyException CannotProceedException + CannotRedoException CannotUndoException Canvas CardLayout Caret CaretEvent CaretListener CellEditor + CellEditorListener CellRendererPane Certificate CertificateEncodingException CertificateException + CertificateExpiredException CertificateFactory CertificateFactorySpi CertificateNotYetValidException + CertificateParsingException CertPath CertPathBuilder CertPathBuilderException CertPathBuilderResult + CertPathBuilderSpi CertPathParameters CertPathTrustManagerParameters CertPathValidator + CertPathValidatorException CertPathValidatorResult CertPathValidatorSpi CertSelector CertStore + CertStoreException CertStoreParameters CertStoreSpi ChangedCharSetException ChangeEvent ChangeListener + Channel Channels Character CharacterCodingException CharacterIterator CharArrayReader CharArrayWriter + CharBuffer CharConversionException CharSequence Charset CharsetDecoder CharsetEncoder CharsetProvider + Checkbox CheckboxGroup CheckboxMenuItem CheckedInputStream CheckedOutputStream Checksum Choice + ChoiceCallback ChoiceFormat Chromaticity Cipher CipherInputStream CipherOutputStream CipherSpi Class + ClassCastException ClassCircularityError ClassDefinition ClassDesc ClassFileTransformer ClassFormatError + ClassLoader ClassLoaderRepository ClassLoadingMXBean ClassNotFoundException Clip Clipboard + ClipboardOwner Clob Cloneable CloneNotSupportedException Closeable ClosedByInterruptException + ClosedChannelException ClosedSelectorException CMMException CoderMalfunctionError CoderResult CodeSigner + CodeSource CodingErrorAction CollationElementIterator CollationKey Collator Collection + CollectionCertStoreParameters Collections Color ColorChooserComponentFactory ColorChooserUI + ColorConvertOp ColorModel ColorSelectionModel ColorSpace ColorSupported ColorType ColorUIResource + ComboBoxEditor ComboBoxModel ComboBoxUI ComboPopup CommunicationException Comparable Comparator + CompilationMXBean Compiler CompletionService Component ComponentAdapter ComponentColorModel + ComponentEvent ComponentInputMap ComponentInputMapUIResource ComponentListener ComponentOrientation + ComponentSampleModel ComponentUI ComponentView Composite CompositeContext CompositeData + CompositeDataSupport CompositeName CompositeType CompositeView CompoundBorder CompoundControl + CompoundEdit CompoundName Compression ConcurrentHashMap ConcurrentLinkedQueue ConcurrentMap + ConcurrentModificationException Condition Configuration ConfigurationException ConfirmationCallback + ConnectException ConnectIOException Connection ConnectionEvent ConnectionEventListener + ConnectionPendingException ConnectionPoolDataSource ConsoleHandler Constructor Container + ContainerAdapter ContainerEvent ContainerListener ContainerOrderFocusTraversalPolicy ContentHandler + ContentHandlerFactory ContentModel Context ContextNotEmptyException ContextualRenderedImageFactory + Control ControlFactory ControllerEventListener ConvolveOp CookieHandler Copies CopiesSupported + CopyOnWriteArrayList CopyOnWriteArraySet CountDownLatch CounterMonitor CounterMonitorMBean CRC32 + CredentialException CredentialExpiredException CredentialNotFoundException CRL CRLException CRLSelector + CropImageFilter CSS CubicCurve2D Currency Cursor Customizer CyclicBarrier DatabaseMetaData DataBuffer + DataBufferByte DataBufferDouble DataBufferFloat DataBufferInt DataBufferShort DataBufferUShort + DataFlavor DataFormatException DatagramChannel DatagramPacket DatagramSocket DatagramSocketImpl + DatagramSocketImplFactory DataInput DataInputStream DataLine DataOutput DataOutputStream DataSource + DataTruncation DatatypeConfigurationException DatatypeConstants DatatypeFactory Date DateFormat + DateFormatSymbols DateFormatter DateTimeAtCompleted DateTimeAtCreation DateTimeAtProcessing + DateTimeSyntax DebugGraphics DecimalFormat DecimalFormatSymbols DefaultBoundedRangeModel + DefaultButtonModel DefaultCaret DefaultCellEditor DefaultColorSelectionModel DefaultComboBoxModel + DefaultDesktopManager DefaultEditorKit DefaultFocusManager DefaultFocusTraversalPolicy DefaultFormatter + DefaultFormatterFactory DefaultHighlighter DefaultKeyboardFocusManager DefaultListCellRenderer + DefaultListModel DefaultListSelectionModel DefaultLoaderRepository DefaultMenuLayout DefaultMetalTheme + DefaultMutableTreeNode DefaultPersistenceDelegate DefaultSingleSelectionModel DefaultStyledDocument + DefaultTableCellRenderer DefaultTableColumnModel DefaultTableModel DefaultTextUI DefaultTreeCellEditor + DefaultTreeCellRenderer DefaultTreeModel DefaultTreeSelectionModel Deflater DeflaterOutputStream Delayed + DelayQueue DelegationPermission Deprecated Descriptor DescriptorAccess DescriptorSupport DESedeKeySpec + DesignMode DESKeySpec DesktopIconUI DesktopManager DesktopPaneUI Destination Destroyable + DestroyFailedException DGC DHGenParameterSpec DHKey DHParameterSpec DHPrivateKey DHPrivateKeySpec + DHPublicKey DHPublicKeySpec Dialog Dictionary DigestException DigestInputStream DigestOutputStream + Dimension Dimension2D DimensionUIResource DirContext DirectColorModel DirectoryManager DirObjectFactory + DirStateFactory DisplayMode DnDConstants Doc DocAttribute DocAttributeSet DocFlavor DocPrintJob Document + DocumentBuilder DocumentBuilderFactory Documented DocumentEvent DocumentFilter DocumentListener + DocumentName DocumentParser DomainCombiner DOMLocator DOMResult DOMSource Double DoubleBuffer + DragGestureEvent DragGestureListener DragGestureRecognizer DragSource DragSourceAdapter + DragSourceContext DragSourceDragEvent DragSourceDropEvent DragSourceEvent DragSourceListener + DragSourceMotionListener Driver DriverManager DriverPropertyInfo DropTarget DropTargetAdapter + DropTargetContext DropTargetDragEvent DropTargetDropEvent DropTargetEvent DropTargetListener DSAKey + DSAKeyPairGenerator DSAParameterSpec DSAParams DSAPrivateKey DSAPrivateKeySpec DSAPublicKey + DSAPublicKeySpec DTD DTDConstants DuplicateFormatFlagsException Duration DynamicMBean ECField ECFieldF2m + ECFieldFp ECGenParameterSpec ECKey ECParameterSpec ECPoint ECPrivateKey ECPrivateKeySpec ECPublicKey + ECPublicKeySpec EditorKit Element ElementIterator ElementType Ellipse2D EllipticCurve EmptyBorder + EmptyStackException EncodedKeySpec Encoder EncryptedPrivateKeyInfo Entity Enum + EnumConstantNotPresentException EnumControl Enumeration EnumMap EnumSet EnumSyntax EOFException Error + ErrorListener ErrorManager EtchedBorder Event EventContext EventDirContext EventHandler EventListener + EventListenerList EventListenerProxy EventObject EventQueue EventSetDescriptor Exception + ExceptionInInitializerError ExceptionListener Exchanger ExecutionException Executor + ExecutorCompletionService Executors ExecutorService ExemptionMechanism ExemptionMechanismException + ExemptionMechanismSpi ExpandVetoException ExportException Expression ExtendedRequest ExtendedResponse + Externalizable FactoryConfigurationError FailedLoginException FeatureDescriptor Fidelity Field + FieldPosition FieldView File FileCacheImageInputStream FileCacheImageOutputStream FileChannel + FileChooserUI FileDescriptor FileDialog FileFilter FileHandler FileImageInputStream + FileImageOutputStream FileInputStream FileLock FileLockInterruptionException FilenameFilter FileNameMap + FileNotFoundException FileOutputStream FilePermission FileReader FileSystemView FileView FileWriter + Filter FilteredImageSource FilteredRowSet FilterInputStream FilterOutputStream FilterReader FilterWriter + Finishings FixedHeightLayoutCache FlatteningPathIterator FlavorEvent FlavorException FlavorListener + FlavorMap FlavorTable Float FloatBuffer FloatControl FlowLayout FlowView Flushable FocusAdapter + FocusEvent FocusListener FocusManager FocusTraversalPolicy Font FontFormatException FontMetrics + FontRenderContext FontUIResource Format FormatConversionProvider FormatFlagsConversionMismatchException + Formattable FormattableFlags Formatter FormatterClosedException FormSubmitEvent FormView Frame Future + FutureTask GapContent GarbageCollectorMXBean GatheringByteChannel GaugeMonitor GaugeMonitorMBean + GeneralPath GeneralSecurityException GenericArrayType GenericDeclaration GenericSignatureFormatError + GlyphJustificationInfo GlyphMetrics GlyphVector GlyphView GradientPaint GraphicAttribute Graphics + Graphics2D GraphicsConfigTemplate GraphicsConfiguration GraphicsDevice GraphicsEnvironment GrayFilter + GregorianCalendar GridBagConstraints GridBagLayout GridLayout Group Guard GuardedObject GZIPInputStream + GZIPOutputStream Handler HandshakeCompletedEvent HandshakeCompletedListener HasControls HashAttributeSet + HashDocAttributeSet HashMap HashPrintJobAttributeSet HashPrintRequestAttributeSet + HashPrintServiceAttributeSet HashSet Hashtable HeadlessException HierarchyBoundsAdapter + HierarchyBoundsListener HierarchyEvent HierarchyListener Highlighter HostnameVerifier HTML HTMLDocument + HTMLEditorKit HTMLFrameHyperlinkEvent HTMLWriter HttpRetryException HttpsURLConnection HttpURLConnection + HyperlinkEvent HyperlinkListener ICC_ColorSpace ICC_Profile ICC_ProfileGray ICC_ProfileRGB Icon + IconUIResource IconView Identity IdentityHashMap IdentityScope IIOByteBuffer IIOException IIOImage + IIOInvalidTreeException IIOMetadata IIOMetadataController IIOMetadataFormat IIOMetadataFormatImpl + IIOMetadataNode IIOParam IIOParamController IIOReadProgressListener IIOReadUpdateListener + IIOReadWarningListener IIORegistry IIOServiceProvider IIOWriteProgressListener IIOWriteWarningListener + IllegalAccessError IllegalAccessException IllegalArgumentException IllegalBlockingModeException + IllegalBlockSizeException IllegalCharsetNameException IllegalClassFormatException + IllegalComponentStateException IllegalFormatCodePointException IllegalFormatConversionException + IllegalFormatException IllegalFormatFlagsException IllegalFormatPrecisionException + IllegalFormatWidthException IllegalMonitorStateException IllegalPathStateException + IllegalSelectorException IllegalStateException IllegalThreadStateException Image ImageCapabilities + ImageConsumer ImageFilter ImageGraphicAttribute ImageIcon ImageInputStream ImageInputStreamImpl + ImageInputStreamSpi ImageIO ImageObserver ImageOutputStream ImageOutputStreamImpl ImageOutputStreamSpi + ImageProducer ImageReader ImageReaderSpi ImageReaderWriterSpi ImageReadParam ImageTranscoder + ImageTranscoderSpi ImageTypeSpecifier ImageView ImageWriteParam ImageWriter ImageWriterSpi + ImagingOpException IncompatibleClassChangeError IncompleteAnnotationException IndexColorModel + IndexedPropertyChangeEvent IndexedPropertyDescriptor IndexOutOfBoundsException Inet4Address Inet6Address + InetAddress InetSocketAddress Inflater InflaterInputStream InheritableThreadLocal Inherited + InitialContext InitialContextFactory InitialContextFactoryBuilder InitialDirContext InitialLdapContext + InlineView InputContext InputEvent InputMap InputMapUIResource InputMethod InputMethodContext + InputMethodDescriptor InputMethodEvent InputMethodHighlight InputMethodListener InputMethodRequests + InputMismatchException InputStream InputStreamReader InputSubset InputVerifier Insets InsetsUIResource + InstanceAlreadyExistsException InstanceNotFoundException InstantiationError InstantiationException + Instrument Instrumentation InsufficientResourcesException IntBuffer Integer IntegerSyntax InternalError + InternalFrameAdapter InternalFrameEvent InternalFrameFocusTraversalPolicy InternalFrameListener + InternalFrameUI InternationalFormatter InterruptedException InterruptedIOException + InterruptedNamingException InterruptibleChannel IntrospectionException Introspector + InvalidActivityException InvalidAlgorithmParameterException InvalidApplicationException + InvalidAttributeIdentifierException InvalidAttributesException InvalidAttributeValueException + InvalidClassException InvalidDnDOperationException InvalidKeyException InvalidKeySpecException + InvalidMarkException InvalidMidiDataException InvalidNameException InvalidObjectException + InvalidOpenTypeException InvalidParameterException InvalidParameterSpecException + InvalidPreferencesFormatException InvalidPropertiesFormatException InvalidRelationIdException + InvalidRelationServiceException InvalidRelationTypeException InvalidRoleInfoException + InvalidRoleValueException InvalidSearchControlsException InvalidSearchFilterException + InvalidTargetObjectTypeException InvalidTransactionException InvocationEvent InvocationHandler + InvocationTargetException IOException ItemEvent ItemListener ItemSelectable Iterable Iterator + IvParameterSpec JApplet JarEntry JarException JarFile JarInputStream JarOutputStream JarURLConnection + JButton JCheckBox JCheckBoxMenuItem JColorChooser JComboBox JComponent JdbcRowSet JDesktopPane JDialog + JEditorPane JFileChooser JFormattedTextField JFrame JInternalFrame JLabel JLayeredPane JList JMenu + JMenuBar JMenuItem JMException JMRuntimeException JMXAuthenticator JMXConnectionNotification + JMXConnector JMXConnectorFactory JMXConnectorProvider JMXConnectorServer JMXConnectorServerFactory + JMXConnectorServerMBean JMXConnectorServerProvider JMXPrincipal JMXProviderException + JMXServerErrorException JMXServiceURL JobAttributes JobHoldUntil JobImpressions JobImpressionsCompleted + JobImpressionsSupported JobKOctets JobKOctetsProcessed JobKOctetsSupported JobMediaSheets + JobMediaSheetsCompleted JobMediaSheetsSupported JobMessageFromOperator JobName JobOriginatingUserName + JobPriority JobPrioritySupported JobSheets JobState JobStateReason JobStateReasons Joinable JoinRowSet + JOptionPane JPanel JPasswordField JPEGHuffmanTable JPEGImageReadParam JPEGImageWriteParam JPEGQTable + JPopupMenu JProgressBar JRadioButton JRadioButtonMenuItem JRootPane JScrollBar JScrollPane JSeparator + JSlider JSpinner JSplitPane JTabbedPane JTable JTableHeader JTextArea JTextComponent JTextField + JTextPane JToggleButton JToolBar JToolTip JTree JViewport JWindow KerberosKey KerberosPrincipal + KerberosTicket Kernel Key KeyAdapter KeyAgreement KeyAgreementSpi KeyAlreadyExistsException + KeyboardFocusManager KeyEvent KeyEventDispatcher KeyEventPostProcessor KeyException KeyFactory + KeyFactorySpi KeyGenerator KeyGeneratorSpi KeyListener KeyManagementException KeyManager + KeyManagerFactory KeyManagerFactorySpi Keymap KeyPair KeyPairGenerator KeyPairGeneratorSpi KeyRep + KeySpec KeyStore KeyStoreBuilderParameters KeyStoreException KeyStoreSpi KeyStroke Label LabelUI + LabelView LanguageCallback LastOwnerException LayeredHighlighter LayoutFocusTraversalPolicy + LayoutManager LayoutManager2 LayoutQueue LDAPCertStoreParameters LdapContext LdapName + LdapReferralException Lease Level LimitExceededException Line Line2D LineBorder LineBreakMeasurer + LineEvent LineListener LineMetrics LineNumberInputStream LineNumberReader LineUnavailableException + LinkageError LinkedBlockingQueue LinkedHashMap LinkedHashSet LinkedList LinkException LinkLoopException + LinkRef List ListCellRenderer ListDataEvent ListDataListener ListenerNotFoundException ListIterator + ListModel ListResourceBundle ListSelectionEvent ListSelectionListener ListSelectionModel ListUI ListView + LoaderHandler Locale LocateRegistry Lock LockSupport Logger LoggingMXBean LoggingPermission LoginContext + LoginException LoginModule LogManager LogRecord LogStream Long LongBuffer LookAndFeel LookupOp + LookupTable Mac MacSpi MalformedInputException MalformedLinkException MalformedObjectNameException + MalformedParameterizedTypeException MalformedURLException ManagementFactory ManagementPermission + ManageReferralControl ManagerFactoryParameters Manifest Map MappedByteBuffer MarshalException + MarshalledObject MaskFormatter Matcher MatchResult Math MathContext MatteBorder MBeanAttributeInfo + MBeanConstructorInfo MBeanException MBeanFeatureInfo MBeanInfo MBeanNotificationInfo MBeanOperationInfo + MBeanParameterInfo MBeanPermission MBeanRegistration MBeanRegistrationException MBeanServer + MBeanServerBuilder MBeanServerConnection MBeanServerDelegate MBeanServerDelegateMBean MBeanServerFactory + MBeanServerForwarder MBeanServerInvocationHandler MBeanServerNotification MBeanServerNotificationFilter + MBeanServerPermission MBeanTrustPermission Media MediaName MediaPrintableArea MediaSize MediaSizeName + MediaTracker MediaTray Member MemoryCacheImageInputStream MemoryCacheImageOutputStream MemoryHandler + MemoryImageSource MemoryManagerMXBean MemoryMXBean MemoryNotificationInfo MemoryPoolMXBean MemoryType + MemoryUsage Menu MenuBar MenuBarUI MenuComponent MenuContainer MenuDragMouseEvent MenuDragMouseListener + MenuElement MenuEvent MenuItem MenuItemUI MenuKeyEvent MenuKeyListener MenuListener MenuSelectionManager + MenuShortcut MessageDigest MessageDigestSpi MessageFormat MetaEventListener MetalBorders MetalButtonUI + MetalCheckBoxIcon MetalCheckBoxUI MetalComboBoxButton MetalComboBoxEditor MetalComboBoxIcon + MetalComboBoxUI MetalDesktopIconUI MetalFileChooserUI MetalIconFactory MetalInternalFrameTitlePane + MetalInternalFrameUI MetalLabelUI MetalLookAndFeel MetalMenuBarUI MetalPopupMenuSeparatorUI + MetalProgressBarUI MetalRadioButtonUI MetalRootPaneUI MetalScrollBarUI MetalScrollButton + MetalScrollPaneUI MetalSeparatorUI MetalSliderUI MetalSplitPaneUI MetalTabbedPaneUI MetalTextFieldUI + MetalTheme MetalToggleButtonUI MetalToolBarUI MetalToolTipUI MetalTreeUI MetaMessage Method + MethodDescriptor MGF1ParameterSpec MidiChannel MidiDevice MidiDeviceProvider MidiEvent MidiFileFormat + MidiFileReader MidiFileWriter MidiMessage MidiSystem MidiUnavailableException MimeTypeParseException + MinimalHTMLWriter MissingFormatArgumentException MissingFormatWidthException MissingResourceException + Mixer MixerProvider MLet MLetMBean ModelMBean ModelMBeanAttributeInfo ModelMBeanConstructorInfo + ModelMBeanInfo ModelMBeanInfoSupport ModelMBeanNotificationBroadcaster ModelMBeanNotificationInfo + ModelMBeanOperationInfo ModificationItem Modifier Monitor MonitorMBean MonitorNotification + MonitorSettingException MouseAdapter MouseDragGestureRecognizer MouseEvent MouseInfo MouseInputAdapter + MouseInputListener MouseListener MouseMotionAdapter MouseMotionListener MouseWheelEvent + MouseWheelListener MultiButtonUI MulticastSocket MultiColorChooserUI MultiComboBoxUI MultiDesktopIconUI + MultiDesktopPaneUI MultiDoc MultiDocPrintJob MultiDocPrintService MultiFileChooserUI + MultiInternalFrameUI MultiLabelUI MultiListUI MultiLookAndFeel MultiMenuBarUI MultiMenuItemUI + MultiOptionPaneUI MultiPanelUI MultiPixelPackedSampleModel MultipleDocumentHandling MultipleMaster + MultiPopupMenuUI MultiProgressBarUI MultiRootPaneUI MultiScrollBarUI MultiScrollPaneUI MultiSeparatorUI + MultiSliderUI MultiSpinnerUI MultiSplitPaneUI MultiTabbedPaneUI MultiTableHeaderUI MultiTableUI + MultiTextUI MultiToolBarUI MultiToolTipUI MultiTreeUI MultiViewportUI MutableAttributeSet + MutableComboBoxModel MutableTreeNode Name NameAlreadyBoundException NameCallback NameClassPair + NameNotFoundException NameParser NamespaceChangeListener NamespaceContext Naming NamingEnumeration + NamingEvent NamingException NamingExceptionEvent NamingListener NamingManager NamingSecurityException + NavigationFilter NegativeArraySizeException NetPermission NetworkInterface NoClassDefFoundError + NoConnectionPendingException NodeChangeEvent NodeChangeListener NoInitialContextException + NoninvertibleTransformException NonReadableChannelException NonWritableChannelException + NoPermissionException NoRouteToHostException NoSuchAlgorithmException NoSuchAttributeException + NoSuchElementException NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException + NoSuchObjectException NoSuchPaddingException NoSuchProviderException NotActiveException + NotBoundException NotCompliantMBeanException NotContextException Notification NotificationBroadcaster + NotificationBroadcasterSupport NotificationEmitter NotificationFilter NotificationFilterSupport + NotificationListener NotificationResult NotOwnerException NotSerializableException NotYetBoundException + NotYetConnectedException NullCipher NullPointerException Number NumberFormat NumberFormatException + NumberFormatter NumberOfDocuments NumberOfInterveningJobs NumberUp NumberUpSupported NumericShaper + OAEPParameterSpec Object ObjectChangeListener ObjectFactory ObjectFactoryBuilder ObjectInput + ObjectInputStream ObjectInputValidation ObjectInstance ObjectName ObjectOutput ObjectOutputStream + ObjectStreamClass ObjectStreamConstants ObjectStreamException ObjectStreamField ObjectView ObjID + Observable Observer OceanTheme OpenDataException OpenMBeanAttributeInfo OpenMBeanAttributeInfoSupport + OpenMBeanConstructorInfo OpenMBeanConstructorInfoSupport OpenMBeanInfo OpenMBeanInfoSupport + OpenMBeanOperationInfo OpenMBeanOperationInfoSupport OpenMBeanParameterInfo + OpenMBeanParameterInfoSupport OpenType OperatingSystemMXBean Operation OperationNotSupportedException + OperationsException Option OptionalDataException OptionPaneUI OrientationRequested OutOfMemoryError + OutputDeviceAssigned OutputKeys OutputStream OutputStreamWriter OverlappingFileLockException + OverlayLayout Override Owner Pack200 Package PackedColorModel Pageable PageAttributes + PagedResultsControl PagedResultsResponseControl PageFormat PageRanges PagesPerMinute PagesPerMinuteColor + Paint PaintContext PaintEvent Panel PanelUI Paper ParagraphView ParameterBlock ParameterDescriptor + ParameterizedType ParameterMetaData ParseException ParsePosition Parser ParserConfigurationException + ParserDelegator PartialResultException PasswordAuthentication PasswordCallback PasswordView Patch + PathIterator Pattern PatternSyntaxException PBEKey PBEKeySpec PBEParameterSpec PDLOverrideSupported + Permission PermissionCollection Permissions PersistenceDelegate PersistentMBean PhantomReference Pipe + PipedInputStream PipedOutputStream PipedReader PipedWriter PixelGrabber PixelInterleavedSampleModel + PKCS8EncodedKeySpec PKIXBuilderParameters PKIXCertPathBuilderResult PKIXCertPathChecker + PKIXCertPathValidatorResult PKIXParameters PlainDocument PlainView Point Point2D PointerInfo Policy + PolicyNode PolicyQualifierInfo Polygon PooledConnection Popup PopupFactory PopupMenu PopupMenuEvent + PopupMenuListener PopupMenuUI Port PortableRemoteObject PortableRemoteObjectDelegate + PortUnreachableException Position Predicate PreferenceChangeEvent PreferenceChangeListener Preferences + PreferencesFactory PreparedStatement PresentationDirection Principal Printable PrinterAbortException + PrinterException PrinterGraphics PrinterInfo PrinterIOException PrinterIsAcceptingJobs PrinterJob + PrinterLocation PrinterMakeAndModel PrinterMessageFromOperator PrinterMoreInfo + PrinterMoreInfoManufacturer PrinterName PrinterResolution PrinterState PrinterStateReason + PrinterStateReasons PrinterURI PrintEvent PrintException PrintGraphics PrintJob PrintJobAdapter + PrintJobAttribute PrintJobAttributeEvent PrintJobAttributeListener PrintJobAttributeSet PrintJobEvent + PrintJobListener PrintQuality PrintRequestAttribute PrintRequestAttributeSet PrintService + PrintServiceAttribute PrintServiceAttributeEvent PrintServiceAttributeListener PrintServiceAttributeSet + PrintServiceLookup PrintStream PrintWriter PriorityBlockingQueue PriorityQueue PrivateClassLoader + PrivateCredentialPermission PrivateKey PrivateMLet PrivilegedAction PrivilegedActionException + PrivilegedExceptionAction Process ProcessBuilder ProfileDataException ProgressBarUI ProgressMonitor + ProgressMonitorInputStream Properties PropertyChangeEvent PropertyChangeListener + PropertyChangeListenerProxy PropertyChangeSupport PropertyDescriptor PropertyEditor + PropertyEditorManager PropertyEditorSupport PropertyPermission PropertyResourceBundle + PropertyVetoException ProtectionDomain ProtocolException Provider ProviderException Proxy ProxySelector + PSource PSSParameterSpec PublicKey PushbackInputStream PushbackReader QName QuadCurve2D Query QueryEval + QueryExp Queue QueuedJobCount Random RandomAccess RandomAccessFile Raster RasterFormatException RasterOp + RC2ParameterSpec RC5ParameterSpec Rdn Readable ReadableByteChannel Reader ReadOnlyBufferException + ReadWriteLock RealmCallback RealmChoiceCallback Receiver Rectangle Rectangle2D RectangularShape + ReentrantLock ReentrantReadWriteLock Ref RefAddr Reference Referenceable ReferenceQueue + ReferenceUriSchemesSupported ReferralException ReflectionException ReflectPermission Refreshable + RefreshFailedException Region RegisterableService Registry RegistryHandler RejectedExecutionException + RejectedExecutionHandler Relation RelationException RelationNotFoundException RelationNotification + RelationService RelationServiceMBean RelationServiceNotRegisteredException RelationSupport + RelationSupportMBean RelationType RelationTypeNotFoundException RelationTypeSupport Remote RemoteCall + RemoteException RemoteObject RemoteObjectInvocationHandler RemoteRef RemoteServer RemoteStub + RenderableImage RenderableImageOp RenderableImageProducer RenderContext RenderedImage + RenderedImageFactory Renderer RenderingHints RepaintManager ReplicateScaleFilter RequestingUserName + RequiredModelMBean RescaleOp ResolutionSyntax Resolver ResolveResult ResourceBundle ResponseCache Result + ResultSet ResultSetMetaData Retention RetentionPolicy ReverbType RGBImageFilter RMIClassLoader + RMIClassLoaderSpi RMIClientSocketFactory RMIConnection RMIConnectionImpl RMIConnectionImpl_Stub + RMIConnector RMIConnectorServer RMIFailureHandler RMIIIOPServerImpl RMIJRMPServerImpl + RMISecurityException RMISecurityManager RMIServer RMIServerImpl RMIServerImpl_Stub + RMIServerSocketFactory RMISocketFactory Robot Role RoleInfo RoleInfoNotFoundException RoleList + RoleNotFoundException RoleResult RoleStatus RoleUnresolved RoleUnresolvedList RootPaneContainer + RootPaneUI RoundingMode RoundRectangle2D RowMapper RowSet RowSetEvent RowSetInternal RowSetListener + RowSetMetaData RowSetMetaDataImpl RowSetReader RowSetWarning RowSetWriter RSAKey RSAKeyGenParameterSpec + RSAMultiPrimePrivateCrtKey RSAMultiPrimePrivateCrtKeySpec RSAOtherPrimeInfo RSAPrivateCrtKey + RSAPrivateCrtKeySpec RSAPrivateKey RSAPrivateKeySpec RSAPublicKey RSAPublicKeySpec RTFEditorKit + RuleBasedCollator Runnable Runtime RuntimeErrorException RuntimeException RuntimeMBeanException + RuntimeMXBean RuntimeOperationsException RuntimePermission SampleModel Sasl SaslClient SaslClientFactory + SaslException SaslServer SaslServerFactory Savepoint SAXParser SAXParserFactory SAXResult SAXSource + SAXTransformerFactory Scanner ScatteringByteChannel ScheduledExecutorService ScheduledFuture + ScheduledThreadPoolExecutor Schema SchemaFactory SchemaFactoryLoader SchemaViolationException Scrollable + Scrollbar ScrollBarUI ScrollPane ScrollPaneAdjustable ScrollPaneConstants ScrollPaneLayout ScrollPaneUI + SealedObject SearchControls SearchResult SecretKey SecretKeyFactory SecretKeyFactorySpi SecretKeySpec + SecureCacheResponse SecureClassLoader SecureRandom SecureRandomSpi Security SecurityException + SecurityManager SecurityPermission Segment SelectableChannel SelectionKey Selector SelectorProvider + Semaphore SeparatorUI Sequence SequenceInputStream Sequencer SerialArray SerialBlob SerialClob + SerialDatalink SerialException Serializable SerializablePermission SerialJavaObject SerialRef + SerialStruct ServerCloneException ServerError ServerException ServerNotActiveException ServerRef + ServerRuntimeException ServerSocket ServerSocketChannel ServerSocketFactory ServiceNotFoundException + ServicePermission ServiceRegistry ServiceUI ServiceUIFactory ServiceUnavailableException Set + SetOfIntegerSyntax Severity Shape ShapeGraphicAttribute SheetCollate Short ShortBuffer + ShortBufferException ShortLookupTable ShortMessage Sides Signature SignatureException SignatureSpi + SignedObject Signer SimpleAttributeSet SimpleBeanInfo SimpleDateFormat SimpleDoc SimpleFormatter + SimpleTimeZone SimpleType SinglePixelPackedSampleModel SingleSelectionModel Size2DSyntax + SizeLimitExceededException SizeRequirements SizeSequence Skeleton SkeletonMismatchException + SkeletonNotFoundException SliderUI Socket SocketAddress SocketChannel SocketException SocketFactory + SocketHandler SocketImpl SocketImplFactory SocketOptions SocketPermission SocketSecurityException + SocketTimeoutException SoftBevelBorder SoftReference SortControl SortedMap SortedSet + SortingFocusTraversalPolicy SortKey SortResponseControl Soundbank SoundbankReader SoundbankResource + Source SourceDataLine SourceLocator SpinnerDateModel SpinnerListModel SpinnerModel SpinnerNumberModel + SpinnerUI SplitPaneUI Spring SpringLayout SQLData SQLException SQLInput SQLInputImpl SQLOutput + SQLOutputImpl SQLPermission SQLWarning SSLContext SSLContextSpi SSLEngine SSLEngineResult SSLException + SSLHandshakeException SSLKeyException SSLPeerUnverifiedException SSLPermission SSLProtocolException + SslRMIClientSocketFactory SslRMIServerSocketFactory SSLServerSocket SSLServerSocketFactory SSLSession + SSLSessionBindingEvent SSLSessionBindingListener SSLSessionContext SSLSocket SSLSocketFactory Stack + StackOverflowError StackTraceElement StandardMBean StartTlsRequest StartTlsResponse StateEdit + StateEditable StateFactory Statement StreamCorruptedException StreamHandler StreamPrintService + StreamPrintServiceFactory StreamResult StreamSource StreamTokenizer StrictMath String StringBuffer + StringBufferInputStream StringBuilder StringCharacterIterator StringContent + StringIndexOutOfBoundsException StringMonitor StringMonitorMBean StringReader StringRefAddr + StringSelection StringTokenizer StringValueExp StringWriter Stroke Struct Stub StubDelegate + StubNotFoundException Style StyleConstants StyleContext StyledDocument StyledEditorKit StyleSheet + Subject SubjectDelegationPermission SubjectDomainCombiner SupportedValuesAttribute SuppressWarnings + SwingConstants SwingPropertyChangeSupport SwingUtilities SyncFactory SyncFactoryException + SyncFailedException SynchronousQueue SyncProvider SyncProviderException SyncResolver SynthConstants + SynthContext Synthesizer SynthGraphicsUtils SynthLookAndFeel SynthPainter SynthStyle SynthStyleFactory + SysexMessage System SystemColor SystemFlavorMap TabableView TabbedPaneUI TabExpander TableCellEditor + TableCellRenderer TableColumn TableColumnModel TableColumnModelEvent TableColumnModelListener + TableHeaderUI TableModel TableModelEvent TableModelListener TableUI TableView TabSet TabStop TabularData + TabularDataSupport TabularType TagElement Target TargetDataLine TargetedNotification Templates + TemplatesHandler TextAction TextArea TextAttribute TextComponent TextEvent TextField TextHitInfo + TextInputCallback TextLayout TextListener TextMeasurer TextOutputCallback TextSyntax TextUI TexturePaint + Thread ThreadDeath ThreadFactory ThreadGroup ThreadInfo ThreadLocal ThreadMXBean ThreadPoolExecutor + Throwable Tie TileObserver Time TimeLimitExceededException TimeoutException Timer + TimerAlarmClockNotification TimerMBean TimerNotification TimerTask Timestamp TimeUnit TimeZone + TitledBorder ToolBarUI Toolkit ToolTipManager ToolTipUI TooManyListenersException Track + TransactionalWriter TransactionRequiredException TransactionRolledbackException Transferable + TransferHandler TransformAttribute Transformer TransformerConfigurationException TransformerException + TransformerFactory TransformerFactoryConfigurationError TransformerHandler Transmitter Transparency + TreeCellEditor TreeCellRenderer TreeExpansionEvent TreeExpansionListener TreeMap TreeModel + TreeModelEvent TreeModelListener TreeNode TreePath TreeSelectionEvent TreeSelectionListener + TreeSelectionModel TreeSet TreeUI TreeWillExpandListener TrustAnchor TrustManager TrustManagerFactory + TrustManagerFactorySpi Type TypeInfoProvider TypeNotPresentException Types TypeVariable UID UIDefaults + UIManager UIResource UndeclaredThrowableException UndoableEdit UndoableEditEvent UndoableEditListener + UndoableEditSupport UndoManager UnexpectedException UnicastRemoteObject UnknownError + UnknownFormatConversionException UnknownFormatFlagsException UnknownGroupException UnknownHostException + UnknownObjectException UnknownServiceException UnmappableCharacterException UnmarshalException + UnmodifiableClassException UnmodifiableSetException UnrecoverableEntryException + UnrecoverableKeyException Unreferenced UnresolvedAddressException UnresolvedPermission + UnsatisfiedLinkError UnsolicitedNotification UnsolicitedNotificationEvent + UnsolicitedNotificationListener UnsupportedAddressTypeException UnsupportedAudioFileException + UnsupportedCallbackException UnsupportedCharsetException UnsupportedClassVersionError + UnsupportedEncodingException UnsupportedFlavorException UnsupportedLookAndFeelException + UnsupportedOperationException URI URIException URIResolver URISyntax URISyntaxException URL + URLClassLoader URLConnection URLDecoder URLEncoder URLStreamHandler URLStreamHandlerFactory + UTFDataFormatException Util UtilDelegate Utilities UUID Validator ValidatorHandler ValueExp ValueHandler + ValueHandlerMultiFormat VariableHeightLayoutCache Vector VerifyError VetoableChangeListener + VetoableChangeListenerProxy VetoableChangeSupport View ViewFactory ViewportLayout ViewportUI + VirtualMachineError Visibility VMID VoiceStatus Void VolatileImage WeakHashMap WeakReference WebRowSet + WildcardType Window WindowAdapter WindowConstants WindowEvent WindowFocusListener WindowListener + WindowStateListener WrappedPlainView WritableByteChannel WritableRaster WritableRenderedImage + WriteAbortedException Writer X500Principal X500PrivateCredential X509Certificate X509CertSelector + X509CRL X509CRLEntry X509CRLSelector X509EncodedKeySpec X509ExtendedKeyManager X509Extension + X509KeyManager X509TrustManager XAConnection XADataSource XAException XAResource Xid XMLConstants + XMLDecoder XMLEncoder XMLFormatter XMLGregorianCalendar XMLParseException XmlReader XmlWriter XPath + XPathConstants XPathException XPathExpression XPathExpressionException XPathFactory + XPathFactoryConfigurationException XPathFunction XPathFunctionException XPathFunctionResolver + XPathVariableResolver ZipEntry ZipException ZipFile ZipInputStream ZipOutputStream ZoneView + ] + #:nocov: + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/java_script.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/java_script.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,213 @@ +module CodeRay +module Scanners + + # Scanner for JavaScript. + # + # Aliases: +ecmascript+, +ecma_script+, +javascript+ + class JavaScript < Scanner + + register_for :java_script + file_extension 'js' + + # The actual JavaScript keywords. + KEYWORDS = %w[ + break case catch continue default delete do else + finally for function if in instanceof new + return switch throw try typeof var void while with + ] # :nodoc: + PREDEFINED_CONSTANTS = %w[ + false null true undefined NaN Infinity + ] # :nodoc: + + MAGIC_VARIABLES = %w[ this arguments ] # :nodoc: arguments was introduced in JavaScript 1.4 + + KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ + case delete in instanceof new return throw typeof with + ] # :nodoc: + + # Reserved for future use. + RESERVED_WORDS = %w[ + abstract boolean byte char class debugger double enum export extends + final float goto implements import int interface long native package + private protected public short static super synchronized throws transient + volatile + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(RESERVED_WORDS, :reserved). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(MAGIC_VARIABLES, :local_variable). + add(KEYWORDS, :keyword) # :nodoc: + + ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x # :nodoc: + REGEXP_ESCAPE = / [bBdDsSwW] /x # :nodoc: + STRING_CONTENT_PATTERN = { + "'" => /[^\\']+/, + '"' => /[^\\"]+/, + '/' => /[^\\\/]+/, + } # :nodoc: + KEY_CHECK_PATTERN = { + "'" => / (?> [^\\']* (?: \\. [^\\']* )* ) ' \s* : /mx, + '"' => / (?> [^\\"]* (?: \\. [^\\"]* )* ) " \s* : /mx, + } # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + value_expected = true + key_expected = false + function_expected = false + + until eos? + + case state + + when :initial + + if match = scan(/ \s+ | \\\n /x) + value_expected = true if !value_expected && match.index(?\n) + encoder.text_token match, :space + + elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) + value_expected = true + encoder.text_token match, :comment + + elsif check(/\.?\d/) + key_expected = value_expected = false + if match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + elsif match = scan(/(?>0[0-7]+)(?![89.eEfF])/) + encoder.text_token match, :octal + elsif match = scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) + encoder.text_token match, :float + elsif match = scan(/\d+/) + encoder.text_token match, :integer + end + + elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim) + # TODO: scan over nested tags + xml_scanner.tokenize match, :tokens => encoder + value_expected = false + next + + elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x) + value_expected = true + last_operator = match[-1] + key_expected = (last_operator == ?{) || (last_operator == ?,) + function_expected = false + encoder.text_token match, :operator + + elsif match = scan(/ [)\]}]+ /x) + function_expected = key_expected = value_expected = false + encoder.text_token match, :operator + + elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x) + kind = IDENT_KIND[match] + value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] + # TODO: labels + if kind == :ident + if match.index(?$) # $ allowed inside an identifier + kind = :predefined + elsif function_expected + kind = :function + elsif check(/\s*[=:]\s*function\b/) + kind = :function + elsif key_expected && check(/\s*:/) + kind = :key + end + end + function_expected = (kind == :keyword) && (match == 'function') + key_expected = false + encoder.text_token match, kind + + elsif match = scan(/["']/) + if key_expected && check(KEY_CHECK_PATTERN[match]) + state = :key + else + state = :string + end + encoder.begin_group state + string_delimiter = match + encoder.text_token match, :delimiter + + elsif value_expected && (match = scan(/\//)) + encoder.begin_group :regexp + state = :regexp + string_delimiter = '/' + encoder.text_token match, :delimiter + + elsif match = scan(/ \/ /x) + value_expected = true + key_expected = false + encoder.text_token match, :operator + + else + encoder.text_token getch, :error + + end + + when :string, :regexp, :key + if match = scan(STRING_CONTENT_PATTERN[string_delimiter]) + encoder.text_token match, :content + elsif match = scan(/["'\/]/) + encoder.text_token match, :delimiter + if state == :regexp + modifiers = scan(/[gim]+/) + encoder.text_token modifiers, :modifier if modifiers && !modifiers.empty? + end + encoder.end_group state + string_delimiter = nil + key_expected = value_expected = false + state = :initial + elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) + if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") + encoder.text_token match, :content + else + encoder.text_token match, :char + end + elsif state == :regexp && match = scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + encoder.text_token match, :error + key_expected = value_expected = false + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state', encoder + + end + + end + + if [:string, :regexp].include? state + encoder.end_group state + end + + encoder + end + + protected + + def reset_instance + super + @xml_scanner.reset if defined? @xml_scanner + end + + def xml_scanner + @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/json.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/json.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,95 @@ +module CodeRay +module Scanners + + # Scanner for JSON (JavaScript Object Notation). + class JSON < Scanner + + register_for :json + file_extension 'json' + + KINDS_NOT_LOC = [ + :float, :char, :content, :delimiter, + :error, :integer, :operator, :value, + ] # :nodoc: + + ESCAPE = / [bfnrt\\"\/] /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: + + protected + + # See http://json.org/ for a definition of the JSON lexic/grammar. + def scan_tokens encoder, options + + state = :initial + stack = [] + key_expected = false + + until eos? + + case state + + when :initial + if match = scan(/ \s+ /x) + encoder.text_token match, :space + elsif match = scan(/"/) + state = key_expected ? :key : :string + encoder.begin_group state + encoder.text_token match, :delimiter + elsif match = scan(/ [:,\[{\]}] /x) + encoder.text_token match, :operator + case match + when ':' then key_expected = false + when ',' then key_expected = true if stack.last == :object + when '{' then stack << :object; key_expected = true + when '[' then stack << :array + when '}', ']' then stack.pop # no error recovery, but works for valid JSON + end + elsif match = scan(/ true | false | null /x) + encoder.text_token match, :value + elsif match = scan(/ -? (?: 0 | [1-9]\d* ) /x) + if scan(/ \.\d+ (?:[eE][-+]?\d+)? | [eE][-+]? \d+ /x) + match << matched + encoder.text_token match, :float + else + encoder.text_token match, :integer + end + else + encoder.text_token getch, :error + end + + when :string, :key + if match = scan(/[^\\"]+/) + encoder.text_token match, :content + elsif match = scan(/"/) + encoder.text_token match, :delimiter + encoder.end_group state + state = :initial + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + encoder.text_token match, :char + elsif match = scan(/\\./m) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group state + encoder.text_token match, :error + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise_inspect 'Unknown state: %p' % [state], encoder + + end + end + + if [:string, :key].include? state + encoder.end_group state + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/php.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/php.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,509 @@ +module CodeRay +module Scanners + + load :html + + # Scanner for PHP. + # + # Original by Stefan Walk. + class PHP < Scanner + + register_for :php + file_extension 'php' + encoding 'BINARY' + + KINDS_NOT_LOC = HTML::KINDS_NOT_LOC + + protected + + def setup + @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true + end + + def reset_instance + super + @html_scanner.reset + end + + module Words # :nodoc: + + # according to http://www.php.net/manual/en/reserved.keywords.php + KEYWORDS = %w[ + abstract and array as break case catch class clone const continue declare default do else elseif + enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global + goto if implements interface instanceof namespace new or private protected public static switch + throw try use var while xor + cfunction old_function + ] + + TYPES = %w[ int integer float double bool boolean string array object resource ] + + LANGUAGE_CONSTRUCTS = %w[ + die echo empty exit eval include include_once isset list + require require_once return print unset + ] + + CLASSES = %w[ Directory stdClass __PHP_Incomplete_Class exception php_user_filter Closure ] + + # according to http://php.net/quickref.php on 2009-04-21; + # all functions with _ excluded (module functions) and selected additional functions + BUILTIN_FUNCTIONS = %w[ + abs acos acosh addcslashes addslashes aggregate array arsort ascii2ebcdic asin asinh asort assert atan atan2 + atanh basename bcadd bccomp bcdiv bcmod bcmul bcpow bcpowmod bcscale bcsqrt bcsub bin2hex bindec + bindtextdomain bzclose bzcompress bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite + calculhmac ceil chdir checkdate checkdnsrr chgrp chmod chop chown chr chroot clearstatcache closedir closelog + compact constant copy cos cosh count crc32 crypt current date dcgettext dcngettext deaggregate decbin dechex + decoct define defined deg2rad delete dgettext die dirname diskfreespace dl dngettext doubleval each + ebcdic2ascii echo empty end ereg eregi escapeshellarg escapeshellcmd eval exec exit exp explode expm1 extract + fclose feof fflush fgetc fgetcsv fgets fgetss file fileatime filectime filegroup fileinode filemtime fileowner + fileperms filepro filesize filetype floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv + fputs fread frenchtojd fscanf fseek fsockopen fstat ftell ftok ftruncate fwrite getallheaders getcwd getdate + getenv gethostbyaddr gethostbyname gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid + getmyuid getopt getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext + gettimeofday gettype glob gmdate gmmktime gmstrftime gregoriantojd gzclose gzcompress gzdecode gzdeflate + gzencode gzeof gzfile gzgetc gzgets gzgetss gzinflate gzopen gzpassthru gzputs gzread gzrewind gzseek gztell + gzuncompress gzwrite hash header hebrev hebrevc hexdec htmlentities htmlspecialchars hypot iconv idate + implode include intval ip2long iptcembed iptcparse isset + jddayofweek jdmonthname jdtofrench jdtogregorian jdtojewish jdtojulian jdtounix jewishtojd join jpeg2wbmp + juliantojd key krsort ksort lcfirst lchgrp lchown levenshtein link linkinfo list localeconv localtime log + log10 log1p long2ip lstat ltrim mail main max md5 metaphone mhash microtime min mkdir mktime msql natcasesort + natsort next ngettext nl2br nthmac octdec opendir openlog + ord overload pack passthru pathinfo pclose pfsockopen phpcredits phpinfo phpversion pi png2wbmp popen pos pow + prev print printf putenv quotemeta rad2deg rand range rawurldecode rawurlencode readdir readfile readgzfile + readline readlink realpath recode rename require reset rewind rewinddir rmdir round rsort rtrim scandir + serialize setcookie setlocale setrawcookie settype sha1 shuffle signeurlpaiement sin sinh sizeof sleep snmpget + snmpgetnext snmprealwalk snmpset snmpwalk snmpwalkoid sort soundex split spliti sprintf sqrt srand sscanf stat + strcasecmp strchr strcmp strcoll strcspn strftime stripcslashes stripos stripslashes stristr strlen + strnatcasecmp strnatcmp strncasecmp strncmp strpbrk strpos strptime strrchr strrev strripos strrpos strspn + strstr strtok strtolower strtotime strtoupper strtr strval substr symlink syslog system tan tanh tempnam + textdomain time tmpfile touch trim uasort ucfirst ucwords uksort umask uniqid unixtojd unlink unpack + unserialize unset urldecode urlencode usleep usort vfprintf virtual vprintf vsprintf wordwrap + array_change_key_case array_chunk array_combine array_count_values array_diff array_diff_assoc + array_diff_key array_diff_uassoc array_diff_ukey array_fill array_fill_keys array_filter array_flip + array_intersect array_intersect_assoc array_intersect_key array_intersect_uassoc array_intersect_ukey + array_key_exists array_keys array_map array_merge array_merge_recursive array_multisort array_pad + array_pop array_product array_push array_rand array_reduce array_reverse array_search array_shift + array_slice array_splice array_sum array_udiff array_udiff_assoc array_udiff_uassoc array_uintersect + array_uintersect_assoc array_uintersect_uassoc array_unique array_unshift array_values array_walk + array_walk_recursive + assert_options base_convert base64_decode base64_encode + chunk_split class_exists class_implements class_parents + count_chars debug_backtrace debug_print_backtrace debug_zval_dump + error_get_last error_log error_reporting extension_loaded + file_exists file_get_contents file_put_contents load_file + func_get_arg func_get_args func_num_args function_exists + get_browser get_called_class get_cfg_var get_class get_class_methods get_class_vars + get_current_user get_declared_classes get_declared_interfaces get_defined_constants + get_defined_functions get_defined_vars get_extension_funcs get_headers get_html_translation_table + get_include_path get_included_files get_loaded_extensions get_magic_quotes_gpc get_magic_quotes_runtime + get_meta_tags get_object_vars get_parent_class get_required_filesget_resource_type + gc_collect_cycles gc_disable gc_enable gc_enabled + halt_compiler headers_list headers_sent highlight_file highlight_string + html_entity_decode htmlspecialchars_decode + in_array include_once inclued_get_data + is_a is_array is_binary is_bool is_buffer is_callable is_dir is_double is_executable is_file is_finite + is_float is_infinite is_int is_integer is_link is_long is_nan is_null is_numeric is_object is_readable + is_real is_resource is_scalar is_soap_fault is_string is_subclass_of is_unicode is_uploaded_file + is_writable is_writeable + locale_get_default locale_set_default + number_format override_function parse_str parse_url + php_check_syntax php_ini_loaded_file php_ini_scanned_files php_logo_guid php_sapi_name + php_strip_whitespace php_uname + preg_filter preg_grep preg_last_error preg_match preg_match_all preg_quote preg_replace + preg_replace_callback preg_split print_r + require_once register_shutdown_function register_tick_function + set_error_handler set_exception_handler set_file_buffer set_include_path + set_magic_quotes_runtime set_time_limit shell_exec + str_getcsv str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split str_word_count + strip_tags substr_compare substr_count substr_replace + time_nanosleep time_sleep_until + token_get_all token_name trigger_error + unregister_tick_function use_soap_error_handler user_error + utf8_decode utf8_encode var_dump var_export + version_compare + zend_logo_guid zend_thread_id zend_version + create_function call_user_func_array + posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid + posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups + posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid + posix_getpwnam posix_getpwuid posix_getrlimit posix_getsid posix_getuid + posix_initgroups posix_isatty posix_kill posix_mkfifo posix_mknod + posix_setegid posix_seteuid posix_setgid posix_setpgid posix_setsid + posix_setuid posix_strerror posix_times posix_ttyname posix_uname + pcntl_alarm pcntl_exec pcntl_fork pcntl_getpriority pcntl_setpriority + pcntl_signal pcntl_signal_dispatch pcntl_sigprocmask pcntl_sigtimedwait + pcntl_sigwaitinfo pcntl_wait pcntl_waitpid pcntl_wexitstatus pcntl_wifexited + pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig + ] + # TODO: more built-in PHP functions? + + EXCEPTIONS = %w[ + E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING + E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT + ] + + CONSTANTS = %w[ + null true false self parent + __LINE__ __DIR__ __FILE__ __LINE__ + __CLASS__ __NAMESPACE__ __METHOD__ __FUNCTION__ + PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION PHP_ZTS + PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_SIZE DEFAULT_INCLUDE_PATH + PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_LIBDIR PHP_DATADIR + PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX + PHP_OUTPUT_HANDLER_START PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END + __COMPILER_HALT_OFFSET__ + EXTR_OVERWRITE EXTR_SKIP EXTR_PREFIX_SAME EXTR_PREFIX_ALL EXTR_PREFIX_INVALID EXTR_PREFIX_IF_EXISTS + EXTR_IF_EXISTS SORT_ASC SORT_DESC SORT_REGULAR SORT_NUMERIC SORT_STRING CASE_LOWER CASE_UPPER COUNT_NORMAL + COUNT_RECURSIVE ASSERT_ACTIVE ASSERT_CALLBACK ASSERT_BAIL ASSERT_WARNING ASSERT_QUIET_EVAL CONNECTION_ABORTED + CONNECTION_NORMAL CONNECTION_TIMEOUT INI_USER INI_PERDIR INI_SYSTEM INI_ALL M_E M_LOG2E M_LOG10E M_LN2 M_LN10 + M_PI M_PI_2 M_PI_4 M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2 CRYPT_SALT_LENGTH CRYPT_STD_DES CRYPT_EXT_DES + CRYPT_MD5 CRYPT_BLOWFISH DIRECTORY_SEPARATOR SEEK_SET SEEK_CUR SEEK_END LOCK_SH LOCK_EX LOCK_UN LOCK_NB + HTML_SPECIALCHARS HTML_ENTITIES ENT_COMPAT ENT_QUOTES ENT_NOQUOTES INFO_GENERAL INFO_CREDITS + INFO_CONFIGURATION INFO_MODULES INFO_ENVIRONMENT INFO_VARIABLES INFO_LICENSE INFO_ALL CREDITS_GROUP + CREDITS_GENERAL CREDITS_SAPI CREDITS_MODULES CREDITS_DOCS CREDITS_FULLPAGE CREDITS_QA CREDITS_ALL STR_PAD_LEFT + STR_PAD_RIGHT STR_PAD_BOTH PATHINFO_DIRNAME PATHINFO_BASENAME PATHINFO_EXTENSION PATH_SEPARATOR CHAR_MAX + LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_ALL LC_MESSAGES ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 + ABDAY_6 ABDAY_7 DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 ABMON_1 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 + ABMON_7 ABMON_8 ABMON_9 ABMON_10 ABMON_11 ABMON_12 MON_1 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 + MON_10 MON_11 MON_12 AM_STR PM_STR D_T_FMT D_FMT T_FMT T_FMT_AMPM ERA ERA_YEAR ERA_D_T_FMT ERA_D_FMT ERA_T_FMT + ALT_DIGITS INT_CURR_SYMBOL CURRENCY_SYMBOL CRNCYSTR MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING + POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES + N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN DECIMAL_POINT RADIXCHAR THOUSANDS_SEP THOUSEP GROUPING YESEXPR NOEXPR + YESSTR NOSTR CODESET LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG LOG_KERN + LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_LOCAL0 + LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_PID LOG_CONS LOG_ODELAY + LOG_NDELAY LOG_NOWAIT LOG_PERROR + ] + + PREDEFINED = %w[ + $GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV + $_COOKIE $php_errormsg $HTTP_RAW_POST_DATA $http_response_header + $argc $argv + ] + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(TYPES, :predefined_type). + add(LANGUAGE_CONSTRUCTS, :keyword). + add(BUILTIN_FUNCTIONS, :predefined). + add(CLASSES, :predefined_constant). + add(EXCEPTIONS, :exception). + add(CONSTANTS, :predefined_constant) + + VARIABLE_KIND = WordList.new(:local_variable). + add(PREDEFINED, :predefined) + end + + module RE # :nodoc: + + PHP_START = / + ]*?language\s*=\s*"php"[^>]*?> | + ]*?language\s*=\s*'php'[^>]*?> | + <\?php\d? | + <\?(?!xml) + /xi + + PHP_END = %r! + | + \?> + !xi + + HTML_INDICATOR = / ]/i + + IDENTIFIER = /[a-z_\x7f-\xFF][a-z0-9_\x7f-\xFF]*/i + VARIABLE = /\$#{IDENTIFIER}/ + + OPERATOR = / + \.(?!\d)=? | # dot that is not decimal point, string concatenation + && | \|\| | # logic + :: | -> | => | # scope, member, dictionary + \\(?!\n) | # namespace + \+\+ | -- | # increment, decrement + [,;?:()\[\]{}] | # simple delimiters + [-+*\/%&|^]=? | # ordinary math, binary logic, assignment shortcuts + [~$] | # whatever + =& | # reference assignment + [=!]=?=? | <> | # comparison and assignment + <<=? | >>=? | [<>]=? # comparison and shift + /x + + end + + protected + + def scan_tokens encoder, options + + if check(RE::PHP_START) || # starts with #{RE::IDENTIFIER}/o) + encoder.begin_group :inline + encoder.text_token match, :local_variable + encoder.text_token scan(/->/), :operator + encoder.text_token scan(/#{RE::IDENTIFIER}/o), :ident + encoder.end_group :inline + elsif check(/->/) + match << scan(/->/) + encoder.text_token match, :error + else + encoder.text_token match, :local_variable + end + elsif match = scan(/\{/) + if check(/\$/) + encoder.begin_group :inline + states[-1] = [states.last, delimiter] + delimiter = nil + states.push :php + encoder.text_token match, :delimiter + else + encoder.text_token match, :content + end + elsif match = scan(/\$\{#{RE::IDENTIFIER}\}/o) + encoder.text_token match, :local_variable + elsif match = scan(/\$/) + encoder.text_token match, :content + else + states.pop + end + + when :class_expected + if match = scan(/\s+/) + encoder.text_token match, :space + elsif match = scan(/#{RE::IDENTIFIER}/o) + encoder.text_token match, :class + states.pop + else + states.pop + end + + when :function_expected + if match = scan(/\s+/) + encoder.text_token match, :space + elsif match = scan(/&/) + encoder.text_token match, :operator + elsif match = scan(/#{RE::IDENTIFIER}/o) + encoder.text_token match, :function + states.pop + else + states.pop + end + + else + raise_inspect 'Unknown state!', encoder, states + end + + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/python.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/python.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,287 @@ +module CodeRay +module Scanners + + # Scanner for Python. Supports Python 3. + # + # Based on pygments' PythonLexer, see + # http://dev.pocoo.org/projects/pygments/browser/pygments/lexers/agile.py. + class Python < Scanner + + register_for :python + file_extension 'py' + + KEYWORDS = [ + 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', + 'del', 'elif', 'else', 'except', 'finally', 'for', + 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', + 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', + 'nonlocal', # new in Python 3 + ] # :nodoc: + + OLD_KEYWORDS = [ + 'exec', 'print', # gone in Python 3 + ] # :nodoc: + + PREDEFINED_METHODS_AND_TYPES = %w[ + __import__ abs all any apply basestring bin bool buffer + bytearray bytes callable chr classmethod cmp coerce compile + complex delattr dict dir divmod enumerate eval execfile exit + file filter float frozenset getattr globals hasattr hash hex id + input int intern isinstance issubclass iter len list locals + long map max min next object oct open ord pow property range + raw_input reduce reload repr reversed round set setattr slice + sorted staticmethod str sum super tuple type unichr unicode + vars xrange zip + ] # :nodoc: + + PREDEFINED_EXCEPTIONS = %w[ + ArithmeticError AssertionError AttributeError + BaseException DeprecationWarning EOFError EnvironmentError + Exception FloatingPointError FutureWarning GeneratorExit IOError + ImportError ImportWarning IndentationError IndexError KeyError + KeyboardInterrupt LookupError MemoryError NameError + NotImplemented NotImplementedError OSError OverflowError + OverflowWarning PendingDeprecationWarning ReferenceError + RuntimeError RuntimeWarning StandardError StopIteration + SyntaxError SyntaxWarning SystemError SystemExit TabError + TypeError UnboundLocalError UnicodeDecodeError + UnicodeEncodeError UnicodeError UnicodeTranslateError + UnicodeWarning UserWarning ValueError Warning ZeroDivisionError + ] # :nodoc: + + PREDEFINED_VARIABLES_AND_CONSTANTS = [ + 'False', 'True', 'None', # "keywords" since Python 3 + 'self', 'Ellipsis', 'NotImplemented', + ] # :nodoc: + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(OLD_KEYWORDS, :old_keyword). + add(PREDEFINED_METHODS_AND_TYPES, :predefined). + add(PREDEFINED_VARIABLES_AND_CONSTANTS, :predefined_constant). + add(PREDEFINED_EXCEPTIONS, :exception) # :nodoc: + + NAME = / [^\W\d] \w* /x # :nodoc: + ESCAPE = / [abfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} | N\{[-\w ]+\} /x # :nodoc: + + OPERATOR = / + \.\.\. | # ellipsis + \.(?!\d) | # dot but not decimal point + [,;:()\[\]{}] | # simple delimiters + \/\/=? | \*\*=? | # special math + [-+*\/%&|^]=? | # ordinary math and binary logic + [~`] | # binary complement and inspection + <<=? | >>=? | [<>=]=? | != # comparison and assignment + /x # :nodoc: + + STRING_DELIMITER_REGEXP = Hash.new { |h, delimiter| + h[delimiter] = Regexp.union delimiter # :nodoc: + } + + STRING_CONTENT_REGEXP = Hash.new { |h, delimiter| + h[delimiter] = / [^\\\n]+? (?= \\ | $ | #{Regexp.escape(delimiter)} ) /x # :nodoc: + } + + DEF_NEW_STATE = WordList.new(:initial). + add(%w(def), :def_expected). + add(%w(import from), :include_expected). + add(%w(class), :class_expected) # :nodoc: + + DESCRIPTOR = / + #{NAME} + (?: \. #{NAME} )* + | \* + /x # :nodoc: + + DOCSTRING_COMING = / + [ \t]* u?r? ("""|''') + /x # :nodoc: + + protected + + def scan_tokens encoder, options + + state = :initial + string_delimiter = nil + string_raw = false + string_type = nil + docstring_coming = match?(/#{DOCSTRING_COMING}/o) + last_token_dot = false + unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' + from_import_state = [] + + until eos? + + if state == :string + if match = scan(STRING_DELIMITER_REGEXP[string_delimiter]) + encoder.text_token match, :delimiter + encoder.end_group string_type + string_type = nil + state = :initial + next + elsif string_delimiter.size == 3 && match = scan(/\n/) + encoder.text_token match, :content + elsif match = scan(STRING_CONTENT_REGEXP[string_delimiter]) + encoder.text_token match, :content + elsif !string_raw && match = scan(/ \\ #{ESCAPE} /ox) + encoder.text_token match, :char + elsif match = scan(/ \\ #{UNICODE_ESCAPE} /ox) + encoder.text_token match, :char + elsif match = scan(/ \\ . /x) + encoder.text_token match, :content + elsif match = scan(/ \\ | $ /x) + encoder.end_group string_type + string_type = nil + encoder.text_token match, :error + state = :initial + else + raise_inspect "else case \" reached; %p not handled." % peek(1), encoder, state + end + + elsif match = scan(/ [ \t]+ | \\?\n /x) + encoder.text_token match, :space + if match == "\n" + state = :initial if state == :include_expected + docstring_coming = true if match?(/#{DOCSTRING_COMING}/o) + end + next + + elsif match = scan(/ \# [^\n]* /mx) + encoder.text_token match, :comment + next + + elsif state == :initial + + if match = scan(/#{OPERATOR}/o) + encoder.text_token match, :operator + + elsif match = scan(/(u?r?|b)?("""|"|'''|')/i) + string_delimiter = self[2] + string_type = docstring_coming ? :docstring : :string + docstring_coming = false if docstring_coming + encoder.begin_group string_type + string_raw = false + modifiers = self[1] + unless modifiers.empty? + string_raw = !!modifiers.index(?r) + encoder.text_token modifiers, :modifier + match = string_delimiter + end + state = :string + encoder.text_token match, :delimiter + + # TODO: backticks + + elsif match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + kind = IDENT_KIND[match] + # TODO: keyword arguments + kind = :ident if last_token_dot + if kind == :old_keyword + kind = check(/\(/) ? :ident : :keyword + elsif kind == :predefined && check(/ *=/) + kind = :ident + elsif kind == :keyword + state = DEF_NEW_STATE[match] + from_import_state << match.to_sym if state == :include_expected + end + encoder.text_token match, kind + + elsif match = scan(/@[a-zA-Z0-9_.]+[lL]?/) + encoder.text_token match, :decorator + + elsif match = scan(/0[xX][0-9A-Fa-f]+[lL]?/) + encoder.text_token match, :hex + + elsif match = scan(/0[bB][01]+[lL]?/) + encoder.text_token match, :binary + + elsif match = scan(/(?:\d*\.\d+|\d+\.\d*)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) + if scan(/[jJ]/) + match << matched + encoder.text_token match, :imaginary + else + encoder.text_token match, :float + end + + elsif match = scan(/0[oO][0-7]+|0[0-7]+(?![89.eE])[lL]?/) + encoder.text_token match, :octal + + elsif match = scan(/\d+([lL])?/) + if self[1] == nil && scan(/[jJ]/) + match << matched + encoder.text_token match, :imaginary + else + encoder.text_token match, :integer + end + + else + encoder.text_token getch, :error + + end + + elsif state == :def_expected + state = :initial + if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + encoder.text_token match, :method + else + next + end + + elsif state == :class_expected + state = :initial + if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) + encoder.text_token match, :class + else + next + end + + elsif state == :include_expected + if match = scan(unicode ? /#{DESCRIPTOR}/uo : /#{DESCRIPTOR}/o) + if match == 'as' + encoder.text_token match, :keyword + from_import_state << :as + elsif from_import_state.first == :from && match == 'import' + encoder.text_token match, :keyword + from_import_state << :import + elsif from_import_state.last == :as + # encoder.text_token match, match[0,1][unicode ? /[[:upper:]]/u : /[[:upper:]]/] ? :class : :method + encoder.text_token match, :ident + from_import_state.pop + elsif IDENT_KIND[match] == :keyword + unscan + match = nil + state = :initial + next + else + encoder.text_token match, :include + end + elsif match = scan(/,/) + from_import_state.pop if from_import_state.last == :as + encoder.text_token match, :operator + else + from_import_state = [] + state = :initial + next + end + + else + raise_inspect 'Unknown state', encoder, state + + end + + last_token_dot = match == '.' + + end + + if state == :string + encoder.end_group string_type + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/raydebug.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/raydebug.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,66 @@ +module CodeRay +module Scanners + + # = Debug Scanner + # + # Parses the output of the Encoders::Debug encoder. + class Raydebug < Scanner + + register_for :raydebug + file_extension 'raydebug' + title 'CodeRay Token Dump' + + protected + + def scan_tokens encoder, options + + opened_tokens = [] + + until eos? + + if match = scan(/\s+/) + encoder.text_token match, :space + + elsif match = scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) /x) + kind = self[1] + encoder.text_token kind, :class + encoder.text_token '(', :operator + match = self[2] + encoder.text_token match, kind.to_sym + encoder.text_token match, :operator if match = scan(/\)/) + + elsif match = scan(/ (\w+) ([<\[]) /x) + kind = self[1] + case self[2] + when '<' + encoder.text_token kind, :class + when '[' + encoder.text_token kind, :class + else + raise 'CodeRay bug: This case should not be reached.' + end + kind = kind.to_sym + opened_tokens << kind + encoder.begin_group kind + encoder.text_token self[2], :operator + + elsif !opened_tokens.empty? && match = scan(/ [>\]] /x) + encoder.text_token match, :operator + encoder.end_group opened_tokens.pop + + else + encoder.text_token getch, :space + + end + + end + + encoder.end_group opened_tokens.pop until opened_tokens.empty? + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/ruby.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/ruby.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,461 @@ +module CodeRay +module Scanners + + # This scanner is really complex, since Ruby _is_ a complex language! + # + # It tries to highlight 100% of all common code, + # and 90% of strange codes. + # + # It is optimized for HTML highlighting, and is not very useful for + # parsing or pretty printing. + class Ruby < Scanner + + register_for :ruby + file_extension 'rb' + + autoload :Patterns, 'coderay/scanners/ruby/patterns' + autoload :StringState, 'coderay/scanners/ruby/string_state' + + def interpreted_string_state + StringState.new :string, true, '"' + end + + protected + + def setup + @state = :initial + end + + def scan_tokens encoder, options + state, heredocs = options[:state] || @state + heredocs = heredocs.dup if heredocs.is_a?(Array) + + if state && state.instance_of?(StringState) + encoder.begin_group state.type + end + + last_state = nil + + method_call_expected = false + value_expected = true + + inline_block_stack = nil + inline_block_curly_depth = 0 + + if heredocs + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + end + + # def_object_stack = nil + # def_object_paren_depth = 0 + + patterns = Patterns # avoid constant lookup + + unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' + + until eos? + + if state.instance_of? ::Symbol + + if match = scan(/[ \t\f\v]+/) + encoder.text_token match, :space + + elsif match = scan(/\n/) + if heredocs + unscan # heredoc scanning needs \n at start + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + else + state = :initial if state == :undef_comma_expected + encoder.text_token match, :space + value_expected = true + end + + elsif match = scan(bol? ? / \#(!)?.* | #{patterns::RUBYDOC_OR_DATA} /ox : /\#.*/) + encoder.text_token match, self[1] ? :doctype : :comment + + elsif match = scan(/\\\n/) + if heredocs + unscan # heredoc scanning needs \n at start + encoder.text_token scan(/\\/), :space + state = heredocs.shift + encoder.begin_group state.type + heredocs = nil if heredocs.empty? + else + encoder.text_token match, :space + end + + elsif state == :initial + + # IDENTS # + if !method_call_expected && + match = scan(unicode ? /#{patterns::METHOD_NAME}/uo : + /#{patterns::METHOD_NAME}/o) + value_expected = false + kind = patterns::IDENT_KIND[match] + if kind == :ident + if match[/\A[A-Z]/] && !(match[/[!?]$/] || match?(/\(/)) + kind = :constant + end + elsif kind == :keyword + state = patterns::KEYWORD_NEW_STATE[match] + value_expected = true if patterns::KEYWORDS_EXPECTING_VALUE[match] + end + value_expected = true if !value_expected && check(/#{patterns::VALUE_FOLLOWS}/o) + encoder.text_token match, kind + + elsif method_call_expected && + match = scan(unicode ? /#{patterns::METHOD_AFTER_DOT}/uo : + /#{patterns::METHOD_AFTER_DOT}/o) + if method_call_expected == '::' && match[/\A[A-Z]/] && !match?(/\(/) + encoder.text_token match, :constant + else + encoder.text_token match, :ident + end + method_call_expected = false + value_expected = check(/#{patterns::VALUE_FOLLOWS}/o) + + # OPERATORS # + elsif !method_call_expected && match = scan(/ (\.(?!\.)|::) | (?: \.\.\.? | ==?=? | [,\(\[\{] )() | [\)\]\}] /x) + method_call_expected = self[1] + value_expected = !method_call_expected && self[2] + if inline_block_stack + case match + when '{' + inline_block_curly_depth += 1 + when '}' + inline_block_curly_depth -= 1 + if inline_block_curly_depth == 0 # closing brace of inline block reached + state, inline_block_curly_depth, heredocs = inline_block_stack.pop + inline_block_stack = nil if inline_block_stack.empty? + heredocs = nil if heredocs && heredocs.empty? + encoder.text_token match, :inline_delimiter + encoder.end_group :inline + next + end + end + end + encoder.text_token match, :operator + + elsif match = scan(unicode ? /#{patterns::SYMBOL}/uo : + /#{patterns::SYMBOL}/o) + case delim = match[1] + when ?', ?" + encoder.begin_group :symbol + encoder.text_token ':', :symbol + match = delim.chr + encoder.text_token match, :delimiter + state = self.class::StringState.new :symbol, delim == ?", match + else + encoder.text_token match, :symbol + value_expected = false + end + + elsif match = scan(/ ' (?:(?>[^'\\]*) ')? | " (?:(?>[^"\\\#]*) ")? /mx) + encoder.begin_group :string + if match.size == 1 + encoder.text_token match, :delimiter + state = self.class::StringState.new :string, match == '"', match # important for streaming + else + encoder.text_token match[0,1], :delimiter + encoder.text_token match[1..-2], :content if match.size > 2 + encoder.text_token match[-1,1], :delimiter + encoder.end_group :string + value_expected = false + end + + elsif match = scan(unicode ? /#{patterns::INSTANCE_VARIABLE}/uo : + /#{patterns::INSTANCE_VARIABLE}/o) + value_expected = false + encoder.text_token match, :instance_variable + + elsif value_expected && match = scan(/\//) + encoder.begin_group :regexp + encoder.text_token match, :delimiter + state = self.class::StringState.new :regexp, true, '/' + + elsif match = scan(value_expected ? /[-+]?#{patterns::NUMERIC}/o : /#{patterns::NUMERIC}/o) + if method_call_expected + encoder.text_token match, :error + method_call_expected = false + else + encoder.text_token match, self[1] ? :float : :integer # TODO: send :hex/:octal/:binary + end + value_expected = false + + elsif match = scan(/ [-+!~^\/]=? | [:;] | [*|&]{1,2}=? | >>? /x) + value_expected = true + encoder.text_token match, :operator + + elsif value_expected && match = scan(/#{patterns::HEREDOC_OPEN}/o) + quote = self[3] + delim = self[quote ? 4 : 2] + kind = patterns::QUOTE_TO_TYPE[quote] + encoder.begin_group kind + encoder.text_token match, :delimiter + encoder.end_group kind + heredocs ||= [] # create heredocs if empty + heredocs << self.class::StringState.new(kind, quote != "'", delim, + self[1] == '-' ? :indented : :linestart) + value_expected = false + + elsif value_expected && match = scan(/#{patterns::FANCY_STRING_START}/o) + kind = patterns::FANCY_STRING_KIND[self[1]] + encoder.begin_group kind + state = self.class::StringState.new kind, patterns::FANCY_STRING_INTERPRETED[self[1]], self[2] + encoder.text_token match, :delimiter + + elsif value_expected && match = scan(/#{patterns::CHARACTER}/o) + value_expected = false + encoder.text_token match, :integer + + elsif match = scan(/ %=? | <(?:<|=>?)? | \? /x) + value_expected = true + encoder.text_token match, :operator + + elsif match = scan(/`/) + encoder.begin_group :shell + encoder.text_token match, :delimiter + state = self.class::StringState.new :shell, true, match + + elsif match = scan(unicode ? /#{patterns::GLOBAL_VARIABLE}/uo : + /#{patterns::GLOBAL_VARIABLE}/o) + encoder.text_token match, :global_variable + value_expected = false + + elsif match = scan(unicode ? /#{patterns::CLASS_VARIABLE}/uo : + /#{patterns::CLASS_VARIABLE}/o) + encoder.text_token match, :class_variable + value_expected = false + + elsif match = scan(/\\\z/) + encoder.text_token match, :space + + else + if method_call_expected + method_call_expected = false + next + end + unless unicode + # check for unicode + $DEBUG_BEFORE, $DEBUG = $DEBUG, false + begin + if check(/./mu).size > 1 + # seems like we should try again with unicode + unicode = true + end + rescue + # bad unicode char; use getch + ensure + $DEBUG = $DEBUG_BEFORE + end + next if unicode + end + + encoder.text_token getch, :error + + end + + if last_state + state = last_state + last_state = nil + end + + elsif state == :def_expected + if match = scan(unicode ? /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : + /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) + encoder.text_token match, :method + state = :initial + else + last_state = :dot_expected + state = :initial + end + + elsif state == :dot_expected + if match = scan(/\.|::/) + # invalid definition + state = :def_expected + encoder.text_token match, :operator + else + state = :initial + end + + elsif state == :module_expected + if match = scan(/<#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : + /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) + encoder.text_token match, :method + elsif match = scan(/#{patterns::SYMBOL}/o) + case delim = match[1] + when ?', ?" + encoder.begin_group :symbol + encoder.text_token ':', :symbol + match = delim.chr + encoder.text_token match, :delimiter + state = self.class::StringState.new :symbol, delim == ?", match + state.next_state = :undef_comma_expected + else + encoder.text_token match, :symbol + end + else + state = :initial + end + + elsif state == :undef_comma_expected + if match = scan(/,/) + encoder.text_token match, :operator + state = :undef_expected + else + state = :initial + end + + elsif state == :alias_expected + match = scan(unicode ? /(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/uo : + /(#{patterns::METHOD_NAME_OR_SYMBOL})([ \t]+)(#{patterns::METHOD_NAME_OR_SYMBOL})/o) + + if match + encoder.text_token self[1], (self[1][0] == ?: ? :symbol : :method) + encoder.text_token self[2], :space + encoder.text_token self[3], (self[3][0] == ?: ? :symbol : :method) + end + state = :initial + + else + #:nocov: + raise_inspect 'Unknown state: %p' % [state], encoder + #:nocov: + end + + else # StringState + + match = scan_until(state.pattern) || scan_rest + unless match.empty? + encoder.text_token match, :content + break if eos? + end + + if state.heredoc && self[1] # end of heredoc + match = getch + match << scan_until(/$/) unless eos? + encoder.text_token match, :delimiter unless match.empty? + encoder.end_group state.type + state = state.next_state + next + end + + case match = getch + + when state.delim + if state.paren_depth + state.paren_depth -= 1 + if state.paren_depth > 0 + encoder.text_token match, :content + next + end + end + encoder.text_token match, :delimiter + if state.type == :regexp && !eos? + match = scan(/#{patterns::REGEXP_MODIFIERS}/o) + encoder.text_token match, :modifier unless match.empty? + end + encoder.end_group state.type + value_expected = false + state = state.next_state + + when '\\' + if state.interpreted + if esc = scan(/#{patterns::ESCAPE}/o) + encoder.text_token match + esc, :char + else + encoder.text_token match, :error + end + else + case esc = getch + when nil + encoder.text_token match, :content + when state.delim, '\\' + encoder.text_token match + esc, :char + else + encoder.text_token match + esc, :content + end + end + + when '#' + case peek(1) + when '{' + inline_block_stack ||= [] + inline_block_stack << [state, inline_block_curly_depth, heredocs] + value_expected = true + state = :initial + inline_block_curly_depth = 1 + encoder.begin_group :inline + encoder.text_token match + getch, :inline_delimiter + when '$', '@' + encoder.text_token match, :escape + last_state = state + state = :initial + else + #:nocov: + raise_inspect 'else-case # reached; #%p not handled' % [peek(1)], encoder + #:nocov: + end + + when state.opening_paren + state.paren_depth += 1 + encoder.text_token match, :content + + else + #:nocov + raise_inspect 'else-case " reached; %p not handled, state = %p' % [match, state], encoder + #:nocov: + + end + + end + + end + + # cleaning up + if state.is_a? StringState + encoder.end_group state.type + end + + if options[:keep_state] + if state.is_a?(StringState) && state.heredoc + (heredocs ||= []).unshift state + state = :initial + elsif heredocs && heredocs.empty? + heredocs = nil + end + @state = state, heredocs + end + + if inline_block_stack + until inline_block_stack.empty? + state, = *inline_block_stack.pop + encoder.end_group :inline + encoder.end_group state.type + end + end + + encoder + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/ruby/patterns.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/ruby/patterns.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,175 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + module Ruby::Patterns # :nodoc: all + + KEYWORDS = %w[ + and def end in or unless begin + defined? ensure module redo super until + BEGIN break do next rescue then + when END case else for retry + while alias class elsif if not return + undef yield + ] + + # See http://murfy.de/ruby-constants. + PREDEFINED_CONSTANTS = %w[ + nil true false self + DATA ARGV ARGF ENV + FALSE TRUE NIL + STDERR STDIN STDOUT + TOPLEVEL_BINDING + RUBY_COPYRIGHT RUBY_DESCRIPTION RUBY_ENGINE RUBY_PATCHLEVEL + RUBY_PLATFORM RUBY_RELEASE_DATE RUBY_REVISION RUBY_VERSION + __FILE__ __LINE__ __ENCODING__ + ] + + IDENT_KIND = WordList.new(:ident). + add(KEYWORDS, :keyword). + add(PREDEFINED_CONSTANTS, :predefined_constant) + + KEYWORD_NEW_STATE = WordList.new(:initial). + add(%w[ def ], :def_expected). + add(%w[ undef ], :undef_expected). + add(%w[ alias ], :alias_expected). + add(%w[ class module ], :module_expected) + + IDENT = 'ä'[/[[:alpha:]]/] == 'ä' ? /[[:alpha:]_][[:alnum:]_]*/ : /[^\W\d]\w*/ + + METHOD_NAME = / #{IDENT} [?!]? /ox + METHOD_NAME_OPERATOR = / + \*\*? # multiplication and power + | [-+~]@? # plus, minus, tilde with and without at sign + | [\/%&|^`] # division, modulo or format strings, and, or, xor, system + | \[\]=? # array getter and setter + | << | >> # append or shift left, shift right + | <=?>? | >=? # comparison, rocket operator + | ===? | =~ # simple equality, case equality, match + | ![~=@]? # negation with and without at sign, not-equal and not-match + /ox + METHOD_SUFFIX = / (?: [?!] | = (?![~>]|=(?!>)) ) /x + METHOD_NAME_EX = / #{IDENT} #{METHOD_SUFFIX}? | #{METHOD_NAME_OPERATOR} /ox + METHOD_AFTER_DOT = / #{IDENT} [?!]? | #{METHOD_NAME_OPERATOR} /ox + INSTANCE_VARIABLE = / @ #{IDENT} /ox + CLASS_VARIABLE = / @@ #{IDENT} /ox + OBJECT_VARIABLE = / @@? #{IDENT} /ox + GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox + PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox + VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox + + QUOTE_TO_TYPE = { + '`' => :shell, + '/'=> :regexp, + } + QUOTE_TO_TYPE.default = :string + + REGEXP_MODIFIERS = /[mousenix]*/ + + DECIMAL = /\d+(?:_\d+)*/ + OCTAL = /0_?[0-7]+(?:_[0-7]+)*/ + HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/ + BINARY = /0b[01]+(?:_[01]+)*/ + + EXPONENT = / [eE] [+-]? #{DECIMAL} /ox + FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox + FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox + NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox + + SYMBOL = / + : + (?: + #{METHOD_NAME_EX} + | #{PREFIX_VARIABLE} + | ['"] + ) + /ox + METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox + + SIMPLE_ESCAPE = / + [abefnrstv] + | [0-7]{1,3} + | x[0-9A-Fa-f]{1,2} + | . + /mx + + CONTROL_META_ESCAPE = / + (?: M-|C-|c ) + (?: \\ (?: M-|C-|c ) )* + (?: [^\\] | \\ #{SIMPLE_ESCAPE} )? + /mox + + ESCAPE = / + #{CONTROL_META_ESCAPE} | #{SIMPLE_ESCAPE} + /mox + + CHARACTER = / + \? + (?: + [^\s\\] + | \\ #{ESCAPE} + ) + /mox + + # NOTE: This is not completely correct, but + # nobody needs heredoc delimiters ending with \n. + HEREDOC_OPEN = / + << (-)? # $1 = float + (?: + ( [A-Za-z_0-9]+ ) # $2 = delim + | + ( ["'`\/] ) # $3 = quote, type + ( [^\n]*? ) \3 # $4 = delim + ) + /mx + + RUBYDOC = / + =begin (?!\S) + .*? + (?: \Z | ^=end (?!\S) [^\n]* ) + /mx + + DATA = / + __END__$ + .*? + (?: \Z | (?=^\#CODE) ) + /mx + + RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo + + # Checks for a valid value to follow. This enables + # value_expected in method calls without parentheses. + VALUE_FOLLOWS = / + (?>[ \t\f\v]+) + (?: + [%\/][^\s=] + | <<-?\S + | [-+] \d + | #{CHARACTER} + ) + /ox + KEYWORDS_EXPECTING_VALUE = WordList.new.add(%w[ + and end in or unless begin + defined? ensure redo super until + break do next rescue then + when case else for retry + while elsif if not return + yield + ]) + + FANCY_STRING_START = / % ( [QqrsWwx] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /x + FANCY_STRING_KIND = Hash.new(:string).merge({ + 'r' => :regexp, + 's' => :symbol, + 'x' => :shell, + }) + FANCY_STRING_INTERPRETED = Hash.new(true).merge({ + 'q' => false, + 's' => false, + 'w' => false, + }) + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/ruby/string_state.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/ruby/string_state.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,71 @@ +# encoding: utf-8 +module CodeRay +module Scanners + + class Ruby + + class StringState < Struct.new :type, :interpreted, :delim, :heredoc, + :opening_paren, :paren_depth, :pattern, :next_state # :nodoc: all + + CLOSING_PAREN = Hash[ *%w[ + ( ) + [ ] + < > + { } + ] ].each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with << + + STRING_PATTERN = Hash.new do |h, k| + delim, interpreted = *k + # delim = delim.dup # workaround for old Ruby + delim_pattern = Regexp.escape(delim) + if closing_paren = CLOSING_PAREN[delim] + delim_pattern << Regexp.escape(closing_paren) + end + delim_pattern << '\\\\' unless delim == '\\' + + # special_escapes = + # case interpreted + # when :regexp_symbols + # '| [|?*+(){}\[\].^$]' + # end + + h[k] = + if interpreted && delim != '#' + / (?= [#{delim_pattern}] | \# [{$@] ) /mx + else + / (?= [#{delim_pattern}] ) /mx + end + end + + def initialize kind, interpreted, delim, heredoc = false + if heredoc + pattern = heredoc_pattern delim, interpreted, heredoc == :indented + delim = nil + else + pattern = STRING_PATTERN[ [delim, interpreted] ] + if closing_paren = CLOSING_PAREN[delim] + opening_paren = delim + delim = closing_paren + paren_depth = 1 + end + end + super kind, interpreted, delim, heredoc, opening_paren, paren_depth, pattern, :initial + end + + def heredoc_pattern delim, interpreted, indented + # delim = delim.dup # workaround for old Ruby + delim_pattern = Regexp.escape(delim) + delim_pattern = / (?:\A|\n) #{ '(?>[ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x + if interpreted + / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc + else + / (?= #{delim_pattern}() | \\ ) /mx + end + end + + end + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/sql.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/sql.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,174 @@ +module CodeRay module Scanners + + # by Josh Goebel + class SQL < Scanner + + register_for :sql + + KEYWORDS = %w( + all and any as before begin between by case check collate + each else end exists + for foreign from full group having if in inner is join + like not of on or order outer over references + then to union using values when where + left right distinct + ) + + OBJECTS = %w( + database databases table tables column columns fields index constraint + constraints transaction function procedure row key view trigger + ) + + COMMANDS = %w( + add alter comment create delete drop grant insert into select update set + show prompt begin commit rollback replace truncate + ) + + PREDEFINED_TYPES = %w( + char varchar varchar2 enum binary text tinytext mediumtext + longtext blob tinyblob mediumblob longblob timestamp + date time datetime year double decimal float int + integer tinyint mediumint bigint smallint unsigned bit + bool boolean hex bin oct + ) + + PREDEFINED_FUNCTIONS = %w( sum cast substring abs pi count min max avg now ) + + DIRECTIVES = %w( + auto_increment unique default charset initially deferred + deferrable cascade immediate read write asc desc after + primary foreign return engine + ) + + PREDEFINED_CONSTANTS = %w( null true false ) + + IDENT_KIND = WordList::CaseIgnoring.new(:ident). + add(KEYWORDS, :keyword). + add(OBJECTS, :type). + add(COMMANDS, :class). + add(PREDEFINED_TYPES, :predefined_type). + add(PREDEFINED_CONSTANTS, :predefined_constant). + add(PREDEFINED_FUNCTIONS, :predefined). + add(DIRECTIVES, :directive) + + ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x + + STRING_PREFIXES = /[xnb]|_\w+/i + + def scan_tokens encoder, options + + state = :initial + string_type = nil + string_content = '' + name_expected = false + + until eos? + + if state == :initial + + if match = scan(/ \s+ | \\\n /x) + encoder.text_token match, :space + + elsif match = scan(/(?:--\s?|#).*/) + encoder.text_token match, :comment + + elsif match = scan(%r( /\* (!)? (?: .*? \*/ | .* ) )mx) + encoder.text_token match, self[1] ? :directive : :comment + + elsif match = scan(/ [*\/=<>:;,!&^|()\[\]{}~%] | [-+\.](?!\d) /x) + name_expected = true if match == '.' && check(/[A-Za-z_]/) + encoder.text_token match, :operator + + elsif match = scan(/(#{STRING_PREFIXES})?([`"'])/o) + prefix = self[1] + string_type = self[2] + encoder.begin_group :string + encoder.text_token prefix, :modifier if prefix + match = string_type + state = :string + encoder.text_token match, :delimiter + + elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x) + encoder.text_token match, name_expected ? :ident : (match[0] == ?@ ? :variable : IDENT_KIND[match]) + name_expected = false + + elsif match = scan(/0[xX][0-9A-Fa-f]+/) + encoder.text_token match, :hex + + elsif match = scan(/0[0-7]+(?![89.eEfF])/) + encoder.text_token match, :octal + + elsif match = scan(/[-+]?(?>\d+)(?![.eEfF])/) + encoder.text_token match, :integer + + elsif match = scan(/[-+]?(?:\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+)/) + encoder.text_token match, :float + + elsif match = scan(/\\N/) + encoder.text_token match, :predefined_constant + + else + encoder.text_token getch, :error + + end + + elsif state == :string + if match = scan(/[^\\"'`]+/) + string_content << match + next + elsif match = scan(/["'`]/) + if string_type == match + if peek(1) == string_type # doubling means escape + string_content << string_type << getch + next + end + unless string_content.empty? + encoder.text_token string_content, :content + string_content = '' + end + encoder.text_token match, :delimiter + encoder.end_group :string + state = :initial + string_type = nil + else + string_content << match + end + elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + unless string_content.empty? + encoder.text_token string_content, :content + string_content = '' + end + encoder.text_token match, :char + elsif match = scan(/ \\ . /mox) + string_content << match + next + elsif match = scan(/ \\ | $ /x) + unless string_content.empty? + encoder.text_token string_content, :content + string_content = '' + end + encoder.text_token match, :error + state = :initial + else + raise "else case \" reached; %p not handled." % peek(1), encoder + end + + else + raise 'else-case reached', encoder + + end + + end + + if state == :string + encoder.end_group state + end + + encoder + + end + + end + +end end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/text.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/text.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,26 @@ +module CodeRay + module Scanners + + # Scanner for plain text. + # + # Yields just one token of the kind :plain. + # + # Alias: +plaintext+, +plain+ + class Text < Scanner + + register_for :text + title 'Plain text' + + KINDS_NOT_LOC = [:plain] # :nodoc: + + protected + + def scan_tokens encoder, options + encoder.text_token string, :plain + encoder + end + + end + + end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/xml.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/xml.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,17 @@ +module CodeRay +module Scanners + + load :html + + # Scanner for XML. + # + # Currently this is the same scanner as Scanners::HTML. + class XML < HTML + + register_for :xml + file_extension 'xml' + + end + +end +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/scanners/yaml.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/scanners/yaml.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,140 @@ +module CodeRay +module Scanners + + # Scanner for YAML. + # + # Based on the YAML scanner from Syntax by Jamis Buck. + class YAML < Scanner + + register_for :yaml + file_extension 'yml' + + KINDS_NOT_LOC = :all + + protected + + def scan_tokens encoder, options + + state = :initial + key_indent = string_indent = 0 + + until eos? + + key_indent = nil if bol? + + if match = scan(/ +[\t ]*/) + encoder.text_token match, :space + + elsif match = scan(/\n+/) + encoder.text_token match, :space + state = :initial if match.index(?\n) + + elsif match = scan(/#.*/) + encoder.text_token match, :comment + + elsif bol? and case + when match = scan(/---|\.\.\./) + encoder.begin_group :head + encoder.text_token match, :head + encoder.end_group :head + next + when match = scan(/%.*/) + encoder.text_token match, :doctype + next + end + + elsif state == :value and case + when !check(/(?:"[^"]*")(?=: |:$)/) && match = scan(/"/) + encoder.begin_group :string + encoder.text_token match, :delimiter + encoder.text_token match, :content if match = scan(/ [^"\\]* (?: \\. [^"\\]* )* /mx) + encoder.text_token match, :delimiter if match = scan(/"/) + encoder.end_group :string + next + when match = scan(/[|>][-+]?/) + encoder.begin_group :string + encoder.text_token match, :delimiter + string_indent = key_indent || column(pos - match.size) - 1 + encoder.text_token matched, :content if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) + encoder.end_group :string + next + when match = scan(/(?![!"*&]).+?(?=$|\s+#)/) + encoder.begin_group :string + encoder.text_token match, :content + string_indent = key_indent || column(pos - match.size) - 1 + encoder.text_token matched, :content if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) + encoder.end_group :string + next + end + + elsif case + when match = scan(/[-:](?= |$)/) + state = :value if state == :colon && (match == ':' || match == '-') + state = :value if state == :initial && match == '-' + encoder.text_token match, :operator + next + when match = scan(/[,{}\[\]]/) + encoder.text_token match, :operator + next + when state == :initial && match = scan(/[\w.() ]*\S(?= *:(?: |$))/) + encoder.text_token match, :key + key_indent = column(pos - match.size) - 1 + state = :colon + next + when match = scan(/(?:"[^"\n]*"|'[^'\n]*')(?= *:(?: |$))/) + encoder.begin_group :key + encoder.text_token match[0,1], :delimiter + encoder.text_token match[1..-2], :content + encoder.text_token match[-1,1], :delimiter + encoder.end_group :key + key_indent = column(pos - match.size) - 1 + state = :colon + next + when match = scan(/(![\w\/]+)(:([\w:]+))?/) + encoder.text_token self[1], :type + if self[2] + encoder.text_token ':', :operator + encoder.text_token self[3], :class + end + next + when match = scan(/&\S+/) + encoder.text_token match, :variable + next + when match = scan(/\*\w+/) + encoder.text_token match, :global_variable + next + when match = scan(/< 'annotation', + :attribute_name => 'attribute-name', + :attribute_value => 'attribute-value', + :binary => 'bin', + :char => 'char', + :class => 'class', + :class_variable => 'class-variable', + :color => 'color', + :comment => 'comment', + :complex => 'complex', + :constant => 'constant', + :content => 'content', + :debug => 'debug', + :decorator => 'decorator', + :definition => 'definition', + :delimiter => 'delimiter', + :directive => 'directive', + :doc => 'doc', + :doctype => 'doctype', + :doc_string => 'doc-string', + :entity => 'entity', + :error => 'error', + :escape => 'escape', + :exception => 'exception', + :filename => 'filename', + :float => 'float', + :function => 'function', + :global_variable => 'global-variable', + :hex => 'hex', + :imaginary => 'imaginary', + :important => 'important', + :include => 'include', + :inline => 'inline', + :inline_delimiter => 'inline-delimiter', + :instance_variable => 'instance-variable', + :integer => 'integer', + :key => 'key', + :keyword => 'keyword', + :label => 'label', + :local_variable => 'local-variable', + :modifier => 'modifier', + :namespace => 'namespace', + :octal => 'octal', + :predefined => 'predefined', + :predefined_constant => 'predefined-constant', + :predefined_type => 'predefined-type', + :preprocessor => 'preprocessor', + :pseudo_class => 'pseudo-class', + :regexp => 'regexp', + :reserved => 'reserved', + :shell => 'shell', + :string => 'string', + :symbol => 'symbol', + :tag => 'tag', + :type => 'type', + :value => 'value', + :variable => 'variable', + + :change => 'change', + :delete => 'delete', + :head => 'head', + :insert => 'insert', + + :eyecatcher => 'eyecatcher', + + :ident => false, + :operator => false, + + :space => false, + :plain => false + ) + + TokenKinds[:method] = TokenKinds[:function] + TokenKinds[:escape] = TokenKinds[:delimiter] + TokenKinds[:docstring] = TokenKinds[:comment] + + TokenKinds.freeze +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/tokens.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/tokens.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,215 @@ +module CodeRay + + # GZip library for writing and reading token dumps. + autoload :GZip, 'coderay/helpers/gzip' + + # = Tokens TODO: Rewrite! + # + # The Tokens class represents a list of tokens returnd from + # a Scanner. + # + # A token is not a special object, just a two-element Array + # consisting of + # * the _token_ _text_ (the original source of the token in a String) or + # a _token_ _action_ (begin_group, end_group, begin_line, end_line) + # * the _token_ _kind_ (a Symbol representing the type of the token) + # + # A token looks like this: + # + # ['# It looks like this', :comment] + # ['3.1415926', :float] + # ['$^', :error] + # + # Some scanners also yield sub-tokens, represented by special + # token actions, namely begin_group and end_group. + # + # The Ruby scanner, for example, splits "a string" into: + # + # [ + # [:begin_group, :string], + # ['"', :delimiter], + # ['a string', :content], + # ['"', :delimiter], + # [:end_group, :string] + # ] + # + # Tokens is the interface between Scanners and Encoders: + # The input is split and saved into a Tokens object. The Encoder + # then builds the output from this object. + # + # Thus, the syntax below becomes clear: + # + # CodeRay.scan('price = 2.59', :ruby).html + # # the Tokens object is here -------^ + # + # See how small it is? ;) + # + # Tokens gives you the power to handle pre-scanned code very easily: + # You can convert it to a webpage, a YAML file, or dump it into a gzip'ed string + # that you put in your DB. + # + # It also allows you to generate tokens directly (without using a scanner), + # to load them from a file, and still use any Encoder that CodeRay provides. + class Tokens < Array + + # The Scanner instance that created the tokens. + attr_accessor :scanner + + # Encode the tokens using encoder. + # + # encoder can be + # * a symbol like :html oder :statistic + # * an Encoder class + # * an Encoder object + # + # options are passed to the encoder. + def encode encoder, options = {} + encoder = Encoders[encoder].new options if encoder.respond_to? :to_sym + encoder.encode_tokens self, options + end + + # Turn tokens into a string by concatenating them. + def to_s + encode CodeRay::Encoders::Encoder.new + end + + # Redirects unknown methods to encoder calls. + # + # For example, if you call +tokens.html+, the HTML encoder + # is used to highlight the tokens. + def method_missing meth, options = {} + encode meth, options + rescue PluginHost::PluginNotFound + super + end + + # Split the tokens into parts of the given +sizes+. + # + # The result will be an Array of Tokens objects. The parts have + # the text size specified by the parameter. In addition, each + # part closes all opened tokens. This is useful to insert tokens + # betweem them. + # + # This method is used by @Scanner#tokenize@ when called with an Array + # of source strings. The Diff encoder uses it for inline highlighting. + def split_into_parts *sizes + parts = [] + opened = [] + content = nil + part = Tokens.new + part_size = 0 + size = sizes.first + i = 0 + for item in self + case content + when nil + content = item + when String + if size && part_size + content.size > size # token must be cut + if part_size < size # some part of the token goes into this part + content = content.dup # content may no be safe to change + part << content.slice!(0, size - part_size) << item + end + # close all open groups and lines... + closing = opened.reverse.flatten.map do |content_or_kind| + case content_or_kind + when :begin_group + :end_group + when :begin_line + :end_line + else + content_or_kind + end + end + part.concat closing + begin + parts << part + part = Tokens.new + size = sizes[i += 1] + end until size.nil? || size > 0 + # ...and open them again. + part.concat opened.flatten + part_size = 0 + redo unless content.empty? + else + part << content << item + part_size += content.size + end + content = nil + when Symbol + case content + when :begin_group, :begin_line + opened << [content, item] + when :end_group, :end_line + opened.pop + else + raise ArgumentError, 'Unknown token action: %p, kind = %p' % [content, item] + end + part << content << item + content = nil + else + raise ArgumentError, 'Token input junk: %p, kind = %p' % [content, item] + end + end + parts << part + parts << Tokens.new while parts.size < sizes.size + parts + end + + # Dumps the object into a String that can be saved + # in files or databases. + # + # The dump is created with Marshal.dump; + # In addition, it is gzipped using GZip.gzip. + # + # The returned String object includes Undumping + # so it has an #undump method. See Tokens.load. + # + # You can configure the level of compression, + # but the default value 7 should be what you want + # in most cases as it is a good compromise between + # speed and compression rate. + # + # See GZip module. + def dump gzip_level = 7 + dump = Marshal.dump self + dump = GZip.gzip dump, gzip_level + dump.extend Undumping + end + + # Return the actual number of tokens. + def count + size / 2 + end + + # Include this module to give an object an #undump + # method. + # + # The string returned by Tokens.dump includes Undumping. + module Undumping + # Calls Tokens.load with itself. + def undump + Tokens.load self + end + end + + # Undump the object using Marshal.load, then + # unzip it using GZip.gunzip. + # + # The result is commonly a Tokens object, but + # this is not guaranteed. + def Tokens.load dump + dump = GZip.gunzip dump + @dump = Marshal.load dump + end + + alias text_token push + def begin_group kind; push :begin_group, kind end + def end_group kind; push :end_group, kind end + def begin_line kind; push :begin_line, kind end + def end_line kind; push :end_line, kind end + alias tokens concat + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/tokens_proxy.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/tokens_proxy.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,55 @@ +module CodeRay + + # The result of a scan operation is a TokensProxy, but should act like Tokens. + # + # This proxy makes it possible to use the classic CodeRay.scan.encode API + # while still providing the benefits of direct streaming. + class TokensProxy + + attr_accessor :input, :lang, :options, :block + + # Create a new TokensProxy with the arguments of CodeRay.scan. + def initialize input, lang, options = {}, block = nil + @input = input + @lang = lang + @options = options + @block = block + end + + # Call CodeRay.encode if +encoder+ is a Symbol; + # otherwise, convert the receiver to tokens and call encoder.encode_tokens. + def encode encoder, options = {} + if encoder.respond_to? :to_sym + CodeRay.encode(input, lang, encoder, options) + else + encoder.encode_tokens tokens, options + end + end + + # Tries to call encode; + # delegates to tokens otherwise. + def method_missing method, *args, &blk + encode method.to_sym, *args + rescue PluginHost::PluginNotFound + tokens.send(method, *args, &blk) + end + + # The (cached) result of the tokenized input; a Tokens instance. + def tokens + @tokens ||= scanner.tokenize(input) + end + + # A (cached) scanner instance to use for the scan task. + def scanner + @scanner ||= CodeRay.scanner(lang, options, &block) + end + + # Overwrite Struct#each. + def each *args, &blk + tokens.each(*args, &blk) + self + end + + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/lib/coderay/version.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/lib/coderay/version.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,3 @@ +module CodeRay + VERSION = '1.0.0' +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/test/functional/basic.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/test/functional/basic.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,304 @@ +# encoding: utf-8 +require 'test/unit' +require File.expand_path('../../lib/assert_warning', __FILE__) + +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +class BasicTest < Test::Unit::TestCase + + def test_version + assert_nothing_raised do + assert_match(/\A\d\.\d\.\d?\z/, CodeRay::VERSION) + end + end + + RUBY_TEST_CODE = 'puts "Hello, World!"' + + RUBY_TEST_TOKENS = [ + ['puts', :ident], + [' ', :space], + [:begin_group, :string], + ['"', :delimiter], + ['Hello, World!', :content], + ['"', :delimiter], + [:end_group, :string] + ].flatten + def test_simple_scan + assert_nothing_raised do + assert_equal RUBY_TEST_TOKENS, CodeRay.scan(RUBY_TEST_CODE, :ruby).tokens + end + end + + RUBY_TEST_HTML = 'puts "' + + 'Hello, World!"' + def test_simple_highlight + assert_nothing_raised do + assert_equal RUBY_TEST_HTML, CodeRay.scan(RUBY_TEST_CODE, :ruby).html + end + end + + def test_scan_file + CodeRay.scan_file __FILE__ + end + + def test_encode + assert_equal 1, CodeRay.encode('test', :python, :count) + end + + def test_encode_tokens + assert_equal 1, CodeRay.encode_tokens(CodeRay::Tokens['test', :string], :count) + end + + def test_encode_file + assert_equal File.read(__FILE__), CodeRay.encode_file(__FILE__, :text) + end + + def test_highlight + assert_match '
    test
    ', CodeRay.highlight('test', :python) + end + + def test_highlight_file + assert_match "require 'test/unit'\n", CodeRay.highlight_file(__FILE__) + end + + def test_duo + assert_equal(RUBY_TEST_CODE, + CodeRay::Duo[:plain, :text].highlight(RUBY_TEST_CODE)) + assert_equal(RUBY_TEST_CODE, + CodeRay::Duo[:plain => :text].highlight(RUBY_TEST_CODE)) + end + + def test_duo_stream + assert_equal(RUBY_TEST_CODE, + CodeRay::Duo[:plain, :text].highlight(RUBY_TEST_CODE, :stream => true)) + end + + def test_comment_filter + assert_equal <<-EXPECTED, CodeRay.scan(<<-INPUT, :ruby).comment_filter.text +#!/usr/bin/env ruby + +code + +more code + EXPECTED +#!/usr/bin/env ruby +=begin +A multi-line comment. +=end +code +# A single-line comment. +more code # and another comment, in-line. + INPUT + end + + def test_lines_of_code + assert_equal 2, CodeRay.scan(<<-INPUT, :ruby).lines_of_code +#!/usr/bin/env ruby +=begin +A multi-line comment. +=end +code +# A single-line comment. +more code # and another comment, in-line. + INPUT + rHTML = <<-RHTML + + + + + + <%= controller.controller_name.titleize %>: <%= controller.action_name %> + <%= stylesheet_link_tag 'scaffold' %> + + + +

    <%= flash[:notice] %>

    + +
    + <%= yield %> +
    + + + + RHTML + assert_equal 0, CodeRay.scan(rHTML, :html).lines_of_code + assert_equal 0, CodeRay.scan(rHTML, :php).lines_of_code + assert_equal 0, CodeRay.scan(rHTML, :yaml).lines_of_code + assert_equal 4, CodeRay.scan(rHTML, :erb).lines_of_code + end + + def test_list_of_encoders + assert_kind_of(Array, CodeRay::Encoders.list) + assert CodeRay::Encoders.list.include?(:count) + end + + def test_list_of_scanners + assert_kind_of(Array, CodeRay::Scanners.list) + assert CodeRay::Scanners.list.include?(:text) + end + + def test_token_kinds + assert_kind_of Hash, CodeRay::TokenKinds + for kind, css_class in CodeRay::TokenKinds + assert_kind_of Symbol, kind + if css_class != false + assert_kind_of String, css_class, "TokenKinds[%p] == %p" % [kind, css_class] + end + end + assert_equal 'reserved', CodeRay::TokenKinds[:reserved] + assert_warning 'Undefined Token kind: :shibboleet' do + assert_equal false, CodeRay::TokenKinds[:shibboleet] + end + end + + class Milk < CodeRay::Encoders::Encoder + FILE_EXTENSION = 'cocoa' + end + + class HoneyBee < CodeRay::Encoders::Encoder + end + + def test_encoder_file_extension + assert_nothing_raised do + assert_equal 'html', CodeRay::Encoders::Page::FILE_EXTENSION + assert_equal 'cocoa', Milk::FILE_EXTENSION + assert_equal 'cocoa', Milk.new.file_extension + assert_equal 'honeybee', HoneyBee::FILE_EXTENSION + assert_equal 'honeybee', HoneyBee.new.file_extension + end + assert_raise NameError do + HoneyBee::MISSING_CONSTANT + end + end + + def test_encoder_tokens + encoder = CodeRay::Encoders::Encoder.new + encoder.send :setup, {} + assert_raise(ArgumentError) { encoder.token :strange, '' } + encoder.token 'test', :debug + end + + def test_encoder_deprecated_interface + encoder = CodeRay::Encoders::Encoder.new + encoder.send :setup, {} + assert_warning 'Using old Tokens#<< interface.' do + encoder << ['test', :content] + end + assert_raise ArgumentError do + encoder << [:strange, :input] + end + assert_raise ArgumentError do + encoder.encode_tokens [['test', :token]] + end + end + + def encoder_token_interface_deprecation_warning_given + CodeRay::Encoders::Encoder.send :class_variable_get, :@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN + end + + def test_scanner_file_extension + assert_equal 'rb', CodeRay::Scanners::Ruby.file_extension + assert_equal 'rb', CodeRay::Scanners::Ruby.new.file_extension + assert_equal 'java', CodeRay::Scanners::Java.file_extension + assert_equal 'java', CodeRay::Scanners::Java.new.file_extension + end + + def test_scanner_lang + assert_equal :ruby, CodeRay::Scanners::Ruby.lang + assert_equal :ruby, CodeRay::Scanners::Ruby.new.lang + assert_equal :java, CodeRay::Scanners::Java.lang + assert_equal :java, CodeRay::Scanners::Java.new.lang + end + + def test_scanner_tokenize + assert_equal ['foo', :plain], CodeRay::Scanners::Plain.new.tokenize('foo') + assert_equal [['foo', :plain], ['bar', :plain]], CodeRay::Scanners::Plain.new.tokenize(['foo', 'bar']) + CodeRay::Scanners::Plain.new.tokenize 42 + end + + def test_scanner_tokens + scanner = CodeRay::Scanners::Plain.new + scanner.tokenize('foo') + assert_equal ['foo', :plain], scanner.tokens + scanner.string = '' + assert_equal ['', :plain], scanner.tokens + end + + def test_scanner_line_and_column + scanner = CodeRay::Scanners::Plain.new "foo\nbär+quux" + assert_equal 0, scanner.pos + assert_equal 1, scanner.line + assert_equal 1, scanner.column + scanner.scan(/foo/) + assert_equal 3, scanner.pos + assert_equal 1, scanner.line + assert_equal 4, scanner.column + scanner.scan(/\n/) + assert_equal 4, scanner.pos + assert_equal 2, scanner.line + assert_equal 1, scanner.column + scanner.scan(/b/) + assert_equal 5, scanner.pos + assert_equal 2, scanner.line + assert_equal 2, scanner.column + scanner.scan(/a/) + assert_equal 5, scanner.pos + assert_equal 2, scanner.line + assert_equal 2, scanner.column + scanner.scan(/ä/) + assert_equal 7, scanner.pos + assert_equal 2, scanner.line + assert_equal 4, scanner.column + scanner.scan(/r/) + assert_equal 8, scanner.pos + assert_equal 2, scanner.line + assert_equal 5, scanner.column + end + + def test_scanner_use_subclasses + assert_raise NotImplementedError do + CodeRay::Scanners::Scanner.new + end + end + + class InvalidScanner < CodeRay::Scanners::Scanner + end + + def test_scanner_scan_tokens + assert_raise NotImplementedError do + InvalidScanner.new.tokenize '' + end + end + + class RaisingScanner < CodeRay::Scanners::Scanner + def scan_tokens encoder, options + raise_inspect 'message', [], :initial + end + end + + def test_scanner_raise_inspect + assert_raise CodeRay::Scanners::Scanner::ScanError do + RaisingScanner.new.tokenize '' + end + end + + def test_scan_a_frozen_string + assert_nothing_raised do + CodeRay.scan RUBY_VERSION, :ruby + CodeRay.scan RUBY_VERSION, :plain + end + end + + def test_scan_a_non_string + assert_nothing_raised do + CodeRay.scan 42, :ruby + CodeRay.scan nil, :ruby + CodeRay.scan self, :ruby + CodeRay.encode ENV.to_hash, :ruby, :page + CodeRay.highlight CodeRay, :plain + end + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/test/functional/examples.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/test/functional/examples.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,130 @@ +require 'test/unit' + +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +class ExamplesTest < Test::Unit::TestCase + + def test_examples + # output as HTML div (using inline CSS styles) + div = CodeRay.scan('puts "Hello, world!"', :ruby).div + assert_equal <<-DIV, div +
    +
    puts "Hello, world!"
    +
    + DIV + + # ...with line numbers + div = CodeRay.scan(<<-CODE.chomp, :ruby).div(:line_numbers => :table) +5.times do + puts 'Hello, world!' +end + CODE + assert_equal <<-DIV, div +
    + + +
    1
    +2
    +3
    +
    5.times do
    +  puts 'Hello, world!'
    +end
    + DIV + + # output as standalone HTML page (using CSS classes) + page = CodeRay.scan('puts "Hello, world!"', :ruby).page + assert page[<<-PAGE] + + + + + +
    +
    puts "Hello, world!"
    + + + PAGE + + # keep scanned tokens for later use + tokens = CodeRay.scan('{ "just": "an", "example": 42 }', :json) + assert_kind_of CodeRay::TokensProxy, tokens + + assert_equal ["{", :operator, " ", :space, :begin_group, :key, + "\"", :delimiter, "just", :content, "\"", :delimiter, + :end_group, :key, ":", :operator, " ", :space, + :begin_group, :string, "\"", :delimiter, "an", :content, + "\"", :delimiter, :end_group, :string, ",", :operator, + " ", :space, :begin_group, :key, "\"", :delimiter, + "example", :content, "\"", :delimiter, :end_group, :key, + ":", :operator, " ", :space, "42", :integer, + " ", :space, "}", :operator], tokens.tokens + + # produce a token statistic + assert_equal <<-STATISTIC, tokens.statistic + +Code Statistics + +Tokens 26 + Non-Whitespace 15 +Bytes Total 31 + +Token Types (7): + type count ratio size (average) +------------------------------------------------------------- + TOTAL 26 100.00 % 1.2 + delimiter 6 23.08 % 1.0 + operator 5 19.23 % 1.0 + space 5 19.23 % 1.0 + key 4 15.38 % 0.0 + :begin_group 3 11.54 % 0.0 + :end_group 3 11.54 % 0.0 + content 3 11.54 % 4.3 + string 2 7.69 % 0.0 + integer 1 3.85 % 2.0 + + STATISTIC + + # count the tokens + assert_equal 26, tokens.count + + # produce a HTML div, but with CSS classes + div = tokens.div(:css => :class) + assert_equal <<-DIV, div +
    +
    { "just": "an", "example": 42 }
    +
    + DIV + + # highlight a file (HTML div); guess the file type base on the extension + require 'coderay/helpers/file_type' + assert_equal :ruby, CodeRay::FileType[__FILE__] + + # get a new scanner for Python + python_scanner = CodeRay.scanner :python + assert_kind_of CodeRay::Scanners::Python, python_scanner + + # get a new encoder for terminal + terminal_encoder = CodeRay.encoder :term + assert_kind_of CodeRay::Encoders::Terminal, terminal_encoder + + # scanning into tokens + tokens = python_scanner.tokenize 'import this; # The Zen of Python' + assert_equal ["import", :keyword, " ", :space, "this", :include, + ";", :operator, " ", :space, "# The Zen of Python", :comment], tokens + + # format the tokens + term = terminal_encoder.encode_tokens(tokens) + assert_equal "\e[1;31mimport\e[0m \e[33mthis\e[0m; \e[37m# The Zen of Python\e[0m", term + + # re-using scanner and encoder + ruby_highlighter = CodeRay::Duo[:ruby, :div] + div = ruby_highlighter.encode('puts "Hello, world!"') + assert_equal <<-DIV, div +
    +
    puts "Hello, world!"
    +
    + DIV + end + +end diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/test/functional/for_redcloth.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/test/functional/for_redcloth.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,84 @@ +require 'test/unit' +require File.expand_path('../../lib/assert_warning', __FILE__) + +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +begin + require 'rubygems' unless defined? Gem + gem 'RedCloth', '>= 4.0.3' rescue nil + require 'redcloth' +rescue LoadError + warn 'RedCloth not found - skipping for_redcloth tests.' + undef RedCloth if defined? RedCloth +end + +class BasicTest < Test::Unit::TestCase + + def test_for_redcloth + require 'coderay/for_redcloth' + assert_equal "

    puts "Hello, World!"

    ", + RedCloth.new('@[ruby]puts "Hello, World!"@').to_html + assert_equal <<-BLOCKCODE.chomp, +
    +
    puts "Hello, World!"
    +
    + BLOCKCODE + RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html + end + + def test_for_redcloth_no_lang + require 'coderay/for_redcloth' + assert_equal "

    puts \"Hello, World!\"

    ", + RedCloth.new('@puts "Hello, World!"@').to_html + assert_equal <<-BLOCKCODE.chomp, +
    puts \"Hello, World!\"
    + BLOCKCODE + RedCloth.new('bc. puts "Hello, World!"').to_html + end + + def test_for_redcloth_style + require 'coderay/for_redcloth' + assert_equal <<-BLOCKCODE.chomp, +
    puts \"Hello, World!\"
    + BLOCKCODE + RedCloth.new('bc{color: red}. puts "Hello, World!"').to_html + end + + def test_for_redcloth_escapes + require 'coderay/for_redcloth' + assert_equal '

    >

    ', + RedCloth.new('@[ruby]>@').to_html + assert_equal <<-BLOCKCODE.chomp, +
    +
    &
    +
    + BLOCKCODE + RedCloth.new('bc[ruby]. &').to_html + end + + def test_for_redcloth_escapes2 + require 'coderay/for_redcloth' + assert_equal "

    #include <test.h>

    ", + RedCloth.new('@[c]#include @').to_html + end + + # See http://jgarber.lighthouseapp.com/projects/13054/tickets/124-code-markup-does-not-allow-brackets. + def test_for_redcloth_false_positive + require 'coderay/for_redcloth' + assert_warning 'CodeRay::Scanners could not load plugin :project; falling back to :text' do + assert_equal '

    [project]_dff.skjd

    ', + RedCloth.new('@[project]_dff.skjd@').to_html + end + # false positive, but expected behavior / known issue + assert_equal "

    _dff.skjd

    ", + RedCloth.new('@[ruby]_dff.skjd@').to_html + assert_warning 'CodeRay::Scanners could not load plugin :project; falling back to :text' do + assert_equal <<-BLOCKCODE.chomp, +
    [project]_dff.skjd
    + BLOCKCODE + RedCloth.new('bc. [project]_dff.skjd').to_html + end + end + +end if defined? RedCloth \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/gems/coderay-1.0.0/test/functional/suite.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/gems/coderay-1.0.0/test/functional/suite.rb Mon Feb 27 13:53:18 2012 +0000 @@ -0,0 +1,15 @@ +require 'test/unit' + +$VERBOSE = $CODERAY_DEBUG = true +$:.unshift File.expand_path('../../../lib', __FILE__) +require 'coderay' + +mydir = File.dirname(__FILE__) +suite = Dir[File.join(mydir, '*.rb')]. + map { |tc| File.basename(tc).sub(/\.rb$/, '') } - %w'suite for_redcloth' + +puts "Running basic CodeRay #{CodeRay::VERSION} tests: #{suite.join(', ')}" + +for test_case in suite + load File.join(mydir, test_case + '.rb') +end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb --- a/vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/acts_as_customizable/lib/acts_as_customizable.rb Mon Feb 27 13:53:18 2012 +0000 @@ -31,7 +31,7 @@ :include => :custom_field, :order => "#{CustomField.table_name}.position", :dependent => :delete_all - before_validation_on_create { |customized| customized.custom_field_values } + before_validation { |customized| customized.custom_field_values if customized.new_record? } # Trigger validation only if custom values were changed validates_associated :custom_values, :on => :update, :if => Proc.new { |customized| customized.custom_field_values_changed? } send :include, Redmine::Acts::Customizable::InstanceMethods @@ -71,7 +71,6 @@ custom_field_values.each do |custom_value| custom_value.value = values[custom_value.custom_field_id.to_s] if values.has_key?(custom_value.custom_field_id.to_s) end if values.is_a?(Hash) - self.custom_values = custom_field_values end def custom_field_values @@ -92,6 +91,7 @@ end def save_custom_field_values + self.custom_values = custom_field_values custom_field_values.each(&:save) @custom_field_values_changed = false @custom_field_values = nil diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb Mon Feb 27 13:53:18 2012 +0000 @@ -162,9 +162,10 @@ end # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree. - def rebuild! + def rebuild!(force=false) # Don't rebuild a valid tree. - return true if valid? + # valid? doesn't strictly validate the tree + return true if !force && valid? scope = lambda{|node|} if acts_as_nested_set_options[:scope] @@ -444,18 +445,18 @@ # Prunes a branch off of the tree, shifting all of the elements on the right # back to the left so the counts still work. def prune_from_tree - return if right.nil? || left.nil? || leaf? || !self.class.exists?(id) + return if right.nil? || left.nil? || !self.class.exists?(id) - delete_method = acts_as_nested_set_options[:dependent] == :destroy ? - :destroy_all : :delete_all - - # TODO: should destroy children (not descendants) when deleted_method is :destroy_all self.class.base_class.transaction do reload_nested_set - nested_set_scope.send(delete_method, - ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", - left, right] - ) + if acts_as_nested_set_options[:dependent] == :destroy + children.each(&:destroy) + else + nested_set_scope.send(:delete_all, + ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", + left, right] + ) + end reload_nested_set diff = right - left + 1 nested_set_scope.update_all( diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/barcode.rb --- a/vendor/plugins/rfpdf/lib/barcode/barcode.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,448 +0,0 @@ - -#============================================================+ -# File name : barcode.rb -# Begin : 2002-07-31 -# Last Update : 2005-01-02 -# Author : Karim Mribti [barcode@mribti.com] -# Version : 1.1 [0.0.8a (original code)] -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : Generic Barcode Render Class for PHP using -# the GD graphics library. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -# - $mCharSet and $mChars variables were added here -#============================================================+ - -# -# Barcode Render Class for PHP using the GD graphics library. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# - -# Styles -# Global - -# -# option: generate barcode border -# -define("BCS_BORDER", 1); - -# -# option: use transparent background -# -define("BCS_TRANSPARENT", 2); - -# -# option: center barcode -# -define("BCS_ALIGN_CENTER", 4); - -# -# option: align left -# -define("BCS_ALIGN_LEFT", 8); - -# -# option: align right -# -define("BCS_ALIGN_RIGHT", 16); - -# -# option: generate JPEG image -# -define("BCS_IMAGE_JPEG", 32); - -# -# option: generate PNG image -# -define("BCS_IMAGE_PNG", 64); - -# -# option: draw text -# -define("BCS_DRAW_TEXT", 128); - -# -# option: stretch text -# -define("BCS_STRETCH_TEXT", 256); - -# -# option: reverse color -# -define("BCS_REVERSE_COLOR", 512); - -# -# option: draw check -# (only for I25 code) -# -define("BCS_I25_DRAW_CHECK", 2048); - -# -# set default background color -# -define("BCD_DEFAULT_BACKGROUND_COLOR", 0xFFFFFF); - -# -# set default foreground color -# -define("BCD_DEFAULT_FOREGROUND_COLOR", 0x000000); - -# -# set default style options -# -define("BCD_DEFAULT_STYLE", BCS_BORDER | BCS_ALIGN_CENTER | BCS_IMAGE_PNG); - -# -# set default width -# -define("BCD_DEFAULT_WIDTH", 460); - -# -# set default height -# -define("BCD_DEFAULT_HEIGHT", 120); - -# -# set default font -# -define("BCD_DEFAULT_FONT", 5); - -# -# st default horizontal resolution -# -define("BCD_DEFAULT_XRES", 2); - -# Margins - -# -# set default margin -# -define("BCD_DEFAULT_MAR_Y1", 0); - -# -# set default margin -# -define("BCD_DEFAULT_MAR_Y2", 0); - -# -# set default text offset -# -define("BCD_DEFAULT_TEXT_OFFSET", 2); - -# For the I25 Only - -# -# narrow bar option -# (only for I25 code) -# -define("BCD_I25_NARROW_BAR", 1); - -# -# wide bar option -# (only for I25 code) -# -define("BCD_I25_WIDE_BAR", 2); - -# For the C39 Only - -# -# narrow bar option -# (only for c39 code) -# -define("BCD_C39_NARROW_BAR", 1); - -# -# wide bar option -# (only for c39 code) -# -define("BCD_C39_WIDE_BAR", 2); - -# For Code 128 - -# -# set type 1 bar -# (only for c128 code) -# -define("BCD_C128_BAR_1", 1); - -# -# set type 2 bar -# (only for c128 code) -# -define("BCD_C128_BAR_2", 2); - -# -# set type 3 bar -# (only for c128 code) -# -define("BCD_C128_BAR_3", 3); - -# -# set type 4 bar -# (only for c128 code) -# -define("BCD_C128_BAR_4", 4); - -# -# Barcode Render Class for PHP using the GD graphics library. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# -class BarcodeObject { - # - # @var Image width in pixels. - # @access protected - # - protected $mWidth; - - # - # @var Image height in pixels. - # @access protected - # - protected $mHeight; - - # - # @var Numeric code for Barcode style. - # @access protected - # - protected $mStyle; - - # - # @var Background color. - # @access protected - # - protected $mBgcolor; - - # - # @var Brush color. - # @access protected - # - protected $mBrush; - - # - # @var Image object. - # @access protected - # - protected $mImg; - - # - # @var Numeric code for character font. - # @access protected - # - protected $mFont; - - # - # @var Error message. - # @access protected - # - protected $mError; - - # - # @var Character Set. - # @access protected - # - protected $mCharSet; - - # - # @var Allowed symbols. - # @access protected - # - protected $mChars; - - # - # Class Constructor. - # @param int $Width Image width in pixels. - # @param int $Height Image height in pixels. - # @param int $Style Barcode style. - # - def __construct($Width=BCD_DEFAULT_WIDTH, $Height=BCD_DEFAULT_HEIGHT, $Style=BCD_DEFAULT_STYLE) - @mWidth = $Width; - @mHeight = $Height; - @mStyle = $Style; - @mFont = BCD_DEFAULT_FONT; - @mImg = ImageCreate(@mWidth, @mHeight); - $dbColor = @mStyle & BCS_REVERSE_COLOR ? BCD_DEFAULT_FOREGROUND_COLOR : BCD_DEFAULT_BACKGROUND_COLOR; - $dfColor = @mStyle & BCS_REVERSE_COLOR ? BCD_DEFAULT_BACKGROUND_COLOR : BCD_DEFAULT_FOREGROUND_COLOR; - @mBgcolor = ImageColorAllocate(@mImg, ($dbColor & 0xFF0000) >> 16, - ($dbColor & 0x00FF00) >> 8, $dbColor & 0x0000FF); - @mBrush = ImageColorAllocate(@mImg, ($dfColor & 0xFF0000) >> 16, - ($dfColor & 0x00FF00) >> 8, $dfColor & 0x0000FF); - if (!(@mStyle & BCS_TRANSPARENT)) - ImageFill(@mImg, @mWidth, @mHeight, @mBgcolor); - end - end - - # - # Class Destructor. - # Destroy image object. - # - def __destructor() - @DestroyObject(); - end - - # - # Returns the image object. - # @return object image. - # @author Nicola Asuni - # @since 1.5.2 - # - def getImage() - return @mImg; - end - - # - # Abstract method used to draw the barcode image. - # @param int $xres Horizontal resolution. - # - def DrawObject($xres) { - # there is not implementation neded, is simply the asbsract function.# - return false; - end - - # - # Draws the barcode border. - # @access protected - # - protected function DrawBorder() - ImageRectangle(@mImg, 0, 0, @mWidth-1, @mHeight-1, @mBrush); - end - - # - # Draws the alphanumeric code. - # @param int $Font Font type. - # @param int $xPos Horiziontal position. - # @param int $yPos Vertical position. - # @param int $Char Alphanumeric code to write. - # @access protected - # - protected function DrawChar($Font, $xPos, $yPos, $Char) - ImageString(@mImg,$Font,$xPos,$yPos,$Char,@mBrush); - end - - # - # Draws a character string. - # @param int $Font Font type. - # @param int $xPos Horiziontal position. - # @param int $yPos Vertical position. - # @param int $Char string to write. - # @access protected - # - protected function DrawText($Font, $xPos, $yPos, $Char) - ImageString(@mImg,$Font,$xPos,$yPos,$Char,@mBrush); - end - - # - # Draws a single barcode bar. - # @param int $xPos Horiziontal position. - # @param int $yPos Vertical position. - # @param int $xSize Horizontal size. - # @param int $xSize Vertical size. - # @return bool trur in case of success, false otherwise. - # @access protected - # - protected function DrawSingleBar($xPos, $yPos, $xSize, $ySize) - if ($xPos>=0 && $xPos<=@mWidth && ($xPos+$xSize)<=@mWidth && - $yPos>=0 && $yPos<=@mHeight && ($yPos+$ySize)<=@mHeight) - for ($i=0;$i<$xSize;$i++) - ImageLine(@mImg, $xPos+$i, $yPos, $xPos+$i, $yPos+$ySize, @mBrush); - end - return true; - end - return false; - end - - # - # Returns the current error message. - # @return string error message. - # - def GetError() - return @mError; - end - - # - # Returns the font height. - # @param int $font font type. - # @return int font height. - # - def GetFontHeight($font) - return ImageFontHeight($font); - end - - # - # Returns the font width. - # @param int $font font type. - # @return int font width. - # - def GetFontWidth($font) - return ImageFontWidth($font); - end - - # - # Set font type. - # @param int $font font type. - # - def SetFont($font) - @mFont = $font; - end - - # - # Returns barcode style. - # @return int barcode style. - # - def GetStyle() - return @mStyle; - end - - # - # Set barcode style. - # @param int $Style barcode style. - # - def SetStyle ($Style) - @mStyle = $Style; - end - - # - # Flush the barcode image. - # - def FlushObject() - if ((@mStyle & BCS_BORDER)) - @DrawBorder(); - end - if (@mStyle & BCS_IMAGE_PNG) - Header("Content-Type: image/png"); - ImagePng(@mImg); - elsif (@mStyle & BCS_IMAGE_JPEG) - Header("Content-Type: image/jpeg"); - ImageJpeg(@mImg); - end - end - - # - # Destroy the barcode image. - # - def DestroyObject() - ImageDestroy(@mImg); - end -} - -#============================================================+ -# END OF FILE -#============================================================+ diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/c128aobject.rb --- a/vendor/plugins/rfpdf/lib/barcode/c128aobject.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ - -#============================================================+ -# File name : c128aobject.rb -# Begin : 2002-07-31 -# Last Update : 2004-12-29 -# Author : Karim Mribti [barcode@mribti.com] -# Version : 0.0.8a 2001-04-01 (original code) -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : Code 128-A Barcode Render Class for PHP using -# the GD graphics library. -# Code 128-A is a continuous, multilevel and -# include all upper case alphanumeric characters -# and ASCII control characters. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -#============================================================+ - -# -# Code 128-A Barcode Render Class for PHP using the GD graphics library.
    -# Code 128-A is a continuous, multilevel and include all upper case alphanumeric characters and ASCII control characters. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# - -# -# Code 128-A Barcode Render Class for PHP using the GD graphics library.
    -# Code 128-A is a continuous, multilevel and include all upper case alphanumeric characters and ASCII control characters. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# -class C128AObject extends BarcodeObject { - - # - # Class Constructor. - # @param int $Width Image width in pixels. - # @param int $Height Image height in pixels. - # @param int $Style Barcode style. - # @param int $Value value to print on barcode. - # - def __construct($Width, $Height, $Style, $Value) - parent::__construct($Width, $Height, $Style); - @mValue = $Value; - @mChars = " !\"#$%&'()*+�-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; - @mCharSet = array ( - "212222", # 00# - "222122", # 01# - "222221", # 02# - "121223", # 03# - "121322", # 04# - "131222", # 05# - "122213", # 06# - "122312", # 07# - "132212", # 08# - "221213", # 09# - "221312", # 10# - "231212", # 11# - "112232", # 12# - "122132", # 13# - "122231", # 14# - "113222", # 15# - "123122", # 16# - "123221", # 17# - "223211", # 18# - "221132", # 19# - "221231", # 20# - "213212", # 21# - "223112", # 22# - "312131", # 23# - "311222", # 24# - "321122", # 25# - "321221", # 26# - "312212", # 27# - "322112", # 28# - "322211", # 29# - "212123", # 30# - "212321", # 31# - "232121", # 32# - "111323", # 33# - "131123", # 34# - "131321", # 35# - "112313", # 36# - "132113", # 37# - "132311", # 38# - "211313", # 39# - "231113", # 40# - "231311", # 41# - "112133", # 42# - "112331", # 43# - "132131", # 44# - "113123", # 45# - "113321", # 46# - "133121", # 47# - "313121", # 48# - "211331", # 49# - "231131", # 50# - "213113", # 51# - "213311", # 52# - "213131", # 53# - "311123", # 54# - "311321", # 55# - "331121", # 56# - "312113", # 57# - "312311", # 58# - "332111", # 59# - "314111", # 60# - "221411", # 61# - "431111", # 62# - "111224", # 63# - "111422", # 64# - "121124", # 65# - "121421", # 66# - "141122", # 67# - "141221", # 68# - "112214", # 69# - "112412", # 70# - "122114", # 71# - "122411", # 72# - "142112", # 73# - "142211", # 74# - "241211", # 75# - "221114", # 76# - "413111", # 77# - "241112", # 78# - "134111", # 79# - "111242", # 80# - "121142", # 81# - "121241", # 82# - "114212", # 83# - "124112", # 84# - "124211", # 85# - "411212", # 86# - "421112", # 87# - "421211", # 88# - "212141", # 89# - "214121", # 90# - "412121", # 91# - "111143", # 92# - "111341", # 93# - "131141", # 94# - "114113", # 95# - "114311", # 96# - "411113", # 97# - "411311", # 98# - "113141", # 99# - "114131", # 100# - "311141", # 101# - "411131" # 102# - ); - end - - # - # Returns the character index. - # @param char $char character. - # @return int character index or -1 in case of error. - # @access private - # - def GetCharIndex($char) - for ($i=0;$i<64;$i++) - if (@mChars[$i] == $char) - return $i; - end - end - return -1; - end - - # - # Returns the bar size. - # @param int $xres Horizontal resolution. - # @param char $char Character. - # @return int barcode size. - # @access private - # - def GetBarSize($xres, $char) - switch ($char) - case '1' - $cVal = BCD_C128_BAR_1; - - case '2' - $cVal = BCD_C128_BAR_2; - - case '3' - $cVal = BCD_C128_BAR_3; - - case '4' - $cVal = BCD_C128_BAR_4; - - default - $cVal = 0; - end - end - return $cVal# $xres; - end - - # - # Returns barcode size. - # @param int $xres Horizontal resolution. - # @return barcode size. - # @access private - # - def GetSize($xres) - $len = @mValue.length; - - if ($len == 0) { - @mError = "Null value"; - return false; - end - $ret = 0; - for ($i=0;$i<$len;$i++) - if (($id = GetCharIndex(@mValue[$i])) == -1) - @mError = "C128A not include the char '".@mValue[$i]."'"; - return false; - else - $cset = @mCharSet[$id]; - $ret += GetBarSize($xres, $cset[0]); - $ret += GetBarSize($xres, $cset[1]); - $ret += GetBarSize($xres, $cset[2]); - $ret += GetBarSize($xres, $cset[3]); - $ret += GetBarSize($xres, $cset[4]); - $ret += GetBarSize($xres, $cset[5]); - end - end - - # length of Check character# - $cset = GetCheckCharValue(); - $CheckSize = 0; - for ($i=0;$i<6;$i++) - $CheckSize += GetBarSize($cset[$i], $xres); - end - $StartSize = 2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres; - $StopSize = 2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + 2*BCD_C128_BAR_3*$xres; - return $StartSize + $ret + $CheckSize + $StopSize; - end - - # - # Returns the check-char value. - # @return string. - # @access private - # - def GetCheckCharValue() - $len = @mValue.length; - $sum = 103; # 'A' type; - for ($i=0;$i<$len;$i++) - $sum += GetCharIndex(@mValue[$i])# ($i+1); - end - $check = $sum % 103; - return @mCharSet[$check]; - end - - # - # Draws the start code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStart($DrawPos, $yPos, $ySize, $xres) - # Start code is '211412'# - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres) , $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('4', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres) , $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('2', $xres); - return $DrawPos; - end - - # - # Draws the stop code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStop($DrawPos, $yPos, $ySize, $xres) - # Stop code is '2331112'# - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - $DrawPos += GetBarSize('3', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('3', $xres) , $ySize); - $DrawPos += GetBarSize('3', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres) , $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - return $DrawPos; - end - - # - # Draws the check-char code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawCheckChar($DrawPos, $yPos, $ySize, $xres) - $cset = GetCheckCharValue(); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[0], $xres) , $ySize); - $DrawPos += GetBarSize($cset[0], $xres); - $DrawPos += GetBarSize($cset[1], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[2], $xres) , $ySize); - $DrawPos += GetBarSize($cset[2], $xres); - $DrawPos += GetBarSize($cset[3], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[4], $xres) , $ySize); - $DrawPos += GetBarSize($cset[4], $xres); - $DrawPos += GetBarSize($cset[5], $xres); - return $DrawPos; - end - - # - # Draws the barcode object. - # @param int $xres Horizontal resolution. - # @return bool true in case of success. - # - def DrawObject($xres) - $len = @mValue.length; - if (($size = GetSize($xres))==0) - return false; - end - - if (@mStyle & BCS_ALIGN_CENTER) $sPos = (integer)((@mWidth - $size ) / 2); - elsif (@mStyle & BCS_ALIGN_RIGHT) $sPos = @mWidth - $size; - else $sPos = 0; - - # Total height of bar code -Bars only-# - if (@mStyle & BCS_DRAW_TEXT) $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2 - GetFontHeight(@mFont); - else $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2; - - # Draw text# - if (@mStyle & BCS_DRAW_TEXT) - if (@mStyle & BCS_STRETCH_TEXT) - for ($i=0;$i<$len;$i++) - @DrawChar(@mFont, $sPos+(2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres)+($size/$len)*$i, - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue[$i]); - else# Center# - $text_width = GetFontWidth(@mFont)# @mValue.length; - @DrawText(@mFont, $sPos+(($size-$text_width)/2)+(2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres), - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue); - end - end - - $cPos = 0; - $DrawPos = @DrawStart($sPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - do { - $c = GetCharIndex(@mValue[$cPos]); - $cset = @mCharSet[$c]; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[0], $xres) , $ysize); - $DrawPos += GetBarSize($cset[0], $xres); - $DrawPos += GetBarSize($cset[1], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[2], $xres) , $ysize); - $DrawPos += GetBarSize($cset[2], $xres); - $DrawPos += GetBarSize($cset[3], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[4], $xres) , $ysize); - $DrawPos += GetBarSize($cset[4], $xres); - $DrawPos += GetBarSize($cset[5], $xres); - $cPos += 1; - end while ($cPos<$len); - $DrawPos = @DrawCheckChar($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - $DrawPos = @DrawStop($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - return true; - end -} - -#============================================================+ -# END OF FILE -#============================================================+ diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/c128bobject.rb --- a/vendor/plugins/rfpdf/lib/barcode/c128bobject.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ - -#============================================================+ -# File name : c128bobject.rb -# Begin : 2002-07-31 -# Last Update : 2004-12-29 -# Author : Karim Mribti [barcode@mribti.com] -# Version : 0.0.8a 2001-04-01 (original code) -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : Code 128-B Barcode Render Class for PHP using -# the GD graphics library. -# Code 128-B is a continuous, multilevel and full -# ASCII code. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -#============================================================+ - -# -# Code 128-B Barcode Render Class for PHP using the GD graphics library.
    -# Code 128-B is a continuous, multilevel and full ASCII code. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# - -# -# Code 128-B Barcode Render Class for PHP using the GD graphics library.
    -# Code 128-B is a continuous, multilevel and full ASCII code. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# -class C128BObject extends BarcodeObject { - - # - # Class Constructor. - # @param int $Width Image width in pixels. - # @param int $Height Image height in pixels. - # @param int $Style Barcode style. - # @param int $Value value to print on barcode. - # - def __construct($Width, $Height, $Style, $Value) - parent::__construct($Width, $Height, $Style); - @mValue = $Value; - @mChars = " !\"#$%&'()*+�-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{ }~"; - @mCharSet = array ( - "212222", # 00# - "222122", # 01# - "222221", # 02# - "121223", # 03# - "121322", # 04# - "131222", # 05# - "122213", # 06# - "122312", # 07# - "132212", # 08# - "221213", # 09# - "221312", # 10# - "231212", # 11# - "112232", # 12# - "122132", # 13# - "122231", # 14# - "113222", # 15# - "123122", # 16# - "123221", # 17# - "223211", # 18# - "221132", # 19# - "221231", # 20# - "213212", # 21# - "223112", # 22# - "312131", # 23# - "311222", # 24# - "321122", # 25# - "321221", # 26# - "312212", # 27# - "322112", # 28# - "322211", # 29# - "212123", # 30# - "212321", # 31# - "232121", # 32# - "111323", # 33# - "131123", # 34# - "131321", # 35# - "112313", # 36# - "132113", # 37# - "132311", # 38# - "211313", # 39# - "231113", # 40# - "231311", # 41# - "112133", # 42# - "112331", # 43# - "132131", # 44# - "113123", # 45# - "113321", # 46# - "133121", # 47# - "313121", # 48# - "211331", # 49# - "231131", # 50# - "213113", # 51# - "213311", # 52# - "213131", # 53# - "311123", # 54# - "311321", # 55# - "331121", # 56# - "312113", # 57# - "312311", # 58# - "332111", # 59# - "314111", # 60# - "221411", # 61# - "431111", # 62# - "111224", # 63# - "111422", # 64# - "121124", # 65# - "121421", # 66# - "141122", # 67# - "141221", # 68# - "112214", # 69# - "112412", # 70# - "122114", # 71# - "122411", # 72# - "142112", # 73# - "142211", # 74# - "241211", # 75# - "221114", # 76# - "413111", # 77# - "241112", # 78# - "134111", # 79# - "111242", # 80# - "121142", # 81# - "121241", # 82# - "114212", # 83# - "124112", # 84# - "124211", # 85# - "411212", # 86# - "421112", # 87# - "421211", # 88# - "212141", # 89# - "214121", # 90# - "412121", # 91# - "111143", # 92# - "111341", # 93# - "131141", # 94# - "114113", # 95# - "114311", # 96# - "411113", # 97# - "411311", # 98# - "113141", # 99# - "114131", # 100# - "311141", # 101# - "411131" # 102# - ); - end - - # - # Returns the character index. - # @param char $char character. - # @return int character index or -1 in case of error. - # @access private - # - def GetCharIndex($char) - for ($i=0;$i<95;$i++) - if (@mChars[$i] == $char) - return $i; - end - end - return -1; - end - - # - # Returns the bar size. - # @param int $xres Horizontal resolution. - # @param char $char Character. - # @return int barcode size. - # @access private - # - def GetBarSize($xres, $char) - switch ($char) - case '1' - $cVal = BCD_C128_BAR_1; - - case '2' - $cVal = BCD_C128_BAR_2; - - case '3' - $cVal = BCD_C128_BAR_3; - - case '4' - $cVal = BCD_C128_BAR_4; - - default - $cVal = 0; - end - end - return $cVal# $xres; - end - - # - # Returns barcode size. - # @param int $xres Horizontal resolution. - # @return barcode size. - # @access private - # - def GetSize($xres) - $len = @mValue.length; - - if ($len == 0) { - @mError = "Null value"; - return false; - end - $ret = 0; - for ($i=0;$i<$len;$i++) - if (($id = GetCharIndex(@mValue[$i])) == -1) - @mError = "C128B not include the char '".@mValue[$i]."'"; - return false; - else - $cset = @mCharSet[$id]; - $ret += GetBarSize($xres, $cset[0]); - $ret += GetBarSize($xres, $cset[1]); - $ret += GetBarSize($xres, $cset[2]); - $ret += GetBarSize($xres, $cset[3]); - $ret += GetBarSize($xres, $cset[4]); - $ret += GetBarSize($xres, $cset[5]); - end - end - # length of Check character# - $cset = GetCheckCharValue(); - $CheckSize = 0; - for ($i=0;$i<6;$i++) - $CheckSize += GetBarSize($cset[$i], $xres); - end - - $StartSize = 2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres; - $StopSize = 2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + 2*BCD_C128_BAR_3*$xres; - - return $StartSize + $ret + $CheckSize + $StopSize; - end - - # - # Returns the check-char value. - # @return string. - # @access private - # - def GetCheckCharValue() - $len = @mValue.length; - $sum = 104; # 'B' type; - for ($i=0;$i<$len;$i++) - $sum += GetCharIndex(@mValue[$i])# ($i+1); - end - $check = $sum % 103; - return @mCharSet[$check]; - end - - # - # Draws the start code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStart($DrawPos, $yPos, $ySize, $xres) - # Start code is '211214'# - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres), $ySize); - $DrawPos += GetBarSize('2', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres), $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('2', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres), $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('4', $xres); - return $DrawPos; - end - - # - # Draws the stop code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStop($DrawPos, $yPos, $ySize, $xres) - # Stop code is '2331112'# - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - $DrawPos += GetBarSize('3', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('3', $xres) , $ySize); - $DrawPos += GetBarSize('3', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres) , $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - return $DrawPos; - end - - # - # Draws the check-char code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawCheckChar($DrawPos, $yPos, $ySize, $xres) - $cset = GetCheckCharValue(); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[0], $xres) , $ySize); - $DrawPos += GetBarSize($cset[0], $xres); - $DrawPos += GetBarSize($cset[1], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[2], $xres) , $ySize); - $DrawPos += GetBarSize($cset[2], $xres); - $DrawPos += GetBarSize($cset[3], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[4], $xres) , $ySize); - $DrawPos += GetBarSize($cset[4], $xres); - $DrawPos += GetBarSize($cset[5], $xres); - return $DrawPos; - end - - # - # Draws the barcode object. - # @param int $xres Horizontal resolution. - # @return bool true in case of success. - # - def DrawObject($xres) - $len = @mValue.length; - if (($size = GetSize($xres))==0) - return false; - end - - if (@mStyle & BCS_ALIGN_CENTER) $sPos = (integer)((@mWidth - $size ) / 2); - elsif (@mStyle & BCS_ALIGN_RIGHT) $sPos = @mWidth - $size; - else $sPos = 0; - - # Total height of bar code -Bars only-# - if (@mStyle & BCS_DRAW_TEXT) $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2 - GetFontHeight(@mFont); - else $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2; - - # Draw text# - if (@mStyle & BCS_DRAW_TEXT) - if (@mStyle & BCS_STRETCH_TEXT) - for ($i=0;$i<$len;$i++) - @DrawChar(@mFont, $sPos+(2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres)+($size/$len)*$i, - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue[$i]); - else# Center# - $text_width = GetFontWidth(@mFont)# @mValue.length; - @DrawText(@mFont, $sPos+(($size-$text_width)/2)+(2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres), - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue); - end - end - - $cPos = 0; - $DrawPos = @DrawStart($sPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - do { - $c = GetCharIndex(@mValue[$cPos]); - $cset = @mCharSet[$c]; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[0], $xres) , $ysize); - $DrawPos += GetBarSize($cset[0], $xres); - $DrawPos += GetBarSize($cset[1], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[2], $xres) , $ysize); - $DrawPos += GetBarSize($cset[2], $xres); - $DrawPos += GetBarSize($cset[3], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[4], $xres) , $ysize); - $DrawPos += GetBarSize($cset[4], $xres); - $DrawPos += GetBarSize($cset[5], $xres); - $cPos += 1; - end while ($cPos<$len); - $DrawPos = @DrawCheckChar($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - $DrawPos = @DrawStop($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - return true; - end -} - -#============================================================+ -# END OF FILE -#============================================================+ diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/c128cobject.rb --- a/vendor/plugins/rfpdf/lib/barcode/c128cobject.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,414 +0,0 @@ - -#============================================================+ -# File name : c128cobject.rb -# Begin : 2002-07-31 -# Last Update : 2004-12-29 -# Author : Karim Mribti [barcode@mribti.com] -# : Sam Michaels [swampgas@swampgas.org] -# : Nicola Asuni [info@tecnick.com] -# Version : 0.0.8a 2001-04-01 (original code) -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : Code 128-C Barcode Render Class for PHP using -# the GD graphics library. -# Code 128-C is numeric only and provides the -# most efficiency. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -#============================================================+ - -# -# Code 128-C Barcode Render Class for PHP using the GD graphics library.
    -# Code 128-C is numeric only and provides the most efficiency. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# - -# -# Code 128-C Barcode Render Class for PHP using the GD graphics library.
    -# Code 128-C is numeric only and provides the most efficiency. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# -class C128CObject extends BarcodeObject { - - # - # Class Constructor. - # @param int $Width Image width in pixels. - # @param int $Height Image height in pixels. - # @param int $Style Barcode style. - # @param int $Value value to print on barcode. - # - def __construct($Width, $Height, $Style, $Value) - parent::__construct($Width, $Height, $Style); - @mValue = $Value; - @mChars = array ( - "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", - "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", - "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", - "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", - "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", - "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", - "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", - "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", - "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", - "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", - ); - @mCharSet = array ( - "212222", # 00# - "222122", # 01# - "222221", # 02# - "121223", # 03# - "121322", # 04# - "131222", # 05# - "122213", # 06# - "122312", # 07# - "132212", # 08# - "221213", # 09# - "221312", # 10# - "231212", # 11# - "112232", # 12# - "122132", # 13# - "122231", # 14# - "113222", # 15# - "123122", # 16# - "123221", # 17# - "223211", # 18# - "221132", # 19# - "221231", # 20# - "213212", # 21# - "223112", # 22# - "312131", # 23# - "311222", # 24# - "321122", # 25# - "321221", # 26# - "312212", # 27# - "322112", # 28# - "322211", # 29# - "212123", # 30# - "212321", # 31# - "232121", # 32# - "111323", # 33# - "131123", # 34# - "131321", # 35# - "112313", # 36# - "132113", # 37# - "132311", # 38# - "211313", # 39# - "231113", # 40# - "231311", # 41# - "112133", # 42# - "112331", # 43# - "132131", # 44# - "113123", # 45# - "113321", # 46# - "133121", # 47# - "313121", # 48# - "211331", # 49# - "231131", # 50# - "213113", # 51# - "213311", # 52# - "213131", # 53# - "311123", # 54# - "311321", # 55# - "331121", # 56# - "312113", # 57# - "312311", # 58# - "332111", # 59# - "314111", # 60# - "221411", # 61# - "431111", # 62# - "111224", # 63# - "111422", # 64# - "121124", # 65# - "121421", # 66# - "141122", # 67# - "141221", # 68# - "112214", # 69# - "112412", # 70# - "122114", # 71# - "122411", # 72# - "142112", # 73# - "142211", # 74# - "241211", # 75# - "221114", # 76# - "413111", # 77# - "241112", # 78# - "134111", # 79# - "111242", # 80# - "121142", # 81# - "121241", # 82# - "114212", # 83# - "124112", # 84# - "124211", # 85# - "411212", # 86# - "421112", # 87# - "421211", # 88# - "212141", # 89# - "214121", # 90# - "412121", # 91# - "111143", # 92# - "111341", # 93# - "131141", # 94# - "114113", # 95# - "114311", # 96# - "411113", # 97# - "411311", # 98# - "113141", # 99# - ); - end - - # - # Returns the character index. - # @param char $char character. - # @return int character index or -1 in case of error. - # @access private - # - def GetCharIndex($char) - for ($i=0;$i<100;$i++) - if (@mChars[$i] == $char) - return $i; - end - end - return -1; - end - - # - # Returns the bar size. - # @param int $xres Horizontal resolution. - # @param char $char Character. - # @return int barcode size. - # @access private - # - def GetBarSize($xres, $char) - switch ($char) - case '1' - $cVal = BCD_C128_BAR_1; - - case '2' - $cVal = BCD_C128_BAR_2; - - case '3' - $cVal = BCD_C128_BAR_3; - - case '4' - $cVal = BCD_C128_BAR_4; - - default - $cVal = 0; - end - end - return $cVal# $xres; - end - - # - # Returns barcode size. - # @param int $xres Horizontal resolution. - # @return barcode size. - # @access private - # - def GetSize($xres) - $len = @mValue.length; - - if ($len == 0) { - @mError = "Null value"; - return false; - end - $ret = 0; - - for ($i=0;$i<$len;$i++) - if ((@mValue[$i][0] < 48) || (@mValue[$i][0] > 57)) - @mError = "Code-128C is numeric only"; - return false; - end - end - - if (($len%2) != 0) - @mError = "The length of barcode value must be even. You must pad the number with zeros."; - return false; - end - - for ($i=0;$i<$len;$i+=2) - $id = GetCharIndex(@mValue[$i].@mValue[$i+1]); - $cset = @mCharSet[$id]; - $ret += GetBarSize($xres, $cset[0]); - $ret += GetBarSize($xres, $cset[1]); - $ret += GetBarSize($xres, $cset[2]); - $ret += GetBarSize($xres, $cset[3]); - $ret += GetBarSize($xres, $cset[4]); - $ret += GetBarSize($xres, $cset[5]); - end - # length of Check character# - $cset = GetCheckCharValue(); - $CheckSize = 0; - for ($i=0;$i<6;$i++) - $CheckSize += GetBarSize($cset[$i], $xres); - end - - $StartSize = 2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres; - $StopSize = 2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + 2*BCD_C128_BAR_3*$xres; - return $StartSize + $ret + $CheckSize + $StopSize; - end - - # - # Returns the check-char value. - # @return string. - # @access private - # - def GetCheckCharValue() - $len = @mValue.length; - $sum = 105; # 'C' type; - $m = 0; - for ($i=0;$i<$len;$i+=2) - $m += 1; - $sum += GetCharIndex(@mValue[$i].@mValue[$i+1])# $m; - end - $check = $sum % 103; - return @mCharSet[$check]; - end - - # - # Draws the start code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStart($DrawPos, $yPos, $ySize, $xres) - # Start code is '211232'# - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres) , $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('2', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('3', $xres) , $ySize); - $DrawPos += GetBarSize('3', $xres); - $DrawPos += GetBarSize('2', $xres); - return $DrawPos; - end - - # - # Draws the stop code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStop($DrawPos, $yPos, $ySize, $xres) - # Stop code is '2331112'# - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - $DrawPos += GetBarSize('3', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('3', $xres) , $ySize); - $DrawPos += GetBarSize('3', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('1', $xres) , $ySize); - $DrawPos += GetBarSize('1', $xres); - $DrawPos += GetBarSize('1', $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize('2', $xres) , $ySize); - $DrawPos += GetBarSize('2', $xres); - return $DrawPos; - end - - # - # Draws the check-char code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawCheckChar($DrawPos, $yPos, $ySize, $xres) - $cset = GetCheckCharValue(); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[0], $xres) , $ySize); - $DrawPos += GetBarSize($cset[0], $xres); - $DrawPos += GetBarSize($cset[1], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[2], $xres) , $ySize); - $DrawPos += GetBarSize($cset[2], $xres); - $DrawPos += GetBarSize($cset[3], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[4], $xres) , $ySize); - $DrawPos += GetBarSize($cset[4], $xres); - $DrawPos += GetBarSize($cset[5], $xres); - return $DrawPos; - end - - # - # Draws the barcode object. - # @param int $xres Horizontal resolution. - # @return bool true in case of success. - # - def DrawObject($xres) - $len = @mValue.length; - if (($size = GetSize($xres))==0) - return false; - end - - if (@mStyle & BCS_ALIGN_CENTER) $sPos = (integer)((@mWidth - $size ) / 2); - elsif (@mStyle & BCS_ALIGN_RIGHT) $sPos = @mWidth - $size; - else $sPos = 0; - - # Total height of bar code -Bars only-# - if (@mStyle & BCS_DRAW_TEXT) $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2 - GetFontHeight(@mFont); - else $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2; - - # Draw text# - if (@mStyle & BCS_DRAW_TEXT) - if (@mStyle & BCS_STRETCH_TEXT) - for ($i=0;$i<$len;$i++) - @DrawChar(@mFont, $sPos+(2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres)+($size/$len)*$i, - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue[$i]); - else# Center# - $text_width = GetFontWidth(@mFont) * @mValue.length; - @DrawText(@mFont, $sPos+(($size-$text_width)/2)+(2*BCD_C128_BAR_2*$xres + 3*BCD_C128_BAR_1*$xres + BCD_C128_BAR_4*$xres), - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue); - end - end - - $cPos = 0; - $DrawPos = @DrawStart($sPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - do { - $c = GetCharIndex(@mValue[$cPos].@mValue[$cPos+1]); - $cset = @mCharSet[$c]; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[0], $xres) , $ysize); - $DrawPos += GetBarSize($cset[0], $xres); - $DrawPos += GetBarSize($cset[1], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[2], $xres) , $ysize); - $DrawPos += GetBarSize($cset[2], $xres); - $DrawPos += GetBarSize($cset[3], $xres); - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, GetBarSize($cset[4], $xres) , $ysize); - $DrawPos += GetBarSize($cset[4], $xres); - $DrawPos += GetBarSize($cset[5], $xres); - $cPos += 2; - end while ($cPos<$len); - $DrawPos = @DrawCheckChar($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - $DrawPos = @DrawStop($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - return true; - end -} - -#============================================================+ -# END OF FILE -#============================================================+ - diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/c39object.rb --- a/vendor/plugins/rfpdf/lib/barcode/c39object.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ - -#============================================================+ -# File name : c39object.rb -# Begin : 2002-07-31 -# Last Update : 2004-12-29 -# Author : Karim Mribti [barcode@mribti.com] -# : Nicola Asuni [info@tecnick.com] -# Version : 0.0.8a 2001-04-01 (original code) -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : Code 39 Barcode Render Class for PHP using -# the GD graphics library. -# Code 39 is an alphanumeric bar code that can -# encode decimal number, case alphabet and some -# special symbols. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -#============================================================+ - -# -# Code 39 Barcode Render Class.
    -# Code 39 is an alphanumeric bar code that can encode decimal number, case alphabet and some special symbols. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# - -# -# Code 39 Barcode Render Class.
    -# Code 39 is an alphanumeric bar code that can encode decimal number, case alphabet and some special symbols. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# -class C39Object extends BarcodeObject { - - # - # Class Constructor. - # @param int $Width Image width in pixels. - # @param int $Height Image height in pixels. - # @param int $Style Barcode style. - # @param int $Value value to print on barcode. - # - def __construct($Width, $Height, $Style, $Value) - parent::__construct($Width, $Height, $Style); - @mValue = $Value; - @mChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.#$/+%"; - @mCharSet = array ( - # 0 # "000110100", - # 1 # "100100001", - # 2 # "001100001", - # 3 # "101100000", - # 4 # "000110001", - # 5 # "100110000", - # 6 # "001110000", - # 7 # "000100101", - # 8 # "100100100", - # 9 # "001100100", - # A # "100001001", - # B # "001001001", - # C # "101001000", - # D # "000011001", - # E # "100011000", - # F # "001011000", - # G # "000001101", - # H # "100001100", - # I # "001001100", - # J # "000011100", - # K # "100000011", - # L # "001000011", - # M # "101000010", - # N # "000010011", - # O # "100010010", - # P # "001010010", - # Q # "000000111", - # R # "100000110", - # S # "001000110", - # T # "000010110", - # U # "110000001", - # V # "011000001", - # W # "111000000", - # X # "010010001", - # Y # "110010000", - # Z # "011010000", - # - # "010000101", - # . # "110000100", - # SP# "011000100", - /*# # "010010100", - # $ # "010101000", - # / # "010100010", - # + # "010001010", - # % # "000101010" - ); - end - - # - # Returns the character index. - # @param char $char character. - # @return int character index or -1 in case of error. - # @access private - # - def GetCharIndex($char) - for ($i=0;$i<44;$i++) - if (@mChars[$i] == $char) - return $i; - end - end - return -1; - end - - # - # Returns barcode size. - # @param int $xres Horizontal resolution. - # @return barcode size. - # @access private - # - def GetSize($xres) - $len = @mValue.length; - - if ($len == 0) { - @mError = "Null value"; - return false; - end - - for ($i=0;$i<$len;$i++) - if (GetCharIndex(@mValue[$i]) == -1 || @mValue[$i] == '*') - # The asterisk is only used as a start and stop code# - @mError = "C39 not include the char '".@mValue[$i]."'"; - return false; - end - end - - # Start, Stop is 010010100 == '*' # - $StartSize = BCD_C39_NARROW_BAR# $xres# 6 + BCD_C39_WIDE_BAR# $xres# 3; - $StopSize = BCD_C39_NARROW_BAR# $xres# 6 + BCD_C39_WIDE_BAR# $xres# 3; - $CharSize = BCD_C39_NARROW_BAR# $xres# 6 + BCD_C39_WIDE_BAR# $xres# 3; # Same for all chars# - - return $CharSize# $len + $StartSize + $StopSize + # Space between chars# BCD_C39_NARROW_BAR# $xres# ($len-1); - end - - # - # Draws the start code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStart($DrawPos, $yPos, $ySize, $xres) - # Start code is '*'# - $narrow = BCD_C39_NARROW_BAR# $xres; - $wide = BCD_C39_WIDE_BAR# $xres; - @DrawSingleBar($DrawPos, $yPos, $narrow , $ySize); - $DrawPos += $narrow; - $DrawPos += $wide; - @DrawSingleBar($DrawPos, $yPos, $narrow , $ySize); - $DrawPos += $narrow; - $DrawPos += $narrow; - @DrawSingleBar($DrawPos, $yPos, $wide , $ySize); - $DrawPos += $wide; - $DrawPos += $narrow; - @DrawSingleBar($DrawPos, $yPos, $wide , $ySize); - $DrawPos += $wide; - $DrawPos += $narrow; - @DrawSingleBar($DrawPos, $yPos, $narrow, $ySize); - $DrawPos += $narrow; - $DrawPos += $narrow; # Space between chars# - return $DrawPos; - end - - # - # Draws the stop code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStop($DrawPos, $yPos, $ySize, $xres) - # Stop code is '*'# - $narrow = BCD_C39_NARROW_BAR# $xres; - $wide = BCD_C39_WIDE_BAR# $xres; - @DrawSingleBar($DrawPos, $yPos, $narrow , $ySize); - $DrawPos += $narrow; - $DrawPos += $wide; - @DrawSingleBar($DrawPos, $yPos, $narrow , $ySize); - $DrawPos += $narrow; - $DrawPos += $narrow; - @DrawSingleBar($DrawPos, $yPos, $wide , $ySize); - $DrawPos += $wide; - $DrawPos += $narrow; - @DrawSingleBar($DrawPos, $yPos, $wide , $ySize); - $DrawPos += $wide; - $DrawPos += $narrow; - @DrawSingleBar($DrawPos, $yPos, $narrow, $ySize); - $DrawPos += $narrow; - return $DrawPos; - end - - # - # Draws the barcode object. - # @param int $xres Horizontal resolution. - # @return bool true in case of success. - # - def DrawObject($xres) - $len = @mValue.length; - - $narrow = BCD_C39_NARROW_BAR# $xres; - $wide = BCD_C39_WIDE_BAR# $xres; - - if (($size = GetSize($xres))==0) - return false; - end - - $cPos = 0; - if (@mStyle & BCS_ALIGN_CENTER) $sPos = (integer)((@mWidth - $size ) / 2); - elsif (@mStyle & BCS_ALIGN_RIGHT) $sPos = @mWidth - $size; - else $sPos = 0; - - # Total height of bar code -Bars only-# - if (@mStyle & BCS_DRAW_TEXT) $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2 - GetFontHeight(@mFont); - else $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2; - - # Draw text# - if (@mStyle & BCS_DRAW_TEXT) - if (@mStyle & BCS_STRETCH_TEXT) - for ($i=0;$i<$len;$i++) - @DrawChar(@mFont, $sPos+($narrow*6+$wide*3)+($size/$len)*$i, - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue[$i]); - else# Center# - $text_width = GetFontWidth(@mFont)# @mValue.length; - @DrawText(@mFont, $sPos+(($size-$text_width)/2)+($narrow*6+$wide*3), - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue); - end - end - - $DrawPos = @DrawStart($sPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - do { - $c = GetCharIndex(@mValue[$cPos]); - $cset = @mCharSet[$c]; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[0] == '0') ? $narrow : $wide , $ysize); - $DrawPos += ($cset[0] == '0') ? $narrow : $wide; - $DrawPos += ($cset[1] == '0') ? $narrow : $wide; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[2] == '0') ? $narrow : $wide , $ysize); - $DrawPos += ($cset[2] == '0') ? $narrow : $wide; - $DrawPos += ($cset[3] == '0') ? $narrow : $wide; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[4] == '0') ? $narrow : $wide , $ysize); - $DrawPos += ($cset[4] == '0') ? $narrow : $wide; - $DrawPos += ($cset[5] == '0') ? $narrow : $wide; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[6] == '0') ? $narrow : $wide , $ysize); - $DrawPos += ($cset[6] == '0') ? $narrow : $wide; - $DrawPos += ($cset[7] == '0') ? $narrow : $wide; - @DrawSingleBar($DrawPos, BCD_DEFAULT_MAR_Y1, ($cset[8] == '0') ? $narrow : $wide , $ysize); - $DrawPos += ($cset[8] == '0') ? $narrow : $wide; - $DrawPos += $narrow; # Space between chars# - $cPos += 1; - end while ($cPos<$len); - $DrawPos = @DrawStop($DrawPos, BCD_DEFAULT_MAR_Y1 , $ysize, $xres); - return true; - end -} - -#============================================================+ -# END OF FILE -#============================================================+ diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/i25object.rb --- a/vendor/plugins/rfpdf/lib/barcode/i25object.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ - -#============================================================+ -# File name : i25aobject.rb -# Begin : 2002-07-31 -# Last Update : 2004-12-29 -# Author : Karim Mribti [barcode@mribti.com] -# : Nicola Asuni [info@tecnick.com] -# Version : 0.0.8a 2001-04-01 (original code) -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : I25 Barcode Render Class for PHP using -# the GD graphics library. -# Interleaved 2 of 5 is a numeric only bar code -# with a optional check number. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -#============================================================+ - -# -# I25 Barcode Render Class for PHP using the GD graphics library. 57)) - @mError = "I25 is numeric only"; - return false; - end - end - - if (($len%2) != 0) - @mError = "The length of barcode value must be even"; - return false; - end - $StartSize = BCD_I25_NARROW_BAR# 4 # $xres; - $StopSize = BCD_I25_WIDE_BAR# $xres + 2# BCD_I25_NARROW_BAR# $xres; - $cPos = 0; - $sPos = 0; - do { - $c1 = @mValue[$cPos]; - $c2 = @mValue[$cPos+1]; - $cset1 = @mCharSet[$c1]; - $cset2 = @mCharSet[$c2]; - - for ($i=0;$i<5;$i++) - $type1 = ($cset1[$i]==0) ? (BCD_I25_NARROW_BAR # $xres) : (BCD_I25_WIDE_BAR# $xres); - $type2 = ($cset2[$i]==0) ? (BCD_I25_NARROW_BAR # $xres) : (BCD_I25_WIDE_BAR# $xres); - $sPos += ($type1 + $type2); - end - $cPos+=2; - end while ($cPos<$len); - - return $sPos + $StartSize + $StopSize; - end - - # - # Draws the start code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStart($DrawPos, $yPos, $ySize, $xres) - # Start code is "0000"# - @DrawSingleBar($DrawPos, $yPos, BCD_I25_NARROW_BAR # $xres , $ySize); - $DrawPos += BCD_I25_NARROW_BAR # $xres; - $DrawPos += BCD_I25_NARROW_BAR # $xres; - @DrawSingleBar($DrawPos, $yPos, BCD_I25_NARROW_BAR # $xres , $ySize); - $DrawPos += BCD_I25_NARROW_BAR # $xres; - $DrawPos += BCD_I25_NARROW_BAR # $xres; - return $DrawPos; - end - - # - # Draws the stop code. - # @param int $DrawPos Drawing position. - # @param int $yPos Vertical position. - # @param int $ySize Vertical size. - # @param int $xres Horizontal resolution. - # @return int drawing position. - # @access private - # - def DrawStop($DrawPos, $yPos, $ySize, $xres) - # Stop code is "100"# - @DrawSingleBar($DrawPos, $yPos, BCD_I25_WIDE_BAR# $xres , $ySize); - $DrawPos += BCD_I25_WIDE_BAR # $xres; - $DrawPos += BCD_I25_NARROW_BAR # $xres; - @DrawSingleBar($DrawPos, $yPos, BCD_I25_NARROW_BAR # $xres , $ySize); - $DrawPos += BCD_I25_NARROW_BAR # $xres; - return $DrawPos; - end - - # - # Draws the barcode object. - # @param int $xres Horizontal resolution. - # @return bool true in case of success. - # - def DrawObject($xres) - $len = @mValue.length; - - if (($size = GetSize($xres))==0) - return false; - end - - $cPos = 0; - - if (@mStyle & BCS_DRAW_TEXT) $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2 - GetFontHeight(@mFont); - else $ysize = @mHeight - BCD_DEFAULT_MAR_Y1 - BCD_DEFAULT_MAR_Y2; - - if (@mStyle & BCS_ALIGN_CENTER) $sPos = (integer)((@mWidth - $size ) / 2); - elsif (@mStyle & BCS_ALIGN_RIGHT) $sPos = @mWidth - $size; - else $sPos = 0; - - if (@mStyle & BCS_DRAW_TEXT) - if (@mStyle & BCS_STRETCH_TEXT) - # Stretch# - for ($i=0;$i<$len;$i++) - @DrawChar(@mFont, $sPos+BCD_I25_NARROW_BAR*4*$xres+($size/$len)*$i, - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET , @mValue[$i]); - end - endelse# Center# - $text_width = GetFontWidth(@mFont) * @mValue.length; - @DrawText(@mFont, $sPos+(($size-$text_width)/2)+(BCD_I25_NARROW_BAR*4*$xres), - $ysize + BCD_DEFAULT_MAR_Y1 + BCD_DEFAULT_TEXT_OFFSET, @mValue); - end - end - - $sPos = @DrawStart($sPos, BCD_DEFAULT_MAR_Y1, $ysize, $xres); - do { - $c1 = @mValue[$cPos]; - $c2 = @mValue[$cPos+1]; - $cset1 = @mCharSet[$c1]; - $cset2 = @mCharSet[$c2]; - - for ($i=0;$i<5;$i++) - $type1 = ($cset1[$i]==0) ? (BCD_I25_NARROW_BAR# $xres) : (BCD_I25_WIDE_BAR# $xres); - $type2 = ($cset2[$i]==0) ? (BCD_I25_NARROW_BAR# $xres) : (BCD_I25_WIDE_BAR# $xres); - @DrawSingleBar($sPos, BCD_DEFAULT_MAR_Y1, $type1 , $ysize); - $sPos += ($type1 + $type2); - end - $cPos+=2; - end while ($cPos<$len); - $sPos = @DrawStop($sPos, BCD_DEFAULT_MAR_Y1, $ysize, $xres); - return true; - end -} - -#============================================================+ -# END OF FILE -#============================================================+ diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/image.rb --- a/vendor/plugins/rfpdf/lib/barcode/image.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ - -#============================================================+ -# File name : image.rb -# Begin : 2002-07-31 -# Last Update : 2005-01-08 -# Author : Karim Mribti [barcode@mribti.com] -# : Nicola Asuni [info@tecnick.com] -# Version : 0.0.8a 2001-04-01 (original code) -# License : GNU LGPL (Lesser General Public License) 2.1 -# http://www.gnu.org/copyleft/lesser.txt -# Source Code : http://www.mribti.com/barcode/ -# -# Description : Barcode Image Rendering. -# -# NOTE: -# This version contains changes by Nicola Asuni: -# - porting to Ruby -# - code style and formatting -# - automatic php documentation in PhpDocumentor Style -# (www.phpdoc.org) -# - minor bug fixing -#============================================================+ - -# -# Barcode Image Rendering. -# @author Karim Mribti, Nicola Asuni -# @name BarcodeObject -# @package com.tecnick.tcpdf -# @@version 0.0.8a 2001-04-01 (original code) -# @since 2001-03-25 -# @license http://www.gnu.org/copyleft/lesser.html LGPL -# - -# -# -# - -require("../../shared/barcode/barcode.rb"); -require("../../shared/barcode/i25object.rb"); -require("../../shared/barcode/c39object.rb"); -require("../../shared/barcode/c128aobject.rb"); -require("../../shared/barcode/c128bobject.rb"); -require("../../shared/barcode/c128cobject.rb"); - -if (!$_REQUEST['style'].nil?) $_REQUEST['style'] = BCD_DEFAULT_STYLE; -if (!$_REQUEST['width'].nil?) $_REQUEST['width'] = BCD_DEFAULT_WIDTH; -if (!$_REQUEST['height'].nil?) $_REQUEST['height'] = BCD_DEFAULT_HEIGHT; -if (!$_REQUEST['xres'].nil?) $_REQUEST['xres'] = BCD_DEFAULT_XRES; -if (!$_REQUEST['font'].nil?) $_REQUEST['font'] = BCD_DEFAULT_FONT; -if (!$_REQUEST['type'].nil?) $_REQUEST['type'] = "C39"; -if (!$_REQUEST['code'].nil?) $_REQUEST['code'] = ""; - -switch ($_REQUEST['type'].upcase) - case "I25" - $obj = new I25Object($_REQUEST['width'], $_REQUEST['height'], $_REQUEST['style'], $_REQUEST['code']); - break; - end - case "C128A" - $obj = new C128AObject($_REQUEST['width'], $_REQUEST['height'], $_REQUEST['style'], $_REQUEST['code']); - break; - end - case "C128B" - $obj = new C128BObject($_REQUEST['width'], $_REQUEST['height'], $_REQUEST['style'], $_REQUEST['code']); - break; - end - case "C128C" - $obj = new C128CObject($_REQUEST['width'], $_REQUEST['height'], $_REQUEST['style'], $_REQUEST['code']); - break; - end - case "C39": - default - $obj = new C39Object($_REQUEST['width'], $_REQUEST['height'], $_REQUEST['style'], $_REQUEST['code']); - break; - end -} - -if ($obj) - $obj->SetFont($_REQUEST['font']); - $obj->DrawObject($_REQUEST['xres']); - $obj->FlushObject(); - $obj->DestroyObject(); - unset($obj); # clean# -} - -#============================================================+ -# END OF FILE -#============================================================+ diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/barcode/lesser.txt --- a/vendor/plugins/rfpdf/lib/barcode/lesser.txt Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -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 and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, 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 library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete 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 distribute a copy of this License along with the -Library. - - 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 Library or any portion -of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -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 Library, 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 Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you 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. - - If distribution of 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 satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be 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. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library 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. - - 9. 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 Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -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 with -this License. - - 11. 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 Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library 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 Library. - -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. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library 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. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser 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 Library -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 Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -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 - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. 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 LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. 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. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/core/rmagick.rb --- a/vendor/plugins/rfpdf/lib/core/rmagick.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/rfpdf/lib/core/rmagick.rb Mon Feb 27 13:53:18 2012 +0000 @@ -57,8 +57,13 @@ end out['bits'] = image.channel_depth + File.open( TCPDF.k_path_cache + File::basename(filename), 'w'){|f| + f.binmode + f.print image.to_blob + f.close + } out end -end \ No newline at end of file +end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSans-ExtraLight.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSans-ExtraLight.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSans-ExtraLight.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSans-ExtraLight.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSans-ExtraLight') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSans-ExtraLight'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-733 -339 1659 1114]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>600, 32=>318, 33=>401, 34=>460, 35=>838, 36=>636, 37=>950, 38=>780, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>361, 46=>318, - 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, - 63=>531, 64=>1000, 65=>684, 66=>655, 67=>698, 68=>770, 69=>632, 70=>575, 71=>775, 72=>752, 73=>295, 74=>295, 75=>656, 76=>557, 77=>863, 78=>748, - 79=>787, 80=>603, 81=>787, 82=>695, 83=>635, 84=>611, 85=>732, 86=>684, 87=>989, 88=>685, 89=>611, 90=>685, 91=>390, 92=>337, 93=>390, 94=>838, - 95=>500, 96=>500, 97=>613, 98=>635, 99=>550, 100=>635, 101=>615, 102=>352, 103=>600, 104=>634, 105=>278, 106=>278, 107=>579, 108=>278, 109=>974, 110=>634, - 111=>612, 112=>635, 113=>635, 114=>411, 115=>521, 116=>392, 117=>634, 118=>592, 119=>818, 120=>592, 121=>592, 122=>525, 123=>636, 124=>337, 125=>636, 126=>838, - 8364=>636, 1027=>557, 8218=>318, 402=>352, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1342, 352=>635, 8249=>400, 338=>1070, 1036=>656, 381=>685, 1039=>752, - 8216=>318, 8217=>318, 8220=>518, 8221=>518, 8211=>500, 8212=>1000, 732=>500, 353=>521, 8250=>400, 339=>1023, 1116=>604, 382=>525, 376=>611, 160=>318, 161=>401, 162=>636, - 163=>636, 164=>636, 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>471, 171=>612, 172=>838, 173=>361, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>401, - 179=>401, 180=>483, 181=>636, 182=>636, 183=>318, 184=>500, 185=>401, 186=>471, 187=>612, 188=>969, 189=>969, 190=>969, 191=>536, 192=>684, 193=>684, 194=>684, - 195=>684, 196=>684, 197=>684, 198=>974, 199=>698, 200=>632, 201=>632, 202=>632, 203=>632, 204=>295, 205=>295, 206=>295, 207=>295, 208=>775, 209=>748, 210=>787, - 211=>787, 212=>787, 213=>787, 214=>787, 215=>838, 216=>787, 217=>732, 218=>732, 219=>732, 220=>732, 221=>611, 222=>605, 223=>676, 224=>613, 225=>613, 226=>613, - 227=>613, 228=>613, 229=>613, 230=>982, 231=>550, 232=>615, 233=>615, 234=>615, 235=>615, 236=>278, 237=>278, 238=>278, 239=>278, 240=>612, 241=>634, 242=>612, - 243=>612, 244=>612, 245=>612, 246=>612, 247=>838, 248=>612, 249=>634, 250=>634, 251=>634, 252=>634, 253=>592, 254=>635, 255=>592, 256=>684, 257=>613, 258=>684, - 259=>613, 260=>684, 261=>613, 262=>698, 263=>550, 264=>698, 265=>550, 266=>698, 267=>550, 268=>698, 269=>550, 270=>770, 271=>635, 272=>775, 273=>635, 274=>632, - 275=>615, 276=>632, 277=>615, 278=>632, 279=>615, 280=>632, 281=>615, 282=>632, 283=>615, 284=>775, 285=>600, 286=>775, 287=>600, 288=>775, 289=>600, 290=>775, - 291=>600, 292=>752, 293=>634, 294=>916, 295=>695, 296=>295, 297=>278, 298=>295, 299=>278, 300=>295, 301=>278, 302=>295, 303=>278, 304=>295, 305=>278, 306=>590, - 307=>556, 308=>295, 309=>278, 310=>656, 311=>579, 312=>579, 313=>557, 314=>293, 315=>557, 316=>278, 317=>557, 318=>375, 319=>557, 320=>342, 321=>562, 322=>284, - 323=>748, 324=>634, 325=>748, 326=>634, 327=>748, 328=>634, 329=>813, 330=>757, 331=>634, 332=>787, 333=>612, 334=>787, 335=>612, 336=>787, 337=>612, 340=>695, - 341=>411, 342=>695, 343=>411, 344=>695, 345=>411, 346=>635, 347=>521, 348=>635, 349=>521, 350=>635, 351=>521, 354=>611, 355=>392, 356=>611, 357=>392, 358=>611, - 359=>392, 360=>732, 361=>634, 362=>732, 363=>634, 364=>732, 365=>634, 366=>732, 367=>634, 368=>732, 369=>634, 370=>732, 371=>634, 372=>989, 373=>818, 374=>611, - 375=>592, 377=>685, 378=>525, 379=>685, 380=>525, 383=>352, 384=>635, 385=>735, 386=>686, 387=>635, 390=>698, 391=>698, 392=>550, 393=>775, 394=>824, 395=>686, - 396=>635, 397=>612, 398=>632, 399=>787, 400=>585, 401=>575, 403=>775, 404=>685, 405=>965, 406=>354, 407=>295, 408=>690, 409=>526, 410=>278, 413=>748, 414=>634, - 415=>787, 416=>934, 417=>757, 420=>652, 421=>635, 423=>635, 424=>521, 425=>632, 427=>392, 428=>611, 429=>392, 430=>611, 431=>879, 432=>779, 433=>764, 434=>721, - 435=>696, 436=>805, 437=>685, 438=>525, 448=>295, 449=>492, 450=>459, 451=>295, 452=>1422, 453=>1299, 454=>1154, 455=>835, 456=>787, 457=>457, 458=>931, 459=>924, - 460=>797, 461=>684, 462=>613, 463=>295, 464=>278, 465=>787, 466=>612, 467=>732, 468=>634, 469=>732, 470=>634, 471=>732, 472=>634, 473=>732, 474=>634, 475=>732, - 476=>634, 477=>615, 478=>684, 479=>613, 480=>684, 481=>613, 482=>974, 483=>982, 486=>775, 487=>600, 488=>656, 489=>579, 490=>787, 491=>612, 492=>787, 493=>612, - 496=>278, 497=>1422, 498=>1299, 499=>1154, 500=>775, 501=>600, 504=>748, 505=>634, 506=>684, 507=>613, 508=>974, 509=>982, 510=>787, 511=>612, 512=>684, 513=>613, - 514=>684, 515=>613, 516=>632, 517=>615, 518=>632, 519=>615, 520=>295, 521=>278, 522=>295, 523=>278, 524=>787, 525=>612, 526=>787, 527=>612, 528=>695, 529=>411, - 530=>695, 531=>411, 532=>732, 533=>634, 534=>732, 535=>634, 536=>635, 537=>521, 538=>611, 539=>392, 542=>752, 543=>634, 550=>684, 551=>613, 552=>632, 553=>615, - 554=>787, 555=>612, 556=>787, 557=>612, 558=>787, 559=>612, 560=>787, 561=>612, 562=>611, 563=>592, 567=>278, 568=>1032, 569=>1032, 581=>684, 592=>614, 593=>635, - 594=>635, 595=>635, 596=>550, 598=>635, 599=>727, 600=>615, 601=>615, 603=>541, 604=>541, 607=>326, 608=>637, 609=>635, 611=>685, 613=>634, 616=>372, 617=>387, - 623=>974, 624=>974, 628=>634, 629=>612, 640=>602, 641=>602, 649=>634, 650=>618, 651=>598, 652=>592, 653=>818, 654=>592, 665=>580, 668=>661, 670=>667, 671=>583, - 675=>1014, 678=>824, 682=>641, 683=>654, 699=>318, 700=>318, 702=>307, 711=>500, 713=>500, 714=>483, 715=>500, 717=>500, 718=>500, 719=>483, 728=>500, 729=>500, - 730=>500, 731=>500, 733=>500, 755=>500, 759=>500, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, - 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 795=>0, 803=>0, 804=>0, - 805=>0, 806=>0, 807=>0, 808=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, - 824=>0, 831=>0, 847=>0, 856=>0, 860=>0, 861=>0, 865=>0, 884=>278, 885=>278, 890=>361, 891=>549, 892=>550, 893=>549, 894=>337, 900=>483, 901=>500, - 902=>692, 903=>318, 904=>746, 905=>871, 906=>408, 908=>813, 910=>825, 911=>826, 912=>387, 913=>684, 914=>655, 915=>557, 916=>684, 917=>632, 918=>685, 919=>752, - 920=>787, 921=>295, 922=>656, 923=>684, 924=>863, 925=>748, 926=>632, 927=>787, 928=>752, 929=>603, 931=>632, 932=>611, 933=>611, 934=>787, 935=>685, 936=>787, - 937=>764, 938=>295, 939=>611, 940=>659, 941=>541, 942=>654, 943=>387, 944=>579, 945=>659, 946=>638, 947=>592, 948=>612, 949=>541, 950=>544, 951=>634, 952=>612, - 953=>387, 954=>604, 955=>592, 956=>636, 957=>559, 958=>558, 959=>612, 960=>602, 961=>635, 962=>587, 963=>634, 964=>602, 965=>579, 966=>660, 967=>592, 968=>660, - 969=>837, 970=>387, 971=>579, 972=>612, 973=>579, 974=>837, 988=>575, 1010=>550, 1011=>278, 1012=>787, 1013=>615, 1014=>615, 1015=>605, 1016=>635, 1017=>698, 1021=>698, - 1022=>698, 1023=>698, 1024=>632, 1025=>632, 1026=>786, 1028=>698, 1029=>635, 1030=>295, 1031=>295, 1032=>295, 1033=>1094, 1034=>1045, 1035=>786, 1037=>748, 1038=>609, 1040=>684, - 1041=>686, 1042=>655, 1043=>557, 1044=>776, 1045=>632, 1046=>863, 1047=>636, 1048=>748, 1049=>748, 1050=>656, 1051=>752, 1052=>863, 1053=>752, 1054=>787, 1055=>752, 1056=>603, - 1057=>698, 1058=>611, 1059=>609, 1060=>787, 1061=>685, 1062=>776, 1063=>686, 1064=>1003, 1065=>1025, 1066=>833, 1067=>882, 1068=>686, 1069=>698, 1070=>1031, 1071=>695, 1072=>613, - 1073=>612, 1074=>586, 1075=>491, 1076=>672, 1077=>615, 1078=>733, 1079=>541, 1080=>657, 1081=>657, 1082=>604, 1083=>639, 1084=>754, 1085=>661, 1086=>612, 1087=>660, 1088=>635, - 1089=>550, 1090=>529, 1091=>592, 1092=>917, 1093=>592, 1094=>681, 1095=>591, 1096=>873, 1097=>893, 1098=>703, 1099=>765, 1100=>589, 1101=>549, 1102=>813, 1103=>602, 1104=>615, - 1105=>615, 1106=>644, 1107=>491, 1108=>549, 1109=>521, 1110=>278, 1111=>278, 1112=>278, 1113=>898, 1114=>892, 1115=>637, 1117=>657, 1118=>592, 1119=>662, 1121=>837, 1124=>942, - 1125=>749, 1136=>787, 1137=>660, 1138=>787, 1168=>557, 1169=>491, 1176=>636, 1177=>541, 1188=>1014, 1189=>868, 1194=>698, 1195=>550, 1198=>611, 1199=>592, 1204=>934, 1205=>809, - 1210=>686, 1211=>634, 1216=>278, 1217=>863, 1218=>733, 1232=>684, 1233=>613, 1234=>684, 1235=>613, 1236=>974, 1237=>982, 1238=>632, 1239=>615, 1240=>787, 1241=>615, 1242=>787, - 1243=>615, 1244=>863, 1245=>733, 1246=>636, 1247=>541, 1250=>748, 1251=>657, 1252=>748, 1253=>657, 1254=>787, 1255=>612, 1256=>787, 1257=>612, 1258=>787, 1259=>612, 1260=>698, - 1261=>549, 1262=>609, 1263=>592, 1264=>609, 1265=>592, 1266=>609, 1267=>592, 1268=>686, 1269=>591, 1272=>882, 1273=>765, 1352=>732, 1357=>732, 1359=>635, 1363=>787, 1365=>787, - 1370=>318, 1373=>392, 1377=>974, 1387=>634, 1389=>1002, 1391=>634, 1392=>634, 1397=>278, 1400=>634, 1402=>974, 1405=>634, 1407=>1002, 1408=>634, 1409=>600, 1411=>1002, 1413=>612, - 1417=>337, 1652=>292, 7426=>982, 7428=>550, 7433=>278, 7435=>604, 7437=>754, 7438=>650, 7439=>612, 7440=>550, 7441=>684, 7442=>684, 7443=>684, 7444=>1023, 7446=>612, 7447=>612, - 7456=>592, 7457=>818, 7458=>525, 7462=>525, 7463=>592, 7464=>654, 7543=>635, 7680=>684, 7681=>613, 7682=>655, 7683=>635, 7684=>655, 7685=>635, 7686=>655, 7687=>635, 7688=>698, - 7689=>550, 7690=>770, 7691=>635, 7692=>770, 7693=>635, 7694=>770, 7695=>635, 7696=>770, 7697=>635, 7698=>770, 7699=>635, 7700=>632, 7701=>615, 7702=>632, 7703=>615, 7704=>632, - 7705=>615, 7706=>632, 7707=>615, 7708=>632, 7709=>615, 7710=>575, 7711=>352, 7712=>775, 7713=>600, 7714=>752, 7715=>634, 7716=>752, 7717=>634, 7718=>752, 7719=>634, 7720=>752, - 7721=>634, 7722=>752, 7723=>634, 7724=>295, 7725=>278, 7726=>295, 7727=>278, 7728=>656, 7729=>579, 7730=>656, 7731=>579, 7732=>656, 7733=>579, 7734=>557, 7735=>278, 7736=>557, - 7737=>278, 7738=>557, 7739=>278, 7740=>557, 7741=>278, 7742=>863, 7743=>974, 7744=>863, 7745=>974, 7746=>863, 7747=>974, 7748=>748, 7749=>634, 7750=>748, 7751=>634, 7752=>748, - 7753=>634, 7754=>748, 7755=>634, 7756=>787, 7757=>612, 7758=>787, 7759=>612, 7760=>787, 7761=>612, 7762=>787, 7763=>612, 7764=>603, 7765=>635, 7766=>603, 7767=>635, 7768=>695, - 7769=>411, 7770=>695, 7771=>411, 7772=>695, 7773=>411, 7774=>695, 7775=>411, 7776=>635, 7777=>521, 7778=>635, 7779=>521, 7780=>635, 7781=>521, 7782=>635, 7783=>521, 7784=>635, - 7785=>521, 7786=>611, 7787=>392, 7788=>611, 7789=>392, 7790=>611, 7791=>392, 7792=>611, 7793=>392, 7794=>732, 7795=>634, 7796=>732, 7797=>634, 7798=>732, 7799=>634, 7800=>732, - 7801=>634, 7802=>732, 7803=>634, 7804=>684, 7805=>592, 7806=>684, 7807=>592, 7808=>989, 7809=>818, 7810=>989, 7811=>818, 7812=>989, 7813=>818, 7814=>989, 7815=>818, 7816=>989, - 7817=>818, 7818=>685, 7819=>592, 7820=>685, 7821=>592, 7822=>611, 7823=>592, 7824=>685, 7825=>525, 7826=>685, 7827=>525, 7828=>685, 7829=>525, 7830=>634, 7831=>392, 7832=>818, - 7833=>592, 7834=>613, 7835=>352, 7840=>684, 7841=>613, 7842=>684, 7843=>613, 7844=>684, 7845=>613, 7846=>684, 7847=>613, 7848=>684, 7849=>613, 7850=>684, 7851=>613, 7852=>684, - 7853=>613, 7854=>684, 7855=>613, 7856=>684, 7857=>613, 7858=>684, 7859=>613, 7860=>684, 7861=>613, 7862=>684, 7863=>613, 7864=>632, 7865=>615, 7866=>632, 7867=>615, 7868=>632, - 7869=>615, 7870=>632, 7871=>615, 7872=>632, 7873=>615, 7874=>632, 7875=>615, 7876=>632, 7877=>615, 7878=>632, 7879=>615, 7880=>295, 7881=>278, 7882=>295, 7883=>278, 7884=>787, - 7885=>612, 7886=>787, 7887=>612, 7888=>787, 7889=>612, 7890=>787, 7891=>612, 7892=>787, 7893=>612, 7894=>787, 7895=>612, 7896=>787, 7897=>612, 7898=>934, 7899=>757, 7900=>934, - 7901=>757, 7902=>934, 7903=>757, 7904=>934, 7905=>757, 7906=>934, 7907=>757, 7908=>732, 7909=>634, 7910=>732, 7911=>634, 7912=>879, 7913=>779, 7914=>879, 7915=>779, 7916=>879, - 7917=>779, 7918=>879, 7919=>779, 7920=>879, 7921=>779, 7922=>611, 7923=>592, 7924=>611, 7925=>592, 7926=>611, 7927=>592, 7928=>611, 7929=>592, 7936=>659, 7937=>659, 7938=>659, - 7939=>659, 7940=>659, 7941=>659, 7942=>659, 7943=>659, 7944=>684, 7945=>684, 7946=>877, 7947=>877, 7948=>769, 7949=>801, 7950=>708, 7951=>743, 7952=>541, 7953=>541, 7954=>541, - 7955=>541, 7956=>541, 7957=>541, 7960=>711, 7961=>711, 7962=>966, 7963=>975, 7964=>898, 7965=>928, 7968=>634, 7969=>634, 7970=>634, 7971=>634, 7972=>634, 7973=>634, 7974=>634, - 7975=>634, 7976=>837, 7977=>835, 7978=>1086, 7979=>1089, 7980=>1027, 7981=>1051, 7982=>934, 7983=>947, 7984=>338, 7985=>338, 7986=>338, 7987=>338, 7988=>338, 7989=>338, 7990=>338, - 7991=>338, 7992=>380, 7993=>374, 7994=>635, 7995=>635, 7996=>570, 7997=>600, 7998=>489, 7999=>493, 8000=>612, 8001=>612, 8002=>612, 8003=>612, 8004=>612, 8005=>612, 8008=>804, - 8009=>848, 8010=>1095, 8011=>1100, 8012=>938, 8013=>970, 8016=>579, 8017=>579, 8018=>579, 8019=>579, 8020=>579, 8021=>579, 8022=>579, 8023=>579, 8025=>784, 8027=>998, 8029=>1012, - 8031=>897, 8032=>837, 8033=>837, 8034=>837, 8035=>837, 8036=>837, 8037=>837, 8038=>837, 8039=>837, 8040=>802, 8041=>843, 8042=>1089, 8043=>1095, 8044=>946, 8045=>972, 8046=>921, - 8047=>952, 8048=>659, 8049=>659, 8050=>541, 8051=>548, 8052=>634, 8053=>654, 8054=>338, 8055=>338, 8056=>612, 8057=>612, 8058=>579, 8059=>579, 8060=>837, 8061=>837, 8064=>659, - 8065=>659, 8066=>659, 8067=>659, 8068=>659, 8069=>659, 8070=>659, 8071=>659, 8072=>684, 8073=>684, 8074=>877, 8075=>877, 8076=>769, 8077=>801, 8078=>708, 8079=>743, 8080=>634, - 8081=>634, 8082=>634, 8083=>634, 8084=>634, 8085=>634, 8086=>634, 8087=>634, 8088=>837, 8089=>835, 8090=>1086, 8091=>1089, 8092=>1027, 8093=>1051, 8094=>934, 8095=>947, 8096=>837, - 8097=>837, 8098=>837, 8099=>837, 8100=>837, 8101=>837, 8102=>837, 8103=>837, 8104=>802, 8105=>843, 8106=>1089, 8107=>1095, 8108=>946, 8109=>972, 8110=>921, 8111=>952, 8112=>659, - 8113=>659, 8114=>659, 8115=>659, 8116=>659, 8118=>659, 8119=>659, 8120=>684, 8121=>684, 8122=>716, 8123=>692, 8124=>684, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, - 8130=>634, 8131=>634, 8132=>654, 8134=>634, 8135=>634, 8136=>805, 8137=>746, 8138=>931, 8139=>871, 8140=>752, 8141=>500, 8142=>500, 8143=>500, 8144=>338, 8145=>338, 8146=>338, - 8147=>338, 8150=>338, 8151=>338, 8152=>295, 8153=>295, 8154=>475, 8155=>408, 8157=>500, 8158=>500, 8159=>500, 8160=>579, 8161=>579, 8162=>579, 8163=>579, 8164=>635, 8165=>635, - 8166=>579, 8167=>579, 8168=>611, 8169=>611, 8170=>845, 8171=>825, 8172=>685, 8173=>500, 8174=>500, 8175=>500, 8178=>837, 8179=>837, 8180=>837, 8182=>837, 8183=>837, 8184=>941, - 8185=>813, 8186=>922, 8187=>826, 8188=>764, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, 8196=>330, 8197=>250, 8198=>167, 8199=>636, 8200=>318, 8201=>200, - 8202=>100, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>361, 8209=>361, 8210=>636, 8213=>1000, 8214=>500, 8215=>500, 8219=>318, 8223=>518, 8228=>334, 8229=>667, - 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1735, 8251=>838, 8252=>485, 8253=>531, 8254=>500, 8255=>804, 8256=>804, 8258=>1000, 8259=>500, 8260=>167, - 8261=>390, 8262=>390, 8263=>922, 8264=>733, 8265=>733, 8267=>636, 8268=>500, 8269=>500, 8270=>500, 8271=>337, 8272=>804, 8273=>500, 8274=>450, 8275=>838, 8276=>804, 8287=>222, - 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>401, 8305=>179, 8308=>401, 8320=>401, 8321=>401, 8322=>401, - 8323=>401, 8324=>401, 8363=>636, 8369=>635, 8451=>1123, 8457=>952, 8470=>1165, 8471=>1000, 8486=>764, 8487=>764, 8490=>656, 8491=>684, 8494=>854, 8498=>575, 8500=>462, 8523=>780, - 8531=>969, 8532=>969, 8543=>568, 8544=>295, 8545=>492, 8546=>689, 8547=>923, 8548=>684, 8549=>922, 8550=>1120, 8551=>1317, 8552=>917, 8553=>685, 8554=>933, 8555=>1131, 8556=>557, - 8557=>698, 8558=>770, 8559=>863, 8560=>278, 8561=>458, 8562=>637, 8563=>812, 8564=>592, 8565=>811, 8566=>991, 8567=>1170, 8568=>819, 8569=>592, 8570=>822, 8571=>1002, 8572=>278, - 8573=>550, 8574=>635, 8575=>974, 8576=>1285, 8579=>698, 8580=>549, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8596=>838, 8597=>838, 8598=>838, 8599=>838, 8600=>838, 8601=>838, - 8644=>838, 8645=>838, 8646=>838, 8647=>838, 8648=>838, 8649=>838, 8650=>838, 8704=>684, 8707=>632, 8710=>684, 8711=>684, 8722=>838, 8725=>167, 8726=>637, 8727=>626, 8728=>626, - 8756=>636, 8757=>636, 8758=>260, 8759=>636, 8764=>636, 9134=>521, 9167=>945, 10731=>494, 57344=>684, 57345=>684, 57346=>684, 57347=>684, 57348=>684, 57349=>684, 57351=>684, 57352=>684, - 57353=>684, 57354=>684, 57355=>684, 57356=>684, 57357=>684, 57358=>684, 57359=>684, 57360=>684, 57361=>684, 57362=>684, 57363=>684, 57364=>684, 64256=>689, 64257=>630, 64258=>630, 64259=>967, - 64260=>967, 64297=>838, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, - 65038=>0, 65039=>0, 65533=>1025} - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSans-ExtraLight.z'; - font[:ctg]='DejaVuSans-ExtraLight.ctg.z'; - font[:originalsize]=132684; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSans-ExtraLight.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSans-ExtraLight.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Bold.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Bold.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Bold.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Bold.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-BoldOblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-BoldOblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-BoldOblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-BoldOblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Oblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Oblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Oblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed-Oblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,287 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansCondensed') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansCondensed'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-918 -356 1513 font[:1068]]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>540}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>286, 33=>360, 34=>414, 35=>754, 36=>572, 37=>855, 38=>702, 39=>247, 40=>351, 41=>351, 42=>450, 43=>754, 44=>286, 45=>325, 46=>286, - 47=>303, 48=>572, 49=>572, 50=>572, 51=>572, 52=>572, 53=>572, 54=>572, 55=>572, 56=>572, 57=>572, 58=>303, 59=>303, 60=>754, 61=>754, 62=>754, - 63=>478, 64=>900, 65=>615, 66=>617, 67=>628, 68=>693, 69=>568, 70=>518, 71=>697, 72=>677, 73=>265, 74=>265, 75=>590, 76=>501, 77=>776, 78=>673, - 79=>708, 80=>542, 81=>708, 82=>625, 83=>571, 84=>549, 85=>659, 86=>615, 87=>890, 88=>616, 89=>549, 90=>616, 91=>351, 92=>303, 93=>351, 94=>754, - 95=>450, 96=>450, 97=>551, 98=>571, 99=>495, 100=>571, 101=>554, 102=>316, 103=>571, 104=>570, 105=>250, 106=>250, 107=>521, 108=>250, 109=>876, 110=>570, - 111=>550, 112=>571, 113=>571, 114=>370, 115=>469, 116=>353, 117=>570, 118=>532, 119=>736, 120=>532, 121=>532, 122=>472, 123=>572, 124=>303, 125=>572, 126=>754, - 8364=>572, 1027=>549, 8218=>286, 402=>316, 8222=>466, 8230=>900, 8224=>450, 8225=>450, 710=>450, 8240=>1208, 352=>571, 8249=>360, 338=>962, 1036=>639, 381=>616, 1039=>677, - 8216=>286, 8217=>286, 8220=>466, 8221=>466, 8226=>531, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>469, 8250=>360, 339=>920, 1116=>543, 382=>472, 376=>549, 160=>286, - 161=>360, 162=>572, 163=>572, 164=>572, 165=>572, 166=>303, 167=>450, 168=>450, 169=>900, 170=>424, 171=>550, 172=>754, 173=>325, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>360, 179=>360, 180=>450, 181=>572, 182=>572, 183=>286, 184=>450, 185=>360, 186=>424, 187=>550, 188=>872, 189=>872, 190=>872, 191=>478, 192=>615, - 193=>615, 194=>615, 195=>615, 196=>615, 197=>615, 198=>876, 199=>628, 200=>568, 201=>568, 202=>568, 203=>568, 204=>265, 205=>265, 206=>265, 207=>265, 208=>697, - 209=>673, 210=>708, 211=>708, 212=>708, 213=>708, 214=>708, 215=>754, 216=>708, 217=>659, 218=>659, 219=>659, 220=>659, 221=>549, 222=>544, 223=>567, 224=>551, - 225=>551, 226=>551, 227=>551, 228=>551, 229=>551, 230=>883, 231=>495, 232=>554, 233=>554, 234=>554, 235=>554, 236=>250, 237=>250, 238=>250, 239=>250, 240=>550, - 241=>570, 242=>550, 243=>550, 244=>550, 245=>550, 246=>550, 247=>754, 248=>550, 249=>570, 250=>570, 251=>570, 252=>570, 253=>532, 254=>571, 255=>532, 256=>615, - 257=>551, 258=>615, 259=>551, 260=>615, 261=>551, 262=>628, 263=>495, 264=>628, 265=>495, 266=>628, 267=>495, 268=>628, 269=>495, 270=>693, 271=>571, 272=>697, - 273=>571, 274=>568, 275=>554, 276=>568, 277=>554, 278=>568, 279=>554, 280=>568, 281=>554, 282=>568, 283=>554, 284=>697, 285=>571, 286=>697, 287=>571, 288=>697, - 289=>571, 290=>697, 291=>571, 292=>677, 293=>570, 294=>824, 295=>625, 296=>265, 297=>250, 298=>265, 299=>250, 300=>265, 301=>250, 302=>265, 303=>250, 304=>265, - 305=>250, 306=>531, 307=>500, 308=>265, 309=>250, 310=>590, 311=>521, 312=>521, 313=>501, 314=>264, 315=>501, 316=>250, 317=>501, 318=>337, 319=>501, 320=>308, - 321=>505, 322=>255, 323=>673, 324=>570, 325=>673, 326=>570, 327=>673, 328=>570, 329=>732, 330=>673, 331=>570, 332=>708, 333=>550, 334=>708, 335=>550, 336=>708, - 337=>550, 340=>625, 341=>370, 342=>625, 343=>370, 344=>625, 345=>370, 346=>571, 347=>469, 348=>571, 349=>469, 350=>571, 351=>469, 354=>549, 355=>353, 356=>549, - 357=>353, 358=>549, 359=>353, 360=>659, 361=>570, 362=>659, 363=>570, 364=>659, 365=>570, 366=>659, 367=>570, 368=>659, 369=>570, 370=>659, 371=>570, 372=>890, - 373=>736, 374=>549, 375=>532, 377=>616, 378=>472, 379=>616, 380=>472, 383=>316, 384=>571, 385=>661, 386=>617, 387=>571, 388=>617, 389=>571, 390=>633, 391=>628, - 392=>495, 393=>697, 394=>737, 395=>617, 396=>571, 397=>550, 398=>568, 399=>708, 400=>553, 401=>518, 403=>697, 404=>618, 405=>885, 406=>318, 407=>265, 408=>671, - 409=>521, 410=>250, 411=>532, 412=>876, 413=>673, 414=>570, 415=>708, 416=>822, 417=>550, 418=>854, 419=>683, 420=>586, 421=>571, 422=>625, 423=>571, 424=>469, - 425=>568, 426=>302, 427=>353, 428=>549, 429=>353, 430=>549, 431=>772, 432=>570, 433=>688, 434=>648, 435=>669, 436=>656, 437=>616, 438=>472, 439=>599, 440=>599, - 441=>520, 442=>472, 443=>572, 444=>599, 445=>520, 446=>459, 447=>571, 448=>265, 449=>443, 450=>413, 451=>266, 452=>1279, 453=>1169, 454=>1039, 455=>751, 456=>708, - 457=>411, 458=>838, 459=>831, 460=>717, 461=>615, 462=>551, 463=>265, 464=>250, 465=>708, 466=>550, 467=>659, 468=>570, 469=>659, 470=>570, 471=>659, 472=>570, - 473=>659, 474=>570, 475=>659, 476=>570, 477=>554, 478=>615, 479=>551, 480=>615, 481=>551, 482=>876, 483=>883, 484=>697, 485=>571, 486=>697, 487=>571, 488=>590, - 489=>521, 490=>708, 491=>550, 492=>708, 493=>550, 494=>599, 495=>520, 496=>250, 497=>1279, 498=>1169, 499=>1039, 500=>697, 501=>571, 502=>1001, 503=>614, 504=>673, - 505=>570, 506=>615, 507=>551, 508=>876, 509=>883, 510=>708, 511=>550, 512=>615, 513=>551, 514=>615, 515=>551, 516=>568, 517=>554, 518=>568, 519=>554, 520=>265, - 521=>250, 522=>265, 523=>250, 524=>708, 525=>550, 526=>708, 527=>550, 528=>625, 529=>370, 530=>625, 531=>370, 532=>659, 533=>570, 534=>659, 535=>570, 536=>571, - 537=>469, 538=>549, 539=>353, 540=>564, 541=>469, 542=>677, 543=>570, 544=>662, 545=>754, 546=>628, 547=>549, 548=>616, 549=>472, 550=>615, 551=>551, 552=>568, - 553=>554, 554=>708, 555=>550, 556=>708, 557=>550, 558=>708, 559=>550, 560=>708, 561=>550, 562=>549, 563=>532, 564=>427, 565=>758, 566=>429, 567=>250, 568=>898, - 569=>898, 570=>615, 571=>628, 572=>495, 573=>501, 574=>549, 575=>469, 576=>472, 577=>542, 578=>431, 579=>617, 580=>659, 581=>615, 582=>568, 583=>554, 584=>265, - 585=>250, 586=>703, 587=>571, 588=>625, 589=>370, 590=>549, 591=>532, 592=>540, 593=>571, 594=>571, 595=>571, 596=>494, 597=>495, 598=>571, 599=>626, 600=>554, - 601=>554, 602=>737, 603=>486, 604=>479, 605=>698, 606=>598, 607=>250, 608=>626, 609=>571, 610=>566, 611=>536, 612=>536, 613=>570, 614=>570, 615=>570, 616=>250, - 617=>304, 618=>334, 619=>356, 620=>438, 621=>250, 622=>635, 623=>876, 624=>876, 625=>876, 626=>581, 627=>578, 628=>570, 629=>550, 630=>772, 631=>655, 632=>593, - 633=>373, 634=>373, 635=>372, 636=>370, 637=>369, 638=>393, 639=>477, 640=>543, 641=>543, 642=>469, 643=>302, 644=>302, 645=>415, 646=>302, 647=>353, 648=>353, - 649=>570, 650=>556, 651=>538, 652=>532, 653=>736, 654=>532, 655=>549, 656=>472, 657=>472, 658=>520, 659=>520, 660=>459, 661=>459, 662=>459, 663=>459, 664=>708, - 665=>521, 666=>598, 667=>637, 668=>588, 669=>263, 670=>600, 671=>456, 672=>654, 673=>459, 674=>459, 675=>913, 676=>952, 677=>911, 678=>742, 679=>549, 680=>700, - 681=>763, 682=>576, 683=>589, 684=>463, 685=>463, 686=>513, 687=>597, 688=>364, 689=>359, 690=>157, 691=>233, 692=>266, 693=>266, 694=>341, 695=>463, 696=>335, - 697=>250, 698=>414, 699=>286, 700=>286, 701=>286, 702=>276, 703=>276, 704=>333, 705=>333, 706=>450, 707=>450, 708=>450, 709=>450, 711=>450, 712=>247, 713=>450, - 714=>450, 715=>450, 716=>247, 717=>450, 718=>450, 719=>450, 720=>303, 721=>303, 722=>276, 723=>276, 724=>450, 725=>450, 726=>371, 727=>450, 728=>450, 729=>450, - 730=>450, 731=>450, 733=>450, 734=>284, 735=>450, 736=>383, 737=>149, 738=>335, 739=>399, 740=>333, 741=>444, 742=>444, 743=>444, 744=>444, 745=>444, 748=>450, - 749=>450, 750=>450, 755=>450, 759=>450, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, - 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, - 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, - 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, - 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, - 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 850=>0, 851=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, - 884=>250, 885=>250, 890=>450, 891=>494, 892=>495, 893=>494, 894=>303, 900=>450, 901=>450, 902=>623, 903=>286, 904=>671, 905=>784, 906=>367, 908=>731, 910=>742, - 911=>743, 912=>304, 913=>615, 914=>617, 915=>501, 916=>615, 917=>568, 918=>616, 919=>677, 920=>708, 921=>265, 922=>590, 923=>615, 924=>776, 925=>673, 926=>568, - 927=>708, 928=>677, 929=>542, 931=>568, 932=>549, 933=>549, 934=>708, 935=>616, 936=>708, 937=>688, 938=>265, 939=>549, 940=>593, 941=>493, 942=>589, 943=>304, - 944=>521, 945=>593, 946=>574, 947=>532, 948=>550, 949=>486, 950=>489, 951=>570, 952=>550, 953=>304, 954=>530, 955=>532, 956=>572, 957=>502, 958=>501, 959=>550, - 960=>542, 961=>571, 962=>528, 963=>570, 964=>542, 965=>521, 966=>593, 967=>520, 968=>593, 969=>753, 970=>304, 971=>521, 972=>550, 973=>521, 974=>753, 976=>553, - 977=>557, 978=>628, 979=>758, 980=>628, 981=>593, 982=>753, 983=>597, 984=>708, 985=>550, 986=>583, 987=>528, 988=>518, 989=>413, 990=>593, 991=>593, 992=>778, - 993=>564, 994=>840, 995=>753, 996=>682, 997=>593, 998=>712, 999=>553, 1000=>618, 1001=>546, 1002=>690, 1003=>563, 1004=>629, 1005=>550, 1006=>549, 1007=>482, 1008=>597, - 1009=>571, 1010=>495, 1011=>250, 1012=>708, 1013=>554, 1014=>554, 1015=>544, 1016=>571, 1017=>628, 1018=>776, 1019=>585, 1020=>571, 1021=>633, 1022=>628, 1023=>633, 1024=>568, - 1025=>568, 1026=>708, 1028=>628, 1029=>571, 1030=>265, 1031=>265, 1032=>265, 1033=>984, 1034=>940, 1035=>708, 1037=>673, 1038=>548, 1040=>615, 1041=>617, 1042=>617, 1043=>549, - 1044=>703, 1045=>568, 1046=>969, 1047=>577, 1048=>673, 1049=>673, 1050=>639, 1051=>677, 1052=>776, 1053=>677, 1054=>708, 1055=>677, 1056=>542, 1057=>628, 1058=>549, 1059=>548, - 1060=>774, 1061=>616, 1062=>699, 1063=>617, 1064=>962, 1065=>984, 1066=>749, 1067=>794, 1068=>617, 1069=>628, 1070=>971, 1071=>625, 1072=>551, 1073=>555, 1074=>530, 1075=>473, - 1076=>622, 1077=>554, 1078=>811, 1079=>479, 1080=>584, 1081=>584, 1082=>543, 1083=>575, 1084=>679, 1085=>588, 1086=>550, 1087=>588, 1088=>571, 1089=>495, 1090=>524, 1091=>532, - 1092=>769, 1093=>532, 1094=>612, 1095=>532, 1096=>823, 1097=>848, 1098=>636, 1099=>710, 1100=>530, 1101=>494, 1102=>757, 1103=>541, 1104=>554, 1105=>554, 1106=>563, 1107=>473, - 1108=>494, 1109=>469, 1110=>250, 1111=>250, 1112=>250, 1113=>812, 1114=>809, 1115=>586, 1117=>584, 1118=>532, 1119=>588, 1120=>840, 1121=>753, 1122=>693, 1123=>604, 1124=>848, - 1125=>674, 1126=>791, 1127=>705, 1128=>1043, 1129=>901, 1130=>708, 1131=>550, 1132=>924, 1133=>742, 1134=>572, 1135=>486, 1136=>771, 1137=>789, 1138=>708, 1139=>533, 1140=>703, - 1141=>598, 1142=>703, 1143=>598, 1144=>893, 1145=>813, 1146=>857, 1147=>682, 1148=>1062, 1149=>925, 1150=>840, 1151=>753, 1152=>628, 1153=>495, 1154=>452, 1155=>0, 1156=>0, - 1157=>0, 1158=>0, 1160=>376, 1161=>376, 1162=>695, 1163=>609, 1164=>617, 1165=>530, 1166=>542, 1167=>571, 1168=>549, 1169=>473, 1170=>607, 1171=>500, 1172=>562, 1173=>477, - 1174=>969, 1175=>811, 1176=>577, 1177=>479, 1178=>639, 1179=>543, 1180=>639, 1181=>543, 1182=>639, 1183=>543, 1184=>771, 1185=>748, 1186=>677, 1187=>594, 1188=>913, 1189=>789, - 1190=>973, 1191=>824, 1192=>716, 1193=>586, 1194=>628, 1195=>495, 1196=>549, 1197=>476, 1198=>549, 1199=>532, 1200=>549, 1201=>532, 1202=>616, 1203=>532, 1204=>840, 1205=>726, - 1206=>617, 1207=>532, 1208=>617, 1209=>532, 1210=>617, 1211=>570, 1212=>847, 1213=>655, 1214=>847, 1215=>655, 1216=>265, 1217=>969, 1218=>811, 1219=>590, 1220=>543, 1221=>698, - 1222=>603, 1223=>677, 1224=>594, 1225=>699, 1226=>612, 1227=>617, 1228=>532, 1229=>799, 1230=>697, 1231=>250, 1232=>615, 1233=>551, 1234=>615, 1235=>551, 1236=>876, 1237=>883, - 1238=>568, 1239=>554, 1240=>708, 1241=>554, 1242=>708, 1243=>554, 1244=>969, 1245=>811, 1246=>577, 1247=>479, 1248=>599, 1249=>520, 1250=>673, 1251=>584, 1252=>673, 1253=>584, - 1254=>708, 1255=>550, 1256=>708, 1257=>550, 1258=>708, 1259=>550, 1260=>628, 1261=>494, 1262=>548, 1263=>532, 1264=>548, 1265=>532, 1266=>548, 1267=>532, 1268=>617, 1269=>532, - 1270=>501, 1271=>442, 1272=>794, 1273=>710, 1274=>607, 1275=>500, 1276=>616, 1277=>532, 1278=>616, 1279=>532, 1280=>617, 1281=>530, 1282=>905, 1283=>807, 1284=>877, 1285=>782, - 1286=>611, 1287=>529, 1288=>964, 1289=>861, 1290=>965, 1291=>870, 1292=>697, 1293=>593, 1294=>695, 1295=>640, 1296=>553, 1297=>486, 1298=>677, 1299=>575, 1329=>780, 1330=>659, - 1331=>794, 1332=>794, 1333=>659, 1334=>579, 1335=>613, 1336=>659, 1337=>765, 1338=>794, 1339=>659, 1340=>501, 1341=>741, 1342=>888, 1343=>659, 1344=>636, 1345=>579, 1346=>794, - 1347=>699, 1348=>794, 1349=>659, 1350=>756, 1351=>659, 1352=>659, 1353=>659, 1354=>711, 1355=>579, 1356=>794, 1357=>659, 1358=>794, 1359=>571, 1360=>659, 1361=>659, 1362=>719, - 1363=>774, 1364=>711, 1365=>708, 1366=>571, 1369=>276, 1370=>286, 1371=>450, 1372=>450, 1373=>352, 1374=>474, 1375=>450, 1377=>876, 1378=>570, 1379=>686, 1380=>690, 1381=>570, - 1382=>627, 1383=>479, 1384=>570, 1385=>630, 1386=>627, 1387=>570, 1388=>363, 1389=>804, 1390=>576, 1391=>570, 1392=>570, 1393=>571, 1394=>631, 1395=>570, 1396=>593, 1397=>250, - 1398=>684, 1399=>464, 1400=>570, 1401=>407, 1402=>876, 1403=>464, 1404=>691, 1405=>570, 1406=>626, 1407=>876, 1408=>570, 1409=>571, 1410=>451, 1411=>876, 1412=>583, 1413=>550, - 1414=>566, 1415=>686, 1417=>303, 1418=>390, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, - 1469=>0, 1471=>0, 1472=>265, 1473=>0, 1474=>0, 1475=>265, 1478=>410, 1479=>0, 1488=>566, 1489=>547, 1490=>403, 1491=>534, 1492=>576, 1493=>245, 1494=>380, 1495=>576, - 1496=>583, 1497=>245, 1498=>532, 1499=>500, 1500=>539, 1501=>576, 1502=>593, 1503=>245, 1504=>397, 1505=>629, 1506=>572, 1507=>576, 1508=>543, 1509=>468, 1510=>523, 1511=>596, - 1512=>532, 1513=>727, 1514=>591, 1520=>423, 1521=>409, 1522=>423, 1548=>290, 1557=>0, 1563=>286, 1567=>478, 1569=>423, 1570=>250, 1571=>250, 1572=>435, 1573=>250, 1574=>704, - 1575=>250, 1576=>847, 1577=>471, 1578=>847, 1579=>847, 1580=>581, 1581=>581, 1582=>581, 1583=>400, 1584=>400, 1585=>435, 1586=>435, 1587=>1099, 1588=>1099, 1589=>1088, 1590=>1088, - 1591=>832, 1592=>832, 1593=>537, 1594=>537, 1600=>264, 1601=>933, 1602=>698, 1603=>742, 1604=>654, 1605=>557, 1606=>661, 1607=>471, 1608=>435, 1609=>704, 1610=>704, 1611=>0, - 1612=>0, 1613=>0, 1614=>0, 1615=>0, 1616=>0, 1617=>0, 1618=>0, 1619=>0, 1620=>0, 1621=>0, 1626=>450, 1632=>483, 1633=>483, 1634=>483, 1635=>483, 1636=>483, - 1637=>483, 1638=>483, 1639=>483, 1640=>483, 1641=>483, 1642=>483, 1643=>292, 1644=>286, 1645=>490, 1646=>847, 1647=>698, 1652=>263, 1657=>847, 1658=>847, 1659=>847, 1660=>847, - 1661=>847, 1662=>847, 1663=>847, 1664=>847, 1665=>581, 1666=>581, 1667=>581, 1668=>581, 1669=>581, 1670=>581, 1671=>581, 1681=>435, 1682=>435, 1685=>549, 1688=>435, 1697=>933, - 1700=>933, 1702=>933, 1705=>805, 1711=>805, 1717=>654, 1722=>661, 1727=>581, 1734=>435, 1740=>704, 1742=>704, 1749=>471, 1776=>483, 1777=>483, 1778=>483, 1779=>483, 1780=>483, - 1781=>483, 1782=>483, 1783=>483, 1784=>483, 1785=>483, 3647=>586, 3713=>603, 3714=>615, 3716=>619, 3719=>434, 3720=>565, 3722=>615, 3725=>619, 3732=>602, 3733=>577, 3734=>580, - 3735=>589, 3737=>593, 3738=>563, 3739=>563, 3740=>670, 3741=>690, 3742=>618, 3743=>618, 3745=>631, 3746=>619, 3747=>615, 3749=>584, 3751=>569, 3754=>633, 3755=>737, 3757=>569, - 3758=>615, 3759=>708, 3760=>569, 3761=>0, 3762=>485, 3763=>485, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>597, 3776=>337, - 3777=>591, 3778=>414, 3779=>492, 3780=>442, 3782=>606, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>925, 3805=>925, 5121=>615, 5122=>615, 5123=>615, - 5124=>615, 5125=>692, 5126=>692, 5127=>692, 5129=>692, 5130=>692, 5131=>692, 5132=>751, 5133=>751, 5134=>751, 5135=>751, 5136=>751, 5137=>751, 5138=>870, 5139=>906, 5140=>870, - 5141=>906, 5142=>692, 5143=>870, 5144=>906, 5145=>870, 5146=>906, 5147=>692, 5149=>230, 5150=>488, 5151=>381, 5152=>381, 5153=>350, 5154=>350, 5155=>354, 5156=>350, 5157=>419, - 5158=>347, 5159=>230, 5160=>350, 5161=>350, 5162=>350, 5163=>980, 5164=>817, 5165=>857, 5166=>1005, 5167=>615, 5168=>615, 5169=>615, 5170=>615, 5171=>656, 5172=>656, 5173=>656, - 5175=>656, 5176=>656, 5177=>656, 5178=>751, 5179=>751, 5180=>751, 5181=>751, 5182=>751, 5183=>751, 5184=>870, 5185=>906, 5186=>870, 5187=>906, 5188=>870, 5189=>906, 5190=>870, - 5191=>906, 5192=>656, 5193=>457, 5194=>172, 5196=>659, 5197=>659, 5198=>659, 5199=>659, 5200=>657, 5201=>657, 5202=>657, 5204=>657, 5205=>657, 5206=>657, 5207=>829, 5208=>800, - 5209=>829, 5210=>800, 5211=>829, 5212=>800, 5213=>835, 5214=>810, 5215=>835, 5216=>810, 5217=>853, 5218=>810, 5219=>853, 5220=>810, 5221=>853, 5222=>457, 5223=>790, 5224=>790, - 5225=>779, 5226=>801, 5227=>565, 5228=>565, 5229=>565, 5230=>565, 5231=>565, 5232=>625, 5233=>565, 5234=>565, 5235=>565, 5236=>773, 5237=>693, 5238=>733, 5239=>734, 5240=>733, - 5241=>734, 5242=>773, 5243=>693, 5244=>773, 5245=>693, 5246=>733, 5247=>734, 5248=>733, 5249=>734, 5250=>733, 5251=>366, 5252=>366, 5253=>675, 5254=>697, 5255=>675, 5256=>697, - 5257=>565, 5258=>565, 5259=>565, 5260=>565, 5261=>565, 5262=>565, 5263=>565, 5264=>565, 5265=>565, 5266=>773, 5267=>693, 5268=>733, 5269=>734, 5270=>733, 5271=>734, 5272=>773, - 5273=>693, 5274=>773, 5275=>693, 5276=>733, 5277=>734, 5278=>733, 5279=>734, 5280=>733, 5281=>391, 5282=>391, 5283=>549, 5284=>501, 5285=>501, 5286=>501, 5287=>549, 5288=>470, - 5289=>549, 5290=>501, 5291=>501, 5292=>674, 5293=>691, 5294=>671, 5295=>687, 5296=>671, 5297=>687, 5298=>674, 5299=>691, 5300=>674, 5301=>691, 5302=>671, 5303=>687, 5304=>671, - 5305=>687, 5306=>671, 5307=>347, 5308=>457, 5309=>347, 5312=>766, 5313=>766, 5314=>766, 5315=>740, 5316=>766, 5317=>766, 5318=>766, 5319=>766, 5320=>766, 5321=>962, 5322=>931, - 5323=>953, 5324=>766, 5325=>953, 5326=>766, 5327=>766, 5328=>540, 5329=>407, 5330=>540, 5331=>766, 5332=>766, 5333=>766, 5334=>766, 5335=>766, 5336=>766, 5337=>766, 5338=>766, - 5339=>766, 5340=>962, 5341=>931, 5342=>953, 5343=>927, 5344=>953, 5345=>927, 5346=>962, 5347=>931, 5348=>962, 5349=>931, 5350=>975, 5351=>927, 5352=>975, 5353=>927, 5354=>540, - 5356=>656, 5357=>542, 5358=>542, 5359=>542, 5360=>542, 5361=>542, 5362=>595, 5363=>542, 5364=>542, 5365=>542, 5366=>751, 5367=>678, 5368=>712, 5369=>694, 5370=>712, 5371=>694, - 5372=>751, 5373=>678, 5374=>751, 5375=>678, 5376=>712, 5377=>694, 5378=>712, 5379=>694, 5380=>712, 5381=>376, 5382=>378, 5383=>376, 5392=>641, 5393=>641, 5394=>641, 5395=>802, - 5396=>802, 5397=>802, 5398=>802, 5399=>818, 5400=>785, 5401=>818, 5402=>785, 5403=>818, 5404=>785, 5405=>1026, 5406=>989, 5407=>1026, 5408=>989, 5409=>1026, 5410=>989, 5411=>1026, - 5412=>989, 5413=>576, 5414=>564, 5415=>564, 5416=>564, 5417=>564, 5418=>564, 5419=>601, 5420=>564, 5421=>564, 5422=>564, 5423=>760, 5424=>703, 5425=>734, 5426=>736, 5427=>734, - 5428=>736, 5429=>760, 5430=>703, 5431=>760, 5432=>703, 5433=>734, 5434=>736, 5435=>734, 5436=>736, 5437=>734, 5438=>376, 5440=>350, 5441=>436, 5442=>824, 5443=>824, 5444=>824, - 5445=>824, 5446=>824, 5447=>824, 5448=>542, 5449=>542, 5450=>542, 5451=>542, 5452=>542, 5453=>542, 5454=>751, 5455=>678, 5456=>376, 5458=>656, 5459=>615, 5460=>615, 5461=>615, - 5462=>615, 5463=>653, 5464=>653, 5465=>653, 5466=>653, 5467=>831, 5468=>906, 5469=>457, 5470=>659, 5471=>659, 5472=>659, 5473=>659, 5474=>659, 5475=>659, 5476=>657, 5477=>657, - 5478=>657, 5479=>657, 5480=>853, 5481=>810, 5482=>457, 5492=>747, 5493=>747, 5494=>747, 5495=>747, 5496=>747, 5497=>747, 5498=>747, 5499=>507, 5500=>677, 5501=>436, 5502=>942, - 5503=>942, 5504=>942, 5505=>942, 5506=>942, 5507=>942, 5508=>942, 5509=>743, 5514=>747, 5515=>747, 5516=>747, 5517=>747, 5518=>1133, 5519=>1133, 5520=>1133, 5521=>901, 5522=>901, - 5523=>1133, 5524=>1133, 5525=>629, 5526=>965, 5536=>766, 5537=>766, 5538=>766, 5539=>766, 5540=>766, 5541=>766, 5542=>540, 5543=>579, 5544=>579, 5545=>579, 5546=>579, 5547=>579, - 5548=>579, 5549=>579, 5550=>376, 5551=>565, 5598=>693, 5601=>690, 5702=>421, 5703=>421, 5742=>399, 5743=>942, 5744=>1178, 5745=>1469, 5746=>1469, 5747=>1237, 5748=>1237, 5749=>1469, - 5750=>1469, 7424=>532, 7425=>646, 7426=>883, 7427=>527, 7428=>495, 7429=>544, 7430=>544, 7431=>441, 7432=>486, 7433=>250, 7434=>355, 7435=>521, 7436=>524, 7437=>679, 7438=>584, - 7439=>550, 7440=>495, 7441=>615, 7442=>615, 7443=>615, 7444=>920, 7446=>550, 7447=>550, 7448=>472, 7449=>541, 7450=>541, 7451=>524, 7452=>517, 7453=>663, 7454=>853, 7455=>574, - 7456=>532, 7457=>736, 7458=>472, 7459=>473, 7462=>524, 7463=>532, 7464=>507, 7465=>472, 7466=>531, 7467=>575, 7468=>387, 7469=>552, 7470=>389, 7472=>436, 7473=>358, 7474=>358, - 7475=>439, 7476=>426, 7477=>167, 7478=>167, 7479=>372, 7480=>315, 7481=>489, 7482=>424, 7483=>424, 7484=>446, 7485=>396, 7486=>342, 7487=>394, 7488=>346, 7489=>415, 7490=>560, - 7491=>352, 7492=>352, 7493=>365, 7494=>583, 7495=>385, 7496=>365, 7497=>375, 7498=>375, 7499=>324, 7500=>323, 7501=>365, 7502=>161, 7503=>383, 7504=>561, 7505=>368, 7506=>372, - 7507=>333, 7508=>372, 7509=>372, 7510=>385, 7511=>265, 7512=>364, 7513=>422, 7514=>561, 7515=>375, 7517=>361, 7518=>335, 7519=>347, 7520=>374, 7521=>327, 7522=>161, 7523=>233, - 7524=>364, 7525=>375, 7526=>361, 7527=>335, 7528=>347, 7529=>374, 7530=>327, 7543=>571, 7544=>426, 7547=>334, 7557=>250, 7579=>365, 7580=>333, 7581=>333, 7582=>372, 7583=>324, - 7584=>267, 7585=>209, 7586=>365, 7587=>364, 7588=>235, 7589=>224, 7590=>234, 7591=>235, 7592=>211, 7593=>224, 7594=>211, 7595=>338, 7596=>561, 7597=>561, 7598=>369, 7599=>431, - 7600=>368, 7601=>372, 7602=>372, 7603=>324, 7604=>258, 7605=>265, 7606=>457, 7607=>376, 7608=>325, 7609=>365, 7610=>375, 7611=>330, 7612=>393, 7613=>330, 7614=>353, 7615=>372, - 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>615, 7681=>551, 7682=>617, 7683=>571, 7684=>617, 7685=>571, 7686=>617, 7687=>571, 7688=>628, 7689=>495, - 7690=>693, 7691=>571, 7692=>693, 7693=>571, 7694=>693, 7695=>571, 7696=>693, 7697=>571, 7698=>693, 7699=>571, 7700=>568, 7701=>554, 7702=>568, 7703=>554, 7704=>568, 7705=>554, - 7706=>568, 7707=>554, 7708=>568, 7709=>554, 7710=>518, 7711=>316, 7712=>697, 7713=>571, 7714=>677, 7715=>570, 7716=>677, 7717=>570, 7718=>677, 7719=>570, 7720=>677, 7721=>570, - 7722=>677, 7723=>570, 7724=>265, 7725=>250, 7726=>265, 7727=>250, 7728=>590, 7729=>521, 7730=>590, 7731=>521, 7732=>590, 7733=>521, 7734=>501, 7735=>250, 7736=>501, 7737=>250, - 7738=>501, 7739=>250, 7740=>501, 7741=>250, 7742=>776, 7743=>876, 7744=>776, 7745=>876, 7746=>776, 7747=>876, 7748=>673, 7749=>570, 7750=>673, 7751=>570, 7752=>673, 7753=>570, - 7754=>673, 7755=>570, 7756=>708, 7757=>550, 7758=>708, 7759=>550, 7760=>708, 7761=>550, 7762=>708, 7763=>550, 7764=>542, 7765=>571, 7766=>542, 7767=>571, 7768=>625, 7769=>370, - 7770=>625, 7771=>370, 7772=>625, 7773=>370, 7774=>625, 7775=>370, 7776=>571, 7777=>469, 7778=>571, 7779=>469, 7780=>571, 7781=>469, 7782=>571, 7783=>469, 7784=>571, 7785=>469, - 7786=>549, 7787=>353, 7788=>549, 7789=>353, 7790=>549, 7791=>353, 7792=>549, 7793=>353, 7794=>659, 7795=>570, 7796=>659, 7797=>570, 7798=>659, 7799=>570, 7800=>659, 7801=>570, - 7802=>659, 7803=>570, 7804=>615, 7805=>532, 7806=>615, 7807=>532, 7808=>890, 7809=>736, 7810=>890, 7811=>736, 7812=>890, 7813=>736, 7814=>890, 7815=>736, 7816=>890, 7817=>736, - 7818=>616, 7819=>532, 7820=>616, 7821=>532, 7822=>549, 7823=>532, 7824=>616, 7825=>472, 7826=>616, 7827=>472, 7828=>616, 7829=>472, 7830=>570, 7831=>353, 7832=>736, 7833=>532, - 7834=>551, 7835=>316, 7840=>615, 7841=>551, 7842=>615, 7843=>551, 7844=>615, 7845=>551, 7846=>615, 7847=>551, 7848=>615, 7849=>551, 7850=>615, 7851=>551, 7852=>615, 7853=>551, - 7854=>615, 7855=>551, 7856=>615, 7857=>551, 7858=>615, 7859=>551, 7860=>615, 7861=>551, 7862=>615, 7863=>551, 7864=>568, 7865=>554, 7866=>568, 7867=>554, 7868=>568, 7869=>554, - 7870=>568, 7871=>554, 7872=>568, 7873=>554, 7874=>568, 7875=>554, 7876=>568, 7877=>554, 7878=>568, 7879=>554, 7880=>265, 7881=>250, 7882=>265, 7883=>250, 7884=>708, 7885=>550, - 7886=>708, 7887=>550, 7888=>708, 7889=>550, 7890=>708, 7891=>550, 7892=>708, 7893=>550, 7894=>708, 7895=>550, 7896=>708, 7897=>550, 7898=>822, 7899=>550, 7900=>822, 7901=>550, - 7902=>822, 7903=>550, 7904=>822, 7905=>550, 7906=>822, 7907=>550, 7908=>659, 7909=>570, 7910=>659, 7911=>570, 7912=>772, 7913=>570, 7914=>772, 7915=>570, 7916=>772, 7917=>570, - 7918=>772, 7919=>570, 7920=>772, 7921=>570, 7922=>549, 7923=>532, 7924=>549, 7925=>532, 7926=>549, 7927=>532, 7928=>549, 7929=>532, 7936=>593, 7937=>593, 7938=>593, 7939=>593, - 7940=>593, 7941=>593, 7942=>593, 7943=>593, 7944=>615, 7945=>615, 7946=>790, 7947=>790, 7948=>692, 7949=>721, 7950=>637, 7951=>668, 7952=>486, 7953=>486, 7954=>486, 7955=>486, - 7956=>486, 7957=>486, 7960=>640, 7961=>640, 7962=>869, 7963=>877, 7964=>809, 7965=>835, 7968=>570, 7969=>570, 7970=>570, 7971=>570, 7972=>570, 7973=>570, 7974=>570, 7975=>570, - 7976=>753, 7977=>751, 7978=>977, 7979=>980, 7980=>924, 7981=>945, 7982=>840, 7983=>852, 7984=>304, 7985=>304, 7986=>304, 7987=>304, 7988=>304, 7989=>304, 7990=>304, 7991=>304, - 7992=>342, 7993=>336, 7994=>571, 7995=>571, 7996=>513, 7997=>540, 7998=>440, 7999=>443, 8000=>550, 8001=>550, 8002=>550, 8003=>550, 8004=>550, 8005=>550, 8008=>724, 8009=>763, - 8010=>985, 8011=>989, 8012=>844, 8013=>873, 8016=>521, 8017=>521, 8018=>521, 8019=>521, 8020=>521, 8021=>521, 8022=>521, 8023=>521, 8025=>705, 8027=>897, 8029=>911, 8031=>808, - 8032=>753, 8033=>753, 8034=>753, 8035=>753, 8036=>753, 8037=>753, 8038=>753, 8039=>753, 8040=>722, 8041=>759, 8042=>980, 8043=>985, 8044=>851, 8045=>875, 8046=>829, 8047=>857, - 8048=>593, 8049=>593, 8050=>486, 8051=>493, 8052=>570, 8053=>589, 8054=>304, 8055=>304, 8056=>550, 8057=>550, 8058=>521, 8059=>521, 8060=>753, 8061=>753, 8064=>593, 8065=>593, - 8066=>593, 8067=>593, 8068=>593, 8069=>593, 8070=>593, 8071=>593, 8072=>615, 8073=>615, 8074=>790, 8075=>790, 8076=>692, 8077=>721, 8078=>637, 8079=>668, 8080=>570, 8081=>570, - 8082=>570, 8083=>570, 8084=>570, 8085=>570, 8086=>570, 8087=>570, 8088=>753, 8089=>751, 8090=>977, 8091=>980, 8092=>924, 8093=>945, 8094=>840, 8095=>852, 8096=>753, 8097=>753, - 8098=>753, 8099=>753, 8100=>753, 8101=>753, 8102=>753, 8103=>753, 8104=>722, 8105=>759, 8106=>980, 8107=>985, 8108=>851, 8109=>875, 8110=>829, 8111=>857, 8112=>593, 8113=>593, - 8114=>593, 8115=>593, 8116=>593, 8118=>593, 8119=>593, 8120=>615, 8121=>615, 8122=>645, 8123=>623, 8124=>615, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>570, - 8131=>570, 8132=>589, 8134=>570, 8135=>570, 8136=>724, 8137=>671, 8138=>837, 8139=>784, 8140=>677, 8141=>450, 8142=>450, 8143=>450, 8144=>304, 8145=>304, 8146=>304, 8147=>304, - 8150=>304, 8151=>304, 8152=>265, 8153=>265, 8154=>427, 8155=>367, 8157=>450, 8158=>450, 8159=>450, 8160=>521, 8161=>521, 8162=>521, 8163=>521, 8164=>571, 8165=>571, 8166=>521, - 8167=>521, 8168=>549, 8169=>549, 8170=>760, 8171=>742, 8172=>616, 8173=>450, 8174=>450, 8175=>450, 8178=>753, 8179=>753, 8180=>753, 8182=>753, 8183=>753, 8184=>847, 8185=>731, - 8186=>830, 8187=>743, 8188=>688, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, 8196=>296, 8197=>225, 8198=>150, 8199=>572, 8200=>286, 8201=>180, 8202=>89, - 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>325, 8209=>325, 8210=>572, 8213=>900, 8214=>450, 8215=>450, 8219=>286, 8223=>466, 8227=>531, 8228=>301, 8229=>601, - 8231=>286, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1562, 8242=>204, 8243=>336, 8244=>468, 8245=>204, 8246=>336, 8247=>468, 8248=>305, 8251=>754, - 8252=>437, 8253=>478, 8254=>450, 8255=>723, 8256=>723, 8257=>225, 8258=>900, 8259=>450, 8260=>150, 8261=>351, 8262=>351, 8263=>830, 8264=>659, 8265=>659, 8266=>447, 8267=>572, - 8268=>450, 8269=>450, 8270=>450, 8271=>303, 8272=>723, 8273=>450, 8274=>404, 8275=>754, 8276=>723, 8277=>754, 8278=>527, 8279=>597, 8280=>754, 8281=>754, 8282=>286, 8283=>717, - 8284=>754, 8285=>286, 8286=>286, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>360, 8305=>161, - 8308=>360, 8309=>360, 8310=>360, 8311=>360, 8312=>360, 8313=>360, 8314=>475, 8315=>475, 8316=>475, 8317=>221, 8318=>221, 8319=>359, 8320=>360, 8321=>360, 8322=>360, 8323=>360, - 8324=>360, 8325=>360, 8326=>360, 8327=>360, 8328=>360, 8329=>360, 8330=>475, 8331=>475, 8332=>475, 8333=>221, 8334=>221, 8336=>352, 8337=>375, 8338=>372, 8339=>399, 8340=>375, - 8352=>789, 8353=>572, 8354=>572, 8355=>572, 8356=>572, 8357=>876, 8358=>673, 8359=>1145, 8360=>966, 8361=>890, 8362=>706, 8363=>572, 8365=>572, 8366=>572, 8367=>1145, 8368=>572, - 8369=>572, 8370=>572, 8371=>572, 8372=>696, 8373=>577, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>917, 8449=>917, 8450=>628, 8451=>1011, 8452=>578, 8453=>917, 8454=>960, - 8455=>553, 8456=>628, 8457=>856, 8459=>889, 8460=>679, 8461=>765, 8462=>570, 8463=>570, 8464=>422, 8465=>627, 8466=>648, 8467=>372, 8468=>736, 8469=>721, 8470=>936, 8471=>900, - 8472=>627, 8473=>631, 8474=>708, 8475=>718, 8476=>732, 8477=>713, 8478=>807, 8479=>615, 8480=>917, 8481=>967, 8483=>615, 8484=>670, 8485=>520, 8486=>688, 8487=>688, 8488=>554, - 8489=>304, 8490=>590, 8491=>615, 8492=>708, 8493=>633, 8494=>769, 8495=>532, 8496=>545, 8497=>708, 8498=>518, 8499=>962, 8500=>416, 8501=>670, 8502=>606, 8503=>422, 8504=>583, - 8505=>342, 8506=>833, 8507=>1074, 8508=>632, 8509=>655, 8510=>589, 8511=>764, 8512=>729, 8513=>697, 8514=>501, 8515=>501, 8516=>549, 8517=>737, 8518=>637, 8519=>554, 8520=>316, - 8521=>316, 8523=>702, 8526=>474, 8531=>872, 8532=>872, 8533=>872, 8534=>872, 8535=>872, 8536=>872, 8537=>872, 8538=>872, 8539=>872, 8540=>872, 8541=>872, 8542=>872, 8543=>511, - 8544=>265, 8545=>443, 8546=>620, 8547=>831, 8548=>615, 8549=>830, 8550=>1007, 8551=>1185, 8552=>826, 8553=>616, 8554=>839, 8555=>1018, 8556=>501, 8557=>628, 8558=>693, 8559=>776, - 8560=>250, 8561=>412, 8562=>573, 8563=>730, 8564=>532, 8565=>729, 8566=>892, 8567=>1053, 8568=>737, 8569=>532, 8570=>740, 8571=>901, 8572=>250, 8573=>495, 8574=>571, 8575=>876, - 8576=>1121, 8577=>693, 8578=>1121, 8579=>633, 8580=>494, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8596=>754, 8597=>754, 8598=>754, 8599=>754, 8600=>754, 8601=>754, 8602=>754, - 8603=>754, 8604=>754, 8605=>754, 8606=>754, 8607=>754, 8608=>754, 8609=>754, 8610=>754, 8611=>754, 8612=>754, 8613=>754, 8614=>754, 8615=>754, 8616=>754, 8617=>754, 8618=>754, - 8619=>754, 8620=>754, 8621=>754, 8622=>754, 8623=>754, 8624=>754, 8625=>754, 8626=>754, 8627=>754, 8628=>754, 8629=>754, 8630=>754, 8631=>754, 8632=>754, 8633=>754, 8634=>754, - 8635=>754, 8636=>754, 8637=>754, 8638=>754, 8639=>754, 8640=>754, 8641=>754, 8642=>754, 8643=>754, 8644=>754, 8645=>754, 8646=>754, 8647=>754, 8648=>754, 8649=>754, 8650=>754, - 8651=>754, 8652=>754, 8653=>754, 8654=>754, 8655=>754, 8656=>754, 8657=>754, 8658=>754, 8659=>754, 8660=>754, 8661=>754, 8662=>754, 8663=>754, 8664=>754, 8665=>754, 8666=>754, - 8667=>754, 8668=>754, 8669=>754, 8670=>754, 8671=>754, 8672=>754, 8673=>754, 8674=>754, 8675=>754, 8676=>754, 8677=>754, 8678=>754, 8679=>754, 8680=>754, 8681=>754, 8682=>754, - 8683=>754, 8684=>754, 8685=>754, 8686=>754, 8687=>754, 8688=>754, 8689=>754, 8690=>754, 8691=>754, 8692=>754, 8693=>754, 8694=>754, 8695=>754, 8696=>754, 8697=>754, 8698=>754, - 8699=>754, 8700=>754, 8701=>754, 8702=>754, 8703=>754, 8704=>615, 8705=>572, 8706=>465, 8707=>568, 8708=>568, 8709=>784, 8710=>602, 8711=>602, 8712=>784, 8713=>784, 8714=>646, - 8715=>784, 8716=>784, 8717=>646, 8718=>572, 8719=>681, 8720=>681, 8721=>606, 8722=>754, 8723=>754, 8724=>754, 8725=>150, 8726=>573, 8727=>754, 8728=>563, 8729=>286, 8730=>573, - 8731=>573, 8732=>573, 8733=>609, 8734=>750, 8735=>754, 8736=>807, 8737=>807, 8738=>754, 8739=>450, 8740=>450, 8741=>450, 8742=>450, 8743=>659, 8744=>659, 8745=>659, 8746=>659, - 8747=>469, 8748=>710, 8749=>951, 8750=>469, 8751=>710, 8752=>951, 8753=>469, 8754=>469, 8755=>469, 8756=>572, 8757=>572, 8758=>234, 8759=>572, 8760=>754, 8761=>754, 8762=>754, - 8763=>754, 8764=>754, 8765=>754, 8766=>754, 8767=>754, 8768=>337, 8769=>754, 8770=>754, 8771=>754, 8772=>754, 8773=>754, 8774=>754, 8775=>754, 8776=>754, 8777=>754, 8778=>754, - 8779=>754, 8780=>754, 8781=>754, 8782=>754, 8783=>754, 8784=>754, 8785=>754, 8786=>754, 8787=>754, 8788=>900, 8789=>900, 8790=>754, 8791=>754, 8792=>754, 8793=>754, 8794=>754, - 8795=>754, 8796=>754, 8797=>754, 8798=>754, 8799=>754, 8800=>754, 8801=>754, 8802=>754, 8803=>754, 8804=>754, 8805=>754, 8806=>754, 8807=>754, 8808=>754, 8809=>754, 8810=>942, - 8811=>942, 8812=>417, 8813=>754, 8814=>754, 8815=>754, 8816=>754, 8817=>754, 8818=>754, 8819=>754, 8820=>754, 8821=>754, 8822=>754, 8823=>754, 8824=>754, 8825=>754, 8826=>754, - 8827=>754, 8828=>754, 8829=>754, 8830=>754, 8831=>754, 8832=>754, 8833=>754, 8834=>754, 8835=>754, 8836=>754, 8837=>754, 8838=>754, 8839=>754, 8840=>754, 8841=>754, 8842=>754, - 8843=>754, 8844=>659, 8845=>659, 8846=>659, 8847=>754, 8848=>754, 8849=>754, 8850=>754, 8851=>649, 8852=>649, 8853=>754, 8854=>754, 8855=>754, 8856=>754, 8857=>754, 8858=>754, - 8859=>754, 8860=>754, 8861=>754, 8862=>754, 8863=>754, 8864=>754, 8865=>754, 8866=>784, 8867=>784, 8868=>784, 8869=>784, 8870=>468, 8871=>468, 8872=>784, 8873=>784, 8874=>784, - 8875=>784, 8876=>784, 8877=>784, 8878=>784, 8879=>784, 8882=>754, 8883=>754, 8884=>754, 8885=>754, 8886=>900, 8887=>900, 8888=>754, 8889=>754, 8890=>468, 8891=>659, 8892=>659, - 8893=>659, 8896=>738, 8897=>738, 8898=>738, 8899=>738, 8900=>444, 8901=>286, 8902=>563, 8904=>900, 8905=>900, 8906=>900, 8907=>900, 8908=>900, 8909=>754, 8918=>754, 8919=>754, - 8920=>1280, 8921=>1280, 8922=>754, 8923=>754, 8924=>754, 8925=>754, 8926=>754, 8927=>754, 8928=>754, 8929=>754, 8930=>754, 8931=>754, 8932=>754, 8933=>754, 8934=>754, 8935=>754, - 8936=>754, 8937=>754, 8938=>754, 8939=>754, 8940=>754, 8941=>754, 8946=>900, 8947=>784, 8948=>646, 8949=>784, 8950=>784, 8951=>646, 8952=>784, 8953=>784, 8954=>900, 8955=>784, - 8956=>646, 8957=>784, 8958=>646, 8959=>784, 8962=>571, 8966=>784, 8968=>351, 8969=>351, 8970=>351, 8971=>351, 8976=>754, 8977=>461, 8984=>900, 8985=>754, 8992=>469, 8993=>469, - 8997=>900, 9000=>1299, 9085=>681, 9115=>450, 9116=>450, 9117=>450, 9118=>450, 9119=>450, 9120=>450, 9121=>450, 9122=>450, 9123=>450, 9124=>450, 9125=>450, 9126=>450, 9127=>675, - 9128=>675, 9129=>675, 9130=>675, 9131=>675, 9132=>675, 9133=>675, 9134=>469, 9166=>754, 9167=>850, 9250=>571, 9251=>571, 9312=>807, 9313=>807, 9314=>807, 9315=>807, 9316=>807, - 9317=>807, 9318=>807, 9319=>807, 9320=>807, 9321=>807, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, 9609=>692, 9610=>692, - 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, 9625=>692, 9626=>692, - 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, 9641=>850, 9642=>610, - 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, 9657=>452, 9658=>692, - 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, 9673=>785, 9674=>444, - 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>712, 9689=>873, 9690=>873, - 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>785, 9697=>785, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>531, 9703=>850, 9704=>850, 9705=>850, 9706=>850, - 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, 9721=>692, 9722=>692, - 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9729=>900, 9730=>807, 9731=>807, 9732=>807, 9733=>807, 9734=>807, 9735=>515, 9736=>806, 9737=>807, 9738=>799, - 9739=>799, 9740=>604, 9741=>911, 9742=>1121, 9743=>1125, 9744=>807, 9745=>807, 9746=>807, 9747=>479, 9748=>807, 9749=>807, 9750=>807, 9751=>807, 9752=>807, 9753=>807, 9754=>807, - 9755=>807, 9756=>807, 9757=>548, 9758=>807, 9759=>548, 9760=>807, 9761=>807, 9762=>807, 9763=>807, 9764=>602, 9765=>671, 9766=>584, 9767=>705, 9768=>490, 9769=>807, 9770=>807, - 9771=>807, 9772=>639, 9773=>807, 9774=>807, 9775=>807, 9776=>807, 9777=>807, 9778=>807, 9779=>807, 9780=>807, 9781=>807, 9782=>807, 9783=>807, 9784=>807, 9785=>807, 9786=>807, - 9787=>807, 9788=>807, 9789=>807, 9790=>807, 9791=>552, 9792=>658, 9793=>658, 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9800=>807, 9801=>807, 9802=>807, - 9803=>807, 9804=>807, 9805=>807, 9806=>807, 9807=>807, 9808=>807, 9809=>807, 9810=>807, 9811=>807, 9812=>807, 9813=>807, 9814=>807, 9815=>807, 9816=>807, 9817=>807, 9818=>807, - 9819=>807, 9820=>807, 9821=>807, 9822=>807, 9823=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9832=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 9840=>673, 9841=>689, 9842=>807, 9843=>807, 9844=>807, 9845=>807, 9846=>807, 9847=>807, 9848=>807, 9849=>807, 9850=>807, - 9851=>807, 9852=>807, 9853=>807, 9854=>807, 9855=>807, 9856=>782, 9857=>782, 9858=>782, 9859=>782, 9860=>782, 9861=>782, 9862=>807, 9863=>807, 9864=>807, 9865=>807, 9866=>807, - 9867=>807, 9868=>807, 9869=>807, 9870=>807, 9871=>807, 9872=>807, 9873=>807, 9874=>807, 9875=>807, 9876=>807, 9877=>487, 9878=>807, 9879=>807, 9880=>807, 9881=>807, 9882=>807, - 9883=>807, 9884=>807, 9888=>807, 9889=>632, 9890=>754, 9891=>754, 9892=>754, 9893=>754, 9894=>754, 9895=>754, 9896=>754, 9897=>754, 9898=>754, 9899=>754, 9900=>754, 9901=>754, - 9902=>754, 9903=>754, 9904=>759, 9905=>754, 9906=>658, 9985=>754, 9986=>754, 9987=>754, 9988=>754, 9990=>754, 9991=>754, 9992=>754, 9993=>754, 9996=>754, 9997=>754, 9998=>754, - 9999=>754, 10000=>754, 10001=>754, 10002=>754, 10003=>754, 10004=>754, 10005=>754, 10006=>754, 10007=>754, 10008=>754, 10009=>754, 10010=>754, 10011=>754, 10012=>754, 10013=>754, 10014=>754, - 10015=>754, 10016=>754, 10017=>754, 10018=>754, 10019=>754, 10020=>754, 10021=>754, 10022=>754, 10023=>754, 10025=>754, 10026=>754, 10027=>754, 10028=>754, 10029=>754, 10030=>754, 10031=>754, - 10032=>754, 10033=>754, 10034=>754, 10035=>754, 10036=>754, 10037=>754, 10038=>754, 10039=>754, 10040=>754, 10041=>754, 10042=>754, 10043=>754, 10044=>754, 10045=>754, 10046=>754, 10047=>754, - 10048=>754, 10049=>754, 10050=>754, 10051=>754, 10052=>754, 10053=>754, 10054=>754, 10055=>754, 10056=>754, 10057=>754, 10058=>754, 10059=>754, 10061=>807, 10063=>807, 10064=>807, 10065=>807, - 10066=>807, 10070=>807, 10072=>754, 10073=>754, 10074=>754, 10075=>290, 10076=>290, 10077=>484, 10078=>484, 10081=>754, 10082=>754, 10083=>754, 10084=>754, 10085=>754, 10086=>754, 10087=>754, - 10088=>754, 10089=>754, 10090=>754, 10091=>754, 10092=>754, 10093=>754, 10094=>754, 10095=>754, 10096=>754, 10097=>754, 10098=>754, 10099=>754, 10100=>754, 10101=>754, 10102=>807, 10103=>807, - 10104=>807, 10105=>807, 10106=>807, 10107=>807, 10108=>807, 10109=>807, 10110=>807, 10111=>807, 10112=>754, 10113=>754, 10114=>754, 10115=>754, 10116=>754, 10117=>754, 10118=>754, 10119=>754, - 10120=>754, 10121=>754, 10122=>754, 10123=>754, 10124=>754, 10125=>754, 10126=>754, 10127=>754, 10128=>754, 10129=>754, 10130=>754, 10131=>754, 10132=>754, 10136=>754, 10137=>754, 10138=>754, - 10139=>754, 10140=>754, 10141=>754, 10142=>754, 10143=>754, 10144=>754, 10145=>754, 10146=>754, 10147=>754, 10148=>754, 10149=>754, 10150=>754, 10151=>754, 10152=>754, 10153=>754, 10154=>754, - 10155=>754, 10156=>754, 10157=>754, 10158=>754, 10159=>754, 10161=>754, 10162=>754, 10163=>754, 10164=>754, 10165=>754, 10166=>754, 10167=>754, 10168=>754, 10169=>754, 10170=>754, 10171=>754, - 10172=>754, 10173=>754, 10174=>754, 10208=>444, 10214=>445, 10215=>445, 10216=>351, 10217=>351, 10218=>500, 10219=>500, 10224=>754, 10225=>754, 10226=>754, 10227=>754, 10228=>1042, 10229=>1290, - 10230=>1290, 10231=>1290, 10232=>1290, 10233=>1290, 10234=>1290, 10235=>1290, 10236=>1290, 10237=>1290, 10238=>1290, 10239=>1290, 10240=>659, 10241=>659, 10242=>659, 10243=>659, 10244=>659, 10245=>659, - 10246=>659, 10247=>659, 10248=>659, 10249=>659, 10250=>659, 10251=>659, 10252=>659, 10253=>659, 10254=>659, 10255=>659, 10256=>659, 10257=>659, 10258=>659, 10259=>659, 10260=>659, 10261=>659, - 10262=>659, 10263=>659, 10264=>659, 10265=>659, 10266=>659, 10267=>659, 10268=>659, 10269=>659, 10270=>659, 10271=>659, 10272=>659, 10273=>659, 10274=>659, 10275=>659, 10276=>659, 10277=>659, - 10278=>659, 10279=>659, 10280=>659, 10281=>659, 10282=>659, 10283=>659, 10284=>659, 10285=>659, 10286=>659, 10287=>659, 10288=>659, 10289=>659, 10290=>659, 10291=>659, 10292=>659, 10293=>659, - 10294=>659, 10295=>659, 10296=>659, 10297=>659, 10298=>659, 10299=>659, 10300=>659, 10301=>659, 10302=>659, 10303=>659, 10304=>659, 10305=>659, 10306=>659, 10307=>659, 10308=>659, 10309=>659, - 10310=>659, 10311=>659, 10312=>659, 10313=>659, 10314=>659, 10315=>659, 10316=>659, 10317=>659, 10318=>659, 10319=>659, 10320=>659, 10321=>659, 10322=>659, 10323=>659, 10324=>659, 10325=>659, - 10326=>659, 10327=>659, 10328=>659, 10329=>659, 10330=>659, 10331=>659, 10332=>659, 10333=>659, 10334=>659, 10335=>659, 10336=>659, 10337=>659, 10338=>659, 10339=>659, 10340=>659, 10341=>659, - 10342=>659, 10343=>659, 10344=>659, 10345=>659, 10346=>659, 10347=>659, 10348=>659, 10349=>659, 10350=>659, 10351=>659, 10352=>659, 10353=>659, 10354=>659, 10355=>659, 10356=>659, 10357=>659, - 10358=>659, 10359=>659, 10360=>659, 10361=>659, 10362=>659, 10363=>659, 10364=>659, 10365=>659, 10366=>659, 10367=>659, 10368=>659, 10369=>659, 10370=>659, 10371=>659, 10372=>659, 10373=>659, - 10374=>659, 10375=>659, 10376=>659, 10377=>659, 10378=>659, 10379=>659, 10380=>659, 10381=>659, 10382=>659, 10383=>659, 10384=>659, 10385=>659, 10386=>659, 10387=>659, 10388=>659, 10389=>659, - 10390=>659, 10391=>659, 10392=>659, 10393=>659, 10394=>659, 10395=>659, 10396=>659, 10397=>659, 10398=>659, 10399=>659, 10400=>659, 10401=>659, 10402=>659, 10403=>659, 10404=>659, 10405=>659, - 10406=>659, 10407=>659, 10408=>659, 10409=>659, 10410=>659, 10411=>659, 10412=>659, 10413=>659, 10414=>659, 10415=>659, 10416=>659, 10417=>659, 10418=>659, 10419=>659, 10420=>659, 10421=>659, - 10422=>659, 10423=>659, 10424=>659, 10425=>659, 10426=>659, 10427=>659, 10428=>659, 10429=>659, 10430=>659, 10431=>659, 10432=>659, 10433=>659, 10434=>659, 10435=>659, 10436=>659, 10437=>659, - 10438=>659, 10439=>659, 10440=>659, 10441=>659, 10442=>659, 10443=>659, 10444=>659, 10445=>659, 10446=>659, 10447=>659, 10448=>659, 10449=>659, 10450=>659, 10451=>659, 10452=>659, 10453=>659, - 10454=>659, 10455=>659, 10456=>659, 10457=>659, 10458=>659, 10459=>659, 10460=>659, 10461=>659, 10462=>659, 10463=>659, 10464=>659, 10465=>659, 10466=>659, 10467=>659, 10468=>659, 10469=>659, - 10470=>659, 10471=>659, 10472=>659, 10473=>659, 10474=>659, 10475=>659, 10476=>659, 10477=>659, 10478=>659, 10479=>659, 10480=>659, 10481=>659, 10482=>659, 10483=>659, 10484=>659, 10485=>659, - 10486=>659, 10487=>659, 10488=>659, 10489=>659, 10490=>659, 10491=>659, 10492=>659, 10493=>659, 10494=>659, 10495=>659, 10502=>754, 10503=>754, 10506=>754, 10507=>754, 10560=>615, 10561=>615, - 10702=>754, 10703=>900, 10704=>900, 10705=>900, 10706=>900, 10707=>900, 10708=>900, 10709=>900, 10731=>444, 10752=>900, 10753=>900, 10754=>900, 10764=>1192, 10765=>469, 10766=>469, 10767=>469, - 10768=>469, 10769=>469, 10770=>469, 10771=>469, 10772=>469, 10773=>469, 10774=>469, 10775=>469, 10776=>469, 10777=>469, 10778=>469, 10779=>469, 10780=>469, 10877=>754, 10878=>754, 10879=>754, - 10880=>754, 10881=>754, 10882=>754, 10883=>754, 10884=>754, 10885=>754, 10886=>754, 10887=>754, 10888=>754, 10889=>754, 10890=>754, 10891=>754, 10892=>754, 10893=>754, 10894=>754, 10895=>754, - 10896=>754, 10897=>754, 10898=>754, 10899=>754, 10900=>754, 10901=>754, 10902=>754, 10903=>754, 10904=>754, 10905=>754, 10906=>754, 10907=>754, 10908=>754, 10909=>754, 10910=>754, 10911=>754, - 10912=>754, 10926=>754, 10927=>754, 10928=>754, 10929=>754, 10930=>754, 10931=>754, 10932=>754, 10933=>754, 10934=>754, 10935=>754, 10936=>754, 10937=>754, 10938=>754, 11001=>754, 11002=>754, - 11008=>754, 11009=>754, 11010=>754, 11011=>754, 11012=>754, 11013=>754, 11014=>754, 11015=>754, 11016=>754, 11017=>754, 11018=>754, 11019=>754, 11020=>754, 11021=>754, 11022=>752, 11023=>752, - 11024=>752, 11025=>752, 11026=>850, 11027=>850, 11028=>850, 11029=>850, 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 11040=>782, 11041=>786, 11042=>786, 11043=>786, 11360=>501, - 11361=>250, 11362=>501, 11363=>542, 11364=>625, 11365=>551, 11366=>353, 11367=>677, 11368=>570, 11369=>590, 11370=>521, 11371=>616, 11372=>472, 11380=>532, 11381=>589, 11382=>511, 11383=>593, - 61440=>879, 61441=>879, 61960=>703, 62047=>532, 63173=>550, 64256=>620, 64257=>567, 64258=>567, 64259=>870, 64260=>870, 64261=>617, 64262=>774, 64275=>1081, 64276=>1081, 64277=>1076, 64278=>1067, - 64279=>1376, 64285=>266, 64287=>444, 64288=>572, 64297=>754, 64298=>719, 64299=>719, 64300=>719, 64301=>719, 64302=>597, 64303=>597, 64304=>597, 64305=>589, 64306=>408, 64307=>546, 64308=>621, - 64309=>302, 64310=>393, 64312=>615, 64313=>302, 64314=>577, 64315=>599, 64316=>571, 64318=>663, 64320=>410, 64321=>694, 64323=>586, 64324=>599, 64326=>575, 64327=>619, 64328=>577, 64329=>719, - 64330=>653, 64331=>245, 64332=>589, 64333=>599, 64334=>599, 64338=>847, 64339=>883, 64340=>250, 64341=>271, 64342=>847, 64343=>883, 64344=>250, 64345=>271, 64346=>847, 64347=>883, 64348=>250, - 64349=>271, 64350=>847, 64351=>883, 64352=>250, 64353=>271, 64354=>847, 64355=>883, 64356=>250, 64357=>271, 64358=>847, 64359=>883, 64360=>250, 64361=>271, 64362=>933, 64363=>932, 64364=>430, - 64365=>455, 64366=>933, 64367=>932, 64368=>430, 64369=>455, 64370=>581, 64371=>581, 64372=>556, 64373=>581, 64374=>581, 64375=>581, 64376=>556, 64377=>581, 64378=>581, 64379=>581, 64380=>556, - 64381=>581, 64382=>581, 64383=>581, 64384=>556, 64385=>581, 64394=>435, 64395=>497, 64396=>435, 64397=>497, 64398=>805, 64399=>805, 64400=>428, 64401=>497, 64402=>805, 64403=>805, 64404=>428, - 64405=>497, 64414=>661, 64415=>685, 64473=>435, 64474=>465, 64488=>250, 64489=>271, 64508=>704, 64509=>750, 64510=>250, 64511=>271, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, - 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65136=>264, 65137=>264, 65138=>264, 65139=>235, 65140=>264, - 65142=>264, 65143=>264, 65144=>264, 65145=>264, 65146=>264, 65147=>264, 65148=>264, 65149=>264, 65150=>264, 65151=>264, 65152=>423, 65153=>250, 65154=>274, 65155=>250, 65156=>274, 65157=>435, - 65158=>465, 65159=>250, 65160=>274, 65161=>704, 65162=>750, 65163=>250, 65164=>271, 65165=>250, 65166=>274, 65167=>847, 65168=>883, 65169=>250, 65170=>271, 65171=>471, 65172=>482, 65173=>847, - 65174=>883, 65175=>250, 65176=>271, 65177=>847, 65178=>883, 65179=>250, 65180=>271, 65181=>581, 65182=>581, 65183=>556, 65184=>581, 65185=>581, 65186=>581, 65187=>556, 65188=>581, 65189=>581, - 65190=>581, 65191=>556, 65192=>581, 65193=>400, 65194=>472, 65195=>400, 65196=>472, 65197=>435, 65198=>497, 65199=>435, 65200=>497, 65201=>1099, 65202=>1147, 65203=>754, 65204=>803, 65205=>1099, - 65206=>1147, 65207=>754, 65208=>803, 65209=>1088, 65210=>1103, 65211=>764, 65212=>780, 65213=>1088, 65214=>1103, 65215=>764, 65216=>780, 65217=>832, 65218=>854, 65219=>716, 65220=>738, 65221=>832, - 65222=>854, 65223=>716, 65224=>738, 65225=>537, 65226=>479, 65227=>537, 65228=>434, 65229=>537, 65230=>479, 65231=>470, 65232=>434, 65233=>933, 65234=>932, 65235=>430, 65236=>455, 65237=>698, - 65238=>750, 65239=>430, 65240=>455, 65241=>742, 65242=>758, 65243=>428, 65244=>497, 65245=>654, 65246=>681, 65247=>274, 65248=>298, 65249=>557, 65250=>599, 65251=>482, 65252=>520, 65253=>661, - 65254=>685, 65255=>250, 65256=>271, 65257=>471, 65258=>482, 65259=>475, 65260=>415, 65261=>435, 65262=>465, 65263=>704, 65264=>750, 65265=>704, 65266=>750, 65267=>250, 65268=>271, 65269=>513, - 65270=>537, 65271=>513, 65272=>537, 65273=>513, 65274=>537, 65275=>513, 65276=>537, 65279=>0, 65533=>923}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansCondensed.z'; - font[:ctg]='DejaVuSansCondensed.ctg.z'; - font[:originalsize]=463772; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensed.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensedb.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensedb.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,287 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansCondensedb') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansCondensed-Bold'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-962 -388 1777 1123]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>540}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>313, 33=>410, 34=>469, 35=>754, 36=>626, 37=>901, 38=>785, 39=>275, 40=>411, 41=>411, 42=>470, 43=>754, 44=>342, 45=>374, 46=>342, - 47=>329, 48=>626, 49=>626, 50=>626, 51=>626, 52=>626, 53=>626, 54=>626, 55=>626, 56=>626, 57=>626, 58=>360, 59=>360, 60=>754, 61=>754, 62=>754, - 63=>522, 64=>900, 65=>696, 66=>686, 67=>660, 68=>747, 69=>615, 70=>615, 71=>738, 72=>753, 73=>334, 74=>334, 75=>697, 76=>573, 77=>896, 78=>753, - 79=>765, 80=>659, 81=>765, 82=>693, 83=>648, 84=>614, 85=>730, 86=>696, 87=>993, 88=>694, 89=>651, 90=>652, 91=>411, 92=>329, 93=>411, 94=>754, - 95=>450, 96=>450, 97=>607, 98=>644, 99=>533, 100=>644, 101=>610, 102=>391, 103=>644, 104=>641, 105=>308, 106=>308, 107=>598, 108=>308, 109=>938, 110=>641, - 111=>618, 112=>644, 113=>644, 114=>444, 115=>536, 116=>430, 117=>641, 118=>586, 119=>831, 120=>580, 121=>586, 122=>523, 123=>641, 124=>329, 125=>641, 126=>754, - 8364=>626, 1027=>573, 8218=>342, 402=>391, 8222=>591, 8230=>900, 8224=>450, 8225=>450, 710=>450, 8240=>1296, 352=>648, 8249=>371, 338=>1050, 1036=>735, 381=>652, 1039=>753, - 8216=>342, 8217=>342, 8220=>591, 8221=>591, 8226=>575, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>536, 8250=>371, 339=>984, 1116=>611, 382=>523, 376=>651, 160=>313, - 161=>410, 162=>626, 163=>626, 164=>572, 165=>626, 166=>329, 167=>450, 168=>450, 169=>900, 170=>507, 171=>581, 172=>754, 173=>374, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>394, 179=>394, 180=>450, 181=>662, 182=>572, 183=>342, 184=>450, 185=>394, 186=>507, 187=>581, 188=>932, 189=>932, 190=>932, 191=>522, 192=>696, - 193=>696, 194=>696, 195=>696, 196=>696, 197=>696, 198=>976, 199=>660, 200=>615, 201=>615, 202=>615, 203=>615, 204=>334, 205=>334, 206=>334, 207=>334, 208=>754, - 209=>753, 210=>765, 211=>765, 212=>765, 213=>765, 214=>765, 215=>754, 216=>765, 217=>730, 218=>730, 219=>730, 220=>730, 221=>651, 222=>664, 223=>647, 224=>607, - 225=>607, 226=>607, 227=>607, 228=>607, 229=>607, 230=>943, 231=>533, 232=>610, 233=>610, 234=>610, 235=>610, 236=>308, 237=>308, 238=>308, 239=>308, 240=>618, - 241=>641, 242=>618, 243=>618, 244=>618, 245=>618, 246=>618, 247=>754, 248=>618, 249=>641, 250=>641, 251=>641, 252=>641, 253=>586, 254=>644, 255=>586, 256=>696, - 257=>607, 258=>696, 259=>607, 260=>696, 261=>607, 262=>660, 263=>533, 264=>660, 265=>533, 266=>660, 267=>533, 268=>660, 269=>533, 270=>747, 271=>644, 272=>754, - 273=>644, 274=>615, 275=>610, 276=>615, 277=>610, 278=>615, 279=>610, 280=>615, 281=>610, 282=>615, 283=>610, 284=>738, 285=>644, 286=>738, 287=>644, 288=>738, - 289=>644, 290=>738, 291=>644, 292=>753, 293=>641, 294=>876, 295=>711, 296=>334, 297=>308, 298=>334, 299=>308, 300=>334, 301=>308, 302=>334, 303=>308, 304=>334, - 305=>308, 306=>669, 307=>617, 308=>334, 309=>308, 310=>697, 311=>598, 312=>598, 313=>573, 314=>308, 315=>573, 316=>308, 317=>573, 318=>431, 319=>573, 320=>501, - 321=>578, 322=>334, 323=>753, 324=>641, 325=>753, 326=>641, 327=>753, 328=>641, 329=>884, 330=>753, 331=>641, 332=>765, 333=>618, 334=>765, 335=>618, 336=>765, - 337=>618, 340=>693, 341=>444, 342=>693, 343=>444, 344=>693, 345=>444, 346=>648, 347=>536, 348=>648, 349=>536, 350=>648, 351=>536, 354=>614, 355=>430, 356=>614, - 357=>430, 358=>614, 359=>430, 360=>730, 361=>641, 362=>730, 363=>641, 364=>730, 365=>641, 366=>730, 367=>641, 368=>730, 369=>641, 370=>730, 371=>641, 372=>993, - 373=>831, 374=>651, 375=>586, 377=>652, 378=>523, 379=>652, 380=>523, 383=>391, 384=>644, 385=>729, 386=>686, 387=>644, 388=>686, 389=>644, 390=>660, 391=>660, - 392=>533, 393=>754, 394=>791, 395=>681, 396=>644, 397=>619, 398=>615, 399=>764, 400=>626, 401=>615, 403=>738, 404=>713, 405=>940, 406=>392, 407=>350, 408=>697, - 409=>598, 410=>324, 411=>532, 412=>938, 413=>753, 414=>641, 415=>765, 416=>786, 417=>618, 418=>1002, 419=>866, 420=>703, 421=>644, 422=>693, 423=>648, 424=>536, - 425=>615, 426=>497, 427=>430, 428=>636, 429=>430, 430=>614, 431=>751, 432=>641, 433=>692, 434=>732, 435=>717, 436=>700, 437=>652, 438=>523, 439=>695, 440=>695, - 441=>576, 442=>523, 443=>626, 444=>695, 445=>576, 446=>515, 447=>644, 448=>334, 449=>593, 450=>489, 451=>334, 452=>1399, 453=>1271, 454=>1168, 455=>908, 456=>882, - 457=>617, 458=>1088, 459=>1062, 460=>949, 461=>696, 462=>607, 463=>334, 464=>308, 465=>765, 466=>618, 467=>730, 468=>641, 469=>730, 470=>641, 471=>730, 472=>641, - 473=>730, 474=>641, 475=>730, 476=>641, 477=>610, 478=>696, 479=>607, 480=>696, 481=>607, 482=>976, 483=>943, 484=>738, 485=>644, 486=>738, 487=>644, 488=>697, - 489=>598, 490=>765, 491=>618, 492=>765, 493=>618, 494=>695, 495=>523, 496=>308, 497=>1399, 498=>1271, 499=>1168, 500=>738, 501=>644, 502=>1160, 503=>708, 504=>753, - 505=>641, 506=>696, 507=>607, 508=>976, 509=>943, 510=>765, 511=>618, 512=>696, 513=>607, 514=>696, 515=>607, 516=>615, 517=>610, 518=>615, 519=>610, 520=>334, - 521=>308, 522=>334, 523=>308, 524=>765, 525=>618, 526=>765, 527=>618, 528=>693, 529=>444, 530=>693, 531=>444, 532=>730, 533=>641, 534=>730, 535=>641, 536=>648, - 537=>536, 538=>614, 539=>430, 540=>621, 541=>546, 542=>753, 543=>641, 544=>753, 545=>778, 546=>728, 547=>593, 548=>652, 549=>523, 550=>696, 551=>607, 552=>615, - 553=>610, 554=>765, 555=>618, 556=>765, 557=>618, 558=>765, 559=>618, 560=>765, 561=>618, 562=>651, 563=>586, 564=>442, 565=>780, 566=>460, 567=>308, 568=>979, - 569=>979, 570=>696, 571=>660, 572=>533, 573=>573, 574=>614, 575=>536, 576=>523, 577=>703, 578=>553, 579=>686, 580=>730, 581=>696, 582=>615, 583=>610, 584=>334, - 585=>308, 586=>774, 587=>712, 588=>693, 589=>444, 590=>651, 591=>586, 592=>607, 593=>644, 594=>644, 595=>644, 596=>533, 597=>533, 598=>645, 599=>712, 600=>610, - 601=>610, 602=>788, 603=>501, 604=>490, 605=>733, 606=>658, 607=>308, 608=>712, 609=>644, 610=>564, 611=>661, 612=>571, 613=>641, 614=>641, 615=>641, 616=>491, - 617=>396, 618=>491, 619=>502, 620=>624, 621=>308, 622=>757, 623=>938, 624=>938, 625=>938, 626=>641, 627=>713, 628=>578, 629=>618, 630=>817, 631=>613, 632=>716, - 633=>484, 634=>484, 635=>584, 636=>444, 637=>444, 638=>536, 639=>536, 640=>578, 641=>578, 642=>536, 643=>374, 644=>391, 645=>544, 646=>497, 647=>430, 648=>430, - 649=>828, 650=>692, 651=>603, 652=>586, 653=>831, 654=>586, 655=>651, 656=>624, 657=>615, 658=>576, 659=>576, 660=>515, 661=>515, 662=>515, 663=>515, 664=>765, - 665=>569, 666=>658, 667=>616, 668=>622, 669=>308, 670=>659, 671=>485, 672=>712, 673=>515, 674=>515, 675=>1040, 676=>1093, 677=>1039, 678=>876, 679=>691, 680=>836, - 681=>923, 682=>712, 683=>702, 684=>532, 685=>374, 686=>609, 687=>710, 688=>410, 689=>410, 690=>197, 691=>284, 692=>284, 693=>284, 694=>369, 695=>532, 696=>375, - 697=>271, 698=>469, 699=>342, 700=>342, 701=>342, 702=>330, 703=>330, 704=>293, 705=>293, 706=>450, 707=>450, 708=>450, 709=>450, 711=>450, 712=>275, 713=>450, - 714=>450, 715=>450, 716=>275, 717=>450, 718=>450, 719=>450, 720=>303, 721=>303, 722=>330, 723=>330, 724=>450, 725=>450, 726=>450, 727=>450, 728=>450, 729=>450, - 730=>450, 731=>450, 733=>450, 734=>315, 735=>450, 736=>370, 737=>197, 738=>343, 739=>371, 740=>293, 741=>450, 742=>450, 743=>450, 744=>450, 745=>450, 748=>450, - 749=>450, 750=>450, 755=>450, 759=>450, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, - 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, - 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, - 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, - 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, - 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 850=>0, 851=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, - 884=>271, 885=>271, 890=>450, 891=>533, 892=>495, 893=>494, 894=>303, 900=>397, 901=>450, 902=>717, 903=>342, 904=>761, 905=>908, 906=>507, 908=>801, 910=>882, - 911=>804, 912=>351, 913=>696, 914=>686, 915=>573, 916=>696, 917=>615, 918=>652, 919=>753, 920=>765, 921=>334, 922=>697, 923=>696, 924=>896, 925=>753, 926=>568, - 927=>765, 928=>753, 929=>659, 931=>615, 932=>614, 933=>651, 934=>765, 935=>694, 936=>765, 937=>765, 938=>334, 939=>651, 940=>618, 941=>501, 942=>641, 943=>351, - 944=>607, 945=>618, 946=>644, 947=>613, 948=>618, 949=>501, 950=>532, 951=>641, 952=>618, 953=>351, 954=>639, 955=>569, 956=>662, 957=>613, 958=>532, 959=>618, - 960=>712, 961=>644, 962=>533, 963=>701, 964=>574, 965=>607, 966=>704, 967=>580, 968=>714, 969=>782, 970=>351, 971=>607, 972=>618, 973=>607, 974=>782, 976=>585, - 977=>594, 978=>671, 979=>883, 980=>671, 981=>716, 982=>782, 983=>669, 984=>765, 985=>618, 986=>660, 987=>533, 988=>615, 989=>444, 990=>632, 991=>593, 992=>827, - 993=>564, 994=>983, 995=>753, 996=>749, 997=>644, 998=>835, 999=>669, 1000=>660, 1001=>585, 1002=>709, 1003=>604, 1004=>677, 1005=>644, 1006=>614, 1007=>531, 1008=>669, - 1009=>644, 1010=>533, 1011=>308, 1012=>765, 1013=>580, 1014=>580, 1015=>664, 1016=>644, 1017=>660, 1018=>896, 1019=>659, 1020=>644, 1021=>628, 1022=>660, 1023=>628, 1024=>615, - 1025=>615, 1026=>791, 1028=>660, 1029=>648, 1030=>334, 1031=>334, 1032=>334, 1033=>1039, 1034=>1017, 1035=>791, 1037=>753, 1038=>694, 1040=>696, 1041=>686, 1042=>686, 1043=>573, - 1044=>801, 1045=>615, 1046=>1102, 1047=>639, 1048=>753, 1049=>753, 1050=>735, 1051=>747, 1052=>896, 1053=>753, 1054=>765, 1055=>753, 1056=>659, 1057=>660, 1058=>614, 1059=>694, - 1060=>892, 1061=>694, 1062=>835, 1063=>727, 1064=>1112, 1065=>1193, 1066=>845, 1067=>932, 1068=>686, 1069=>660, 1070=>1056, 1071=>693, 1072=>607, 1073=>628, 1074=>569, 1075=>470, - 1076=>727, 1077=>610, 1078=>896, 1079=>523, 1080=>630, 1081=>630, 1082=>611, 1083=>659, 1084=>735, 1085=>622, 1086=>618, 1087=>622, 1088=>644, 1089=>533, 1090=>521, 1091=>586, - 1092=>893, 1093=>580, 1094=>667, 1095=>618, 1096=>956, 1097=>995, 1098=>676, 1099=>813, 1100=>569, 1101=>533, 1102=>875, 1103=>578, 1104=>610, 1105=>610, 1106=>642, 1107=>470, - 1108=>533, 1109=>536, 1110=>308, 1111=>308, 1112=>308, 1113=>892, 1114=>860, 1115=>661, 1117=>630, 1118=>586, 1119=>622, 1120=>983, 1121=>782, 1122=>756, 1123=>662, 1124=>911, - 1125=>755, 1126=>893, 1127=>749, 1128=>1222, 1129=>1009, 1130=>765, 1131=>618, 1132=>1112, 1133=>906, 1134=>626, 1135=>501, 1136=>967, 1137=>955, 1138=>765, 1139=>601, 1140=>765, - 1141=>625, 1142=>765, 1143=>625, 1144=>1033, 1145=>939, 1146=>967, 1147=>776, 1148=>1265, 1149=>1055, 1150=>983, 1151=>782, 1152=>660, 1153=>533, 1154=>587, 1155=>0, 1156=>0, - 1157=>0, 1158=>0, 1160=>376, 1161=>376, 1162=>861, 1163=>726, 1164=>686, 1165=>550, 1166=>659, 1167=>644, 1168=>573, 1169=>470, 1170=>599, 1171=>488, 1172=>727, 1173=>602, - 1174=>1102, 1175=>896, 1176=>639, 1177=>523, 1178=>697, 1179=>611, 1180=>735, 1181=>611, 1182=>735, 1183=>611, 1184=>914, 1185=>743, 1186=>860, 1187=>727, 1188=>992, 1189=>787, - 1190=>1146, 1191=>915, 1192=>787, 1193=>639, 1194=>660, 1195=>533, 1196=>614, 1197=>521, 1198=>651, 1199=>586, 1200=>651, 1201=>586, 1202=>694, 1203=>580, 1204=>1001, 1205=>900, - 1206=>727, 1207=>618, 1208=>727, 1209=>618, 1210=>727, 1211=>641, 1212=>923, 1213=>729, 1214=>923, 1215=>729, 1216=>334, 1217=>1102, 1218=>896, 1219=>697, 1220=>567, 1221=>855, - 1222=>725, 1223=>753, 1224=>622, 1225=>861, 1226=>726, 1227=>727, 1228=>618, 1229=>1003, 1230=>839, 1231=>308, 1232=>696, 1233=>607, 1234=>696, 1235=>607, 1236=>976, 1237=>943, - 1238=>615, 1239=>610, 1240=>764, 1241=>610, 1242=>764, 1243=>610, 1244=>1102, 1245=>896, 1246=>639, 1247=>523, 1248=>695, 1249=>576, 1250=>753, 1251=>630, 1252=>753, 1253=>630, - 1254=>765, 1255=>618, 1256=>765, 1257=>618, 1258=>765, 1259=>618, 1260=>660, 1261=>533, 1262=>694, 1263=>586, 1264=>694, 1265=>586, 1266=>694, 1267=>586, 1268=>727, 1269=>618, - 1270=>573, 1271=>470, 1272=>932, 1273=>813, 1274=>599, 1275=>488, 1276=>694, 1277=>580, 1278=>694, 1279=>580, 1280=>686, 1281=>547, 1282=>1043, 1283=>804, 1284=>1007, 1285=>828, - 1286=>745, 1287=>624, 1288=>1117, 1289=>915, 1290=>1123, 1291=>912, 1292=>755, 1293=>574, 1294=>844, 1295=>722, 1296=>626, 1297=>501, 1298=>747, 1299=>659, 1329=>886, 1330=>730, - 1331=>886, 1332=>886, 1333=>730, 1334=>699, 1335=>730, 1336=>730, 1337=>877, 1338=>886, 1339=>730, 1340=>639, 1341=>970, 1342=>1022, 1343=>730, 1344=>639, 1345=>681, 1346=>886, - 1347=>789, 1348=>886, 1349=>714, 1350=>886, 1351=>730, 1352=>730, 1353=>730, 1354=>862, 1355=>699, 1356=>886, 1357=>730, 1358=>886, 1359=>648, 1360=>730, 1361=>714, 1362=>805, - 1363=>765, 1364=>842, 1365=>765, 1366=>648, 1369=>330, 1370=>342, 1371=>495, 1372=>495, 1373=>342, 1374=>491, 1375=>468, 1377=>938, 1378=>641, 1379=>779, 1380=>781, 1381=>641, - 1382=>735, 1383=>588, 1384=>641, 1385=>729, 1386=>735, 1387=>641, 1388=>448, 1389=>916, 1390=>644, 1391=>641, 1392=>641, 1393=>644, 1394=>737, 1395=>641, 1396=>676, 1397=>308, - 1398=>794, 1399=>502, 1400=>641, 1401=>502, 1402=>938, 1403=>502, 1404=>777, 1405=>641, 1406=>732, 1407=>938, 1408=>641, 1409=>644, 1410=>514, 1411=>938, 1412=>700, 1413=>618, - 1414=>648, 1415=>776, 1417=>360, 1418=>438, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, - 1469=>0, 1471=>0, 1472=>334, 1473=>0, 1474=>0, 1475=>334, 1478=>479, 1479=>0, 1488=>676, 1489=>658, 1490=>483, 1491=>615, 1492=>700, 1493=>334, 1494=>468, 1495=>700, - 1496=>692, 1497=>334, 1498=>700, 1499=>675, 1500=>646, 1501=>700, 1502=>771, 1503=>334, 1504=>479, 1505=>770, 1506=>647, 1507=>721, 1508=>699, 1509=>565, 1510=>676, 1511=>723, - 1512=>700, 1513=>867, 1514=>740, 1520=>623, 1521=>623, 1522=>623, 1548=>342, 1557=>0, 1563=>360, 1567=>522, 1569=>460, 1570=>308, 1571=>308, 1572=>559, 1573=>308, 1574=>825, - 1575=>308, 1576=>904, 1577=>531, 1578=>904, 1579=>904, 1580=>648, 1581=>648, 1582=>648, 1583=>461, 1584=>461, 1585=>518, 1586=>518, 1587=>1242, 1588=>1242, 1589=>1210, 1590=>1210, - 1591=>935, 1592=>935, 1593=>615, 1594=>615, 1600=>308, 1601=>1045, 1602=>804, 1603=>825, 1604=>781, 1605=>659, 1606=>768, 1607=>531, 1608=>559, 1609=>825, 1610=>825, 1611=>0, - 1612=>0, 1613=>0, 1614=>0, 1615=>0, 1616=>0, 1617=>0, 1618=>0, 1619=>0, 1620=>0, 1621=>0, 1626=>450, 1632=>549, 1633=>549, 1634=>549, 1635=>549, 1636=>549, - 1637=>549, 1638=>549, 1639=>549, 1640=>549, 1641=>549, 1642=>549, 1643=>336, 1644=>342, 1645=>490, 1646=>904, 1647=>804, 1652=>263, 1657=>904, 1658=>904, 1659=>904, 1660=>904, - 1661=>904, 1662=>904, 1663=>904, 1664=>904, 1665=>648, 1666=>648, 1667=>648, 1668=>648, 1669=>648, 1670=>648, 1671=>648, 1681=>518, 1682=>518, 1685=>613, 1688=>518, 1697=>1045, - 1700=>1045, 1702=>1045, 1705=>921, 1711=>921, 1717=>781, 1722=>768, 1727=>648, 1734=>559, 1740=>825, 1742=>825, 1749=>531, 1776=>549, 1777=>549, 1778=>549, 1779=>549, 1780=>549, - 1781=>549, 1782=>549, 1783=>549, 1784=>549, 1785=>549, 3647=>668, 3713=>710, 3714=>673, 3716=>674, 3719=>512, 3720=>668, 3722=>669, 3725=>685, 3732=>635, 3733=>633, 3734=>672, - 3735=>737, 3737=>657, 3738=>654, 3739=>654, 3740=>830, 3741=>744, 3742=>779, 3743=>779, 3745=>752, 3746=>685, 3747=>692, 3749=>691, 3751=>642, 3754=>744, 3755=>928, 3757=>651, - 3758=>705, 3759=>840, 3760=>620, 3761=>0, 3762=>549, 3763=>549, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>603, 3776=>464, - 3777=>774, 3778=>464, 3779=>584, 3780=>569, 3782=>683, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>1227, 3805=>1227, 5121=>696, 5122=>696, 5123=>696, - 5124=>696, 5125=>814, 5126=>814, 5127=>814, 5129=>814, 5130=>814, 5131=>814, 5132=>916, 5133=>908, 5134=>916, 5135=>908, 5136=>916, 5137=>908, 5138=>1034, 5139=>1025, 5140=>1034, - 5141=>1025, 5142=>814, 5143=>1034, 5144=>1028, 5145=>1034, 5146=>1028, 5147=>814, 5149=>278, 5150=>476, 5151=>382, 5152=>382, 5153=>355, 5154=>355, 5155=>355, 5156=>355, 5157=>507, - 5158=>423, 5159=>278, 5160=>355, 5161=>355, 5162=>355, 5163=>1092, 5164=>888, 5165=>1094, 5166=>1167, 5167=>696, 5168=>696, 5169=>696, 5170=>696, 5171=>797, 5172=>797, 5173=>797, - 5175=>797, 5176=>797, 5177=>797, 5178=>916, 5179=>908, 5180=>916, 5181=>908, 5182=>916, 5183=>908, 5184=>1034, 5185=>1025, 5186=>1034, 5187=>1025, 5188=>1034, 5189=>1028, 5190=>1034, - 5191=>1028, 5192=>797, 5193=>518, 5194=>206, 5196=>730, 5197=>730, 5198=>730, 5199=>730, 5200=>734, 5201=>734, 5202=>734, 5204=>734, 5205=>734, 5206=>734, 5207=>950, 5208=>943, - 5209=>950, 5210=>943, 5211=>950, 5212=>943, 5213=>954, 5214=>949, 5215=>954, 5216=>949, 5217=>954, 5218=>946, 5219=>954, 5220=>946, 5221=>954, 5222=>493, 5223=>904, 5224=>904, - 5225=>921, 5226=>915, 5227=>668, 5228=>668, 5229=>668, 5230=>668, 5231=>668, 5232=>680, 5233=>668, 5234=>668, 5235=>668, 5236=>926, 5237=>877, 5238=>882, 5239=>877, 5240=>882, - 5241=>877, 5242=>926, 5243=>877, 5244=>926, 5245=>877, 5246=>882, 5247=>877, 5248=>882, 5249=>877, 5250=>882, 5251=>451, 5252=>451, 5253=>844, 5254=>844, 5255=>844, 5256=>844, - 5257=>668, 5258=>668, 5259=>668, 5260=>668, 5261=>668, 5262=>680, 5263=>668, 5264=>668, 5265=>668, 5266=>926, 5267=>877, 5268=>926, 5269=>877, 5270=>926, 5271=>877, 5272=>926, - 5273=>877, 5274=>926, 5275=>877, 5276=>926, 5277=>877, 5278=>926, 5279=>877, 5280=>926, 5281=>451, 5282=>451, 5283=>563, 5284=>563, 5285=>563, 5286=>563, 5287=>563, 5288=>601, - 5289=>563, 5290=>563, 5291=>563, 5292=>793, 5293=>769, 5294=>777, 5295=>786, 5296=>777, 5297=>786, 5298=>793, 5299=>786, 5300=>793, 5301=>786, 5302=>777, 5303=>786, 5304=>777, - 5305=>786, 5306=>777, 5307=>392, 5308=>493, 5309=>392, 5312=>889, 5313=>889, 5314=>889, 5315=>889, 5316=>838, 5317=>838, 5318=>838, 5319=>838, 5320=>838, 5321=>1114, 5322=>1122, - 5323=>1080, 5324=>1105, 5325=>1080, 5326=>1105, 5327=>838, 5328=>593, 5329=>447, 5330=>593, 5331=>889, 5332=>889, 5333=>889, 5334=>889, 5335=>838, 5336=>838, 5337=>838, 5338=>838, - 5339=>838, 5340=>1107, 5341=>1122, 5342=>1155, 5343=>1105, 5344=>1155, 5345=>1105, 5346=>1105, 5347=>1093, 5348=>1105, 5349=>1093, 5350=>1155, 5351=>1105, 5352=>1155, 5353=>1105, 5354=>593, - 5356=>797, 5357=>657, 5358=>657, 5359=>657, 5360=>657, 5361=>657, 5362=>680, 5363=>657, 5364=>657, 5365=>657, 5366=>897, 5367=>862, 5368=>870, 5369=>890, 5370=>870, 5371=>890, - 5372=>897, 5373=>862, 5374=>897, 5375=>862, 5376=>870, 5377=>890, 5378=>870, 5379=>890, 5380=>870, 5381=>443, 5382=>414, 5383=>443, 5392=>831, 5393=>831, 5394=>831, 5395=>1022, - 5396=>1022, 5397=>1022, 5398=>1022, 5399=>1088, 5400=>1081, 5401=>1088, 5402=>1081, 5403=>1088, 5404=>1081, 5405=>1288, 5406=>1278, 5407=>1288, 5408=>1278, 5409=>1288, 5410=>1278, 5411=>1288, - 5412=>1278, 5413=>671, 5414=>698, 5415=>698, 5416=>698, 5417=>698, 5418=>698, 5419=>698, 5420=>698, 5421=>698, 5422=>698, 5423=>902, 5424=>903, 5425=>911, 5426=>896, 5427=>911, - 5428=>896, 5429=>902, 5430=>903, 5431=>902, 5432=>903, 5433=>911, 5434=>896, 5435=>911, 5436=>896, 5437=>911, 5438=>445, 5440=>355, 5441=>458, 5442=>929, 5443=>929, 5444=>878, - 5445=>878, 5446=>878, 5447=>878, 5448=>659, 5449=>659, 5450=>659, 5451=>659, 5452=>659, 5453=>659, 5454=>902, 5455=>863, 5456=>445, 5458=>797, 5459=>696, 5460=>696, 5461=>696, - 5462=>696, 5463=>835, 5464=>835, 5465=>835, 5466=>835, 5467=>1055, 5468=>1028, 5469=>542, 5470=>730, 5471=>730, 5472=>730, 5473=>730, 5474=>730, 5475=>730, 5476=>734, 5477=>734, - 5478=>734, 5479=>734, 5480=>954, 5481=>946, 5482=>493, 5492=>879, 5493=>879, 5494=>879, 5495=>879, 5496=>879, 5497=>879, 5498=>879, 5499=>556, 5500=>753, 5501=>458, 5502=>1114, - 5503=>1114, 5504=>1114, 5505=>1114, 5506=>1114, 5507=>1114, 5508=>1114, 5509=>890, 5514=>879, 5515=>879, 5516=>879, 5517=>879, 5518=>1432, 5519=>1432, 5520=>1432, 5521=>1165, 5522=>1165, - 5523=>1432, 5524=>1432, 5525=>763, 5526=>1146, 5536=>889, 5537=>889, 5538=>838, 5539=>838, 5540=>838, 5541=>838, 5542=>593, 5543=>698, 5544=>698, 5545=>698, 5546=>698, 5547=>698, - 5548=>698, 5549=>698, 5550=>445, 5551=>668, 5598=>747, 5601=>747, 5702=>446, 5703=>446, 5742=>371, 5743=>1114, 5744=>1432, 5745=>1814, 5746=>1814, 5747=>1548, 5748=>1510, 5749=>1814, - 5750=>1814, 7424=>586, 7425=>750, 7426=>943, 7427=>547, 7428=>533, 7429=>608, 7430=>608, 7431=>502, 7432=>501, 7433=>308, 7434=>444, 7435=>598, 7436=>485, 7437=>735, 7438=>630, - 7439=>618, 7440=>533, 7441=>594, 7442=>594, 7443=>594, 7444=>984, 7446=>618, 7447=>618, 7448=>500, 7449=>578, 7450=>578, 7451=>521, 7452=>571, 7453=>663, 7454=>853, 7455=>625, - 7456=>586, 7457=>831, 7458=>523, 7459=>581, 7462=>485, 7463=>586, 7464=>622, 7465=>500, 7466=>703, 7467=>659, 7468=>438, 7469=>615, 7470=>432, 7472=>470, 7473=>387, 7474=>387, - 7475=>465, 7476=>474, 7477=>211, 7478=>211, 7479=>439, 7480=>361, 7481=>563, 7482=>474, 7483=>474, 7484=>481, 7485=>458, 7486=>415, 7487=>436, 7488=>387, 7489=>460, 7490=>625, - 7491=>412, 7492=>412, 7493=>431, 7494=>641, 7495=>431, 7496=>431, 7497=>431, 7498=>431, 7499=>347, 7500=>347, 7501=>431, 7502=>197, 7503=>438, 7504=>597, 7505=>410, 7506=>439, - 7507=>372, 7508=>439, 7509=>439, 7510=>431, 7511=>349, 7512=>410, 7513=>416, 7514=>597, 7515=>451, 7517=>405, 7518=>386, 7519=>389, 7520=>443, 7521=>365, 7522=>197, 7523=>284, - 7524=>410, 7525=>451, 7526=>405, 7527=>386, 7528=>389, 7529=>443, 7530=>365, 7543=>644, 7544=>474, 7547=>491, 7557=>462, 7579=>431, 7580=>372, 7581=>372, 7582=>439, 7583=>347, - 7584=>339, 7585=>313, 7586=>431, 7587=>410, 7588=>312, 7589=>253, 7590=>312, 7591=>312, 7592=>388, 7593=>293, 7594=>296, 7595=>333, 7596=>598, 7597=>597, 7598=>505, 7599=>505, - 7600=>403, 7601=>439, 7602=>488, 7603=>379, 7604=>356, 7605=>349, 7606=>524, 7607=>444, 7608=>359, 7609=>405, 7610=>451, 7611=>375, 7612=>471, 7613=>422, 7614=>409, 7615=>382, - 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>696, 7681=>607, 7682=>686, 7683=>644, 7684=>686, 7685=>644, 7686=>686, 7687=>644, 7688=>660, 7689=>533, - 7690=>747, 7691=>644, 7692=>747, 7693=>644, 7694=>747, 7695=>644, 7696=>747, 7697=>644, 7698=>747, 7699=>644, 7700=>615, 7701=>610, 7702=>615, 7703=>610, 7704=>615, 7705=>610, - 7706=>615, 7707=>610, 7708=>615, 7709=>610, 7710=>615, 7711=>391, 7712=>738, 7713=>644, 7714=>753, 7715=>641, 7716=>753, 7717=>641, 7718=>753, 7719=>641, 7720=>753, 7721=>641, - 7722=>753, 7723=>641, 7724=>334, 7725=>308, 7726=>334, 7727=>308, 7728=>697, 7729=>598, 7730=>697, 7731=>598, 7732=>697, 7733=>598, 7734=>573, 7735=>308, 7736=>573, 7737=>308, - 7738=>573, 7739=>308, 7740=>573, 7741=>308, 7742=>896, 7743=>938, 7744=>896, 7745=>938, 7746=>896, 7747=>938, 7748=>753, 7749=>641, 7750=>753, 7751=>641, 7752=>753, 7753=>641, - 7754=>753, 7755=>641, 7756=>765, 7757=>618, 7758=>765, 7759=>618, 7760=>765, 7761=>618, 7762=>765, 7763=>618, 7764=>659, 7765=>644, 7766=>659, 7767=>644, 7768=>693, 7769=>444, - 7770=>693, 7771=>444, 7772=>693, 7773=>444, 7774=>693, 7775=>444, 7776=>648, 7777=>536, 7778=>648, 7779=>536, 7780=>648, 7781=>536, 7782=>648, 7783=>536, 7784=>648, 7785=>536, - 7786=>614, 7787=>430, 7788=>614, 7789=>430, 7790=>614, 7791=>430, 7792=>614, 7793=>430, 7794=>730, 7795=>641, 7796=>730, 7797=>641, 7798=>730, 7799=>641, 7800=>730, 7801=>641, - 7802=>730, 7803=>641, 7804=>696, 7805=>586, 7806=>696, 7807=>586, 7808=>993, 7809=>831, 7810=>993, 7811=>831, 7812=>993, 7813=>831, 7814=>993, 7815=>831, 7816=>993, 7817=>831, - 7818=>694, 7819=>580, 7820=>694, 7821=>580, 7822=>651, 7823=>586, 7824=>652, 7825=>523, 7826=>652, 7827=>523, 7828=>652, 7829=>523, 7830=>641, 7831=>430, 7832=>831, 7833=>586, - 7834=>607, 7835=>391, 7840=>696, 7841=>607, 7842=>696, 7843=>607, 7844=>696, 7845=>607, 7846=>696, 7847=>607, 7848=>696, 7849=>607, 7850=>696, 7851=>607, 7852=>696, 7853=>607, - 7854=>696, 7855=>607, 7856=>696, 7857=>607, 7858=>696, 7859=>607, 7860=>696, 7861=>607, 7862=>696, 7863=>607, 7864=>615, 7865=>610, 7866=>615, 7867=>610, 7868=>615, 7869=>610, - 7870=>615, 7871=>610, 7872=>615, 7873=>610, 7874=>615, 7875=>610, 7876=>615, 7877=>610, 7878=>615, 7879=>610, 7880=>334, 7881=>308, 7882=>334, 7883=>308, 7884=>765, 7885=>618, - 7886=>765, 7887=>618, 7888=>765, 7889=>618, 7890=>765, 7891=>618, 7892=>765, 7893=>618, 7894=>765, 7895=>618, 7896=>765, 7897=>618, 7898=>786, 7899=>618, 7900=>786, 7901=>618, - 7902=>786, 7903=>618, 7904=>786, 7905=>618, 7906=>786, 7907=>618, 7908=>730, 7909=>641, 7910=>730, 7911=>641, 7912=>751, 7913=>641, 7914=>751, 7915=>641, 7916=>751, 7917=>641, - 7918=>751, 7919=>641, 7920=>751, 7921=>641, 7922=>651, 7923=>586, 7924=>651, 7925=>586, 7926=>651, 7927=>586, 7928=>651, 7929=>586, 7936=>618, 7937=>618, 7938=>618, 7939=>618, - 7940=>618, 7941=>618, 7942=>618, 7943=>618, 7944=>696, 7945=>696, 7946=>937, 7947=>939, 7948=>841, 7949=>866, 7950=>751, 7951=>773, 7952=>501, 7953=>501, 7954=>501, 7955=>501, - 7956=>501, 7957=>501, 7960=>712, 7961=>715, 7962=>989, 7963=>986, 7964=>920, 7965=>947, 7968=>641, 7969=>641, 7970=>641, 7971=>641, 7972=>641, 7973=>641, 7974=>641, 7975=>641, - 7976=>851, 7977=>856, 7978=>1125, 7979=>1125, 7980=>1062, 7981=>1085, 7982=>948, 7983=>956, 7984=>351, 7985=>351, 7986=>351, 7987=>351, 7988=>351, 7989=>351, 7990=>351, 7991=>351, - 7992=>435, 7993=>440, 7994=>699, 7995=>707, 7996=>641, 7997=>664, 7998=>544, 7999=>544, 8000=>618, 8001=>618, 8002=>618, 8003=>618, 8004=>618, 8005=>618, 8008=>802, 8009=>839, - 8010=>1099, 8011=>1101, 8012=>947, 8013=>974, 8016=>607, 8017=>607, 8018=>607, 8019=>607, 8020=>607, 8021=>607, 8022=>607, 8023=>607, 8025=>837, 8027=>1065, 8029=>1079, 8031=>944, - 8032=>782, 8033=>782, 8034=>782, 8035=>782, 8036=>782, 8037=>782, 8038=>782, 8039=>782, 8040=>817, 8041=>862, 8042=>1121, 8043=>1126, 8044=>968, 8045=>994, 8046=>925, 8047=>968, - 8048=>618, 8049=>618, 8050=>501, 8051=>501, 8052=>641, 8053=>641, 8054=>351, 8055=>351, 8056=>618, 8057=>618, 8058=>607, 8059=>607, 8060=>782, 8061=>782, 8064=>618, 8065=>618, - 8066=>618, 8067=>618, 8068=>618, 8069=>618, 8070=>618, 8071=>618, 8072=>696, 8073=>696, 8074=>937, 8075=>939, 8076=>841, 8077=>866, 8078=>751, 8079=>773, 8080=>641, 8081=>641, - 8082=>641, 8083=>641, 8084=>641, 8085=>641, 8086=>641, 8087=>641, 8088=>851, 8089=>856, 8090=>1125, 8091=>1125, 8092=>1062, 8093=>1085, 8094=>948, 8095=>956, 8096=>782, 8097=>782, - 8098=>782, 8099=>782, 8100=>782, 8101=>782, 8102=>782, 8103=>782, 8104=>817, 8105=>862, 8106=>1121, 8107=>1126, 8108=>968, 8109=>994, 8110=>925, 8111=>968, 8112=>618, 8113=>618, - 8114=>618, 8115=>618, 8116=>618, 8118=>618, 8119=>618, 8120=>696, 8121=>696, 8122=>789, 8123=>717, 8124=>696, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>641, - 8131=>641, 8132=>641, 8134=>641, 8135=>641, 8136=>836, 8137=>761, 8138=>972, 8139=>908, 8140=>753, 8141=>450, 8142=>450, 8143=>450, 8144=>351, 8145=>351, 8146=>351, 8147=>351, - 8150=>351, 8151=>351, 8152=>334, 8153=>334, 8154=>559, 8155=>507, 8157=>450, 8158=>450, 8159=>450, 8160=>607, 8161=>607, 8162=>607, 8163=>607, 8164=>644, 8165=>644, 8166=>607, - 8167=>607, 8168=>651, 8169=>651, 8170=>918, 8171=>882, 8172=>754, 8173=>450, 8174=>450, 8175=>450, 8178=>782, 8179=>782, 8180=>782, 8182=>782, 8183=>782, 8184=>958, 8185=>801, - 8186=>976, 8187=>804, 8188=>765, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, 8196=>296, 8197=>225, 8198=>150, 8199=>626, 8200=>342, 8201=>180, 8202=>89, - 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>374, 8209=>374, 8210=>626, 8213=>900, 8214=>450, 8215=>450, 8219=>342, 8223=>591, 8227=>575, 8228=>299, 8229=>600, - 8231=>313, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1698, 8242=>237, 8243=>402, 8244=>567, 8245=>237, 8246=>402, 8247=>567, 8248=>659, 8251=>875, - 8252=>564, 8253=>522, 8254=>450, 8255=>745, 8256=>745, 8257=>296, 8258=>920, 8259=>450, 8260=>410, 8261=>411, 8262=>411, 8263=>927, 8264=>746, 8265=>746, 8266=>461, 8267=>572, - 8268=>450, 8269=>450, 8270=>470, 8271=>360, 8272=>745, 8273=>470, 8274=>500, 8275=>754, 8276=>745, 8277=>754, 8278=>615, 8279=>731, 8280=>754, 8281=>754, 8282=>342, 8283=>784, - 8284=>754, 8285=>342, 8286=>342, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>394, 8305=>197, - 8308=>394, 8309=>394, 8310=>394, 8311=>394, 8312=>394, 8313=>394, 8314=>475, 8315=>475, 8316=>475, 8317=>259, 8318=>259, 8319=>410, 8320=>394, 8321=>394, 8322=>394, 8323=>394, - 8324=>394, 8325=>394, 8326=>394, 8327=>394, 8328=>394, 8329=>394, 8330=>475, 8331=>475, 8332=>475, 8333=>259, 8334=>259, 8336=>412, 8337=>431, 8338=>439, 8339=>371, 8340=>431, - 8352=>836, 8353=>626, 8354=>626, 8355=>626, 8356=>626, 8357=>938, 8358=>753, 8359=>1366, 8360=>1084, 8361=>993, 8362=>813, 8363=>626, 8365=>626, 8366=>614, 8367=>1252, 8368=>626, - 8369=>626, 8370=>626, 8371=>626, 8372=>773, 8373=>626, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>1007, 8449=>1053, 8450=>660, 8451=>1090, 8452=>806, 8453=>982, 8454=>1029, - 8455=>553, 8456=>628, 8457=>978, 8459=>965, 8460=>822, 8461=>765, 8462=>641, 8463=>641, 8464=>544, 8465=>624, 8466=>781, 8467=>424, 8468=>876, 8469=>753, 8470=>1083, 8471=>900, - 8472=>627, 8473=>631, 8474=>765, 8475=>789, 8476=>732, 8477=>713, 8478=>807, 8479=>639, 8480=>917, 8481=>1152, 8483=>679, 8484=>652, 8485=>520, 8486=>765, 8487=>692, 8488=>686, - 8489=>304, 8490=>697, 8491=>696, 8492=>835, 8493=>699, 8494=>769, 8495=>572, 8496=>664, 8497=>729, 8498=>615, 8499=>1074, 8500=>418, 8501=>714, 8502=>662, 8503=>453, 8504=>625, - 8505=>342, 8506=>851, 8507=>1213, 8508=>710, 8509=>663, 8510=>586, 8511=>760, 8512=>756, 8513=>697, 8514=>501, 8515=>573, 8516=>684, 8517=>747, 8518=>644, 8519=>610, 8520=>308, - 8521=>308, 8523=>785, 8526=>492, 8531=>932, 8532=>932, 8533=>932, 8534=>932, 8535=>932, 8536=>932, 8537=>932, 8538=>932, 8539=>932, 8540=>932, 8541=>932, 8542=>932, 8543=>554, - 8544=>334, 8545=>593, 8546=>851, 8547=>989, 8548=>696, 8549=>989, 8550=>1247, 8551=>1505, 8552=>1008, 8553=>694, 8554=>1008, 8555=>1266, 8556=>573, 8557=>660, 8558=>747, 8559=>896, - 8560=>308, 8561=>546, 8562=>785, 8563=>885, 8564=>586, 8565=>866, 8566=>1104, 8567=>1342, 8568=>872, 8569=>580, 8570=>872, 8571=>1110, 8572=>308, 8573=>533, 8574=>644, 8575=>938, - 8576=>1160, 8577=>747, 8578=>1160, 8579=>660, 8580=>533, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8596=>754, 8597=>754, 8598=>754, 8599=>754, 8600=>754, 8601=>754, 8602=>754, - 8603=>754, 8604=>754, 8605=>754, 8606=>754, 8607=>754, 8608=>754, 8609=>754, 8610=>754, 8611=>754, 8612=>754, 8613=>754, 8614=>754, 8615=>754, 8616=>754, 8617=>754, 8618=>754, - 8619=>754, 8620=>754, 8621=>754, 8622=>754, 8623=>754, 8624=>754, 8625=>754, 8626=>754, 8627=>754, 8628=>754, 8629=>754, 8630=>754, 8631=>754, 8632=>754, 8633=>754, 8634=>754, - 8635=>754, 8636=>754, 8637=>754, 8638=>754, 8639=>754, 8640=>754, 8641=>754, 8642=>754, 8643=>754, 8644=>754, 8645=>754, 8646=>754, 8647=>754, 8648=>754, 8649=>754, 8650=>754, - 8651=>754, 8652=>754, 8653=>754, 8654=>754, 8655=>754, 8656=>754, 8657=>754, 8658=>754, 8659=>754, 8660=>754, 8661=>754, 8662=>754, 8663=>754, 8664=>754, 8665=>754, 8666=>754, - 8667=>754, 8668=>754, 8669=>754, 8670=>754, 8671=>754, 8672=>754, 8673=>754, 8674=>754, 8675=>754, 8676=>754, 8677=>754, 8678=>754, 8679=>754, 8680=>754, 8681=>754, 8682=>754, - 8683=>754, 8684=>754, 8685=>754, 8686=>754, 8687=>754, 8688=>754, 8689=>754, 8690=>754, 8691=>754, 8692=>754, 8693=>754, 8694=>754, 8695=>754, 8696=>754, 8697=>754, 8698=>754, - 8699=>754, 8700=>754, 8701=>754, 8702=>754, 8703=>754, 8704=>696, 8705=>626, 8706=>489, 8707=>615, 8708=>615, 8709=>771, 8710=>627, 8711=>627, 8712=>807, 8713=>807, 8714=>675, - 8715=>807, 8716=>807, 8717=>675, 8718=>572, 8719=>708, 8720=>708, 8721=>646, 8722=>754, 8723=>754, 8724=>626, 8725=>150, 8726=>626, 8727=>754, 8728=>563, 8729=>342, 8730=>600, - 8731=>600, 8732=>600, 8733=>602, 8734=>750, 8735=>754, 8736=>807, 8737=>807, 8738=>754, 8739=>450, 8740=>450, 8741=>450, 8742=>450, 8743=>730, 8744=>730, 8745=>730, 8746=>730, - 8747=>549, 8748=>835, 8749=>1165, 8750=>506, 8751=>879, 8752=>1181, 8753=>506, 8754=>506, 8755=>506, 8756=>626, 8757=>626, 8758=>264, 8759=>626, 8760=>754, 8761=>754, 8762=>754, - 8763=>754, 8764=>754, 8765=>754, 8766=>754, 8767=>754, 8768=>337, 8769=>754, 8770=>754, 8771=>754, 8772=>754, 8773=>754, 8774=>754, 8775=>754, 8776=>754, 8777=>754, 8778=>754, - 8779=>754, 8780=>754, 8781=>754, 8782=>754, 8783=>754, 8784=>754, 8785=>754, 8786=>754, 8787=>754, 8788=>956, 8789=>956, 8790=>754, 8791=>754, 8792=>754, 8793=>754, 8794=>754, - 8795=>754, 8796=>754, 8797=>754, 8798=>754, 8799=>754, 8800=>754, 8801=>754, 8802=>754, 8803=>754, 8804=>754, 8805=>754, 8806=>754, 8807=>754, 8808=>756, 8809=>756, 8810=>942, - 8811=>942, 8812=>450, 8813=>754, 8814=>754, 8815=>754, 8816=>754, 8817=>754, 8818=>754, 8819=>754, 8820=>754, 8821=>754, 8822=>754, 8823=>754, 8824=>754, 8825=>754, 8826=>754, - 8827=>754, 8828=>754, 8829=>754, 8830=>754, 8831=>754, 8832=>754, 8833=>754, 8834=>754, 8835=>754, 8836=>754, 8837=>754, 8838=>754, 8839=>754, 8840=>754, 8841=>754, 8842=>754, - 8843=>754, 8844=>730, 8845=>730, 8846=>730, 8847=>754, 8848=>754, 8849=>754, 8850=>754, 8851=>678, 8852=>678, 8853=>754, 8854=>754, 8855=>754, 8856=>754, 8857=>754, 8858=>754, - 8859=>754, 8860=>754, 8861=>754, 8862=>754, 8863=>754, 8864=>754, 8865=>754, 8866=>822, 8867=>822, 8868=>822, 8869=>822, 8870=>488, 8871=>488, 8872=>822, 8873=>822, 8874=>822, - 8875=>822, 8876=>822, 8877=>822, 8878=>822, 8879=>822, 8882=>754, 8883=>754, 8884=>754, 8885=>754, 8886=>900, 8887=>900, 8888=>754, 8889=>754, 8890=>488, 8891=>730, 8892=>730, - 8893=>730, 8896=>758, 8897=>758, 8898=>758, 8899=>758, 8900=>444, 8901=>342, 8902=>563, 8904=>900, 8905=>900, 8906=>900, 8907=>900, 8908=>900, 8909=>754, 8918=>754, 8919=>754, - 8920=>1280, 8921=>1280, 8922=>754, 8923=>754, 8924=>754, 8925=>754, 8926=>754, 8927=>754, 8928=>754, 8929=>754, 8930=>754, 8931=>754, 8932=>754, 8933=>754, 8934=>754, 8935=>754, - 8936=>754, 8937=>754, 8938=>754, 8939=>754, 8940=>754, 8941=>754, 8946=>1042, 8947=>807, 8948=>675, 8949=>807, 8950=>807, 8951=>675, 8952=>807, 8953=>807, 8954=>1042, 8955=>807, - 8956=>675, 8957=>807, 8958=>675, 8959=>807, 8962=>644, 8966=>826, 8968=>411, 8969=>411, 8970=>411, 8971=>411, 8976=>754, 8977=>484, 8984=>835, 8985=>754, 8992=>549, 8993=>549, - 8997=>900, 9000=>1299, 9085=>776, 9115=>450, 9116=>450, 9117=>450, 9118=>450, 9119=>450, 9120=>450, 9121=>450, 9122=>450, 9123=>450, 9124=>450, 9125=>450, 9126=>450, 9127=>675, - 9128=>675, 9129=>675, 9130=>675, 9131=>675, 9132=>675, 9133=>675, 9134=>549, 9166=>754, 9167=>850, 9250=>644, 9251=>644, 9312=>762, 9313=>762, 9314=>762, 9315=>762, 9316=>762, - 9317=>762, 9318=>762, 9319=>762, 9320=>762, 9321=>762, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, 9609=>692, 9610=>692, - 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, 9625=>692, 9626=>692, - 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, 9641=>850, 9642=>610, - 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, 9657=>452, 9658=>692, - 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, 9673=>785, 9674=>444, - 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>756, 9689=>873, 9690=>873, - 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>692, 9697=>692, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>575, 9703=>850, 9704=>850, 9705=>850, 9706=>850, - 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, 9721=>692, 9722=>692, - 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9729=>900, 9730=>807, 9731=>807, 9732=>807, 9733=>807, 9734=>807, 9735=>515, 9736=>806, 9737=>807, 9738=>799, - 9739=>799, 9740=>604, 9741=>911, 9742=>1121, 9743=>1125, 9744=>807, 9745=>807, 9746=>807, 9747=>479, 9748=>807, 9749=>807, 9750=>807, 9751=>807, 9752=>807, 9753=>807, 9754=>807, - 9755=>807, 9756=>807, 9757=>548, 9758=>807, 9759=>548, 9760=>807, 9761=>807, 9762=>807, 9763=>807, 9764=>602, 9765=>671, 9766=>584, 9767=>705, 9768=>490, 9769=>807, 9770=>807, - 9771=>807, 9772=>639, 9773=>807, 9774=>807, 9775=>807, 9776=>807, 9777=>807, 9778=>807, 9779=>807, 9780=>807, 9781=>807, 9782=>807, 9783=>807, 9784=>807, 9785=>807, 9786=>807, - 9787=>807, 9788=>807, 9789=>807, 9790=>807, 9791=>552, 9792=>658, 9793=>658, 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9800=>807, 9801=>807, 9802=>807, - 9803=>807, 9804=>807, 9805=>807, 9806=>807, 9807=>807, 9808=>807, 9809=>807, 9810=>807, 9811=>807, 9812=>807, 9813=>807, 9814=>807, 9815=>807, 9816=>807, 9817=>807, 9818=>807, - 9819=>807, 9820=>807, 9821=>807, 9822=>807, 9823=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9832=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 9840=>673, 9841=>689, 9842=>807, 9843=>807, 9844=>807, 9845=>807, 9846=>807, 9847=>807, 9848=>807, 9849=>807, 9850=>807, - 9851=>807, 9852=>807, 9853=>807, 9854=>807, 9855=>807, 9856=>782, 9857=>782, 9858=>782, 9859=>782, 9860=>782, 9861=>782, 9862=>807, 9863=>807, 9864=>807, 9865=>807, 9866=>807, - 9867=>807, 9868=>807, 9869=>807, 9870=>807, 9871=>807, 9872=>807, 9873=>807, 9874=>807, 9875=>807, 9876=>807, 9877=>487, 9878=>807, 9879=>807, 9880=>807, 9881=>807, 9882=>807, - 9883=>807, 9884=>807, 9888=>807, 9889=>632, 9890=>754, 9891=>754, 9892=>754, 9893=>754, 9894=>754, 9895=>754, 9896=>754, 9897=>754, 9898=>754, 9899=>754, 9900=>754, 9901=>754, - 9902=>754, 9903=>754, 9904=>759, 9905=>754, 9906=>658, 9985=>754, 9986=>754, 9987=>754, 9988=>754, 9990=>754, 9991=>754, 9992=>754, 9993=>754, 9996=>754, 9997=>754, 9998=>754, - 9999=>754, 10000=>754, 10001=>754, 10002=>754, 10003=>754, 10004=>754, 10005=>754, 10006=>754, 10007=>754, 10008=>754, 10009=>754, 10010=>754, 10011=>754, 10012=>754, 10013=>754, 10014=>754, - 10015=>754, 10016=>754, 10017=>754, 10018=>754, 10019=>754, 10020=>754, 10021=>754, 10022=>754, 10023=>754, 10025=>754, 10026=>754, 10027=>754, 10028=>754, 10029=>754, 10030=>754, 10031=>754, - 10032=>754, 10033=>754, 10034=>754, 10035=>754, 10036=>754, 10037=>754, 10038=>754, 10039=>754, 10040=>754, 10041=>754, 10042=>754, 10043=>754, 10044=>754, 10045=>754, 10046=>754, 10047=>754, - 10048=>754, 10049=>754, 10050=>754, 10051=>754, 10052=>754, 10053=>754, 10054=>754, 10055=>754, 10056=>754, 10057=>754, 10058=>754, 10059=>754, 10061=>807, 10063=>807, 10064=>807, 10065=>807, - 10066=>807, 10070=>807, 10072=>754, 10073=>754, 10074=>754, 10075=>312, 10076=>312, 10077=>528, 10078=>528, 10081=>754, 10082=>754, 10083=>754, 10084=>754, 10085=>754, 10086=>754, 10087=>754, - 10088=>754, 10089=>754, 10090=>754, 10091=>754, 10092=>754, 10093=>754, 10094=>754, 10095=>754, 10096=>754, 10097=>754, 10098=>754, 10099=>754, 10100=>754, 10101=>754, 10102=>762, 10103=>762, - 10104=>762, 10105=>762, 10106=>762, 10107=>762, 10108=>762, 10109=>762, 10110=>762, 10111=>762, 10112=>754, 10113=>754, 10114=>754, 10115=>754, 10116=>754, 10117=>754, 10118=>754, 10119=>754, - 10120=>754, 10121=>754, 10122=>754, 10123=>754, 10124=>754, 10125=>754, 10126=>754, 10127=>754, 10128=>754, 10129=>754, 10130=>754, 10131=>754, 10132=>754, 10136=>754, 10137=>754, 10138=>754, - 10139=>754, 10140=>754, 10141=>754, 10142=>754, 10143=>754, 10144=>754, 10145=>754, 10146=>754, 10147=>754, 10148=>754, 10149=>754, 10150=>754, 10151=>754, 10152=>754, 10153=>754, 10154=>754, - 10155=>754, 10156=>754, 10157=>754, 10158=>754, 10159=>754, 10161=>754, 10162=>754, 10163=>754, 10164=>754, 10165=>754, 10166=>754, 10167=>754, 10168=>754, 10169=>754, 10170=>754, 10171=>754, - 10172=>754, 10173=>754, 10174=>754, 10208=>444, 10214=>438, 10215=>438, 10216=>411, 10217=>411, 10218=>648, 10219=>648, 10224=>754, 10225=>754, 10226=>754, 10227=>754, 10228=>1042, 10229=>1290, - 10230=>1290, 10231=>1290, 10232=>1290, 10233=>1290, 10234=>1290, 10235=>1290, 10236=>1290, 10237=>1290, 10238=>1290, 10239=>1290, 10240=>703, 10241=>703, 10242=>703, 10243=>703, 10244=>703, 10245=>703, - 10246=>703, 10247=>703, 10248=>703, 10249=>703, 10250=>703, 10251=>703, 10252=>703, 10253=>703, 10254=>703, 10255=>703, 10256=>703, 10257=>703, 10258=>703, 10259=>703, 10260=>703, 10261=>703, - 10262=>703, 10263=>703, 10264=>703, 10265=>703, 10266=>703, 10267=>703, 10268=>703, 10269=>703, 10270=>703, 10271=>703, 10272=>703, 10273=>703, 10274=>703, 10275=>703, 10276=>703, 10277=>703, - 10278=>703, 10279=>703, 10280=>703, 10281=>703, 10282=>703, 10283=>703, 10284=>703, 10285=>703, 10286=>703, 10287=>703, 10288=>703, 10289=>703, 10290=>703, 10291=>703, 10292=>703, 10293=>703, - 10294=>703, 10295=>703, 10296=>703, 10297=>703, 10298=>703, 10299=>703, 10300=>703, 10301=>703, 10302=>703, 10303=>703, 10304=>703, 10305=>703, 10306=>703, 10307=>703, 10308=>703, 10309=>703, - 10310=>703, 10311=>703, 10312=>703, 10313=>703, 10314=>703, 10315=>703, 10316=>703, 10317=>703, 10318=>703, 10319=>703, 10320=>703, 10321=>703, 10322=>703, 10323=>703, 10324=>703, 10325=>703, - 10326=>703, 10327=>703, 10328=>703, 10329=>703, 10330=>703, 10331=>703, 10332=>703, 10333=>703, 10334=>703, 10335=>703, 10336=>703, 10337=>703, 10338=>703, 10339=>703, 10340=>703, 10341=>703, - 10342=>703, 10343=>703, 10344=>703, 10345=>703, 10346=>703, 10347=>703, 10348=>703, 10349=>703, 10350=>703, 10351=>703, 10352=>703, 10353=>703, 10354=>703, 10355=>703, 10356=>703, 10357=>703, - 10358=>703, 10359=>703, 10360=>703, 10361=>703, 10362=>703, 10363=>703, 10364=>703, 10365=>703, 10366=>703, 10367=>703, 10368=>703, 10369=>703, 10370=>703, 10371=>703, 10372=>703, 10373=>703, - 10374=>703, 10375=>703, 10376=>703, 10377=>703, 10378=>703, 10379=>703, 10380=>703, 10381=>703, 10382=>703, 10383=>703, 10384=>703, 10385=>703, 10386=>703, 10387=>703, 10388=>703, 10389=>703, - 10390=>703, 10391=>703, 10392=>703, 10393=>703, 10394=>703, 10395=>703, 10396=>703, 10397=>703, 10398=>703, 10399=>703, 10400=>703, 10401=>703, 10402=>703, 10403=>703, 10404=>703, 10405=>703, - 10406=>703, 10407=>703, 10408=>703, 10409=>703, 10410=>703, 10411=>703, 10412=>703, 10413=>703, 10414=>703, 10415=>703, 10416=>703, 10417=>703, 10418=>703, 10419=>703, 10420=>703, 10421=>703, - 10422=>703, 10423=>703, 10424=>703, 10425=>703, 10426=>703, 10427=>703, 10428=>703, 10429=>703, 10430=>703, 10431=>703, 10432=>703, 10433=>703, 10434=>703, 10435=>703, 10436=>703, 10437=>703, - 10438=>703, 10439=>703, 10440=>703, 10441=>703, 10442=>703, 10443=>703, 10444=>703, 10445=>703, 10446=>703, 10447=>703, 10448=>703, 10449=>703, 10450=>703, 10451=>703, 10452=>703, 10453=>703, - 10454=>703, 10455=>703, 10456=>703, 10457=>703, 10458=>703, 10459=>703, 10460=>703, 10461=>703, 10462=>703, 10463=>703, 10464=>703, 10465=>703, 10466=>703, 10467=>703, 10468=>703, 10469=>703, - 10470=>703, 10471=>703, 10472=>703, 10473=>703, 10474=>703, 10475=>703, 10476=>703, 10477=>703, 10478=>703, 10479=>703, 10480=>703, 10481=>703, 10482=>703, 10483=>703, 10484=>703, 10485=>703, - 10486=>703, 10487=>703, 10488=>703, 10489=>703, 10490=>703, 10491=>703, 10492=>703, 10493=>703, 10494=>703, 10495=>703, 10502=>754, 10503=>754, 10506=>754, 10507=>754, 10560=>754, 10561=>754, - 10702=>754, 10703=>941, 10704=>941, 10705=>900, 10706=>900, 10707=>900, 10708=>900, 10709=>900, 10731=>444, 10752=>900, 10753=>900, 10754=>900, 10764=>1495, 10765=>506, 10766=>506, 10767=>506, - 10768=>506, 10769=>506, 10770=>506, 10771=>506, 10772=>506, 10773=>506, 10774=>506, 10775=>506, 10776=>506, 10777=>506, 10778=>506, 10779=>506, 10780=>506, 10877=>754, 10878=>754, 10879=>754, - 10880=>754, 10881=>754, 10882=>754, 10883=>754, 10884=>754, 10885=>754, 10886=>754, 10887=>754, 10888=>754, 10889=>754, 10890=>754, 10891=>754, 10892=>754, 10893=>754, 10894=>754, 10895=>754, - 10896=>754, 10897=>754, 10898=>754, 10899=>754, 10900=>754, 10901=>754, 10902=>754, 10903=>754, 10904=>754, 10905=>754, 10906=>754, 10907=>754, 10908=>754, 10909=>754, 10910=>754, 10911=>754, - 10912=>754, 10926=>754, 10927=>754, 10928=>754, 10929=>754, 10930=>754, 10931=>754, 10932=>754, 10933=>754, 10934=>754, 10935=>754, 10936=>754, 10937=>754, 10938=>754, 11001=>754, 11002=>754, - 11008=>754, 11009=>754, 11010=>754, 11011=>754, 11012=>754, 11013=>754, 11014=>754, 11015=>754, 11016=>754, 11017=>754, 11018=>754, 11019=>754, 11020=>754, 11021=>754, 11022=>754, 11023=>754, - 11024=>754, 11025=>754, 11026=>850, 11027=>850, 11028=>850, 11029=>850, 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 11040=>782, 11041=>786, 11042=>786, 11043=>786, 11360=>573, - 11361=>324, 11362=>573, 11363=>659, 11364=>693, 11365=>607, 11366=>430, 11367=>860, 11368=>641, 11369=>697, 11370=>598, 11371=>652, 11372=>523, 11380=>586, 11381=>584, 11382=>464, 11383=>704, - 61960=>774, 62047=>647, 63173=>618, 64256=>729, 64257=>667, 64258=>667, 64259=>1003, 64260=>1004, 64261=>727, 64262=>917, 64275=>1249, 64276=>1245, 64277=>1240, 64278=>1245, 64279=>1542, 64285=>334, - 64287=>623, 64288=>647, 64297=>754, 64298=>867, 64299=>867, 64300=>867, 64301=>867, 64302=>676, 64303=>676, 64304=>676, 64305=>658, 64306=>483, 64307=>615, 64308=>700, 64309=>420, 64310=>468, - 64312=>692, 64313=>420, 64314=>700, 64315=>675, 64316=>646, 64318=>771, 64320=>479, 64321=>770, 64323=>721, 64324=>699, 64326=>676, 64327=>723, 64328=>700, 64329=>867, 64330=>740, 64331=>334, - 64332=>658, 64333=>678, 64334=>699, 64338=>904, 64339=>953, 64340=>338, 64341=>367, 64342=>904, 64343=>953, 64344=>338, 64345=>367, 64346=>904, 64347=>953, 64348=>338, 64349=>367, 64350=>904, - 64351=>953, 64352=>338, 64353=>367, 64354=>904, 64355=>953, 64356=>338, 64357=>367, 64358=>904, 64359=>953, 64360=>338, 64361=>367, 64362=>1045, 64363=>1072, 64364=>589, 64365=>647, 64366=>1045, - 64367=>1072, 64368=>589, 64369=>647, 64370=>648, 64371=>648, 64372=>648, 64373=>648, 64374=>648, 64375=>648, 64376=>648, 64377=>648, 64378=>648, 64379=>648, 64380=>648, 64381=>648, 64382=>648, - 64383=>648, 64384=>648, 64385=>648, 64394=>518, 64395=>560, 64396=>518, 64397=>560, 64398=>921, 64399=>921, 64400=>523, 64401=>523, 64402=>921, 64403=>921, 64404=>523, 64405=>523, 64414=>768, - 64415=>810, 64473=>559, 64474=>564, 64488=>338, 64489=>367, 64508=>825, 64509=>910, 64510=>338, 64511=>367, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, - 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65136=>308, 65137=>308, 65138=>308, 65139=>311, 65140=>308, 65142=>308, 65143=>308, - 65144=>308, 65145=>308, 65146=>308, 65147=>308, 65148=>308, 65149=>308, 65150=>308, 65151=>308, 65152=>460, 65153=>308, 65154=>338, 65155=>308, 65156=>338, 65157=>559, 65158=>564, 65159=>308, - 65160=>338, 65161=>825, 65162=>825, 65163=>338, 65164=>367, 65165=>308, 65166=>338, 65167=>904, 65168=>953, 65169=>338, 65170=>367, 65171=>531, 65172=>545, 65173=>904, 65174=>953, 65175=>338, - 65176=>367, 65177=>904, 65178=>953, 65179=>338, 65180=>367, 65181=>648, 65182=>648, 65183=>648, 65184=>648, 65185=>648, 65186=>648, 65187=>648, 65188=>648, 65189=>648, 65190=>648, 65191=>648, - 65192=>648, 65193=>461, 65194=>520, 65195=>461, 65196=>520, 65197=>518, 65198=>560, 65199=>518, 65200=>560, 65201=>1242, 65202=>1272, 65203=>885, 65204=>916, 65205=>1242, 65206=>1272, 65207=>885, - 65208=>916, 65209=>1210, 65210=>1228, 65211=>870, 65212=>887, 65213=>1210, 65214=>1228, 65215=>870, 65216=>887, 65217=>935, 65218=>963, 65219=>848, 65220=>876, 65221=>935, 65222=>963, 65223=>848, - 65224=>876, 65225=>615, 65226=>615, 65227=>615, 65228=>508, 65229=>615, 65230=>615, 65231=>615, 65232=>508, 65233=>1045, 65234=>1072, 65235=>589, 65236=>647, 65237=>804, 65238=>811, 65239=>589, - 65240=>647, 65241=>825, 65242=>838, 65243=>523, 65244=>523, 65245=>781, 65246=>803, 65247=>338, 65248=>367, 65249=>659, 65250=>706, 65251=>557, 65252=>603, 65253=>768, 65254=>810, 65255=>338, - 65256=>367, 65257=>531, 65258=>545, 65259=>624, 65260=>594, 65261=>559, 65262=>564, 65263=>825, 65264=>910, 65265=>825, 65266=>910, 65267=>338, 65268=>367, 65269=>670, 65270=>683, 65271=>670, - 65272=>683, 65273=>670, 65274=>683, 65275=>670, 65276=>683, 65279=>0, 65533=>1002}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansCondensed-Bold.z'; - font[:ctg]='DejaVuSansCondensed-Bold.ctg.z'; - font[:originalsize]=456120; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensedbi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensedbi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansCondensedbi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansCondensed-BoldOblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-960 -388 1804 1121]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>540}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>313, 33=>410, 34=>469, 35=>626, 36=>626, 37=>901, 38=>785, 39=>275, 40=>411, 41=>411, 42=>470, 43=>754, 44=>342, 45=>374, 46=>342, - 47=>329, 48=>626, 49=>626, 50=>626, 51=>626, 52=>626, 53=>626, 54=>626, 55=>626, 56=>626, 57=>626, 58=>360, 59=>360, 60=>754, 61=>754, 62=>754, - 63=>522, 64=>900, 65=>696, 66=>686, 67=>660, 68=>747, 69=>615, 70=>615, 71=>738, 72=>753, 73=>334, 74=>334, 75=>697, 76=>573, 77=>896, 78=>753, - 79=>765, 80=>659, 81=>765, 82=>693, 83=>648, 84=>614, 85=>730, 86=>696, 87=>993, 88=>694, 89=>651, 90=>652, 91=>411, 92=>329, 93=>411, 94=>754, - 95=>450, 96=>450, 97=>607, 98=>644, 99=>533, 100=>644, 101=>610, 102=>391, 103=>644, 104=>641, 105=>308, 106=>308, 107=>598, 108=>308, 109=>938, 110=>641, - 111=>618, 112=>644, 113=>644, 114=>444, 115=>536, 116=>430, 117=>641, 118=>586, 119=>831, 120=>580, 121=>586, 122=>523, 123=>641, 124=>329, 125=>641, 126=>754, - 8364=>626, 1027=>573, 8218=>342, 402=>391, 8222=>580, 8230=>900, 8224=>450, 8225=>450, 710=>450, 8240=>1309, 352=>648, 8249=>371, 338=>1050, 1036=>735, 381=>652, 1039=>753, - 8216=>342, 8217=>342, 8220=>580, 8221=>580, 8226=>575, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>536, 8250=>371, 339=>984, 1116=>611, 382=>523, 376=>651, 160=>313, - 161=>410, 162=>626, 163=>626, 164=>572, 165=>626, 166=>329, 167=>450, 168=>450, 169=>900, 170=>507, 171=>584, 172=>754, 173=>374, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>394, 179=>394, 180=>450, 181=>662, 182=>572, 183=>342, 184=>450, 185=>394, 186=>507, 187=>584, 188=>932, 189=>932, 190=>932, 191=>522, 192=>696, - 193=>696, 194=>696, 195=>696, 196=>696, 197=>696, 198=>976, 199=>660, 200=>615, 201=>615, 202=>615, 203=>615, 204=>334, 205=>334, 206=>334, 207=>334, 208=>760, - 209=>753, 210=>765, 211=>765, 212=>765, 213=>765, 214=>765, 215=>754, 216=>765, 217=>730, 218=>730, 219=>730, 220=>730, 221=>651, 222=>668, 223=>647, 224=>607, - 225=>607, 226=>607, 227=>607, 228=>607, 229=>607, 230=>943, 231=>533, 232=>610, 233=>610, 234=>610, 235=>610, 236=>308, 237=>308, 238=>308, 239=>308, 240=>618, - 241=>641, 242=>618, 243=>618, 244=>618, 245=>618, 246=>618, 247=>754, 248=>618, 249=>641, 250=>641, 251=>641, 252=>641, 253=>586, 254=>644, 255=>586, 256=>696, - 257=>607, 258=>696, 259=>607, 260=>696, 261=>607, 262=>660, 263=>533, 264=>660, 265=>533, 266=>660, 267=>533, 268=>660, 269=>533, 270=>747, 271=>644, 272=>760, - 273=>644, 274=>615, 275=>610, 276=>615, 277=>610, 278=>615, 279=>610, 280=>615, 281=>610, 282=>615, 283=>610, 284=>738, 285=>644, 286=>738, 287=>644, 288=>738, - 289=>644, 290=>738, 291=>644, 292=>753, 293=>641, 294=>876, 295=>711, 296=>334, 297=>308, 298=>334, 299=>308, 300=>334, 301=>308, 302=>334, 303=>308, 304=>334, - 305=>308, 306=>669, 307=>617, 308=>334, 309=>308, 310=>697, 311=>598, 312=>598, 313=>573, 314=>308, 315=>573, 316=>308, 317=>573, 318=>413, 319=>573, 320=>438, - 321=>594, 322=>337, 323=>753, 324=>641, 325=>753, 326=>641, 327=>753, 328=>641, 329=>884, 330=>753, 331=>641, 332=>765, 333=>618, 334=>765, 335=>618, 336=>765, - 337=>618, 340=>693, 341=>444, 342=>693, 343=>444, 344=>693, 345=>444, 346=>648, 347=>536, 348=>648, 349=>536, 350=>648, 351=>536, 354=>614, 355=>430, 356=>614, - 357=>430, 358=>614, 359=>430, 360=>730, 361=>641, 362=>730, 363=>641, 364=>730, 365=>641, 366=>730, 367=>641, 368=>730, 369=>641, 370=>730, 371=>641, 372=>993, - 373=>831, 374=>651, 375=>586, 377=>652, 378=>523, 379=>652, 380=>523, 383=>391, 384=>644, 385=>729, 386=>686, 387=>644, 388=>686, 389=>644, 390=>660, 391=>660, - 392=>533, 393=>760, 394=>791, 395=>686, 396=>644, 397=>618, 398=>615, 399=>765, 400=>626, 401=>615, 403=>738, 404=>713, 405=>940, 406=>392, 407=>350, 408=>697, - 409=>598, 410=>324, 411=>532, 412=>938, 413=>753, 414=>641, 415=>765, 416=>765, 417=>618, 418=>1002, 419=>866, 420=>703, 421=>644, 422=>693, 423=>648, 424=>536, - 425=>615, 426=>497, 427=>430, 428=>636, 429=>430, 430=>614, 431=>730, 432=>641, 433=>692, 434=>732, 435=>717, 436=>700, 437=>652, 438=>523, 439=>695, 440=>695, - 441=>576, 442=>523, 443=>626, 444=>695, 445=>576, 446=>515, 447=>644, 448=>334, 449=>593, 450=>489, 451=>334, 452=>1393, 453=>1305, 454=>1176, 455=>879, 456=>881, - 457=>603, 458=>1074, 459=>1091, 460=>957, 461=>696, 462=>607, 463=>334, 464=>308, 465=>765, 466=>618, 467=>730, 468=>641, 469=>730, 470=>641, 471=>730, 472=>641, - 473=>730, 474=>641, 475=>730, 476=>641, 477=>610, 478=>696, 479=>607, 480=>696, 481=>607, 482=>976, 483=>943, 484=>738, 485=>644, 486=>738, 487=>644, 488=>697, - 489=>598, 490=>765, 491=>618, 492=>765, 493=>618, 494=>695, 495=>523, 496=>308, 497=>1393, 498=>1305, 499=>1176, 500=>738, 501=>644, 502=>1160, 503=>708, 504=>753, - 505=>641, 506=>696, 507=>607, 508=>976, 509=>943, 510=>765, 511=>618, 512=>696, 513=>607, 514=>696, 515=>607, 516=>615, 517=>610, 518=>615, 519=>610, 520=>334, - 521=>308, 522=>334, 523=>308, 524=>765, 525=>618, 526=>765, 527=>618, 528=>693, 529=>444, 530=>693, 531=>444, 532=>730, 533=>641, 534=>730, 535=>641, 536=>648, - 537=>536, 538=>614, 539=>430, 540=>621, 541=>546, 542=>753, 543=>641, 544=>753, 545=>778, 546=>728, 547=>593, 548=>652, 549=>523, 550=>696, 551=>607, 552=>615, - 553=>610, 554=>765, 555=>618, 556=>765, 557=>618, 558=>765, 559=>618, 560=>765, 561=>618, 562=>651, 563=>586, 564=>442, 565=>780, 566=>460, 567=>308, 568=>979, - 569=>979, 570=>696, 571=>660, 572=>533, 573=>573, 574=>614, 575=>536, 576=>523, 577=>703, 578=>553, 579=>686, 580=>730, 581=>696, 582=>615, 583=>610, 584=>334, - 585=>308, 586=>774, 587=>712, 588=>693, 589=>444, 590=>651, 591=>586, 592=>607, 593=>644, 594=>644, 595=>644, 596=>533, 597=>533, 598=>712, 599=>712, 600=>610, - 601=>610, 602=>788, 603=>501, 604=>490, 605=>696, 606=>658, 607=>308, 608=>712, 609=>644, 610=>564, 611=>661, 612=>571, 613=>641, 614=>641, 615=>641, 616=>491, - 617=>396, 618=>491, 619=>502, 620=>624, 621=>308, 622=>757, 623=>938, 624=>938, 625=>938, 626=>641, 627=>713, 628=>578, 629=>618, 630=>817, 631=>613, 632=>716, - 633=>484, 634=>484, 635=>584, 636=>444, 637=>444, 638=>536, 639=>536, 640=>578, 641=>578, 642=>536, 643=>374, 644=>391, 645=>544, 646=>497, 647=>430, 648=>430, - 649=>828, 650=>692, 651=>603, 652=>586, 653=>831, 654=>586, 655=>651, 656=>624, 657=>615, 658=>576, 659=>576, 660=>515, 661=>515, 662=>515, 663=>515, 664=>765, - 665=>569, 666=>658, 667=>616, 668=>622, 669=>308, 670=>659, 671=>485, 672=>712, 673=>515, 674=>515, 675=>1040, 676=>1093, 677=>1039, 678=>876, 679=>691, 680=>836, - 681=>923, 682=>712, 683=>702, 684=>532, 685=>374, 686=>609, 687=>710, 688=>410, 689=>410, 690=>197, 691=>284, 692=>284, 693=>284, 694=>369, 695=>532, 696=>375, - 697=>271, 698=>469, 699=>342, 700=>342, 701=>342, 702=>330, 703=>330, 704=>293, 705=>293, 706=>450, 707=>450, 708=>450, 709=>450, 711=>450, 712=>275, 713=>450, - 714=>450, 715=>450, 716=>275, 717=>450, 718=>450, 719=>450, 720=>303, 721=>303, 722=>330, 723=>330, 724=>450, 725=>450, 726=>450, 727=>450, 728=>450, 729=>450, - 730=>450, 731=>450, 733=>450, 734=>315, 735=>450, 736=>370, 737=>197, 738=>343, 739=>371, 740=>293, 741=>450, 742=>450, 743=>450, 744=>450, 745=>450, 748=>450, - 749=>450, 750=>450, 755=>450, 759=>450, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, - 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, - 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, - 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, - 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, - 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 850=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, 884=>271, - 885=>271, 890=>450, 891=>533, 892=>495, 893=>494, 894=>303, 900=>397, 901=>450, 902=>717, 903=>342, 904=>761, 905=>908, 906=>507, 908=>801, 910=>882, 911=>804, - 912=>351, 913=>696, 914=>686, 915=>573, 916=>696, 917=>615, 918=>652, 919=>753, 920=>765, 921=>334, 922=>697, 923=>696, 924=>896, 925=>753, 926=>568, 927=>765, - 928=>753, 929=>659, 931=>615, 932=>614, 933=>651, 934=>765, 935=>694, 936=>765, 937=>765, 938=>334, 939=>651, 940=>618, 941=>501, 942=>641, 943=>351, 944=>607, - 945=>618, 946=>644, 947=>613, 948=>618, 949=>501, 950=>532, 951=>641, 952=>618, 953=>351, 954=>639, 955=>569, 956=>662, 957=>613, 958=>532, 959=>618, 960=>712, - 961=>644, 962=>533, 963=>701, 964=>574, 965=>607, 966=>704, 967=>580, 968=>714, 969=>782, 970=>351, 971=>607, 972=>618, 973=>607, 974=>782, 976=>585, 977=>594, - 978=>671, 979=>883, 980=>671, 981=>716, 982=>782, 983=>669, 984=>765, 985=>618, 986=>660, 987=>533, 988=>615, 989=>444, 990=>632, 991=>593, 992=>827, 993=>564, - 994=>983, 995=>753, 996=>749, 997=>644, 998=>835, 999=>669, 1000=>660, 1001=>585, 1002=>709, 1003=>604, 1004=>677, 1005=>644, 1006=>614, 1007=>531, 1008=>669, 1009=>644, - 1010=>533, 1011=>308, 1012=>765, 1013=>580, 1014=>580, 1015=>668, 1016=>644, 1017=>660, 1018=>896, 1019=>659, 1020=>644, 1021=>660, 1022=>660, 1023=>628, 1024=>615, 1025=>615, - 1026=>791, 1028=>660, 1029=>648, 1030=>334, 1031=>334, 1032=>334, 1033=>1039, 1034=>1017, 1035=>791, 1037=>753, 1038=>694, 1040=>696, 1041=>686, 1042=>686, 1043=>573, 1044=>801, - 1045=>615, 1046=>1102, 1047=>639, 1048=>753, 1049=>753, 1050=>735, 1051=>747, 1052=>896, 1053=>753, 1054=>765, 1055=>753, 1056=>659, 1057=>660, 1058=>614, 1059=>694, 1060=>892, - 1061=>694, 1062=>835, 1063=>727, 1064=>1112, 1065=>1193, 1066=>845, 1067=>932, 1068=>686, 1069=>660, 1070=>1056, 1071=>693, 1072=>607, 1073=>628, 1074=>569, 1075=>470, 1076=>727, - 1077=>610, 1078=>896, 1079=>523, 1080=>630, 1081=>630, 1082=>611, 1083=>659, 1084=>735, 1085=>622, 1086=>618, 1087=>622, 1088=>644, 1089=>533, 1090=>521, 1091=>586, 1092=>893, - 1093=>580, 1094=>667, 1095=>618, 1096=>956, 1097=>995, 1098=>676, 1099=>813, 1100=>569, 1101=>533, 1102=>875, 1103=>578, 1104=>610, 1105=>610, 1106=>642, 1107=>470, 1108=>533, - 1109=>536, 1110=>308, 1111=>308, 1112=>308, 1113=>892, 1114=>860, 1115=>661, 1117=>630, 1118=>586, 1119=>622, 1120=>983, 1121=>782, 1122=>756, 1123=>662, 1124=>911, 1125=>755, - 1126=>893, 1127=>749, 1128=>1222, 1129=>1009, 1130=>765, 1131=>618, 1132=>1112, 1133=>906, 1134=>626, 1135=>501, 1136=>967, 1137=>955, 1138=>765, 1139=>601, 1140=>765, 1141=>625, - 1142=>765, 1143=>625, 1144=>1033, 1145=>939, 1146=>967, 1147=>776, 1148=>1265, 1149=>1055, 1150=>983, 1151=>782, 1152=>660, 1153=>533, 1154=>587, 1155=>0, 1156=>0, 1157=>0, - 1158=>0, 1160=>376, 1161=>376, 1162=>844, 1163=>725, 1164=>686, 1165=>550, 1166=>662, 1167=>646, 1168=>573, 1169=>470, 1170=>599, 1171=>488, 1172=>709, 1173=>470, 1174=>1102, - 1175=>896, 1176=>639, 1177=>523, 1178=>697, 1179=>611, 1180=>735, 1181=>611, 1182=>735, 1183=>611, 1184=>914, 1185=>743, 1186=>753, 1187=>622, 1188=>992, 1189=>783, 1190=>1129, - 1191=>880, 1192=>787, 1193=>639, 1194=>660, 1195=>533, 1196=>614, 1197=>521, 1198=>651, 1199=>586, 1200=>651, 1201=>586, 1202=>694, 1203=>580, 1204=>993, 1205=>901, 1206=>727, - 1207=>618, 1208=>727, 1209=>618, 1210=>727, 1211=>641, 1212=>923, 1213=>729, 1214=>923, 1215=>729, 1216=>334, 1217=>1102, 1218=>896, 1219=>700, 1220=>566, 1221=>839, 1222=>724, - 1223=>753, 1224=>622, 1225=>844, 1226=>725, 1227=>727, 1228=>618, 1229=>986, 1230=>838, 1231=>308, 1232=>696, 1233=>607, 1234=>696, 1235=>607, 1236=>976, 1237=>943, 1238=>615, - 1239=>610, 1240=>765, 1241=>610, 1242=>765, 1243=>610, 1244=>1102, 1245=>896, 1246=>639, 1247=>523, 1248=>695, 1249=>576, 1250=>753, 1251=>630, 1252=>753, 1253=>630, 1254=>765, - 1255=>618, 1256=>765, 1257=>618, 1258=>765, 1259=>618, 1260=>660, 1261=>533, 1262=>694, 1263=>586, 1264=>694, 1265=>586, 1266=>694, 1267=>586, 1268=>727, 1269=>618, 1270=>573, - 1271=>470, 1272=>932, 1273=>813, 1274=>599, 1275=>488, 1276=>694, 1277=>580, 1278=>694, 1279=>580, 1280=>686, 1281=>547, 1282=>1043, 1283=>804, 1284=>1007, 1285=>828, 1286=>745, - 1287=>624, 1288=>1117, 1289=>915, 1290=>1123, 1291=>912, 1292=>755, 1293=>574, 1294=>844, 1295=>722, 1296=>626, 1297=>501, 1298=>747, 1299=>659, 1329=>886, 1330=>730, 1331=>886, - 1332=>886, 1333=>730, 1334=>699, 1335=>730, 1336=>730, 1337=>877, 1338=>886, 1339=>730, 1340=>639, 1341=>970, 1342=>1022, 1343=>730, 1344=>639, 1345=>681, 1346=>886, 1347=>789, - 1348=>886, 1349=>714, 1350=>886, 1351=>730, 1352=>730, 1353=>730, 1354=>862, 1355=>699, 1356=>886, 1357=>730, 1358=>886, 1359=>648, 1360=>730, 1361=>714, 1362=>805, 1363=>765, - 1364=>842, 1365=>765, 1366=>648, 1369=>330, 1370=>342, 1371=>495, 1372=>495, 1373=>342, 1374=>491, 1375=>468, 1377=>938, 1378=>641, 1379=>779, 1380=>781, 1381=>641, 1382=>735, - 1383=>588, 1384=>641, 1385=>729, 1386=>735, 1387=>641, 1388=>448, 1389=>916, 1390=>644, 1391=>641, 1392=>641, 1393=>644, 1394=>737, 1395=>641, 1396=>676, 1397=>308, 1398=>794, - 1399=>502, 1400=>641, 1401=>502, 1402=>938, 1403=>502, 1404=>777, 1405=>641, 1406=>732, 1407=>938, 1408=>641, 1409=>644, 1410=>514, 1411=>938, 1412=>700, 1413=>618, 1414=>648, - 1415=>776, 1417=>360, 1418=>438, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, 1469=>0, - 1471=>0, 1472=>334, 1473=>0, 1474=>0, 1475=>334, 1478=>479, 1479=>0, 1488=>676, 1489=>658, 1490=>483, 1491=>615, 1492=>700, 1493=>334, 1494=>468, 1495=>700, 1496=>692, - 1497=>334, 1498=>700, 1499=>675, 1500=>646, 1501=>700, 1502=>771, 1503=>334, 1504=>479, 1505=>770, 1506=>647, 1507=>721, 1508=>699, 1509=>565, 1510=>676, 1511=>723, 1512=>700, - 1513=>867, 1514=>740, 1520=>623, 1521=>623, 1522=>623, 3647=>668, 3713=>734, 3714=>673, 3716=>674, 3719=>512, 3720=>668, 3722=>669, 3725=>685, 3732=>635, 3733=>633, 3734=>672, - 3735=>737, 3737=>657, 3738=>654, 3739=>654, 3740=>830, 3741=>744, 3742=>779, 3743=>779, 3745=>752, 3746=>685, 3747=>692, 3749=>691, 3751=>642, 3754=>744, 3755=>928, 3757=>651, - 3758=>705, 3759=>840, 3760=>620, 3761=>0, 3762=>549, 3763=>549, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>603, 3776=>464, - 3777=>774, 3778=>464, 3779=>584, 3780=>569, 3782=>683, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>1227, 3805=>1227, 5121=>696, 5122=>696, 5123=>696, - 5124=>696, 5125=>814, 5126=>814, 5127=>814, 5129=>814, 5130=>814, 5131=>814, 5132=>916, 5133=>908, 5134=>916, 5135=>908, 5136=>916, 5137=>908, 5138=>1034, 5139=>1025, 5140=>1034, - 5141=>1025, 5142=>814, 5143=>1034, 5144=>1028, 5145=>1034, 5146=>1028, 5147=>814, 5149=>278, 5150=>476, 5151=>382, 5152=>382, 5153=>355, 5154=>355, 5155=>355, 5156=>355, 5157=>507, - 5158=>423, 5159=>278, 5160=>355, 5161=>355, 5162=>355, 5163=>1092, 5164=>888, 5165=>1094, 5166=>1167, 5167=>696, 5168=>696, 5169=>696, 5170=>696, 5171=>797, 5172=>797, 5173=>797, - 5175=>797, 5176=>797, 5177=>797, 5178=>916, 5179=>908, 5180=>916, 5181=>908, 5182=>916, 5183=>908, 5184=>1034, 5185=>1025, 5186=>1034, 5187=>1025, 5188=>1034, 5189=>1028, 5190=>1034, - 5191=>1028, 5192=>797, 5193=>518, 5194=>206, 5196=>730, 5197=>730, 5198=>730, 5199=>730, 5200=>734, 5201=>734, 5202=>734, 5204=>734, 5205=>734, 5206=>734, 5207=>950, 5208=>943, - 5209=>950, 5210=>943, 5211=>950, 5212=>943, 5213=>954, 5214=>949, 5215=>954, 5216=>949, 5217=>954, 5218=>946, 5219=>954, 5220=>946, 5221=>954, 5222=>493, 5223=>904, 5224=>904, - 5225=>921, 5226=>915, 5227=>668, 5228=>668, 5229=>668, 5230=>668, 5231=>668, 5232=>668, 5233=>668, 5234=>668, 5235=>668, 5236=>926, 5237=>877, 5238=>882, 5239=>877, 5240=>882, - 5241=>877, 5242=>926, 5243=>877, 5244=>926, 5245=>877, 5246=>882, 5247=>877, 5248=>882, 5249=>877, 5250=>882, 5251=>451, 5252=>451, 5253=>844, 5254=>844, 5255=>844, 5256=>844, - 5257=>668, 5258=>668, 5259=>668, 5260=>668, 5261=>668, 5262=>668, 5263=>668, 5264=>668, 5265=>668, 5266=>926, 5267=>877, 5268=>926, 5269=>877, 5270=>926, 5271=>877, 5272=>926, - 5273=>877, 5274=>926, 5275=>877, 5276=>926, 5277=>877, 5278=>926, 5279=>877, 5280=>926, 5281=>451, 5282=>451, 5283=>563, 5284=>563, 5285=>563, 5286=>563, 5287=>563, 5288=>563, - 5289=>563, 5290=>563, 5291=>563, 5292=>793, 5293=>769, 5294=>777, 5295=>786, 5296=>777, 5297=>786, 5298=>793, 5299=>786, 5300=>793, 5301=>786, 5302=>777, 5303=>786, 5304=>777, - 5305=>786, 5306=>777, 5307=>392, 5308=>493, 5309=>392, 5312=>889, 5313=>889, 5314=>889, 5315=>889, 5316=>838, 5317=>838, 5318=>838, 5319=>838, 5320=>838, 5321=>1114, 5322=>1122, - 5323=>1080, 5324=>1105, 5325=>1080, 5326=>1105, 5327=>838, 5328=>593, 5329=>447, 5330=>593, 5331=>889, 5332=>889, 5333=>889, 5334=>889, 5335=>838, 5336=>838, 5337=>838, 5338=>838, - 5339=>838, 5340=>1107, 5341=>1122, 5342=>1155, 5343=>1105, 5344=>1155, 5345=>1105, 5346=>1105, 5347=>1093, 5348=>1105, 5349=>1093, 5350=>1155, 5351=>1105, 5352=>1155, 5353=>1105, 5354=>593, - 5356=>797, 5357=>657, 5358=>657, 5359=>657, 5360=>657, 5361=>657, 5362=>657, 5363=>657, 5364=>657, 5365=>657, 5366=>897, 5367=>862, 5368=>870, 5369=>890, 5370=>870, 5371=>890, - 5372=>897, 5373=>862, 5374=>897, 5375=>862, 5376=>870, 5377=>890, 5378=>870, 5379=>890, 5380=>870, 5381=>443, 5382=>414, 5383=>443, 5392=>831, 5393=>831, 5394=>831, 5395=>1022, - 5396=>1022, 5397=>1022, 5398=>1022, 5399=>1088, 5400=>1081, 5401=>1088, 5402=>1081, 5403=>1088, 5404=>1081, 5405=>1288, 5406=>1278, 5407=>1288, 5408=>1278, 5409=>1288, 5410=>1278, 5411=>1288, - 5412=>1278, 5413=>671, 5414=>698, 5415=>698, 5416=>698, 5417=>698, 5418=>698, 5419=>698, 5420=>698, 5421=>698, 5422=>698, 5423=>902, 5424=>903, 5425=>911, 5426=>896, 5427=>911, - 5428=>896, 5429=>902, 5430=>903, 5431=>902, 5432=>903, 5433=>911, 5434=>896, 5435=>911, 5436=>896, 5437=>911, 5438=>445, 5440=>355, 5441=>458, 5442=>929, 5443=>929, 5444=>878, - 5445=>878, 5446=>878, 5447=>878, 5448=>659, 5449=>659, 5450=>659, 5451=>659, 5452=>659, 5453=>659, 5454=>902, 5455=>863, 5456=>445, 5458=>797, 5459=>696, 5460=>696, 5461=>696, - 5462=>696, 5463=>835, 5464=>835, 5465=>835, 5466=>835, 5467=>1055, 5468=>1028, 5469=>542, 5470=>730, 5471=>730, 5472=>730, 5473=>730, 5474=>730, 5475=>730, 5476=>734, 5477=>734, - 5478=>734, 5479=>734, 5480=>954, 5481=>946, 5482=>493, 5492=>879, 5493=>879, 5494=>879, 5495=>879, 5496=>879, 5497=>879, 5498=>879, 5499=>556, 5500=>753, 5501=>458, 5502=>1114, - 5503=>1114, 5504=>1114, 5505=>1114, 5506=>1114, 5507=>1114, 5508=>1114, 5509=>890, 5514=>879, 5515=>879, 5516=>879, 5517=>879, 5518=>1432, 5519=>1432, 5520=>1432, 5521=>1165, 5522=>1165, - 5523=>1432, 5524=>1432, 5525=>763, 5526=>1146, 5536=>889, 5537=>889, 5538=>838, 5539=>838, 5540=>838, 5541=>838, 5542=>593, 5543=>698, 5544=>698, 5545=>698, 5546=>698, 5547=>698, - 5548=>698, 5549=>698, 5550=>445, 5551=>668, 5598=>747, 5601=>747, 5702=>446, 5703=>446, 5742=>371, 5743=>1114, 5744=>1432, 5745=>1814, 5746=>1814, 5747=>1548, 5748=>1510, 5749=>1814, - 5750=>1814, 7424=>586, 7425=>750, 7426=>943, 7427=>547, 7428=>533, 7429=>608, 7430=>608, 7431=>502, 7432=>501, 7433=>308, 7434=>444, 7435=>598, 7436=>485, 7437=>735, 7438=>630, - 7439=>618, 7440=>533, 7441=>594, 7442=>594, 7443=>594, 7444=>984, 7446=>618, 7447=>618, 7448=>500, 7449=>578, 7450=>578, 7451=>521, 7452=>571, 7453=>663, 7454=>853, 7455=>625, - 7456=>586, 7457=>831, 7458=>523, 7459=>581, 7462=>485, 7463=>586, 7464=>622, 7465=>500, 7466=>703, 7467=>659, 7468=>438, 7469=>615, 7470=>432, 7472=>470, 7473=>387, 7474=>387, - 7475=>465, 7476=>474, 7477=>211, 7478=>211, 7479=>439, 7480=>361, 7481=>563, 7482=>474, 7483=>474, 7484=>481, 7485=>458, 7486=>415, 7487=>436, 7488=>387, 7489=>460, 7490=>625, - 7491=>412, 7492=>412, 7493=>431, 7494=>641, 7495=>431, 7496=>431, 7497=>431, 7498=>431, 7499=>347, 7500=>347, 7501=>431, 7502=>197, 7503=>438, 7504=>597, 7505=>410, 7506=>439, - 7507=>372, 7508=>439, 7509=>439, 7510=>431, 7511=>349, 7512=>410, 7513=>416, 7514=>597, 7515=>451, 7517=>405, 7518=>386, 7519=>389, 7520=>443, 7521=>365, 7522=>197, 7523=>284, - 7524=>410, 7525=>451, 7526=>405, 7527=>386, 7528=>389, 7529=>443, 7530=>365, 7543=>644, 7544=>474, 7547=>491, 7557=>462, 7579=>431, 7580=>372, 7581=>372, 7582=>439, 7583=>347, - 7584=>339, 7585=>313, 7586=>431, 7587=>410, 7588=>312, 7589=>253, 7590=>312, 7591=>312, 7592=>388, 7593=>293, 7594=>296, 7595=>333, 7596=>598, 7597=>597, 7598=>505, 7599=>505, - 7600=>403, 7601=>439, 7602=>488, 7603=>379, 7604=>356, 7605=>349, 7606=>524, 7607=>444, 7608=>359, 7609=>405, 7610=>451, 7611=>375, 7612=>471, 7613=>422, 7614=>409, 7615=>382, - 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>696, 7681=>607, 7682=>686, 7683=>644, 7684=>686, 7685=>644, 7686=>686, 7687=>644, 7688=>660, 7689=>533, - 7690=>747, 7691=>644, 7692=>747, 7693=>644, 7694=>747, 7695=>644, 7696=>747, 7697=>644, 7698=>747, 7699=>644, 7700=>615, 7701=>610, 7702=>615, 7703=>610, 7704=>615, 7705=>610, - 7706=>615, 7707=>610, 7708=>615, 7709=>610, 7710=>615, 7711=>391, 7712=>738, 7713=>644, 7714=>753, 7715=>641, 7716=>753, 7717=>641, 7718=>753, 7719=>641, 7720=>753, 7721=>641, - 7722=>753, 7723=>641, 7724=>334, 7725=>308, 7726=>334, 7727=>308, 7728=>697, 7729=>598, 7730=>697, 7731=>598, 7732=>697, 7733=>598, 7734=>573, 7735=>308, 7736=>573, 7737=>308, - 7738=>573, 7739=>308, 7740=>573, 7741=>308, 7742=>896, 7743=>938, 7744=>896, 7745=>938, 7746=>896, 7747=>938, 7748=>753, 7749=>641, 7750=>753, 7751=>641, 7752=>753, 7753=>641, - 7754=>753, 7755=>641, 7756=>765, 7757=>618, 7758=>765, 7759=>618, 7760=>765, 7761=>618, 7762=>765, 7763=>618, 7764=>659, 7765=>644, 7766=>659, 7767=>644, 7768=>693, 7769=>444, - 7770=>693, 7771=>444, 7772=>693, 7773=>444, 7774=>693, 7775=>444, 7776=>648, 7777=>536, 7778=>648, 7779=>536, 7780=>648, 7781=>536, 7782=>648, 7783=>536, 7784=>648, 7785=>536, - 7786=>614, 7787=>430, 7788=>614, 7789=>430, 7790=>614, 7791=>430, 7792=>614, 7793=>430, 7794=>730, 7795=>641, 7796=>730, 7797=>641, 7798=>730, 7799=>641, 7800=>730, 7801=>641, - 7802=>730, 7803=>641, 7804=>696, 7805=>586, 7806=>696, 7807=>586, 7808=>993, 7809=>831, 7810=>993, 7811=>831, 7812=>993, 7813=>831, 7814=>993, 7815=>831, 7816=>993, 7817=>831, - 7818=>694, 7819=>580, 7820=>694, 7821=>580, 7822=>651, 7823=>586, 7824=>652, 7825=>523, 7826=>652, 7827=>523, 7828=>652, 7829=>523, 7830=>641, 7831=>430, 7832=>831, 7833=>586, - 7834=>607, 7835=>391, 7840=>696, 7841=>607, 7842=>696, 7843=>607, 7844=>696, 7845=>607, 7846=>696, 7847=>607, 7848=>696, 7849=>607, 7850=>696, 7851=>607, 7852=>696, 7853=>607, - 7854=>696, 7855=>607, 7856=>696, 7857=>607, 7858=>696, 7859=>607, 7860=>696, 7861=>607, 7862=>696, 7863=>607, 7864=>615, 7865=>610, 7866=>615, 7867=>610, 7868=>615, 7869=>610, - 7870=>615, 7871=>610, 7872=>615, 7873=>610, 7874=>615, 7875=>610, 7876=>615, 7877=>610, 7878=>615, 7879=>610, 7880=>334, 7881=>308, 7882=>334, 7883=>308, 7884=>765, 7885=>618, - 7886=>765, 7887=>618, 7888=>765, 7889=>618, 7890=>765, 7891=>618, 7892=>765, 7893=>618, 7894=>765, 7895=>618, 7896=>765, 7897=>618, 7898=>765, 7899=>618, 7900=>765, 7901=>618, - 7902=>765, 7903=>618, 7904=>765, 7905=>618, 7906=>765, 7907=>618, 7908=>730, 7909=>641, 7910=>730, 7911=>641, 7912=>730, 7913=>641, 7914=>730, 7915=>641, 7916=>730, 7917=>641, - 7918=>730, 7919=>641, 7920=>730, 7921=>641, 7922=>651, 7923=>586, 7924=>651, 7925=>586, 7926=>651, 7927=>586, 7928=>651, 7929=>586, 7936=>618, 7937=>618, 7938=>618, 7939=>618, - 7940=>618, 7941=>618, 7942=>618, 7943=>618, 7944=>696, 7945=>696, 7946=>937, 7947=>939, 7948=>841, 7949=>866, 7950=>751, 7951=>773, 7952=>501, 7953=>501, 7954=>501, 7955=>501, - 7956=>501, 7957=>501, 7960=>712, 7961=>715, 7962=>989, 7963=>986, 7964=>920, 7965=>947, 7968=>641, 7969=>641, 7970=>641, 7971=>641, 7972=>641, 7973=>641, 7974=>641, 7975=>641, - 7976=>851, 7977=>856, 7978=>1125, 7979=>1125, 7980=>1062, 7981=>1085, 7982=>948, 7983=>956, 7984=>351, 7985=>351, 7986=>351, 7987=>351, 7988=>351, 7989=>351, 7990=>351, 7991=>351, - 7992=>435, 7993=>440, 7994=>699, 7995=>707, 7996=>641, 7997=>664, 7998=>544, 7999=>544, 8000=>618, 8001=>618, 8002=>618, 8003=>618, 8004=>618, 8005=>618, 8008=>802, 8009=>839, - 8010=>1099, 8011=>1101, 8012=>947, 8013=>974, 8016=>607, 8017=>607, 8018=>607, 8019=>607, 8020=>607, 8021=>607, 8022=>607, 8023=>607, 8025=>837, 8027=>1065, 8029=>1079, 8031=>944, - 8032=>782, 8033=>782, 8034=>782, 8035=>782, 8036=>782, 8037=>782, 8038=>782, 8039=>782, 8040=>817, 8041=>862, 8042=>1121, 8043=>1126, 8044=>968, 8045=>994, 8046=>925, 8047=>968, - 8048=>618, 8049=>618, 8050=>501, 8051=>501, 8052=>641, 8053=>641, 8054=>351, 8055=>351, 8056=>618, 8057=>618, 8058=>607, 8059=>607, 8060=>782, 8061=>782, 8064=>618, 8065=>618, - 8066=>618, 8067=>618, 8068=>618, 8069=>618, 8070=>618, 8071=>618, 8072=>696, 8073=>696, 8074=>937, 8075=>939, 8076=>841, 8077=>866, 8078=>751, 8079=>773, 8080=>641, 8081=>641, - 8082=>641, 8083=>641, 8084=>641, 8085=>641, 8086=>641, 8087=>641, 8088=>851, 8089=>856, 8090=>1125, 8091=>1125, 8092=>1062, 8093=>1085, 8094=>948, 8095=>956, 8096=>782, 8097=>782, - 8098=>782, 8099=>782, 8100=>782, 8101=>782, 8102=>782, 8103=>782, 8104=>817, 8105=>862, 8106=>1121, 8107=>1126, 8108=>968, 8109=>994, 8110=>925, 8111=>968, 8112=>618, 8113=>618, - 8114=>618, 8115=>618, 8116=>618, 8118=>618, 8119=>618, 8120=>696, 8121=>696, 8122=>789, 8123=>717, 8124=>696, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>641, - 8131=>641, 8132=>641, 8134=>641, 8135=>641, 8136=>836, 8137=>761, 8138=>972, 8139=>908, 8140=>753, 8141=>450, 8142=>450, 8143=>450, 8144=>351, 8145=>351, 8146=>351, 8147=>351, - 8150=>351, 8151=>351, 8152=>334, 8153=>334, 8154=>559, 8155=>507, 8157=>450, 8158=>450, 8159=>450, 8160=>607, 8161=>607, 8162=>607, 8163=>607, 8164=>644, 8165=>644, 8166=>607, - 8167=>607, 8168=>651, 8169=>651, 8170=>918, 8171=>882, 8172=>754, 8173=>450, 8174=>450, 8175=>450, 8178=>782, 8179=>782, 8180=>782, 8182=>782, 8183=>782, 8184=>958, 8185=>801, - 8186=>976, 8187=>804, 8188=>765, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, 8196=>296, 8197=>225, 8198=>150, 8199=>626, 8200=>342, 8201=>180, 8202=>89, - 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>374, 8209=>374, 8210=>626, 8213=>900, 8214=>450, 8215=>450, 8219=>342, 8223=>591, 8227=>575, 8228=>342, 8229=>616, - 8231=>313, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1717, 8242=>237, 8243=>402, 8244=>567, 8245=>237, 8246=>402, 8247=>567, 8248=>659, 8251=>875, - 8252=>564, 8253=>522, 8254=>450, 8255=>745, 8256=>745, 8257=>296, 8258=>920, 8259=>450, 8260=>150, 8261=>411, 8262=>411, 8263=>927, 8264=>746, 8265=>746, 8266=>461, 8267=>618, - 8268=>450, 8269=>450, 8270=>470, 8271=>360, 8272=>745, 8273=>470, 8274=>500, 8275=>754, 8276=>746, 8277=>754, 8278=>615, 8279=>731, 8280=>754, 8281=>754, 8282=>342, 8283=>784, - 8284=>754, 8285=>342, 8286=>342, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>394, 8305=>197, - 8308=>394, 8309=>394, 8310=>394, 8311=>394, 8312=>394, 8313=>394, 8314=>475, 8315=>475, 8316=>475, 8317=>259, 8318=>259, 8319=>410, 8320=>394, 8321=>394, 8322=>394, 8323=>394, - 8324=>394, 8325=>394, 8326=>394, 8327=>394, 8328=>394, 8329=>394, 8330=>475, 8331=>475, 8332=>475, 8333=>259, 8334=>259, 8336=>412, 8337=>431, 8338=>439, 8339=>371, 8340=>431, - 8352=>836, 8353=>626, 8354=>626, 8355=>626, 8356=>626, 8357=>938, 8358=>753, 8359=>1339, 8360=>1084, 8361=>993, 8362=>768, 8363=>642, 8365=>626, 8366=>614, 8367=>1252, 8368=>626, - 8369=>626, 8370=>626, 8371=>626, 8372=>773, 8373=>626, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>995, 8449=>995, 8450=>660, 8451=>1090, 8452=>807, 8453=>1002, 8454=>1033, - 8455=>626, 8456=>628, 8457=>856, 8459=>965, 8460=>822, 8461=>765, 8462=>641, 8463=>641, 8464=>544, 8465=>627, 8466=>781, 8467=>424, 8468=>876, 8469=>753, 8470=>1083, 8471=>900, - 8472=>627, 8473=>631, 8474=>765, 8475=>789, 8476=>732, 8477=>713, 8478=>807, 8479=>639, 8480=>917, 8481=>1115, 8483=>751, 8484=>652, 8485=>560, 8486=>765, 8487=>692, 8488=>686, - 8489=>272, 8490=>697, 8491=>696, 8492=>835, 8493=>699, 8494=>769, 8495=>572, 8496=>664, 8497=>729, 8498=>615, 8499=>1074, 8500=>418, 8501=>714, 8502=>662, 8503=>453, 8504=>625, - 8505=>342, 8506=>851, 8507=>1232, 8508=>710, 8509=>663, 8510=>586, 8511=>760, 8512=>756, 8513=>707, 8514=>518, 8515=>573, 8516=>684, 8517=>747, 8518=>644, 8519=>610, 8520=>308, - 8521=>308, 8523=>785, 8526=>492, 8531=>932, 8532=>932, 8533=>932, 8534=>932, 8535=>932, 8536=>932, 8537=>932, 8538=>932, 8539=>932, 8540=>932, 8541=>932, 8542=>932, 8543=>554, - 8544=>334, 8545=>593, 8546=>851, 8547=>989, 8548=>696, 8549=>989, 8550=>1247, 8551=>1505, 8552=>1008, 8553=>694, 8554=>1008, 8555=>1266, 8556=>573, 8557=>660, 8558=>747, 8559=>896, - 8560=>308, 8561=>546, 8562=>785, 8563=>885, 8564=>586, 8565=>866, 8566=>1104, 8567=>1342, 8568=>872, 8569=>580, 8570=>872, 8571=>1110, 8572=>308, 8573=>533, 8574=>644, 8575=>938, - 8576=>1160, 8577=>747, 8578=>1160, 8579=>660, 8580=>533, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8596=>754, 8597=>754, 8598=>754, 8599=>754, 8600=>754, 8601=>754, 8602=>754, - 8603=>754, 8604=>754, 8605=>754, 8606=>754, 8607=>754, 8608=>754, 8609=>754, 8610=>754, 8611=>754, 8612=>754, 8613=>754, 8614=>754, 8615=>754, 8616=>754, 8617=>754, 8618=>754, - 8619=>754, 8620=>754, 8621=>754, 8622=>754, 8623=>754, 8624=>754, 8625=>754, 8626=>754, 8627=>754, 8628=>754, 8629=>754, 8630=>754, 8631=>754, 8632=>754, 8633=>754, 8634=>754, - 8635=>754, 8636=>754, 8637=>754, 8638=>754, 8639=>754, 8640=>754, 8641=>754, 8642=>754, 8643=>754, 8644=>754, 8645=>754, 8646=>754, 8647=>754, 8648=>754, 8649=>754, 8650=>754, - 8651=>754, 8652=>754, 8653=>754, 8654=>754, 8655=>754, 8656=>754, 8657=>754, 8658=>754, 8659=>754, 8660=>754, 8661=>754, 8662=>754, 8663=>754, 8664=>754, 8665=>754, 8666=>754, - 8667=>754, 8668=>754, 8669=>754, 8670=>754, 8671=>754, 8672=>754, 8673=>754, 8674=>754, 8675=>754, 8676=>754, 8677=>754, 8678=>754, 8679=>754, 8680=>754, 8681=>754, 8682=>754, - 8683=>754, 8684=>754, 8685=>754, 8686=>754, 8687=>754, 8688=>754, 8689=>754, 8690=>754, 8691=>754, 8692=>754, 8693=>754, 8694=>754, 8695=>754, 8696=>754, 8697=>754, 8698=>754, - 8699=>754, 8700=>754, 8701=>754, 8702=>754, 8703=>754, 8704=>696, 8705=>626, 8706=>489, 8707=>615, 8708=>615, 8709=>771, 8710=>627, 8711=>627, 8712=>807, 8713=>807, 8714=>675, - 8715=>807, 8716=>807, 8717=>675, 8718=>572, 8719=>708, 8720=>708, 8721=>646, 8722=>754, 8723=>754, 8724=>626, 8725=>150, 8726=>626, 8727=>754, 8728=>563, 8729=>342, 8730=>600, - 8731=>600, 8732=>600, 8733=>602, 8734=>750, 8735=>754, 8736=>807, 8737=>807, 8738=>754, 8739=>450, 8740=>450, 8741=>450, 8742=>450, 8743=>730, 8744=>730, 8745=>730, 8746=>730, - 8747=>549, 8748=>835, 8749=>1165, 8750=>506, 8751=>879, 8752=>1181, 8753=>506, 8754=>506, 8755=>506, 8756=>626, 8757=>626, 8758=>264, 8759=>626, 8760=>754, 8761=>754, 8762=>754, - 8763=>754, 8764=>754, 8765=>754, 8766=>754, 8767=>754, 8768=>337, 8769=>754, 8770=>754, 8771=>754, 8772=>754, 8773=>754, 8774=>754, 8775=>754, 8776=>754, 8777=>754, 8778=>754, - 8779=>754, 8780=>754, 8781=>754, 8782=>754, 8783=>754, 8784=>754, 8785=>754, 8786=>754, 8787=>754, 8788=>956, 8789=>956, 8790=>754, 8791=>754, 8792=>754, 8793=>754, 8794=>754, - 8795=>754, 8796=>754, 8797=>754, 8798=>754, 8799=>754, 8800=>754, 8801=>754, 8802=>754, 8803=>754, 8804=>754, 8805=>754, 8806=>754, 8807=>754, 8808=>756, 8809=>756, 8810=>942, - 8811=>942, 8812=>450, 8813=>754, 8814=>754, 8815=>754, 8816=>754, 8817=>754, 8818=>754, 8819=>754, 8820=>754, 8821=>754, 8822=>754, 8823=>754, 8824=>754, 8825=>754, 8826=>754, - 8827=>754, 8828=>754, 8829=>754, 8830=>754, 8831=>754, 8832=>754, 8833=>754, 8834=>754, 8835=>754, 8836=>754, 8837=>754, 8838=>754, 8839=>754, 8840=>754, 8841=>754, 8842=>754, - 8843=>754, 8844=>730, 8845=>730, 8846=>730, 8847=>754, 8848=>754, 8849=>754, 8850=>754, 8851=>678, 8852=>678, 8853=>754, 8854=>754, 8855=>754, 8856=>754, 8857=>754, 8858=>754, - 8859=>754, 8860=>754, 8861=>754, 8862=>754, 8863=>754, 8864=>754, 8865=>754, 8866=>822, 8867=>822, 8868=>822, 8869=>822, 8870=>488, 8871=>488, 8872=>822, 8873=>822, 8874=>822, - 8875=>822, 8876=>822, 8877=>822, 8878=>822, 8879=>822, 8882=>754, 8883=>754, 8884=>754, 8885=>754, 8886=>900, 8887=>900, 8888=>754, 8889=>754, 8890=>488, 8891=>730, 8892=>730, - 8893=>730, 8896=>758, 8897=>758, 8898=>758, 8899=>758, 8900=>444, 8901=>342, 8902=>563, 8904=>900, 8905=>900, 8906=>900, 8907=>900, 8908=>900, 8909=>754, 8918=>754, 8919=>754, - 8920=>1280, 8921=>1280, 8922=>754, 8923=>754, 8924=>754, 8925=>754, 8926=>754, 8927=>754, 8928=>754, 8929=>754, 8930=>754, 8931=>754, 8932=>754, 8933=>754, 8934=>754, 8935=>754, - 8936=>754, 8937=>754, 8938=>754, 8939=>754, 8940=>754, 8941=>754, 8946=>1042, 8947=>807, 8948=>675, 8949=>807, 8950=>807, 8951=>675, 8952=>807, 8953=>807, 8954=>1042, 8955=>807, - 8956=>675, 8957=>807, 8958=>675, 8959=>807, 8962=>644, 8966=>826, 8968=>411, 8969=>411, 8970=>411, 8971=>411, 8976=>754, 8977=>484, 8984=>835, 8985=>754, 8992=>549, 8993=>549, - 8997=>900, 9000=>1299, 9085=>776, 9115=>450, 9116=>450, 9117=>450, 9118=>450, 9119=>450, 9120=>450, 9121=>450, 9122=>450, 9123=>450, 9124=>450, 9125=>450, 9126=>450, 9127=>675, - 9128=>675, 9129=>675, 9130=>675, 9131=>675, 9132=>675, 9133=>675, 9134=>549, 9166=>754, 9167=>850, 9250=>644, 9251=>644, 9312=>762, 9313=>762, 9314=>762, 9315=>762, 9316=>762, - 9317=>762, 9318=>762, 9319=>762, 9320=>762, 9321=>762, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, 9609=>692, 9610=>692, - 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, 9625=>692, 9626=>692, - 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, 9641=>850, 9642=>610, - 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, 9657=>452, 9658=>692, - 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, 9673=>785, 9674=>444, - 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>756, 9689=>873, 9690=>873, - 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>692, 9697=>692, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>575, 9703=>850, 9704=>850, 9705=>850, 9706=>850, - 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, 9721=>692, 9722=>692, - 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9729=>900, 9730=>807, 9731=>807, 9732=>807, 9733=>807, 9734=>807, 9735=>515, 9736=>806, 9737=>807, 9738=>799, - 9739=>799, 9740=>604, 9741=>911, 9742=>1121, 9743=>1125, 9744=>807, 9745=>807, 9746=>807, 9747=>479, 9748=>807, 9749=>807, 9750=>807, 9751=>807, 9752=>807, 9753=>807, 9754=>807, - 9755=>807, 9756=>807, 9757=>548, 9758=>807, 9759=>548, 9760=>807, 9761=>807, 9762=>807, 9763=>807, 9764=>602, 9765=>671, 9766=>584, 9767=>705, 9768=>490, 9769=>807, 9770=>807, - 9771=>807, 9772=>639, 9773=>807, 9774=>807, 9775=>807, 9776=>807, 9777=>807, 9778=>807, 9779=>807, 9780=>807, 9781=>807, 9782=>807, 9783=>807, 9784=>807, 9785=>807, 9786=>807, - 9787=>807, 9788=>807, 9789=>807, 9790=>807, 9791=>552, 9792=>658, 9793=>658, 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9800=>807, 9801=>807, 9802=>807, - 9803=>807, 9804=>807, 9805=>807, 9806=>807, 9807=>807, 9808=>807, 9809=>807, 9810=>807, 9811=>807, 9812=>807, 9813=>807, 9814=>807, 9815=>807, 9816=>807, 9817=>807, 9818=>807, - 9819=>807, 9820=>807, 9821=>807, 9822=>807, 9823=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9832=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 9840=>673, 9841=>689, 9842=>807, 9843=>807, 9844=>807, 9845=>807, 9846=>807, 9847=>807, 9848=>807, 9849=>807, 9850=>807, - 9851=>807, 9852=>807, 9853=>807, 9854=>807, 9855=>807, 9856=>782, 9857=>782, 9858=>782, 9859=>782, 9860=>782, 9861=>782, 9862=>807, 9863=>807, 9864=>807, 9865=>807, 9866=>807, - 9867=>807, 9868=>807, 9869=>807, 9870=>807, 9871=>807, 9872=>807, 9873=>807, 9874=>807, 9875=>807, 9876=>807, 9877=>487, 9878=>807, 9879=>807, 9880=>807, 9881=>807, 9882=>807, - 9883=>807, 9884=>807, 9888=>807, 9889=>632, 9890=>754, 9891=>754, 9892=>754, 9893=>754, 9894=>754, 9895=>754, 9896=>754, 9897=>754, 9898=>754, 9899=>754, 9900=>754, 9901=>754, - 9902=>754, 9903=>754, 9904=>759, 9905=>754, 9906=>658, 9985=>754, 9986=>754, 9987=>754, 9988=>754, 9990=>754, 9991=>754, 9992=>754, 9993=>754, 9996=>754, 9997=>754, 9998=>754, - 9999=>754, 10000=>754, 10001=>754, 10002=>754, 10003=>754, 10004=>754, 10005=>754, 10006=>754, 10007=>754, 10008=>754, 10009=>754, 10010=>754, 10011=>754, 10012=>754, 10013=>754, 10014=>754, - 10015=>754, 10016=>754, 10017=>754, 10018=>754, 10019=>754, 10020=>754, 10021=>754, 10022=>754, 10023=>754, 10025=>754, 10026=>754, 10027=>754, 10028=>754, 10029=>754, 10030=>754, 10031=>754, - 10032=>754, 10033=>754, 10034=>754, 10035=>754, 10036=>754, 10037=>754, 10038=>754, 10039=>754, 10040=>754, 10041=>754, 10042=>754, 10043=>754, 10044=>754, 10045=>754, 10046=>754, 10047=>754, - 10048=>754, 10049=>754, 10050=>754, 10051=>754, 10052=>754, 10053=>754, 10054=>754, 10055=>754, 10056=>754, 10057=>754, 10058=>754, 10059=>754, 10061=>807, 10063=>807, 10064=>807, 10065=>807, - 10066=>807, 10070=>807, 10072=>754, 10073=>754, 10074=>754, 10075=>290, 10076=>290, 10077=>484, 10078=>484, 10081=>754, 10082=>754, 10083=>754, 10084=>754, 10085=>754, 10086=>754, 10087=>754, - 10088=>754, 10089=>754, 10090=>754, 10091=>754, 10092=>754, 10093=>754, 10094=>754, 10095=>754, 10096=>754, 10097=>754, 10098=>754, 10099=>754, 10100=>754, 10101=>754, 10102=>762, 10103=>762, - 10104=>762, 10105=>762, 10106=>762, 10107=>762, 10108=>762, 10109=>762, 10110=>762, 10111=>762, 10112=>754, 10113=>754, 10114=>754, 10115=>754, 10116=>754, 10117=>754, 10118=>754, 10119=>754, - 10120=>754, 10121=>754, 10122=>754, 10123=>754, 10124=>754, 10125=>754, 10126=>754, 10127=>754, 10128=>754, 10129=>754, 10130=>754, 10131=>754, 10132=>754, 10136=>754, 10137=>754, 10138=>754, - 10139=>754, 10140=>754, 10141=>754, 10142=>754, 10143=>754, 10144=>754, 10145=>754, 10146=>754, 10147=>754, 10148=>754, 10149=>754, 10150=>754, 10151=>754, 10152=>754, 10153=>754, 10154=>754, - 10155=>754, 10156=>754, 10157=>754, 10158=>754, 10159=>754, 10161=>754, 10162=>754, 10163=>754, 10164=>754, 10165=>754, 10166=>754, 10167=>754, 10168=>754, 10169=>754, 10170=>754, 10171=>754, - 10172=>754, 10173=>754, 10174=>754, 10208=>444, 10214=>438, 10215=>438, 10216=>411, 10217=>411, 10218=>648, 10219=>648, 10224=>754, 10225=>754, 10226=>754, 10227=>754, 10228=>1042, 10229=>1290, - 10230=>1290, 10231=>1290, 10232=>1290, 10233=>1290, 10234=>1290, 10235=>1290, 10236=>1290, 10237=>1290, 10238=>1290, 10239=>1290, 10240=>703, 10241=>703, 10242=>703, 10243=>703, 10244=>703, 10245=>703, - 10246=>703, 10247=>703, 10248=>703, 10249=>703, 10250=>703, 10251=>703, 10252=>703, 10253=>703, 10254=>703, 10255=>703, 10256=>703, 10257=>703, 10258=>703, 10259=>703, 10260=>703, 10261=>703, - 10262=>703, 10263=>703, 10264=>703, 10265=>703, 10266=>703, 10267=>703, 10268=>703, 10269=>703, 10270=>703, 10271=>703, 10272=>703, 10273=>703, 10274=>703, 10275=>703, 10276=>703, 10277=>703, - 10278=>703, 10279=>703, 10280=>703, 10281=>703, 10282=>703, 10283=>703, 10284=>703, 10285=>703, 10286=>703, 10287=>703, 10288=>703, 10289=>703, 10290=>703, 10291=>703, 10292=>703, 10293=>703, - 10294=>703, 10295=>703, 10296=>703, 10297=>703, 10298=>703, 10299=>703, 10300=>703, 10301=>703, 10302=>703, 10303=>703, 10304=>703, 10305=>703, 10306=>703, 10307=>703, 10308=>703, 10309=>703, - 10310=>703, 10311=>703, 10312=>703, 10313=>703, 10314=>703, 10315=>703, 10316=>703, 10317=>703, 10318=>703, 10319=>703, 10320=>703, 10321=>703, 10322=>703, 10323=>703, 10324=>703, 10325=>703, - 10326=>703, 10327=>703, 10328=>703, 10329=>703, 10330=>703, 10331=>703, 10332=>703, 10333=>703, 10334=>703, 10335=>703, 10336=>703, 10337=>703, 10338=>703, 10339=>703, 10340=>703, 10341=>703, - 10342=>703, 10343=>703, 10344=>703, 10345=>703, 10346=>703, 10347=>703, 10348=>703, 10349=>703, 10350=>703, 10351=>703, 10352=>703, 10353=>703, 10354=>703, 10355=>703, 10356=>703, 10357=>703, - 10358=>703, 10359=>703, 10360=>703, 10361=>703, 10362=>703, 10363=>703, 10364=>703, 10365=>703, 10366=>703, 10367=>703, 10368=>703, 10369=>703, 10370=>703, 10371=>703, 10372=>703, 10373=>703, - 10374=>703, 10375=>703, 10376=>703, 10377=>703, 10378=>703, 10379=>703, 10380=>703, 10381=>703, 10382=>703, 10383=>703, 10384=>703, 10385=>703, 10386=>703, 10387=>703, 10388=>703, 10389=>703, - 10390=>703, 10391=>703, 10392=>703, 10393=>703, 10394=>703, 10395=>703, 10396=>703, 10397=>703, 10398=>703, 10399=>703, 10400=>703, 10401=>703, 10402=>703, 10403=>703, 10404=>703, 10405=>703, - 10406=>703, 10407=>703, 10408=>703, 10409=>703, 10410=>703, 10411=>703, 10412=>703, 10413=>703, 10414=>703, 10415=>703, 10416=>703, 10417=>703, 10418=>703, 10419=>703, 10420=>703, 10421=>703, - 10422=>703, 10423=>703, 10424=>703, 10425=>703, 10426=>703, 10427=>703, 10428=>703, 10429=>703, 10430=>703, 10431=>703, 10432=>703, 10433=>703, 10434=>703, 10435=>703, 10436=>703, 10437=>703, - 10438=>703, 10439=>703, 10440=>703, 10441=>703, 10442=>703, 10443=>703, 10444=>703, 10445=>703, 10446=>703, 10447=>703, 10448=>703, 10449=>703, 10450=>703, 10451=>703, 10452=>703, 10453=>703, - 10454=>703, 10455=>703, 10456=>703, 10457=>703, 10458=>703, 10459=>703, 10460=>703, 10461=>703, 10462=>703, 10463=>703, 10464=>703, 10465=>703, 10466=>703, 10467=>703, 10468=>703, 10469=>703, - 10470=>703, 10471=>703, 10472=>703, 10473=>703, 10474=>703, 10475=>703, 10476=>703, 10477=>703, 10478=>703, 10479=>703, 10480=>703, 10481=>703, 10482=>703, 10483=>703, 10484=>703, 10485=>703, - 10486=>703, 10487=>703, 10488=>703, 10489=>703, 10490=>703, 10491=>703, 10492=>703, 10493=>703, 10494=>703, 10495=>703, 10502=>754, 10503=>754, 10506=>754, 10507=>754, 10560=>754, 10561=>754, - 10702=>754, 10703=>941, 10704=>941, 10705=>900, 10706=>900, 10707=>900, 10708=>900, 10709=>900, 10731=>444, 10752=>900, 10753=>900, 10754=>900, 10764=>1495, 10765=>506, 10766=>506, 10767=>506, - 10768=>506, 10769=>506, 10770=>506, 10771=>506, 10772=>506, 10773=>506, 10774=>506, 10775=>506, 10776=>506, 10777=>506, 10778=>506, 10779=>506, 10780=>506, 10877=>754, 10878=>754, 10879=>754, - 10880=>754, 10881=>754, 10882=>754, 10883=>754, 10884=>754, 10885=>754, 10886=>754, 10887=>754, 10888=>754, 10889=>754, 10890=>754, 10891=>754, 10892=>754, 10893=>754, 10894=>754, 10895=>754, - 10896=>754, 10897=>754, 10898=>754, 10899=>754, 10900=>754, 10901=>754, 10902=>754, 10903=>754, 10904=>754, 10905=>754, 10906=>754, 10907=>754, 10908=>754, 10909=>754, 10910=>754, 10911=>754, - 10912=>754, 10926=>754, 10927=>754, 10928=>754, 10929=>754, 10930=>754, 10931=>754, 10932=>754, 10933=>754, 10934=>754, 10935=>754, 10936=>754, 10937=>754, 10938=>754, 11001=>754, 11002=>754, - 11008=>754, 11009=>754, 11010=>754, 11011=>754, 11012=>754, 11013=>754, 11014=>754, 11015=>754, 11016=>754, 11017=>754, 11018=>754, 11019=>754, 11020=>754, 11021=>754, 11022=>754, 11023=>754, - 11024=>754, 11025=>754, 11026=>850, 11027=>850, 11028=>850, 11029=>850, 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 11040=>782, 11041=>786, 11042=>786, 11043=>786, 11360=>573, - 11361=>324, 11362=>573, 11363=>659, 11364=>693, 11365=>607, 11366=>430, 11367=>860, 11368=>641, 11369=>697, 11370=>598, 11371=>652, 11372=>523, 11380=>586, 11381=>584, 11382=>464, 11383=>704, - 61960=>774, 62047=>647, 62917=>618, 64256=>749, 64257=>708, 64258=>708, 64259=>1024, 64260=>1024, 64261=>727, 64262=>917, 64275=>1249, 64276=>1245, 64277=>1240, 64278=>1245, 64279=>1542, 64285=>334, - 64287=>623, 64288=>647, 64297=>754, 64298=>877, 64299=>877, 64300=>877, 64301=>877, 64302=>676, 64303=>676, 64304=>676, 64305=>658, 64306=>452, 64307=>615, 64308=>700, 64309=>420, 64310=>468, - 64312=>747, 64313=>420, 64314=>700, 64315=>678, 64316=>650, 64318=>781, 64320=>479, 64321=>747, 64323=>744, 64324=>779, 64326=>654, 64327=>733, 64328=>700, 64329=>877, 64330=>740, 64331=>334, - 64332=>658, 64333=>678, 64334=>779, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, - 65037=>0, 65038=>0, 65039=>0, 65533=>1002}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansCondensed-BoldOblique.z'; - font[:ctg]='DejaVuSansCondensed-BoldOblique.ctg.z'; - font[:originalsize]=436624; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensedi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansCondensedi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansCondensedi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansCondensed-Oblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-914 -385 1493 1068]','ItalicAngle'=>-11,'StemV'=>70,'MissingWidth'=>540}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>286, 33=>360, 34=>414, 35=>754, 36=>572, 37=>855, 38=>702, 39=>247, 40=>351, 41=>351, 42=>450, 43=>754, 44=>286, 45=>325, 46=>286, - 47=>303, 48=>572, 49=>572, 50=>572, 51=>572, 52=>572, 53=>572, 54=>572, 55=>572, 56=>572, 57=>572, 58=>303, 59=>303, 60=>754, 61=>754, 62=>754, - 63=>478, 64=>900, 65=>615, 66=>617, 67=>628, 68=>693, 69=>568, 70=>518, 71=>697, 72=>677, 73=>265, 74=>265, 75=>590, 76=>501, 77=>776, 78=>673, - 79=>708, 80=>542, 81=>708, 82=>625, 83=>571, 84=>549, 85=>659, 86=>615, 87=>890, 88=>616, 89=>549, 90=>616, 91=>351, 92=>303, 93=>351, 94=>754, - 95=>450, 96=>450, 97=>551, 98=>571, 99=>495, 100=>571, 101=>554, 102=>316, 103=>571, 104=>570, 105=>250, 106=>250, 107=>521, 108=>250, 109=>876, 110=>570, - 111=>550, 112=>571, 113=>571, 114=>370, 115=>469, 116=>353, 117=>570, 118=>532, 119=>736, 120=>532, 121=>532, 122=>472, 123=>572, 124=>303, 125=>572, 126=>754, - 8364=>572, 1027=>501, 8218=>286, 402=>316, 8222=>466, 8230=>900, 8224=>450, 8225=>450, 710=>450, 8240=>1215, 352=>571, 8249=>360, 338=>962, 1036=>639, 381=>616, 1039=>677, - 8216=>286, 8217=>286, 8220=>466, 8221=>466, 8226=>531, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>469, 8250=>360, 339=>925, 1116=>543, 382=>472, 376=>549, 160=>286, - 161=>360, 162=>572, 163=>572, 164=>572, 165=>572, 166=>303, 167=>450, 168=>450, 169=>900, 170=>424, 171=>555, 172=>754, 173=>325, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>360, 179=>360, 180=>450, 181=>572, 182=>572, 183=>286, 184=>450, 185=>360, 186=>424, 187=>555, 188=>872, 189=>872, 190=>872, 191=>478, 192=>615, - 193=>615, 194=>615, 195=>615, 196=>615, 197=>615, 198=>876, 199=>628, 200=>568, 201=>568, 202=>568, 203=>568, 204=>265, 205=>265, 206=>265, 207=>265, 208=>697, - 209=>673, 210=>708, 211=>708, 212=>708, 213=>708, 214=>708, 215=>754, 216=>708, 217=>659, 218=>659, 219=>659, 220=>659, 221=>549, 222=>547, 223=>567, 224=>551, - 225=>551, 226=>551, 227=>551, 228=>551, 229=>551, 230=>896, 231=>495, 232=>554, 233=>554, 234=>554, 235=>554, 236=>250, 237=>250, 238=>250, 239=>250, 240=>550, - 241=>570, 242=>550, 243=>550, 244=>550, 245=>550, 246=>550, 247=>754, 248=>550, 249=>570, 250=>570, 251=>570, 252=>570, 253=>532, 254=>571, 255=>532, 256=>615, - 257=>551, 258=>615, 259=>551, 260=>615, 261=>551, 262=>628, 263=>495, 264=>628, 265=>495, 266=>628, 267=>495, 268=>628, 269=>495, 270=>693, 271=>571, 272=>697, - 273=>571, 274=>568, 275=>554, 276=>568, 277=>554, 278=>568, 279=>554, 280=>568, 281=>554, 282=>568, 283=>554, 284=>697, 285=>571, 286=>697, 287=>571, 288=>697, - 289=>571, 290=>697, 291=>571, 292=>677, 293=>570, 294=>824, 295=>625, 296=>265, 297=>250, 298=>265, 299=>250, 300=>265, 301=>250, 302=>265, 303=>250, 304=>265, - 305=>250, 306=>531, 307=>500, 308=>265, 309=>250, 310=>590, 311=>521, 312=>521, 313=>501, 314=>250, 315=>501, 316=>250, 317=>501, 318=>296, 319=>501, 320=>536, - 321=>505, 322=>258, 323=>673, 324=>570, 325=>673, 326=>570, 327=>673, 328=>570, 329=>732, 330=>673, 331=>570, 332=>708, 333=>550, 334=>708, 335=>550, 336=>708, - 337=>550, 340=>625, 341=>370, 342=>625, 343=>370, 344=>625, 345=>370, 346=>571, 347=>469, 348=>571, 349=>469, 350=>571, 351=>469, 354=>549, 355=>353, 356=>549, - 357=>353, 358=>549, 359=>353, 360=>659, 361=>570, 362=>659, 363=>570, 364=>659, 365=>570, 366=>659, 367=>570, 368=>659, 369=>570, 370=>659, 371=>570, 372=>890, - 373=>736, 374=>549, 375=>532, 377=>616, 378=>472, 379=>616, 380=>472, 383=>316, 384=>571, 385=>661, 386=>617, 387=>571, 388=>617, 389=>571, 390=>633, 391=>628, - 392=>495, 393=>697, 394=>737, 395=>617, 396=>571, 397=>550, 398=>568, 399=>708, 400=>553, 401=>518, 403=>697, 404=>618, 405=>885, 406=>318, 407=>265, 408=>671, - 409=>521, 410=>250, 411=>532, 412=>876, 413=>673, 414=>570, 415=>708, 416=>822, 417=>550, 418=>844, 419=>663, 420=>586, 421=>571, 422=>625, 423=>571, 424=>469, - 425=>568, 426=>302, 427=>353, 428=>549, 429=>353, 430=>549, 431=>754, 432=>570, 433=>688, 434=>648, 435=>669, 436=>656, 437=>616, 438=>472, 439=>599, 440=>599, - 441=>520, 442=>472, 443=>572, 444=>599, 445=>520, 446=>459, 447=>571, 448=>265, 449=>443, 450=>413, 451=>266, 452=>1310, 453=>1165, 454=>1043, 455=>767, 456=>751, - 457=>500, 458=>938, 459=>923, 460=>820, 461=>615, 462=>551, 463=>265, 464=>250, 465=>708, 466=>550, 467=>659, 468=>570, 469=>659, 470=>570, 471=>659, 472=>570, - 473=>659, 474=>570, 475=>659, 476=>570, 477=>554, 478=>615, 479=>551, 480=>615, 481=>551, 482=>876, 483=>896, 484=>697, 485=>571, 486=>697, 487=>571, 488=>590, - 489=>521, 490=>708, 491=>550, 492=>708, 493=>550, 494=>599, 495=>472, 496=>250, 497=>1310, 498=>1165, 499=>1043, 500=>697, 501=>571, 502=>1001, 503=>614, 504=>673, - 505=>570, 506=>615, 507=>551, 508=>876, 509=>896, 510=>708, 511=>550, 512=>615, 513=>551, 514=>615, 515=>551, 516=>568, 517=>554, 518=>568, 519=>554, 520=>265, - 521=>250, 522=>265, 523=>250, 524=>708, 525=>550, 526=>708, 527=>550, 528=>625, 529=>370, 530=>625, 531=>370, 532=>659, 533=>570, 534=>659, 535=>570, 536=>571, - 537=>469, 538=>549, 539=>353, 540=>564, 541=>469, 542=>677, 543=>570, 544=>662, 545=>754, 546=>628, 547=>549, 548=>616, 549=>472, 550=>615, 551=>551, 552=>568, - 553=>554, 554=>708, 555=>550, 556=>708, 557=>550, 558=>708, 559=>550, 560=>708, 561=>550, 562=>549, 563=>532, 564=>427, 565=>758, 566=>429, 567=>250, 568=>898, - 569=>898, 570=>615, 571=>628, 572=>495, 573=>501, 574=>549, 575=>469, 576=>472, 577=>542, 578=>431, 579=>617, 580=>659, 581=>615, 582=>568, 583=>554, 584=>265, - 585=>250, 586=>703, 587=>571, 588=>625, 589=>370, 590=>549, 591=>532, 592=>551, 593=>571, 594=>571, 595=>571, 596=>495, 597=>495, 598=>571, 599=>654, 600=>554, - 601=>554, 602=>759, 603=>490, 604=>490, 605=>698, 606=>598, 607=>293, 608=>626, 609=>571, 610=>566, 611=>536, 612=>536, 613=>570, 614=>570, 615=>570, 616=>334, - 617=>348, 618=>334, 619=>356, 620=>438, 621=>250, 622=>635, 623=>876, 624=>876, 625=>876, 626=>581, 627=>578, 628=>570, 629=>550, 630=>772, 631=>655, 632=>593, - 633=>422, 634=>422, 635=>422, 636=>422, 637=>422, 638=>477, 639=>477, 640=>541, 641=>541, 642=>469, 643=>302, 644=>302, 645=>415, 646=>302, 647=>353, 648=>353, - 649=>570, 650=>556, 651=>538, 652=>532, 653=>736, 654=>532, 655=>549, 656=>472, 657=>472, 658=>520, 659=>520, 660=>459, 661=>459, 662=>459, 663=>459, 664=>708, - 665=>521, 666=>598, 667=>637, 668=>588, 669=>263, 670=>600, 671=>456, 672=>654, 673=>459, 674=>459, 675=>913, 676=>952, 677=>911, 678=>742, 679=>549, 680=>700, - 681=>763, 682=>576, 683=>589, 684=>463, 685=>463, 686=>513, 687=>597, 688=>359, 689=>359, 690=>157, 691=>233, 692=>266, 693=>266, 694=>341, 695=>463, 696=>335, - 697=>250, 698=>414, 699=>286, 700=>286, 701=>286, 702=>276, 703=>276, 704=>333, 705=>333, 706=>450, 707=>450, 708=>450, 709=>450, 711=>450, 712=>247, 713=>450, - 714=>450, 715=>450, 716=>247, 717=>450, 718=>450, 719=>450, 720=>303, 721=>303, 722=>276, 723=>276, 724=>450, 725=>450, 726=>371, 727=>450, 728=>450, 729=>450, - 730=>450, 731=>450, 733=>450, 734=>284, 735=>450, 736=>383, 737=>149, 738=>335, 739=>399, 740=>333, 741=>444, 742=>444, 743=>444, 744=>444, 745=>444, 748=>450, - 749=>450, 750=>450, 755=>450, 759=>450, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, - 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, - 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, - 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, - 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, - 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, 884=>250, 885=>250, - 890=>450, 891=>494, 892=>495, 893=>494, 894=>303, 900=>450, 901=>450, 902=>625, 903=>286, 904=>690, 905=>813, 906=>391, 908=>755, 910=>773, 911=>814, 912=>304, - 913=>615, 914=>617, 915=>501, 916=>615, 917=>568, 918=>616, 919=>677, 920=>708, 921=>265, 922=>590, 923=>615, 924=>776, 925=>673, 926=>568, 927=>708, 928=>677, - 929=>542, 931=>568, 932=>549, 933=>549, 934=>708, 935=>616, 936=>708, 937=>688, 938=>265, 939=>549, 940=>593, 941=>488, 942=>567, 943=>304, 944=>521, 945=>593, - 946=>574, 947=>532, 948=>550, 949=>486, 950=>489, 951=>570, 952=>550, 953=>304, 954=>530, 955=>532, 956=>572, 957=>502, 958=>501, 959=>550, 960=>542, 961=>571, - 962=>528, 963=>570, 964=>542, 965=>521, 966=>593, 967=>532, 968=>593, 969=>753, 970=>304, 971=>521, 972=>550, 973=>521, 974=>753, 976=>553, 977=>557, 978=>628, - 979=>758, 980=>628, 981=>593, 982=>753, 983=>597, 984=>708, 985=>550, 986=>583, 987=>528, 988=>518, 989=>413, 990=>593, 991=>593, 992=>778, 993=>564, 994=>840, - 995=>753, 996=>682, 997=>593, 998=>712, 999=>553, 1000=>618, 1001=>546, 1002=>690, 1003=>563, 1004=>629, 1005=>550, 1006=>549, 1007=>482, 1008=>597, 1009=>571, 1010=>495, - 1011=>250, 1012=>708, 1013=>554, 1014=>554, 1015=>547, 1016=>571, 1017=>628, 1018=>776, 1019=>585, 1020=>571, 1021=>633, 1022=>628, 1023=>633, 1024=>568, 1025=>568, 1026=>708, - 1028=>628, 1029=>571, 1030=>265, 1031=>265, 1032=>265, 1033=>984, 1034=>940, 1035=>708, 1037=>673, 1038=>548, 1040=>615, 1041=>617, 1042=>617, 1043=>501, 1044=>703, 1045=>568, - 1046=>969, 1047=>577, 1048=>673, 1049=>673, 1050=>639, 1051=>677, 1052=>776, 1053=>677, 1054=>708, 1055=>677, 1056=>542, 1057=>628, 1058=>549, 1059=>548, 1060=>774, 1061=>616, - 1062=>699, 1063=>617, 1064=>962, 1065=>984, 1066=>749, 1067=>736, 1068=>617, 1069=>628, 1070=>971, 1071=>625, 1072=>551, 1073=>555, 1074=>530, 1075=>473, 1076=>622, 1077=>554, - 1078=>811, 1079=>479, 1080=>584, 1081=>584, 1082=>543, 1083=>575, 1084=>679, 1085=>588, 1086=>550, 1087=>588, 1088=>571, 1089=>495, 1090=>524, 1091=>532, 1092=>769, 1093=>532, - 1094=>612, 1095=>532, 1096=>823, 1097=>848, 1098=>636, 1099=>710, 1100=>530, 1101=>494, 1102=>757, 1103=>541, 1104=>554, 1105=>554, 1106=>563, 1107=>473, 1108=>494, 1109=>469, - 1110=>250, 1111=>250, 1112=>250, 1113=>812, 1114=>809, 1115=>586, 1117=>584, 1118=>532, 1119=>588, 1120=>840, 1121=>753, 1122=>693, 1123=>604, 1124=>848, 1125=>674, 1126=>791, - 1127=>705, 1128=>1043, 1129=>901, 1130=>708, 1131=>550, 1132=>924, 1133=>742, 1134=>572, 1135=>486, 1136=>771, 1137=>789, 1138=>708, 1139=>533, 1140=>703, 1141=>598, 1142=>703, - 1143=>598, 1144=>893, 1145=>813, 1146=>857, 1147=>682, 1148=>1062, 1149=>925, 1150=>840, 1151=>753, 1152=>628, 1153=>495, 1154=>452, 1155=>0, 1156=>0, 1157=>0, 1158=>0, - 1160=>376, 1161=>376, 1162=>673, 1163=>591, 1164=>617, 1165=>530, 1166=>542, 1167=>571, 1168=>549, 1169=>473, 1170=>607, 1171=>500, 1172=>501, 1173=>441, 1174=>969, 1175=>811, - 1176=>577, 1177=>479, 1178=>639, 1179=>543, 1180=>639, 1181=>543, 1182=>639, 1183=>543, 1184=>771, 1185=>748, 1186=>677, 1187=>594, 1188=>913, 1189=>789, 1190=>1002, 1191=>855, - 1192=>716, 1193=>586, 1194=>628, 1195=>495, 1196=>549, 1197=>476, 1198=>549, 1199=>532, 1200=>549, 1201=>532, 1202=>616, 1203=>532, 1204=>840, 1205=>726, 1206=>617, 1207=>532, - 1208=>617, 1209=>532, 1210=>617, 1211=>570, 1212=>836, 1213=>658, 1214=>836, 1215=>658, 1216=>265, 1217=>969, 1218=>811, 1219=>589, 1220=>543, 1221=>677, 1222=>575, 1223=>677, - 1224=>594, 1225=>677, 1226=>594, 1227=>617, 1228=>532, 1229=>776, 1230=>679, 1231=>250, 1232=>615, 1233=>551, 1234=>615, 1235=>551, 1236=>876, 1237=>896, 1238=>568, 1239=>554, - 1240=>708, 1241=>554, 1242=>708, 1243=>554, 1244=>969, 1245=>811, 1246=>577, 1247=>479, 1248=>599, 1249=>520, 1250=>673, 1251=>584, 1252=>673, 1253=>584, 1254=>708, 1255=>550, - 1256=>708, 1257=>550, 1258=>708, 1259=>550, 1260=>628, 1261=>494, 1262=>548, 1263=>532, 1264=>548, 1265=>532, 1266=>548, 1267=>532, 1268=>617, 1269=>532, 1270=>501, 1271=>442, - 1272=>736, 1273=>710, 1274=>607, 1275=>500, 1276=>616, 1277=>532, 1278=>616, 1279=>532, 1280=>617, 1281=>530, 1282=>905, 1283=>807, 1284=>877, 1285=>782, 1286=>611, 1287=>529, - 1288=>964, 1289=>861, 1290=>965, 1291=>870, 1292=>697, 1293=>593, 1294=>695, 1295=>640, 1296=>553, 1297=>486, 1298=>677, 1299=>575, 1329=>780, 1330=>659, 1331=>794, 1332=>794, - 1333=>659, 1334=>579, 1335=>613, 1336=>659, 1337=>765, 1338=>794, 1339=>659, 1340=>501, 1341=>741, 1342=>888, 1343=>659, 1344=>636, 1345=>579, 1346=>794, 1347=>699, 1348=>794, - 1349=>659, 1350=>756, 1351=>659, 1352=>659, 1353=>659, 1354=>711, 1355=>579, 1356=>794, 1357=>659, 1358=>794, 1359=>571, 1360=>659, 1361=>659, 1362=>719, 1363=>774, 1364=>711, - 1365=>708, 1366=>571, 1369=>276, 1370=>286, 1371=>450, 1372=>450, 1373=>352, 1374=>474, 1375=>450, 1377=>876, 1378=>570, 1379=>686, 1380=>690, 1381=>570, 1382=>627, 1383=>479, - 1384=>570, 1385=>630, 1386=>627, 1387=>570, 1388=>363, 1389=>804, 1390=>576, 1391=>570, 1392=>570, 1393=>571, 1394=>631, 1395=>570, 1396=>593, 1397=>250, 1398=>684, 1399=>464, - 1400=>570, 1401=>407, 1402=>876, 1403=>464, 1404=>691, 1405=>570, 1406=>626, 1407=>876, 1408=>570, 1409=>621, 1410=>451, 1411=>876, 1412=>583, 1413=>550, 1414=>566, 1415=>686, - 1417=>303, 1418=>390, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, 1469=>0, 1471=>0, - 1472=>265, 1473=>0, 1474=>0, 1475=>265, 1478=>410, 1479=>0, 1488=>566, 1489=>547, 1490=>403, 1491=>534, 1492=>576, 1493=>245, 1494=>380, 1495=>576, 1496=>583, 1497=>245, - 1498=>532, 1499=>500, 1500=>539, 1501=>576, 1502=>593, 1503=>245, 1504=>397, 1505=>629, 1506=>572, 1507=>576, 1508=>543, 1509=>468, 1510=>523, 1511=>596, 1512=>532, 1513=>727, - 1514=>591, 1520=>423, 1521=>409, 1522=>423, 3647=>586, 3713=>603, 3714=>615, 3716=>619, 3719=>434, 3720=>565, 3722=>615, 3725=>619, 3732=>577, 3733=>577, 3734=>605, 3735=>589, - 3737=>576, 3738=>533, 3739=>533, 3740=>670, 3741=>690, 3742=>618, 3743=>618, 3745=>631, 3746=>619, 3747=>615, 3749=>584, 3751=>569, 3754=>633, 3755=>737, 3757=>569, 3758=>615, - 3759=>708, 3760=>569, 3761=>0, 3762=>485, 3763=>485, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>597, 3776=>324, 3777=>611, - 3778=>414, 3779=>492, 3780=>442, 3782=>606, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>925, 3805=>925, 5121=>615, 5122=>615, 5123=>615, 5124=>615, - 5125=>728, 5126=>728, 5127=>728, 5129=>728, 5130=>647, 5131=>647, 5132=>751, 5133=>751, 5134=>751, 5135=>751, 5136=>751, 5137=>751, 5138=>870, 5139=>906, 5140=>870, 5141=>906, - 5142=>728, 5143=>870, 5144=>906, 5145=>870, 5146=>906, 5147=>647, 5149=>230, 5150=>488, 5151=>381, 5152=>381, 5153=>350, 5154=>350, 5155=>354, 5156=>350, 5157=>419, 5158=>347, - 5159=>230, 5160=>350, 5161=>350, 5162=>350, 5163=>980, 5164=>817, 5165=>857, 5166=>1005, 5167=>615, 5168=>615, 5169=>615, 5170=>615, 5171=>566, 5172=>566, 5173=>566, 5175=>566, - 5176=>566, 5177=>566, 5178=>751, 5179=>615, 5180=>751, 5181=>751, 5182=>751, 5183=>751, 5184=>870, 5185=>906, 5186=>870, 5187=>906, 5188=>870, 5189=>906, 5190=>870, 5191=>906, - 5192=>656, 5193=>457, 5194=>172, 5196=>659, 5197=>659, 5198=>659, 5199=>659, 5200=>657, 5201=>657, 5202=>657, 5204=>657, 5205=>657, 5206=>657, 5207=>829, 5208=>800, 5209=>829, - 5210=>800, 5211=>829, 5212=>800, 5213=>835, 5214=>810, 5215=>835, 5216=>810, 5217=>853, 5218=>810, 5219=>853, 5220=>810, 5221=>853, 5222=>457, 5223=>790, 5224=>790, 5225=>779, - 5226=>801, 5227=>565, 5228=>565, 5229=>565, 5230=>565, 5231=>565, 5232=>565, 5233=>565, 5234=>565, 5235=>565, 5236=>773, 5237=>693, 5238=>733, 5239=>734, 5240=>733, 5241=>734, - 5242=>773, 5243=>693, 5244=>773, 5245=>693, 5246=>733, 5247=>734, 5248=>733, 5249=>734, 5250=>733, 5251=>366, 5252=>366, 5253=>675, 5254=>697, 5255=>675, 5256=>697, 5257=>565, - 5258=>565, 5259=>565, 5260=>565, 5261=>565, 5262=>565, 5263=>565, 5264=>565, 5265=>565, 5266=>773, 5267=>693, 5268=>733, 5269=>734, 5270=>733, 5271=>734, 5272=>773, 5273=>693, - 5274=>773, 5275=>693, 5276=>733, 5277=>734, 5278=>733, 5279=>734, 5280=>733, 5281=>391, 5282=>391, 5283=>470, 5284=>470, 5285=>470, 5286=>470, 5287=>470, 5288=>470, 5289=>470, - 5290=>470, 5291=>470, 5292=>674, 5293=>691, 5294=>671, 5295=>687, 5296=>671, 5297=>687, 5298=>674, 5299=>691, 5300=>674, 5301=>691, 5302=>671, 5303=>687, 5304=>671, 5305=>687, - 5306=>671, 5307=>347, 5308=>457, 5309=>347, 5312=>766, 5313=>766, 5314=>766, 5315=>766, 5316=>719, 5317=>719, 5318=>719, 5319=>719, 5320=>719, 5321=>962, 5322=>931, 5323=>953, - 5324=>766, 5325=>953, 5326=>719, 5327=>766, 5328=>540, 5329=>407, 5330=>540, 5331=>766, 5332=>766, 5333=>766, 5334=>766, 5335=>719, 5336=>719, 5337=>719, 5338=>719, 5339=>719, - 5340=>962, 5341=>931, 5342=>953, 5343=>927, 5344=>953, 5345=>927, 5346=>962, 5347=>931, 5348=>962, 5349=>931, 5350=>975, 5351=>927, 5352=>975, 5353=>927, 5354=>540, 5356=>656, - 5357=>542, 5358=>542, 5359=>542, 5360=>542, 5361=>542, 5362=>542, 5363=>542, 5364=>542, 5365=>542, 5366=>751, 5367=>678, 5368=>712, 5369=>694, 5370=>712, 5371=>694, 5372=>751, - 5373=>678, 5374=>751, 5375=>678, 5376=>712, 5377=>694, 5378=>712, 5379=>694, 5380=>712, 5381=>376, 5382=>378, 5383=>376, 5392=>641, 5393=>641, 5394=>641, 5395=>802, 5396=>802, - 5397=>802, 5398=>802, 5399=>818, 5400=>785, 5401=>818, 5402=>785, 5403=>818, 5404=>785, 5405=>1026, 5406=>989, 5407=>1026, 5408=>989, 5409=>1026, 5410=>989, 5411=>1026, 5412=>989, - 5413=>576, 5414=>564, 5415=>564, 5416=>564, 5417=>564, 5418=>564, 5419=>564, 5420=>564, 5421=>564, 5422=>564, 5423=>760, 5424=>703, 5425=>734, 5426=>736, 5427=>734, 5428=>736, - 5429=>760, 5430=>703, 5431=>760, 5432=>703, 5433=>734, 5434=>736, 5435=>734, 5436=>736, 5437=>734, 5438=>376, 5440=>350, 5441=>436, 5442=>824, 5443=>824, 5444=>776, 5445=>824, - 5446=>776, 5447=>776, 5448=>542, 5449=>542, 5450=>542, 5451=>542, 5452=>542, 5453=>542, 5454=>751, 5455=>678, 5456=>376, 5458=>656, 5459=>615, 5460=>615, 5461=>615, 5462=>615, - 5463=>605, 5464=>605, 5465=>605, 5466=>605, 5467=>831, 5468=>906, 5469=>457, 5470=>659, 5471=>659, 5472=>659, 5473=>659, 5474=>659, 5475=>659, 5476=>657, 5477=>657, 5478=>657, - 5479=>657, 5480=>853, 5481=>810, 5482=>457, 5492=>747, 5493=>747, 5494=>747, 5495=>747, 5496=>747, 5497=>747, 5498=>747, 5499=>507, 5500=>677, 5501=>436, 5502=>942, 5503=>942, - 5504=>942, 5505=>942, 5506=>942, 5507=>942, 5508=>942, 5509=>743, 5514=>747, 5515=>747, 5516=>747, 5517=>747, 5518=>1133, 5519=>1133, 5520=>1133, 5521=>901, 5522=>901, 5523=>1133, - 5524=>1133, 5525=>629, 5526=>965, 5536=>766, 5537=>766, 5538=>719, 5539=>719, 5540=>719, 5541=>719, 5542=>540, 5543=>579, 5544=>579, 5545=>579, 5546=>579, 5547=>579, 5548=>579, - 5549=>579, 5550=>376, 5551=>565, 5598=>693, 5601=>693, 5702=>421, 5703=>421, 5742=>399, 5743=>942, 5744=>1178, 5745=>1469, 5746=>1469, 5747=>1237, 5748=>1237, 5749=>1469, 5750=>1469, - 7424=>532, 7425=>646, 7426=>883, 7427=>527, 7428=>495, 7429=>544, 7430=>544, 7431=>441, 7432=>486, 7433=>250, 7434=>355, 7435=>521, 7436=>524, 7437=>679, 7438=>584, 7439=>550, - 7440=>495, 7441=>615, 7442=>615, 7443=>615, 7444=>920, 7446=>550, 7447=>550, 7448=>472, 7449=>541, 7450=>541, 7451=>524, 7452=>517, 7453=>663, 7454=>853, 7455=>574, 7456=>532, - 7457=>736, 7458=>472, 7459=>473, 7462=>524, 7463=>532, 7464=>507, 7465=>472, 7466=>531, 7467=>575, 7468=>387, 7469=>552, 7470=>389, 7472=>436, 7473=>358, 7474=>358, 7475=>439, - 7476=>426, 7477=>167, 7478=>167, 7479=>372, 7480=>315, 7481=>489, 7482=>424, 7483=>424, 7484=>446, 7485=>396, 7486=>342, 7487=>394, 7488=>346, 7489=>415, 7490=>560, 7491=>352, - 7492=>352, 7493=>365, 7494=>583, 7495=>385, 7496=>365, 7497=>375, 7498=>375, 7499=>324, 7500=>323, 7501=>365, 7502=>161, 7503=>383, 7504=>561, 7505=>368, 7506=>372, 7507=>333, - 7508=>372, 7509=>372, 7510=>385, 7511=>265, 7512=>364, 7513=>422, 7514=>561, 7515=>375, 7516=>900, 7517=>361, 7518=>335, 7519=>347, 7520=>374, 7521=>327, 7522=>161, 7523=>233, - 7524=>364, 7525=>375, 7526=>361, 7527=>335, 7528=>347, 7529=>374, 7530=>327, 7543=>571, 7544=>426, 7547=>334, 7557=>250, 7579=>365, 7580=>333, 7581=>333, 7582=>372, 7583=>324, - 7584=>267, 7585=>209, 7586=>365, 7587=>364, 7588=>235, 7589=>224, 7590=>234, 7591=>235, 7592=>211, 7593=>224, 7594=>211, 7595=>338, 7596=>561, 7597=>561, 7598=>369, 7599=>431, - 7600=>368, 7601=>372, 7602=>372, 7603=>324, 7604=>258, 7605=>265, 7606=>457, 7607=>376, 7608=>325, 7609=>365, 7610=>375, 7611=>330, 7612=>393, 7613=>330, 7614=>353, 7615=>372, - 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>615, 7681=>551, 7682=>617, 7683=>571, 7684=>617, 7685=>571, 7686=>617, 7687=>571, 7688=>628, 7689=>495, - 7690=>693, 7691=>571, 7692=>693, 7693=>571, 7694=>693, 7695=>571, 7696=>693, 7697=>571, 7698=>693, 7699=>571, 7700=>568, 7701=>554, 7702=>568, 7703=>554, 7704=>568, 7705=>554, - 7706=>568, 7707=>554, 7708=>568, 7709=>554, 7710=>518, 7711=>316, 7712=>697, 7713=>571, 7714=>677, 7715=>570, 7716=>677, 7717=>570, 7718=>677, 7719=>570, 7720=>677, 7721=>570, - 7722=>677, 7723=>570, 7724=>265, 7725=>250, 7726=>265, 7727=>250, 7728=>590, 7729=>521, 7730=>590, 7731=>521, 7732=>590, 7733=>521, 7734=>501, 7735=>250, 7736=>501, 7737=>250, - 7738=>501, 7739=>250, 7740=>501, 7741=>250, 7742=>776, 7743=>876, 7744=>776, 7745=>876, 7746=>776, 7747=>876, 7748=>673, 7749=>570, 7750=>673, 7751=>570, 7752=>673, 7753=>570, - 7754=>673, 7755=>570, 7756=>708, 7757=>550, 7758=>708, 7759=>550, 7760=>708, 7761=>550, 7762=>708, 7763=>550, 7764=>542, 7765=>571, 7766=>542, 7767=>571, 7768=>625, 7769=>370, - 7770=>625, 7771=>370, 7772=>625, 7773=>370, 7774=>625, 7775=>370, 7776=>571, 7777=>469, 7778=>571, 7779=>469, 7780=>571, 7781=>469, 7782=>571, 7783=>469, 7784=>571, 7785=>469, - 7786=>549, 7787=>353, 7788=>549, 7789=>353, 7790=>549, 7791=>353, 7792=>549, 7793=>353, 7794=>659, 7795=>570, 7796=>659, 7797=>570, 7798=>659, 7799=>570, 7800=>659, 7801=>570, - 7802=>659, 7803=>570, 7804=>615, 7805=>532, 7806=>615, 7807=>532, 7808=>890, 7809=>736, 7810=>890, 7811=>736, 7812=>890, 7813=>736, 7814=>890, 7815=>736, 7816=>890, 7817=>736, - 7818=>616, 7819=>532, 7820=>616, 7821=>532, 7822=>549, 7823=>532, 7824=>616, 7825=>472, 7826=>616, 7827=>472, 7828=>616, 7829=>472, 7830=>570, 7831=>353, 7832=>736, 7833=>532, - 7834=>551, 7835=>316, 7840=>615, 7841=>551, 7842=>615, 7843=>551, 7844=>615, 7845=>551, 7846=>615, 7847=>551, 7848=>615, 7849=>551, 7850=>615, 7851=>551, 7852=>615, 7853=>551, - 7854=>615, 7855=>551, 7856=>615, 7857=>551, 7858=>615, 7859=>551, 7860=>615, 7861=>551, 7862=>615, 7863=>551, 7864=>568, 7865=>554, 7866=>568, 7867=>554, 7868=>568, 7869=>554, - 7870=>568, 7871=>554, 7872=>568, 7873=>554, 7874=>568, 7875=>554, 7876=>568, 7877=>554, 7878=>568, 7879=>554, 7880=>265, 7881=>250, 7882=>265, 7883=>250, 7884=>708, 7885=>550, - 7886=>708, 7887=>550, 7888=>708, 7889=>550, 7890=>708, 7891=>550, 7892=>708, 7893=>550, 7894=>708, 7895=>550, 7896=>708, 7897=>550, 7898=>822, 7899=>550, 7900=>822, 7901=>550, - 7902=>822, 7903=>550, 7904=>822, 7905=>550, 7906=>822, 7907=>550, 7908=>659, 7909=>570, 7910=>659, 7911=>570, 7912=>754, 7913=>570, 7914=>754, 7915=>570, 7916=>754, 7917=>570, - 7918=>754, 7919=>570, 7920=>754, 7921=>570, 7922=>549, 7923=>532, 7924=>549, 7925=>532, 7926=>549, 7927=>532, 7928=>549, 7929=>532, 7936=>593, 7937=>593, 7938=>593, 7939=>593, - 7940=>593, 7941=>593, 7942=>593, 7943=>593, 7944=>615, 7945=>615, 7946=>790, 7947=>790, 7948=>692, 7949=>721, 7950=>637, 7951=>668, 7952=>486, 7953=>486, 7954=>486, 7955=>486, - 7956=>486, 7957=>486, 7960=>640, 7961=>640, 7962=>869, 7963=>877, 7964=>809, 7965=>835, 7968=>570, 7969=>570, 7970=>570, 7971=>570, 7972=>570, 7973=>570, 7974=>570, 7975=>570, - 7976=>753, 7977=>751, 7978=>977, 7979=>980, 7980=>924, 7981=>945, 7982=>840, 7983=>852, 7984=>304, 7985=>304, 7986=>304, 7987=>304, 7988=>304, 7989=>304, 7990=>304, 7991=>304, - 7992=>342, 7993=>336, 7994=>571, 7995=>571, 7996=>513, 7997=>540, 7998=>440, 7999=>443, 8000=>550, 8001=>550, 8002=>550, 8003=>550, 8004=>550, 8005=>550, 8008=>724, 8009=>763, - 8010=>985, 8011=>989, 8012=>844, 8013=>873, 8016=>521, 8017=>521, 8018=>521, 8019=>521, 8020=>521, 8021=>521, 8022=>521, 8023=>521, 8025=>705, 8027=>897, 8029=>911, 8031=>808, - 8032=>753, 8033=>753, 8034=>753, 8035=>753, 8036=>753, 8037=>753, 8038=>753, 8039=>753, 8040=>722, 8041=>759, 8042=>980, 8043=>985, 8044=>851, 8045=>875, 8046=>829, 8047=>857, - 8048=>593, 8049=>593, 8050=>486, 8051=>493, 8052=>570, 8053=>589, 8054=>304, 8055=>304, 8056=>550, 8057=>550, 8058=>521, 8059=>521, 8060=>753, 8061=>753, 8064=>593, 8065=>593, - 8066=>593, 8067=>593, 8068=>593, 8069=>593, 8070=>593, 8071=>593, 8072=>615, 8073=>615, 8074=>790, 8075=>790, 8076=>692, 8077=>721, 8078=>637, 8079=>668, 8080=>570, 8081=>570, - 8082=>570, 8083=>570, 8084=>570, 8085=>570, 8086=>570, 8087=>570, 8088=>753, 8089=>751, 8090=>977, 8091=>980, 8092=>924, 8093=>945, 8094=>840, 8095=>852, 8096=>753, 8097=>753, - 8098=>753, 8099=>753, 8100=>753, 8101=>753, 8102=>753, 8103=>753, 8104=>722, 8105=>759, 8106=>980, 8107=>985, 8108=>851, 8109=>875, 8110=>829, 8111=>857, 8112=>593, 8113=>593, - 8114=>593, 8115=>593, 8116=>593, 8118=>593, 8119=>593, 8120=>615, 8121=>615, 8122=>645, 8123=>623, 8124=>615, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>570, - 8131=>570, 8132=>589, 8134=>570, 8135=>570, 8136=>724, 8137=>671, 8138=>837, 8139=>784, 8140=>677, 8141=>450, 8142=>450, 8143=>450, 8144=>304, 8145=>304, 8146=>304, 8147=>304, - 8150=>304, 8151=>304, 8152=>265, 8153=>265, 8154=>427, 8155=>367, 8157=>450, 8158=>450, 8159=>450, 8160=>521, 8161=>521, 8162=>521, 8163=>521, 8164=>571, 8165=>571, 8166=>521, - 8167=>521, 8168=>549, 8169=>549, 8170=>760, 8171=>742, 8172=>616, 8173=>450, 8174=>450, 8175=>450, 8178=>753, 8179=>753, 8180=>753, 8182=>753, 8183=>753, 8184=>847, 8185=>731, - 8186=>830, 8187=>743, 8188=>688, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, 8196=>296, 8197=>225, 8198=>150, 8199=>572, 8200=>286, 8201=>180, 8202=>89, - 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>325, 8209=>325, 8210=>572, 8213=>900, 8214=>0, 8215=>450, 8219=>286, 8223=>466, 8227=>531, 8228=>299, 8229=>600, - 8231=>286, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1521, 8242=>204, 8243=>336, 8244=>468, 8245=>204, 8246=>336, 8247=>468, 8248=>305, 8251=>754, - 8252=>437, 8253=>478, 8254=>450, 8255=>723, 8256=>723, 8257=>225, 8258=>900, 8259=>450, 8260=>150, 8261=>351, 8262=>351, 8263=>830, 8264=>659, 8265=>659, 8266=>447, 8267=>572, - 8268=>450, 8269=>450, 8270=>450, 8271=>303, 8272=>723, 8273=>450, 8274=>404, 8275=>754, 8276=>723, 8277=>754, 8278=>527, 8279=>597, 8280=>754, 8281=>754, 8282=>286, 8283=>717, - 8284=>754, 8285=>286, 8286=>286, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>360, 8305=>161, - 8308=>360, 8309=>360, 8310=>360, 8311=>360, 8312=>360, 8313=>360, 8314=>475, 8315=>475, 8316=>475, 8317=>221, 8318=>221, 8319=>359, 8320=>360, 8321=>360, 8322=>360, 8323=>360, - 8324=>360, 8325=>360, 8326=>360, 8327=>360, 8328=>360, 8329=>360, 8330=>475, 8331=>475, 8332=>475, 8333=>221, 8334=>221, 8336=>352, 8337=>375, 8338=>372, 8339=>399, 8340=>375, - 8352=>789, 8353=>572, 8354=>572, 8355=>572, 8356=>572, 8357=>876, 8358=>673, 8359=>1143, 8360=>966, 8361=>890, 8362=>754, 8363=>572, 8365=>590, 8366=>549, 8367=>1145, 8368=>572, - 8369=>572, 8370=>572, 8371=>572, 8372=>696, 8373=>577, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>873, 8449=>873, 8450=>628, 8451=>1011, 8452=>807, 8453=>872, 8454=>929, - 8455=>553, 8456=>628, 8457=>856, 8459=>889, 8460=>648, 8461=>765, 8462=>570, 8463=>570, 8464=>422, 8465=>627, 8466=>648, 8467=>372, 8468=>736, 8469=>721, 8470=>936, 8471=>900, - 8472=>627, 8473=>631, 8474=>708, 8475=>718, 8476=>732, 8477=>713, 8478=>807, 8479=>615, 8480=>917, 8481=>912, 8483=>615, 8484=>670, 8485=>520, 8486=>688, 8487=>688, 8488=>554, - 8489=>304, 8490=>590, 8491=>615, 8492=>708, 8493=>633, 8494=>769, 8495=>532, 8496=>545, 8497=>708, 8498=>518, 8499=>962, 8500=>416, 8501=>670, 8502=>606, 8503=>404, 8504=>625, - 8505=>342, 8506=>833, 8507=>1041, 8508=>632, 8509=>655, 8510=>589, 8511=>764, 8512=>729, 8513=>697, 8514=>501, 8515=>501, 8516=>549, 8517=>737, 8518=>637, 8519=>554, 8520=>316, - 8521=>316, 8523=>702, 8526=>474, 8531=>872, 8532=>872, 8533=>872, 8534=>872, 8535=>872, 8536=>872, 8537=>872, 8538=>872, 8539=>872, 8540=>872, 8541=>872, 8542=>872, 8543=>511, - 8544=>265, 8545=>443, 8546=>620, 8547=>831, 8548=>615, 8549=>830, 8550=>1007, 8551=>1185, 8552=>826, 8553=>616, 8554=>839, 8555=>1018, 8556=>501, 8557=>628, 8558=>693, 8559=>776, - 8560=>250, 8561=>412, 8562=>573, 8563=>730, 8564=>532, 8565=>729, 8566=>892, 8567=>1053, 8568=>737, 8569=>532, 8570=>740, 8571=>901, 8572=>250, 8573=>495, 8574=>571, 8575=>876, - 8576=>1121, 8577=>693, 8578=>1121, 8579=>633, 8580=>494, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8596=>754, 8597=>754, 8598=>754, 8599=>754, 8600=>754, 8601=>754, 8602=>754, - 8603=>754, 8604=>754, 8605=>754, 8606=>754, 8607=>754, 8608=>754, 8609=>754, 8610=>754, 8611=>754, 8612=>754, 8613=>754, 8614=>754, 8615=>754, 8616=>754, 8617=>754, 8618=>754, - 8619=>754, 8620=>754, 8621=>754, 8622=>754, 8623=>754, 8624=>754, 8625=>754, 8626=>754, 8627=>754, 8628=>754, 8629=>754, 8630=>754, 8631=>754, 8632=>754, 8633=>754, 8634=>754, - 8635=>754, 8636=>754, 8637=>754, 8638=>754, 8639=>754, 8640=>754, 8641=>754, 8642=>754, 8643=>754, 8644=>754, 8645=>754, 8646=>754, 8647=>754, 8648=>754, 8649=>754, 8650=>754, - 8651=>754, 8652=>754, 8653=>754, 8654=>754, 8655=>754, 8656=>754, 8657=>754, 8658=>754, 8659=>754, 8660=>754, 8661=>754, 8662=>754, 8663=>754, 8664=>754, 8665=>754, 8666=>754, - 8667=>754, 8668=>754, 8669=>754, 8670=>754, 8671=>754, 8672=>754, 8673=>754, 8674=>754, 8675=>754, 8676=>754, 8677=>754, 8678=>754, 8679=>754, 8680=>754, 8681=>754, 8682=>754, - 8683=>754, 8684=>754, 8685=>754, 8686=>754, 8687=>754, 8688=>754, 8689=>754, 8690=>754, 8691=>754, 8692=>754, 8693=>754, 8694=>754, 8695=>754, 8696=>754, 8697=>754, 8698=>754, - 8699=>754, 8700=>754, 8701=>754, 8702=>754, 8703=>754, 8704=>615, 8705=>572, 8706=>465, 8707=>568, 8708=>568, 8709=>784, 8710=>602, 8711=>602, 8712=>784, 8713=>784, 8714=>646, - 8715=>784, 8716=>784, 8717=>646, 8718=>572, 8719=>681, 8720=>681, 8721=>606, 8722=>754, 8723=>754, 8724=>754, 8725=>150, 8726=>573, 8727=>754, 8728=>563, 8729=>286, 8730=>573, - 8731=>573, 8732=>573, 8733=>609, 8734=>750, 8735=>754, 8736=>807, 8737=>807, 8738=>754, 8739=>450, 8740=>450, 8741=>450, 8742=>450, 8743=>659, 8744=>659, 8745=>659, 8746=>659, - 8747=>469, 8748=>710, 8749=>951, 8750=>469, 8751=>710, 8752=>951, 8753=>469, 8754=>469, 8755=>469, 8756=>572, 8757=>572, 8758=>234, 8759=>572, 8760=>754, 8761=>754, 8762=>754, - 8763=>754, 8764=>754, 8765=>754, 8766=>754, 8767=>754, 8768=>337, 8769=>754, 8770=>754, 8771=>754, 8772=>754, 8773=>754, 8774=>754, 8775=>754, 8776=>754, 8777=>754, 8778=>754, - 8779=>754, 8780=>754, 8781=>754, 8782=>754, 8783=>754, 8784=>754, 8785=>754, 8786=>754, 8787=>754, 8788=>900, 8789=>900, 8790=>754, 8791=>754, 8792=>754, 8793=>754, 8794=>754, - 8795=>754, 8796=>754, 8797=>754, 8798=>754, 8799=>754, 8800=>754, 8801=>754, 8802=>754, 8803=>754, 8804=>754, 8805=>754, 8806=>754, 8807=>754, 8808=>754, 8809=>754, 8810=>942, - 8811=>942, 8812=>417, 8813=>754, 8814=>754, 8815=>754, 8816=>754, 8817=>754, 8818=>754, 8819=>754, 8820=>754, 8821=>754, 8822=>754, 8823=>754, 8824=>754, 8825=>754, 8826=>754, - 8827=>754, 8828=>754, 8829=>754, 8830=>754, 8831=>754, 8832=>754, 8833=>754, 8834=>754, 8835=>754, 8836=>754, 8837=>754, 8838=>754, 8839=>754, 8840=>754, 8841=>754, 8842=>754, - 8843=>754, 8844=>659, 8845=>659, 8846=>659, 8847=>754, 8848=>754, 8849=>754, 8850=>754, 8851=>649, 8852=>649, 8853=>754, 8854=>754, 8855=>754, 8856=>754, 8857=>754, 8858=>754, - 8859=>754, 8860=>754, 8861=>754, 8862=>754, 8863=>754, 8864=>754, 8865=>754, 8866=>784, 8867=>784, 8868=>784, 8869=>784, 8870=>468, 8871=>468, 8872=>784, 8873=>784, 8874=>784, - 8875=>784, 8876=>784, 8877=>784, 8878=>784, 8879=>784, 8882=>754, 8883=>754, 8884=>754, 8885=>754, 8886=>900, 8887=>900, 8888=>754, 8889=>754, 8890=>468, 8891=>659, 8892=>659, - 8893=>659, 8896=>738, 8897=>738, 8898=>738, 8899=>738, 8900=>444, 8901=>286, 8902=>563, 8904=>900, 8905=>900, 8906=>900, 8907=>900, 8908=>900, 8909=>754, 8918=>754, 8919=>754, - 8920=>1280, 8921=>1280, 8922=>754, 8923=>754, 8924=>754, 8925=>754, 8926=>754, 8927=>754, 8928=>754, 8929=>754, 8930=>754, 8931=>754, 8932=>754, 8933=>754, 8934=>754, 8935=>754, - 8936=>754, 8937=>754, 8938=>754, 8939=>754, 8940=>754, 8941=>754, 8946=>900, 8947=>784, 8948=>646, 8949=>784, 8950=>784, 8951=>646, 8952=>784, 8953=>784, 8954=>900, 8955=>784, - 8956=>646, 8957=>784, 8958=>646, 8959=>784, 8962=>571, 8966=>784, 8968=>351, 8969=>351, 8970=>351, 8971=>351, 8976=>754, 8977=>461, 8984=>900, 8985=>754, 8992=>469, 8993=>469, - 8997=>900, 9000=>1299, 9085=>681, 9115=>450, 9116=>450, 9117=>450, 9118=>450, 9119=>450, 9120=>450, 9121=>450, 9122=>450, 9123=>450, 9124=>450, 9125=>450, 9126=>450, 9127=>675, - 9128=>675, 9129=>675, 9130=>675, 9131=>675, 9132=>675, 9133=>675, 9134=>469, 9166=>754, 9167=>850, 9250=>571, 9251=>571, 9312=>807, 9313=>807, 9314=>807, 9315=>807, 9316=>807, - 9317=>807, 9318=>807, 9319=>807, 9320=>807, 9321=>807, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, 9609=>692, 9610=>692, - 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, 9625=>692, 9626=>692, - 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, 9641=>850, 9642=>610, - 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, 9657=>452, 9658=>692, - 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, 9673=>785, 9674=>444, - 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>712, 9689=>873, 9690=>873, - 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>692, 9697=>692, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>531, 9703=>850, 9704=>850, 9705=>850, 9706=>850, - 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, 9721=>692, 9722=>692, - 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9729=>900, 9730=>807, 9731=>807, 9732=>807, 9733=>807, 9734=>807, 9735=>515, 9736=>806, 9737=>807, 9738=>799, - 9739=>799, 9740=>604, 9741=>911, 9742=>1121, 9743=>1125, 9744=>807, 9745=>807, 9746=>807, 9747=>479, 9748=>807, 9749=>807, 9750=>807, 9751=>807, 9752=>807, 9753=>807, 9754=>807, - 9755=>807, 9756=>807, 9757=>548, 9758=>807, 9759=>548, 9760=>807, 9761=>807, 9762=>807, 9763=>807, 9764=>602, 9765=>671, 9766=>584, 9767=>705, 9768=>490, 9769=>807, 9770=>807, - 9771=>807, 9772=>639, 9773=>807, 9774=>807, 9775=>807, 9776=>807, 9777=>807, 9778=>807, 9779=>807, 9780=>807, 9781=>807, 9782=>807, 9783=>807, 9784=>807, 9785=>807, 9786=>807, - 9787=>807, 9788=>807, 9789=>807, 9790=>807, 9791=>552, 9792=>658, 9793=>658, 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9800=>807, 9801=>807, 9802=>807, - 9803=>807, 9804=>807, 9805=>807, 9806=>807, 9807=>807, 9808=>807, 9809=>807, 9810=>807, 9811=>807, 9812=>807, 9813=>807, 9814=>807, 9815=>807, 9816=>807, 9817=>807, 9818=>807, - 9819=>807, 9820=>807, 9821=>807, 9822=>807, 9823=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9832=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 9840=>673, 9841=>689, 9842=>807, 9843=>807, 9844=>807, 9845=>807, 9846=>807, 9847=>807, 9848=>807, 9849=>807, 9850=>807, - 9851=>807, 9852=>807, 9853=>807, 9854=>807, 9855=>807, 9856=>782, 9857=>782, 9858=>782, 9859=>782, 9860=>782, 9861=>782, 9862=>800, 9863=>800, 9864=>800, 9865=>800, 9866=>800, - 9867=>800, 9868=>800, 9869=>800, 9870=>800, 9871=>800, 9872=>675, 9873=>675, 9874=>800, 9875=>734, 9876=>644, 9877=>483, 9878=>766, 9879=>800, 9880=>615, 9881=>800, 9882=>637, - 9883=>800, 9884=>800, 9888=>800, 9889=>800, 9890=>754, 9891=>754, 9892=>754, 9893=>754, 9894=>754, 9895=>754, 9896=>754, 9897=>754, 9898=>754, 9899=>754, 9900=>754, 9901=>754, - 9902=>754, 9903=>754, 9904=>759, 9905=>754, 9906=>658, 9985=>754, 9986=>754, 9987=>754, 9988=>754, 9990=>754, 9991=>754, 9992=>754, 9993=>754, 9996=>754, 9997=>754, 9998=>754, - 9999=>754, 10000=>754, 10001=>754, 10002=>754, 10003=>754, 10004=>754, 10005=>754, 10006=>754, 10007=>754, 10008=>754, 10009=>754, 10010=>754, 10011=>754, 10012=>754, 10013=>754, 10014=>754, - 10015=>754, 10016=>754, 10017=>754, 10018=>754, 10019=>754, 10020=>754, 10021=>754, 10022=>754, 10023=>754, 10025=>754, 10026=>754, 10027=>754, 10028=>754, 10029=>754, 10030=>754, 10031=>754, - 10032=>754, 10033=>754, 10034=>754, 10035=>754, 10036=>754, 10037=>754, 10038=>754, 10039=>754, 10040=>754, 10041=>754, 10042=>754, 10043=>754, 10044=>754, 10045=>754, 10046=>754, 10047=>754, - 10048=>754, 10049=>754, 10050=>754, 10051=>754, 10052=>754, 10053=>754, 10054=>754, 10055=>754, 10056=>754, 10057=>754, 10058=>754, 10059=>754, 10061=>807, 10063=>807, 10064=>807, 10065=>807, - 10066=>807, 10070=>807, 10072=>754, 10073=>754, 10074=>754, 10075=>290, 10076=>290, 10077=>484, 10078=>484, 10081=>754, 10082=>754, 10083=>754, 10084=>754, 10085=>754, 10086=>754, 10087=>754, - 10088=>754, 10089=>754, 10090=>754, 10091=>754, 10092=>754, 10093=>754, 10094=>754, 10095=>754, 10096=>754, 10097=>754, 10098=>754, 10099=>754, 10100=>754, 10101=>754, 10102=>807, 10103=>807, - 10104=>807, 10105=>807, 10106=>807, 10107=>807, 10108=>807, 10109=>807, 10110=>807, 10111=>807, 10112=>754, 10113=>754, 10114=>754, 10115=>754, 10116=>754, 10117=>754, 10118=>754, 10119=>754, - 10120=>754, 10121=>754, 10122=>754, 10123=>754, 10124=>754, 10125=>754, 10126=>754, 10127=>754, 10128=>754, 10129=>754, 10130=>754, 10131=>754, 10132=>754, 10136=>754, 10137=>754, 10138=>754, - 10139=>754, 10140=>754, 10141=>754, 10142=>754, 10143=>754, 10144=>754, 10145=>754, 10146=>754, 10147=>754, 10148=>754, 10149=>754, 10150=>754, 10151=>754, 10152=>754, 10153=>754, 10154=>754, - 10155=>754, 10156=>754, 10157=>754, 10158=>754, 10159=>754, 10161=>754, 10162=>754, 10163=>754, 10164=>754, 10165=>754, 10166=>754, 10167=>754, 10168=>754, 10169=>754, 10170=>754, 10171=>754, - 10172=>754, 10173=>754, 10174=>754, 10208=>444, 10214=>445, 10215=>445, 10216=>351, 10217=>351, 10218=>500, 10219=>500, 10224=>754, 10225=>754, 10226=>754, 10227=>754, 10228=>1042, 10229=>1290, - 10230=>1290, 10231=>1290, 10232=>1290, 10233=>1290, 10234=>1290, 10235=>1290, 10236=>1290, 10237=>1290, 10238=>1290, 10239=>1290, 10240=>659, 10241=>659, 10242=>659, 10243=>659, 10244=>659, 10245=>659, - 10246=>659, 10247=>659, 10248=>659, 10249=>659, 10250=>659, 10251=>659, 10252=>659, 10253=>659, 10254=>659, 10255=>659, 10256=>659, 10257=>659, 10258=>659, 10259=>659, 10260=>659, 10261=>659, - 10262=>659, 10263=>659, 10264=>659, 10265=>659, 10266=>659, 10267=>659, 10268=>659, 10269=>659, 10270=>659, 10271=>659, 10272=>659, 10273=>659, 10274=>659, 10275=>659, 10276=>659, 10277=>659, - 10278=>659, 10279=>659, 10280=>659, 10281=>659, 10282=>659, 10283=>659, 10284=>659, 10285=>659, 10286=>659, 10287=>659, 10288=>659, 10289=>659, 10290=>659, 10291=>659, 10292=>659, 10293=>659, - 10294=>659, 10295=>659, 10296=>659, 10297=>659, 10298=>659, 10299=>659, 10300=>659, 10301=>659, 10302=>659, 10303=>659, 10304=>659, 10305=>659, 10306=>659, 10307=>659, 10308=>659, 10309=>659, - 10310=>659, 10311=>659, 10312=>659, 10313=>659, 10314=>659, 10315=>659, 10316=>659, 10317=>659, 10318=>659, 10319=>659, 10320=>659, 10321=>659, 10322=>659, 10323=>659, 10324=>659, 10325=>659, - 10326=>659, 10327=>659, 10328=>659, 10329=>659, 10330=>659, 10331=>659, 10332=>659, 10333=>659, 10334=>659, 10335=>659, 10336=>659, 10337=>659, 10338=>659, 10339=>659, 10340=>659, 10341=>659, - 10342=>659, 10343=>659, 10344=>659, 10345=>659, 10346=>659, 10347=>659, 10348=>659, 10349=>659, 10350=>659, 10351=>659, 10352=>659, 10353=>659, 10354=>659, 10355=>659, 10356=>659, 10357=>659, - 10358=>659, 10359=>659, 10360=>659, 10361=>659, 10362=>659, 10363=>659, 10364=>659, 10365=>659, 10366=>659, 10367=>659, 10368=>659, 10369=>659, 10370=>659, 10371=>659, 10372=>659, 10373=>659, - 10374=>659, 10375=>659, 10376=>659, 10377=>659, 10378=>659, 10379=>659, 10380=>659, 10381=>659, 10382=>659, 10383=>659, 10384=>659, 10385=>659, 10386=>659, 10387=>659, 10388=>659, 10389=>659, - 10390=>659, 10391=>659, 10392=>659, 10393=>659, 10394=>659, 10395=>659, 10396=>659, 10397=>659, 10398=>659, 10399=>659, 10400=>659, 10401=>659, 10402=>659, 10403=>659, 10404=>659, 10405=>659, - 10406=>659, 10407=>659, 10408=>659, 10409=>659, 10410=>659, 10411=>659, 10412=>659, 10413=>659, 10414=>659, 10415=>659, 10416=>659, 10417=>659, 10418=>659, 10419=>659, 10420=>659, 10421=>659, - 10422=>659, 10423=>659, 10424=>659, 10425=>659, 10426=>659, 10427=>659, 10428=>659, 10429=>659, 10430=>659, 10431=>659, 10432=>659, 10433=>659, 10434=>659, 10435=>659, 10436=>659, 10437=>659, - 10438=>659, 10439=>659, 10440=>659, 10441=>659, 10442=>659, 10443=>659, 10444=>659, 10445=>659, 10446=>659, 10447=>659, 10448=>659, 10449=>659, 10450=>659, 10451=>659, 10452=>659, 10453=>659, - 10454=>659, 10455=>659, 10456=>659, 10457=>659, 10458=>659, 10459=>659, 10460=>659, 10461=>659, 10462=>659, 10463=>659, 10464=>659, 10465=>659, 10466=>659, 10467=>659, 10468=>659, 10469=>659, - 10470=>659, 10471=>659, 10472=>659, 10473=>659, 10474=>659, 10475=>659, 10476=>659, 10477=>659, 10478=>659, 10479=>659, 10480=>659, 10481=>659, 10482=>659, 10483=>659, 10484=>659, 10485=>659, - 10486=>659, 10487=>659, 10488=>659, 10489=>659, 10490=>659, 10491=>659, 10492=>659, 10493=>659, 10494=>659, 10495=>659, 10502=>754, 10503=>754, 10506=>754, 10507=>754, 10560=>615, 10561=>615, - 10702=>754, 10703=>900, 10704=>900, 10705=>900, 10706=>900, 10707=>900, 10708=>900, 10709=>900, 10731=>444, 10752=>900, 10753=>900, 10754=>900, 10764=>1192, 10765=>469, 10766=>469, 10767=>469, - 10768=>469, 10769=>469, 10770=>469, 10771=>469, 10772=>469, 10773=>469, 10774=>469, 10775=>469, 10776=>469, 10777=>469, 10778=>469, 10779=>469, 10780=>469, 10877=>754, 10878=>754, 10879=>754, - 10880=>754, 10881=>754, 10882=>754, 10883=>754, 10884=>754, 10885=>754, 10886=>754, 10887=>754, 10888=>754, 10889=>754, 10890=>754, 10891=>754, 10892=>754, 10893=>754, 10894=>754, 10895=>754, - 10896=>754, 10897=>754, 10898=>754, 10899=>754, 10900=>754, 10901=>754, 10902=>754, 10903=>754, 10904=>754, 10905=>754, 10906=>754, 10907=>754, 10908=>754, 10909=>754, 10910=>754, 10911=>754, - 10912=>754, 10926=>754, 10927=>754, 10928=>754, 10929=>754, 10930=>754, 10931=>754, 10932=>754, 10933=>754, 10934=>754, 10935=>754, 10936=>754, 10937=>754, 10938=>754, 11001=>754, 11002=>754, - 11008=>754, 11009=>754, 11010=>754, 11011=>754, 11012=>754, 11013=>754, 11014=>754, 11015=>754, 11016=>754, 11017=>754, 11018=>754, 11019=>754, 11020=>754, 11021=>754, 11022=>752, 11023=>752, - 11024=>752, 11025=>752, 11026=>850, 11027=>850, 11028=>850, 11029=>850, 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 11040=>782, 11041=>786, 11042=>786, 11043=>786, 11360=>501, - 11361=>250, 11362=>501, 11363=>542, 11364=>625, 11365=>551, 11366=>353, 11367=>677, 11368=>570, 11369=>590, 11370=>521, 11371=>616, 11372=>472, 11380=>532, 11381=>589, 11382=>511, 11383=>593, - 61960=>703, 62047=>532, 63173=>550, 64256=>649, 64257=>581, 64258=>581, 64259=>899, 64260=>899, 64261=>617, 64262=>774, 64275=>1081, 64276=>1081, 64277=>1076, 64278=>1067, 64279=>1376, 64285=>266, - 64287=>444, 64288=>572, 64297=>754, 64298=>719, 64299=>719, 64300=>719, 64301=>719, 64302=>597, 64303=>597, 64304=>597, 64305=>589, 64306=>408, 64307=>546, 64308=>621, 64309=>302, 64310=>393, - 64311=>900, 64312=>615, 64313=>302, 64314=>577, 64315=>599, 64316=>571, 64318=>663, 64320=>410, 64321=>694, 64323=>586, 64324=>599, 64326=>575, 64327=>619, 64328=>577, 64329=>719, 64330=>653, - 64331=>245, 64332=>589, 64333=>599, 64334=>599, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, - 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65533=>923}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansCondensed-Oblique.z'; - font[:ctg]='DejaVuSansCondensed-Oblique.ctg.z'; - font[:originalsize]=425256; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Bold.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Bold.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Bold.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Bold.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-BoldOblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-BoldOblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-BoldOblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-BoldOblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Oblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Oblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Oblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono-Oblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansMono') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansMono'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>33,'FontBBox'=>'[-344 -375 718 1058]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>602}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 1027=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 1036=>602, 381=>602, 1039=>602, - 8216=>602, 8217=>602, 8220=>602, 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 1116=>602, 382=>602, 376=>602, 160=>602, - 161=>602, 162=>602, 163=>602, 164=>602, 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, - 177=>602, 178=>602, 179=>602, 180=>602, 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, - 193=>602, 194=>602, 195=>602, 196=>602, 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, - 209=>602, 210=>602, 211=>602, 212=>602, 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, - 225=>602, 226=>602, 227=>602, 228=>602, 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, - 241=>602, 242=>602, 243=>602, 244=>602, 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 256=>602, - 257=>602, 258=>602, 259=>602, 260=>602, 261=>602, 262=>602, 263=>602, 264=>602, 265=>602, 266=>602, 267=>602, 268=>602, 269=>602, 270=>602, 271=>602, 272=>602, - 273=>602, 274=>602, 275=>602, 276=>602, 277=>602, 278=>602, 279=>602, 280=>602, 281=>602, 282=>602, 283=>602, 284=>602, 285=>602, 286=>602, 287=>602, 288=>602, - 289=>602, 290=>602, 291=>602, 292=>602, 293=>602, 294=>602, 295=>602, 296=>602, 297=>602, 298=>602, 299=>602, 300=>602, 301=>602, 302=>602, 303=>602, 304=>602, - 305=>602, 306=>602, 307=>602, 308=>602, 309=>602, 310=>602, 311=>602, 312=>602, 313=>602, 314=>602, 315=>602, 316=>602, 317=>602, 318=>602, 319=>602, 320=>602, - 321=>602, 322=>602, 323=>602, 324=>602, 325=>602, 326=>602, 327=>602, 328=>602, 329=>602, 330=>602, 331=>602, 332=>602, 333=>602, 334=>602, 335=>602, 336=>602, - 337=>602, 340=>602, 341=>602, 342=>602, 343=>602, 344=>602, 345=>602, 346=>602, 347=>602, 348=>602, 349=>602, 350=>602, 351=>602, 354=>602, 355=>602, 356=>602, - 357=>602, 358=>602, 359=>602, 360=>602, 361=>602, 362=>602, 363=>602, 364=>602, 365=>602, 366=>602, 367=>602, 368=>602, 369=>602, 370=>602, 371=>602, 372=>602, - 373=>602, 374=>602, 375=>602, 377=>602, 378=>602, 379=>602, 380=>602, 383=>602, 385=>602, 386=>602, 387=>602, 388=>602, 389=>602, 390=>602, 391=>602, 392=>602, - 393=>602, 394=>602, 395=>602, 396=>602, 397=>602, 398=>602, 399=>602, 400=>602, 401=>602, 403=>602, 404=>602, 405=>602, 406=>602, 407=>602, 408=>602, 409=>602, - 410=>602, 411=>602, 412=>602, 413=>602, 414=>602, 415=>602, 416=>602, 417=>602, 418=>602, 419=>602, 420=>602, 421=>602, 422=>602, 423=>602, 424=>602, 425=>602, - 426=>602, 427=>602, 428=>602, 429=>602, 430=>602, 431=>602, 432=>602, 433=>602, 434=>602, 435=>602, 436=>602, 437=>602, 438=>602, 439=>602, 440=>602, 441=>602, - 443=>602, 444=>602, 445=>602, 446=>602, 448=>602, 449=>602, 450=>602, 451=>602, 461=>602, 462=>602, 463=>602, 464=>602, 465=>602, 466=>602, 467=>602, 468=>602, - 470=>602, 471=>602, 472=>602, 473=>602, 474=>602, 475=>602, 476=>602, 477=>602, 479=>602, 482=>602, 483=>602, 486=>602, 487=>602, 488=>602, 489=>602, 490=>602, - 491=>602, 492=>602, 493=>602, 494=>602, 495=>602, 496=>602, 500=>602, 501=>602, 502=>602, 504=>602, 505=>602, 508=>602, 509=>602, 510=>602, 511=>602, 512=>602, - 513=>602, 514=>602, 515=>602, 516=>602, 517=>602, 518=>602, 519=>602, 520=>602, 521=>602, 522=>602, 523=>602, 524=>602, 525=>602, 526=>602, 527=>602, 528=>602, - 529=>602, 530=>602, 531=>602, 532=>602, 533=>602, 534=>602, 535=>602, 536=>602, 537=>602, 538=>602, 539=>602, 542=>602, 543=>602, 545=>602, 548=>602, 549=>602, - 550=>602, 551=>602, 552=>602, 553=>602, 555=>602, 557=>602, 558=>602, 559=>602, 561=>602, 562=>602, 563=>602, 564=>602, 565=>602, 566=>602, 567=>602, 568=>602, - 569=>602, 570=>602, 571=>602, 572=>602, 573=>602, 574=>602, 575=>602, 576=>602, 577=>602, 581=>602, 592=>602, 593=>602, 594=>602, 595=>602, 596=>602, 597=>602, - 598=>602, 599=>602, 600=>602, 601=>602, 602=>602, 603=>602, 604=>602, 605=>602, 606=>602, 607=>602, 608=>602, 609=>602, 610=>602, 611=>602, 612=>602, 613=>602, - 614=>602, 615=>602, 616=>602, 617=>602, 618=>602, 619=>602, 620=>602, 621=>602, 622=>602, 623=>602, 624=>602, 625=>602, 626=>602, 627=>602, 628=>602, 629=>602, - 630=>602, 631=>602, 632=>602, 633=>602, 634=>602, 635=>602, 636=>602, 637=>602, 638=>602, 639=>602, 640=>602, 641=>602, 642=>602, 643=>602, 644=>602, 645=>602, - 646=>602, 647=>602, 648=>602, 649=>602, 650=>602, 651=>602, 652=>602, 653=>602, 654=>602, 655=>602, 656=>602, 657=>602, 658=>602, 659=>602, 660=>602, 661=>602, - 662=>602, 663=>602, 664=>602, 665=>602, 666=>602, 667=>602, 668=>602, 669=>602, 670=>602, 671=>602, 672=>602, 673=>602, 674=>602, 675=>602, 676=>602, 677=>602, - 678=>602, 679=>602, 680=>602, 681=>602, 682=>602, 683=>602, 684=>602, 685=>602, 686=>602, 687=>602, 688=>602, 689=>602, 690=>602, 691=>602, 692=>602, 693=>602, - 694=>602, 695=>602, 696=>602, 697=>602, 699=>602, 700=>602, 701=>602, 702=>602, 703=>602, 704=>602, 705=>602, 711=>602, 712=>602, 713=>602, 716=>602, 717=>602, - 720=>602, 721=>602, 722=>602, 723=>602, 726=>602, 728=>602, 729=>602, 730=>602, 731=>602, 733=>602, 734=>602, 736=>602, 737=>602, 738=>602, 739=>602, 740=>602, - 741=>602, 742=>602, 743=>602, 744=>602, 745=>602, 755=>602, 768=>602, 769=>602, 770=>602, 771=>602, 772=>602, 773=>602, 774=>602, 775=>602, 776=>602, 777=>602, - 778=>602, 779=>602, 780=>602, 781=>602, 782=>602, 783=>602, 784=>602, 785=>602, 786=>602, 787=>602, 788=>602, 789=>602, 790=>602, 791=>602, 792=>602, 793=>602, - 794=>602, 795=>602, 796=>602, 797=>602, 798=>602, 799=>602, 800=>602, 801=>602, 802=>602, 803=>602, 804=>602, 805=>602, 806=>602, 807=>602, 808=>602, 809=>602, - 810=>602, 811=>602, 812=>602, 813=>602, 814=>602, 815=>602, 816=>602, 817=>602, 818=>602, 819=>602, 820=>602, 821=>602, 822=>602, 823=>602, 824=>602, 825=>602, - 826=>602, 827=>602, 828=>602, 829=>602, 830=>602, 831=>602, 835=>602, 856=>602, 865=>602, 884=>602, 885=>602, 890=>602, 894=>602, 900=>602, 901=>602, 902=>602, - 903=>602, 904=>602, 905=>602, 906=>602, 908=>602, 910=>602, 911=>602, 912=>602, 913=>602, 914=>602, 915=>602, 916=>602, 917=>602, 918=>602, 919=>602, 920=>602, - 921=>602, 922=>602, 923=>602, 924=>602, 925=>602, 926=>602, 927=>602, 928=>602, 929=>602, 931=>602, 932=>602, 933=>602, 934=>602, 935=>602, 936=>602, 937=>602, - 938=>602, 939=>602, 940=>602, 941=>602, 942=>602, 943=>602, 944=>602, 945=>602, 946=>602, 947=>602, 948=>602, 949=>602, 950=>602, 951=>602, 952=>602, 953=>602, - 954=>602, 955=>602, 956=>602, 957=>602, 958=>602, 959=>602, 960=>602, 961=>602, 962=>602, 963=>602, 964=>602, 965=>602, 966=>602, 967=>602, 968=>602, 969=>602, - 970=>602, 971=>602, 972=>602, 973=>602, 974=>602, 976=>602, 977=>602, 978=>602, 979=>602, 980=>602, 981=>602, 982=>602, 983=>602, 984=>602, 985=>602, 986=>602, - 987=>602, 988=>602, 989=>602, 990=>602, 991=>602, 992=>602, 993=>602, 1008=>602, 1009=>602, 1010=>602, 1011=>602, 1012=>602, 1013=>602, 1014=>602, 1015=>602, 1016=>602, - 1017=>602, 1018=>602, 1019=>602, 1020=>602, 1021=>602, 1022=>602, 1023=>602, 1024=>602, 1025=>602, 1026=>602, 1028=>602, 1029=>602, 1030=>602, 1031=>602, 1032=>602, 1033=>602, - 1034=>602, 1035=>602, 1037=>602, 1038=>602, 1040=>602, 1041=>602, 1042=>602, 1043=>602, 1044=>602, 1045=>602, 1046=>602, 1047=>602, 1048=>602, 1049=>602, 1050=>602, 1051=>602, - 1052=>602, 1053=>602, 1054=>602, 1055=>602, 1056=>602, 1057=>602, 1058=>602, 1059=>602, 1060=>602, 1061=>602, 1062=>602, 1063=>602, 1064=>602, 1065=>602, 1066=>602, 1067=>602, - 1068=>602, 1069=>602, 1070=>602, 1071=>602, 1072=>602, 1073=>602, 1074=>602, 1075=>602, 1076=>602, 1077=>602, 1078=>602, 1079=>602, 1080=>602, 1081=>602, 1082=>602, 1083=>602, - 1084=>602, 1085=>602, 1086=>602, 1087=>602, 1088=>602, 1089=>602, 1090=>602, 1091=>602, 1092=>602, 1093=>602, 1094=>602, 1095=>602, 1096=>602, 1097=>602, 1098=>602, 1099=>602, - 1100=>602, 1101=>602, 1102=>602, 1103=>602, 1104=>602, 1105=>602, 1106=>602, 1107=>602, 1108=>602, 1109=>602, 1110=>602, 1111=>602, 1112=>602, 1113=>602, 1114=>602, 1115=>602, - 1117=>602, 1118=>602, 1119=>602, 1168=>602, 1169=>602, 1170=>602, 1171=>602, 1172=>602, 1173=>602, 1176=>602, 1177=>602, 1178=>602, 1179=>602, 1186=>602, 1187=>602, 1194=>602, - 1195=>602, 1196=>602, 1197=>602, 1198=>602, 1199=>602, 1202=>602, 1203=>602, 1210=>602, 1211=>602, 1216=>602, 1217=>602, 1218=>602, 1219=>602, 1220=>602, 1223=>602, 1224=>602, - 1227=>602, 1228=>602, 1231=>602, 1232=>602, 1233=>602, 1234=>602, 1235=>602, 1236=>602, 1237=>602, 1238=>602, 1239=>602, 1240=>602, 1241=>602, 1242=>602, 1243=>602, 1244=>602, - 1245=>602, 1246=>602, 1247=>602, 1248=>602, 1249=>602, 1250=>602, 1251=>602, 1252=>602, 1253=>602, 1254=>602, 1255=>602, 1256=>602, 1257=>602, 1258=>602, 1259=>602, 1260=>602, - 1261=>602, 1262=>602, 1263=>602, 1264=>602, 1265=>602, 1266=>602, 1267=>602, 1268=>602, 1269=>602, 1270=>602, 1271=>602, 1272=>602, 1273=>602, 3713=>602, 3714=>602, 3716=>602, - 3719=>602, 3720=>602, 3722=>602, 3725=>602, 3732=>602, 3733=>602, 3734=>602, 3735=>602, 3737=>602, 3738=>602, 3739=>602, 3740=>602, 3741=>602, 3742=>602, 3743=>602, 3745=>602, - 3746=>602, 3747=>602, 3749=>602, 3751=>602, 3754=>602, 3755=>602, 3757=>602, 3758=>602, 3759=>602, 7426=>602, 7432=>602, 7433=>602, 7444=>602, 7446=>602, 7447=>602, 7453=>602, - 7454=>602, 7455=>602, 7491=>602, 7492=>602, 7493=>602, 7494=>602, 7495=>602, 7496=>602, 7497=>602, 7498=>602, 7499=>602, 7500=>602, 7501=>602, 7502=>602, 7503=>602, 7504=>602, - 7505=>602, 7506=>602, 7507=>602, 7508=>602, 7509=>602, 7510=>602, 7511=>602, 7512=>602, 7513=>602, 7514=>602, 7515=>602, 7543=>602, 7547=>602, 7557=>602, 7579=>602, 7580=>602, - 7581=>602, 7582=>602, 7583=>602, 7584=>602, 7585=>602, 7586=>602, 7587=>602, 7588=>602, 7589=>602, 7590=>602, 7591=>602, 7592=>602, 7593=>602, 7594=>602, 7595=>602, 7596=>602, - 7597=>602, 7598=>602, 7599=>602, 7600=>602, 7601=>602, 7602=>602, 7603=>602, 7604=>602, 7605=>602, 7606=>602, 7607=>602, 7609=>602, 7610=>602, 7611=>602, 7612=>602, 7613=>602, - 7614=>602, 7615=>602, 7680=>602, 7681=>602, 7682=>602, 7683=>602, 7684=>602, 7685=>602, 7686=>602, 7687=>602, 7690=>602, 7691=>602, 7692=>602, 7693=>602, 7694=>602, 7695=>602, - 7698=>602, 7699=>602, 7704=>602, 7705=>602, 7706=>602, 7707=>602, 7708=>602, 7709=>602, 7710=>602, 7711=>602, 7712=>602, 7713=>602, 7714=>602, 7715=>602, 7716=>602, 7717=>602, - 7720=>602, 7721=>602, 7722=>602, 7723=>602, 7724=>602, 7725=>602, 7728=>602, 7729=>602, 7730=>602, 7731=>602, 7732=>602, 7733=>602, 7734=>602, 7735=>602, 7736=>602, 7737=>602, - 7738=>602, 7739=>602, 7740=>602, 7741=>602, 7742=>602, 7743=>602, 7744=>602, 7745=>602, 7746=>602, 7747=>602, 7748=>602, 7749=>602, 7750=>602, 7751=>602, 7752=>602, 7753=>602, - 7754=>602, 7755=>602, 7766=>602, 7767=>602, 7768=>602, 7769=>602, 7770=>602, 7771=>602, 7772=>602, 7773=>602, 7774=>602, 7775=>602, 7776=>602, 7777=>602, 7778=>602, 7779=>602, - 7784=>602, 7785=>602, 7786=>602, 7787=>602, 7788=>602, 7789=>602, 7790=>602, 7791=>602, 7792=>602, 7793=>602, 7794=>602, 7795=>602, 7796=>602, 7797=>602, 7798=>602, 7799=>602, - 7806=>602, 7807=>602, 7808=>602, 7809=>602, 7810=>602, 7811=>602, 7812=>602, 7813=>602, 7814=>602, 7815=>602, 7816=>602, 7817=>602, 7818=>602, 7819=>602, 7822=>602, 7823=>602, - 7826=>602, 7827=>602, 7828=>602, 7829=>602, 7830=>602, 7835=>602, 7840=>602, 7841=>602, 7864=>602, 7865=>602, 7868=>602, 7869=>602, 7882=>602, 7883=>602, 7884=>602, 7885=>602, - 7908=>602, 7909=>602, 7922=>602, 7923=>602, 7924=>602, 7925=>602, 7928=>602, 7929=>602, 7936=>602, 7937=>602, 7938=>602, 7939=>602, 7940=>602, 7941=>602, 7942=>602, 7943=>602, - 7944=>602, 7945=>602, 7946=>602, 7947=>602, 7948=>602, 7949=>602, 7950=>602, 7951=>602, 7952=>602, 7953=>602, 7954=>602, 7955=>602, 7956=>602, 7957=>602, 7960=>602, 7961=>602, - 7962=>602, 7963=>602, 7964=>602, 7965=>602, 7968=>602, 7969=>602, 7970=>602, 7971=>602, 7972=>602, 7973=>602, 7974=>602, 7975=>602, 7976=>602, 7977=>602, 7978=>602, 7979=>602, - 7980=>602, 7981=>602, 7982=>602, 7983=>602, 7984=>602, 7985=>602, 7986=>602, 7987=>602, 7988=>602, 7989=>602, 7990=>602, 7991=>602, 7992=>602, 7993=>602, 7994=>602, 7995=>602, - 7996=>602, 7997=>602, 7998=>602, 7999=>602, 8000=>602, 8001=>602, 8002=>602, 8003=>602, 8004=>602, 8005=>602, 8008=>602, 8009=>602, 8010=>602, 8011=>602, 8012=>602, 8013=>602, - 8016=>602, 8017=>602, 8018=>602, 8019=>602, 8020=>602, 8021=>602, 8022=>602, 8023=>602, 8025=>602, 8027=>602, 8029=>602, 8031=>602, 8032=>602, 8033=>602, 8034=>602, 8035=>602, - 8036=>602, 8037=>602, 8038=>602, 8039=>602, 8040=>602, 8041=>602, 8042=>602, 8043=>602, 8044=>602, 8045=>602, 8046=>602, 8047=>602, 8048=>602, 8049=>602, 8050=>602, 8051=>602, - 8052=>602, 8053=>602, 8054=>602, 8055=>602, 8056=>602, 8057=>602, 8058=>602, 8059=>602, 8060=>602, 8061=>602, 8064=>602, 8065=>602, 8066=>602, 8067=>602, 8068=>602, 8069=>602, - 8070=>602, 8071=>602, 8072=>602, 8073=>602, 8074=>602, 8075=>602, 8076=>602, 8077=>602, 8078=>602, 8079=>602, 8080=>602, 8081=>602, 8082=>602, 8083=>602, 8084=>602, 8085=>602, - 8086=>602, 8087=>602, 8088=>602, 8089=>602, 8090=>602, 8091=>602, 8092=>602, 8093=>602, 8094=>602, 8095=>602, 8096=>602, 8097=>602, 8098=>602, 8099=>602, 8100=>602, 8101=>602, - 8102=>602, 8103=>602, 8104=>602, 8105=>602, 8106=>602, 8107=>602, 8108=>602, 8109=>602, 8110=>602, 8111=>602, 8112=>602, 8113=>602, 8114=>602, 8115=>602, 8116=>602, 8118=>602, - 8119=>602, 8120=>602, 8121=>602, 8122=>602, 8123=>602, 8124=>602, 8125=>602, 8126=>602, 8127=>602, 8128=>602, 8129=>602, 8130=>602, 8131=>602, 8132=>602, 8134=>602, 8135=>602, - 8136=>602, 8137=>602, 8138=>602, 8139=>602, 8140=>602, 8141=>602, 8142=>602, 8143=>602, 8144=>602, 8145=>602, 8146=>602, 8147=>602, 8150=>602, 8151=>602, 8152=>602, 8153=>602, - 8154=>602, 8155=>602, 8157=>602, 8158=>602, 8159=>602, 8160=>602, 8161=>602, 8162=>602, 8163=>602, 8164=>602, 8165=>602, 8166=>602, 8167=>602, 8168=>602, 8169=>602, 8170=>602, - 8171=>602, 8172=>602, 8173=>602, 8174=>602, 8175=>602, 8178=>602, 8179=>602, 8180=>602, 8182=>602, 8183=>602, 8184=>602, 8185=>602, 8186=>602, 8187=>602, 8188=>602, 8189=>602, - 8190=>602, 8192=>602, 8193=>602, 8194=>602, 8195=>602, 8196=>602, 8197=>602, 8198=>602, 8199=>602, 8200=>602, 8201=>602, 8202=>602, 8208=>602, 8209=>602, 8210=>602, 8213=>602, - 8215=>602, 8219=>602, 8223=>602, 8227=>602, 8239=>602, 8241=>602, 8252=>602, 8253=>602, 8254=>602, 8261=>602, 8262=>602, 8263=>602, 8264=>602, 8265=>602, 8287=>602, 8304=>602, - 8308=>602, 8309=>602, 8310=>602, 8311=>602, 8312=>602, 8313=>602, 8319=>602, 8320=>602, 8321=>602, 8322=>602, 8323=>602, 8324=>602, 8325=>602, 8326=>602, 8327=>602, 8328=>602, - 8329=>602, 8358=>602, 8369=>602, 8372=>602, 8373=>602, 8462=>602, 8470=>602, 8486=>602, 8490=>602, 8491=>602, 8531=>602, 8532=>602, 8533=>602, 8534=>602, 8535=>602, 8536=>602, - 8537=>602, 8538=>602, 8539=>602, 8540=>602, 8541=>602, 8542=>602, 8543=>602, 8592=>602, 8593=>602, 8594=>602, 8595=>602, 8596=>602, 8597=>602, 8598=>602, 8599=>602, 8600=>602, - 8601=>602, 8602=>602, 8603=>602, 8604=>602, 8605=>602, 8606=>602, 8607=>602, 8608=>602, 8609=>602, 8610=>602, 8611=>602, 8612=>602, 8613=>602, 8614=>602, 8615=>602, 8616=>602, - 8617=>602, 8618=>602, 8619=>602, 8620=>602, 8621=>602, 8622=>602, 8623=>602, 8624=>602, 8625=>602, 8626=>602, 8627=>602, 8628=>602, 8629=>602, 8630=>602, 8631=>602, 8632=>602, - 8633=>602, 8634=>602, 8635=>602, 8636=>602, 8637=>602, 8638=>602, 8639=>602, 8640=>602, 8641=>602, 8642=>602, 8643=>602, 8644=>602, 8645=>602, 8646=>602, 8647=>602, 8648=>602, - 8649=>602, 8650=>602, 8651=>602, 8652=>602, 8653=>602, 8654=>602, 8655=>602, 8656=>602, 8657=>602, 8658=>602, 8659=>602, 8660=>602, 8661=>602, 8662=>602, 8663=>602, 8664=>602, - 8665=>602, 8666=>602, 8667=>602, 8668=>602, 8669=>602, 8670=>602, 8671=>602, 8672=>602, 8673=>602, 8674=>602, 8675=>602, 8676=>602, 8677=>602, 8678=>602, 8679=>602, 8680=>602, - 8681=>602, 8682=>602, 8683=>602, 8684=>602, 8685=>602, 8686=>602, 8687=>602, 8688=>602, 8689=>602, 8690=>602, 8691=>602, 8692=>602, 8693=>602, 8694=>602, 8695=>602, 8696=>602, - 8697=>602, 8698=>602, 8699=>602, 8700=>602, 8701=>602, 8702=>602, 8703=>602, 8706=>602, 8709=>602, 8710=>602, 8711=>602, 8712=>602, 8713=>602, 8714=>602, 8715=>602, 8716=>602, - 8717=>602, 8719=>602, 8721=>602, 8722=>602, 8723=>602, 8725=>602, 8727=>602, 8728=>602, 8729=>602, 8730=>602, 8733=>602, 8734=>602, 8735=>602, 8736=>602, 8743=>602, 8744=>602, - 8745=>602, 8746=>602, 8747=>602, 8748=>602, 8749=>602, 8760=>602, 8761=>602, 8762=>602, 8763=>602, 8764=>602, 8765=>602, 8769=>602, 8770=>602, 8771=>602, 8772=>602, 8773=>602, - 8774=>602, 8775=>602, 8776=>602, 8777=>602, 8778=>602, 8779=>602, 8780=>602, 8781=>602, 8782=>602, 8783=>602, 8784=>602, 8785=>602, 8786=>602, 8787=>602, 8788=>602, 8789=>602, - 8790=>602, 8791=>602, 8792=>602, 8793=>602, 8794=>602, 8795=>602, 8796=>602, 8797=>602, 8798=>602, 8799=>602, 8800=>602, 8801=>602, 8802=>602, 8803=>602, 8804=>602, 8805=>602, - 8806=>602, 8807=>602, 8808=>602, 8809=>602, 8813=>602, 8814=>602, 8815=>602, 8816=>602, 8817=>602, 8818=>602, 8819=>602, 8820=>602, 8821=>602, 8822=>602, 8823=>602, 8824=>602, - 8825=>602, 8826=>602, 8827=>602, 8828=>602, 8829=>602, 8830=>602, 8831=>602, 8832=>602, 8833=>602, 8834=>602, 8835=>602, 8836=>602, 8837=>602, 8838=>602, 8839=>602, 8840=>602, - 8841=>602, 8842=>602, 8843=>602, 8847=>602, 8848=>602, 8849=>602, 8850=>602, 8853=>602, 8854=>602, 8855=>602, 8856=>602, 8857=>602, 8858=>602, 8859=>602, 8860=>602, 8861=>602, - 8862=>602, 8863=>602, 8864=>602, 8865=>602, 8901=>602, 8902=>602, 8909=>602, 8922=>602, 8923=>602, 8924=>602, 8925=>602, 8926=>602, 8927=>602, 8928=>602, 8929=>602, 8930=>602, - 8931=>602, 8932=>602, 8933=>602, 8934=>602, 8935=>602, 8936=>602, 8937=>602, 8943=>602, 8960=>602, 8961=>602, 8962=>602, 8963=>602, 8964=>602, 8965=>602, 8966=>602, 8968=>602, - 8969=>602, 8970=>602, 8971=>602, 8972=>602, 8973=>602, 8974=>602, 8975=>602, 8976=>602, 8977=>602, 8978=>602, 8979=>602, 8980=>602, 8981=>602, 8984=>602, 8985=>602, 8988=>602, - 8989=>602, 8990=>602, 8991=>602, 8992=>602, 8993=>602, 8997=>602, 8998=>602, 8999=>602, 9000=>602, 9003=>602, 9013=>602, 9015=>602, 9016=>602, 9017=>602, 9018=>602, 9019=>602, - 9020=>602, 9021=>602, 9022=>602, 9025=>602, 9026=>602, 9027=>602, 9028=>602, 9031=>602, 9032=>602, 9033=>602, 9035=>602, 9036=>602, 9037=>602, 9040=>602, 9042=>602, 9043=>602, - 9044=>602, 9047=>602, 9048=>602, 9049=>602, 9050=>602, 9051=>602, 9052=>602, 9054=>602, 9055=>602, 9056=>602, 9059=>602, 9060=>602, 9061=>602, 9064=>602, 9065=>602, 9067=>602, - 9068=>602, 9069=>602, 9070=>602, 9071=>602, 9072=>602, 9075=>602, 9076=>602, 9077=>602, 9078=>602, 9079=>602, 9080=>602, 9081=>602, 9082=>602, 9085=>602, 9088=>602, 9089=>602, - 9090=>602, 9091=>602, 9096=>602, 9097=>602, 9098=>602, 9099=>602, 9109=>602, 9115=>602, 9116=>602, 9117=>602, 9118=>602, 9119=>602, 9120=>602, 9121=>602, 9122=>602, 9123=>602, - 9124=>602, 9125=>602, 9126=>602, 9127=>602, 9128=>602, 9129=>602, 9130=>602, 9131=>602, 9132=>602, 9133=>602, 9134=>602, 9166=>602, 9167=>602, 9251=>602, 9472=>602, 9473=>602, - 9474=>602, 9475=>602, 9476=>602, 9477=>602, 9478=>602, 9479=>602, 9480=>602, 9481=>602, 9482=>602, 9483=>602, 9484=>602, 9485=>602, 9486=>602, 9487=>602, 9488=>602, 9489=>602, - 9490=>602, 9491=>602, 9492=>602, 9493=>602, 9494=>602, 9495=>602, 9496=>602, 9497=>602, 9498=>602, 9499=>602, 9500=>602, 9501=>602, 9502=>602, 9503=>602, 9504=>602, 9505=>602, - 9506=>602, 9507=>602, 9508=>602, 9509=>602, 9510=>602, 9511=>602, 9512=>602, 9513=>602, 9514=>602, 9515=>602, 9516=>602, 9517=>602, 9518=>602, 9519=>602, 9520=>602, 9521=>602, - 9522=>602, 9523=>602, 9524=>602, 9525=>602, 9526=>602, 9527=>602, 9528=>602, 9529=>602, 9530=>602, 9531=>602, 9532=>602, 9533=>602, 9534=>602, 9535=>602, 9536=>602, 9537=>602, - 9538=>602, 9539=>602, 9540=>602, 9541=>602, 9542=>602, 9543=>602, 9544=>602, 9545=>602, 9546=>602, 9547=>602, 9548=>602, 9549=>602, 9550=>602, 9551=>602, 9552=>602, 9553=>602, - 9554=>602, 9555=>602, 9556=>602, 9557=>602, 9558=>602, 9559=>602, 9560=>602, 9561=>602, 9562=>602, 9563=>602, 9564=>602, 9565=>602, 9566=>602, 9567=>602, 9568=>602, 9569=>602, - 9570=>602, 9571=>602, 9572=>602, 9573=>602, 9574=>602, 9575=>602, 9576=>602, 9577=>602, 9578=>602, 9579=>602, 9580=>602, 9581=>602, 9582=>602, 9583=>602, 9584=>602, 9585=>602, - 9586=>602, 9587=>602, 9588=>602, 9589=>602, 9590=>602, 9591=>602, 9592=>602, 9593=>602, 9594=>602, 9595=>602, 9596=>602, 9597=>602, 9598=>602, 9599=>602, 9600=>602, 9601=>602, - 9602=>602, 9603=>602, 9604=>602, 9605=>602, 9606=>602, 9607=>602, 9608=>602, 9609=>602, 9610=>602, 9611=>602, 9612=>602, 9613=>602, 9614=>602, 9615=>602, 9616=>602, 9617=>602, - 9618=>602, 9619=>602, 9620=>602, 9621=>602, 9622=>602, 9623=>602, 9624=>602, 9625=>602, 9626=>602, 9627=>602, 9628=>602, 9629=>602, 9630=>602, 9631=>602, 9632=>602, 9633=>602, - 9634=>602, 9635=>602, 9636=>602, 9637=>602, 9638=>602, 9639=>602, 9640=>602, 9641=>602, 9642=>602, 9643=>602, 9644=>602, 9645=>602, 9646=>602, 9647=>602, 9648=>602, 9649=>602, - 9650=>602, 9651=>602, 9652=>602, 9653=>602, 9654=>602, 9655=>602, 9656=>602, 9657=>602, 9658=>602, 9659=>602, 9660=>602, 9661=>602, 9662=>602, 9663=>602, 9664=>602, 9665=>602, - 9666=>602, 9667=>602, 9668=>602, 9669=>602, 9670=>602, 9671=>602, 9672=>602, 9673=>602, 9674=>602, 9675=>602, 9676=>602, 9677=>602, 9678=>602, 9679=>602, 9680=>602, 9681=>602, - 9682=>602, 9683=>602, 9684=>602, 9685=>602, 9686=>602, 9687=>602, 9688=>602, 9689=>602, 9690=>602, 9691=>602, 9692=>602, 9693=>602, 9694=>602, 9695=>602, 9696=>602, 9697=>602, - 9698=>602, 9699=>602, 9700=>602, 9701=>602, 9702=>602, 9703=>602, 9704=>602, 9705=>602, 9706=>602, 9707=>602, 9708=>602, 9709=>602, 9710=>602, 9711=>602, 9712=>602, 9713=>602, - 9714=>602, 9715=>602, 9716=>602, 9717=>602, 9718=>602, 9719=>602, 9720=>602, 9721=>602, 9722=>602, 9723=>602, 9724=>602, 9725=>602, 9726=>602, 9727=>602, 9728=>602, 9729=>602, - 9730=>602, 9731=>602, 9732=>602, 9733=>602, 9734=>602, 9735=>602, 9736=>602, 9737=>602, 9738=>602, 9739=>602, 9740=>602, 9741=>602, 9742=>602, 9743=>602, 9744=>602, 9745=>602, - 9746=>602, 9747=>602, 9748=>602, 9749=>602, 9750=>602, 9751=>602, 9752=>602, 9753=>602, 9754=>602, 9755=>602, 9756=>602, 9757=>602, 9758=>602, 9759=>602, 9760=>602, 9761=>602, - 9762=>602, 9763=>602, 9764=>602, 9765=>602, 9766=>602, 9767=>602, 9768=>602, 9769=>602, 9770=>602, 9771=>602, 9772=>602, 9773=>602, 9774=>602, 9775=>602, 9784=>602, 9785=>602, - 9786=>602, 9787=>602, 9788=>602, 9789=>602, 9790=>602, 9791=>602, 9792=>602, 9793=>602, 9794=>602, 9795=>602, 9796=>602, 9797=>602, 9798=>602, 9799=>602, 9800=>602, 9801=>602, - 9802=>602, 9803=>602, 9804=>602, 9805=>602, 9806=>602, 9807=>602, 9808=>602, 9809=>602, 9810=>602, 9811=>602, 9812=>602, 9813=>602, 9814=>602, 9815=>602, 9816=>602, 9817=>602, - 9818=>602, 9819=>602, 9820=>602, 9821=>602, 9822=>602, 9823=>602, 9824=>602, 9825=>602, 9826=>602, 9827=>602, 9828=>602, 9829=>602, 9830=>602, 9831=>602, 9832=>602, 9833=>602, - 9834=>602, 9835=>602, 9836=>602, 9837=>602, 9838=>602, 9839=>602, 9840=>602, 9841=>602, 9842=>602, 9843=>602, 9844=>602, 9845=>602, 9846=>602, 9847=>602, 9848=>602, 9849=>602, - 9850=>602, 9851=>602, 9852=>602, 9853=>602, 9854=>602, 9855=>602, 9856=>602, 9857=>602, 9858=>602, 9859=>602, 9860=>602, 9861=>602, 9862=>602, 9863=>602, 9864=>602, 9865=>602, - 9866=>602, 9867=>602, 9872=>602, 9873=>602, 9874=>602, 9875=>602, 9876=>602, 9877=>602, 9878=>602, 9879=>602, 9880=>602, 9881=>602, 9882=>602, 9883=>602, 9884=>602, 9888=>602, - 9889=>602, 9904=>602, 9905=>602, 9985=>602, 9986=>602, 9987=>602, 9988=>602, 9990=>602, 9991=>602, 9992=>602, 9993=>602, 9996=>602, 9997=>602, 9998=>602, 9999=>602, 10000=>602, - 10001=>602, 10002=>602, 10003=>602, 10004=>602, 10005=>602, 10006=>602, 10007=>602, 10008=>602, 10009=>602, 10010=>602, 10011=>602, 10012=>602, 10013=>602, 10014=>602, 10015=>602, 10016=>602, - 10017=>602, 10018=>602, 10019=>602, 10020=>602, 10021=>602, 10022=>602, 10023=>602, 10025=>602, 10026=>602, 10027=>602, 10028=>602, 10029=>602, 10030=>602, 10031=>602, 10032=>602, 10033=>602, - 10034=>602, 10035=>602, 10036=>602, 10037=>602, 10038=>602, 10039=>602, 10040=>602, 10041=>602, 10042=>602, 10043=>602, 10044=>602, 10045=>602, 10046=>602, 10047=>602, 10048=>602, 10049=>602, - 10050=>602, 10051=>602, 10052=>602, 10053=>602, 10054=>602, 10055=>602, 10056=>602, 10057=>602, 10058=>602, 10059=>602, 10061=>602, 10063=>602, 10064=>602, 10065=>602, 10066=>602, 10070=>602, - 10072=>602, 10073=>602, 10074=>602, 10075=>602, 10076=>602, 10077=>602, 10078=>602, 10081=>602, 10082=>602, 10083=>602, 10084=>602, 10085=>602, 10086=>602, 10087=>602, 10088=>602, 10089=>602, - 10090=>602, 10091=>602, 10092=>602, 10093=>602, 10094=>602, 10095=>602, 10096=>602, 10097=>602, 10098=>602, 10099=>602, 10100=>602, 10101=>602, 10132=>602, 10136=>602, 10137=>602, 10138=>602, - 10139=>602, 10140=>602, 10141=>602, 10142=>602, 10143=>602, 10144=>602, 10145=>602, 10146=>602, 10147=>602, 10148=>602, 10149=>602, 10150=>602, 10151=>602, 10152=>602, 10153=>602, 10154=>602, - 10155=>602, 10156=>602, 10157=>602, 10158=>602, 10159=>602, 10161=>602, 10162=>602, 10163=>602, 10164=>602, 10165=>602, 10166=>602, 10167=>602, 10168=>602, 10169=>602, 10170=>602, 10171=>602, - 10172=>602, 10173=>602, 10174=>602, 10208=>602, 10216=>602, 10217=>602, 10731=>602, 11026=>602, 11027=>602, 11028=>602, 11029=>602, 11030=>602, 11031=>602, 11032=>602, 11033=>602, 11034=>602, - 63173=>602, 64257=>602, 64258=>602, 65533=>602}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansMono.z'; - font[:ctg]='DejaVuSansMono.ctg.z'; - font[:originalsize]=258332; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSansMono.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMonob.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansMonob.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansMonob') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansMono-Bold'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>33,'FontBBox'=>'[-446 -394 720 1102]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>602}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 1027=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 1036=>602, 381=>602, 1039=>602, - 8216=>602, 8217=>602, 8220=>602, 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 1116=>602, 382=>602, 376=>602, 160=>602, - 161=>602, 162=>602, 163=>602, 164=>602, 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, - 177=>602, 178=>602, 179=>602, 180=>602, 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, - 193=>602, 194=>602, 195=>602, 196=>602, 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, - 209=>602, 210=>602, 211=>602, 212=>602, 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, - 225=>602, 226=>602, 227=>602, 228=>602, 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, - 241=>602, 242=>602, 243=>602, 244=>602, 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 256=>602, - 257=>602, 258=>602, 259=>602, 260=>602, 261=>602, 262=>602, 263=>602, 264=>602, 265=>602, 266=>602, 267=>602, 268=>602, 269=>602, 270=>602, 271=>602, 272=>602, - 273=>602, 274=>602, 275=>602, 276=>602, 277=>602, 278=>602, 279=>602, 280=>602, 281=>602, 282=>602, 283=>602, 284=>602, 285=>602, 286=>602, 287=>602, 288=>602, - 289=>602, 290=>602, 291=>602, 292=>602, 293=>602, 294=>602, 295=>602, 296=>602, 297=>602, 298=>602, 299=>602, 300=>602, 301=>602, 302=>602, 303=>602, 304=>602, - 305=>602, 306=>602, 307=>602, 308=>602, 309=>602, 310=>602, 311=>602, 312=>602, 313=>602, 314=>602, 315=>602, 316=>602, 317=>602, 318=>602, 319=>602, 320=>602, - 321=>602, 322=>602, 323=>602, 324=>602, 325=>602, 326=>602, 327=>602, 328=>602, 329=>602, 330=>602, 331=>602, 332=>602, 333=>602, 334=>602, 335=>602, 336=>602, - 337=>602, 340=>602, 341=>602, 342=>602, 343=>602, 344=>602, 345=>602, 346=>602, 347=>602, 348=>602, 349=>602, 350=>602, 351=>602, 354=>602, 355=>602, 356=>602, - 357=>602, 358=>602, 359=>602, 360=>602, 361=>602, 362=>602, 363=>602, 364=>602, 365=>602, 366=>602, 367=>602, 368=>602, 369=>602, 370=>602, 371=>602, 372=>602, - 373=>602, 374=>602, 375=>602, 377=>602, 378=>602, 379=>602, 380=>602, 383=>602, 385=>602, 386=>602, 387=>602, 388=>602, 389=>602, 390=>602, 391=>602, 392=>602, - 393=>602, 394=>602, 395=>602, 396=>602, 397=>602, 398=>602, 399=>602, 400=>602, 401=>602, 403=>602, 404=>602, 405=>602, 406=>602, 407=>602, 408=>602, 409=>602, - 410=>602, 411=>602, 412=>602, 413=>602, 414=>602, 415=>602, 416=>602, 417=>602, 418=>602, 419=>602, 420=>602, 421=>602, 422=>602, 423=>602, 424=>602, 425=>602, - 426=>602, 427=>602, 428=>602, 429=>602, 430=>602, 431=>602, 432=>602, 433=>602, 434=>602, 435=>602, 436=>602, 437=>602, 438=>602, 439=>602, 440=>602, 441=>602, - 443=>602, 444=>602, 445=>602, 446=>602, 448=>602, 449=>602, 450=>602, 451=>602, 461=>602, 462=>602, 463=>602, 464=>602, 465=>602, 466=>602, 467=>602, 468=>602, - 470=>602, 471=>602, 472=>602, 473=>602, 474=>602, 475=>602, 476=>602, 477=>602, 479=>602, 482=>602, 483=>602, 486=>602, 487=>602, 488=>602, 489=>602, 490=>602, - 491=>602, 492=>602, 493=>602, 494=>602, 495=>602, 500=>602, 501=>602, 502=>602, 504=>602, 505=>602, 508=>602, 509=>602, 510=>602, 511=>602, 512=>602, 513=>602, - 514=>602, 515=>602, 516=>602, 517=>602, 518=>602, 519=>602, 520=>602, 521=>602, 522=>602, 523=>602, 524=>602, 525=>602, 526=>602, 527=>602, 528=>602, 529=>602, - 530=>602, 531=>602, 532=>602, 533=>602, 534=>602, 535=>602, 536=>602, 537=>602, 538=>602, 539=>602, 542=>602, 543=>602, 545=>602, 548=>602, 549=>602, 550=>602, - 551=>602, 552=>602, 553=>602, 555=>602, 557=>602, 558=>602, 559=>602, 561=>602, 562=>602, 563=>602, 564=>602, 565=>602, 566=>602, 567=>602, 568=>602, 569=>602, - 570=>602, 571=>602, 572=>602, 573=>602, 574=>602, 575=>602, 576=>602, 577=>602, 581=>602, 592=>602, 593=>602, 594=>602, 595=>602, 596=>602, 597=>602, 598=>602, - 599=>602, 600=>602, 601=>602, 602=>602, 603=>602, 604=>602, 605=>602, 606=>602, 607=>602, 608=>602, 609=>602, 610=>602, 611=>602, 612=>602, 613=>602, 614=>602, - 615=>602, 616=>602, 617=>602, 618=>602, 619=>602, 620=>602, 621=>602, 622=>602, 623=>602, 624=>602, 625=>602, 626=>602, 627=>602, 628=>602, 629=>602, 630=>602, - 631=>602, 632=>602, 633=>602, 634=>602, 635=>602, 636=>602, 637=>602, 638=>602, 639=>602, 640=>602, 641=>602, 642=>602, 643=>602, 644=>602, 645=>602, 646=>602, - 647=>602, 648=>602, 649=>602, 650=>602, 651=>602, 652=>602, 653=>602, 654=>602, 655=>602, 656=>602, 657=>602, 658=>602, 659=>602, 660=>602, 661=>602, 662=>602, - 663=>602, 664=>602, 665=>602, 666=>602, 667=>602, 668=>602, 669=>602, 670=>602, 671=>602, 672=>602, 673=>602, 674=>602, 675=>602, 676=>602, 677=>602, 678=>602, - 679=>602, 680=>602, 681=>602, 682=>602, 683=>602, 684=>602, 685=>602, 686=>602, 687=>602, 688=>602, 689=>602, 690=>602, 691=>602, 692=>602, 693=>602, 694=>602, - 695=>602, 696=>602, 697=>602, 699=>602, 700=>602, 701=>602, 702=>602, 703=>602, 704=>602, 705=>602, 711=>602, 712=>602, 713=>602, 716=>602, 717=>602, 720=>602, - 721=>602, 722=>602, 723=>602, 726=>602, 728=>602, 729=>602, 730=>602, 731=>602, 733=>602, 734=>602, 736=>602, 737=>602, 738=>602, 739=>602, 740=>602, 741=>602, - 742=>602, 743=>602, 744=>602, 745=>602, 755=>602, 768=>602, 769=>602, 770=>602, 771=>602, 772=>602, 773=>602, 774=>602, 775=>602, 776=>602, 777=>602, 778=>602, - 779=>602, 780=>602, 781=>602, 782=>602, 783=>602, 784=>602, 785=>602, 786=>602, 787=>602, 788=>602, 789=>602, 790=>602, 791=>602, 792=>602, 793=>602, 794=>602, - 795=>602, 796=>602, 797=>602, 798=>602, 799=>602, 800=>602, 801=>602, 802=>602, 803=>602, 804=>602, 805=>602, 806=>602, 807=>602, 808=>602, 809=>602, 810=>602, - 811=>602, 812=>602, 813=>602, 814=>602, 815=>602, 816=>602, 817=>602, 818=>602, 819=>602, 820=>602, 821=>602, 822=>602, 823=>602, 824=>602, 825=>602, 826=>602, - 827=>602, 828=>602, 829=>602, 830=>602, 831=>602, 835=>602, 856=>602, 865=>602, 884=>602, 885=>602, 890=>602, 894=>602, 900=>602, 901=>602, 902=>602, 903=>602, - 904=>602, 905=>602, 906=>602, 908=>602, 910=>602, 911=>602, 912=>602, 913=>602, 914=>602, 915=>602, 916=>602, 917=>602, 918=>602, 919=>602, 920=>602, 921=>602, - 922=>602, 923=>602, 924=>602, 925=>602, 926=>602, 927=>602, 928=>602, 929=>602, 931=>602, 932=>602, 933=>602, 934=>602, 935=>602, 936=>602, 937=>602, 938=>602, - 939=>602, 940=>602, 941=>602, 942=>602, 943=>602, 944=>602, 945=>602, 946=>602, 947=>602, 948=>602, 949=>602, 950=>602, 951=>602, 952=>602, 953=>602, 954=>602, - 955=>602, 956=>602, 957=>602, 958=>602, 959=>602, 960=>602, 961=>602, 962=>602, 963=>602, 964=>602, 965=>602, 966=>602, 967=>602, 968=>602, 969=>602, 970=>602, - 971=>602, 972=>602, 973=>602, 974=>602, 976=>602, 977=>602, 978=>602, 979=>602, 980=>602, 981=>602, 982=>602, 983=>602, 984=>602, 985=>602, 986=>602, 987=>602, - 988=>602, 989=>602, 990=>602, 991=>602, 992=>602, 993=>602, 1008=>602, 1009=>602, 1010=>602, 1011=>602, 1012=>602, 1013=>602, 1014=>602, 1015=>602, 1016=>602, 1017=>602, - 1018=>602, 1019=>602, 1020=>602, 1021=>602, 1022=>602, 1023=>602, 1024=>602, 1025=>602, 1026=>602, 1028=>602, 1029=>602, 1030=>602, 1031=>602, 1032=>602, 1033=>602, 1034=>602, - 1035=>602, 1037=>602, 1038=>602, 1040=>602, 1041=>602, 1042=>602, 1043=>602, 1044=>602, 1045=>602, 1046=>602, 1047=>602, 1048=>602, 1049=>602, 1050=>602, 1051=>602, 1052=>602, - 1053=>602, 1054=>602, 1055=>602, 1056=>602, 1057=>602, 1058=>602, 1059=>602, 1060=>602, 1061=>602, 1062=>602, 1063=>602, 1064=>602, 1065=>602, 1066=>602, 1067=>602, 1068=>602, - 1069=>602, 1070=>602, 1071=>602, 1072=>602, 1073=>602, 1074=>602, 1075=>602, 1076=>602, 1077=>602, 1078=>602, 1079=>602, 1080=>602, 1081=>602, 1082=>602, 1083=>602, 1084=>602, - 1085=>602, 1086=>602, 1087=>602, 1088=>602, 1089=>602, 1090=>602, 1091=>602, 1092=>602, 1093=>602, 1094=>602, 1095=>602, 1096=>602, 1097=>602, 1098=>602, 1099=>602, 1100=>602, - 1101=>602, 1102=>602, 1103=>602, 1104=>602, 1105=>602, 1106=>602, 1107=>602, 1108=>602, 1109=>602, 1110=>602, 1111=>602, 1112=>602, 1113=>602, 1114=>602, 1115=>602, 1117=>602, - 1118=>602, 1119=>602, 1168=>602, 1169=>602, 1170=>602, 1171=>602, 1172=>602, 1173=>602, 1176=>602, 1177=>602, 1178=>602, 1179=>602, 1186=>602, 1187=>602, 1194=>602, 1195=>602, - 1196=>602, 1197=>602, 1198=>602, 1199=>602, 1202=>602, 1203=>602, 1210=>602, 1211=>602, 1216=>602, 1217=>602, 1218=>602, 1219=>602, 1220=>602, 1223=>602, 1224=>602, 1227=>602, - 1228=>602, 1231=>602, 1232=>602, 1233=>602, 1234=>602, 1235=>602, 1236=>602, 1237=>602, 1238=>602, 1239=>602, 1240=>602, 1241=>602, 1242=>602, 1243=>602, 1244=>602, 1245=>602, - 1246=>602, 1247=>602, 1248=>602, 1249=>602, 1250=>602, 1251=>602, 1252=>602, 1253=>602, 1254=>602, 1255=>602, 1256=>602, 1257=>602, 1258=>602, 1259=>602, 1260=>602, 1261=>602, - 1262=>602, 1263=>602, 1264=>602, 1265=>602, 1266=>602, 1267=>602, 1268=>602, 1269=>602, 1270=>602, 1271=>602, 1272=>602, 1273=>602, 3713=>602, 3714=>602, 3716=>602, 3719=>602, - 3720=>602, 3722=>602, 3725=>602, 3732=>602, 3733=>602, 3734=>602, 3735=>602, 3737=>602, 3738=>602, 3739=>602, 3740=>602, 3741=>602, 3742=>602, 3743=>602, 3745=>602, 3746=>602, - 3747=>602, 3749=>602, 3751=>602, 3754=>602, 3755=>602, 3757=>602, 3758=>602, 3759=>602, 7426=>602, 7432=>602, 7433=>602, 7444=>602, 7446=>602, 7447=>602, 7453=>602, 7454=>602, - 7455=>602, 7491=>602, 7492=>602, 7493=>602, 7494=>602, 7495=>602, 7496=>602, 7497=>602, 7498=>602, 7499=>602, 7500=>602, 7501=>602, 7502=>602, 7503=>602, 7504=>602, 7505=>602, - 7506=>602, 7507=>602, 7508=>602, 7509=>602, 7510=>602, 7511=>602, 7512=>602, 7513=>602, 7514=>602, 7515=>602, 7543=>602, 7547=>602, 7557=>602, 7579=>602, 7580=>602, 7581=>602, - 7582=>602, 7583=>602, 7584=>602, 7585=>602, 7586=>602, 7587=>602, 7588=>602, 7589=>602, 7590=>602, 7591=>602, 7592=>602, 7593=>602, 7594=>602, 7595=>602, 7596=>602, 7597=>602, - 7598=>602, 7599=>602, 7600=>602, 7601=>602, 7602=>602, 7603=>602, 7604=>602, 7605=>602, 7606=>602, 7607=>602, 7609=>602, 7610=>602, 7611=>602, 7612=>602, 7613=>602, 7614=>602, - 7615=>602, 7680=>602, 7681=>602, 7682=>602, 7683=>602, 7684=>602, 7685=>602, 7686=>602, 7687=>602, 7690=>602, 7691=>602, 7692=>602, 7693=>602, 7694=>602, 7695=>602, 7698=>602, - 7699=>602, 7704=>602, 7705=>602, 7706=>602, 7707=>602, 7708=>602, 7709=>602, 7710=>602, 7711=>602, 7712=>602, 7713=>602, 7714=>602, 7715=>602, 7716=>602, 7717=>602, 7720=>602, - 7721=>602, 7722=>602, 7723=>602, 7724=>602, 7725=>602, 7728=>602, 7729=>602, 7730=>602, 7731=>602, 7732=>602, 7733=>602, 7734=>602, 7735=>602, 7736=>602, 7737=>602, 7738=>602, - 7739=>602, 7740=>602, 7741=>602, 7742=>602, 7743=>602, 7744=>602, 7745=>602, 7746=>602, 7747=>602, 7748=>602, 7749=>602, 7750=>602, 7751=>602, 7752=>602, 7753=>602, 7754=>602, - 7755=>602, 7766=>602, 7767=>602, 7768=>602, 7769=>602, 7770=>602, 7771=>602, 7772=>602, 7773=>602, 7774=>602, 7775=>602, 7776=>602, 7777=>602, 7778=>602, 7779=>602, 7784=>602, - 7785=>602, 7786=>602, 7787=>602, 7788=>602, 7789=>602, 7790=>602, 7791=>602, 7792=>602, 7793=>602, 7794=>602, 7795=>602, 7796=>602, 7797=>602, 7798=>602, 7799=>602, 7806=>602, - 7807=>602, 7808=>602, 7809=>602, 7810=>602, 7811=>602, 7812=>602, 7813=>602, 7814=>602, 7815=>602, 7816=>602, 7817=>602, 7818=>602, 7819=>602, 7822=>602, 7823=>602, 7826=>602, - 7827=>602, 7828=>602, 7829=>602, 7830=>602, 7835=>602, 7840=>602, 7841=>602, 7864=>602, 7865=>602, 7868=>602, 7869=>602, 7882=>602, 7883=>602, 7884=>602, 7885=>602, 7908=>602, - 7909=>602, 7922=>602, 7923=>602, 7924=>602, 7925=>602, 7928=>602, 7929=>602, 7936=>602, 7937=>602, 7938=>602, 7939=>602, 7940=>602, 7941=>602, 7942=>602, 7943=>602, 7944=>602, - 7945=>602, 7946=>602, 7947=>602, 7948=>602, 7949=>602, 7950=>602, 7951=>602, 7952=>602, 7953=>602, 7954=>602, 7955=>602, 7956=>602, 7957=>602, 7960=>602, 7961=>602, 7962=>602, - 7963=>602, 7964=>602, 7965=>602, 7968=>602, 7969=>602, 7970=>602, 7971=>602, 7972=>602, 7973=>602, 7974=>602, 7975=>602, 7976=>602, 7977=>602, 7978=>602, 7979=>602, 7980=>602, - 7981=>602, 7982=>602, 7983=>602, 7984=>602, 7985=>602, 7986=>602, 7987=>602, 7988=>602, 7989=>602, 7990=>602, 7991=>602, 7992=>602, 7993=>602, 7994=>602, 7995=>602, 7996=>602, - 7997=>602, 7998=>602, 7999=>602, 8000=>602, 8001=>602, 8002=>602, 8003=>602, 8004=>602, 8005=>602, 8008=>602, 8009=>602, 8010=>602, 8011=>602, 8012=>602, 8013=>602, 8016=>602, - 8017=>602, 8018=>602, 8019=>602, 8020=>602, 8021=>602, 8022=>602, 8023=>602, 8025=>602, 8027=>602, 8029=>602, 8031=>602, 8032=>602, 8033=>602, 8034=>602, 8035=>602, 8036=>602, - 8037=>602, 8038=>602, 8039=>602, 8040=>602, 8041=>602, 8042=>602, 8043=>602, 8044=>602, 8045=>602, 8046=>602, 8047=>602, 8048=>602, 8049=>602, 8050=>602, 8051=>602, 8052=>602, - 8053=>602, 8054=>602, 8055=>602, 8056=>602, 8057=>602, 8058=>602, 8059=>602, 8060=>602, 8061=>602, 8064=>602, 8065=>602, 8066=>602, 8067=>602, 8068=>602, 8069=>602, 8070=>602, - 8071=>602, 8072=>602, 8073=>602, 8074=>602, 8075=>602, 8076=>602, 8077=>602, 8078=>602, 8079=>602, 8080=>602, 8081=>602, 8082=>602, 8083=>602, 8084=>602, 8085=>602, 8086=>602, - 8087=>602, 8088=>602, 8089=>602, 8090=>602, 8091=>602, 8092=>602, 8093=>602, 8094=>602, 8095=>602, 8096=>602, 8097=>602, 8098=>602, 8099=>602, 8100=>602, 8101=>602, 8102=>602, - 8103=>602, 8104=>602, 8105=>602, 8106=>602, 8107=>602, 8108=>602, 8109=>602, 8110=>602, 8111=>602, 8112=>602, 8113=>602, 8114=>602, 8115=>602, 8116=>602, 8118=>602, 8119=>602, - 8120=>602, 8121=>602, 8122=>602, 8123=>602, 8124=>602, 8125=>602, 8126=>602, 8127=>602, 8128=>602, 8129=>602, 8130=>602, 8131=>602, 8132=>602, 8134=>602, 8135=>602, 8136=>602, - 8137=>602, 8138=>602, 8139=>602, 8140=>602, 8141=>602, 8142=>602, 8143=>602, 8144=>602, 8145=>602, 8146=>602, 8147=>602, 8150=>602, 8151=>602, 8152=>602, 8153=>602, 8154=>602, - 8155=>602, 8157=>602, 8158=>602, 8159=>602, 8160=>602, 8161=>602, 8162=>602, 8163=>602, 8164=>602, 8165=>602, 8166=>602, 8167=>602, 8168=>602, 8169=>602, 8170=>602, 8171=>602, - 8172=>602, 8173=>602, 8174=>602, 8175=>602, 8178=>602, 8179=>602, 8180=>602, 8182=>602, 8183=>602, 8184=>602, 8185=>602, 8186=>602, 8187=>602, 8188=>602, 8189=>602, 8190=>602, - 8192=>602, 8193=>602, 8194=>602, 8195=>602, 8196=>602, 8197=>602, 8198=>602, 8199=>602, 8200=>602, 8201=>602, 8202=>602, 8208=>602, 8209=>602, 8210=>602, 8213=>602, 8215=>602, - 8219=>602, 8223=>602, 8227=>602, 8239=>602, 8241=>602, 8252=>602, 8253=>602, 8254=>602, 8261=>602, 8262=>602, 8263=>602, 8264=>602, 8265=>602, 8287=>602, 8304=>602, 8308=>602, - 8309=>602, 8310=>602, 8311=>602, 8312=>602, 8313=>602, 8319=>602, 8320=>602, 8321=>602, 8322=>602, 8323=>602, 8324=>602, 8325=>602, 8326=>602, 8327=>602, 8328=>602, 8329=>602, - 8358=>602, 8369=>602, 8372=>602, 8373=>602, 8462=>602, 8470=>602, 8486=>602, 8490=>602, 8491=>602, 8531=>602, 8532=>602, 8533=>602, 8534=>602, 8535=>602, 8536=>602, 8537=>602, - 8538=>602, 8539=>602, 8540=>602, 8541=>602, 8542=>602, 8543=>602, 8592=>602, 8593=>602, 8594=>602, 8595=>602, 8596=>602, 8597=>602, 8598=>602, 8599=>602, 8600=>602, 8601=>602, - 8602=>602, 8603=>602, 8604=>602, 8605=>602, 8606=>602, 8607=>602, 8608=>602, 8609=>602, 8610=>602, 8611=>602, 8612=>602, 8613=>602, 8614=>602, 8615=>602, 8616=>602, 8617=>602, - 8618=>602, 8619=>602, 8620=>602, 8621=>602, 8622=>602, 8623=>602, 8624=>602, 8625=>602, 8626=>602, 8627=>602, 8628=>602, 8629=>602, 8630=>602, 8631=>602, 8632=>602, 8633=>602, - 8634=>602, 8635=>602, 8636=>602, 8637=>602, 8638=>602, 8639=>602, 8640=>602, 8641=>602, 8642=>602, 8643=>602, 8644=>602, 8645=>602, 8646=>602, 8647=>602, 8648=>602, 8649=>602, - 8650=>602, 8651=>602, 8652=>602, 8653=>602, 8654=>602, 8655=>602, 8656=>602, 8657=>602, 8658=>602, 8659=>602, 8660=>602, 8661=>602, 8662=>602, 8663=>602, 8664=>602, 8665=>602, - 8666=>602, 8667=>602, 8668=>602, 8669=>602, 8670=>602, 8671=>602, 8672=>602, 8673=>602, 8674=>602, 8675=>602, 8676=>602, 8677=>602, 8678=>602, 8679=>602, 8680=>602, 8681=>602, - 8682=>602, 8683=>602, 8684=>602, 8685=>602, 8686=>602, 8687=>602, 8688=>602, 8689=>602, 8690=>602, 8691=>602, 8692=>602, 8693=>602, 8694=>602, 8695=>602, 8696=>602, 8697=>602, - 8698=>602, 8699=>602, 8700=>602, 8701=>602, 8702=>602, 8703=>602, 8706=>602, 8709=>602, 8710=>602, 8711=>602, 8712=>602, 8713=>602, 8714=>602, 8715=>602, 8716=>602, 8717=>602, - 8719=>602, 8721=>602, 8722=>602, 8723=>602, 8725=>602, 8727=>602, 8728=>602, 8729=>602, 8730=>602, 8733=>602, 8734=>602, 8735=>602, 8736=>602, 8743=>602, 8744=>602, 8745=>602, - 8746=>602, 8747=>602, 8748=>602, 8749=>602, 8760=>602, 8761=>602, 8762=>602, 8763=>602, 8764=>602, 8765=>602, 8769=>602, 8770=>602, 8771=>602, 8772=>602, 8773=>602, 8774=>602, - 8775=>602, 8776=>602, 8777=>602, 8778=>602, 8779=>602, 8780=>602, 8781=>602, 8782=>602, 8783=>602, 8784=>602, 8785=>602, 8786=>602, 8787=>602, 8788=>602, 8789=>602, 8790=>602, - 8791=>602, 8792=>602, 8793=>602, 8794=>602, 8795=>602, 8796=>602, 8797=>602, 8798=>602, 8799=>602, 8800=>602, 8801=>602, 8802=>602, 8803=>602, 8804=>602, 8805=>602, 8806=>602, - 8807=>602, 8808=>602, 8809=>602, 8813=>602, 8814=>602, 8815=>602, 8816=>602, 8817=>602, 8818=>602, 8819=>602, 8820=>602, 8821=>602, 8822=>602, 8823=>602, 8824=>602, 8825=>602, - 8826=>602, 8827=>602, 8828=>602, 8829=>602, 8830=>602, 8831=>602, 8832=>602, 8833=>602, 8834=>602, 8835=>602, 8836=>602, 8837=>602, 8838=>602, 8839=>602, 8840=>602, 8841=>602, - 8842=>602, 8843=>602, 8847=>602, 8848=>602, 8849=>602, 8850=>602, 8853=>602, 8854=>602, 8855=>602, 8856=>602, 8857=>602, 8858=>602, 8859=>602, 8860=>602, 8861=>602, 8862=>602, - 8863=>602, 8864=>602, 8865=>602, 8901=>602, 8902=>602, 8909=>602, 8922=>602, 8923=>602, 8924=>602, 8925=>602, 8926=>602, 8927=>602, 8928=>602, 8929=>602, 8930=>602, 8931=>602, - 8932=>602, 8933=>602, 8934=>602, 8935=>602, 8936=>602, 8937=>602, 8943=>602, 8960=>602, 8961=>602, 8962=>602, 8963=>602, 8964=>602, 8965=>602, 8966=>602, 8968=>602, 8969=>602, - 8970=>602, 8971=>602, 8972=>602, 8973=>602, 8974=>602, 8975=>602, 8976=>602, 8977=>602, 8978=>602, 8979=>602, 8980=>602, 8981=>602, 8984=>602, 8985=>602, 8988=>602, 8989=>602, - 8990=>602, 8991=>602, 8992=>602, 8993=>602, 8997=>602, 8998=>602, 8999=>602, 9000=>602, 9003=>602, 9013=>602, 9015=>602, 9016=>602, 9017=>602, 9018=>602, 9019=>602, 9020=>602, - 9021=>602, 9022=>602, 9025=>602, 9026=>602, 9027=>602, 9028=>602, 9031=>602, 9032=>602, 9033=>602, 9035=>602, 9036=>602, 9037=>602, 9040=>602, 9042=>602, 9043=>602, 9044=>602, - 9047=>602, 9048=>602, 9049=>602, 9050=>602, 9051=>602, 9052=>602, 9054=>602, 9055=>602, 9056=>602, 9059=>602, 9060=>602, 9061=>602, 9064=>602, 9065=>602, 9067=>602, 9068=>602, - 9069=>602, 9070=>602, 9071=>602, 9072=>602, 9075=>602, 9076=>602, 9077=>602, 9078=>602, 9079=>602, 9080=>602, 9081=>602, 9082=>602, 9085=>602, 9088=>602, 9089=>602, 9090=>602, - 9091=>602, 9096=>602, 9097=>602, 9098=>602, 9099=>602, 9109=>602, 9115=>602, 9116=>602, 9117=>602, 9118=>602, 9119=>602, 9120=>602, 9121=>602, 9122=>602, 9123=>602, 9124=>602, - 9125=>602, 9126=>602, 9127=>602, 9128=>602, 9129=>602, 9130=>602, 9131=>602, 9132=>602, 9133=>602, 9134=>602, 9166=>602, 9167=>602, 9251=>602, 9600=>602, 9601=>602, 9602=>602, - 9603=>602, 9604=>602, 9605=>602, 9606=>602, 9607=>602, 9608=>602, 9609=>602, 9610=>602, 9611=>602, 9612=>602, 9613=>602, 9614=>602, 9615=>602, 9616=>602, 9617=>602, 9618=>602, - 9619=>602, 9620=>602, 9621=>602, 9622=>602, 9623=>602, 9624=>602, 9625=>602, 9626=>602, 9627=>602, 9628=>602, 9629=>602, 9630=>602, 9631=>602, 9632=>602, 9633=>602, 9634=>602, - 9635=>602, 9636=>602, 9637=>602, 9638=>602, 9639=>602, 9640=>602, 9641=>602, 9642=>602, 9643=>602, 9644=>602, 9645=>602, 9646=>602, 9647=>602, 9648=>602, 9649=>602, 9650=>602, - 9651=>602, 9652=>602, 9653=>602, 9654=>602, 9655=>602, 9656=>602, 9657=>602, 9658=>602, 9659=>602, 9660=>602, 9661=>602, 9662=>602, 9663=>602, 9664=>602, 9665=>602, 9666=>602, - 9667=>602, 9668=>602, 9669=>602, 9670=>602, 9671=>602, 9672=>602, 9673=>602, 9674=>602, 9675=>602, 9676=>602, 9677=>602, 9678=>602, 9679=>602, 9680=>602, 9681=>602, 9682=>602, - 9683=>602, 9684=>602, 9685=>602, 9686=>602, 9687=>602, 9688=>602, 9689=>602, 9690=>602, 9691=>602, 9692=>602, 9693=>602, 9694=>602, 9695=>602, 9696=>602, 9697=>602, 9698=>602, - 9699=>602, 9700=>602, 9701=>602, 9702=>602, 9703=>602, 9704=>602, 9705=>602, 9706=>602, 9707=>602, 9708=>602, 9709=>602, 9710=>602, 9711=>602, 9712=>602, 9713=>602, 9714=>602, - 9715=>602, 9716=>602, 9717=>602, 9718=>602, 9719=>602, 9720=>602, 9721=>602, 9722=>602, 9723=>602, 9724=>602, 9725=>602, 9726=>602, 9727=>602, 9728=>602, 9729=>602, 9730=>602, - 9731=>602, 9732=>602, 9733=>602, 9734=>602, 9735=>602, 9736=>602, 9737=>602, 9738=>602, 9739=>602, 9740=>602, 9741=>602, 9742=>602, 9743=>602, 9744=>602, 9745=>602, 9746=>602, - 9747=>602, 9748=>602, 9749=>602, 9750=>602, 9751=>602, 9752=>602, 9753=>602, 9754=>602, 9755=>602, 9756=>602, 9757=>602, 9758=>602, 9759=>602, 9760=>602, 9761=>602, 9762=>602, - 9763=>602, 9764=>602, 9765=>602, 9766=>602, 9767=>602, 9768=>602, 9769=>602, 9770=>602, 9771=>602, 9772=>602, 9773=>602, 9774=>602, 9775=>602, 9784=>602, 9785=>602, 9786=>602, - 9787=>602, 9788=>602, 9789=>602, 9790=>602, 9791=>602, 9792=>602, 9793=>602, 9794=>602, 9795=>602, 9796=>602, 9797=>602, 9798=>602, 9799=>602, 9800=>602, 9801=>602, 9802=>602, - 9803=>602, 9804=>602, 9805=>602, 9806=>602, 9807=>602, 9808=>602, 9809=>602, 9810=>602, 9811=>602, 9812=>602, 9813=>602, 9814=>602, 9815=>602, 9816=>602, 9817=>602, 9818=>602, - 9819=>602, 9820=>602, 9821=>602, 9822=>602, 9823=>602, 9824=>602, 9825=>602, 9826=>602, 9827=>602, 9828=>602, 9829=>602, 9830=>602, 9831=>602, 9832=>602, 9833=>602, 9834=>602, - 9835=>602, 9836=>602, 9837=>602, 9838=>602, 9839=>602, 9840=>602, 9841=>602, 9842=>602, 9843=>602, 9844=>602, 9845=>602, 9846=>602, 9847=>602, 9848=>602, 9849=>602, 9850=>602, - 9851=>602, 9852=>602, 9853=>602, 9854=>602, 9855=>602, 9856=>602, 9857=>602, 9858=>602, 9859=>602, 9860=>602, 9861=>602, 9862=>602, 9863=>602, 9864=>602, 9865=>602, 9866=>602, - 9867=>602, 9872=>602, 9873=>602, 9874=>602, 9875=>602, 9876=>602, 9877=>602, 9878=>602, 9879=>602, 9880=>602, 9881=>602, 9882=>602, 9883=>602, 9884=>602, 9888=>602, 9889=>602, - 9904=>602, 9905=>602, 9985=>602, 9986=>602, 9987=>602, 9988=>602, 9990=>602, 9991=>602, 9992=>602, 9993=>602, 9996=>602, 9997=>602, 9998=>602, 9999=>602, 10000=>602, 10001=>602, - 10002=>602, 10003=>602, 10004=>602, 10005=>602, 10006=>602, 10007=>602, 10008=>602, 10009=>602, 10010=>602, 10011=>602, 10012=>602, 10013=>602, 10014=>602, 10015=>602, 10016=>602, 10017=>602, - 10018=>602, 10019=>602, 10020=>602, 10021=>602, 10022=>602, 10023=>602, 10025=>602, 10026=>602, 10027=>602, 10028=>602, 10029=>602, 10030=>602, 10031=>602, 10032=>602, 10033=>602, 10034=>602, - 10035=>602, 10036=>602, 10037=>602, 10038=>602, 10039=>602, 10040=>602, 10041=>602, 10042=>602, 10043=>602, 10044=>602, 10045=>602, 10046=>602, 10047=>602, 10048=>602, 10049=>602, 10050=>602, - 10051=>602, 10052=>602, 10053=>602, 10054=>602, 10055=>602, 10056=>602, 10057=>602, 10058=>602, 10059=>602, 10061=>602, 10063=>602, 10064=>602, 10065=>602, 10066=>602, 10070=>602, 10072=>602, - 10073=>602, 10074=>602, 10075=>602, 10076=>602, 10077=>602, 10078=>602, 10081=>602, 10082=>602, 10083=>602, 10084=>602, 10085=>602, 10086=>602, 10087=>602, 10088=>602, 10089=>602, 10090=>602, - 10091=>602, 10092=>602, 10093=>602, 10094=>602, 10095=>602, 10096=>602, 10097=>602, 10098=>602, 10099=>602, 10100=>602, 10101=>602, 10132=>602, 10136=>602, 10137=>602, 10138=>602, 10139=>602, - 10140=>602, 10141=>602, 10142=>602, 10143=>602, 10144=>602, 10145=>602, 10146=>602, 10147=>602, 10148=>602, 10149=>602, 10150=>602, 10151=>602, 10152=>602, 10153=>602, 10154=>602, 10155=>602, - 10156=>602, 10157=>602, 10158=>602, 10159=>602, 10161=>602, 10162=>602, 10163=>602, 10164=>602, 10165=>602, 10166=>602, 10167=>602, 10168=>602, 10169=>602, 10170=>602, 10171=>602, 10172=>602, - 10173=>602, 10174=>602, 10175=>602, 10208=>602, 10216=>602, 10217=>602, 10731=>602, 11026=>602, 11027=>602, 11028=>602, 11029=>602, 11030=>602, 11031=>602, 11032=>602, 11033=>602, 11034=>602, - 63173=>602, 64257=>602, 64258=>602, 65533=>602}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansMono-Bold.z'; - font[:ctg]='DejaVuSansMono-Bold.ctg.z'; - font[:originalsize]=245648; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMonobi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansMonobi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansMonobi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansMono-BoldOblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>97,'FontBBox'=>'[-386 -394 808 1102]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>602}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 1027=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 1036=>602, 381=>602, 1039=>602, - 8216=>602, 8217=>602, 8220=>602, 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 1116=>602, 382=>602, 376=>602, 160=>602, - 161=>602, 162=>602, 163=>602, 164=>602, 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, - 177=>602, 178=>602, 179=>602, 180=>602, 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, - 193=>602, 194=>602, 195=>602, 196=>602, 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, - 209=>602, 210=>602, 211=>602, 212=>602, 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, - 225=>602, 226=>602, 227=>602, 228=>602, 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, - 241=>602, 242=>602, 243=>602, 244=>602, 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 256=>602, - 257=>602, 258=>602, 259=>602, 260=>602, 261=>602, 262=>602, 263=>602, 264=>602, 265=>602, 266=>602, 267=>602, 268=>602, 269=>602, 270=>602, 271=>602, 272=>602, - 273=>602, 274=>602, 275=>602, 276=>602, 277=>602, 278=>602, 279=>602, 280=>602, 281=>602, 282=>602, 283=>602, 284=>602, 285=>602, 286=>602, 287=>602, 288=>602, - 289=>602, 290=>602, 291=>602, 292=>602, 293=>602, 294=>602, 295=>602, 296=>602, 297=>602, 298=>602, 299=>602, 300=>602, 301=>602, 302=>602, 303=>602, 304=>602, - 305=>602, 306=>602, 307=>602, 308=>602, 309=>602, 310=>602, 311=>602, 312=>602, 313=>602, 314=>602, 315=>602, 316=>602, 317=>602, 318=>602, 319=>602, 320=>602, - 321=>602, 322=>602, 323=>602, 324=>602, 325=>602, 326=>602, 327=>602, 328=>602, 329=>602, 330=>602, 331=>602, 332=>602, 333=>602, 334=>602, 335=>602, 336=>602, - 337=>602, 340=>602, 341=>602, 342=>602, 343=>602, 344=>602, 345=>602, 346=>602, 347=>602, 348=>602, 349=>602, 350=>602, 351=>602, 354=>602, 355=>602, 356=>602, - 357=>602, 358=>602, 359=>602, 360=>602, 361=>602, 362=>602, 363=>602, 364=>602, 365=>602, 366=>602, 367=>602, 368=>602, 369=>602, 370=>602, 371=>602, 372=>602, - 373=>602, 374=>602, 375=>602, 377=>602, 378=>602, 379=>602, 380=>602, 383=>602, 385=>602, 386=>602, 387=>602, 388=>602, 389=>602, 390=>602, 391=>602, 392=>602, - 393=>602, 394=>602, 395=>602, 396=>602, 397=>602, 398=>602, 399=>602, 400=>602, 401=>602, 403=>602, 404=>602, 405=>602, 406=>602, 407=>602, 408=>602, 409=>602, - 410=>602, 411=>602, 412=>602, 413=>602, 414=>602, 415=>602, 416=>602, 417=>602, 418=>602, 419=>602, 420=>602, 421=>602, 422=>602, 423=>602, 424=>602, 425=>602, - 426=>602, 427=>602, 428=>602, 429=>602, 430=>602, 431=>602, 432=>602, 433=>602, 434=>602, 435=>602, 436=>602, 437=>602, 438=>602, 439=>602, 440=>602, 441=>602, - 443=>602, 444=>602, 445=>602, 446=>602, 448=>602, 449=>602, 450=>602, 451=>602, 461=>602, 462=>602, 463=>602, 464=>602, 465=>602, 466=>602, 467=>602, 468=>602, - 470=>602, 471=>602, 472=>602, 473=>602, 474=>602, 475=>602, 476=>602, 477=>602, 479=>602, 482=>602, 483=>602, 486=>602, 487=>602, 488=>602, 489=>602, 490=>602, - 491=>602, 492=>602, 493=>602, 494=>602, 495=>602, 500=>602, 501=>602, 502=>602, 504=>602, 505=>602, 508=>602, 509=>602, 510=>602, 511=>602, 512=>602, 513=>602, - 514=>602, 515=>602, 516=>602, 517=>602, 518=>602, 519=>602, 520=>602, 521=>602, 522=>602, 523=>602, 524=>602, 525=>602, 526=>602, 527=>602, 528=>602, 529=>602, - 530=>602, 531=>602, 532=>602, 533=>602, 534=>602, 535=>602, 536=>602, 537=>602, 538=>602, 539=>602, 542=>602, 543=>602, 545=>602, 548=>602, 549=>602, 550=>602, - 551=>602, 552=>602, 553=>602, 555=>602, 557=>602, 558=>602, 559=>602, 561=>602, 562=>602, 563=>602, 564=>602, 565=>602, 566=>602, 567=>602, 568=>602, 569=>602, - 570=>602, 571=>602, 572=>602, 573=>602, 574=>602, 575=>602, 576=>602, 577=>602, 581=>602, 592=>602, 593=>602, 594=>602, 595=>602, 596=>602, 597=>602, 598=>602, - 599=>602, 600=>602, 601=>602, 602=>602, 603=>602, 604=>602, 605=>602, 606=>602, 607=>602, 608=>602, 609=>602, 610=>602, 611=>602, 612=>602, 613=>602, 614=>602, - 615=>602, 616=>602, 617=>602, 618=>602, 619=>602, 620=>602, 621=>602, 622=>602, 623=>602, 624=>602, 625=>602, 626=>602, 627=>602, 628=>602, 629=>602, 630=>602, - 631=>602, 632=>602, 633=>602, 634=>602, 635=>602, 636=>602, 637=>602, 638=>602, 639=>602, 640=>602, 641=>602, 642=>602, 643=>602, 644=>602, 645=>602, 646=>602, - 647=>602, 648=>602, 649=>602, 650=>602, 651=>602, 652=>602, 653=>602, 654=>602, 655=>602, 656=>602, 657=>602, 658=>602, 659=>602, 660=>602, 661=>602, 662=>602, - 663=>602, 664=>602, 665=>602, 666=>602, 667=>602, 668=>602, 669=>602, 670=>602, 671=>602, 672=>602, 673=>602, 674=>602, 675=>602, 676=>602, 677=>602, 678=>602, - 679=>602, 680=>602, 681=>602, 682=>602, 683=>602, 684=>602, 685=>602, 686=>602, 687=>602, 688=>602, 689=>602, 690=>602, 691=>602, 692=>602, 693=>602, 694=>602, - 695=>602, 696=>602, 697=>602, 699=>602, 700=>602, 701=>602, 702=>602, 703=>602, 704=>602, 705=>602, 711=>602, 712=>602, 713=>602, 716=>602, 717=>602, 720=>602, - 721=>602, 722=>602, 723=>602, 726=>602, 728=>602, 729=>602, 730=>602, 731=>602, 733=>602, 734=>602, 736=>602, 737=>602, 738=>602, 739=>602, 740=>602, 741=>602, - 742=>602, 743=>602, 744=>602, 745=>602, 755=>602, 768=>602, 769=>602, 770=>602, 771=>602, 772=>602, 773=>602, 774=>602, 775=>602, 776=>602, 777=>602, 778=>602, - 779=>602, 780=>602, 781=>602, 782=>602, 783=>602, 784=>602, 785=>602, 786=>602, 787=>602, 788=>602, 789=>602, 790=>602, 791=>602, 792=>602, 793=>602, 794=>602, - 795=>602, 796=>602, 797=>602, 798=>602, 799=>602, 800=>602, 801=>602, 802=>602, 803=>602, 804=>602, 805=>602, 806=>602, 807=>602, 808=>602, 809=>602, 810=>602, - 811=>602, 812=>602, 813=>602, 814=>602, 815=>602, 816=>602, 817=>602, 818=>602, 819=>602, 820=>602, 821=>602, 822=>602, 823=>602, 824=>602, 825=>602, 826=>602, - 827=>602, 828=>602, 829=>602, 830=>602, 831=>602, 835=>602, 856=>602, 865=>602, 884=>602, 885=>602, 890=>602, 894=>602, 900=>602, 901=>602, 902=>602, 903=>602, - 904=>602, 905=>602, 906=>602, 908=>602, 910=>602, 911=>602, 912=>602, 913=>602, 914=>602, 915=>602, 916=>602, 917=>602, 918=>602, 919=>602, 920=>602, 921=>602, - 922=>602, 923=>602, 924=>602, 925=>602, 926=>602, 927=>602, 928=>602, 929=>602, 931=>602, 932=>602, 933=>602, 934=>602, 935=>602, 936=>602, 937=>602, 938=>602, - 939=>602, 940=>602, 941=>602, 942=>602, 943=>602, 944=>602, 945=>602, 946=>602, 947=>602, 948=>602, 949=>602, 950=>602, 951=>602, 952=>602, 953=>602, 954=>602, - 955=>602, 956=>602, 957=>602, 958=>602, 959=>602, 960=>602, 961=>602, 962=>602, 963=>602, 964=>602, 965=>602, 966=>602, 967=>602, 968=>602, 969=>602, 970=>602, - 971=>602, 972=>602, 973=>602, 974=>602, 976=>602, 977=>602, 978=>602, 979=>602, 980=>602, 981=>602, 982=>602, 983=>602, 984=>602, 985=>602, 986=>602, 987=>602, - 988=>602, 989=>602, 990=>602, 991=>602, 992=>602, 993=>602, 1008=>602, 1009=>602, 1010=>602, 1011=>602, 1012=>602, 1013=>602, 1014=>602, 1015=>602, 1016=>602, 1017=>602, - 1018=>602, 1019=>602, 1020=>602, 1021=>602, 1022=>602, 1023=>602, 1024=>602, 1025=>602, 1026=>602, 1028=>602, 1029=>602, 1030=>602, 1031=>602, 1032=>602, 1033=>602, 1034=>602, - 1035=>602, 1037=>602, 1038=>602, 1040=>602, 1041=>602, 1042=>602, 1043=>602, 1044=>602, 1045=>602, 1046=>602, 1047=>602, 1048=>602, 1049=>602, 1050=>602, 1051=>602, 1052=>602, - 1053=>602, 1054=>602, 1055=>602, 1056=>602, 1057=>602, 1058=>602, 1059=>602, 1060=>602, 1061=>602, 1062=>602, 1063=>602, 1064=>602, 1065=>602, 1066=>602, 1067=>602, 1068=>602, - 1069=>602, 1070=>602, 1071=>602, 1072=>602, 1073=>602, 1074=>602, 1075=>602, 1076=>602, 1077=>602, 1078=>602, 1079=>602, 1080=>602, 1081=>602, 1082=>602, 1083=>602, 1084=>602, - 1085=>602, 1086=>602, 1087=>602, 1088=>602, 1089=>602, 1090=>602, 1091=>602, 1092=>602, 1093=>602, 1094=>602, 1095=>602, 1096=>602, 1097=>602, 1098=>602, 1099=>602, 1100=>602, - 1101=>602, 1102=>602, 1103=>602, 1104=>602, 1105=>602, 1106=>602, 1107=>602, 1108=>602, 1109=>602, 1110=>602, 1111=>602, 1112=>602, 1113=>602, 1114=>602, 1115=>602, 1117=>602, - 1118=>602, 1119=>602, 1168=>602, 1169=>602, 1170=>602, 1171=>602, 1172=>602, 1173=>602, 1176=>602, 1177=>602, 1178=>602, 1179=>602, 1186=>602, 1187=>602, 1194=>602, 1195=>602, - 1196=>602, 1197=>602, 1198=>602, 1199=>602, 1202=>602, 1203=>602, 1210=>602, 1211=>602, 1216=>602, 1217=>602, 1218=>602, 1219=>602, 1220=>602, 1223=>602, 1224=>602, 1227=>602, - 1228=>602, 1231=>602, 1232=>602, 1233=>602, 1234=>602, 1235=>602, 1236=>602, 1237=>602, 1238=>602, 1239=>602, 1240=>602, 1241=>602, 1242=>602, 1243=>602, 1244=>602, 1245=>602, - 1246=>602, 1247=>602, 1248=>602, 1249=>602, 1250=>602, 1251=>602, 1252=>602, 1253=>602, 1254=>602, 1255=>602, 1256=>602, 1257=>602, 1258=>602, 1259=>602, 1260=>602, 1261=>602, - 1262=>602, 1263=>602, 1264=>602, 1265=>602, 1266=>602, 1267=>602, 1268=>602, 1269=>602, 1270=>602, 1271=>602, 1272=>602, 1273=>602, 3713=>602, 3714=>602, 3716=>602, 3719=>602, - 3720=>602, 3722=>602, 3725=>602, 3732=>602, 3733=>602, 3734=>602, 3735=>602, 3737=>602, 3738=>602, 3739=>602, 3740=>602, 3741=>602, 3742=>602, 3743=>602, 3745=>602, 3746=>602, - 3747=>602, 3749=>602, 3751=>602, 3754=>602, 3755=>602, 3757=>602, 3758=>602, 3759=>602, 7426=>602, 7432=>602, 7433=>602, 7444=>602, 7446=>602, 7447=>602, 7453=>602, 7454=>602, - 7455=>602, 7491=>602, 7492=>602, 7493=>602, 7494=>602, 7495=>602, 7496=>602, 7497=>602, 7498=>602, 7499=>602, 7500=>602, 7501=>602, 7502=>602, 7503=>602, 7504=>602, 7505=>602, - 7506=>602, 7507=>602, 7508=>602, 7509=>602, 7510=>602, 7511=>602, 7512=>602, 7513=>602, 7514=>602, 7515=>602, 7543=>602, 7547=>602, 7557=>602, 7579=>602, 7580=>602, 7581=>602, - 7582=>602, 7583=>602, 7584=>602, 7585=>602, 7586=>602, 7587=>602, 7588=>602, 7589=>602, 7590=>602, 7591=>602, 7592=>602, 7593=>602, 7594=>602, 7595=>602, 7596=>602, 7597=>602, - 7598=>602, 7599=>602, 7600=>602, 7601=>602, 7602=>602, 7603=>602, 7604=>602, 7605=>602, 7606=>602, 7607=>602, 7609=>602, 7610=>602, 7611=>602, 7612=>602, 7613=>602, 7614=>602, - 7615=>602, 7680=>602, 7681=>602, 7682=>602, 7683=>602, 7684=>602, 7685=>602, 7686=>602, 7687=>602, 7690=>602, 7691=>602, 7692=>602, 7693=>602, 7694=>602, 7695=>602, 7698=>602, - 7699=>602, 7704=>602, 7705=>602, 7706=>602, 7707=>602, 7708=>602, 7709=>602, 7710=>602, 7711=>602, 7712=>602, 7713=>602, 7714=>602, 7715=>602, 7716=>602, 7717=>602, 7720=>602, - 7721=>602, 7722=>602, 7723=>602, 7724=>602, 7725=>602, 7728=>602, 7729=>602, 7730=>602, 7731=>602, 7732=>602, 7733=>602, 7734=>602, 7735=>602, 7736=>602, 7737=>602, 7738=>602, - 7739=>602, 7740=>602, 7741=>602, 7742=>602, 7743=>602, 7744=>602, 7745=>602, 7746=>602, 7747=>602, 7748=>602, 7749=>602, 7750=>602, 7751=>602, 7752=>602, 7753=>602, 7754=>602, - 7755=>602, 7766=>602, 7767=>602, 7768=>602, 7769=>602, 7770=>602, 7771=>602, 7772=>602, 7773=>602, 7774=>602, 7775=>602, 7776=>602, 7777=>602, 7778=>602, 7779=>602, 7784=>602, - 7785=>602, 7786=>602, 7787=>602, 7788=>602, 7789=>602, 7790=>602, 7791=>602, 7792=>602, 7793=>602, 7794=>602, 7795=>602, 7796=>602, 7797=>602, 7798=>602, 7799=>602, 7806=>602, - 7807=>602, 7808=>602, 7809=>602, 7810=>602, 7811=>602, 7812=>602, 7813=>602, 7814=>602, 7815=>602, 7816=>602, 7817=>602, 7818=>602, 7819=>602, 7822=>602, 7823=>602, 7826=>602, - 7827=>602, 7828=>602, 7829=>602, 7830=>602, 7835=>602, 7840=>602, 7841=>602, 7864=>602, 7865=>602, 7868=>602, 7869=>602, 7882=>602, 7883=>602, 7884=>602, 7885=>602, 7908=>602, - 7909=>602, 7922=>602, 7923=>602, 7924=>602, 7925=>602, 7928=>602, 7929=>602, 7936=>602, 7937=>602, 7938=>602, 7939=>602, 7940=>602, 7941=>602, 7942=>602, 7943=>602, 7944=>602, - 7945=>602, 7946=>602, 7947=>602, 7948=>602, 7949=>602, 7950=>602, 7951=>602, 7952=>602, 7953=>602, 7954=>602, 7955=>602, 7956=>602, 7957=>602, 7960=>602, 7961=>602, 7962=>602, - 7963=>602, 7964=>602, 7965=>602, 7968=>602, 7969=>602, 7970=>602, 7971=>602, 7972=>602, 7973=>602, 7974=>602, 7975=>602, 7976=>602, 7977=>602, 7978=>602, 7979=>602, 7980=>602, - 7981=>602, 7982=>602, 7983=>602, 7984=>602, 7985=>602, 7986=>602, 7987=>602, 7988=>602, 7989=>602, 7990=>602, 7991=>602, 7992=>602, 7993=>602, 7994=>602, 7995=>602, 7996=>602, - 7997=>602, 7998=>602, 7999=>602, 8000=>602, 8001=>602, 8002=>602, 8003=>602, 8004=>602, 8005=>602, 8008=>602, 8009=>602, 8010=>602, 8011=>602, 8012=>602, 8013=>602, 8016=>602, - 8017=>602, 8018=>602, 8019=>602, 8020=>602, 8021=>602, 8022=>602, 8023=>602, 8025=>602, 8027=>602, 8029=>602, 8031=>602, 8032=>602, 8033=>602, 8034=>602, 8035=>602, 8036=>602, - 8037=>602, 8038=>602, 8039=>602, 8040=>602, 8041=>602, 8042=>602, 8043=>602, 8044=>602, 8045=>602, 8046=>602, 8047=>602, 8048=>602, 8049=>602, 8050=>602, 8051=>602, 8052=>602, - 8053=>602, 8054=>602, 8055=>602, 8056=>602, 8057=>602, 8058=>602, 8059=>602, 8060=>602, 8061=>602, 8064=>602, 8065=>602, 8066=>602, 8067=>602, 8068=>602, 8069=>602, 8070=>602, - 8071=>602, 8072=>602, 8073=>602, 8074=>602, 8075=>602, 8076=>602, 8077=>602, 8078=>602, 8079=>602, 8080=>602, 8081=>602, 8082=>602, 8083=>602, 8084=>602, 8085=>602, 8086=>602, - 8087=>602, 8088=>602, 8089=>602, 8090=>602, 8091=>602, 8092=>602, 8093=>602, 8094=>602, 8095=>602, 8096=>602, 8097=>602, 8098=>602, 8099=>602, 8100=>602, 8101=>602, 8102=>602, - 8103=>602, 8104=>602, 8105=>602, 8106=>602, 8107=>602, 8108=>602, 8109=>602, 8110=>602, 8111=>602, 8112=>602, 8113=>602, 8114=>602, 8115=>602, 8116=>602, 8118=>602, 8119=>602, - 8120=>602, 8121=>602, 8122=>602, 8123=>602, 8124=>602, 8125=>602, 8126=>602, 8127=>602, 8128=>602, 8129=>602, 8130=>602, 8131=>602, 8132=>602, 8134=>602, 8135=>602, 8136=>602, - 8137=>602, 8138=>602, 8139=>602, 8140=>602, 8141=>602, 8142=>602, 8143=>602, 8144=>602, 8145=>602, 8146=>602, 8147=>602, 8150=>602, 8151=>602, 8152=>602, 8153=>602, 8154=>602, - 8155=>602, 8157=>602, 8158=>602, 8159=>602, 8160=>602, 8161=>602, 8162=>602, 8163=>602, 8164=>602, 8165=>602, 8166=>602, 8167=>602, 8168=>602, 8169=>602, 8170=>602, 8171=>602, - 8172=>602, 8173=>602, 8174=>602, 8175=>602, 8178=>602, 8179=>602, 8180=>602, 8182=>602, 8183=>602, 8184=>602, 8185=>602, 8186=>602, 8187=>602, 8188=>602, 8189=>602, 8190=>602, - 8192=>602, 8193=>602, 8194=>602, 8195=>602, 8196=>602, 8197=>602, 8198=>602, 8199=>602, 8200=>602, 8201=>602, 8202=>602, 8208=>602, 8209=>602, 8210=>602, 8213=>602, 8215=>602, - 8219=>602, 8223=>602, 8227=>602, 8239=>602, 8241=>602, 8252=>602, 8253=>602, 8254=>602, 8261=>602, 8262=>602, 8263=>602, 8264=>602, 8265=>602, 8287=>602, 8304=>602, 8308=>602, - 8309=>602, 8310=>602, 8311=>602, 8312=>602, 8313=>602, 8319=>602, 8320=>602, 8321=>602, 8322=>602, 8323=>602, 8324=>602, 8325=>602, 8326=>602, 8327=>602, 8328=>602, 8329=>602, - 8358=>602, 8369=>602, 8372=>602, 8373=>602, 8462=>602, 8470=>602, 8486=>602, 8490=>602, 8491=>602, 8531=>602, 8532=>602, 8533=>602, 8534=>602, 8535=>602, 8536=>602, 8537=>602, - 8538=>602, 8539=>602, 8540=>602, 8541=>602, 8542=>602, 8543=>602, 8592=>602, 8593=>602, 8594=>602, 8595=>602, 8596=>602, 8597=>602, 8598=>602, 8599=>602, 8600=>602, 8601=>602, - 8602=>602, 8603=>602, 8604=>602, 8605=>602, 8606=>602, 8607=>602, 8608=>602, 8609=>602, 8610=>602, 8611=>602, 8612=>602, 8613=>602, 8614=>602, 8615=>602, 8616=>602, 8617=>602, - 8618=>602, 8619=>602, 8620=>602, 8621=>602, 8622=>602, 8623=>602, 8624=>602, 8625=>602, 8626=>602, 8627=>602, 8628=>602, 8629=>602, 8630=>602, 8631=>602, 8632=>602, 8633=>602, - 8634=>602, 8635=>602, 8636=>602, 8637=>602, 8638=>602, 8639=>602, 8640=>602, 8641=>602, 8642=>602, 8643=>602, 8644=>602, 8645=>602, 8646=>602, 8647=>602, 8648=>602, 8649=>602, - 8650=>602, 8651=>602, 8652=>602, 8653=>602, 8654=>602, 8655=>602, 8656=>602, 8657=>602, 8658=>602, 8659=>602, 8660=>602, 8661=>602, 8662=>602, 8663=>602, 8664=>602, 8665=>602, - 8666=>602, 8667=>602, 8668=>602, 8669=>602, 8670=>602, 8671=>602, 8672=>602, 8673=>602, 8674=>602, 8675=>602, 8676=>602, 8677=>602, 8678=>602, 8679=>602, 8680=>602, 8681=>602, - 8682=>602, 8683=>602, 8684=>602, 8685=>602, 8686=>602, 8687=>602, 8688=>602, 8689=>602, 8690=>602, 8691=>602, 8692=>602, 8693=>602, 8694=>602, 8695=>602, 8696=>602, 8697=>602, - 8698=>602, 8699=>602, 8700=>602, 8701=>602, 8702=>602, 8703=>602, 8706=>602, 8709=>602, 8710=>602, 8711=>602, 8712=>602, 8713=>602, 8714=>602, 8715=>602, 8716=>602, 8717=>602, - 8719=>602, 8721=>602, 8722=>602, 8723=>602, 8725=>602, 8727=>602, 8728=>602, 8729=>602, 8730=>602, 8733=>602, 8734=>602, 8735=>602, 8736=>602, 8743=>602, 8744=>602, 8745=>602, - 8746=>602, 8747=>602, 8748=>602, 8749=>602, 8760=>602, 8761=>602, 8762=>602, 8763=>602, 8764=>602, 8765=>602, 8769=>602, 8770=>602, 8771=>602, 8772=>602, 8773=>602, 8774=>602, - 8775=>602, 8776=>602, 8777=>602, 8778=>602, 8779=>602, 8780=>602, 8781=>602, 8782=>602, 8783=>602, 8784=>602, 8785=>602, 8786=>602, 8787=>602, 8788=>602, 8789=>602, 8790=>602, - 8791=>602, 8792=>602, 8793=>602, 8794=>602, 8795=>602, 8796=>602, 8797=>602, 8798=>602, 8799=>602, 8800=>602, 8801=>602, 8802=>602, 8803=>602, 8804=>602, 8805=>602, 8806=>602, - 8807=>602, 8808=>602, 8809=>602, 8813=>602, 8814=>602, 8815=>602, 8816=>602, 8817=>602, 8818=>602, 8819=>602, 8820=>602, 8821=>602, 8822=>602, 8823=>602, 8824=>602, 8825=>602, - 8826=>602, 8827=>602, 8828=>602, 8829=>602, 8830=>602, 8831=>602, 8832=>602, 8833=>602, 8834=>602, 8835=>602, 8836=>602, 8837=>602, 8838=>602, 8839=>602, 8840=>602, 8841=>602, - 8842=>602, 8843=>602, 8847=>602, 8848=>602, 8849=>602, 8850=>602, 8853=>602, 8854=>602, 8855=>602, 8856=>602, 8857=>602, 8858=>602, 8859=>602, 8860=>602, 8861=>602, 8862=>602, - 8863=>602, 8864=>602, 8865=>602, 8901=>602, 8902=>602, 8909=>602, 8922=>602, 8923=>602, 8924=>602, 8925=>602, 8926=>602, 8927=>602, 8928=>602, 8929=>602, 8930=>602, 8931=>602, - 8932=>602, 8933=>602, 8934=>602, 8935=>602, 8936=>602, 8937=>602, 8943=>602, 8960=>602, 8961=>602, 8962=>602, 8963=>602, 8964=>602, 8965=>602, 8966=>602, 8968=>602, 8969=>602, - 8970=>602, 8971=>602, 8972=>602, 8973=>602, 8974=>602, 8975=>602, 8976=>602, 8977=>602, 8978=>602, 8979=>602, 8980=>602, 8981=>602, 8984=>602, 8985=>602, 8988=>602, 8989=>602, - 8990=>602, 8991=>602, 8992=>602, 8993=>602, 8997=>602, 8998=>602, 8999=>602, 9000=>602, 9003=>602, 9013=>602, 9015=>602, 9016=>602, 9017=>602, 9018=>602, 9019=>602, 9020=>602, - 9021=>602, 9022=>602, 9025=>602, 9026=>602, 9027=>602, 9028=>602, 9031=>602, 9032=>602, 9033=>602, 9035=>602, 9036=>602, 9037=>602, 9040=>602, 9042=>602, 9043=>602, 9044=>602, - 9047=>602, 9048=>602, 9049=>602, 9050=>602, 9051=>602, 9052=>602, 9054=>602, 9055=>602, 9056=>602, 9059=>602, 9060=>602, 9061=>602, 9064=>602, 9065=>602, 9067=>602, 9068=>602, - 9069=>602, 9070=>602, 9071=>602, 9072=>602, 9075=>602, 9076=>602, 9077=>602, 9078=>602, 9079=>602, 9080=>602, 9081=>602, 9082=>602, 9085=>602, 9088=>602, 9089=>602, 9090=>602, - 9091=>602, 9096=>602, 9097=>602, 9098=>602, 9099=>602, 9109=>602, 9115=>602, 9116=>602, 9117=>602, 9118=>602, 9119=>602, 9120=>602, 9121=>602, 9122=>602, 9123=>602, 9124=>602, - 9125=>602, 9126=>602, 9127=>602, 9128=>602, 9129=>602, 9130=>602, 9131=>602, 9132=>602, 9133=>602, 9134=>602, 9166=>602, 9167=>602, 9251=>602, 9600=>602, 9601=>602, 9602=>602, - 9603=>602, 9604=>602, 9605=>602, 9606=>602, 9607=>602, 9608=>602, 9609=>602, 9610=>602, 9611=>602, 9612=>602, 9613=>602, 9614=>602, 9615=>602, 9616=>602, 9617=>602, 9618=>602, - 9619=>602, 9620=>602, 9621=>602, 9622=>602, 9623=>602, 9624=>602, 9625=>602, 9626=>602, 9627=>602, 9628=>602, 9629=>602, 9630=>602, 9631=>602, 9632=>602, 9633=>602, 9634=>602, - 9635=>602, 9636=>602, 9637=>602, 9638=>602, 9639=>602, 9640=>602, 9641=>602, 9642=>602, 9643=>602, 9644=>602, 9645=>602, 9646=>602, 9647=>602, 9648=>602, 9649=>602, 9650=>602, - 9651=>602, 9652=>602, 9653=>602, 9654=>602, 9655=>602, 9656=>602, 9657=>602, 9658=>602, 9659=>602, 9660=>602, 9661=>602, 9662=>602, 9663=>602, 9664=>602, 9665=>602, 9666=>602, - 9667=>602, 9668=>602, 9669=>602, 9670=>602, 9671=>602, 9672=>602, 9673=>602, 9674=>602, 9675=>602, 9676=>602, 9677=>602, 9678=>602, 9679=>602, 9680=>602, 9681=>602, 9682=>602, - 9683=>602, 9684=>602, 9685=>602, 9686=>602, 9687=>602, 9688=>602, 9689=>602, 9690=>602, 9691=>602, 9692=>602, 9693=>602, 9694=>602, 9695=>602, 9696=>602, 9697=>602, 9698=>602, - 9699=>602, 9700=>602, 9701=>602, 9702=>602, 9703=>602, 9704=>602, 9705=>602, 9706=>602, 9707=>602, 9708=>602, 9709=>602, 9710=>602, 9711=>602, 9712=>602, 9713=>602, 9714=>602, - 9715=>602, 9716=>602, 9717=>602, 9718=>602, 9719=>602, 9720=>602, 9721=>602, 9722=>602, 9723=>602, 9724=>602, 9725=>602, 9726=>602, 9727=>602, 9728=>602, 9784=>602, 9785=>602, - 9786=>602, 9787=>602, 9788=>602, 9791=>602, 9792=>602, 9793=>602, 9794=>602, 9795=>602, 9796=>602, 9797=>602, 9798=>602, 9799=>602, 9824=>602, 9825=>602, 9826=>602, 9827=>602, - 9828=>602, 9829=>602, 9830=>602, 9831=>602, 9833=>602, 9834=>602, 9835=>602, 9836=>602, 9837=>602, 9838=>602, 9839=>602, 10208=>602, 10216=>602, 10217=>602, 10731=>602, 11026=>602, - 11027=>602, 11028=>602, 11029=>602, 11030=>602, 11031=>602, 11032=>602, 11033=>602, 11034=>602, 63173=>602, 64257=>602, 64258=>602, 65533=>602}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansMono-BoldOblique.z'; - font[:ctg]='DejaVuSansMono-BoldOblique.ctg.z'; - font[:originalsize]=195388; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansMonoi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansMonoi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansMonoi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSansMono-Oblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>97,'FontBBox'=>'[-311 -375 746 1058]','ItalicAngle'=>-11,'StemV'=>70,'MissingWidth'=>602}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 1027=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 1036=>602, 381=>602, 1039=>602, - 8216=>602, 8217=>602, 8220=>602, 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 1116=>602, 382=>602, 376=>602, 160=>602, - 161=>602, 162=>602, 163=>602, 164=>602, 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, - 177=>602, 178=>602, 179=>602, 180=>602, 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, - 193=>602, 194=>602, 195=>602, 196=>602, 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, - 209=>602, 210=>602, 211=>602, 212=>602, 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, - 225=>602, 226=>602, 227=>602, 228=>602, 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, - 241=>602, 242=>602, 243=>602, 244=>602, 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 256=>602, - 257=>602, 258=>602, 259=>602, 260=>602, 261=>602, 262=>602, 263=>602, 264=>602, 265=>602, 266=>602, 267=>602, 268=>602, 269=>602, 270=>602, 271=>602, 272=>602, - 273=>602, 274=>602, 275=>602, 276=>602, 277=>602, 278=>602, 279=>602, 280=>602, 281=>602, 282=>602, 283=>602, 284=>602, 285=>602, 286=>602, 287=>602, 288=>602, - 289=>602, 290=>602, 291=>602, 292=>602, 293=>602, 294=>602, 295=>602, 296=>602, 297=>602, 298=>602, 299=>602, 300=>602, 301=>602, 302=>602, 303=>602, 304=>602, - 305=>602, 306=>602, 307=>602, 308=>602, 309=>602, 310=>602, 311=>602, 312=>602, 313=>602, 314=>602, 315=>602, 316=>602, 317=>602, 318=>602, 319=>602, 320=>602, - 321=>602, 322=>602, 323=>602, 324=>602, 325=>602, 326=>602, 327=>602, 328=>602, 329=>602, 330=>602, 331=>602, 332=>602, 333=>602, 334=>602, 335=>602, 336=>602, - 337=>602, 340=>602, 341=>602, 342=>602, 343=>602, 344=>602, 345=>602, 346=>602, 347=>602, 348=>602, 349=>602, 350=>602, 351=>602, 354=>602, 355=>602, 356=>602, - 357=>602, 358=>602, 359=>602, 360=>602, 361=>602, 362=>602, 363=>602, 364=>602, 365=>602, 366=>602, 367=>602, 368=>602, 369=>602, 370=>602, 371=>602, 372=>602, - 373=>602, 374=>602, 375=>602, 377=>602, 378=>602, 379=>602, 380=>602, 383=>602, 385=>602, 386=>602, 387=>602, 388=>602, 389=>602, 390=>602, 391=>602, 392=>602, - 393=>602, 394=>602, 395=>602, 396=>602, 397=>602, 398=>602, 399=>602, 400=>602, 401=>602, 403=>602, 404=>602, 405=>602, 406=>602, 407=>602, 408=>602, 409=>602, - 410=>602, 411=>602, 412=>602, 413=>602, 414=>602, 415=>602, 416=>602, 417=>602, 418=>602, 419=>602, 420=>602, 421=>602, 422=>602, 423=>602, 424=>602, 425=>602, - 426=>602, 427=>602, 428=>602, 429=>602, 430=>602, 431=>602, 432=>602, 433=>602, 434=>602, 435=>602, 436=>602, 437=>602, 438=>602, 439=>602, 440=>602, 441=>602, - 443=>602, 444=>602, 445=>602, 446=>602, 448=>602, 449=>602, 450=>602, 451=>602, 461=>602, 462=>602, 463=>602, 464=>602, 465=>602, 466=>602, 467=>602, 468=>602, - 470=>602, 471=>602, 472=>602, 473=>602, 474=>602, 475=>602, 476=>602, 477=>602, 479=>602, 482=>602, 483=>602, 486=>602, 487=>602, 488=>602, 489=>602, 490=>602, - 491=>602, 492=>602, 493=>602, 494=>602, 495=>602, 500=>602, 501=>602, 502=>602, 504=>602, 505=>602, 508=>602, 509=>602, 510=>602, 511=>602, 512=>602, 513=>602, - 514=>602, 515=>602, 516=>602, 517=>602, 518=>602, 519=>602, 520=>602, 521=>602, 522=>602, 523=>602, 524=>602, 525=>602, 526=>602, 527=>602, 528=>602, 529=>602, - 530=>602, 531=>602, 532=>602, 533=>602, 534=>602, 535=>602, 536=>602, 537=>602, 538=>602, 539=>602, 542=>602, 543=>602, 545=>602, 548=>602, 549=>602, 550=>602, - 551=>602, 552=>602, 553=>602, 555=>602, 557=>602, 558=>602, 559=>602, 561=>602, 562=>602, 563=>602, 564=>602, 565=>602, 566=>602, 567=>602, 568=>602, 569=>602, - 570=>602, 571=>602, 572=>602, 573=>602, 574=>602, 575=>602, 576=>602, 577=>602, 581=>602, 592=>602, 593=>602, 594=>602, 595=>602, 596=>602, 597=>602, 598=>602, - 599=>602, 600=>602, 601=>602, 602=>602, 603=>602, 604=>602, 605=>602, 606=>602, 607=>602, 608=>602, 609=>602, 610=>602, 611=>602, 612=>602, 613=>602, 614=>602, - 615=>602, 616=>602, 617=>602, 618=>602, 619=>602, 620=>602, 621=>602, 622=>602, 623=>602, 624=>602, 625=>602, 626=>602, 627=>602, 628=>602, 629=>602, 630=>602, - 631=>602, 632=>602, 633=>602, 634=>602, 635=>602, 636=>602, 637=>602, 638=>602, 639=>602, 640=>602, 641=>602, 642=>602, 643=>602, 644=>602, 645=>602, 646=>602, - 647=>602, 648=>602, 649=>602, 650=>602, 651=>602, 652=>602, 653=>602, 654=>602, 655=>602, 656=>602, 657=>602, 658=>602, 659=>602, 660=>602, 661=>602, 662=>602, - 663=>602, 664=>602, 665=>602, 666=>602, 667=>602, 668=>602, 669=>602, 670=>602, 671=>602, 672=>602, 673=>602, 674=>602, 675=>602, 676=>602, 677=>602, 678=>602, - 679=>602, 680=>602, 681=>602, 682=>602, 683=>602, 684=>602, 685=>602, 686=>602, 687=>602, 688=>602, 689=>602, 690=>602, 691=>602, 692=>602, 693=>602, 694=>602, - 695=>602, 696=>602, 697=>602, 699=>602, 700=>602, 701=>602, 702=>602, 703=>602, 704=>602, 705=>602, 711=>602, 712=>602, 713=>602, 716=>602, 717=>602, 720=>602, - 721=>602, 722=>602, 723=>602, 726=>602, 728=>602, 729=>602, 730=>602, 731=>602, 733=>602, 734=>602, 736=>602, 737=>602, 738=>602, 739=>602, 740=>602, 741=>602, - 742=>602, 743=>602, 744=>602, 745=>602, 755=>602, 768=>602, 769=>602, 770=>602, 771=>602, 772=>602, 773=>602, 774=>602, 775=>602, 776=>602, 777=>602, 778=>602, - 779=>602, 780=>602, 781=>602, 782=>602, 783=>602, 784=>602, 785=>602, 786=>602, 787=>602, 788=>602, 789=>602, 790=>602, 791=>602, 792=>602, 793=>602, 794=>602, - 795=>602, 796=>602, 797=>602, 798=>602, 799=>602, 800=>602, 801=>602, 802=>602, 803=>602, 804=>602, 805=>602, 806=>602, 807=>602, 808=>602, 809=>602, 810=>602, - 811=>602, 812=>602, 813=>602, 814=>602, 815=>602, 816=>602, 817=>602, 818=>602, 819=>602, 820=>602, 821=>602, 822=>602, 823=>602, 824=>602, 825=>602, 826=>602, - 827=>602, 828=>602, 829=>602, 830=>602, 831=>602, 835=>602, 856=>602, 865=>602, 884=>602, 885=>602, 890=>602, 894=>602, 900=>602, 901=>602, 902=>602, 903=>602, - 904=>602, 905=>602, 906=>602, 908=>602, 910=>602, 911=>602, 912=>602, 913=>602, 914=>602, 915=>602, 916=>602, 917=>602, 918=>602, 919=>602, 920=>602, 921=>602, - 922=>602, 923=>602, 924=>602, 925=>602, 926=>602, 927=>602, 928=>602, 929=>602, 931=>602, 932=>602, 933=>602, 934=>602, 935=>602, 936=>602, 937=>602, 938=>602, - 939=>602, 940=>602, 941=>602, 942=>602, 943=>602, 944=>602, 945=>602, 946=>602, 947=>602, 948=>602, 949=>602, 950=>602, 951=>602, 952=>602, 953=>602, 954=>602, - 955=>602, 956=>602, 957=>602, 958=>602, 959=>602, 960=>602, 961=>602, 962=>602, 963=>602, 964=>602, 965=>602, 966=>602, 967=>602, 968=>602, 969=>602, 970=>602, - 971=>602, 972=>602, 973=>602, 974=>602, 976=>602, 977=>602, 978=>602, 979=>602, 980=>602, 981=>602, 982=>602, 983=>602, 984=>602, 985=>602, 986=>602, 987=>602, - 988=>602, 989=>602, 990=>602, 991=>602, 992=>602, 993=>602, 1008=>602, 1009=>602, 1010=>602, 1011=>602, 1012=>602, 1013=>602, 1014=>602, 1015=>602, 1016=>602, 1017=>602, - 1018=>602, 1019=>602, 1020=>602, 1021=>602, 1022=>602, 1023=>602, 1024=>602, 1025=>602, 1026=>602, 1028=>602, 1029=>602, 1030=>602, 1031=>602, 1032=>602, 1033=>602, 1034=>602, - 1035=>602, 1037=>602, 1038=>602, 1040=>602, 1041=>602, 1042=>602, 1043=>602, 1044=>602, 1045=>602, 1046=>602, 1047=>602, 1048=>602, 1049=>602, 1050=>602, 1051=>602, 1052=>602, - 1053=>602, 1054=>602, 1055=>602, 1056=>602, 1057=>602, 1058=>602, 1059=>602, 1060=>602, 1061=>602, 1062=>602, 1063=>602, 1064=>602, 1065=>602, 1066=>602, 1067=>602, 1068=>602, - 1069=>602, 1070=>602, 1071=>602, 1072=>602, 1073=>602, 1074=>602, 1075=>602, 1076=>602, 1077=>602, 1078=>602, 1079=>602, 1080=>602, 1081=>602, 1082=>602, 1083=>602, 1084=>602, - 1085=>602, 1086=>602, 1087=>602, 1088=>602, 1089=>602, 1090=>602, 1091=>602, 1092=>602, 1093=>602, 1094=>602, 1095=>602, 1096=>602, 1097=>602, 1098=>602, 1099=>602, 1100=>602, - 1101=>602, 1102=>602, 1103=>602, 1104=>602, 1105=>602, 1106=>602, 1107=>602, 1108=>602, 1109=>602, 1110=>602, 1111=>602, 1112=>602, 1113=>602, 1114=>602, 1115=>602, 1117=>602, - 1118=>602, 1119=>602, 1168=>602, 1169=>602, 1170=>602, 1171=>602, 1172=>602, 1173=>602, 1176=>602, 1177=>602, 1178=>602, 1179=>602, 1186=>602, 1187=>602, 1194=>602, 1195=>602, - 1196=>602, 1197=>602, 1198=>602, 1199=>602, 1202=>602, 1203=>602, 1210=>602, 1211=>602, 1216=>602, 1217=>602, 1218=>602, 1219=>602, 1220=>602, 1223=>602, 1224=>602, 1227=>602, - 1228=>602, 1231=>602, 1232=>602, 1233=>602, 1234=>602, 1235=>602, 1236=>602, 1237=>602, 1238=>602, 1239=>602, 1240=>602, 1241=>602, 1242=>602, 1243=>602, 1244=>602, 1245=>602, - 1246=>602, 1247=>602, 1248=>602, 1249=>602, 1250=>602, 1251=>602, 1252=>602, 1253=>602, 1254=>602, 1255=>602, 1256=>602, 1257=>602, 1258=>602, 1259=>602, 1260=>602, 1261=>602, - 1262=>602, 1263=>602, 1264=>602, 1265=>602, 1266=>602, 1267=>602, 1268=>602, 1269=>602, 1270=>602, 1271=>602, 1272=>602, 1273=>602, 3713=>602, 3714=>602, 3716=>602, 3719=>602, - 3720=>602, 3722=>602, 3725=>602, 3732=>602, 3733=>602, 3734=>602, 3735=>602, 3737=>602, 3738=>602, 3739=>602, 3740=>602, 3741=>602, 3742=>602, 3743=>602, 3745=>602, 3746=>602, - 3747=>602, 3749=>602, 3751=>602, 3754=>602, 3755=>602, 3757=>602, 3758=>602, 3759=>602, 7426=>602, 7432=>602, 7433=>602, 7444=>602, 7446=>602, 7447=>602, 7453=>602, 7454=>602, - 7455=>602, 7491=>602, 7492=>602, 7493=>602, 7494=>602, 7495=>602, 7496=>602, 7497=>602, 7498=>602, 7499=>602, 7500=>602, 7501=>602, 7502=>602, 7503=>602, 7504=>602, 7505=>602, - 7506=>602, 7507=>602, 7508=>602, 7509=>602, 7510=>602, 7511=>602, 7512=>602, 7513=>602, 7514=>602, 7515=>602, 7543=>602, 7547=>602, 7557=>602, 7579=>602, 7580=>602, 7581=>602, - 7582=>602, 7583=>602, 7584=>602, 7585=>602, 7586=>602, 7587=>602, 7588=>602, 7589=>602, 7590=>602, 7591=>602, 7592=>602, 7593=>602, 7594=>602, 7595=>602, 7596=>602, 7597=>602, - 7598=>602, 7599=>602, 7600=>602, 7601=>602, 7602=>602, 7603=>602, 7604=>602, 7605=>602, 7606=>602, 7607=>602, 7609=>602, 7610=>602, 7611=>602, 7612=>602, 7613=>602, 7614=>602, - 7615=>602, 7680=>602, 7681=>602, 7682=>602, 7683=>602, 7684=>602, 7685=>602, 7686=>602, 7687=>602, 7690=>602, 7691=>602, 7692=>602, 7693=>602, 7694=>602, 7695=>602, 7698=>602, - 7699=>602, 7704=>602, 7705=>602, 7706=>602, 7707=>602, 7708=>602, 7709=>602, 7710=>602, 7711=>602, 7712=>602, 7713=>602, 7714=>602, 7715=>602, 7716=>602, 7717=>602, 7720=>602, - 7721=>602, 7722=>602, 7723=>602, 7724=>602, 7725=>602, 7728=>602, 7729=>602, 7730=>602, 7731=>602, 7732=>602, 7733=>602, 7734=>602, 7735=>602, 7736=>602, 7737=>602, 7738=>602, - 7739=>602, 7740=>602, 7741=>602, 7742=>602, 7743=>602, 7744=>602, 7745=>602, 7746=>602, 7747=>602, 7748=>602, 7749=>602, 7750=>602, 7751=>602, 7752=>602, 7753=>602, 7754=>602, - 7755=>602, 7766=>602, 7767=>602, 7768=>602, 7769=>602, 7770=>602, 7771=>602, 7772=>602, 7773=>602, 7774=>602, 7775=>602, 7776=>602, 7777=>602, 7778=>602, 7779=>602, 7784=>602, - 7785=>602, 7786=>602, 7787=>602, 7788=>602, 7789=>602, 7790=>602, 7791=>602, 7792=>602, 7793=>602, 7794=>602, 7795=>602, 7796=>602, 7797=>602, 7798=>602, 7799=>602, 7806=>602, - 7807=>602, 7808=>602, 7809=>602, 7810=>602, 7811=>602, 7812=>602, 7813=>602, 7814=>602, 7815=>602, 7816=>602, 7817=>602, 7818=>602, 7819=>602, 7822=>602, 7823=>602, 7826=>602, - 7827=>602, 7828=>602, 7829=>602, 7830=>602, 7835=>602, 7840=>602, 7841=>602, 7864=>602, 7865=>602, 7868=>602, 7869=>602, 7882=>602, 7883=>602, 7884=>602, 7885=>602, 7908=>602, - 7909=>602, 7922=>602, 7923=>602, 7924=>602, 7925=>602, 7928=>602, 7929=>602, 7936=>602, 7937=>602, 7938=>602, 7939=>602, 7940=>602, 7941=>602, 7942=>602, 7943=>602, 7944=>602, - 7945=>602, 7946=>602, 7947=>602, 7948=>602, 7949=>602, 7950=>602, 7951=>602, 7952=>602, 7953=>602, 7954=>602, 7955=>602, 7956=>602, 7957=>602, 7960=>602, 7961=>602, 7962=>602, - 7963=>602, 7964=>602, 7965=>602, 7968=>602, 7969=>602, 7970=>602, 7971=>602, 7972=>602, 7973=>602, 7974=>602, 7975=>602, 7976=>602, 7977=>602, 7978=>602, 7979=>602, 7980=>602, - 7981=>602, 7982=>602, 7983=>602, 7984=>602, 7985=>602, 7986=>602, 7987=>602, 7988=>602, 7989=>602, 7990=>602, 7991=>602, 7992=>602, 7993=>602, 7994=>602, 7995=>602, 7996=>602, - 7997=>602, 7998=>602, 7999=>602, 8000=>602, 8001=>602, 8002=>602, 8003=>602, 8004=>602, 8005=>602, 8008=>602, 8009=>602, 8010=>602, 8011=>602, 8012=>602, 8013=>602, 8016=>602, - 8017=>602, 8018=>602, 8019=>602, 8020=>602, 8021=>602, 8022=>602, 8023=>602, 8025=>602, 8027=>602, 8029=>602, 8031=>602, 8032=>602, 8033=>602, 8034=>602, 8035=>602, 8036=>602, - 8037=>602, 8038=>602, 8039=>602, 8040=>602, 8041=>602, 8042=>602, 8043=>602, 8044=>602, 8045=>602, 8046=>602, 8047=>602, 8048=>602, 8049=>602, 8050=>602, 8051=>602, 8052=>602, - 8053=>602, 8054=>602, 8055=>602, 8056=>602, 8057=>602, 8058=>602, 8059=>602, 8060=>602, 8061=>602, 8064=>602, 8065=>602, 8066=>602, 8067=>602, 8068=>602, 8069=>602, 8070=>602, - 8071=>602, 8072=>602, 8073=>602, 8074=>602, 8075=>602, 8076=>602, 8077=>602, 8078=>602, 8079=>602, 8080=>602, 8081=>602, 8082=>602, 8083=>602, 8084=>602, 8085=>602, 8086=>602, - 8087=>602, 8088=>602, 8089=>602, 8090=>602, 8091=>602, 8092=>602, 8093=>602, 8094=>602, 8095=>602, 8096=>602, 8097=>602, 8098=>602, 8099=>602, 8100=>602, 8101=>602, 8102=>602, - 8103=>602, 8104=>602, 8105=>602, 8106=>602, 8107=>602, 8108=>602, 8109=>602, 8110=>602, 8111=>602, 8112=>602, 8113=>602, 8114=>602, 8115=>602, 8116=>602, 8118=>602, 8119=>602, - 8120=>602, 8121=>602, 8122=>602, 8123=>602, 8124=>602, 8125=>602, 8126=>602, 8127=>602, 8128=>602, 8129=>602, 8130=>602, 8131=>602, 8132=>602, 8134=>602, 8135=>602, 8136=>602, - 8137=>602, 8138=>602, 8139=>602, 8140=>602, 8141=>602, 8142=>602, 8143=>602, 8144=>602, 8145=>602, 8146=>602, 8147=>602, 8150=>602, 8151=>602, 8152=>602, 8153=>602, 8154=>602, - 8155=>602, 8157=>602, 8158=>602, 8159=>602, 8160=>602, 8161=>602, 8162=>602, 8163=>602, 8164=>602, 8165=>602, 8166=>602, 8167=>602, 8168=>602, 8169=>602, 8170=>602, 8171=>602, - 8172=>602, 8173=>602, 8174=>602, 8175=>602, 8178=>602, 8179=>602, 8180=>602, 8182=>602, 8183=>602, 8184=>602, 8185=>602, 8186=>602, 8187=>602, 8188=>602, 8189=>602, 8190=>602, - 8192=>602, 8193=>602, 8194=>602, 8195=>602, 8196=>602, 8197=>602, 8198=>602, 8199=>602, 8200=>602, 8201=>602, 8202=>602, 8208=>602, 8209=>602, 8210=>602, 8213=>602, 8215=>602, - 8219=>602, 8223=>602, 8227=>602, 8239=>602, 8241=>602, 8252=>602, 8253=>602, 8254=>602, 8261=>602, 8262=>602, 8263=>602, 8264=>602, 8265=>602, 8287=>602, 8304=>602, 8308=>602, - 8309=>602, 8310=>602, 8311=>602, 8312=>602, 8313=>602, 8319=>602, 8320=>602, 8321=>602, 8322=>602, 8323=>602, 8324=>602, 8325=>602, 8326=>602, 8327=>602, 8328=>602, 8329=>602, - 8358=>602, 8369=>602, 8372=>602, 8373=>602, 8462=>602, 8470=>602, 8486=>602, 8490=>602, 8491=>602, 8531=>602, 8532=>602, 8533=>602, 8534=>602, 8535=>602, 8536=>602, 8537=>602, - 8538=>602, 8539=>602, 8540=>602, 8541=>602, 8542=>602, 8543=>602, 8592=>602, 8593=>602, 8594=>602, 8595=>602, 8596=>602, 8597=>602, 8598=>602, 8599=>602, 8600=>602, 8601=>602, - 8602=>602, 8603=>602, 8604=>602, 8605=>602, 8606=>602, 8607=>602, 8608=>602, 8609=>602, 8610=>602, 8611=>602, 8612=>602, 8613=>602, 8614=>602, 8615=>602, 8616=>602, 8617=>602, - 8618=>602, 8619=>602, 8620=>602, 8621=>602, 8622=>602, 8623=>602, 8624=>602, 8625=>602, 8626=>602, 8627=>602, 8628=>602, 8629=>602, 8630=>602, 8631=>602, 8632=>602, 8633=>602, - 8634=>602, 8635=>602, 8636=>602, 8637=>602, 8638=>602, 8639=>602, 8640=>602, 8641=>602, 8642=>602, 8643=>602, 8644=>602, 8645=>602, 8646=>602, 8647=>602, 8648=>602, 8649=>602, - 8650=>602, 8651=>602, 8652=>602, 8653=>602, 8654=>602, 8655=>602, 8656=>602, 8657=>602, 8658=>602, 8659=>602, 8660=>602, 8661=>602, 8662=>602, 8663=>602, 8664=>602, 8665=>602, - 8666=>602, 8667=>602, 8668=>602, 8669=>602, 8670=>602, 8671=>602, 8672=>602, 8673=>602, 8674=>602, 8675=>602, 8676=>602, 8677=>602, 8678=>602, 8679=>602, 8680=>602, 8681=>602, - 8682=>602, 8683=>602, 8684=>602, 8685=>602, 8686=>602, 8687=>602, 8688=>602, 8689=>602, 8690=>602, 8691=>602, 8692=>602, 8693=>602, 8694=>602, 8695=>602, 8696=>602, 8697=>602, - 8698=>602, 8699=>602, 8700=>602, 8701=>602, 8702=>602, 8703=>602, 8706=>602, 8709=>602, 8710=>602, 8711=>602, 8712=>602, 8713=>602, 8714=>602, 8715=>602, 8716=>602, 8717=>602, - 8719=>602, 8721=>602, 8722=>602, 8723=>602, 8725=>602, 8727=>602, 8728=>602, 8729=>602, 8730=>602, 8733=>602, 8734=>602, 8735=>602, 8736=>602, 8743=>602, 8744=>602, 8745=>602, - 8746=>602, 8747=>602, 8748=>602, 8749=>602, 8760=>602, 8761=>602, 8762=>602, 8763=>602, 8764=>602, 8765=>602, 8769=>602, 8770=>602, 8771=>602, 8772=>602, 8773=>602, 8774=>602, - 8775=>602, 8776=>602, 8777=>602, 8778=>602, 8779=>602, 8780=>602, 8781=>602, 8782=>602, 8783=>602, 8784=>602, 8785=>602, 8786=>602, 8787=>602, 8788=>602, 8789=>602, 8790=>602, - 8791=>602, 8792=>602, 8793=>602, 8794=>602, 8795=>602, 8796=>602, 8797=>602, 8798=>602, 8799=>602, 8800=>602, 8801=>602, 8802=>602, 8803=>602, 8804=>602, 8805=>602, 8806=>602, - 8807=>602, 8808=>602, 8809=>602, 8813=>602, 8814=>602, 8815=>602, 8816=>602, 8817=>602, 8818=>602, 8819=>602, 8820=>602, 8821=>602, 8822=>602, 8823=>602, 8824=>602, 8825=>602, - 8826=>602, 8827=>602, 8828=>602, 8829=>602, 8830=>602, 8831=>602, 8832=>602, 8833=>602, 8834=>602, 8835=>602, 8836=>602, 8837=>602, 8838=>602, 8839=>602, 8840=>602, 8841=>602, - 8842=>602, 8843=>602, 8847=>602, 8848=>602, 8849=>602, 8850=>602, 8853=>602, 8854=>602, 8855=>602, 8856=>602, 8857=>602, 8858=>602, 8859=>602, 8860=>602, 8861=>602, 8862=>602, - 8863=>602, 8864=>602, 8865=>602, 8901=>602, 8902=>602, 8909=>602, 8922=>602, 8923=>602, 8924=>602, 8925=>602, 8926=>602, 8927=>602, 8928=>602, 8929=>602, 8930=>602, 8931=>602, - 8932=>602, 8933=>602, 8934=>602, 8935=>602, 8936=>602, 8937=>602, 8943=>602, 8960=>602, 8961=>602, 8962=>602, 8963=>602, 8964=>602, 8965=>602, 8966=>602, 8968=>602, 8969=>602, - 8970=>602, 8971=>602, 8972=>602, 8973=>602, 8974=>602, 8975=>602, 8976=>602, 8977=>602, 8978=>602, 8979=>602, 8980=>602, 8981=>602, 8984=>602, 8985=>602, 8988=>602, 8989=>602, - 8990=>602, 8991=>602, 8992=>602, 8993=>602, 8997=>602, 8998=>602, 8999=>602, 9000=>602, 9003=>602, 9013=>602, 9015=>602, 9016=>602, 9017=>602, 9018=>602, 9019=>602, 9020=>602, - 9021=>602, 9022=>602, 9025=>602, 9026=>602, 9027=>602, 9028=>602, 9031=>602, 9032=>602, 9033=>602, 9035=>602, 9036=>602, 9037=>602, 9040=>602, 9042=>602, 9043=>602, 9044=>602, - 9047=>602, 9048=>602, 9049=>602, 9050=>602, 9051=>602, 9052=>602, 9054=>602, 9055=>602, 9056=>602, 9059=>602, 9060=>602, 9061=>602, 9064=>602, 9065=>602, 9067=>602, 9068=>602, - 9069=>602, 9070=>602, 9071=>602, 9072=>602, 9075=>602, 9076=>602, 9077=>602, 9078=>602, 9079=>602, 9080=>602, 9081=>602, 9082=>602, 9085=>602, 9088=>602, 9089=>602, 9090=>602, - 9091=>602, 9096=>602, 9097=>602, 9098=>602, 9099=>602, 9109=>602, 9115=>602, 9116=>602, 9117=>602, 9118=>602, 9119=>602, 9120=>602, 9121=>602, 9122=>602, 9123=>602, 9124=>602, - 9125=>602, 9126=>602, 9127=>602, 9128=>602, 9129=>602, 9130=>602, 9131=>602, 9132=>602, 9133=>602, 9134=>602, 9166=>602, 9167=>602, 9251=>602, 9472=>602, 9473=>602, 9474=>602, - 9475=>602, 9476=>602, 9477=>602, 9478=>602, 9479=>602, 9480=>602, 9481=>602, 9482=>602, 9483=>602, 9484=>602, 9485=>602, 9486=>602, 9487=>602, 9488=>602, 9489=>602, 9490=>602, - 9491=>602, 9492=>602, 9493=>602, 9494=>602, 9495=>602, 9496=>602, 9497=>602, 9498=>602, 9499=>602, 9500=>602, 9501=>602, 9502=>602, 9503=>602, 9504=>602, 9505=>602, 9506=>602, - 9507=>602, 9508=>602, 9509=>602, 9510=>602, 9511=>602, 9512=>602, 9513=>602, 9514=>602, 9515=>602, 9516=>602, 9517=>602, 9518=>602, 9519=>602, 9520=>602, 9521=>602, 9522=>602, - 9523=>602, 9524=>602, 9525=>602, 9526=>602, 9527=>602, 9528=>602, 9529=>602, 9530=>602, 9531=>602, 9532=>602, 9533=>602, 9534=>602, 9535=>602, 9536=>602, 9537=>602, 9538=>602, - 9539=>602, 9540=>602, 9541=>602, 9542=>602, 9543=>602, 9544=>602, 9545=>602, 9546=>602, 9547=>602, 9548=>602, 9549=>602, 9550=>602, 9551=>602, 9552=>602, 9553=>602, 9554=>602, - 9555=>602, 9556=>602, 9557=>602, 9558=>602, 9559=>602, 9560=>602, 9561=>602, 9562=>602, 9563=>602, 9564=>602, 9565=>602, 9566=>602, 9567=>602, 9568=>602, 9569=>602, 9570=>602, - 9571=>602, 9572=>602, 9573=>602, 9574=>602, 9575=>602, 9576=>602, 9577=>602, 9578=>602, 9579=>602, 9580=>602, 9581=>602, 9582=>602, 9583=>602, 9584=>602, 9585=>602, 9586=>602, - 9587=>602, 9588=>602, 9589=>602, 9590=>602, 9591=>602, 9592=>602, 9593=>602, 9594=>602, 9595=>602, 9596=>602, 9597=>602, 9598=>602, 9599=>602, 9600=>602, 9601=>602, 9602=>602, - 9603=>602, 9604=>602, 9605=>602, 9606=>602, 9607=>602, 9608=>602, 9609=>602, 9610=>602, 9611=>602, 9612=>602, 9613=>602, 9614=>602, 9615=>602, 9616=>602, 9617=>602, 9618=>602, - 9619=>602, 9620=>602, 9621=>602, 9622=>602, 9623=>602, 9624=>602, 9625=>602, 9626=>602, 9627=>602, 9628=>602, 9629=>602, 9630=>602, 9631=>602, 9632=>602, 9633=>602, 9634=>602, - 9635=>602, 9636=>602, 9637=>602, 9638=>602, 9639=>602, 9640=>602, 9641=>602, 9642=>602, 9643=>602, 9644=>602, 9645=>602, 9646=>602, 9647=>602, 9648=>602, 9649=>602, 9650=>602, - 9651=>602, 9652=>602, 9653=>602, 9654=>602, 9655=>602, 9656=>602, 9657=>602, 9658=>602, 9659=>602, 9660=>602, 9661=>602, 9662=>602, 9663=>602, 9664=>602, 9665=>602, 9666=>602, - 9667=>602, 9668=>602, 9669=>602, 9670=>602, 9671=>602, 9672=>602, 9673=>602, 9674=>602, 9675=>602, 9676=>602, 9677=>602, 9678=>602, 9679=>602, 9680=>602, 9681=>602, 9682=>602, - 9683=>602, 9684=>602, 9685=>602, 9686=>602, 9687=>602, 9688=>602, 9689=>602, 9690=>602, 9691=>602, 9692=>602, 9693=>602, 9694=>602, 9695=>602, 9696=>602, 9697=>602, 9698=>602, - 9699=>602, 9700=>602, 9701=>602, 9702=>602, 9703=>602, 9704=>602, 9705=>602, 9706=>602, 9707=>602, 9708=>602, 9709=>602, 9710=>602, 9711=>602, 9712=>602, 9713=>602, 9714=>602, - 9715=>602, 9716=>602, 9717=>602, 9718=>602, 9719=>602, 9720=>602, 9721=>602, 9722=>602, 9723=>602, 9724=>602, 9725=>602, 9726=>602, 9727=>602, 9728=>602, 9784=>602, 9785=>602, - 9786=>602, 9787=>602, 9788=>602, 9791=>602, 9792=>602, 9793=>602, 9794=>602, 9795=>602, 9796=>602, 9797=>602, 9798=>602, 9799=>602, 9824=>602, 9825=>602, 9826=>602, 9827=>602, - 9828=>602, 9829=>602, 9830=>602, 9831=>602, 9833=>602, 9834=>602, 9835=>602, 9836=>602, 9837=>602, 9838=>602, 9839=>602, 10208=>602, 10216=>602, 10217=>602, 10731=>602, 11026=>602, - 11027=>602, 11028=>602, 11029=>602, 11030=>602, 11031=>602, 11032=>602, 11033=>602, 11034=>602, 63173=>602, 64257=>602, 64258=>602, 65533=>602}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSansMono-Oblique.z'; - font[:ctg]='DejaVuSansMono-Oblique.ctg.z'; - font[:originalsize]=203124; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSansbi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSansbi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSansbi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSans-BoldOblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-1067 -388 2005 1121]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>600}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>600, 32=>348, 33=>456, 34=>521, 35=>696, 36=>696, 37=>1002, 38=>872, 39=>306, 40=>457, 41=>457, 42=>523, 43=>838, 44=>380, 45=>415, 46=>380, - 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>400, 59=>400, 60=>838, 61=>838, 62=>838, - 63=>580, 64=>1000, 65=>774, 66=>762, 67=>734, 68=>830, 69=>683, 70=>683, 71=>821, 72=>837, 73=>372, 74=>372, 75=>775, 76=>637, 77=>995, 78=>837, - 79=>850, 80=>733, 81=>850, 82=>770, 83=>720, 84=>682, 85=>812, 86=>774, 87=>1103, 88=>771, 89=>724, 90=>725, 91=>457, 92=>365, 93=>457, 94=>838, - 95=>500, 96=>500, 97=>675, 98=>716, 99=>593, 100=>716, 101=>678, 102=>435, 103=>716, 104=>712, 105=>343, 106=>343, 107=>665, 108=>343, 109=>1042, 110=>712, - 111=>687, 112=>716, 113=>716, 114=>493, 115=>595, 116=>478, 117=>712, 118=>652, 119=>924, 120=>645, 121=>652, 122=>582, 123=>712, 124=>365, 125=>712, 126=>838, - 8364=>696, 1027=>637, 8218=>380, 402=>435, 8222=>644, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1454, 352=>720, 8249=>412, 338=>1167, 1036=>817, 381=>725, 1039=>837, - 8216=>380, 8217=>380, 8220=>644, 8221=>644, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>595, 8250=>412, 339=>1094, 1116=>679, 382=>582, 376=>724, 160=>348, - 161=>456, 162=>696, 163=>696, 164=>636, 165=>696, 166=>365, 167=>500, 168=>500, 169=>1000, 170=>564, 171=>650, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, - 177=>838, 178=>438, 179=>438, 180=>500, 181=>736, 182=>636, 183=>380, 184=>500, 185=>438, 186=>564, 187=>650, 188=>1035, 189=>1035, 190=>1035, 191=>580, 192=>774, - 193=>774, 194=>774, 195=>774, 196=>774, 197=>774, 198=>1085, 199=>734, 200=>683, 201=>683, 202=>683, 203=>683, 204=>372, 205=>372, 206=>372, 207=>372, 208=>845, - 209=>837, 210=>850, 211=>850, 212=>850, 213=>850, 214=>850, 215=>838, 216=>850, 217=>812, 218=>812, 219=>812, 220=>812, 221=>724, 222=>742, 223=>719, 224=>675, - 225=>675, 226=>675, 227=>675, 228=>675, 229=>675, 230=>1048, 231=>593, 232=>678, 233=>678, 234=>678, 235=>678, 236=>343, 237=>343, 238=>343, 239=>343, 240=>687, - 241=>712, 242=>687, 243=>687, 244=>687, 245=>687, 246=>687, 247=>838, 248=>687, 249=>712, 250=>712, 251=>712, 252=>712, 253=>652, 254=>716, 255=>652, 256=>774, - 257=>675, 258=>774, 259=>675, 260=>774, 261=>675, 262=>734, 263=>593, 264=>734, 265=>593, 266=>734, 267=>593, 268=>734, 269=>593, 270=>830, 271=>716, 272=>845, - 273=>716, 274=>683, 275=>678, 276=>683, 277=>678, 278=>683, 279=>678, 280=>683, 281=>678, 282=>683, 283=>678, 284=>821, 285=>716, 286=>821, 287=>716, 288=>821, - 289=>716, 290=>821, 291=>716, 292=>837, 293=>712, 294=>974, 295=>790, 296=>372, 297=>343, 298=>372, 299=>343, 300=>372, 301=>343, 302=>372, 303=>343, 304=>372, - 305=>343, 306=>744, 307=>686, 308=>372, 309=>343, 310=>775, 311=>665, 312=>665, 313=>637, 314=>343, 315=>637, 316=>343, 317=>637, 318=>459, 319=>637, 320=>486, - 321=>660, 322=>375, 323=>837, 324=>712, 325=>837, 326=>712, 327=>837, 328=>712, 329=>983, 330=>837, 331=>712, 332=>850, 333=>687, 334=>850, 335=>687, 336=>850, - 337=>687, 340=>770, 341=>493, 342=>770, 343=>493, 344=>770, 345=>493, 346=>720, 347=>595, 348=>720, 349=>595, 350=>720, 351=>595, 354=>682, 355=>478, 356=>682, - 357=>478, 358=>682, 359=>478, 360=>812, 361=>712, 362=>812, 363=>712, 364=>812, 365=>712, 366=>812, 367=>712, 368=>812, 369=>712, 370=>812, 371=>712, 372=>1103, - 373=>924, 374=>724, 375=>652, 377=>725, 378=>582, 379=>725, 380=>582, 383=>435, 384=>716, 385=>811, 386=>762, 387=>716, 388=>762, 389=>716, 390=>734, 391=>734, - 392=>593, 393=>845, 394=>879, 395=>762, 396=>716, 397=>687, 398=>683, 399=>850, 400=>696, 401=>683, 403=>821, 404=>793, 405=>1045, 406=>436, 407=>389, 408=>775, - 409=>665, 410=>360, 411=>592, 412=>1042, 413=>837, 414=>712, 415=>850, 416=>850, 417=>687, 418=>1114, 419=>962, 420=>782, 421=>716, 422=>770, 423=>720, 424=>595, - 425=>683, 426=>552, 427=>478, 428=>707, 429=>478, 430=>682, 431=>812, 432=>712, 433=>769, 434=>813, 435=>797, 436=>778, 437=>725, 438=>582, 439=>772, 440=>772, - 441=>641, 442=>582, 443=>696, 444=>772, 445=>641, 446=>573, 447=>716, 448=>372, 449=>659, 450=>544, 451=>372, 452=>1548, 453=>1450, 454=>1307, 455=>977, 456=>979, - 457=>670, 458=>1193, 459=>1213, 460=>1063, 461=>774, 462=>675, 463=>372, 464=>343, 465=>850, 466=>687, 467=>812, 468=>712, 469=>812, 470=>712, 471=>812, 472=>712, - 473=>812, 474=>712, 475=>812, 476=>712, 477=>678, 478=>774, 479=>675, 480=>774, 481=>675, 482=>1085, 483=>1048, 484=>821, 485=>716, 486=>821, 487=>716, 488=>775, - 489=>665, 490=>850, 491=>687, 492=>850, 493=>687, 494=>772, 495=>582, 496=>343, 497=>1548, 498=>1450, 499=>1307, 500=>821, 501=>716, 502=>1289, 503=>787, 504=>837, - 505=>712, 506=>774, 507=>675, 508=>1085, 509=>1048, 510=>850, 511=>687, 512=>774, 513=>675, 514=>774, 515=>675, 516=>683, 517=>678, 518=>683, 519=>678, 520=>372, - 521=>343, 522=>372, 523=>343, 524=>850, 525=>687, 526=>850, 527=>687, 528=>770, 529=>493, 530=>770, 531=>493, 532=>812, 533=>712, 534=>812, 535=>712, 536=>720, - 537=>595, 538=>682, 539=>478, 540=>690, 541=>607, 542=>837, 543=>712, 544=>837, 545=>865, 546=>809, 547=>659, 548=>725, 549=>582, 550=>774, 551=>675, 552=>683, - 553=>678, 554=>850, 555=>687, 556=>850, 557=>687, 558=>850, 559=>687, 560=>850, 561=>687, 562=>724, 563=>652, 564=>492, 565=>867, 566=>512, 567=>343, 568=>1088, - 569=>1088, 570=>774, 571=>734, 572=>593, 573=>637, 574=>682, 575=>595, 576=>582, 577=>782, 578=>614, 579=>762, 580=>812, 581=>774, 582=>683, 583=>678, 584=>372, - 585=>343, 586=>860, 587=>791, 588=>770, 589=>493, 590=>724, 591=>652, 592=>675, 593=>716, 594=>716, 595=>716, 596=>593, 597=>593, 598=>791, 599=>792, 600=>678, - 601=>678, 602=>876, 603=>557, 604=>545, 605=>774, 606=>731, 607=>343, 608=>792, 609=>716, 610=>627, 611=>735, 612=>635, 613=>712, 614=>712, 615=>712, 616=>545, - 617=>440, 618=>545, 619=>559, 620=>693, 621=>343, 622=>841, 623=>1042, 624=>1042, 625=>1042, 626=>712, 627=>793, 628=>642, 629=>687, 630=>909, 631=>682, 632=>796, - 633=>538, 634=>538, 635=>650, 636=>493, 637=>493, 638=>596, 639=>596, 640=>642, 641=>642, 642=>595, 643=>415, 644=>435, 645=>605, 646=>552, 647=>478, 648=>478, - 649=>920, 650=>769, 651=>670, 652=>652, 653=>924, 654=>652, 655=>724, 656=>694, 657=>684, 658=>641, 659=>641, 660=>573, 661=>573, 662=>573, 663=>573, 664=>850, - 665=>633, 666=>731, 667=>685, 668=>691, 669=>343, 670=>732, 671=>539, 672=>792, 673=>573, 674=>573, 675=>1156, 676=>1214, 677=>1155, 678=>974, 679=>769, 680=>929, - 681=>1026, 682=>792, 683=>780, 684=>591, 685=>415, 686=>677, 687=>789, 688=>456, 689=>456, 690=>219, 691=>315, 692=>315, 693=>315, 694=>411, 695=>591, 696=>417, - 697=>302, 698=>521, 699=>380, 700=>380, 701=>380, 702=>366, 703=>366, 704=>326, 705=>326, 706=>500, 707=>500, 708=>500, 709=>500, 711=>500, 712=>306, 713=>500, - 714=>500, 715=>500, 716=>306, 717=>500, 718=>500, 719=>500, 720=>337, 721=>337, 722=>366, 723=>366, 724=>500, 725=>500, 726=>500, 727=>500, 728=>500, 729=>500, - 730=>500, 731=>500, 733=>500, 734=>351, 735=>500, 736=>412, 737=>219, 738=>381, 739=>413, 740=>326, 741=>500, 742=>500, 743=>500, 744=>500, 745=>500, 748=>500, - 749=>500, 750=>500, 755=>500, 759=>500, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, - 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, - 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, - 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, - 828=>0, 829=>0, 830=>0, 831=>0, 832=>0, 833=>0, 834=>0, 835=>0, 836=>0, 837=>0, 838=>0, 839=>0, 840=>0, 841=>0, 842=>0, 843=>0, - 844=>0, 845=>0, 846=>0, 847=>0, 849=>0, 850=>0, 855=>0, 856=>0, 860=>0, 861=>0, 862=>0, 863=>0, 864=>0, 865=>0, 866=>0, 884=>302, - 885=>302, 890=>500, 891=>593, 892=>550, 893=>549, 894=>337, 900=>441, 901=>500, 902=>797, 903=>380, 904=>846, 905=>1009, 906=>563, 908=>891, 910=>980, 911=>894, - 912=>390, 913=>774, 914=>762, 915=>637, 916=>774, 917=>683, 918=>725, 919=>837, 920=>850, 921=>372, 922=>775, 923=>774, 924=>995, 925=>837, 926=>632, 927=>850, - 928=>837, 929=>733, 931=>683, 932=>682, 933=>724, 934=>850, 935=>771, 936=>850, 937=>850, 938=>372, 939=>724, 940=>687, 941=>557, 942=>712, 943=>390, 944=>675, - 945=>687, 946=>716, 947=>681, 948=>687, 949=>557, 950=>591, 951=>712, 952=>687, 953=>390, 954=>710, 955=>633, 956=>736, 957=>681, 958=>591, 959=>687, 960=>791, - 961=>716, 962=>593, 963=>779, 964=>638, 965=>675, 966=>782, 967=>645, 968=>794, 969=>869, 970=>390, 971=>675, 972=>687, 973=>675, 974=>869, 976=>651, 977=>661, - 978=>746, 979=>981, 980=>746, 981=>796, 982=>869, 983=>744, 984=>850, 985=>687, 986=>734, 987=>593, 988=>683, 989=>494, 990=>702, 991=>660, 992=>919, 993=>627, - 994=>1093, 995=>837, 996=>832, 997=>716, 998=>928, 999=>744, 1000=>733, 1001=>650, 1002=>789, 1003=>671, 1004=>752, 1005=>716, 1006=>682, 1007=>590, 1008=>744, 1009=>716, - 1010=>593, 1011=>343, 1012=>850, 1013=>645, 1014=>645, 1015=>742, 1016=>716, 1017=>734, 1018=>995, 1019=>732, 1020=>716, 1021=>734, 1022=>734, 1023=>698, 1024=>683, 1025=>683, - 1026=>878, 1028=>734, 1029=>720, 1030=>372, 1031=>372, 1032=>372, 1033=>1154, 1034=>1130, 1035=>878, 1037=>837, 1038=>771, 1040=>774, 1041=>762, 1042=>762, 1043=>637, 1044=>891, - 1045=>683, 1046=>1224, 1047=>710, 1048=>837, 1049=>837, 1050=>817, 1051=>831, 1052=>995, 1053=>837, 1054=>850, 1055=>837, 1056=>733, 1057=>734, 1058=>682, 1059=>771, 1060=>992, - 1061=>771, 1062=>928, 1063=>808, 1064=>1235, 1065=>1326, 1066=>939, 1067=>1036, 1068=>762, 1069=>734, 1070=>1174, 1071=>770, 1072=>675, 1073=>698, 1074=>633, 1075=>522, 1076=>808, - 1077=>678, 1078=>995, 1079=>581, 1080=>701, 1081=>701, 1082=>679, 1083=>732, 1084=>817, 1085=>691, 1086=>687, 1087=>691, 1088=>716, 1089=>593, 1090=>580, 1091=>652, 1092=>992, - 1093=>645, 1094=>741, 1095=>687, 1096=>1062, 1097=>1105, 1098=>751, 1099=>904, 1100=>632, 1101=>593, 1102=>972, 1103=>642, 1104=>678, 1105=>678, 1106=>714, 1107=>522, 1108=>593, - 1109=>595, 1110=>343, 1111=>343, 1112=>343, 1113=>991, 1114=>956, 1115=>734, 1117=>701, 1118=>652, 1119=>691, 1120=>1093, 1121=>869, 1122=>840, 1123=>736, 1124=>1012, 1125=>839, - 1126=>992, 1127=>832, 1128=>1358, 1129=>1121, 1130=>850, 1131=>687, 1132=>1236, 1133=>1007, 1134=>696, 1135=>557, 1136=>1075, 1137=>1061, 1138=>850, 1139=>667, 1140=>850, 1141=>695, - 1142=>850, 1143=>695, 1144=>1148, 1145=>1043, 1146=>1074, 1147=>863, 1148=>1405, 1149=>1173, 1150=>1093, 1151=>869, 1152=>734, 1153=>593, 1154=>652, 1155=>0, 1156=>0, 1157=>0, - 1158=>0, 1160=>418, 1161=>418, 1162=>938, 1163=>806, 1164=>762, 1165=>611, 1166=>736, 1167=>718, 1168=>637, 1169=>522, 1170=>666, 1171=>543, 1172=>789, 1173=>522, 1174=>1224, - 1175=>995, 1176=>710, 1177=>581, 1178=>775, 1179=>679, 1180=>817, 1181=>679, 1182=>817, 1183=>679, 1184=>1015, 1185=>826, 1186=>837, 1187=>691, 1188=>1103, 1189=>871, 1190=>1254, - 1191=>979, 1192=>875, 1193=>710, 1194=>734, 1195=>593, 1196=>682, 1197=>580, 1198=>724, 1199=>652, 1200=>724, 1201=>652, 1202=>771, 1203=>645, 1204=>1104, 1205=>1001, 1206=>808, - 1207=>687, 1208=>808, 1209=>687, 1210=>808, 1211=>712, 1212=>1026, 1213=>810, 1214=>1026, 1215=>810, 1216=>372, 1217=>1224, 1218=>995, 1219=>778, 1220=>629, 1221=>933, 1222=>804, - 1223=>837, 1224=>691, 1225=>938, 1226=>806, 1227=>808, 1228=>687, 1229=>1096, 1230=>932, 1231=>343, 1232=>774, 1233=>675, 1234=>774, 1235=>675, 1236=>1085, 1237=>1048, 1238=>683, - 1239=>678, 1240=>850, 1241=>678, 1242=>850, 1243=>678, 1244=>1224, 1245=>995, 1246=>710, 1247=>581, 1248=>772, 1249=>641, 1250=>837, 1251=>701, 1252=>837, 1253=>701, 1254=>850, - 1255=>687, 1256=>850, 1257=>687, 1258=>850, 1259=>687, 1260=>734, 1261=>593, 1262=>771, 1263=>652, 1264=>771, 1265=>652, 1266=>771, 1267=>652, 1268=>808, 1269=>687, 1270=>637, - 1271=>522, 1272=>1036, 1273=>904, 1274=>666, 1275=>543, 1276=>771, 1277=>645, 1278=>771, 1279=>645, 1280=>762, 1281=>608, 1282=>1159, 1283=>893, 1284=>1119, 1285=>920, 1286=>828, - 1287=>693, 1288=>1242, 1289=>1017, 1290=>1248, 1291=>1013, 1292=>839, 1293=>638, 1294=>938, 1295=>803, 1296=>696, 1297=>557, 1298=>831, 1299=>732, 1329=>984, 1330=>812, 1331=>984, - 1332=>984, 1333=>812, 1334=>777, 1335=>812, 1336=>812, 1337=>975, 1338=>984, 1339=>812, 1340=>710, 1341=>1078, 1342=>1136, 1343=>812, 1344=>710, 1345=>757, 1346=>984, 1347=>876, - 1348=>984, 1349=>793, 1350=>984, 1351=>812, 1352=>812, 1353=>812, 1354=>958, 1355=>777, 1356=>984, 1357=>812, 1358=>984, 1359=>720, 1360=>812, 1361=>793, 1362=>895, 1363=>850, - 1364=>936, 1365=>850, 1366=>720, 1369=>366, 1370=>380, 1371=>550, 1372=>550, 1373=>380, 1374=>546, 1375=>521, 1377=>1042, 1378=>712, 1379=>866, 1380=>868, 1381=>712, 1382=>817, - 1383=>653, 1384=>712, 1385=>811, 1386=>817, 1387=>712, 1388=>498, 1389=>1018, 1390=>716, 1391=>712, 1392=>712, 1393=>716, 1394=>819, 1395=>712, 1396=>751, 1397=>343, 1398=>882, - 1399=>559, 1400=>712, 1401=>559, 1402=>1042, 1403=>559, 1404=>863, 1405=>712, 1406=>813, 1407=>1042, 1408=>712, 1409=>716, 1410=>571, 1411=>1042, 1412=>778, 1413=>687, 1414=>720, - 1415=>862, 1417=>400, 1418=>487, 1456=>0, 1457=>0, 1458=>0, 1459=>0, 1460=>0, 1461=>0, 1462=>0, 1463=>0, 1464=>0, 1465=>0, 1467=>0, 1468=>0, 1469=>0, - 1471=>0, 1472=>372, 1473=>0, 1474=>0, 1475=>372, 1478=>532, 1479=>0, 1488=>751, 1489=>731, 1490=>537, 1491=>684, 1492=>778, 1493=>372, 1494=>521, 1495=>778, 1496=>770, - 1497=>372, 1498=>778, 1499=>750, 1500=>718, 1501=>778, 1502=>856, 1503=>372, 1504=>532, 1505=>855, 1506=>720, 1507=>802, 1508=>777, 1509=>628, 1510=>751, 1511=>803, 1512=>778, - 1513=>963, 1514=>822, 1520=>692, 1521=>692, 1522=>692, 3647=>743, 3713=>815, 3714=>748, 3716=>749, 3719=>569, 3720=>742, 3722=>744, 3725=>761, 3732=>706, 3733=>704, 3734=>747, - 3735=>819, 3737=>730, 3738=>727, 3739=>727, 3740=>922, 3741=>827, 3742=>866, 3743=>866, 3745=>836, 3746=>761, 3747=>770, 3749=>769, 3751=>713, 3754=>827, 3755=>1031, 3757=>724, - 3758=>784, 3759=>934, 3760=>688, 3761=>0, 3762=>610, 3763=>610, 3764=>0, 3765=>0, 3766=>0, 3767=>0, 3768=>0, 3769=>0, 3771=>0, 3772=>0, 3773=>670, 3776=>516, - 3777=>860, 3778=>516, 3779=>650, 3780=>632, 3782=>759, 3784=>0, 3785=>0, 3786=>0, 3787=>0, 3788=>0, 3789=>0, 3804=>1363, 3805=>1363, 5121=>774, 5122=>774, 5123=>774, - 5124=>774, 5125=>905, 5126=>905, 5127=>905, 5129=>905, 5130=>905, 5131=>905, 5132=>1018, 5133=>1009, 5134=>1018, 5135=>1009, 5136=>1018, 5137=>1009, 5138=>1149, 5139=>1140, 5140=>1149, - 5141=>1140, 5142=>905, 5143=>1149, 5144=>1142, 5145=>1149, 5146=>1142, 5147=>905, 5149=>310, 5150=>529, 5151=>425, 5152=>425, 5153=>395, 5154=>395, 5155=>395, 5156=>395, 5157=>564, - 5158=>470, 5159=>310, 5160=>395, 5161=>395, 5162=>395, 5163=>1213, 5164=>986, 5165=>1216, 5166=>1297, 5167=>774, 5168=>774, 5169=>774, 5170=>774, 5171=>886, 5172=>886, 5173=>886, - 5175=>886, 5176=>886, 5177=>886, 5178=>1018, 5179=>1009, 5180=>1018, 5181=>1009, 5182=>1018, 5183=>1009, 5184=>1149, 5185=>1140, 5186=>1149, 5187=>1140, 5188=>1149, 5189=>1142, 5190=>1149, - 5191=>1142, 5192=>886, 5193=>576, 5194=>229, 5196=>812, 5197=>812, 5198=>812, 5199=>812, 5200=>815, 5201=>815, 5202=>815, 5204=>815, 5205=>815, 5206=>815, 5207=>1056, 5208=>1048, - 5209=>1056, 5210=>1048, 5211=>1056, 5212=>1048, 5213=>1060, 5214=>1054, 5215=>1060, 5216=>1054, 5217=>1060, 5218=>1052, 5219=>1060, 5220=>1052, 5221=>1060, 5222=>483, 5223=>1005, 5224=>1005, - 5225=>1023, 5226=>1017, 5227=>743, 5228=>743, 5229=>743, 5230=>743, 5231=>743, 5232=>743, 5233=>743, 5234=>743, 5235=>743, 5236=>1029, 5237=>975, 5238=>980, 5239=>975, 5240=>980, - 5241=>975, 5242=>1029, 5243=>975, 5244=>1029, 5245=>975, 5246=>980, 5247=>975, 5248=>980, 5249=>975, 5250=>980, 5251=>501, 5252=>501, 5253=>938, 5254=>938, 5255=>938, 5256=>938, - 5257=>743, 5258=>743, 5259=>743, 5260=>743, 5261=>743, 5262=>743, 5263=>743, 5264=>743, 5265=>743, 5266=>1029, 5267=>975, 5268=>1029, 5269=>975, 5270=>1029, 5271=>975, 5272=>1029, - 5273=>975, 5274=>1029, 5275=>975, 5276=>1029, 5277=>975, 5278=>1029, 5279=>975, 5280=>1029, 5281=>501, 5282=>501, 5283=>626, 5284=>626, 5285=>626, 5286=>626, 5287=>626, 5288=>626, - 5289=>626, 5290=>626, 5291=>626, 5292=>881, 5293=>854, 5294=>863, 5295=>874, 5296=>863, 5297=>874, 5298=>881, 5299=>874, 5300=>881, 5301=>874, 5302=>863, 5303=>874, 5304=>863, - 5305=>874, 5306=>863, 5307=>436, 5308=>548, 5309=>436, 5312=>988, 5313=>988, 5314=>988, 5315=>988, 5316=>931, 5317=>931, 5318=>931, 5319=>931, 5320=>931, 5321=>1238, 5322=>1247, - 5323=>1200, 5324=>1228, 5325=>1200, 5326=>1228, 5327=>931, 5328=>660, 5329=>497, 5330=>660, 5331=>988, 5332=>988, 5333=>988, 5334=>988, 5335=>931, 5336=>931, 5337=>931, 5338=>931, - 5339=>931, 5340=>1231, 5341=>1247, 5342=>1283, 5343=>1228, 5344=>1283, 5345=>1228, 5346=>1228, 5347=>1214, 5348=>1228, 5349=>1214, 5350=>1283, 5351=>1228, 5352=>1283, 5353=>1228, 5354=>660, - 5356=>886, 5357=>730, 5358=>730, 5359=>730, 5360=>730, 5361=>730, 5362=>730, 5363=>730, 5364=>730, 5365=>730, 5366=>998, 5367=>958, 5368=>967, 5369=>989, 5370=>967, 5371=>989, - 5372=>998, 5373=>958, 5374=>998, 5375=>958, 5376=>967, 5377=>989, 5378=>967, 5379=>989, 5380=>967, 5381=>493, 5382=>460, 5383=>493, 5392=>923, 5393=>923, 5394=>923, 5395=>1136, - 5396=>1136, 5397=>1136, 5398=>1136, 5399=>1209, 5400=>1202, 5401=>1209, 5402=>1202, 5403=>1209, 5404=>1202, 5405=>1431, 5406=>1420, 5407=>1431, 5408=>1420, 5409=>1431, 5410=>1420, 5411=>1431, - 5412=>1420, 5413=>746, 5414=>776, 5415=>776, 5416=>776, 5417=>776, 5418=>776, 5419=>776, 5420=>776, 5421=>776, 5422=>776, 5423=>1003, 5424=>1003, 5425=>1013, 5426=>996, 5427=>1013, - 5428=>996, 5429=>1003, 5430=>1003, 5431=>1003, 5432=>1003, 5433=>1013, 5434=>996, 5435=>1013, 5436=>996, 5437=>1013, 5438=>495, 5440=>395, 5441=>510, 5442=>1033, 5443=>1033, 5444=>976, - 5445=>976, 5446=>976, 5447=>976, 5448=>733, 5449=>733, 5450=>733, 5451=>733, 5452=>733, 5453=>733, 5454=>1003, 5455=>959, 5456=>495, 5458=>886, 5459=>774, 5460=>774, 5461=>774, - 5462=>774, 5463=>928, 5464=>928, 5465=>928, 5466=>928, 5467=>1172, 5468=>1142, 5469=>602, 5470=>812, 5471=>812, 5472=>812, 5473=>812, 5474=>812, 5475=>812, 5476=>815, 5477=>815, - 5478=>815, 5479=>815, 5480=>1060, 5481=>1052, 5482=>548, 5492=>977, 5493=>977, 5494=>977, 5495=>977, 5496=>977, 5497=>977, 5498=>977, 5499=>618, 5500=>837, 5501=>510, 5502=>1238, - 5503=>1238, 5504=>1238, 5505=>1238, 5506=>1238, 5507=>1238, 5508=>1238, 5509=>989, 5514=>977, 5515=>977, 5516=>977, 5517=>977, 5518=>1591, 5519=>1591, 5520=>1591, 5521=>1295, 5522=>1295, - 5523=>1591, 5524=>1591, 5525=>848, 5526=>1273, 5536=>988, 5537=>988, 5538=>931, 5539=>931, 5540=>931, 5541=>931, 5542=>660, 5543=>776, 5544=>776, 5545=>776, 5546=>776, 5547=>776, - 5548=>776, 5549=>776, 5550=>495, 5551=>743, 5598=>830, 5601=>830, 5702=>496, 5703=>496, 5742=>413, 5743=>1238, 5744=>1591, 5745=>2016, 5746=>2016, 5747=>1720, 5748=>1678, 5749=>2016, - 5750=>2016, 7424=>652, 7425=>833, 7426=>1048, 7427=>608, 7428=>593, 7429=>676, 7430=>676, 7431=>559, 7432=>557, 7433=>343, 7434=>494, 7435=>665, 7436=>539, 7437=>817, 7438=>701, - 7439=>687, 7440=>593, 7441=>660, 7442=>660, 7443=>660, 7444=>1094, 7446=>687, 7447=>687, 7448=>556, 7449=>642, 7450=>642, 7451=>580, 7452=>634, 7453=>737, 7454=>948, 7455=>695, - 7456=>652, 7457=>924, 7458=>582, 7459=>646, 7462=>539, 7463=>652, 7464=>691, 7465=>556, 7466=>781, 7467=>732, 7468=>487, 7469=>683, 7470=>480, 7472=>523, 7473=>430, 7474=>430, - 7475=>517, 7476=>527, 7477=>234, 7478=>234, 7479=>488, 7480=>401, 7481=>626, 7482=>527, 7483=>527, 7484=>535, 7485=>509, 7486=>461, 7487=>485, 7488=>430, 7489=>511, 7490=>695, - 7491=>458, 7492=>458, 7493=>479, 7494=>712, 7495=>479, 7496=>479, 7497=>479, 7498=>479, 7499=>386, 7500=>386, 7501=>479, 7502=>219, 7503=>487, 7504=>664, 7505=>456, 7506=>488, - 7507=>414, 7508=>488, 7509=>488, 7510=>479, 7511=>388, 7512=>456, 7513=>462, 7514=>664, 7515=>501, 7517=>451, 7518=>429, 7519=>433, 7520=>493, 7521=>406, 7522=>219, 7523=>315, - 7524=>456, 7525=>501, 7526=>451, 7527=>429, 7528=>433, 7529=>493, 7530=>406, 7543=>716, 7544=>527, 7547=>545, 7557=>514, 7579=>479, 7580=>414, 7581=>414, 7582=>488, 7583=>386, - 7584=>377, 7585=>348, 7586=>479, 7587=>456, 7588=>347, 7589=>281, 7590=>347, 7591=>347, 7592=>431, 7593=>326, 7594=>330, 7595=>370, 7596=>664, 7597=>664, 7598=>562, 7599=>562, - 7600=>448, 7601=>488, 7602=>542, 7603=>422, 7604=>396, 7605=>388, 7606=>583, 7607=>494, 7608=>399, 7609=>451, 7610=>501, 7611=>417, 7612=>523, 7613=>470, 7614=>455, 7615=>425, - 7620=>0, 7621=>0, 7622=>0, 7623=>0, 7624=>0, 7625=>0, 7680=>774, 7681=>675, 7682=>762, 7683=>716, 7684=>762, 7685=>716, 7686=>762, 7687=>716, 7688=>734, 7689=>593, - 7690=>830, 7691=>716, 7692=>830, 7693=>716, 7694=>830, 7695=>716, 7696=>830, 7697=>716, 7698=>830, 7699=>716, 7700=>683, 7701=>678, 7702=>683, 7703=>678, 7704=>683, 7705=>678, - 7706=>683, 7707=>678, 7708=>683, 7709=>678, 7710=>683, 7711=>435, 7712=>821, 7713=>716, 7714=>837, 7715=>712, 7716=>837, 7717=>712, 7718=>837, 7719=>712, 7720=>837, 7721=>712, - 7722=>837, 7723=>712, 7724=>372, 7725=>343, 7726=>372, 7727=>343, 7728=>775, 7729=>665, 7730=>775, 7731=>665, 7732=>775, 7733=>665, 7734=>637, 7735=>343, 7736=>637, 7737=>343, - 7738=>637, 7739=>343, 7740=>637, 7741=>343, 7742=>995, 7743=>1042, 7744=>995, 7745=>1042, 7746=>995, 7747=>1042, 7748=>837, 7749=>712, 7750=>837, 7751=>712, 7752=>837, 7753=>712, - 7754=>837, 7755=>712, 7756=>850, 7757=>687, 7758=>850, 7759=>687, 7760=>850, 7761=>687, 7762=>850, 7763=>687, 7764=>733, 7765=>716, 7766=>733, 7767=>716, 7768=>770, 7769=>493, - 7770=>770, 7771=>493, 7772=>770, 7773=>493, 7774=>770, 7775=>493, 7776=>720, 7777=>595, 7778=>720, 7779=>595, 7780=>720, 7781=>595, 7782=>720, 7783=>595, 7784=>720, 7785=>595, - 7786=>682, 7787=>478, 7788=>682, 7789=>478, 7790=>682, 7791=>478, 7792=>682, 7793=>478, 7794=>812, 7795=>712, 7796=>812, 7797=>712, 7798=>812, 7799=>712, 7800=>812, 7801=>712, - 7802=>812, 7803=>712, 7804=>774, 7805=>652, 7806=>774, 7807=>652, 7808=>1103, 7809=>924, 7810=>1103, 7811=>924, 7812=>1103, 7813=>924, 7814=>1103, 7815=>924, 7816=>1103, 7817=>924, - 7818=>771, 7819=>645, 7820=>771, 7821=>645, 7822=>724, 7823=>652, 7824=>725, 7825=>582, 7826=>725, 7827=>582, 7828=>725, 7829=>582, 7830=>712, 7831=>478, 7832=>924, 7833=>652, - 7834=>675, 7835=>435, 7840=>774, 7841=>675, 7842=>774, 7843=>675, 7844=>774, 7845=>675, 7846=>774, 7847=>675, 7848=>774, 7849=>675, 7850=>774, 7851=>675, 7852=>774, 7853=>675, - 7854=>774, 7855=>675, 7856=>774, 7857=>675, 7858=>774, 7859=>675, 7860=>774, 7861=>675, 7862=>774, 7863=>675, 7864=>683, 7865=>678, 7866=>683, 7867=>678, 7868=>683, 7869=>678, - 7870=>683, 7871=>678, 7872=>683, 7873=>678, 7874=>683, 7875=>678, 7876=>683, 7877=>678, 7878=>683, 7879=>678, 7880=>372, 7881=>343, 7882=>372, 7883=>343, 7884=>850, 7885=>687, - 7886=>850, 7887=>687, 7888=>850, 7889=>687, 7890=>850, 7891=>687, 7892=>850, 7893=>687, 7894=>850, 7895=>687, 7896=>850, 7897=>687, 7898=>850, 7899=>687, 7900=>850, 7901=>687, - 7902=>850, 7903=>687, 7904=>850, 7905=>687, 7906=>850, 7907=>687, 7908=>812, 7909=>712, 7910=>812, 7911=>712, 7912=>812, 7913=>712, 7914=>812, 7915=>712, 7916=>812, 7917=>712, - 7918=>812, 7919=>712, 7920=>812, 7921=>712, 7922=>724, 7923=>652, 7924=>724, 7925=>652, 7926=>724, 7927=>652, 7928=>724, 7929=>652, 7936=>687, 7937=>687, 7938=>687, 7939=>687, - 7940=>687, 7941=>687, 7942=>687, 7943=>687, 7944=>774, 7945=>774, 7946=>1041, 7947=>1043, 7948=>935, 7949=>963, 7950=>835, 7951=>859, 7952=>557, 7953=>557, 7954=>557, 7955=>557, - 7956=>557, 7957=>557, 7960=>792, 7961=>794, 7962=>1100, 7963=>1096, 7964=>1023, 7965=>1052, 7968=>712, 7969=>712, 7970=>712, 7971=>712, 7972=>712, 7973=>712, 7974=>712, 7975=>712, - 7976=>945, 7977=>951, 7978=>1250, 7979=>1250, 7980=>1180, 7981=>1206, 7982=>1054, 7983=>1063, 7984=>390, 7985=>390, 7986=>390, 7987=>390, 7988=>390, 7989=>390, 7990=>390, 7991=>390, - 7992=>483, 7993=>489, 7994=>777, 7995=>785, 7996=>712, 7997=>738, 7998=>604, 7999=>604, 8000=>687, 8001=>687, 8002=>687, 8003=>687, 8004=>687, 8005=>687, 8008=>892, 8009=>933, - 8010=>1221, 8011=>1224, 8012=>1053, 8013=>1082, 8016=>675, 8017=>675, 8018=>675, 8019=>675, 8020=>675, 8021=>675, 8022=>675, 8023=>675, 8025=>930, 8027=>1184, 8029=>1199, 8031=>1049, - 8032=>869, 8033=>869, 8034=>869, 8035=>869, 8036=>869, 8037=>869, 8038=>869, 8039=>869, 8040=>909, 8041=>958, 8042=>1246, 8043=>1251, 8044=>1076, 8045=>1105, 8046=>1028, 8047=>1076, - 8048=>687, 8049=>687, 8050=>557, 8051=>557, 8052=>712, 8053=>712, 8054=>390, 8055=>390, 8056=>687, 8057=>687, 8058=>675, 8059=>675, 8060=>869, 8061=>869, 8064=>687, 8065=>687, - 8066=>687, 8067=>687, 8068=>687, 8069=>687, 8070=>687, 8071=>687, 8072=>774, 8073=>774, 8074=>1041, 8075=>1043, 8076=>935, 8077=>963, 8078=>835, 8079=>859, 8080=>712, 8081=>712, - 8082=>712, 8083=>712, 8084=>712, 8085=>712, 8086=>712, 8087=>712, 8088=>945, 8089=>951, 8090=>1250, 8091=>1250, 8092=>1180, 8093=>1206, 8094=>1054, 8095=>1063, 8096=>869, 8097=>869, - 8098=>869, 8099=>869, 8100=>869, 8101=>869, 8102=>869, 8103=>869, 8104=>909, 8105=>958, 8106=>1246, 8107=>1251, 8108=>1076, 8109=>1105, 8110=>1028, 8111=>1076, 8112=>687, 8113=>687, - 8114=>687, 8115=>687, 8116=>687, 8118=>687, 8119=>687, 8120=>774, 8121=>774, 8122=>876, 8123=>797, 8124=>774, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>712, - 8131=>712, 8132=>712, 8134=>712, 8135=>712, 8136=>929, 8137=>846, 8138=>1080, 8139=>1009, 8140=>837, 8141=>500, 8142=>500, 8143=>500, 8144=>390, 8145=>390, 8146=>390, 8147=>390, - 8150=>390, 8151=>390, 8152=>372, 8153=>372, 8154=>621, 8155=>563, 8157=>500, 8158=>500, 8159=>500, 8160=>675, 8161=>675, 8162=>675, 8163=>675, 8164=>716, 8165=>716, 8166=>675, - 8167=>675, 8168=>724, 8169=>724, 8170=>1020, 8171=>980, 8172=>838, 8173=>500, 8174=>500, 8175=>500, 8178=>869, 8179=>869, 8180=>869, 8182=>869, 8183=>869, 8184=>1065, 8185=>891, - 8186=>1084, 8187=>894, 8188=>850, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, 8196=>330, 8197=>250, 8198=>167, 8199=>696, 8200=>380, 8201=>200, 8202=>100, - 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>415, 8209=>415, 8210=>696, 8213=>1000, 8214=>500, 8215=>500, 8219=>380, 8223=>657, 8227=>639, 8228=>380, 8229=>685, - 8231=>348, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1908, 8242=>264, 8243=>447, 8244=>630, 8245=>264, 8246=>447, 8247=>630, 8248=>733, 8251=>972, - 8252=>627, 8253=>580, 8254=>500, 8255=>828, 8256=>828, 8257=>329, 8258=>1023, 8259=>500, 8260=>167, 8261=>457, 8262=>457, 8263=>1030, 8264=>829, 8265=>829, 8266=>513, 8267=>687, - 8268=>500, 8269=>500, 8270=>523, 8271=>400, 8272=>828, 8273=>523, 8274=>556, 8275=>838, 8276=>829, 8277=>838, 8278=>684, 8279=>813, 8280=>838, 8281=>838, 8282=>380, 8283=>872, - 8284=>838, 8285=>380, 8286=>380, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>438, 8305=>219, - 8308=>438, 8309=>438, 8310=>438, 8311=>438, 8312=>438, 8313=>438, 8314=>528, 8315=>528, 8316=>528, 8317=>288, 8318=>288, 8319=>456, 8320=>438, 8321=>438, 8322=>438, 8323=>438, - 8324=>438, 8325=>438, 8326=>438, 8327=>438, 8328=>438, 8329=>438, 8330=>528, 8331=>528, 8332=>528, 8333=>288, 8334=>288, 8336=>458, 8337=>479, 8338=>488, 8339=>413, 8340=>479, - 8352=>929, 8353=>696, 8354=>696, 8355=>696, 8356=>696, 8357=>1042, 8358=>837, 8359=>1488, 8360=>1205, 8361=>1103, 8362=>854, 8363=>714, 8365=>696, 8366=>682, 8367=>1392, 8368=>696, - 8369=>696, 8370=>696, 8371=>696, 8372=>859, 8373=>696, 8400=>0, 8401=>0, 8406=>0, 8407=>0, 8448=>1106, 8449=>1106, 8450=>734, 8451=>1211, 8452=>896, 8453=>1114, 8454=>1148, - 8455=>696, 8456=>698, 8457=>952, 8459=>1073, 8460=>913, 8461=>850, 8462=>712, 8463=>712, 8464=>604, 8465=>697, 8466=>868, 8467=>472, 8468=>974, 8469=>837, 8470=>1203, 8471=>1000, - 8472=>697, 8473=>702, 8474=>850, 8475=>876, 8476=>814, 8477=>792, 8478=>896, 8479=>710, 8480=>1020, 8481=>1239, 8483=>834, 8484=>725, 8485=>622, 8486=>850, 8487=>769, 8488=>763, - 8489=>303, 8490=>775, 8491=>774, 8492=>928, 8493=>776, 8494=>854, 8495=>636, 8496=>738, 8497=>811, 8498=>683, 8499=>1193, 8500=>465, 8501=>794, 8502=>736, 8503=>503, 8504=>695, - 8505=>380, 8506=>945, 8507=>1370, 8508=>790, 8509=>737, 8510=>652, 8511=>845, 8512=>840, 8513=>786, 8514=>576, 8515=>637, 8516=>760, 8517=>830, 8518=>716, 8519=>678, 8520=>343, - 8521=>343, 8523=>872, 8526=>547, 8531=>1035, 8532=>1035, 8533=>1035, 8534=>1035, 8535=>1035, 8536=>1035, 8537=>1035, 8538=>1035, 8539=>1035, 8540=>1035, 8541=>1035, 8542=>1035, 8543=>615, - 8544=>372, 8545=>659, 8546=>945, 8547=>1099, 8548=>774, 8549=>1099, 8550=>1386, 8551=>1672, 8552=>1121, 8553=>771, 8554=>1120, 8555=>1407, 8556=>637, 8557=>734, 8558=>830, 8559=>995, - 8560=>343, 8561=>607, 8562=>872, 8563=>984, 8564=>652, 8565=>962, 8566=>1227, 8567=>1491, 8568=>969, 8569=>645, 8570=>969, 8571=>1233, 8572=>343, 8573=>593, 8574=>716, 8575=>1042, - 8576=>1289, 8577=>830, 8578=>1289, 8579=>734, 8580=>593, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8596=>838, 8597=>838, 8598=>838, 8599=>838, 8600=>838, 8601=>838, 8602=>838, - 8603=>838, 8604=>838, 8605=>838, 8606=>838, 8607=>838, 8608=>838, 8609=>838, 8610=>838, 8611=>838, 8612=>838, 8613=>838, 8614=>838, 8615=>838, 8616=>838, 8617=>838, 8618=>838, - 8619=>838, 8620=>838, 8621=>838, 8622=>838, 8623=>838, 8624=>838, 8625=>838, 8626=>838, 8627=>838, 8628=>838, 8629=>838, 8630=>838, 8631=>838, 8632=>838, 8633=>838, 8634=>838, - 8635=>838, 8636=>838, 8637=>838, 8638=>838, 8639=>838, 8640=>838, 8641=>838, 8642=>838, 8643=>838, 8644=>838, 8645=>838, 8646=>838, 8647=>838, 8648=>838, 8649=>838, 8650=>838, - 8651=>838, 8652=>838, 8653=>838, 8654=>838, 8655=>838, 8656=>838, 8657=>838, 8658=>838, 8659=>838, 8660=>838, 8661=>838, 8662=>838, 8663=>838, 8664=>838, 8665=>838, 8666=>838, - 8667=>838, 8668=>838, 8669=>838, 8670=>838, 8671=>838, 8672=>838, 8673=>838, 8674=>838, 8675=>838, 8676=>838, 8677=>838, 8678=>838, 8679=>838, 8680=>838, 8681=>838, 8682=>838, - 8683=>838, 8684=>838, 8685=>838, 8686=>838, 8687=>838, 8688=>838, 8689=>838, 8690=>838, 8691=>838, 8692=>838, 8693=>838, 8694=>838, 8695=>838, 8696=>838, 8697=>838, 8698=>838, - 8699=>838, 8700=>838, 8701=>838, 8702=>838, 8703=>838, 8704=>774, 8705=>696, 8706=>544, 8707=>683, 8708=>683, 8709=>856, 8710=>697, 8711=>697, 8712=>896, 8713=>896, 8714=>750, - 8715=>896, 8716=>896, 8717=>750, 8718=>636, 8719=>787, 8720=>787, 8721=>718, 8722=>838, 8723=>838, 8724=>696, 8725=>167, 8726=>696, 8727=>838, 8728=>626, 8729=>380, 8730=>667, - 8731=>667, 8732=>667, 8733=>669, 8734=>833, 8735=>838, 8736=>896, 8737=>896, 8738=>838, 8739=>500, 8740=>500, 8741=>500, 8742=>500, 8743=>812, 8744=>812, 8745=>812, 8746=>812, - 8747=>610, 8748=>929, 8749=>1295, 8750=>563, 8751=>977, 8752=>1313, 8753=>563, 8754=>563, 8755=>563, 8756=>696, 8757=>696, 8758=>294, 8759=>696, 8760=>838, 8761=>838, 8762=>838, - 8763=>838, 8764=>838, 8765=>838, 8766=>838, 8767=>838, 8768=>375, 8769=>838, 8770=>838, 8771=>838, 8772=>838, 8773=>838, 8774=>838, 8775=>838, 8776=>838, 8777=>838, 8778=>838, - 8779=>838, 8780=>838, 8781=>838, 8782=>838, 8783=>838, 8784=>838, 8785=>838, 8786=>838, 8787=>838, 8788=>1063, 8789=>1063, 8790=>838, 8791=>838, 8792=>838, 8793=>838, 8794=>838, - 8795=>838, 8796=>838, 8797=>838, 8798=>838, 8799=>838, 8800=>838, 8801=>838, 8802=>838, 8803=>838, 8804=>838, 8805=>838, 8806=>838, 8807=>838, 8808=>841, 8809=>841, 8810=>1047, - 8811=>1047, 8812=>500, 8813=>838, 8814=>838, 8815=>838, 8816=>838, 8817=>838, 8818=>838, 8819=>838, 8820=>838, 8821=>838, 8822=>838, 8823=>838, 8824=>838, 8825=>838, 8826=>838, - 8827=>838, 8828=>838, 8829=>838, 8830=>838, 8831=>838, 8832=>838, 8833=>838, 8834=>838, 8835=>838, 8836=>838, 8837=>838, 8838=>838, 8839=>838, 8840=>838, 8841=>838, 8842=>838, - 8843=>838, 8844=>812, 8845=>812, 8846=>812, 8847=>838, 8848=>838, 8849=>838, 8850=>838, 8851=>754, 8852=>754, 8853=>838, 8854=>838, 8855=>838, 8856=>838, 8857=>838, 8858=>838, - 8859=>838, 8860=>838, 8861=>838, 8862=>838, 8863=>838, 8864=>838, 8865=>838, 8866=>914, 8867=>914, 8868=>914, 8869=>914, 8870=>542, 8871=>542, 8872=>914, 8873=>914, 8874=>914, - 8875=>914, 8876=>914, 8877=>914, 8878=>914, 8879=>914, 8882=>838, 8883=>838, 8884=>838, 8885=>838, 8886=>1000, 8887=>1000, 8888=>838, 8889=>838, 8890=>542, 8891=>812, 8892=>812, - 8893=>812, 8896=>843, 8897=>843, 8898=>843, 8899=>843, 8900=>494, 8901=>380, 8902=>626, 8904=>1000, 8905=>1000, 8906=>1000, 8907=>1000, 8908=>1000, 8909=>838, 8918=>838, 8919=>838, - 8920=>1422, 8921=>1422, 8922=>838, 8923=>838, 8924=>838, 8925=>838, 8926=>838, 8927=>838, 8928=>838, 8929=>838, 8930=>838, 8931=>838, 8932=>838, 8933=>838, 8934=>838, 8935=>838, - 8936=>838, 8937=>838, 8938=>838, 8939=>838, 8940=>838, 8941=>838, 8946=>1158, 8947=>896, 8948=>750, 8949=>896, 8950=>896, 8951=>750, 8952=>896, 8953=>896, 8954=>1158, 8955=>896, - 8956=>750, 8957=>896, 8958=>750, 8959=>896, 8962=>716, 8966=>917, 8968=>457, 8969=>457, 8970=>457, 8971=>457, 8976=>838, 8977=>539, 8984=>928, 8985=>838, 8992=>610, 8993=>610, - 8997=>1000, 9000=>1443, 9085=>863, 9115=>500, 9116=>500, 9117=>500, 9118=>500, 9119=>500, 9120=>500, 9121=>500, 9122=>500, 9123=>500, 9124=>500, 9125=>500, 9126=>500, 9127=>750, - 9128=>750, 9129=>750, 9130=>750, 9131=>750, 9132=>750, 9133=>750, 9134=>610, 9166=>838, 9167=>945, 9250=>716, 9251=>716, 9312=>847, 9313=>847, 9314=>847, 9315=>847, 9316=>847, - 9317=>847, 9318=>847, 9319=>847, 9320=>847, 9321=>847, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, 9609=>769, 9610=>769, - 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, 9625=>769, 9626=>769, - 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, 9641=>945, 9642=>678, - 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, 9657=>502, 9658=>769, - 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, 9673=>873, 9674=>494, - 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>840, 9689=>970, 9690=>970, - 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>769, 9697=>769, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>639, 9703=>945, 9704=>945, 9705=>945, 9706=>945, - 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, 9721=>769, 9722=>769, - 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9729=>1000, 9730=>896, 9731=>896, 9732=>896, 9733=>896, 9734=>896, 9735=>573, 9736=>896, 9737=>896, 9738=>888, - 9739=>888, 9740=>671, 9741=>1013, 9742=>1246, 9743=>1250, 9744=>896, 9745=>896, 9746=>896, 9747=>532, 9748=>896, 9749=>896, 9750=>896, 9751=>896, 9752=>896, 9753=>896, 9754=>896, - 9755=>896, 9756=>896, 9757=>609, 9758=>896, 9759=>609, 9760=>896, 9761=>896, 9762=>896, 9763=>896, 9764=>669, 9765=>746, 9766=>649, 9767=>784, 9768=>545, 9769=>896, 9770=>896, - 9771=>896, 9772=>710, 9773=>896, 9774=>896, 9775=>896, 9776=>896, 9777=>896, 9778=>896, 9779=>896, 9780=>896, 9781=>896, 9782=>896, 9783=>896, 9784=>896, 9785=>896, 9786=>896, - 9787=>896, 9788=>896, 9789=>896, 9790=>896, 9791=>614, 9792=>731, 9793=>731, 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9800=>896, 9801=>896, 9802=>896, - 9803=>896, 9804=>896, 9805=>896, 9806=>896, 9807=>896, 9808=>896, 9809=>896, 9810=>896, 9811=>896, 9812=>896, 9813=>896, 9814=>896, 9815=>896, 9816=>896, 9817=>896, 9818=>896, - 9819=>896, 9820=>896, 9821=>896, 9822=>896, 9823=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9832=>896, 9833=>472, 9834=>638, - 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 9840=>748, 9841=>766, 9842=>896, 9843=>896, 9844=>896, 9845=>896, 9846=>896, 9847=>896, 9848=>896, 9849=>896, 9850=>896, - 9851=>896, 9852=>896, 9853=>896, 9854=>896, 9855=>896, 9856=>869, 9857=>869, 9858=>869, 9859=>869, 9860=>869, 9861=>869, 9862=>896, 9863=>896, 9864=>896, 9865=>896, 9866=>896, - 9867=>896, 9868=>896, 9869=>896, 9870=>896, 9871=>896, 9872=>896, 9873=>896, 9874=>896, 9875=>896, 9876=>896, 9877=>541, 9878=>896, 9879=>896, 9880=>896, 9881=>896, 9882=>896, - 9883=>896, 9884=>896, 9888=>896, 9889=>702, 9890=>838, 9891=>838, 9892=>838, 9893=>838, 9894=>838, 9895=>838, 9896=>838, 9897=>838, 9898=>838, 9899=>838, 9900=>838, 9901=>838, - 9902=>838, 9903=>838, 9904=>844, 9905=>838, 9906=>731, 9985=>838, 9986=>838, 9987=>838, 9988=>838, 9990=>838, 9991=>838, 9992=>838, 9993=>838, 9996=>838, 9997=>838, 9998=>838, - 9999=>838, 10000=>838, 10001=>838, 10002=>838, 10003=>838, 10004=>838, 10005=>838, 10006=>838, 10007=>838, 10008=>838, 10009=>838, 10010=>838, 10011=>838, 10012=>838, 10013=>838, 10014=>838, - 10015=>838, 10016=>838, 10017=>838, 10018=>838, 10019=>838, 10020=>838, 10021=>838, 10022=>838, 10023=>838, 10025=>838, 10026=>838, 10027=>838, 10028=>838, 10029=>838, 10030=>838, 10031=>838, - 10032=>838, 10033=>838, 10034=>838, 10035=>838, 10036=>838, 10037=>838, 10038=>838, 10039=>838, 10040=>838, 10041=>838, 10042=>838, 10043=>838, 10044=>838, 10045=>838, 10046=>838, 10047=>838, - 10048=>838, 10049=>838, 10050=>838, 10051=>838, 10052=>838, 10053=>838, 10054=>838, 10055=>838, 10056=>838, 10057=>838, 10058=>838, 10059=>838, 10061=>896, 10063=>896, 10064=>896, 10065=>896, - 10066=>896, 10070=>896, 10072=>838, 10073=>838, 10074=>838, 10075=>322, 10076=>322, 10077=>538, 10078=>538, 10081=>838, 10082=>838, 10083=>838, 10084=>838, 10085=>838, 10086=>838, 10087=>838, - 10088=>838, 10089=>838, 10090=>838, 10091=>838, 10092=>838, 10093=>838, 10094=>838, 10095=>838, 10096=>838, 10097=>838, 10098=>838, 10099=>838, 10100=>838, 10101=>838, 10102=>847, 10103=>847, - 10104=>847, 10105=>847, 10106=>847, 10107=>847, 10108=>847, 10109=>847, 10110=>847, 10111=>847, 10112=>838, 10113=>838, 10114=>838, 10115=>838, 10116=>838, 10117=>838, 10118=>838, 10119=>838, - 10120=>838, 10121=>838, 10122=>838, 10123=>838, 10124=>838, 10125=>838, 10126=>838, 10127=>838, 10128=>838, 10129=>838, 10130=>838, 10131=>838, 10132=>838, 10136=>838, 10137=>838, 10138=>838, - 10139=>838, 10140=>838, 10141=>838, 10142=>838, 10143=>838, 10144=>838, 10145=>838, 10146=>838, 10147=>838, 10148=>838, 10149=>838, 10150=>838, 10151=>838, 10152=>838, 10153=>838, 10154=>838, - 10155=>838, 10156=>838, 10157=>838, 10158=>838, 10159=>838, 10161=>838, 10162=>838, 10163=>838, 10164=>838, 10165=>838, 10166=>838, 10167=>838, 10168=>838, 10169=>838, 10170=>838, 10171=>838, - 10172=>838, 10173=>838, 10174=>838, 10208=>494, 10214=>487, 10215=>487, 10216=>457, 10217=>457, 10218=>721, 10219=>721, 10224=>838, 10225=>838, 10226=>838, 10227=>838, 10228=>1157, 10229=>1434, - 10230=>1434, 10231=>1434, 10232=>1434, 10233=>1434, 10234=>1434, 10235=>1434, 10236=>1434, 10237=>1434, 10238=>1434, 10239=>1434, 10240=>781, 10241=>781, 10242=>781, 10243=>781, 10244=>781, 10245=>781, - 10246=>781, 10247=>781, 10248=>781, 10249=>781, 10250=>781, 10251=>781, 10252=>781, 10253=>781, 10254=>781, 10255=>781, 10256=>781, 10257=>781, 10258=>781, 10259=>781, 10260=>781, 10261=>781, - 10262=>781, 10263=>781, 10264=>781, 10265=>781, 10266=>781, 10267=>781, 10268=>781, 10269=>781, 10270=>781, 10271=>781, 10272=>781, 10273=>781, 10274=>781, 10275=>781, 10276=>781, 10277=>781, - 10278=>781, 10279=>781, 10280=>781, 10281=>781, 10282=>781, 10283=>781, 10284=>781, 10285=>781, 10286=>781, 10287=>781, 10288=>781, 10289=>781, 10290=>781, 10291=>781, 10292=>781, 10293=>781, - 10294=>781, 10295=>781, 10296=>781, 10297=>781, 10298=>781, 10299=>781, 10300=>781, 10301=>781, 10302=>781, 10303=>781, 10304=>781, 10305=>781, 10306=>781, 10307=>781, 10308=>781, 10309=>781, - 10310=>781, 10311=>781, 10312=>781, 10313=>781, 10314=>781, 10315=>781, 10316=>781, 10317=>781, 10318=>781, 10319=>781, 10320=>781, 10321=>781, 10322=>781, 10323=>781, 10324=>781, 10325=>781, - 10326=>781, 10327=>781, 10328=>781, 10329=>781, 10330=>781, 10331=>781, 10332=>781, 10333=>781, 10334=>781, 10335=>781, 10336=>781, 10337=>781, 10338=>781, 10339=>781, 10340=>781, 10341=>781, - 10342=>781, 10343=>781, 10344=>781, 10345=>781, 10346=>781, 10347=>781, 10348=>781, 10349=>781, 10350=>781, 10351=>781, 10352=>781, 10353=>781, 10354=>781, 10355=>781, 10356=>781, 10357=>781, - 10358=>781, 10359=>781, 10360=>781, 10361=>781, 10362=>781, 10363=>781, 10364=>781, 10365=>781, 10366=>781, 10367=>781, 10368=>781, 10369=>781, 10370=>781, 10371=>781, 10372=>781, 10373=>781, - 10374=>781, 10375=>781, 10376=>781, 10377=>781, 10378=>781, 10379=>781, 10380=>781, 10381=>781, 10382=>781, 10383=>781, 10384=>781, 10385=>781, 10386=>781, 10387=>781, 10388=>781, 10389=>781, - 10390=>781, 10391=>781, 10392=>781, 10393=>781, 10394=>781, 10395=>781, 10396=>781, 10397=>781, 10398=>781, 10399=>781, 10400=>781, 10401=>781, 10402=>781, 10403=>781, 10404=>781, 10405=>781, - 10406=>781, 10407=>781, 10408=>781, 10409=>781, 10410=>781, 10411=>781, 10412=>781, 10413=>781, 10414=>781, 10415=>781, 10416=>781, 10417=>781, 10418=>781, 10419=>781, 10420=>781, 10421=>781, - 10422=>781, 10423=>781, 10424=>781, 10425=>781, 10426=>781, 10427=>781, 10428=>781, 10429=>781, 10430=>781, 10431=>781, 10432=>781, 10433=>781, 10434=>781, 10435=>781, 10436=>781, 10437=>781, - 10438=>781, 10439=>781, 10440=>781, 10441=>781, 10442=>781, 10443=>781, 10444=>781, 10445=>781, 10446=>781, 10447=>781, 10448=>781, 10449=>781, 10450=>781, 10451=>781, 10452=>781, 10453=>781, - 10454=>781, 10455=>781, 10456=>781, 10457=>781, 10458=>781, 10459=>781, 10460=>781, 10461=>781, 10462=>781, 10463=>781, 10464=>781, 10465=>781, 10466=>781, 10467=>781, 10468=>781, 10469=>781, - 10470=>781, 10471=>781, 10472=>781, 10473=>781, 10474=>781, 10475=>781, 10476=>781, 10477=>781, 10478=>781, 10479=>781, 10480=>781, 10481=>781, 10482=>781, 10483=>781, 10484=>781, 10485=>781, - 10486=>781, 10487=>781, 10488=>781, 10489=>781, 10490=>781, 10491=>781, 10492=>781, 10493=>781, 10494=>781, 10495=>781, 10502=>838, 10503=>838, 10506=>838, 10507=>838, 10560=>838, 10561=>838, - 10702=>838, 10703=>1046, 10704=>1046, 10705=>1000, 10706=>1000, 10707=>1000, 10708=>1000, 10709=>1000, 10731=>494, 10752=>1000, 10753=>1000, 10754=>1000, 10764=>1661, 10765=>563, 10766=>563, 10767=>563, - 10768=>563, 10769=>563, 10770=>563, 10771=>563, 10772=>563, 10773=>563, 10774=>563, 10775=>563, 10776=>563, 10777=>563, 10778=>563, 10779=>563, 10780=>563, 10877=>838, 10878=>838, 10879=>838, - 10880=>838, 10881=>838, 10882=>838, 10883=>838, 10884=>838, 10885=>838, 10886=>838, 10887=>838, 10888=>838, 10889=>838, 10890=>838, 10891=>838, 10892=>838, 10893=>838, 10894=>838, 10895=>838, - 10896=>838, 10897=>838, 10898=>838, 10899=>838, 10900=>838, 10901=>838, 10902=>838, 10903=>838, 10904=>838, 10905=>838, 10906=>838, 10907=>838, 10908=>838, 10909=>838, 10910=>838, 10911=>838, - 10912=>838, 10926=>838, 10927=>838, 10928=>838, 10929=>838, 10930=>838, 10931=>838, 10932=>838, 10933=>838, 10934=>838, 10935=>838, 10936=>838, 10937=>838, 10938=>838, 11001=>838, 11002=>838, - 11008=>838, 11009=>838, 11010=>838, 11011=>838, 11012=>838, 11013=>838, 11014=>838, 11015=>838, 11016=>838, 11017=>838, 11018=>838, 11019=>838, 11020=>838, 11021=>838, 11022=>838, 11023=>838, - 11024=>838, 11025=>838, 11026=>945, 11027=>945, 11028=>945, 11029=>945, 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 11040=>869, 11041=>873, 11042=>873, 11043=>873, 11360=>637, - 11361=>360, 11362=>637, 11363=>733, 11364=>770, 11365=>675, 11366=>478, 11367=>956, 11368=>712, 11369=>775, 11370=>665, 11371=>725, 11372=>582, 11380=>652, 11381=>649, 11382=>516, 11383=>782, - 61960=>860, 62047=>720, 62917=>687, 64256=>833, 64257=>787, 64258=>787, 64259=>1138, 64260=>1139, 64261=>808, 64262=>1020, 64275=>1388, 64276=>1384, 64277=>1378, 64278=>1384, 64279=>1713, 64285=>372, - 64287=>692, 64288=>720, 64297=>838, 64298=>975, 64299=>975, 64300=>975, 64301=>975, 64302=>751, 64303=>751, 64304=>751, 64305=>731, 64306=>502, 64307=>684, 64308=>778, 64309=>467, 64310=>521, - 64312=>830, 64313=>467, 64314=>778, 64315=>754, 64316=>723, 64318=>868, 64320=>532, 64321=>830, 64323=>827, 64324=>866, 64326=>727, 64327=>814, 64328=>778, 64329=>975, 64330=>822, 64331=>372, - 64332=>731, 64333=>754, 64334=>866, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, - 65037=>0, 65038=>0, 65039=>0, 65533=>1113}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSans-BoldOblique.z'; - font[:ctg]='DejaVuSans-BoldOblique.ctg.z'; - font[:originalsize]=468340; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Bold.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Bold.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Bold.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Bold.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-BoldOblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-BoldOblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-BoldOblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-BoldOblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Oblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Oblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Oblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif-Oblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerif.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerif') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerif'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-770 -401 1679 1242]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>600, 32=>318, 33=>402, 34=>460, 35=>838, 36=>636, 37=>950, 38=>890, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>338, 46=>318, - 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, - 63=>536, 64=>1000, 65=>722, 66=>735, 67=>765, 68=>802, 69=>730, 70=>694, 71=>799, 72=>872, 73=>395, 74=>401, 75=>747, 76=>664, 77=>1024, 78=>875, - 79=>820, 80=>673, 81=>820, 82=>753, 83=>685, 84=>667, 85=>843, 86=>722, 87=>1028, 88=>712, 89=>660, 90=>695, 91=>390, 92=>337, 93=>390, 94=>838, - 95=>500, 96=>500, 97=>596, 98=>640, 99=>560, 100=>640, 101=>592, 102=>370, 103=>640, 104=>644, 105=>320, 106=>310, 107=>606, 108=>320, 109=>948, 110=>644, - 111=>602, 112=>640, 113=>640, 114=>478, 115=>513, 116=>402, 117=>644, 118=>565, 119=>856, 120=>564, 121=>565, 122=>527, 123=>636, 124=>337, 125=>636, 126=>838, - 8364=>636, 1027=>719, 8218=>318, 402=>370, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1342, 352=>685, 8249=>400, 338=>1137, 1036=>774, 381=>695, 1039=>872, - 8216=>318, 8217=>318, 8220=>511, 8221=>511, 8226=>590, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>513, 8250=>400, 339=>989, 1116=>625, 382=>527, 376=>660, 160=>318, - 161=>402, 162=>636, 163=>636, 164=>636, 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>475, 171=>612, 172=>838, 173=>338, 174=>1000, 175=>500, 176=>500, - 177=>838, 178=>401, 179=>401, 180=>500, 181=>650, 182=>636, 183=>318, 184=>500, 185=>401, 186=>470, 187=>612, 188=>969, 189=>969, 190=>969, 191=>536, 192=>722, - 193=>722, 194=>722, 195=>722, 196=>722, 197=>722, 198=>1001, 199=>765, 200=>730, 201=>730, 202=>730, 203=>730, 204=>395, 205=>395, 206=>395, 207=>395, 208=>807, - 209=>875, 210=>820, 211=>820, 212=>820, 213=>820, 214=>820, 215=>838, 216=>820, 217=>843, 218=>843, 219=>843, 220=>843, 221=>660, 222=>676, 223=>668, 224=>596, - 225=>596, 226=>596, 227=>596, 228=>596, 229=>596, 230=>940, 231=>560, 232=>592, 233=>592, 234=>592, 235=>592, 236=>320, 237=>320, 238=>320, 239=>320, 240=>602, - 241=>644, 242=>602, 243=>602, 244=>602, 245=>602, 246=>602, 247=>838, 248=>602, 249=>644, 250=>644, 251=>644, 252=>644, 253=>565, 254=>640, 255=>565, 256=>722, - 257=>596, 258=>722, 259=>596, 260=>722, 261=>596, 262=>765, 263=>560, 264=>765, 265=>560, 266=>765, 267=>560, 268=>765, 269=>560, 270=>802, 271=>640, 272=>807, - 273=>640, 274=>730, 275=>592, 276=>730, 277=>592, 278=>730, 279=>592, 280=>730, 281=>592, 282=>730, 283=>592, 284=>799, 285=>640, 286=>799, 287=>640, 288=>799, - 289=>640, 290=>799, 291=>640, 292=>872, 293=>644, 294=>872, 295=>644, 296=>395, 297=>320, 298=>395, 299=>320, 300=>395, 301=>320, 302=>395, 303=>320, 304=>395, - 305=>320, 306=>801, 307=>533, 308=>401, 309=>310, 310=>747, 311=>606, 312=>606, 313=>664, 314=>320, 315=>664, 316=>320, 317=>664, 318=>400, 319=>671, 320=>465, - 321=>669, 322=>324, 323=>875, 324=>644, 325=>875, 326=>644, 327=>875, 328=>644, 329=>866, 330=>875, 331=>644, 332=>820, 333=>602, 334=>820, 335=>602, 336=>820, - 337=>602, 340=>753, 341=>478, 342=>753, 343=>478, 344=>753, 345=>478, 346=>685, 347=>513, 348=>685, 349=>513, 350=>685, 351=>513, 354=>667, 355=>402, 356=>667, - 357=>402, 358=>667, 359=>402, 360=>843, 361=>644, 362=>843, 363=>644, 364=>843, 365=>644, 366=>843, 367=>644, 368=>843, 369=>644, 370=>843, 371=>644, 372=>1028, - 373=>856, 374=>660, 375=>565, 377=>695, 378=>527, 379=>695, 380=>527, 383=>370, 384=>640, 385=>735, 386=>735, 387=>640, 388=>735, 389=>640, 390=>765, 391=>765, - 392=>560, 393=>807, 394=>802, 395=>735, 396=>640, 397=>602, 398=>730, 399=>820, 400=>636, 401=>694, 403=>799, 404=>712, 405=>932, 406=>395, 407=>395, 408=>747, - 409=>606, 410=>320, 411=>634, 412=>948, 413=>875, 414=>644, 415=>820, 416=>820, 417=>602, 418=>1040, 419=>807, 420=>673, 421=>640, 422=>753, 423=>685, 424=>513, - 425=>707, 426=>324, 427=>402, 428=>667, 429=>402, 430=>667, 431=>843, 432=>644, 433=>829, 434=>760, 435=>738, 436=>663, 437=>695, 438=>527, 439=>564, 440=>564, - 441=>564, 443=>636, 444=>687, 445=>564, 446=>536, 448=>295, 449=>492, 450=>459, 451=>295, 452=>1497, 453=>1329, 454=>1167, 455=>1065, 456=>974, 457=>630, 458=>1276, - 459=>1185, 460=>954, 461=>722, 462=>596, 463=>395, 464=>320, 465=>820, 466=>602, 467=>843, 468=>644, 469=>843, 470=>644, 471=>843, 472=>644, 473=>843, 474=>644, - 475=>843, 476=>644, 477=>592, 478=>722, 479=>596, 480=>722, 481=>596, 482=>1001, 483=>940, 484=>848, 485=>640, 486=>799, 487=>640, 488=>747, 489=>606, 490=>820, - 491=>602, 492=>820, 493=>602, 494=>564, 495=>564, 496=>320, 497=>1497, 498=>1329, 499=>1167, 500=>799, 501=>640, 502=>1154, 504=>875, 505=>644, 506=>722, 507=>596, - 508=>1001, 509=>940, 510=>820, 511=>602, 512=>722, 513=>596, 514=>722, 515=>596, 516=>730, 517=>592, 518=>730, 519=>592, 520=>395, 521=>320, 522=>395, 523=>320, - 524=>820, 525=>602, 526=>820, 527=>602, 528=>753, 529=>478, 530=>753, 531=>478, 532=>843, 533=>644, 534=>843, 535=>644, 536=>685, 537=>513, 538=>667, 539=>402, - 542=>872, 543=>644, 545=>814, 548=>695, 549=>527, 550=>722, 551=>596, 552=>730, 553=>592, 554=>820, 555=>602, 556=>820, 557=>602, 558=>820, 559=>602, 560=>820, - 561=>602, 562=>660, 563=>565, 564=>500, 565=>832, 566=>494, 567=>310, 568=>960, 569=>960, 570=>722, 571=>765, 572=>560, 573=>664, 574=>667, 575=>513, 576=>527, - 577=>583, 578=>464, 581=>722, 592=>596, 593=>640, 594=>640, 595=>640, 596=>560, 597=>560, 598=>647, 599=>683, 600=>592, 601=>592, 602=>843, 603=>518, 604=>509, - 605=>773, 606=>613, 607=>315, 608=>683, 609=>640, 610=>544, 611=>712, 612=>564, 613=>644, 614=>644, 615=>644, 616=>320, 617=>392, 618=>320, 619=>380, 620=>454, - 621=>363, 622=>704, 623=>948, 624=>948, 625=>948, 626=>644, 627=>694, 628=>646, 629=>602, 630=>790, 631=>647, 632=>602, 633=>501, 634=>501, 635=>551, 636=>478, - 637=>478, 638=>453, 639=>453, 640=>594, 641=>594, 642=>513, 643=>271, 644=>370, 645=>487, 646=>324, 647=>402, 648=>402, 649=>644, 650=>620, 651=>608, 652=>565, - 653=>856, 654=>565, 655=>655, 656=>597, 657=>560, 658=>564, 659=>560, 660=>536, 661=>536, 662=>536, 663=>513, 664=>820, 665=>563, 666=>613, 667=>654, 668=>667, - 669=>366, 670=>606, 671=>646, 672=>683, 673=>536, 674=>536, 675=>996, 676=>1033, 677=>998, 678=>809, 679=>598, 680=>782, 681=>894, 682=>646, 683=>676, 684=>598, - 685=>443, 686=>781, 687=>767, 688=>433, 689=>430, 690=>264, 691=>347, 692=>347, 693=>430, 694=>392, 695=>585, 696=>423, 697=>278, 699=>318, 700=>318, 701=>318, - 702=>307, 703=>307, 704=>280, 705=>281, 711=>500, 712=>275, 713=>500, 716=>275, 720=>337, 721=>337, 722=>307, 723=>307, 726=>329, 728=>500, 729=>500, 730=>500, - 731=>500, 733=>500, 734=>417, 736=>447, 737=>243, 738=>337, 739=>424, 740=>281, 741=>602, 742=>602, 743=>602, 744=>602, 745=>602, 750=>484, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>278, 885=>278, 890=>500, 894=>337, 900=>500, 901=>500, 902=>722, 903=>318, 904=>900, 905=>1039, 906=>562, 908=>835, 910=>897, 911=>853, - 912=>392, 913=>722, 914=>735, 915=>694, 916=>722, 917=>730, 918=>695, 919=>872, 920=>820, 921=>395, 922=>747, 923=>722, 924=>1024, 925=>875, 926=>704, 927=>820, - 928=>872, 929=>673, 931=>707, 932=>667, 933=>660, 934=>820, 935=>712, 936=>877, 937=>829, 938=>395, 939=>660, 940=>675, 941=>518, 942=>599, 943=>392, 944=>608, - 945=>675, 946=>578, 947=>598, 948=>602, 949=>518, 950=>542, 951=>599, 952=>602, 953=>392, 954=>625, 955=>634, 956=>650, 957=>608, 958=>551, 959=>602, 960=>657, - 961=>588, 962=>560, 963=>683, 964=>553, 965=>608, 966=>700, 967=>606, 968=>784, 969=>815, 970=>392, 971=>608, 972=>602, 973=>608, 974=>815, 976=>583, 977=>715, - 978=>687, 979=>874, 980=>687, 981=>682, 982=>815, 983=>624, 984=>820, 985=>602, 986=>765, 987=>560, 988=>694, 989=>463, 990=>590, 991=>660, 992=>782, 993=>577, - 1008=>624, 1009=>588, 1010=>560, 1011=>310, 1012=>820, 1013=>560, 1014=>560, 1015=>676, 1016=>640, 1017=>765, 1018=>1024, 1019=>708, 1020=>588, 1021=>765, 1022=>765, 1023=>765, - 1024=>754, 1025=>709, 1026=>799, 1028=>765, 1029=>685, 1030=>395, 1031=>395, 1032=>401, 1033=>1084, 1034=>1118, 1035=>872, 1037=>903, 1038=>723, 1040=>757, 1041=>735, 1042=>735, - 1043=>662, 1044=>813, 1045=>730, 1046=>1124, 1047=>623, 1048=>872, 1049=>872, 1050=>774, 1051=>834, 1052=>1024, 1053=>872, 1054=>820, 1055=>872, 1056=>673, 1057=>765, 1058=>667, - 1059=>723, 1060=>830, 1061=>712, 1062=>872, 1063=>773, 1064=>1141, 1065=>1141, 1066=>794, 1067=>984, 1068=>674, 1069=>765, 1070=>1193, 1071=>808, 1072=>596, 1073=>602, 1074=>563, - 1075=>524, 1076=>616, 1077=>592, 1078=>920, 1079=>545, 1080=>667, 1081=>667, 1082=>625, 1083=>635, 1084=>778, 1085=>667, 1086=>602, 1087=>667, 1088=>640, 1089=>560, 1090=>553, - 1091=>588, 1092=>783, 1093=>564, 1094=>643, 1095=>661, 1096=>930, 1097=>930, 1098=>636, 1099=>796, 1100=>544, 1101=>560, 1102=>871, 1103=>631, 1104=>592, 1105=>592, 1106=>624, - 1107=>524, 1108=>560, 1109=>513, 1110=>320, 1111=>320, 1112=>310, 1113=>843, 1114=>860, 1115=>644, 1117=>667, 1118=>588, 1119=>656, 1122=>762, 1123=>603, 1138=>820, 1139=>552, - 1140=>859, 1141=>678, 1164=>690, 1165=>492, 1168=>672, 1169=>529, 1170=>694, 1171=>538, 1172=>728, 1173=>614, 1174=>1124, 1175=>920, 1176=>636, 1177=>537, 1178=>774, 1179=>606, - 1182=>774, 1183=>606, 1184=>891, 1185=>668, 1186=>872, 1187=>690, 1188=>1139, 1189=>852, 1190=>1205, 1191=>941, 1194=>765, 1195=>560, 1196=>667, 1197=>553, 1198=>660, 1199=>565, - 1202=>712, 1203=>564, 1204=>1079, 1205=>899, 1206=>749, 1207=>690, 1210=>749, 1211=>644, 1216=>395, 1217=>1124, 1218=>920, 1219=>747, 1220=>606, 1223=>872, 1224=>667, 1227=>749, - 1228=>667, 1231=>320, 1232=>757, 1233=>596, 1234=>757, 1235=>596, 1236=>1001, 1237=>940, 1238=>730, 1239=>592, 1240=>820, 1241=>592, 1242=>820, 1243=>592, 1244=>1124, 1245=>920, - 1246=>623, 1247=>545, 1248=>564, 1249=>564, 1250=>872, 1251=>667, 1252=>872, 1253=>667, 1254=>820, 1255=>602, 1256=>820, 1257=>602, 1258=>820, 1259=>602, 1260=>765, 1261=>560, - 1262=>723, 1263=>588, 1264=>723, 1265=>588, 1266=>723, 1267=>588, 1268=>773, 1269=>661, 1270=>662, 1271=>524, 1272=>984, 1273=>796, 7426=>940, 7432=>509, 7433=>320, 7444=>989, - 7446=>602, 7447=>602, 7453=>737, 7454=>948, 7455=>948, 7491=>386, 7492=>247, 7493=>400, 7494=>618, 7495=>400, 7496=>400, 7497=>387, 7498=>387, 7499=>340, 7500=>340, 7501=>400, - 7502=>175, 7503=>365, 7504=>613, 7505=>399, 7506=>385, 7507=>346, 7508=>385, 7509=>385, 7510=>400, 7511=>247, 7512=>399, 7513=>464, 7514=>613, 7515=>373, 7543=>640, 7547=>372, - 7557=>320, 7579=>400, 7580=>346, 7581=>346, 7582=>385, 7583=>340, 7584=>222, 7585=>229, 7586=>400, 7587=>399, 7588=>234, 7589=>244, 7590=>234, 7591=>234, 7592=>230, 7593=>175, - 7594=>175, 7595=>367, 7596=>613, 7597=>613, 7598=>407, 7599=>404, 7600=>399, 7601=>385, 7602=>385, 7603=>328, 7604=>211, 7605=>247, 7606=>399, 7607=>389, 7609=>376, 7610=>373, - 7611=>331, 7612=>331, 7613=>331, 7614=>364, 7615=>385, 7680=>722, 7681=>596, 7682=>735, 7683=>640, 7684=>735, 7685=>640, 7686=>735, 7687=>640, 7688=>765, 7689=>560, 7690=>802, - 7691=>640, 7692=>802, 7693=>640, 7694=>802, 7695=>640, 7696=>802, 7697=>640, 7698=>802, 7699=>640, 7700=>730, 7701=>592, 7702=>730, 7703=>592, 7704=>730, 7705=>592, 7706=>730, - 7707=>592, 7710=>694, 7711=>370, 7712=>799, 7713=>640, 7714=>872, 7715=>644, 7716=>872, 7717=>644, 7718=>872, 7719=>644, 7720=>872, 7721=>644, 7722=>872, 7723=>644, 7724=>395, - 7725=>320, 7728=>747, 7729=>606, 7730=>747, 7731=>606, 7732=>747, 7733=>606, 7734=>664, 7735=>320, 7736=>664, 7737=>320, 7738=>664, 7739=>320, 7740=>664, 7741=>320, 7742=>1024, - 7743=>948, 7744=>1024, 7745=>948, 7746=>1024, 7747=>948, 7748=>875, 7749=>644, 7750=>875, 7751=>644, 7752=>875, 7753=>644, 7754=>875, 7755=>644, 7760=>820, 7761=>602, 7762=>820, - 7763=>602, 7764=>673, 7765=>640, 7766=>673, 7767=>640, 7768=>753, 7769=>478, 7770=>753, 7771=>478, 7772=>753, 7773=>478, 7774=>753, 7775=>478, 7776=>685, 7777=>513, 7778=>685, - 7779=>513, 7784=>685, 7785=>513, 7786=>667, 7787=>402, 7788=>667, 7789=>402, 7790=>667, 7791=>402, 7792=>667, 7793=>402, 7794=>843, 7795=>644, 7796=>843, 7797=>644, 7798=>843, - 7799=>644, 7800=>843, 7801=>644, 7802=>843, 7803=>644, 7804=>722, 7805=>565, 7806=>722, 7807=>565, 7808=>1028, 7809=>856, 7810=>1028, 7811=>856, 7812=>1028, 7813=>856, 7814=>1028, - 7815=>856, 7816=>1028, 7817=>856, 7818=>712, 7819=>564, 7820=>712, 7821=>564, 7822=>660, 7823=>565, 7824=>695, 7825=>527, 7826=>695, 7827=>527, 7828=>695, 7829=>527, 7830=>644, - 7831=>402, 7832=>856, 7833=>565, 7834=>903, 7835=>513, 7840=>722, 7841=>596, 7842=>722, 7843=>596, 7852=>722, 7853=>596, 7854=>722, 7855=>596, 7856=>722, 7857=>596, 7858=>722, - 7859=>596, 7860=>722, 7861=>596, 7862=>722, 7863=>596, 7864=>730, 7865=>592, 7866=>730, 7867=>592, 7868=>730, 7869=>592, 7878=>730, 7879=>592, 7880=>395, 7881=>320, 7882=>395, - 7883=>320, 7884=>820, 7885=>602, 7886=>820, 7887=>602, 7896=>820, 7897=>602, 7908=>843, 7909=>644, 7910=>843, 7911=>644, 7922=>660, 7923=>565, 7924=>660, 7925=>565, 7926=>660, - 7927=>565, 7928=>660, 7929=>565, 7936=>675, 7937=>675, 7938=>675, 7939=>675, 7940=>675, 7941=>675, 7942=>675, 7943=>675, 7944=>722, 7945=>722, 7946=>869, 7947=>869, 7948=>734, - 7949=>763, 7950=>722, 7951=>722, 7952=>537, 7953=>537, 7954=>537, 7955=>537, 7956=>537, 7957=>537, 7960=>853, 7961=>841, 7962=>1067, 7963=>1077, 7964=>1008, 7965=>1035, 7968=>599, - 7969=>599, 7970=>599, 7971=>599, 7972=>599, 7973=>599, 7974=>599, 7975=>599, 7976=>998, 7977=>992, 7978=>1212, 7979=>1224, 7980=>1159, 7981=>1183, 7982=>1098, 7983=>1095, 7984=>392, - 7985=>392, 7986=>392, 7987=>392, 7988=>392, 7989=>392, 7990=>392, 7991=>392, 7992=>521, 7993=>512, 7994=>735, 7995=>738, 7996=>679, 7997=>706, 7998=>624, 7999=>615, 8000=>602, - 8001=>602, 8002=>602, 8003=>602, 8004=>602, 8005=>602, 8008=>820, 8009=>859, 8010=>1120, 8011=>1127, 8012=>937, 8013=>964, 8016=>608, 8017=>608, 8018=>608, 8019=>608, 8020=>608, - 8021=>608, 8022=>608, 8023=>608, 8025=>851, 8027=>1079, 8029=>1044, 8031=>953, 8032=>815, 8033=>815, 8034=>815, 8035=>815, 8036=>815, 8037=>815, 8038=>815, 8039=>815, 8040=>829, - 8041=>870, 8042=>1131, 8043=>1137, 8044=>946, 8045=>976, 8046=>938, 8047=>970, 8048=>675, 8049=>675, 8050=>537, 8051=>537, 8052=>599, 8053=>599, 8054=>392, 8055=>392, 8056=>602, - 8057=>602, 8058=>608, 8059=>608, 8060=>815, 8061=>815, 8064=>675, 8065=>675, 8066=>675, 8067=>675, 8068=>675, 8069=>675, 8070=>675, 8071=>675, 8072=>722, 8073=>722, 8074=>869, - 8075=>869, 8076=>734, 8077=>763, 8078=>722, 8079=>722, 8080=>599, 8081=>599, 8082=>599, 8083=>599, 8084=>599, 8085=>599, 8086=>599, 8087=>599, 8088=>998, 8089=>992, 8090=>1212, - 8091=>1224, 8092=>1159, 8093=>1183, 8094=>1098, 8095=>1095, 8096=>815, 8097=>815, 8098=>815, 8099=>815, 8100=>815, 8101=>815, 8102=>815, 8103=>815, 8104=>829, 8105=>870, 8106=>1131, - 8107=>1137, 8108=>946, 8109=>976, 8110=>938, 8111=>970, 8112=>675, 8113=>675, 8114=>675, 8115=>675, 8116=>675, 8118=>675, 8119=>675, 8120=>722, 8121=>722, 8122=>722, 8123=>722, - 8124=>722, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>599, 8131=>599, 8132=>599, 8134=>599, 8135=>599, 8136=>912, 8137=>900, 8138=>1063, 8139=>1039, 8140=>872, - 8141=>500, 8142=>500, 8143=>500, 8144=>392, 8145=>392, 8146=>392, 8147=>392, 8150=>392, 8151=>392, 8152=>395, 8153=>395, 8154=>588, 8155=>562, 8157=>500, 8158=>500, 8159=>500, - 8160=>608, 8161=>608, 8162=>608, 8163=>608, 8164=>588, 8165=>588, 8166=>608, 8167=>608, 8168=>660, 8169=>660, 8170=>921, 8171=>897, 8172=>790, 8173=>500, 8174=>500, 8175=>500, - 8178=>815, 8179=>815, 8180=>815, 8182=>815, 8183=>815, 8184=>961, 8185=>835, 8186=>984, 8187=>853, 8188=>829, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, - 8196=>330, 8197=>250, 8198=>167, 8199=>636, 8200=>318, 8201=>200, 8202=>100, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>338, 8209=>338, 8210=>636, 8213=>1000, - 8215=>500, 8219=>318, 8223=>511, 8227=>590, 8228=>334, 8229=>667, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1734, 8252=>527, 8253=>536, 8254=>500, - 8263=>976, 8264=>753, 8265=>753, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>401, 8308=>401, - 8309=>401, 8310=>401, 8311=>401, 8312=>401, 8313=>401, 8319=>433, 8320=>401, 8321=>401, 8322=>401, 8323=>401, 8324=>401, 8325=>401, 8326=>401, 8327=>401, 8328=>401, 8329=>401, - 8358=>660, 8367=>1057, 8369=>706, 8372=>780, 8373=>636, 8462=>644, 8470=>946, 8486=>829, 8490=>747, 8491=>722, 8531=>969, 8532=>969, 8533=>969, 8534=>969, 8535=>969, 8536=>969, - 8537=>969, 8538=>969, 8539=>969, 8540=>969, 8541=>969, 8542=>969, 8543=>568, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8706=>517, 8710=>698, 8711=>698, 8719=>796, 8721=>714, - 8722=>838, 8725=>167, 8729=>318, 8730=>637, 8733=>677, 8734=>833, 8735=>838, 8736=>838, 8743=>732, 8744=>732, 8745=>732, 8746=>732, 8747=>521, 8748=>852, 8749=>1182, 8770=>838, - 8771=>838, 8776=>838, 8800=>838, 8801=>838, 8804=>838, 8805=>838, 8962=>764, 8968=>390, 8969=>390, 8970=>390, 8971=>390, 8976=>838, 8977=>513, 8984=>1000, 8985=>838, 8992=>521, - 8993=>521, 8997=>1000, 9000=>1443, 9085=>919, 9134=>521, 9167=>945, 9251=>764, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, - 9609=>769, 9610=>769, 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, - 9625=>769, 9626=>769, 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, - 9641=>945, 9642=>678, 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, - 9657=>502, 9658=>769, 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, - 9673=>873, 9674=>494, 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>791, - 9689=>970, 9690=>970, 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>873, 9697=>873, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>590, 9703=>945, 9704=>945, - 9705=>945, 9706=>945, 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, - 9721=>769, 9722=>769, 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9784=>896, 9785=>896, 9786=>896, 9787=>896, 9788=>896, 9791=>614, 9792=>731, 9793=>731, - 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9833=>472, 9834=>638, - 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 10208=>494, 10216=>390, 10217=>390, 10731=>494, 10764=>1513, 10765=>521, 10766=>521, 11026=>945, 11027=>945, 11028=>945, 11029=>945, - 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 63173=>602, 63185=>500, 63188=>500, 64256=>811, 64257=>667, 64258=>667, 64259=>1040, 64260=>1030, 64261=>771, 64262=>933, 65024=>0, - 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65533=>1025}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerif.z'; - font[:ctg]='DejaVuSerif.ctg.z'; - font[:originalsize]=212332; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerif.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerif.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Bold.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Bold.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Bold.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Bold.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-BoldOblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-BoldOblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-BoldOblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-BoldOblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Oblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Oblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Oblique.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed-Oblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifCondensed') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerifCondensed'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-692 -401 1511 1242]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>540} - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>286, 33=>361, 34=>414, 35=>754, 36=>572, 37=>855, 38=>801, 39=>247, 40=>351, 41=>351, 42=>450, 43=>754, 44=>286, 45=>304, 46=>286, - 47=>303, 48=>572, 49=>572, 50=>572, 51=>572, 52=>572, 53=>572, 54=>572, 55=>572, 56=>572, 57=>572, 58=>303, 59=>303, 60=>754, 61=>754, 62=>754, - 63=>482, 64=>900, 65=>650, 66=>661, 67=>688, 68=>721, 69=>657, 70=>624, 71=>719, 72=>785, 73=>355, 74=>360, 75=>672, 76=>598, 77=>921, 78=>787, - 79=>738, 80=>605, 81=>738, 82=>677, 83=>616, 84=>600, 85=>758, 86=>650, 87=>925, 88=>641, 89=>594, 90=>625, 91=>351, 92=>303, 93=>351, 94=>754, - 95=>450, 96=>450, 97=>536, 98=>576, 99=>504, 100=>576, 101=>532, 102=>333, 103=>576, 104=>580, 105=>288, 106=>279, 107=>545, 108=>288, 109=>853, 110=>580, - 111=>542, 112=>576, 113=>576, 114=>430, 115=>461, 116=>361, 117=>580, 118=>508, 119=>770, 120=>507, 121=>508, 122=>474, 123=>572, 124=>303, 125=>572, 126=>754, - 8364=>572, 1027=>647, 8218=>286, 402=>333, 8222=>466, 8230=>900, 8224=>450, 8225=>450, 710=>450, 8240=>1208, 352=>616, 8249=>360, 338=>1023, 1036=>696, 381=>625, 1039=>785, - 8216=>286, 8217=>286, 8220=>460, 8221=>460, 8226=>531, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>461, 8250=>360, 339=>890, 1116=>563, 382=>474, 376=>594, 160=>286, - 161=>361, 162=>572, 163=>572, 164=>572, 165=>572, 166=>303, 167=>450, 168=>450, 169=>900, 170=>427, 171=>550, 172=>754, 173=>304, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>360, 179=>360, 180=>450, 181=>584, 182=>572, 183=>286, 184=>450, 185=>360, 186=>423, 187=>550, 188=>872, 189=>872, 190=>872, 191=>482, 192=>650, - 193=>650, 194=>650, 195=>650, 196=>650, 197=>650, 198=>901, 199=>688, 200=>657, 201=>657, 202=>657, 203=>657, 204=>355, 205=>355, 206=>355, 207=>355, 208=>726, - 209=>787, 210=>738, 211=>738, 212=>738, 213=>738, 214=>738, 215=>754, 216=>738, 217=>758, 218=>758, 219=>758, 220=>758, 221=>594, 222=>608, 223=>601, 224=>536, - 225=>536, 226=>536, 227=>536, 228=>536, 229=>536, 230=>846, 231=>504, 232=>532, 233=>532, 234=>532, 235=>532, 236=>288, 237=>288, 238=>288, 239=>288, 240=>542, - 241=>580, 242=>542, 243=>542, 244=>542, 245=>542, 246=>542, 247=>754, 248=>542, 249=>580, 250=>580, 251=>580, 252=>580, 253=>508, 254=>576, 255=>508, 256=>650, - 257=>536, 258=>650, 259=>536, 260=>650, 261=>536, 262=>688, 263=>504, 264=>688, 265=>504, 266=>688, 267=>504, 268=>688, 269=>504, 270=>721, 271=>576, 272=>726, - 273=>576, 274=>657, 275=>532, 276=>657, 277=>532, 278=>657, 279=>532, 280=>657, 281=>532, 282=>657, 283=>532, 284=>719, 285=>576, 286=>719, 287=>576, 288=>719, - 289=>576, 290=>719, 291=>576, 292=>785, 293=>580, 294=>785, 295=>580, 296=>355, 297=>288, 298=>355, 299=>288, 300=>355, 301=>288, 302=>355, 303=>288, 304=>355, - 305=>288, 306=>721, 307=>479, 308=>360, 309=>279, 310=>672, 311=>545, 312=>545, 313=>598, 314=>288, 315=>598, 316=>288, 317=>598, 318=>360, 319=>604, 320=>418, - 321=>602, 322=>292, 323=>787, 324=>580, 325=>787, 326=>580, 327=>787, 328=>580, 329=>779, 330=>787, 331=>580, 332=>738, 333=>542, 334=>738, 335=>542, 336=>738, - 337=>542, 340=>677, 341=>430, 342=>677, 343=>430, 344=>677, 345=>430, 346=>616, 347=>461, 348=>616, 349=>461, 350=>616, 351=>461, 354=>600, 355=>361, 356=>600, - 357=>361, 358=>600, 359=>361, 360=>758, 361=>580, 362=>758, 363=>580, 364=>758, 365=>580, 366=>758, 367=>580, 368=>758, 369=>580, 370=>758, 371=>580, 372=>925, - 373=>770, 374=>594, 375=>508, 377=>625, 378=>474, 379=>625, 380=>474, 383=>333, 384=>576, 385=>661, 386=>661, 387=>576, 388=>661, 389=>576, 390=>688, 391=>688, - 392=>504, 393=>726, 394=>721, 395=>661, 396=>576, 397=>542, 398=>657, 399=>738, 400=>572, 401=>624, 403=>719, 404=>641, 405=>839, 406=>355, 407=>355, 408=>672, - 409=>545, 410=>288, 411=>570, 412=>853, 413=>787, 414=>580, 415=>738, 416=>738, 417=>542, 418=>936, 419=>726, 420=>605, 421=>576, 422=>677, 423=>616, 424=>461, - 425=>636, 426=>292, 427=>361, 428=>600, 429=>361, 430=>600, 431=>758, 432=>580, 433=>746, 434=>684, 435=>664, 436=>596, 437=>625, 438=>474, 439=>508, 440=>508, - 441=>508, 443=>572, 444=>618, 445=>508, 446=>482, 448=>265, 449=>443, 450=>413, 451=>265, 452=>1347, 453=>1195, 454=>1050, 455=>958, 456=>876, 457=>567, 458=>1148, - 459=>1066, 460=>858, 461=>650, 462=>536, 463=>355, 464=>288, 465=>738, 466=>542, 467=>758, 468=>580, 469=>758, 470=>580, 471=>758, 472=>580, 473=>758, 474=>580, - 475=>758, 476=>580, 477=>532, 478=>650, 479=>536, 480=>650, 481=>536, 482=>901, 483=>846, 484=>763, 485=>576, 486=>719, 487=>576, 488=>672, 489=>545, 490=>738, - 491=>542, 492=>738, 493=>542, 494=>508, 495=>508, 496=>288, 497=>1347, 498=>1195, 499=>1050, 500=>719, 501=>576, 502=>1038, 504=>787, 505=>580, 506=>650, 507=>536, - 508=>901, 509=>846, 510=>738, 511=>542, 512=>650, 513=>536, 514=>650, 515=>536, 516=>657, 517=>532, 518=>657, 519=>532, 520=>355, 521=>288, 522=>355, 523=>288, - 524=>738, 525=>542, 526=>738, 527=>542, 528=>677, 529=>430, 530=>677, 531=>430, 532=>758, 533=>580, 534=>758, 535=>580, 536=>616, 537=>461, 538=>600, 539=>361, - 542=>785, 543=>580, 545=>732, 548=>625, 549=>474, 550=>650, 551=>536, 552=>657, 553=>532, 554=>738, 555=>542, 556=>738, 557=>542, 558=>738, 559=>542, 560=>738, - 561=>542, 562=>594, 563=>508, 564=>450, 565=>748, 566=>444, 567=>279, 568=>864, 569=>864, 570=>650, 571=>688, 572=>504, 573=>598, 574=>600, 575=>461, 576=>474, - 577=>525, 578=>417, 581=>650, 592=>536, 593=>576, 594=>576, 595=>576, 596=>504, 597=>504, 598=>582, 599=>614, 600=>532, 601=>532, 602=>759, 603=>466, 604=>458, - 605=>695, 606=>552, 607=>283, 608=>615, 609=>576, 610=>489, 611=>641, 612=>507, 613=>580, 614=>580, 615=>580, 616=>288, 617=>353, 618=>288, 619=>342, 620=>409, - 621=>326, 622=>633, 623=>853, 624=>853, 625=>853, 626=>579, 627=>624, 628=>581, 629=>542, 630=>711, 631=>583, 632=>542, 633=>451, 634=>451, 635=>496, 636=>430, - 637=>430, 638=>407, 639=>407, 640=>534, 641=>534, 642=>461, 643=>244, 644=>333, 645=>438, 646=>292, 647=>361, 648=>361, 649=>580, 650=>558, 651=>547, 652=>508, - 653=>770, 654=>508, 655=>589, 656=>537, 657=>504, 658=>508, 659=>504, 660=>482, 661=>482, 662=>482, 663=>461, 664=>738, 665=>506, 666=>552, 667=>588, 668=>600, - 669=>329, 670=>545, 671=>581, 672=>615, 673=>482, 674=>482, 675=>896, 676=>930, 677=>898, 678=>728, 679=>538, 680=>704, 681=>804, 682=>582, 683=>608, 684=>538, - 685=>398, 686=>703, 687=>690, 688=>389, 689=>387, 690=>237, 691=>312, 692=>312, 693=>387, 694=>352, 695=>527, 696=>381, 697=>250, 699=>286, 700=>286, 701=>286, - 702=>276, 703=>276, 704=>252, 705=>252, 711=>450, 712=>247, 713=>450, 716=>247, 720=>303, 721=>303, 722=>276, 723=>276, 726=>295, 728=>450, 729=>450, 730=>450, - 731=>450, 733=>450, 734=>375, 736=>402, 737=>218, 738=>303, 739=>381, 740=>252, 741=>542, 742=>542, 743=>542, 744=>542, 745=>542, 750=>435, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>250, 885=>250, 890=>450, 894=>303, 900=>450, 901=>450, 902=>650, 903=>286, 904=>810, 905=>935, 906=>505, 908=>751, 910=>808, 911=>767, - 912=>353, 913=>650, 914=>661, 915=>624, 916=>650, 917=>657, 918=>625, 919=>785, 920=>738, 921=>355, 922=>672, 923=>650, 924=>921, 925=>787, 926=>633, 927=>738, - 928=>785, 929=>605, 931=>636, 932=>600, 933=>594, 934=>738, 935=>641, 936=>789, 937=>746, 938=>355, 939=>594, 940=>607, 941=>466, 942=>539, 943=>353, 944=>547, - 945=>607, 946=>520, 947=>538, 948=>542, 949=>466, 950=>488, 951=>539, 952=>542, 953=>353, 954=>563, 955=>570, 956=>584, 957=>547, 958=>496, 959=>542, 960=>591, - 961=>529, 962=>504, 963=>614, 964=>498, 965=>547, 966=>630, 967=>545, 968=>706, 969=>734, 970=>353, 971=>547, 972=>542, 973=>547, 974=>734, 976=>524, 977=>643, - 978=>618, 979=>787, 980=>618, 981=>613, 982=>734, 983=>561, 984=>738, 985=>542, 986=>688, 987=>504, 988=>624, 989=>417, 990=>531, 991=>593, 992=>704, 993=>519, - 1008=>561, 1009=>529, 1010=>504, 1011=>279, 1012=>738, 1013=>504, 1014=>504, 1015=>608, 1016=>576, 1017=>688, 1018=>921, 1019=>637, 1020=>529, 1021=>688, 1022=>688, 1023=>688, - 1024=>678, 1025=>638, 1026=>719, 1028=>688, 1029=>616, 1030=>355, 1031=>355, 1032=>360, 1033=>976, 1034=>1006, 1035=>785, 1037=>813, 1038=>650, 1040=>681, 1041=>661, 1042=>661, - 1043=>596, 1044=>731, 1045=>657, 1046=>1011, 1047=>561, 1048=>785, 1049=>785, 1050=>696, 1051=>751, 1052=>921, 1053=>785, 1054=>738, 1055=>785, 1056=>605, 1057=>688, 1058=>600, - 1059=>650, 1060=>747, 1061=>641, 1062=>785, 1063=>695, 1064=>1027, 1065=>1027, 1066=>715, 1067=>885, 1068=>606, 1069=>688, 1070=>1074, 1071=>727, 1072=>536, 1073=>542, 1074=>506, - 1075=>471, 1076=>554, 1077=>532, 1078=>828, 1079=>491, 1080=>600, 1081=>600, 1082=>563, 1083=>571, 1084=>700, 1085=>600, 1086=>542, 1087=>600, 1088=>576, 1089=>504, 1090=>498, - 1091=>529, 1092=>704, 1093=>507, 1094=>579, 1095=>595, 1096=>836, 1097=>836, 1098=>572, 1099=>716, 1100=>490, 1101=>504, 1102=>783, 1103=>567, 1104=>532, 1105=>532, 1106=>561, - 1107=>471, 1108=>504, 1109=>461, 1110=>288, 1111=>288, 1112=>279, 1113=>759, 1114=>774, 1115=>580, 1117=>600, 1118=>529, 1119=>590, 1122=>686, 1123=>542, 1138=>738, 1139=>497, - 1140=>773, 1141=>610, 1164=>621, 1165=>442, 1168=>604, 1169=>476, 1170=>624, 1171=>483, 1172=>655, 1173=>552, 1174=>1011, 1175=>828, 1176=>572, 1177=>483, 1178=>696, 1179=>545, - 1182=>696, 1183=>545, 1184=>801, 1185=>602, 1186=>785, 1187=>621, 1188=>1025, 1189=>767, 1190=>1084, 1191=>847, 1194=>688, 1195=>504, 1196=>600, 1197=>498, 1198=>594, 1199=>508, - 1202=>641, 1203=>507, 1204=>971, 1205=>809, 1206=>674, 1207=>621, 1210=>674, 1211=>580, 1216=>355, 1217=>1011, 1218=>828, 1219=>672, 1220=>545, 1223=>785, 1224=>600, 1227=>674, - 1228=>600, 1231=>288, 1232=>681, 1233=>536, 1234=>681, 1235=>536, 1236=>901, 1237=>846, 1238=>657, 1239=>532, 1240=>738, 1241=>532, 1242=>738, 1243=>532, 1244=>1011, 1245=>828, - 1246=>561, 1247=>491, 1248=>508, 1249=>508, 1250=>785, 1251=>600, 1252=>785, 1253=>600, 1254=>738, 1255=>542, 1256=>738, 1257=>542, 1258=>738, 1259=>542, 1260=>688, 1261=>504, - 1262=>650, 1263=>529, 1264=>650, 1265=>529, 1266=>650, 1267=>529, 1268=>695, 1269=>595, 1270=>596, 1271=>471, 1272=>885, 1273=>716, 7426=>846, 7432=>458, 7433=>288, 7444=>890, - 7446=>542, 7447=>542, 7453=>663, 7454=>853, 7455=>853, 7491=>347, 7492=>222, 7493=>360, 7494=>556, 7495=>360, 7496=>360, 7497=>348, 7498=>348, 7499=>306, 7500=>306, 7501=>360, - 7502=>157, 7503=>328, 7504=>552, 7505=>359, 7506=>347, 7507=>312, 7508=>347, 7509=>347, 7510=>360, 7511=>222, 7512=>359, 7513=>417, 7514=>552, 7515=>335, 7543=>576, 7547=>334, - 7557=>288, 7579=>360, 7580=>312, 7581=>312, 7582=>347, 7583=>306, 7584=>199, 7585=>206, 7586=>360, 7587=>359, 7588=>210, 7589=>219, 7590=>210, 7591=>210, 7592=>207, 7593=>158, - 7594=>157, 7595=>330, 7596=>552, 7597=>552, 7598=>366, 7599=>364, 7600=>359, 7601=>347, 7602=>347, 7603=>295, 7604=>190, 7605=>222, 7606=>359, 7607=>350, 7609=>338, 7610=>335, - 7611=>297, 7612=>297, 7613=>297, 7614=>327, 7615=>347, 7680=>650, 7681=>536, 7682=>661, 7683=>576, 7684=>661, 7685=>576, 7686=>661, 7687=>576, 7688=>688, 7689=>504, 7690=>721, - 7691=>576, 7692=>721, 7693=>576, 7694=>721, 7695=>576, 7696=>721, 7697=>576, 7698=>721, 7699=>576, 7700=>657, 7701=>532, 7702=>657, 7703=>532, 7704=>657, 7705=>532, 7706=>657, - 7707=>532, 7710=>624, 7711=>333, 7712=>719, 7713=>576, 7714=>785, 7715=>580, 7716=>785, 7717=>580, 7718=>785, 7719=>580, 7720=>785, 7721=>580, 7722=>785, 7723=>580, 7724=>355, - 7725=>288, 7728=>672, 7729=>545, 7730=>672, 7731=>545, 7732=>672, 7733=>545, 7734=>598, 7735=>288, 7736=>598, 7737=>288, 7738=>598, 7739=>288, 7740=>598, 7741=>288, 7742=>921, - 7743=>853, 7744=>921, 7745=>853, 7746=>921, 7747=>853, 7748=>787, 7749=>580, 7750=>787, 7751=>580, 7752=>787, 7753=>580, 7754=>787, 7755=>580, 7760=>738, 7761=>542, 7762=>738, - 7763=>542, 7764=>605, 7765=>576, 7766=>605, 7767=>576, 7768=>677, 7769=>430, 7770=>677, 7771=>430, 7772=>677, 7773=>430, 7774=>677, 7775=>430, 7776=>616, 7777=>461, 7778=>616, - 7779=>461, 7784=>616, 7785=>461, 7786=>600, 7787=>361, 7788=>600, 7789=>361, 7790=>600, 7791=>361, 7792=>600, 7793=>361, 7794=>758, 7795=>580, 7796=>758, 7797=>580, 7798=>758, - 7799=>580, 7800=>758, 7801=>580, 7802=>758, 7803=>580, 7804=>650, 7805=>508, 7806=>650, 7807=>508, 7808=>925, 7809=>770, 7810=>925, 7811=>770, 7812=>925, 7813=>770, 7814=>925, - 7815=>770, 7816=>925, 7817=>770, 7818=>641, 7819=>507, 7820=>641, 7821=>507, 7822=>594, 7823=>508, 7824=>625, 7825=>474, 7826=>625, 7827=>474, 7828=>625, 7829=>474, 7830=>580, - 7831=>361, 7832=>770, 7833=>508, 7834=>813, 7835=>461, 7840=>650, 7841=>536, 7842=>650, 7843=>536, 7852=>650, 7853=>536, 7854=>650, 7855=>536, 7856=>650, 7857=>536, 7858=>650, - 7859=>536, 7860=>650, 7861=>536, 7862=>650, 7863=>536, 7864=>657, 7865=>532, 7866=>657, 7867=>532, 7868=>657, 7869=>532, 7878=>657, 7879=>532, 7880=>355, 7881=>288, 7882=>355, - 7883=>288, 7884=>738, 7885=>542, 7886=>738, 7887=>542, 7896=>738, 7897=>542, 7908=>758, 7909=>580, 7910=>758, 7911=>580, 7922=>594, 7923=>508, 7924=>594, 7925=>508, 7926=>594, - 7927=>508, 7928=>594, 7929=>508, 7936=>607, 7937=>607, 7938=>607, 7939=>607, 7940=>607, 7941=>607, 7942=>607, 7943=>607, 7944=>650, 7945=>650, 7946=>782, 7947=>782, 7948=>660, - 7949=>687, 7950=>650, 7951=>650, 7952=>483, 7953=>483, 7954=>483, 7955=>483, 7956=>483, 7957=>483, 7960=>768, 7961=>757, 7962=>960, 7963=>969, 7964=>907, 7965=>931, 7968=>539, - 7969=>539, 7970=>539, 7971=>539, 7972=>539, 7973=>539, 7974=>539, 7975=>539, 7976=>898, 7977=>893, 7978=>1090, 7979=>1101, 7980=>1043, 7981=>1064, 7982=>988, 7983=>985, 7984=>353, - 7985=>353, 7986=>353, 7987=>353, 7988=>353, 7989=>353, 7990=>353, 7991=>353, 7992=>469, 7993=>461, 7994=>661, 7995=>664, 7996=>611, 7997=>635, 7998=>561, 7999=>553, 8000=>542, - 8001=>542, 8002=>542, 8003=>542, 8004=>542, 8005=>542, 8008=>738, 8009=>773, 8010=>1008, 8011=>1015, 8012=>843, 8013=>867, 8016=>547, 8017=>547, 8018=>547, 8019=>547, 8020=>547, - 8021=>547, 8022=>547, 8023=>547, 8025=>765, 8027=>971, 8029=>939, 8031=>857, 8032=>734, 8033=>734, 8034=>734, 8035=>734, 8036=>734, 8037=>734, 8038=>734, 8039=>734, 8040=>746, - 8041=>783, 8042=>1018, 8043=>1023, 8044=>852, 8045=>878, 8046=>844, 8047=>873, 8048=>607, 8049=>607, 8050=>483, 8051=>483, 8052=>539, 8053=>539, 8054=>353, 8055=>353, 8056=>542, - 8057=>542, 8058=>547, 8059=>547, 8060=>734, 8061=>734, 8064=>607, 8065=>607, 8066=>607, 8067=>607, 8068=>607, 8069=>607, 8070=>607, 8071=>607, 8072=>650, 8073=>650, 8074=>782, - 8075=>782, 8076=>660, 8077=>687, 8078=>650, 8079=>650, 8080=>539, 8081=>539, 8082=>539, 8083=>539, 8084=>539, 8085=>539, 8086=>539, 8087=>539, 8088=>898, 8089=>893, 8090=>1090, - 8091=>1101, 8092=>1043, 8093=>1064, 8094=>988, 8095=>985, 8096=>734, 8097=>734, 8098=>734, 8099=>734, 8100=>734, 8101=>734, 8102=>734, 8103=>734, 8104=>746, 8105=>783, 8106=>1018, - 8107=>1023, 8108=>852, 8109=>878, 8110=>844, 8111=>873, 8112=>607, 8113=>607, 8114=>607, 8115=>607, 8116=>607, 8118=>607, 8119=>607, 8120=>650, 8121=>650, 8122=>650, 8123=>650, - 8124=>650, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>539, 8131=>539, 8132=>539, 8134=>539, 8135=>539, 8136=>820, 8137=>810, 8138=>956, 8139=>935, 8140=>785, - 8141=>450, 8142=>450, 8143=>450, 8144=>353, 8145=>353, 8146=>353, 8147=>353, 8150=>353, 8151=>353, 8152=>355, 8153=>355, 8154=>529, 8155=>505, 8157=>450, 8158=>450, 8159=>450, - 8160=>547, 8161=>547, 8162=>547, 8163=>547, 8164=>529, 8165=>529, 8166=>547, 8167=>547, 8168=>594, 8169=>594, 8170=>829, 8171=>808, 8172=>711, 8173=>450, 8174=>450, 8175=>450, - 8178=>734, 8179=>734, 8180=>734, 8182=>734, 8183=>734, 8184=>865, 8185=>751, 8186=>886, 8187=>767, 8188=>746, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, - 8196=>296, 8197=>225, 8198=>150, 8199=>572, 8200=>286, 8201=>180, 8202=>89, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>304, 8209=>304, 8210=>572, 8213=>900, - 8215=>450, 8219=>286, 8223=>460, 8227=>531, 8228=>300, 8229=>600, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1560, 8252=>475, 8253=>482, 8254=>450, - 8263=>878, 8264=>678, 8265=>678, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>360, 8308=>360, - 8309=>360, 8310=>360, 8311=>360, 8312=>360, 8313=>360, 8319=>389, 8320=>360, 8321=>360, 8322=>360, 8323=>360, 8324=>360, 8325=>360, 8326=>360, 8327=>360, 8328=>360, 8329=>360, - 8358=>594, 8367=>951, 8369=>635, 8372=>702, 8373=>572, 8462=>580, 8470=>852, 8486=>746, 8490=>672, 8491=>650, 8531=>872, 8532=>872, 8533=>872, 8534=>872, 8535=>872, 8536=>872, - 8537=>872, 8538=>872, 8539=>872, 8540=>872, 8541=>872, 8542=>872, 8543=>511, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8706=>465, 8710=>628, 8711=>628, 8719=>716, 8721=>642, - 8722=>754, 8725=>150, 8729=>286, 8730=>573, 8733=>609, 8734=>750, 8735=>754, 8736=>754, 8743=>659, 8744=>659, 8745=>659, 8746=>659, 8747=>469, 8748=>766, 8749=>1063, 8770=>754, - 8771=>754, 8776=>754, 8800=>754, 8801=>754, 8804=>754, 8805=>754, 8962=>687, 8968=>351, 8969=>351, 8970=>351, 8971=>351, 8976=>754, 8977=>461, 8984=>900, 8985=>754, 8992=>469, - 8993=>469, 8997=>900, 9000=>1299, 9085=>827, 9134=>469, 9167=>850, 9251=>687, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, - 9609=>692, 9610=>692, 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, - 9625=>692, 9626=>692, 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, - 9641=>850, 9642=>610, 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, - 9657=>452, 9658=>692, 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, - 9673=>785, 9674=>444, 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>712, - 9689=>873, 9690=>873, 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>785, 9697=>785, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>531, 9703=>850, 9704=>850, - 9705=>850, 9706=>850, 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, - 9721=>692, 9722=>692, 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9784=>807, 9785=>807, 9786=>807, 9787=>807, 9788=>807, 9791=>552, 9792=>658, 9793=>658, - 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 10208=>444, 10216=>351, 10217=>351, 10731=>444, 10764=>1361, 10765=>469, 10766=>469, 11026=>850, 11027=>850, 11028=>850, 11029=>850, - 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 63173=>542, 63185=>450, 63188=>450, 64256=>729, 64257=>600, 64258=>600, 64259=>936, 64260=>927, 64261=>694, 64262=>839, 65024=>0, - 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65533=>923} - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerifCondensed.z'; - font[:ctg]='DejaVuSerifCondensed.ctg.z'; - font[:originalsize]=176080; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed.z Binary file vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensed.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensedb.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensedb.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifCondensedb') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerifCondensed-Bold'; - font[:desc]={'Ascent'=>939,'Descent'=>-236,'CapHeight'=>939,'Flags'=>32,'FontBBox'=>'[-752 -423 1616 1235]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>540} - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>313, 33=>395, 34=>469, 35=>754, 36=>626, 37=>855, 38=>813, 39=>275, 40=>426, 41=>426, 42=>470, 43=>754, 44=>313, 45=>374, 46=>313, - 47=>329, 48=>626, 49=>626, 50=>626, 51=>626, 52=>626, 53=>626, 54=>626, 55=>626, 56=>626, 57=>626, 58=>332, 59=>332, 60=>754, 61=>754, 62=>754, - 63=>527, 64=>900, 65=>698, 66=>760, 67=>716, 68=>780, 69=>686, 70=>639, 71=>769, 72=>850, 73=>421, 74=>426, 75=>782, 76=>633, 77=>996, 78=>822, - 79=>784, 80=>677, 81=>784, 82=>748, 83=>650, 84=>669, 85=>785, 86=>698, 87=>1011, 88=>698, 89=>642, 90=>657, 91=>426, 92=>329, 93=>426, 94=>754, - 95=>450, 96=>450, 97=>583, 98=>629, 99=>548, 100=>629, 101=>572, 102=>387, 103=>629, 104=>654, 105=>342, 106=>325, 107=>624, 108=>342, 109=>952, 110=>654, - 111=>600, 112=>629, 113=>629, 114=>474, 115=>506, 116=>416, 117=>654, 118=>523, 119=>774, 120=>536, 121=>523, 122=>511, 123=>579, 124=>327, 125=>579, 126=>754, - 8364=>626, 1027=>621, 8218=>313, 402=>387, 8222=>518, 8230=>900, 8224=>470, 8225=>470, 710=>450, 8240=>1246, 352=>650, 8249=>360, 338=>1062, 1036=>818, 381=>657, 1039=>850, - 8216=>313, 8217=>313, 8220=>518, 8221=>518, 8226=>575, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>506, 8250=>360, 339=>925, 1116=>650, 382=>511, 376=>642, 160=>313, - 161=>395, 162=>626, 163=>626, 164=>572, 165=>626, 166=>327, 167=>470, 168=>450, 169=>900, 170=>438, 171=>563, 172=>754, 173=>374, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>394, 179=>394, 180=>450, 181=>659, 182=>572, 183=>313, 184=>450, 185=>394, 186=>450, 187=>563, 188=>938, 189=>938, 190=>938, 191=>527, 192=>698, - 193=>698, 194=>698, 195=>698, 196=>698, 197=>698, 198=>931, 199=>716, 200=>686, 201=>686, 202=>686, 203=>686, 204=>421, 205=>421, 206=>421, 207=>421, 208=>787, - 209=>822, 210=>784, 211=>784, 212=>784, 213=>784, 214=>784, 215=>754, 216=>784, 217=>785, 218=>785, 219=>785, 220=>785, 221=>642, 222=>681, 223=>684, 224=>583, - 225=>583, 226=>583, 227=>583, 228=>583, 229=>583, 230=>877, 231=>548, 232=>572, 233=>572, 234=>572, 235=>572, 236=>342, 237=>342, 238=>342, 239=>342, 240=>600, - 241=>654, 242=>600, 243=>600, 244=>600, 245=>600, 246=>600, 247=>754, 248=>600, 249=>654, 250=>654, 251=>654, 252=>654, 253=>523, 254=>629, 255=>523, 256=>698, - 257=>583, 258=>698, 259=>583, 260=>698, 261=>583, 262=>716, 263=>548, 264=>716, 265=>548, 266=>716, 267=>548, 268=>716, 269=>548, 270=>780, 271=>629, 272=>787, - 273=>629, 274=>686, 275=>572, 276=>686, 277=>572, 278=>686, 279=>572, 280=>686, 281=>572, 282=>686, 283=>572, 284=>769, 285=>629, 286=>769, 287=>629, 288=>769, - 289=>629, 290=>769, 291=>629, 292=>850, 293=>654, 294=>850, 295=>654, 296=>421, 297=>342, 298=>421, 299=>342, 300=>421, 301=>342, 302=>421, 303=>342, 304=>421, - 305=>342, 306=>848, 307=>676, 308=>426, 309=>325, 310=>782, 311=>624, 312=>624, 313=>633, 314=>342, 315=>633, 316=>342, 317=>633, 318=>457, 319=>633, 320=>501, - 321=>639, 322=>346, 323=>822, 324=>654, 325=>822, 326=>654, 327=>822, 328=>654, 329=>907, 330=>822, 331=>654, 332=>784, 333=>600, 334=>784, 335=>600, 336=>784, - 337=>600, 340=>748, 341=>474, 342=>748, 343=>474, 344=>748, 345=>474, 346=>650, 347=>506, 348=>650, 349=>506, 350=>650, 351=>506, 354=>669, 355=>416, 356=>669, - 357=>416, 358=>669, 359=>416, 360=>785, 361=>654, 362=>785, 363=>654, 364=>785, 365=>654, 366=>785, 367=>654, 368=>785, 369=>654, 370=>785, 371=>654, 372=>1011, - 373=>774, 374=>642, 375=>523, 377=>657, 378=>511, 379=>657, 380=>511, 383=>387, 384=>629, 385=>760, 386=>769, 387=>629, 388=>769, 389=>629, 390=>716, 391=>716, - 392=>548, 393=>787, 394=>780, 395=>769, 396=>629, 397=>600, 398=>686, 399=>784, 400=>626, 401=>639, 403=>769, 404=>693, 405=>938, 406=>421, 407=>421, 408=>782, - 409=>624, 410=>342, 411=>631, 412=>952, 413=>822, 414=>654, 415=>784, 416=>784, 417=>600, 418=>1080, 419=>849, 420=>677, 421=>629, 422=>748, 423=>650, 424=>506, - 425=>636, 426=>298, 427=>416, 428=>669, 429=>416, 430=>669, 431=>785, 432=>654, 433=>801, 434=>801, 435=>642, 436=>637, 437=>657, 438=>511, 439=>511, 440=>511, - 441=>511, 443=>626, 444=>678, 445=>511, 446=>482, 448=>265, 449=>443, 450=>413, 451=>265, 452=>1437, 453=>1292, 454=>1140, 455=>1059, 456=>958, 457=>667, 458=>1248, - 459=>1148, 460=>980, 461=>698, 462=>583, 463=>421, 464=>342, 465=>784, 466=>600, 467=>785, 468=>654, 469=>785, 470=>654, 471=>785, 472=>654, 473=>785, 474=>654, - 475=>785, 476=>654, 477=>572, 478=>698, 479=>583, 480=>698, 481=>583, 482=>931, 483=>877, 484=>806, 485=>629, 486=>769, 487=>629, 488=>782, 489=>624, 490=>784, - 491=>600, 492=>784, 493=>600, 494=>511, 495=>511, 496=>342, 497=>1437, 498=>1292, 499=>1140, 500=>769, 501=>629, 502=>1099, 504=>822, 505=>654, 506=>698, 507=>583, - 508=>931, 509=>877, 510=>784, 511=>600, 512=>698, 513=>583, 514=>698, 515=>583, 516=>686, 517=>572, 518=>686, 519=>572, 520=>421, 521=>342, 522=>421, 523=>342, - 524=>784, 525=>600, 526=>784, 527=>600, 528=>748, 529=>474, 530=>748, 531=>474, 532=>785, 533=>654, 534=>785, 535=>654, 536=>650, 537=>506, 538=>669, 539=>416, - 542=>850, 543=>654, 545=>711, 548=>657, 549=>511, 550=>698, 551=>583, 552=>686, 553=>572, 554=>784, 555=>600, 556=>784, 557=>600, 558=>784, 559=>600, 560=>784, - 561=>600, 562=>642, 563=>523, 564=>516, 565=>830, 566=>508, 567=>325, 568=>928, 569=>928, 570=>698, 571=>716, 572=>548, 573=>633, 574=>669, 575=>506, 576=>511, - 577=>594, 578=>492, 581=>698, 592=>583, 593=>629, 594=>629, 595=>629, 596=>548, 597=>548, 598=>629, 599=>657, 600=>572, 601=>572, 602=>816, 603=>547, 604=>505, - 605=>816, 606=>647, 607=>348, 608=>629, 609=>629, 610=>563, 611=>641, 612=>564, 613=>654, 614=>654, 615=>654, 616=>342, 617=>342, 618=>342, 619=>368, 620=>462, - 621=>342, 622=>716, 623=>952, 624=>952, 625=>952, 626=>654, 627=>654, 628=>641, 629=>600, 630=>955, 631=>674, 632=>600, 633=>514, 634=>514, 635=>514, 636=>474, - 637=>474, 638=>406, 639=>438, 640=>721, 641=>721, 642=>506, 643=>298, 644=>387, 645=>486, 646=>298, 647=>443, 648=>416, 649=>654, 650=>611, 651=>624, 652=>577, - 653=>816, 654=>571, 655=>654, 656=>511, 657=>511, 658=>511, 659=>511, 660=>482, 661=>482, 662=>482, 663=>490, 664=>784, 665=>625, 666=>647, 667=>563, 668=>659, - 669=>345, 670=>666, 671=>581, 672=>629, 673=>482, 674=>482, 675=>1005, 676=>1061, 677=>1005, 678=>819, 679=>643, 680=>817, 681=>935, 682=>711, 683=>716, 684=>596, - 685=>398, 686=>552, 687=>646, 688=>469, 689=>466, 690=>282, 691=>372, 692=>372, 693=>432, 694=>474, 695=>595, 696=>436, 697=>271, 699=>313, 700=>313, 701=>313, - 702=>330, 703=>330, 704=>282, 705=>282, 711=>450, 712=>254, 713=>450, 716=>254, 720=>332, 721=>332, 722=>330, 723=>330, 726=>353, 728=>450, 729=>450, 730=>450, - 731=>450, 733=>450, 734=>375, 736=>412, 737=>263, 738=>355, 739=>427, 740=>282, 741=>436, 742=>436, 743=>436, 744=>436, 745=>436, 750=>498, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>271, 885=>271, 890=>450, 894=>332, 900=>450, 901=>450, 902=>698, 903=>313, 904=>852, 905=>1006, 906=>595, 908=>798, 910=>857, 911=>820, - 912=>435, 913=>698, 914=>760, 915=>639, 916=>698, 917=>686, 918=>657, 919=>850, 920=>784, 921=>421, 922=>782, 923=>698, 924=>996, 925=>822, 926=>633, 927=>784, - 928=>850, 929=>677, 931=>636, 932=>669, 933=>642, 934=>784, 935=>698, 936=>822, 937=>801, 938=>421, 939=>642, 940=>692, 941=>547, 942=>654, 943=>435, 944=>624, - 945=>692, 946=>598, 947=>594, 948=>600, 949=>547, 950=>533, 951=>654, 952=>600, 953=>435, 954=>674, 955=>631, 956=>659, 957=>624, 958=>533, 959=>600, 960=>659, - 961=>598, 962=>548, 963=>664, 964=>605, 965=>624, 966=>814, 967=>592, 968=>847, 969=>857, 970=>435, 971=>624, 972=>600, 973=>624, 974=>857, 976=>600, 977=>764, - 978=>687, 979=>872, 980=>687, 981=>847, 982=>857, 983=>589, 984=>784, 985=>600, 986=>716, 987=>548, 988=>639, 989=>475, 990=>531, 991=>593, 992=>716, 993=>600, - 1008=>589, 1009=>598, 1010=>548, 1011=>325, 1012=>784, 1013=>548, 1014=>548, 1015=>681, 1016=>629, 1017=>716, 1018=>996, 1019=>774, 1020=>623, 1021=>716, 1022=>716, 1023=>716, - 1024=>686, 1025=>686, 1026=>811, 1028=>716, 1029=>650, 1030=>421, 1031=>421, 1032=>426, 1033=>1081, 1034=>1135, 1035=>866, 1037=>850, 1038=>730, 1040=>733, 1041=>769, 1042=>760, - 1043=>621, 1044=>800, 1045=>686, 1046=>1181, 1047=>649, 1048=>850, 1049=>850, 1050=>818, 1051=>795, 1052=>996, 1053=>850, 1054=>784, 1055=>850, 1056=>677, 1057=>716, 1058=>669, - 1059=>730, 1060=>854, 1061=>698, 1062=>870, 1063=>822, 1064=>1141, 1065=>1164, 1066=>861, 1067=>1081, 1068=>743, 1069=>716, 1070=>1158, 1071=>793, 1072=>583, 1073=>600, 1074=>625, - 1075=>551, 1076=>600, 1077=>572, 1078=>909, 1079=>574, 1080=>667, 1081=>667, 1082=>650, 1083=>634, 1084=>782, 1085=>659, 1086=>600, 1087=>659, 1088=>629, 1089=>548, 1090=>558, - 1091=>576, 1092=>812, 1093=>536, 1094=>665, 1095=>659, 1096=>967, 1097=>974, 1098=>690, 1099=>902, 1100=>611, 1101=>548, 1102=>923, 1103=>665, 1104=>572, 1105=>572, 1106=>646, - 1107=>551, 1108=>548, 1109=>506, 1110=>342, 1111=>342, 1112=>325, 1113=>871, 1114=>896, 1115=>654, 1117=>667, 1118=>576, 1119=>659, 1122=>792, 1123=>633, 1138=>784, 1139=>587, - 1140=>824, 1141=>673, 1164=>712, 1165=>598, 1168=>630, 1169=>556, 1170=>639, 1171=>573, 1172=>781, 1173=>645, 1174=>1181, 1175=>909, 1176=>649, 1177=>574, 1178=>852, 1179=>669, - 1182=>818, 1183=>624, 1184=>899, 1185=>660, 1186=>870, 1187=>665, 1188=>1068, 1189=>882, 1190=>1210, 1191=>953, 1194=>716, 1195=>548, 1196=>669, 1197=>558, 1198=>642, 1199=>523, - 1202=>779, 1203=>584, 1204=>1125, 1205=>896, 1206=>835, 1207=>665, 1210=>819, 1211=>654, 1216=>421, 1217=>1181, 1218=>909, 1219=>782, 1220=>624, 1223=>850, 1224=>659, 1227=>822, - 1228=>659, 1231=>342, 1232=>733, 1233=>583, 1234=>733, 1235=>583, 1236=>931, 1237=>877, 1238=>686, 1239=>572, 1240=>784, 1241=>572, 1242=>784, 1243=>572, 1244=>1181, 1245=>909, - 1246=>649, 1247=>574, 1248=>511, 1249=>511, 1250=>850, 1251=>667, 1252=>850, 1253=>667, 1254=>784, 1255=>600, 1256=>784, 1257=>600, 1258=>784, 1259=>600, 1260=>716, 1261=>548, - 1262=>730, 1263=>576, 1264=>730, 1265=>576, 1266=>730, 1267=>576, 1268=>822, 1269=>659, 1270=>621, 1271=>551, 1272=>1081, 1273=>902, 7426=>846, 7432=>458, 7433=>288, 7444=>890, - 7446=>600, 7447=>600, 7453=>663, 7454=>853, 7455=>853, 7491=>419, 7492=>419, 7493=>448, 7494=>591, 7495=>448, 7496=>448, 7497=>400, 7498=>400, 7499=>370, 7500=>370, 7501=>448, - 7502=>270, 7503=>471, 7504=>655, 7505=>426, 7506=>420, 7507=>384, 7508=>420, 7509=>420, 7510=>448, 7511=>333, 7512=>468, 7513=>390, 7514=>655, 7515=>442, 7543=>576, 7547=>342, - 7557=>342, 7579=>448, 7580=>384, 7581=>384, 7582=>420, 7583=>370, 7584=>345, 7585=>335, 7586=>448, 7587=>470, 7588=>270, 7589=>276, 7590=>270, 7591=>270, 7592=>333, 7593=>331, - 7594=>289, 7595=>387, 7596=>613, 7597=>655, 7598=>529, 7599=>528, 7600=>425, 7601=>420, 7602=>470, 7603=>360, 7604=>348, 7605=>333, 7606=>468, 7607=>427, 7609=>439, 7610=>442, - 7611=>371, 7612=>474, 7613=>371, 7614=>407, 7615=>420, 7680=>698, 7681=>583, 7682=>760, 7683=>629, 7684=>760, 7685=>629, 7686=>760, 7687=>629, 7688=>716, 7689=>548, 7690=>780, - 7691=>629, 7692=>780, 7693=>629, 7694=>780, 7695=>629, 7696=>780, 7697=>629, 7698=>780, 7699=>629, 7700=>686, 7701=>572, 7702=>686, 7703=>572, 7704=>686, 7705=>572, 7706=>686, - 7707=>572, 7710=>639, 7711=>387, 7712=>769, 7713=>629, 7714=>850, 7715=>654, 7716=>850, 7717=>654, 7718=>850, 7719=>654, 7720=>850, 7721=>654, 7722=>850, 7723=>654, 7724=>421, - 7725=>342, 7728=>782, 7729=>624, 7730=>782, 7731=>624, 7732=>782, 7733=>624, 7734=>633, 7735=>342, 7736=>633, 7737=>342, 7738=>633, 7739=>342, 7740=>633, 7741=>342, 7742=>996, - 7743=>952, 7744=>996, 7745=>952, 7746=>996, 7747=>952, 7748=>822, 7749=>654, 7750=>822, 7751=>654, 7752=>822, 7753=>654, 7754=>822, 7755=>654, 7760=>784, 7761=>600, 7762=>784, - 7763=>600, 7764=>677, 7765=>629, 7766=>677, 7767=>629, 7768=>748, 7769=>474, 7770=>748, 7771=>474, 7772=>748, 7773=>474, 7774=>748, 7775=>474, 7776=>650, 7777=>506, 7778=>650, - 7779=>506, 7784=>650, 7785=>506, 7786=>669, 7787=>416, 7788=>669, 7789=>416, 7790=>669, 7791=>416, 7792=>669, 7793=>416, 7794=>785, 7795=>654, 7796=>785, 7797=>654, 7798=>785, - 7799=>654, 7800=>785, 7801=>654, 7802=>785, 7803=>654, 7804=>698, 7805=>523, 7806=>698, 7807=>523, 7808=>1011, 7809=>774, 7810=>1011, 7811=>774, 7812=>1011, 7813=>774, 7814=>1011, - 7815=>774, 7816=>1011, 7817=>774, 7818=>698, 7819=>536, 7820=>698, 7821=>536, 7822=>642, 7823=>523, 7824=>657, 7825=>511, 7826=>657, 7827=>511, 7828=>657, 7829=>511, 7830=>654, - 7831=>416, 7832=>774, 7833=>523, 7834=>913, 7835=>506, 7840=>698, 7841=>583, 7842=>698, 7843=>583, 7852=>698, 7853=>583, 7854=>698, 7855=>583, 7856=>698, 7857=>583, 7858=>698, - 7859=>583, 7860=>698, 7861=>583, 7862=>698, 7863=>583, 7864=>686, 7865=>572, 7866=>686, 7867=>572, 7868=>686, 7869=>572, 7878=>686, 7879=>572, 7880=>421, 7881=>342, 7882=>421, - 7883=>342, 7884=>784, 7885=>600, 7886=>784, 7887=>600, 7896=>784, 7897=>600, 7908=>785, 7909=>654, 7910=>785, 7911=>654, 7922=>642, 7923=>523, 7924=>642, 7925=>523, 7926=>642, - 7927=>523, 7928=>642, 7929=>523, 7936=>692, 7937=>692, 7938=>692, 7939=>692, 7940=>692, 7941=>692, 7942=>692, 7943=>692, 7944=>698, 7945=>698, 7946=>880, 7947=>880, 7948=>748, - 7949=>764, 7950=>698, 7951=>698, 7952=>547, 7953=>547, 7954=>547, 7955=>547, 7956=>547, 7957=>547, 7960=>826, 7961=>817, 7962=>1052, 7963=>1052, 7964=>984, 7965=>1007, 7968=>654, - 7969=>654, 7970=>654, 7971=>654, 7972=>654, 7973=>654, 7974=>654, 7975=>654, 7976=>990, 7977=>984, 7978=>1222, 7979=>1225, 7980=>1151, 7981=>1177, 7982=>1077, 7983=>1074, 7984=>435, - 7985=>435, 7986=>435, 7987=>435, 7988=>435, 7989=>435, 7990=>435, 7991=>435, 7992=>566, 7993=>555, 7994=>790, 7995=>792, 7996=>719, 7997=>748, 7998=>650, 7999=>642, 8000=>600, - 8001=>600, 8002=>600, 8003=>600, 8004=>600, 8005=>600, 8008=>810, 8009=>841, 8010=>1116, 8011=>1113, 8012=>931, 8013=>959, 8016=>624, 8017=>624, 8018=>624, 8019=>624, 8020=>624, - 8021=>624, 8022=>624, 8023=>624, 8025=>830, 8027=>1067, 8029=>1020, 8031=>917, 8032=>857, 8033=>857, 8034=>857, 8035=>857, 8036=>857, 8037=>857, 8038=>857, 8039=>857, 8040=>838, - 8041=>867, 8042=>1141, 8043=>1146, 8044=>949, 8045=>979, 8046=>920, 8047=>954, 8048=>692, 8049=>692, 8050=>547, 8051=>547, 8052=>654, 8053=>654, 8054=>435, 8055=>435, 8056=>600, - 8057=>600, 8058=>624, 8059=>624, 8060=>857, 8061=>857, 8064=>692, 8065=>692, 8066=>692, 8067=>692, 8068=>692, 8069=>692, 8070=>692, 8071=>692, 8072=>698, 8073=>698, 8074=>880, - 8075=>880, 8076=>748, 8077=>764, 8078=>698, 8079=>698, 8080=>654, 8081=>654, 8082=>654, 8083=>654, 8084=>654, 8085=>654, 8086=>654, 8087=>654, 8088=>990, 8089=>984, 8090=>1222, - 8091=>1225, 8092=>1151, 8093=>1177, 8094=>1077, 8095=>1074, 8096=>857, 8097=>857, 8098=>857, 8099=>857, 8100=>857, 8101=>857, 8102=>857, 8103=>857, 8104=>838, 8105=>867, 8106=>1141, - 8107=>1146, 8108=>949, 8109=>979, 8110=>920, 8111=>954, 8112=>692, 8113=>692, 8114=>692, 8115=>692, 8116=>692, 8118=>692, 8119=>692, 8120=>698, 8121=>698, 8122=>729, 8123=>698, - 8124=>698, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>654, 8131=>654, 8132=>654, 8134=>654, 8135=>654, 8136=>899, 8137=>852, 8138=>1072, 8139=>1006, 8140=>850, - 8141=>450, 8142=>450, 8143=>450, 8144=>435, 8145=>435, 8146=>435, 8147=>435, 8150=>435, 8151=>435, 8152=>421, 8153=>421, 8154=>642, 8155=>595, 8157=>450, 8158=>450, 8159=>450, - 8160=>624, 8161=>624, 8162=>624, 8163=>624, 8164=>598, 8165=>598, 8166=>624, 8167=>624, 8168=>642, 8169=>642, 8170=>917, 8171=>857, 8172=>819, 8173=>450, 8174=>450, 8175=>450, - 8178=>857, 8179=>857, 8180=>857, 8182=>857, 8183=>857, 8184=>962, 8185=>798, 8186=>991, 8187=>820, 8188=>801, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, - 8196=>296, 8197=>225, 8198=>150, 8199=>626, 8200=>313, 8201=>180, 8202=>89, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>374, 8209=>374, 8210=>626, 8213=>900, - 8215=>450, 8219=>313, 8223=>518, 8227=>575, 8228=>313, 8229=>606, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1638, 8252=>566, 8253=>527, 8254=>450, - 8263=>974, 8264=>770, 8265=>770, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>394, 8308=>394, - 8309=>394, 8310=>394, 8311=>394, 8312=>394, 8313=>394, 8319=>467, 8320=>394, 8321=>394, 8322=>394, 8323=>394, 8324=>394, 8325=>394, 8326=>394, 8327=>394, 8328=>394, 8329=>394, - 8358=>626, 8367=>1039, 8369=>710, 8372=>788, 8373=>626, 8462=>654, 8470=>978, 8486=>801, 8490=>782, 8491=>698, 8531=>932, 8532=>932, 8533=>932, 8534=>932, 8535=>932, 8536=>932, - 8537=>932, 8538=>932, 8539=>932, 8540=>932, 8541=>932, 8542=>932, 8543=>554, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8706=>480, 8710=>677, 8711=>677, 8719=>757, 8721=>677, - 8722=>754, 8725=>150, 8729=>313, 8730=>591, 8733=>604, 8734=>750, 8735=>754, 8736=>754, 8743=>730, 8744=>730, 8745=>730, 8746=>730, 8747=>521, 8748=>900, 8749=>1252, 8770=>754, - 8771=>754, 8776=>754, 8800=>754, 8801=>754, 8804=>754, 8805=>754, 8962=>751, 8968=>426, 8969=>426, 8970=>426, 8971=>426, 8976=>754, 8977=>484, 8984=>835, 8985=>754, 8992=>521, - 8993=>521, 8997=>900, 9000=>1299, 9085=>907, 9134=>521, 9167=>850, 9251=>751, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, - 9609=>692, 9610=>692, 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, - 9625=>692, 9626=>692, 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, - 9641=>850, 9642=>610, 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, - 9657=>452, 9658=>692, 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, - 9673=>785, 9674=>444, 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>712, - 9689=>873, 9690=>873, 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>785, 9697=>785, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>531, 9703=>850, 9704=>850, - 9705=>850, 9706=>850, 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, - 9721=>692, 9722=>692, 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9784=>807, 9785=>807, 9786=>807, 9787=>807, 9788=>807, 9791=>552, 9792=>658, 9793=>658, - 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 10208=>444, 10216=>411, 10217=>411, 10731=>444, 10764=>1604, 10765=>549, 10766=>549, 11026=>850, 11027=>850, 11028=>850, 11029=>850, - 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 63173=>600, 63185=>450, 63188=>450, 64256=>837, 64257=>654, 64258=>654, 64259=>1013, 64260=>1011, 64261=>784, 64262=>908, 65024=>0, - 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65533=>1002} - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerifCondensed-Bold.z'; - font[:ctg]='DejaVuSerifCondensed-Bold.ctg.z'; - font[:originalsize]=177248; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensedbi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensedbi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifCondensedbi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerifCondensed-BoldOblique'; - font[:desc]={'Ascent'=>939,'Descent'=>-236,'CapHeight'=>939,'Flags'=>96,'FontBBox'=>'[-815 -423 1584 1235]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>540} - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>313, 33=>395, 34=>469, 35=>754, 36=>626, 37=>855, 38=>813, 39=>275, 40=>426, 41=>426, 42=>470, 43=>754, 44=>313, 45=>374, 46=>313, - 47=>329, 48=>626, 49=>626, 50=>626, 51=>626, 52=>626, 53=>626, 54=>626, 55=>626, 56=>626, 57=>626, 58=>332, 59=>332, 60=>754, 61=>754, 62=>754, - 63=>527, 64=>900, 65=>698, 66=>760, 67=>716, 68=>780, 69=>686, 70=>639, 71=>769, 72=>850, 73=>421, 74=>426, 75=>782, 76=>633, 77=>996, 78=>822, - 79=>784, 80=>677, 81=>784, 82=>748, 83=>650, 84=>669, 85=>785, 86=>698, 87=>1011, 88=>698, 89=>642, 90=>657, 91=>426, 92=>329, 93=>426, 94=>754, - 95=>450, 96=>450, 97=>583, 98=>629, 99=>548, 100=>629, 101=>572, 102=>387, 103=>629, 104=>654, 105=>342, 106=>325, 107=>624, 108=>342, 109=>952, 110=>654, - 111=>600, 112=>629, 113=>629, 114=>474, 115=>506, 116=>416, 117=>654, 118=>523, 119=>774, 120=>536, 121=>523, 122=>511, 123=>579, 124=>327, 125=>579, 126=>754, - 8364=>626, 1027=>621, 8218=>313, 402=>387, 8222=>518, 8230=>900, 8224=>470, 8225=>470, 710=>450, 8240=>1246, 352=>650, 8249=>360, 338=>1062, 1036=>818, 381=>657, 1039=>850, - 8216=>313, 8217=>313, 8220=>518, 8221=>518, 8226=>575, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>506, 8250=>360, 339=>925, 1116=>609, 382=>511, 376=>642, 160=>313, - 161=>395, 162=>626, 163=>626, 164=>572, 165=>626, 166=>327, 167=>470, 168=>450, 169=>900, 170=>438, 171=>563, 172=>754, 173=>374, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>394, 179=>394, 180=>450, 181=>659, 182=>572, 183=>313, 184=>450, 185=>394, 186=>450, 187=>563, 188=>938, 189=>938, 190=>938, 191=>527, 192=>698, - 193=>698, 194=>698, 195=>698, 196=>698, 197=>698, 198=>931, 199=>716, 200=>686, 201=>686, 202=>686, 203=>686, 204=>421, 205=>421, 206=>421, 207=>421, 208=>787, - 209=>822, 210=>784, 211=>784, 212=>784, 213=>784, 214=>784, 215=>754, 216=>784, 217=>785, 218=>785, 219=>785, 220=>785, 221=>642, 222=>681, 223=>684, 224=>583, - 225=>583, 226=>583, 227=>583, 228=>583, 229=>583, 230=>877, 231=>548, 232=>572, 233=>572, 234=>572, 235=>572, 236=>342, 237=>342, 238=>342, 239=>342, 240=>600, - 241=>654, 242=>600, 243=>600, 244=>600, 245=>600, 246=>600, 247=>754, 248=>600, 249=>654, 250=>654, 251=>654, 252=>654, 253=>523, 254=>629, 255=>523, 256=>698, - 257=>583, 258=>698, 259=>583, 260=>698, 261=>583, 262=>716, 263=>548, 264=>716, 265=>548, 266=>716, 267=>548, 268=>716, 269=>548, 270=>780, 271=>629, 272=>787, - 273=>629, 274=>686, 275=>572, 276=>686, 277=>572, 278=>686, 279=>572, 280=>686, 281=>572, 282=>686, 283=>572, 284=>769, 285=>629, 286=>769, 287=>629, 288=>769, - 289=>629, 290=>769, 291=>629, 292=>850, 293=>654, 294=>850, 295=>654, 296=>421, 297=>342, 298=>421, 299=>342, 300=>421, 301=>342, 302=>421, 303=>342, 304=>421, - 305=>342, 306=>848, 307=>676, 308=>426, 309=>325, 310=>782, 311=>624, 312=>624, 313=>633, 314=>342, 315=>633, 316=>342, 317=>633, 318=>457, 319=>633, 320=>501, - 321=>639, 322=>346, 323=>822, 324=>654, 325=>822, 326=>654, 327=>822, 328=>654, 329=>907, 330=>822, 331=>654, 332=>784, 333=>600, 334=>784, 335=>600, 336=>784, - 337=>600, 340=>748, 341=>474, 342=>748, 343=>474, 344=>748, 345=>474, 346=>650, 347=>506, 348=>650, 349=>506, 350=>650, 351=>506, 354=>669, 355=>416, 356=>669, - 357=>416, 358=>669, 359=>416, 360=>785, 361=>654, 362=>785, 363=>654, 364=>785, 365=>654, 366=>785, 367=>654, 368=>785, 369=>654, 370=>785, 371=>654, 372=>1011, - 373=>774, 374=>642, 375=>523, 377=>657, 378=>511, 379=>657, 380=>511, 383=>387, 384=>629, 385=>760, 386=>769, 387=>629, 388=>769, 389=>629, 390=>716, 391=>716, - 392=>548, 393=>787, 394=>780, 395=>769, 396=>629, 397=>600, 398=>686, 399=>784, 400=>626, 401=>639, 403=>769, 404=>693, 405=>938, 406=>421, 407=>421, 408=>782, - 409=>624, 410=>342, 411=>631, 412=>952, 413=>822, 414=>654, 415=>784, 416=>784, 417=>600, 418=>1080, 419=>849, 420=>677, 421=>629, 422=>748, 423=>650, 424=>506, - 425=>636, 426=>298, 427=>416, 428=>669, 429=>416, 430=>669, 431=>785, 432=>654, 433=>801, 434=>801, 435=>642, 436=>628, 437=>657, 438=>511, 439=>511, 440=>511, - 441=>511, 443=>626, 444=>678, 445=>511, 446=>482, 448=>265, 449=>443, 450=>413, 451=>265, 452=>1437, 453=>1292, 454=>1140, 455=>1059, 456=>958, 457=>667, 458=>1248, - 459=>1148, 460=>980, 461=>698, 462=>583, 463=>421, 464=>342, 465=>784, 466=>600, 467=>785, 468=>654, 469=>785, 470=>654, 471=>785, 472=>654, 473=>785, 474=>654, - 475=>785, 476=>654, 477=>572, 478=>698, 479=>583, 480=>698, 481=>583, 482=>931, 483=>877, 484=>806, 485=>629, 486=>769, 487=>629, 488=>782, 489=>624, 490=>784, - 491=>600, 492=>784, 493=>600, 494=>511, 495=>511, 496=>325, 497=>1437, 498=>1292, 499=>1140, 500=>769, 501=>629, 502=>1099, 504=>822, 505=>654, 506=>698, 507=>583, - 508=>931, 509=>877, 510=>784, 511=>600, 512=>698, 513=>583, 514=>698, 515=>583, 516=>686, 517=>572, 518=>686, 519=>572, 520=>421, 521=>342, 522=>421, 523=>342, - 524=>784, 525=>600, 526=>784, 527=>600, 528=>748, 529=>474, 530=>748, 531=>474, 532=>785, 533=>654, 534=>785, 535=>654, 536=>650, 537=>506, 538=>669, 539=>416, - 542=>850, 543=>654, 545=>711, 548=>657, 549=>511, 550=>698, 551=>583, 552=>686, 553=>572, 554=>784, 555=>600, 556=>784, 557=>600, 558=>784, 559=>600, 560=>784, - 561=>600, 562=>642, 563=>523, 564=>516, 565=>830, 566=>508, 567=>325, 568=>928, 569=>928, 570=>698, 571=>716, 572=>548, 573=>633, 574=>669, 575=>506, 576=>511, - 577=>594, 578=>492, 581=>698, 592=>583, 593=>629, 594=>629, 595=>629, 596=>548, 597=>548, 598=>629, 599=>657, 600=>572, 601=>572, 602=>816, 603=>547, 604=>505, - 605=>816, 606=>647, 607=>348, 608=>629, 609=>629, 610=>563, 611=>641, 612=>564, 613=>654, 614=>654, 615=>654, 616=>342, 617=>342, 618=>342, 619=>368, 620=>462, - 621=>342, 622=>716, 623=>952, 624=>952, 625=>952, 626=>654, 627=>654, 628=>641, 629=>600, 630=>955, 631=>674, 632=>600, 633=>514, 634=>514, 635=>514, 636=>474, - 637=>474, 638=>406, 639=>438, 640=>721, 641=>721, 642=>506, 643=>298, 644=>387, 645=>486, 646=>298, 647=>443, 648=>416, 649=>654, 650=>611, 651=>624, 652=>577, - 653=>816, 654=>571, 655=>654, 656=>511, 657=>511, 658=>511, 659=>511, 660=>482, 661=>482, 662=>482, 663=>490, 664=>784, 665=>625, 666=>647, 667=>563, 668=>659, - 669=>345, 670=>666, 671=>581, 672=>629, 673=>482, 674=>482, 675=>1005, 676=>1061, 677=>1005, 678=>819, 679=>643, 680=>817, 681=>935, 682=>711, 683=>716, 684=>596, - 685=>398, 686=>552, 687=>646, 688=>469, 689=>466, 690=>282, 691=>372, 692=>372, 693=>432, 694=>474, 695=>595, 696=>436, 697=>271, 699=>313, 700=>313, 701=>313, - 702=>330, 703=>330, 704=>282, 705=>282, 711=>450, 712=>254, 713=>450, 716=>254, 720=>332, 721=>332, 722=>330, 723=>330, 726=>353, 728=>450, 729=>450, 730=>450, - 731=>450, 733=>450, 734=>375, 736=>412, 737=>263, 738=>355, 739=>427, 740=>282, 741=>436, 742=>436, 743=>436, 744=>436, 745=>436, 750=>498, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>271, 885=>271, 890=>450, 894=>332, 900=>450, 901=>450, 902=>698, 903=>313, 904=>852, 905=>1022, 906=>595, 908=>798, 910=>857, 911=>820, - 912=>435, 913=>698, 914=>760, 915=>639, 916=>698, 917=>686, 918=>657, 919=>850, 920=>784, 921=>421, 922=>782, 923=>698, 924=>996, 925=>822, 926=>633, 927=>784, - 928=>850, 929=>677, 931=>636, 932=>669, 933=>642, 934=>784, 935=>698, 936=>822, 937=>801, 938=>421, 939=>642, 940=>692, 941=>547, 942=>654, 943=>435, 944=>624, - 945=>692, 946=>598, 947=>594, 948=>600, 949=>547, 950=>533, 951=>654, 952=>600, 953=>435, 954=>674, 955=>631, 956=>659, 957=>624, 958=>533, 959=>600, 960=>659, - 961=>598, 962=>548, 963=>664, 964=>605, 965=>624, 966=>814, 967=>592, 968=>847, 969=>857, 970=>435, 971=>624, 972=>600, 973=>624, 974=>857, 976=>600, 977=>764, - 978=>687, 979=>872, 980=>687, 981=>847, 982=>857, 983=>589, 984=>784, 985=>600, 986=>716, 987=>548, 988=>639, 989=>475, 990=>531, 991=>593, 992=>716, 993=>600, - 1008=>589, 1009=>598, 1010=>548, 1011=>325, 1012=>784, 1013=>548, 1014=>548, 1015=>681, 1016=>629, 1017=>716, 1018=>996, 1019=>774, 1020=>623, 1021=>716, 1022=>716, 1023=>716, - 1024=>686, 1025=>686, 1026=>811, 1028=>716, 1029=>650, 1030=>421, 1031=>421, 1032=>426, 1033=>1081, 1034=>1135, 1035=>866, 1037=>850, 1038=>730, 1040=>733, 1041=>769, 1042=>760, - 1043=>621, 1044=>800, 1045=>686, 1046=>1181, 1047=>649, 1048=>850, 1049=>850, 1050=>818, 1051=>795, 1052=>996, 1053=>850, 1054=>784, 1055=>850, 1056=>677, 1057=>716, 1058=>669, - 1059=>730, 1060=>854, 1061=>698, 1062=>870, 1063=>822, 1064=>1141, 1065=>1164, 1066=>861, 1067=>1081, 1068=>743, 1069=>716, 1070=>1158, 1071=>793, 1072=>583, 1073=>650, 1074=>591, - 1075=>506, 1076=>625, 1077=>572, 1078=>1175, 1079=>574, 1080=>654, 1081=>654, 1082=>609, 1083=>659, 1084=>873, 1085=>656, 1086=>600, 1087=>654, 1088=>629, 1089=>548, 1090=>952, - 1091=>538, 1092=>812, 1093=>536, 1094=>723, 1095=>643, 1096=>952, 1097=>1021, 1098=>654, 1099=>916, 1100=>593, 1101=>580, 1102=>901, 1103=>716, 1104=>572, 1105=>572, 1106=>646, - 1107=>506, 1108=>548, 1109=>506, 1110=>342, 1111=>342, 1112=>325, 1113=>913, 1114=>910, 1115=>654, 1117=>654, 1118=>538, 1119=>654, 1122=>792, 1123=>945, 1138=>784, 1139=>587, - 1140=>824, 1141=>673, 1164=>712, 1165=>598, 1168=>630, 1169=>556, 1170=>639, 1171=>573, 1172=>768, 1173=>634, 1174=>1181, 1175=>1175, 1176=>649, 1177=>574, 1178=>812, 1179=>624, - 1182=>818, 1183=>624, 1184=>899, 1185=>659, 1186=>856, 1187=>725, 1188=>1068, 1189=>882, 1190=>1191, 1191=>911, 1194=>716, 1195=>548, 1196=>669, 1197=>1028, 1198=>642, 1199=>523, - 1202=>709, 1203=>536, 1204=>1112, 1205=>876, 1206=>822, 1207=>644, 1210=>819, 1211=>654, 1216=>421, 1217=>1181, 1218=>1175, 1219=>782, 1220=>624, 1223=>850, 1224=>659, 1227=>885, - 1228=>659, 1231=>342, 1232=>733, 1233=>583, 1234=>733, 1235=>583, 1236=>931, 1237=>877, 1238=>686, 1239=>572, 1240=>784, 1241=>572, 1242=>784, 1243=>572, 1244=>1181, 1245=>1175, - 1246=>649, 1247=>574, 1248=>511, 1249=>511, 1250=>850, 1251=>654, 1252=>850, 1253=>654, 1254=>784, 1255=>600, 1256=>784, 1257=>600, 1258=>784, 1259=>600, 1260=>716, 1261=>580, - 1262=>730, 1263=>538, 1264=>730, 1265=>538, 1266=>730, 1267=>538, 1268=>822, 1269=>643, 1270=>621, 1271=>573, 1272=>1081, 1273=>916, 7426=>846, 7432=>458, 7433=>288, 7444=>890, - 7446=>600, 7447=>600, 7453=>663, 7454=>853, 7455=>853, 7491=>419, 7492=>419, 7493=>448, 7494=>591, 7495=>448, 7496=>448, 7497=>400, 7498=>400, 7499=>370, 7500=>370, 7501=>448, - 7502=>270, 7503=>471, 7504=>655, 7505=>426, 7506=>420, 7507=>384, 7508=>420, 7509=>420, 7510=>448, 7511=>333, 7512=>468, 7513=>390, 7514=>655, 7515=>442, 7543=>576, 7547=>342, - 7557=>342, 7579=>448, 7580=>384, 7581=>384, 7582=>420, 7583=>370, 7584=>345, 7585=>335, 7586=>448, 7587=>470, 7588=>270, 7589=>276, 7590=>270, 7591=>270, 7592=>333, 7593=>331, - 7594=>289, 7595=>387, 7596=>613, 7597=>655, 7598=>529, 7599=>528, 7600=>425, 7601=>420, 7602=>470, 7603=>360, 7604=>348, 7605=>333, 7606=>468, 7607=>427, 7609=>439, 7610=>442, - 7611=>371, 7612=>474, 7613=>371, 7614=>407, 7615=>420, 7680=>698, 7681=>583, 7682=>760, 7683=>629, 7684=>760, 7685=>629, 7686=>760, 7687=>629, 7688=>716, 7689=>548, 7690=>780, - 7691=>629, 7692=>780, 7693=>629, 7694=>780, 7695=>629, 7696=>780, 7697=>629, 7698=>780, 7699=>629, 7700=>686, 7701=>572, 7702=>686, 7703=>572, 7704=>686, 7705=>572, 7706=>686, - 7707=>572, 7710=>639, 7711=>387, 7712=>769, 7713=>629, 7714=>850, 7715=>654, 7716=>850, 7717=>654, 7718=>850, 7719=>654, 7720=>850, 7721=>654, 7722=>850, 7723=>654, 7724=>421, - 7725=>342, 7728=>782, 7729=>624, 7730=>782, 7731=>624, 7732=>782, 7733=>624, 7734=>633, 7735=>342, 7736=>633, 7737=>342, 7738=>633, 7739=>342, 7740=>633, 7741=>342, 7742=>996, - 7743=>952, 7744=>996, 7745=>952, 7746=>996, 7747=>952, 7748=>822, 7749=>654, 7750=>822, 7751=>654, 7752=>822, 7753=>654, 7754=>822, 7755=>654, 7760=>784, 7761=>600, 7762=>784, - 7763=>600, 7764=>677, 7765=>629, 7766=>677, 7767=>629, 7768=>748, 7769=>474, 7770=>748, 7771=>474, 7772=>748, 7773=>474, 7774=>748, 7775=>474, 7776=>650, 7777=>506, 7778=>650, - 7779=>506, 7784=>650, 7785=>506, 7786=>669, 7787=>416, 7788=>669, 7789=>416, 7790=>669, 7791=>416, 7792=>669, 7793=>416, 7794=>785, 7795=>654, 7796=>785, 7797=>654, 7798=>785, - 7799=>654, 7800=>785, 7801=>654, 7802=>785, 7803=>654, 7804=>698, 7805=>523, 7806=>698, 7807=>523, 7808=>1011, 7809=>774, 7810=>1011, 7811=>774, 7812=>1011, 7813=>774, 7814=>1011, - 7815=>774, 7816=>1011, 7817=>774, 7818=>698, 7819=>536, 7820=>698, 7821=>536, 7822=>642, 7823=>523, 7824=>657, 7825=>511, 7826=>657, 7827=>511, 7828=>657, 7829=>511, 7830=>654, - 7831=>416, 7832=>774, 7833=>523, 7834=>913, 7835=>506, 7840=>698, 7841=>583, 7842=>698, 7843=>583, 7852=>698, 7853=>583, 7854=>698, 7855=>583, 7856=>698, 7857=>583, 7858=>698, - 7859=>583, 7860=>698, 7861=>583, 7862=>698, 7863=>583, 7864=>686, 7865=>572, 7866=>686, 7867=>572, 7868=>686, 7869=>572, 7878=>686, 7879=>572, 7880=>421, 7881=>342, 7882=>421, - 7883=>342, 7884=>784, 7885=>600, 7886=>784, 7887=>600, 7896=>784, 7897=>600, 7908=>785, 7909=>654, 7910=>785, 7911=>654, 7922=>642, 7923=>523, 7924=>642, 7925=>523, 7926=>642, - 7927=>523, 7928=>642, 7929=>523, 7936=>692, 7937=>692, 7938=>692, 7939=>692, 7940=>692, 7941=>692, 7942=>692, 7943=>692, 7944=>698, 7945=>698, 7946=>880, 7947=>880, 7948=>748, - 7949=>764, 7950=>698, 7951=>698, 7952=>547, 7953=>547, 7954=>547, 7955=>547, 7956=>547, 7957=>547, 7960=>826, 7961=>817, 7962=>1052, 7963=>1052, 7964=>984, 7965=>1007, 7968=>654, - 7969=>654, 7970=>654, 7971=>654, 7972=>654, 7973=>654, 7974=>654, 7975=>654, 7976=>990, 7977=>984, 7978=>1222, 7979=>1225, 7980=>1151, 7981=>1177, 7982=>1077, 7983=>1074, 7984=>435, - 7985=>435, 7986=>435, 7987=>435, 7988=>435, 7989=>435, 7990=>435, 7991=>435, 7992=>566, 7993=>555, 7994=>790, 7995=>792, 7996=>719, 7997=>748, 7998=>650, 7999=>642, 8000=>600, - 8001=>600, 8002=>600, 8003=>600, 8004=>600, 8005=>600, 8008=>810, 8009=>841, 8010=>1116, 8011=>1113, 8012=>931, 8013=>959, 8016=>624, 8017=>624, 8018=>624, 8019=>624, 8020=>624, - 8021=>624, 8022=>624, 8023=>624, 8025=>830, 8027=>1067, 8029=>1020, 8031=>917, 8032=>857, 8033=>857, 8034=>857, 8035=>857, 8036=>857, 8037=>857, 8038=>857, 8039=>857, 8040=>838, - 8041=>867, 8042=>1141, 8043=>1146, 8044=>949, 8045=>979, 8046=>920, 8047=>954, 8048=>692, 8049=>692, 8050=>547, 8051=>547, 8052=>654, 8053=>654, 8054=>435, 8055=>435, 8056=>600, - 8057=>600, 8058=>624, 8059=>624, 8060=>857, 8061=>857, 8064=>692, 8065=>692, 8066=>692, 8067=>692, 8068=>692, 8069=>692, 8070=>692, 8071=>692, 8072=>698, 8073=>698, 8074=>880, - 8075=>880, 8076=>748, 8077=>764, 8078=>698, 8079=>698, 8080=>654, 8081=>654, 8082=>654, 8083=>654, 8084=>654, 8085=>654, 8086=>654, 8087=>654, 8088=>990, 8089=>984, 8090=>1222, - 8091=>1225, 8092=>1151, 8093=>1177, 8094=>1077, 8095=>1074, 8096=>857, 8097=>857, 8098=>857, 8099=>857, 8100=>857, 8101=>857, 8102=>857, 8103=>857, 8104=>838, 8105=>867, 8106=>1141, - 8107=>1146, 8108=>949, 8109=>979, 8110=>920, 8111=>954, 8112=>692, 8113=>692, 8114=>692, 8115=>692, 8116=>692, 8118=>692, 8119=>692, 8120=>698, 8121=>698, 8122=>729, 8123=>698, - 8124=>698, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>654, 8131=>654, 8132=>654, 8134=>654, 8135=>654, 8136=>899, 8137=>852, 8138=>1072, 8139=>1006, 8140=>850, - 8141=>450, 8142=>450, 8143=>450, 8144=>435, 8145=>435, 8146=>435, 8147=>435, 8150=>435, 8151=>435, 8152=>421, 8153=>421, 8154=>642, 8155=>595, 8157=>450, 8158=>450, 8159=>450, - 8160=>624, 8161=>624, 8162=>624, 8163=>624, 8164=>598, 8165=>598, 8166=>624, 8167=>624, 8168=>642, 8169=>642, 8170=>917, 8171=>857, 8172=>819, 8173=>450, 8174=>450, 8175=>450, - 8178=>857, 8179=>857, 8180=>857, 8182=>857, 8183=>857, 8184=>962, 8185=>798, 8186=>991, 8187=>820, 8188=>801, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, - 8196=>296, 8197=>225, 8198=>150, 8199=>626, 8200=>313, 8201=>180, 8202=>89, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>374, 8209=>374, 8210=>626, 8213=>900, - 8215=>450, 8219=>313, 8223=>518, 8227=>575, 8228=>313, 8229=>606, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1631, 8252=>566, 8253=>527, 8254=>450, - 8263=>974, 8264=>770, 8265=>770, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>394, 8308=>394, - 8309=>394, 8310=>394, 8311=>394, 8312=>394, 8313=>394, 8319=>467, 8320=>394, 8321=>394, 8322=>394, 8323=>394, 8324=>394, 8325=>394, 8326=>394, 8327=>394, 8328=>394, 8329=>394, - 8358=>626, 8367=>1039, 8369=>710, 8372=>788, 8373=>626, 8462=>654, 8470=>978, 8486=>801, 8490=>782, 8491=>698, 8531=>932, 8532=>932, 8533=>932, 8534=>932, 8535=>932, 8536=>932, - 8537=>932, 8538=>932, 8539=>932, 8540=>932, 8541=>932, 8542=>932, 8543=>554, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8706=>480, 8710=>677, 8711=>677, 8719=>757, 8721=>677, - 8722=>754, 8725=>150, 8729=>313, 8730=>591, 8733=>604, 8734=>750, 8735=>754, 8736=>754, 8743=>730, 8744=>730, 8745=>730, 8746=>730, 8747=>521, 8748=>900, 8749=>1252, 8770=>754, - 8771=>754, 8776=>754, 8800=>754, 8801=>754, 8804=>754, 8805=>754, 8962=>751, 8968=>426, 8969=>426, 8970=>426, 8971=>426, 8976=>754, 8977=>484, 8984=>835, 8985=>754, 8992=>521, - 8993=>521, 8997=>900, 9000=>1299, 9085=>907, 9134=>521, 9167=>850, 9251=>751, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, - 9609=>692, 9610=>692, 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, - 9625=>692, 9626=>692, 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, - 9641=>850, 9642=>610, 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, - 9657=>452, 9658=>692, 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, - 9673=>785, 9674=>444, 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>712, - 9689=>873, 9690=>873, 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>785, 9697=>785, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>531, 9703=>850, 9704=>850, - 9705=>850, 9706=>850, 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, - 9721=>692, 9722=>692, 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9784=>807, 9785=>807, 9786=>807, 9787=>807, 9788=>807, 9791=>552, 9792=>658, 9793=>658, - 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 10208=>444, 10216=>411, 10217=>411, 10731=>444, 10764=>1604, 10765=>549, 10766=>549, 11026=>850, 11027=>850, 11028=>850, 11029=>850, - 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 63172=>506, 63173=>600, 63174=>629, 63175=>654, 63176=>952, 63185=>450, 63188=>450, 64256=>744, 64257=>654, 64258=>654, 64259=>998, - 64260=>1031, 64261=>791, 64262=>906, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, - 65037=>0, 65038=>0, 65039=>0, 65533=>1002} - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerifCondensed-BoldOblique.z'; - font[:ctg]='DejaVuSerifCondensed-BoldOblique.ctg.z'; - font[:originalsize]=182696; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensedi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifCondensedi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifCondensedi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerifCondensed-Oblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-755 -401 1485 1227]','ItalicAngle'=>-11,'StemV'=>70,'MissingWidth'=>540} - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>540, 32=>286, 33=>361, 34=>414, 35=>754, 36=>572, 37=>855, 38=>801, 39=>247, 40=>351, 41=>351, 42=>450, 43=>754, 44=>286, 45=>304, 46=>286, - 47=>303, 48=>572, 49=>572, 50=>572, 51=>572, 52=>572, 53=>572, 54=>572, 55=>572, 56=>572, 57=>572, 58=>303, 59=>303, 60=>754, 61=>754, 62=>754, - 63=>482, 64=>900, 65=>650, 66=>661, 67=>688, 68=>721, 69=>657, 70=>624, 71=>719, 72=>785, 73=>355, 74=>360, 75=>672, 76=>598, 77=>921, 78=>787, - 79=>738, 80=>605, 81=>738, 82=>677, 83=>616, 84=>600, 85=>758, 86=>650, 87=>925, 88=>641, 89=>594, 90=>625, 91=>351, 92=>303, 93=>351, 94=>754, - 95=>450, 96=>450, 97=>536, 98=>576, 99=>504, 100=>576, 101=>532, 102=>333, 103=>576, 104=>580, 105=>288, 106=>279, 107=>545, 108=>288, 109=>853, 110=>580, - 111=>542, 112=>576, 113=>576, 114=>430, 115=>461, 116=>361, 117=>580, 118=>508, 119=>770, 120=>507, 121=>508, 122=>474, 123=>572, 124=>303, 125=>572, 126=>754, - 8364=>572, 1027=>596, 8218=>286, 402=>333, 8222=>466, 8230=>900, 8224=>450, 8225=>450, 710=>450, 8240=>1208, 352=>616, 8249=>360, 338=>1023, 1036=>696, 381=>625, 1039=>785, - 8216=>286, 8217=>286, 8220=>460, 8221=>460, 8226=>531, 8211=>450, 8212=>900, 732=>450, 8482=>900, 353=>461, 8250=>360, 339=>890, 1116=>554, 382=>474, 376=>594, 160=>286, - 161=>361, 162=>572, 163=>572, 164=>572, 165=>572, 166=>303, 167=>450, 168=>450, 169=>900, 170=>427, 171=>550, 172=>754, 173=>304, 174=>900, 175=>450, 176=>450, - 177=>754, 178=>360, 179=>360, 180=>450, 181=>584, 182=>572, 183=>286, 184=>450, 185=>360, 186=>423, 187=>550, 188=>872, 189=>872, 190=>872, 191=>482, 192=>650, - 193=>650, 194=>650, 195=>650, 196=>650, 197=>650, 198=>901, 199=>688, 200=>657, 201=>657, 202=>657, 203=>657, 204=>355, 205=>355, 206=>355, 207=>355, 208=>726, - 209=>787, 210=>738, 211=>738, 212=>738, 213=>738, 214=>738, 215=>754, 216=>738, 217=>758, 218=>758, 219=>758, 220=>758, 221=>594, 222=>608, 223=>601, 224=>536, - 225=>536, 226=>536, 227=>536, 228=>536, 229=>536, 230=>846, 231=>504, 232=>532, 233=>532, 234=>532, 235=>532, 236=>288, 237=>288, 238=>288, 239=>288, 240=>542, - 241=>580, 242=>542, 243=>542, 244=>542, 245=>542, 246=>542, 247=>754, 248=>542, 249=>580, 250=>580, 251=>580, 252=>580, 253=>508, 254=>576, 255=>508, 256=>650, - 257=>536, 258=>650, 259=>536, 260=>650, 261=>536, 262=>688, 263=>504, 264=>688, 265=>504, 266=>688, 267=>504, 268=>688, 269=>504, 270=>721, 271=>576, 272=>726, - 273=>576, 274=>657, 275=>532, 276=>657, 277=>532, 278=>657, 279=>532, 280=>657, 281=>532, 282=>657, 283=>532, 284=>719, 285=>576, 286=>719, 287=>576, 288=>719, - 289=>576, 290=>719, 291=>576, 292=>785, 293=>580, 294=>785, 295=>580, 296=>355, 297=>288, 298=>355, 299=>288, 300=>355, 301=>288, 302=>355, 303=>288, 304=>355, - 305=>288, 306=>721, 307=>479, 308=>360, 309=>279, 310=>672, 311=>545, 312=>545, 313=>598, 314=>288, 315=>598, 316=>288, 317=>598, 318=>360, 319=>604, 320=>418, - 321=>602, 322=>292, 323=>787, 324=>580, 325=>787, 326=>580, 327=>787, 328=>580, 329=>779, 330=>787, 331=>580, 332=>738, 333=>542, 334=>738, 335=>542, 336=>738, - 337=>542, 340=>677, 341=>430, 342=>677, 343=>430, 344=>677, 345=>430, 346=>616, 347=>461, 348=>616, 349=>461, 350=>616, 351=>461, 354=>600, 355=>361, 356=>600, - 357=>361, 358=>600, 359=>361, 360=>758, 361=>580, 362=>758, 363=>580, 364=>758, 365=>580, 366=>758, 367=>580, 368=>758, 369=>580, 370=>758, 371=>580, 372=>925, - 373=>770, 374=>594, 375=>508, 377=>625, 378=>474, 379=>625, 380=>474, 383=>333, 384=>576, 385=>661, 386=>661, 387=>576, 388=>661, 389=>576, 390=>688, 391=>688, - 392=>504, 393=>726, 394=>721, 395=>661, 396=>576, 397=>542, 398=>657, 399=>738, 400=>572, 401=>624, 403=>719, 404=>641, 405=>839, 406=>355, 407=>355, 408=>672, - 409=>545, 410=>288, 411=>570, 412=>853, 413=>787, 414=>580, 415=>738, 416=>738, 417=>542, 418=>936, 419=>726, 420=>605, 421=>576, 422=>677, 423=>616, 424=>461, - 425=>636, 426=>292, 427=>361, 428=>600, 429=>361, 430=>600, 431=>758, 432=>580, 433=>746, 434=>684, 435=>664, 436=>670, 437=>625, 438=>474, 439=>508, 440=>508, - 441=>508, 443=>572, 444=>618, 445=>508, 446=>482, 448=>265, 449=>443, 450=>413, 451=>265, 452=>1347, 453=>1195, 454=>1050, 455=>958, 456=>876, 457=>567, 458=>1148, - 459=>1066, 460=>858, 461=>650, 462=>536, 463=>355, 464=>288, 465=>738, 466=>542, 467=>758, 468=>580, 469=>758, 470=>580, 471=>758, 472=>580, 473=>758, 474=>580, - 475=>758, 476=>580, 477=>532, 478=>650, 479=>536, 480=>650, 481=>536, 482=>901, 483=>846, 484=>763, 485=>576, 486=>719, 487=>576, 488=>672, 489=>545, 490=>738, - 491=>542, 492=>738, 493=>542, 494=>508, 495=>508, 496=>288, 497=>1347, 498=>1195, 499=>1050, 500=>719, 501=>576, 502=>1038, 504=>787, 505=>580, 506=>650, 507=>536, - 508=>901, 509=>846, 510=>738, 511=>542, 512=>650, 513=>536, 514=>650, 515=>536, 516=>657, 517=>532, 518=>657, 519=>532, 520=>355, 521=>288, 522=>355, 523=>288, - 524=>738, 525=>542, 526=>738, 527=>542, 528=>677, 529=>430, 530=>677, 531=>430, 532=>758, 533=>580, 534=>758, 535=>580, 536=>616, 537=>461, 538=>600, 539=>361, - 542=>785, 543=>580, 545=>732, 548=>625, 549=>474, 550=>650, 551=>536, 552=>657, 553=>532, 554=>738, 555=>542, 556=>738, 557=>542, 558=>738, 559=>542, 560=>738, - 561=>542, 562=>594, 563=>508, 564=>450, 565=>748, 566=>444, 567=>279, 568=>864, 569=>864, 570=>650, 571=>688, 572=>504, 573=>598, 574=>600, 575=>461, 576=>474, - 577=>525, 578=>417, 581=>650, 592=>536, 593=>576, 594=>607, 595=>576, 596=>504, 597=>504, 598=>582, 599=>614, 600=>532, 601=>532, 602=>759, 603=>483, 604=>458, - 605=>695, 606=>552, 607=>283, 608=>615, 609=>576, 610=>489, 611=>641, 612=>507, 613=>580, 614=>580, 615=>580, 616=>288, 617=>353, 618=>288, 619=>342, 620=>409, - 621=>326, 622=>633, 623=>853, 624=>853, 625=>853, 626=>579, 627=>624, 628=>581, 629=>542, 630=>711, 631=>583, 632=>542, 633=>451, 634=>451, 635=>496, 636=>430, - 637=>430, 638=>407, 639=>407, 640=>534, 641=>534, 642=>461, 643=>244, 644=>333, 645=>438, 646=>292, 647=>361, 648=>361, 649=>580, 650=>558, 651=>547, 652=>508, - 653=>770, 654=>508, 655=>589, 656=>537, 657=>504, 658=>508, 659=>504, 660=>482, 661=>482, 662=>482, 663=>461, 664=>738, 665=>506, 666=>552, 667=>588, 668=>600, - 669=>329, 670=>545, 671=>581, 672=>615, 673=>482, 674=>482, 675=>896, 676=>930, 677=>898, 678=>728, 679=>538, 680=>704, 681=>804, 682=>582, 683=>608, 684=>538, - 685=>398, 686=>703, 687=>690, 688=>389, 689=>387, 690=>237, 691=>312, 692=>312, 693=>387, 694=>352, 695=>527, 696=>381, 697=>250, 699=>286, 700=>286, 701=>286, - 702=>276, 703=>276, 704=>252, 705=>252, 711=>450, 712=>254, 713=>450, 716=>254, 720=>303, 721=>303, 722=>276, 723=>276, 726=>353, 728=>450, 729=>450, 730=>450, - 731=>450, 733=>450, 734=>375, 736=>402, 737=>218, 738=>303, 739=>381, 740=>252, 741=>436, 742=>436, 743=>436, 744=>436, 745=>436, 750=>435, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>250, 885=>250, 890=>450, 894=>303, 900=>450, 901=>450, 902=>650, 903=>286, 904=>810, 905=>935, 906=>505, 908=>751, 910=>808, 911=>767, - 912=>353, 913=>650, 914=>661, 915=>624, 916=>650, 917=>657, 918=>625, 919=>785, 920=>738, 921=>355, 922=>672, 923=>650, 924=>921, 925=>787, 926=>633, 927=>738, - 928=>785, 929=>605, 931=>636, 932=>600, 933=>594, 934=>738, 935=>641, 936=>789, 937=>746, 938=>355, 939=>594, 940=>607, 941=>483, 942=>539, 943=>353, 944=>547, - 945=>607, 946=>520, 947=>538, 948=>542, 949=>483, 950=>488, 951=>539, 952=>542, 953=>353, 954=>590, 955=>570, 956=>584, 957=>547, 958=>496, 959=>542, 960=>591, - 961=>529, 962=>504, 963=>614, 964=>498, 965=>547, 966=>630, 967=>545, 968=>706, 969=>734, 970=>353, 971=>547, 972=>542, 973=>547, 974=>734, 976=>524, 977=>643, - 978=>618, 979=>787, 980=>618, 981=>613, 982=>734, 983=>561, 984=>738, 985=>542, 986=>688, 987=>504, 988=>624, 989=>417, 990=>531, 991=>593, 992=>704, 993=>519, - 1008=>561, 1009=>529, 1010=>504, 1011=>279, 1012=>738, 1013=>504, 1014=>504, 1015=>608, 1016=>576, 1017=>688, 1018=>921, 1019=>637, 1020=>529, 1021=>688, 1022=>688, 1023=>688, - 1024=>657, 1025=>657, 1026=>719, 1028=>688, 1029=>616, 1030=>355, 1031=>355, 1032=>360, 1033=>976, 1034=>1006, 1035=>785, 1037=>785, 1038=>650, 1040=>681, 1041=>661, 1042=>661, - 1043=>596, 1044=>731, 1045=>657, 1046=>1011, 1047=>561, 1048=>785, 1049=>773, 1050=>696, 1051=>751, 1052=>921, 1053=>785, 1054=>738, 1055=>785, 1056=>605, 1057=>688, 1058=>600, - 1059=>650, 1060=>747, 1061=>641, 1062=>785, 1063=>695, 1064=>1027, 1065=>1027, 1066=>715, 1067=>885, 1068=>606, 1069=>688, 1070=>1074, 1071=>727, 1072=>536, 1073=>584, 1074=>532, - 1075=>455, 1076=>575, 1077=>532, 1078=>1034, 1079=>491, 1080=>580, 1081=>580, 1082=>554, 1083=>573, 1084=>786, 1085=>593, 1086=>542, 1087=>580, 1088=>576, 1089=>504, 1090=>853, - 1091=>522, 1092=>704, 1093=>507, 1094=>628, 1095=>560, 1096=>853, 1097=>901, 1098=>600, 1099=>733, 1100=>490, 1101=>504, 1102=>792, 1103=>596, 1104=>532, 1105=>532, 1106=>561, - 1107=>455, 1108=>504, 1109=>461, 1110=>288, 1111=>288, 1112=>279, 1113=>773, 1114=>790, 1115=>580, 1117=>580, 1118=>522, 1119=>580, 1122=>686, 1123=>794, 1138=>738, 1139=>497, - 1140=>773, 1141=>610, 1164=>621, 1165=>442, 1168=>604, 1169=>476, 1170=>624, 1171=>483, 1172=>657, 1173=>552, 1174=>1011, 1175=>1034, 1176=>561, 1177=>491, 1178=>696, 1179=>545, - 1182=>696, 1183=>545, 1184=>803, 1185=>597, 1186=>785, 1187=>641, 1188=>1025, 1189=>779, 1190=>1085, 1191=>848, 1194=>688, 1195=>504, 1196=>600, 1197=>911, 1198=>594, 1199=>508, - 1202=>641, 1203=>507, 1204=>971, 1205=>809, 1206=>674, 1207=>621, 1210=>674, 1211=>580, 1216=>355, 1217=>1011, 1218=>1034, 1219=>672, 1220=>545, 1223=>785, 1224=>600, 1227=>674, - 1228=>600, 1231=>288, 1232=>681, 1233=>536, 1234=>681, 1235=>536, 1236=>901, 1237=>846, 1238=>657, 1239=>532, 1240=>738, 1241=>532, 1242=>738, 1243=>532, 1244=>1011, 1245=>1034, - 1246=>561, 1247=>491, 1248=>508, 1249=>508, 1250=>785, 1251=>580, 1252=>785, 1253=>580, 1254=>738, 1255=>542, 1256=>738, 1257=>542, 1258=>738, 1259=>542, 1260=>688, 1261=>504, - 1262=>650, 1263=>522, 1264=>650, 1265=>522, 1266=>650, 1267=>522, 1268=>695, 1269=>560, 1270=>596, 1271=>483, 1272=>885, 1273=>733, 7426=>846, 7432=>458, 7433=>288, 7444=>890, - 7446=>542, 7447=>542, 7453=>663, 7454=>853, 7455=>853, 7491=>426, 7492=>301, 7493=>439, 7494=>635, 7495=>439, 7496=>439, 7497=>427, 7498=>427, 7499=>385, 7500=>385, 7501=>439, - 7502=>236, 7503=>407, 7504=>631, 7505=>438, 7506=>426, 7507=>391, 7508=>426, 7509=>426, 7510=>439, 7511=>301, 7512=>438, 7513=>497, 7514=>631, 7515=>414, 7543=>576, 7547=>334, - 7557=>288, 7579=>439, 7580=>391, 7581=>391, 7582=>426, 7583=>385, 7584=>278, 7585=>285, 7586=>439, 7587=>438, 7588=>290, 7589=>298, 7590=>290, 7591=>290, 7592=>286, 7593=>237, - 7594=>236, 7595=>409, 7596=>631, 7597=>631, 7598=>445, 7599=>443, 7600=>438, 7601=>426, 7602=>426, 7603=>374, 7604=>269, 7605=>301, 7606=>438, 7607=>429, 7609=>417, 7610=>414, - 7611=>376, 7612=>376, 7613=>376, 7614=>406, 7615=>426, 7680=>650, 7681=>536, 7682=>661, 7683=>576, 7684=>661, 7685=>576, 7686=>661, 7687=>576, 7688=>688, 7689=>504, 7690=>721, - 7691=>576, 7692=>721, 7693=>576, 7694=>721, 7695=>576, 7696=>721, 7697=>576, 7698=>721, 7699=>576, 7700=>657, 7701=>532, 7702=>657, 7703=>532, 7704=>657, 7705=>532, 7706=>657, - 7707=>532, 7710=>624, 7711=>333, 7712=>719, 7713=>576, 7714=>785, 7715=>580, 7716=>785, 7717=>580, 7718=>785, 7719=>580, 7720=>785, 7721=>580, 7722=>785, 7723=>580, 7724=>355, - 7725=>288, 7728=>672, 7729=>545, 7730=>672, 7731=>545, 7732=>672, 7733=>545, 7734=>598, 7735=>288, 7736=>598, 7737=>288, 7738=>598, 7739=>288, 7740=>598, 7741=>288, 7742=>921, - 7743=>853, 7744=>921, 7745=>853, 7746=>921, 7747=>857, 7748=>787, 7749=>580, 7750=>787, 7751=>580, 7752=>787, 7753=>580, 7754=>787, 7755=>580, 7760=>738, 7761=>542, 7762=>738, - 7763=>542, 7764=>605, 7765=>576, 7766=>605, 7767=>576, 7768=>677, 7769=>430, 7770=>677, 7771=>430, 7772=>677, 7773=>430, 7774=>677, 7775=>430, 7776=>616, 7777=>461, 7778=>616, - 7779=>461, 7784=>616, 7785=>461, 7786=>600, 7787=>361, 7788=>600, 7789=>361, 7790=>600, 7791=>361, 7792=>600, 7793=>361, 7794=>758, 7795=>580, 7796=>758, 7797=>580, 7798=>758, - 7799=>580, 7800=>758, 7801=>580, 7802=>758, 7803=>580, 7804=>650, 7805=>508, 7806=>650, 7807=>508, 7808=>925, 7809=>770, 7810=>925, 7811=>770, 7812=>925, 7813=>770, 7814=>925, - 7815=>770, 7816=>925, 7817=>770, 7818=>641, 7819=>507, 7820=>641, 7821=>507, 7822=>594, 7823=>508, 7824=>625, 7825=>474, 7826=>625, 7827=>474, 7828=>625, 7829=>474, 7830=>580, - 7831=>361, 7832=>770, 7833=>508, 7834=>813, 7835=>461, 7840=>650, 7841=>536, 7842=>650, 7843=>536, 7852=>650, 7853=>536, 7854=>650, 7855=>536, 7856=>650, 7857=>536, 7858=>650, - 7859=>536, 7860=>650, 7861=>536, 7862=>650, 7863=>536, 7864=>657, 7865=>532, 7866=>657, 7867=>532, 7868=>657, 7869=>532, 7878=>657, 7879=>532, 7880=>355, 7881=>288, 7882=>355, - 7883=>288, 7884=>738, 7885=>542, 7886=>738, 7887=>542, 7896=>738, 7897=>542, 7908=>758, 7909=>580, 7910=>758, 7911=>580, 7922=>594, 7923=>508, 7924=>594, 7925=>508, 7926=>594, - 7927=>508, 7928=>594, 7929=>508, 7936=>607, 7937=>607, 7938=>607, 7939=>607, 7940=>607, 7941=>607, 7942=>607, 7943=>607, 7944=>650, 7945=>650, 7946=>782, 7947=>782, 7948=>660, - 7949=>687, 7950=>650, 7951=>650, 7952=>483, 7953=>483, 7954=>483, 7955=>483, 7956=>483, 7957=>483, 7960=>768, 7961=>757, 7962=>960, 7963=>969, 7964=>907, 7965=>931, 7968=>539, - 7969=>539, 7970=>539, 7971=>539, 7972=>539, 7973=>539, 7974=>539, 7975=>539, 7976=>898, 7977=>893, 7978=>1090, 7979=>1101, 7980=>1043, 7981=>1064, 7982=>988, 7983=>985, 7984=>353, - 7985=>353, 7986=>353, 7987=>353, 7988=>353, 7989=>353, 7990=>353, 7991=>353, 7992=>469, 7993=>461, 7994=>661, 7995=>664, 7996=>611, 7997=>635, 7998=>561, 7999=>553, 8000=>542, - 8001=>542, 8002=>542, 8003=>542, 8004=>542, 8005=>542, 8008=>738, 8009=>773, 8010=>1008, 8011=>1015, 8012=>843, 8013=>867, 8016=>547, 8017=>547, 8018=>547, 8019=>547, 8020=>547, - 8021=>547, 8022=>547, 8023=>547, 8025=>765, 8027=>971, 8029=>939, 8031=>857, 8032=>734, 8033=>734, 8034=>734, 8035=>734, 8036=>734, 8037=>734, 8038=>734, 8039=>734, 8040=>746, - 8041=>783, 8042=>1018, 8043=>1023, 8044=>852, 8045=>878, 8046=>844, 8047=>873, 8048=>607, 8049=>607, 8050=>483, 8051=>483, 8052=>539, 8053=>539, 8054=>353, 8055=>353, 8056=>542, - 8057=>542, 8058=>547, 8059=>547, 8060=>734, 8061=>734, 8064=>607, 8065=>607, 8066=>607, 8067=>607, 8068=>607, 8069=>607, 8070=>607, 8071=>607, 8072=>650, 8073=>650, 8074=>782, - 8075=>782, 8076=>660, 8077=>687, 8078=>650, 8079=>650, 8080=>539, 8081=>539, 8082=>539, 8083=>539, 8084=>539, 8085=>539, 8086=>539, 8087=>539, 8088=>898, 8089=>893, 8090=>1090, - 8091=>1101, 8092=>1043, 8093=>1064, 8094=>988, 8095=>985, 8096=>734, 8097=>734, 8098=>734, 8099=>734, 8100=>734, 8101=>734, 8102=>734, 8103=>734, 8104=>746, 8105=>783, 8106=>1018, - 8107=>1023, 8108=>852, 8109=>878, 8110=>844, 8111=>873, 8112=>607, 8113=>607, 8114=>607, 8115=>607, 8116=>607, 8118=>607, 8119=>607, 8120=>650, 8121=>650, 8122=>650, 8123=>650, - 8124=>650, 8125=>450, 8126=>450, 8127=>450, 8128=>450, 8129=>450, 8130=>539, 8131=>539, 8132=>539, 8134=>539, 8135=>539, 8136=>820, 8137=>810, 8138=>956, 8139=>935, 8140=>785, - 8141=>450, 8142=>450, 8143=>450, 8144=>353, 8145=>353, 8146=>353, 8147=>353, 8150=>353, 8151=>353, 8152=>355, 8153=>355, 8154=>529, 8155=>505, 8157=>450, 8158=>450, 8159=>450, - 8160=>547, 8161=>547, 8162=>547, 8163=>547, 8164=>529, 8165=>529, 8166=>547, 8167=>547, 8168=>594, 8169=>594, 8170=>829, 8171=>808, 8172=>711, 8173=>450, 8174=>450, 8175=>450, - 8178=>734, 8179=>734, 8180=>734, 8182=>734, 8183=>734, 8184=>865, 8185=>751, 8186=>886, 8187=>767, 8188=>746, 8189=>450, 8190=>450, 8192=>450, 8193=>900, 8194=>450, 8195=>900, - 8196=>296, 8197=>225, 8198=>150, 8199=>572, 8200=>286, 8201=>180, 8202=>89, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>304, 8209=>304, 8210=>572, 8213=>900, - 8215=>450, 8219=>286, 8223=>460, 8227=>531, 8228=>301, 8229=>600, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>180, 8241=>1560, 8252=>475, 8253=>482, 8254=>450, - 8263=>878, 8264=>678, 8265=>678, 8287=>200, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>360, 8308=>360, - 8309=>360, 8310=>360, 8311=>360, 8312=>360, 8313=>360, 8319=>389, 8320=>360, 8321=>360, 8322=>360, 8323=>360, 8324=>360, 8325=>360, 8326=>360, 8327=>360, 8328=>360, 8329=>360, - 8358=>594, 8367=>951, 8369=>635, 8372=>702, 8373=>572, 8462=>580, 8470=>852, 8486=>746, 8490=>672, 8491=>650, 8531=>872, 8532=>872, 8533=>872, 8534=>872, 8535=>872, 8536=>872, - 8537=>872, 8538=>872, 8539=>872, 8540=>872, 8541=>872, 8542=>872, 8543=>511, 8592=>754, 8593=>754, 8594=>754, 8595=>754, 8706=>465, 8710=>628, 8711=>628, 8719=>716, 8721=>642, - 8722=>754, 8725=>150, 8729=>286, 8730=>573, 8733=>609, 8734=>750, 8735=>754, 8736=>754, 8743=>659, 8744=>659, 8745=>659, 8746=>659, 8747=>469, 8748=>766, 8749=>1063, 8770=>754, - 8771=>754, 8776=>754, 8800=>754, 8801=>754, 8804=>754, 8805=>754, 8962=>687, 8968=>351, 8969=>351, 8970=>351, 8971=>351, 8976=>754, 8977=>461, 8984=>900, 8985=>754, 8992=>469, - 8993=>469, 8997=>900, 9000=>1299, 9085=>827, 9134=>469, 9167=>850, 9251=>687, 9600=>692, 9601=>692, 9602=>692, 9603=>692, 9604=>692, 9605=>692, 9606=>692, 9607=>692, 9608=>692, - 9609=>692, 9610=>692, 9611=>692, 9612=>692, 9613=>692, 9614=>692, 9615=>692, 9616=>692, 9617=>692, 9618=>692, 9619=>692, 9620=>692, 9621=>692, 9622=>692, 9623=>692, 9624=>692, - 9625=>692, 9626=>692, 9627=>692, 9628=>692, 9629=>692, 9630=>692, 9631=>692, 9632=>850, 9633=>850, 9634=>850, 9635=>850, 9636=>850, 9637=>850, 9638=>850, 9639=>850, 9640=>850, - 9641=>850, 9642=>610, 9643=>610, 9644=>850, 9645=>850, 9646=>495, 9647=>495, 9648=>692, 9649=>692, 9650=>692, 9651=>692, 9652=>452, 9653=>452, 9654=>692, 9655=>692, 9656=>452, - 9657=>452, 9658=>692, 9659=>692, 9660=>692, 9661=>692, 9662=>452, 9663=>452, 9664=>692, 9665=>692, 9666=>452, 9667=>452, 9668=>692, 9669=>692, 9670=>692, 9671=>692, 9672=>692, - 9673=>785, 9674=>444, 9675=>785, 9676=>785, 9677=>785, 9678=>785, 9679=>785, 9680=>785, 9681=>785, 9682=>785, 9683=>785, 9684=>785, 9685=>785, 9686=>474, 9687=>474, 9688=>712, - 9689=>873, 9690=>873, 9691=>873, 9692=>348, 9693=>348, 9694=>348, 9695=>348, 9696=>785, 9697=>785, 9698=>692, 9699=>692, 9700=>692, 9701=>692, 9702=>531, 9703=>850, 9704=>850, - 9705=>850, 9706=>850, 9707=>850, 9708=>692, 9709=>692, 9710=>692, 9711=>1007, 9712=>850, 9713=>850, 9714=>850, 9715=>850, 9716=>785, 9717=>785, 9718=>785, 9719=>785, 9720=>692, - 9721=>692, 9722=>692, 9723=>747, 9724=>747, 9725=>659, 9726=>659, 9727=>692, 9728=>807, 9784=>807, 9785=>807, 9786=>807, 9787=>807, 9788=>807, 9791=>552, 9792=>658, 9793=>658, - 9794=>807, 9795=>807, 9796=>807, 9797=>807, 9798=>807, 9799=>807, 9824=>807, 9825=>807, 9826=>807, 9827=>807, 9828=>807, 9829=>807, 9830=>807, 9831=>807, 9833=>424, 9834=>574, - 9835=>807, 9836=>807, 9837=>424, 9838=>321, 9839=>435, 10208=>444, 10216=>351, 10217=>351, 10731=>444, 10764=>1361, 10765=>469, 10766=>469, 11026=>850, 11027=>850, 11028=>850, 11029=>850, - 11030=>692, 11031=>692, 11032=>692, 11033=>692, 11034=>850, 63172=>455, 63173=>542, 63174=>576, 63175=>580, 63176=>853, 63185=>450, 63188=>450, 64256=>637, 64257=>600, 64258=>600, 64259=>847, - 64260=>887, 64261=>669, 64262=>795, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, - 65037=>0, 65038=>0, 65039=>0, 65533=>923} - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerifCondensed-Oblique.z'; - font[:ctg]='DejaVuSerifCondensed-Oblique.ctg.z'; - font[:originalsize]=181700; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifb.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifb.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifb') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerif-Bold'; - font[:desc]={'Ascent'=>939,'Descent'=>-236,'CapHeight'=>939,'Flags'=>32,'FontBBox'=>'[-836 -423 1796 1235]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>600}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>600, 32=>348, 33=>439, 34=>521, 35=>838, 36=>696, 37=>950, 38=>903, 39=>306, 40=>473, 41=>473, 42=>523, 43=>838, 44=>348, 45=>415, 46=>348, - 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>369, 59=>369, 60=>838, 61=>838, 62=>838, - 63=>586, 64=>1000, 65=>776, 66=>845, 67=>796, 68=>867, 69=>762, 70=>710, 71=>854, 72=>945, 73=>468, 74=>473, 75=>869, 76=>703, 77=>1107, 78=>914, - 79=>871, 80=>752, 81=>871, 82=>831, 83=>722, 84=>744, 85=>872, 86=>776, 87=>1123, 88=>776, 89=>714, 90=>730, 91=>473, 92=>365, 93=>473, 94=>838, - 95=>500, 96=>500, 97=>648, 98=>699, 99=>609, 100=>699, 101=>636, 102=>430, 103=>699, 104=>727, 105=>380, 106=>362, 107=>693, 108=>380, 109=>1058, 110=>727, - 111=>667, 112=>699, 113=>699, 114=>527, 115=>563, 116=>462, 117=>727, 118=>581, 119=>861, 120=>596, 121=>581, 122=>568, 123=>643, 124=>364, 125=>643, 126=>838, - 8364=>696, 1027=>690, 8218=>348, 402=>430, 8222=>575, 8230=>1000, 8224=>523, 8225=>523, 710=>500, 8240=>1385, 352=>722, 8249=>400, 338=>1180, 1036=>910, 381=>730, 1039=>945, - 8216=>348, 8217=>348, 8220=>575, 8221=>575, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>563, 8250=>400, 339=>1028, 1116=>722, 382=>568, 376=>714, 160=>348, - 161=>439, 162=>696, 163=>696, 164=>636, 165=>696, 166=>364, 167=>523, 168=>500, 169=>1000, 170=>487, 171=>625, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, - 177=>838, 178=>438, 179=>438, 180=>500, 181=>732, 182=>636, 183=>348, 184=>500, 185=>438, 186=>500, 187=>625, 188=>1043, 189=>1043, 190=>1043, 191=>586, 192=>776, - 193=>776, 194=>776, 195=>776, 196=>776, 197=>776, 198=>1034, 199=>796, 200=>762, 201=>762, 202=>762, 203=>762, 204=>468, 205=>468, 206=>468, 207=>468, 208=>874, - 209=>914, 210=>871, 211=>871, 212=>871, 213=>871, 214=>871, 215=>838, 216=>871, 217=>872, 218=>872, 219=>872, 220=>872, 221=>714, 222=>757, 223=>760, 224=>648, - 225=>648, 226=>648, 227=>648, 228=>648, 229=>648, 230=>975, 231=>609, 232=>636, 233=>636, 234=>636, 235=>636, 236=>380, 237=>380, 238=>380, 239=>380, 240=>667, - 241=>727, 242=>667, 243=>667, 244=>667, 245=>667, 246=>667, 247=>838, 248=>667, 249=>727, 250=>727, 251=>727, 252=>727, 253=>581, 254=>699, 255=>581, 256=>776, - 257=>648, 258=>776, 259=>648, 260=>776, 261=>648, 262=>796, 263=>609, 264=>796, 265=>609, 266=>796, 267=>609, 268=>796, 269=>609, 270=>867, 271=>699, 272=>874, - 273=>699, 274=>762, 275=>636, 276=>762, 277=>636, 278=>762, 279=>636, 280=>762, 281=>636, 282=>762, 283=>636, 284=>854, 285=>699, 286=>854, 287=>699, 288=>854, - 289=>699, 290=>854, 291=>699, 292=>945, 293=>727, 294=>945, 295=>727, 296=>468, 297=>380, 298=>468, 299=>380, 300=>468, 301=>380, 302=>468, 303=>380, 304=>468, - 305=>380, 306=>942, 307=>751, 308=>473, 309=>362, 310=>869, 311=>693, 312=>693, 313=>703, 314=>380, 315=>703, 316=>380, 317=>703, 318=>508, 319=>703, 320=>557, - 321=>710, 322=>385, 323=>914, 324=>727, 325=>914, 326=>727, 327=>914, 328=>727, 329=>1008, 330=>914, 331=>727, 332=>871, 333=>667, 334=>871, 335=>667, 336=>871, - 337=>667, 340=>831, 341=>527, 342=>831, 343=>527, 344=>831, 345=>527, 346=>722, 347=>563, 348=>722, 349=>563, 350=>722, 351=>563, 354=>744, 355=>462, 356=>744, - 357=>462, 358=>744, 359=>462, 360=>872, 361=>727, 362=>872, 363=>727, 364=>872, 365=>727, 366=>872, 367=>727, 368=>872, 369=>727, 370=>872, 371=>727, 372=>1123, - 373=>861, 374=>714, 375=>581, 377=>730, 378=>568, 379=>730, 380=>568, 383=>430, 384=>699, 385=>845, 386=>854, 387=>699, 388=>854, 389=>699, 390=>796, 391=>796, - 392=>609, 393=>874, 394=>867, 395=>854, 396=>699, 397=>667, 398=>762, 399=>871, 400=>696, 401=>710, 403=>854, 404=>771, 405=>1043, 406=>468, 407=>468, 408=>869, - 409=>693, 410=>380, 411=>701, 412=>1058, 413=>914, 414=>727, 415=>871, 416=>871, 417=>667, 418=>1200, 419=>943, 420=>752, 421=>699, 422=>831, 423=>722, 424=>563, - 425=>707, 426=>331, 427=>462, 428=>744, 429=>462, 430=>744, 431=>872, 432=>727, 433=>890, 434=>890, 435=>714, 436=>708, 437=>730, 438=>568, 439=>568, 440=>568, - 441=>568, 443=>696, 444=>754, 445=>568, 446=>536, 448=>295, 449=>492, 450=>459, 451=>295, 452=>1597, 453=>1435, 454=>1267, 455=>1176, 456=>1065, 457=>742, 458=>1387, - 459=>1276, 460=>1089, 461=>776, 462=>648, 463=>468, 464=>380, 465=>871, 466=>667, 467=>872, 468=>727, 469=>872, 470=>727, 471=>872, 472=>727, 473=>872, 474=>727, - 475=>872, 476=>727, 477=>636, 478=>776, 479=>648, 480=>776, 481=>648, 482=>1034, 483=>975, 484=>896, 485=>699, 486=>854, 487=>699, 488=>869, 489=>693, 490=>871, - 491=>667, 492=>871, 493=>667, 494=>568, 495=>568, 496=>380, 497=>1597, 498=>1435, 499=>1267, 500=>854, 501=>699, 502=>1221, 504=>914, 505=>727, 506=>776, 507=>648, - 508=>1034, 509=>975, 510=>871, 511=>667, 512=>776, 513=>648, 514=>776, 515=>648, 516=>762, 517=>636, 518=>762, 519=>636, 520=>468, 521=>380, 522=>468, 523=>380, - 524=>871, 525=>667, 526=>871, 527=>667, 528=>831, 529=>527, 530=>831, 531=>527, 532=>872, 533=>727, 534=>872, 535=>727, 536=>722, 537=>563, 538=>744, 539=>462, - 542=>945, 543=>727, 545=>791, 548=>730, 549=>568, 550=>776, 551=>648, 552=>762, 553=>636, 554=>871, 555=>667, 556=>871, 557=>667, 558=>871, 559=>667, 560=>871, - 561=>667, 562=>714, 563=>581, 564=>573, 565=>922, 566=>564, 567=>362, 568=>1031, 569=>1031, 570=>776, 571=>796, 572=>609, 573=>703, 574=>744, 575=>563, 576=>568, - 577=>660, 578=>547, 581=>776, 592=>648, 593=>699, 594=>699, 595=>699, 596=>609, 597=>609, 598=>699, 599=>730, 600=>636, 601=>636, 602=>907, 603=>608, 604=>562, - 605=>907, 606=>720, 607=>387, 608=>699, 609=>699, 610=>626, 611=>712, 612=>627, 613=>727, 614=>727, 615=>727, 616=>380, 617=>380, 618=>380, 619=>409, 620=>514, - 621=>380, 622=>795, 623=>1058, 624=>1058, 625=>1058, 626=>727, 627=>727, 628=>712, 629=>667, 630=>1061, 631=>749, 632=>667, 633=>571, 634=>571, 635=>571, 636=>527, - 637=>527, 638=>452, 639=>487, 640=>801, 641=>801, 642=>563, 643=>331, 644=>430, 645=>540, 646=>331, 647=>492, 648=>462, 649=>727, 650=>679, 651=>694, 652=>641, - 653=>907, 654=>635, 655=>727, 656=>568, 657=>568, 658=>568, 659=>568, 660=>536, 661=>536, 662=>536, 663=>545, 664=>871, 665=>695, 666=>720, 667=>626, 668=>732, - 669=>384, 670=>740, 671=>646, 672=>699, 673=>536, 674=>536, 675=>1117, 676=>1179, 677=>1117, 678=>911, 679=>715, 680=>909, 681=>1039, 682=>790, 683=>795, 684=>662, - 685=>443, 686=>613, 687=>717, 688=>521, 689=>519, 690=>313, 691=>414, 692=>414, 693=>480, 694=>527, 695=>662, 696=>485, 697=>302, 699=>348, 700=>348, 701=>348, - 702=>366, 703=>366, 704=>313, 705=>313, 711=>500, 712=>282, 713=>500, 716=>282, 720=>369, 721=>369, 722=>366, 723=>366, 726=>392, 728=>500, 729=>500, 730=>500, - 731=>500, 733=>500, 734=>417, 736=>458, 737=>292, 738=>395, 739=>475, 740=>313, 741=>484, 742=>484, 743=>484, 744=>484, 745=>484, 750=>553, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>302, 885=>302, 890=>500, 894=>369, 900=>500, 901=>500, 902=>776, 903=>348, 904=>947, 905=>1118, 906=>662, 908=>887, 910=>953, 911=>911, - 912=>484, 913=>776, 914=>845, 915=>710, 916=>776, 917=>762, 918=>730, 919=>945, 920=>871, 921=>468, 922=>869, 923=>776, 924=>1107, 925=>914, 926=>704, 927=>871, - 928=>944, 929=>752, 931=>707, 932=>744, 933=>714, 934=>871, 935=>776, 936=>913, 937=>890, 938=>468, 939=>714, 940=>770, 941=>608, 942=>727, 943=>484, 944=>694, - 945=>770, 946=>664, 947=>660, 948=>667, 949=>608, 950=>592, 951=>727, 952=>667, 953=>484, 954=>750, 955=>701, 956=>732, 957=>694, 958=>592, 959=>667, 960=>732, - 961=>665, 962=>609, 963=>737, 964=>673, 965=>694, 966=>905, 967=>658, 968=>941, 969=>952, 970=>484, 971=>694, 972=>667, 973=>694, 974=>952, 976=>667, 977=>849, - 978=>764, 979=>969, 980=>764, 981=>941, 982=>952, 983=>655, 984=>871, 985=>667, 986=>796, 987=>609, 988=>710, 989=>527, 990=>590, 991=>660, 992=>796, 993=>667, - 1008=>655, 1009=>665, 1010=>609, 1011=>362, 1012=>871, 1013=>609, 1014=>609, 1015=>757, 1016=>699, 1017=>796, 1018=>1107, 1019=>860, 1020=>692, 1021=>796, 1022=>796, 1023=>796, - 1024=>762, 1025=>762, 1026=>901, 1028=>795, 1029=>722, 1030=>468, 1031=>468, 1032=>473, 1033=>1202, 1034=>1262, 1035=>963, 1037=>945, 1038=>812, 1040=>814, 1041=>854, 1042=>845, - 1043=>690, 1044=>889, 1045=>762, 1046=>1312, 1047=>721, 1048=>945, 1049=>945, 1050=>910, 1051=>884, 1052=>1107, 1053=>945, 1054=>871, 1055=>944, 1056=>752, 1057=>796, 1058=>744, - 1059=>812, 1060=>949, 1061=>776, 1062=>966, 1063=>913, 1064=>1268, 1065=>1293, 1066=>957, 1067=>1202, 1068=>825, 1069=>795, 1070=>1287, 1071=>882, 1072=>648, 1073=>667, 1074=>695, - 1075=>613, 1076=>667, 1077=>636, 1078=>1010, 1079=>638, 1080=>742, 1081=>742, 1082=>722, 1083=>705, 1084=>869, 1085=>732, 1086=>667, 1087=>732, 1088=>699, 1089=>609, 1090=>620, - 1091=>640, 1092=>902, 1093=>596, 1094=>739, 1095=>732, 1096=>1075, 1097=>1082, 1098=>767, 1099=>1002, 1100=>679, 1101=>609, 1102=>1025, 1103=>739, 1104=>636, 1105=>636, 1106=>719, - 1107=>613, 1108=>609, 1109=>563, 1110=>380, 1111=>380, 1112=>362, 1113=>968, 1114=>995, 1115=>727, 1117=>742, 1118=>640, 1119=>732, 1122=>880, 1123=>703, 1138=>871, 1139=>652, - 1140=>916, 1141=>749, 1164=>792, 1165=>664, 1168=>700, 1169=>618, 1170=>710, 1171=>637, 1172=>868, 1173=>716, 1174=>1312, 1175=>1010, 1176=>721, 1177=>638, 1178=>947, 1179=>744, - 1182=>910, 1183=>693, 1184=>999, 1185=>733, 1186=>966, 1187=>739, 1188=>1187, 1189=>980, 1190=>1345, 1191=>1059, 1194=>796, 1195=>609, 1196=>744, 1197=>620, 1198=>714, 1199=>581, - 1202=>866, 1203=>649, 1204=>1250, 1205=>997, 1206=>928, 1207=>739, 1210=>910, 1211=>727, 1216=>468, 1217=>1312, 1218=>1010, 1219=>869, 1220=>693, 1223=>945, 1224=>732, 1227=>913, - 1228=>732, 1231=>380, 1232=>814, 1233=>648, 1234=>814, 1235=>648, 1236=>1034, 1237=>975, 1238=>762, 1239=>636, 1240=>871, 1241=>636, 1242=>871, 1243=>636, 1244=>1312, 1245=>1010, - 1246=>721, 1247=>638, 1248=>568, 1249=>568, 1250=>945, 1251=>742, 1252=>945, 1253=>742, 1254=>871, 1255=>667, 1256=>871, 1257=>667, 1258=>871, 1259=>667, 1260=>795, 1261=>609, - 1262=>812, 1263=>640, 1264=>812, 1265=>640, 1266=>812, 1267=>640, 1268=>913, 1269=>732, 1270=>690, 1271=>613, 1272=>1202, 1273=>1002, 7426=>940, 7432=>509, 7433=>320, 7444=>989, - 7446=>667, 7447=>667, 7453=>737, 7454=>948, 7455=>948, 7491=>466, 7492=>466, 7493=>498, 7494=>657, 7495=>499, 7496=>498, 7497=>444, 7498=>444, 7499=>412, 7500=>412, 7501=>498, - 7502=>300, 7503=>523, 7504=>729, 7505=>473, 7506=>467, 7507=>427, 7508=>467, 7509=>467, 7510=>499, 7511=>371, 7512=>520, 7513=>434, 7514=>729, 7515=>491, 7543=>640, 7547=>380, - 7557=>380, 7579=>498, 7580=>427, 7581=>427, 7582=>467, 7583=>412, 7584=>383, 7585=>373, 7586=>498, 7587=>522, 7588=>300, 7589=>307, 7590=>300, 7591=>300, 7592=>370, 7593=>368, - 7594=>321, 7595=>430, 7596=>682, 7597=>729, 7598=>588, 7599=>587, 7600=>472, 7601=>467, 7602=>522, 7603=>400, 7604=>387, 7605=>371, 7606=>520, 7607=>475, 7609=>489, 7610=>491, - 7611=>412, 7612=>527, 7613=>412, 7614=>452, 7615=>467, 7680=>776, 7681=>648, 7682=>845, 7683=>699, 7684=>845, 7685=>699, 7686=>845, 7687=>699, 7688=>796, 7689=>609, 7690=>867, - 7691=>699, 7692=>867, 7693=>699, 7694=>867, 7695=>699, 7696=>867, 7697=>699, 7698=>867, 7699=>699, 7700=>762, 7701=>636, 7702=>762, 7703=>636, 7704=>762, 7705=>636, 7706=>762, - 7707=>636, 7710=>710, 7711=>430, 7712=>854, 7713=>699, 7714=>945, 7715=>727, 7716=>945, 7717=>727, 7718=>945, 7719=>727, 7720=>945, 7721=>727, 7722=>945, 7723=>727, 7724=>468, - 7725=>380, 7728=>869, 7729=>693, 7730=>869, 7731=>693, 7732=>869, 7733=>693, 7734=>703, 7735=>380, 7736=>703, 7737=>380, 7738=>703, 7739=>380, 7740=>703, 7741=>380, 7742=>1107, - 7743=>1058, 7744=>1107, 7745=>1058, 7746=>1107, 7747=>1058, 7748=>914, 7749=>727, 7750=>914, 7751=>727, 7752=>914, 7753=>727, 7754=>914, 7755=>727, 7760=>871, 7761=>667, 7762=>871, - 7763=>667, 7764=>752, 7765=>699, 7766=>752, 7767=>699, 7768=>831, 7769=>527, 7770=>831, 7771=>527, 7772=>831, 7773=>527, 7774=>831, 7775=>527, 7776=>722, 7777=>563, 7778=>722, - 7779=>563, 7784=>722, 7785=>563, 7786=>744, 7787=>462, 7788=>744, 7789=>462, 7790=>744, 7791=>462, 7792=>744, 7793=>462, 7794=>872, 7795=>727, 7796=>872, 7797=>727, 7798=>872, - 7799=>727, 7800=>872, 7801=>727, 7802=>872, 7803=>727, 7804=>776, 7805=>581, 7806=>776, 7807=>581, 7808=>1123, 7809=>861, 7810=>1123, 7811=>861, 7812=>1123, 7813=>861, 7814=>1123, - 7815=>861, 7816=>1123, 7817=>861, 7818=>776, 7819=>596, 7820=>776, 7821=>596, 7822=>714, 7823=>581, 7824=>730, 7825=>568, 7826=>730, 7827=>568, 7828=>730, 7829=>568, 7830=>727, - 7831=>462, 7832=>861, 7833=>581, 7834=>1014, 7835=>563, 7840=>776, 7841=>648, 7842=>776, 7843=>648, 7852=>776, 7853=>648, 7854=>776, 7855=>648, 7856=>776, 7857=>648, 7858=>776, - 7859=>648, 7860=>776, 7861=>648, 7862=>776, 7863=>648, 7864=>762, 7865=>636, 7866=>762, 7867=>636, 7868=>762, 7869=>636, 7878=>762, 7879=>636, 7880=>468, 7881=>380, 7882=>468, - 7883=>380, 7884=>871, 7885=>667, 7886=>871, 7887=>667, 7896=>871, 7897=>667, 7908=>872, 7909=>727, 7910=>872, 7911=>727, 7922=>714, 7923=>581, 7924=>714, 7925=>581, 7926=>714, - 7927=>581, 7928=>714, 7929=>581, 7936=>770, 7937=>770, 7938=>770, 7939=>770, 7940=>770, 7941=>770, 7942=>770, 7943=>770, 7944=>776, 7945=>776, 7946=>978, 7947=>978, 7948=>832, - 7949=>849, 7950=>776, 7951=>776, 7952=>608, 7953=>608, 7954=>608, 7955=>608, 7956=>608, 7957=>608, 7960=>917, 7961=>909, 7962=>1169, 7963=>1169, 7964=>1093, 7965=>1120, 7968=>727, - 7969=>727, 7970=>727, 7971=>727, 7972=>727, 7973=>727, 7974=>727, 7975=>727, 7976=>1100, 7977=>1094, 7978=>1358, 7979=>1361, 7980=>1279, 7981=>1308, 7982=>1197, 7983=>1194, 7984=>484, - 7985=>484, 7986=>484, 7987=>484, 7988=>484, 7989=>484, 7990=>484, 7991=>484, 7992=>629, 7993=>617, 7994=>878, 7995=>881, 7996=>799, 7997=>831, 7998=>723, 7999=>714, 8000=>667, - 8001=>667, 8002=>667, 8003=>667, 8004=>667, 8005=>667, 8008=>900, 8009=>935, 8010=>1240, 8011=>1237, 8012=>1035, 8013=>1066, 8016=>694, 8017=>694, 8018=>694, 8019=>694, 8020=>694, - 8021=>694, 8022=>694, 8023=>694, 8025=>922, 8027=>1186, 8029=>1133, 8031=>1019, 8032=>952, 8033=>952, 8034=>952, 8035=>952, 8036=>952, 8037=>952, 8038=>952, 8039=>952, 8040=>931, - 8041=>963, 8042=>1268, 8043=>1274, 8044=>1054, 8045=>1088, 8046=>1023, 8047=>1060, 8048=>770, 8049=>770, 8050=>608, 8051=>608, 8052=>727, 8053=>727, 8054=>484, 8055=>484, 8056=>667, - 8057=>667, 8058=>694, 8059=>694, 8060=>952, 8061=>952, 8064=>770, 8065=>770, 8066=>770, 8067=>770, 8068=>770, 8069=>770, 8070=>770, 8071=>770, 8072=>776, 8073=>776, 8074=>978, - 8075=>978, 8076=>832, 8077=>849, 8078=>776, 8079=>776, 8080=>727, 8081=>727, 8082=>727, 8083=>727, 8084=>727, 8085=>727, 8086=>727, 8087=>727, 8088=>1100, 8089=>1094, 8090=>1358, - 8091=>1361, 8092=>1279, 8093=>1308, 8094=>1197, 8095=>1194, 8096=>952, 8097=>952, 8098=>952, 8099=>952, 8100=>952, 8101=>952, 8102=>952, 8103=>952, 8104=>931, 8105=>963, 8106=>1268, - 8107=>1274, 8108=>1054, 8109=>1088, 8110=>1023, 8111=>1060, 8112=>770, 8113=>770, 8114=>770, 8115=>770, 8116=>770, 8118=>770, 8119=>770, 8120=>776, 8121=>776, 8122=>811, 8123=>776, - 8124=>776, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>727, 8131=>727, 8132=>727, 8134=>727, 8135=>727, 8136=>1000, 8137=>947, 8138=>1191, 8139=>1118, 8140=>945, - 8141=>500, 8142=>500, 8143=>500, 8144=>484, 8145=>484, 8146=>484, 8147=>484, 8150=>484, 8151=>484, 8152=>468, 8153=>468, 8154=>714, 8155=>662, 8157=>500, 8158=>500, 8159=>500, - 8160=>694, 8161=>694, 8162=>694, 8163=>694, 8164=>665, 8165=>665, 8166=>694, 8167=>694, 8168=>714, 8169=>714, 8170=>1019, 8171=>953, 8172=>910, 8173=>500, 8174=>500, 8175=>500, - 8178=>952, 8179=>952, 8180=>952, 8182=>952, 8183=>952, 8184=>1069, 8185=>887, 8186=>1101, 8187=>911, 8188=>890, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, - 8196=>330, 8197=>250, 8198=>167, 8199=>696, 8200=>348, 8201=>200, 8202=>100, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>415, 8209=>415, 8210=>696, 8213=>1000, - 8215=>500, 8219=>348, 8223=>575, 8227=>639, 8228=>348, 8229=>674, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1820, 8252=>629, 8253=>586, 8254=>500, - 8263=>1082, 8264=>856, 8265=>856, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>438, 8308=>438, - 8309=>438, 8310=>438, 8311=>438, 8312=>438, 8313=>438, 8319=>519, 8320=>438, 8321=>438, 8322=>438, 8323=>438, 8324=>438, 8325=>438, 8326=>438, 8327=>438, 8328=>438, 8329=>438, - 8358=>696, 8367=>1155, 8369=>790, 8372=>876, 8373=>696, 8462=>727, 8470=>1087, 8486=>890, 8490=>869, 8491=>776, 8531=>1035, 8532=>1035, 8533=>1035, 8534=>1035, 8535=>1035, 8536=>1035, - 8537=>1035, 8538=>1035, 8539=>1035, 8540=>1035, 8541=>1035, 8542=>1035, 8543=>615, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8706=>534, 8710=>753, 8711=>753, 8719=>842, 8721=>753, - 8722=>838, 8725=>167, 8729=>348, 8730=>657, 8733=>672, 8734=>833, 8735=>838, 8736=>838, 8743=>812, 8744=>812, 8745=>812, 8746=>812, 8747=>579, 8748=>1000, 8749=>1391, 8770=>838, - 8771=>838, 8776=>838, 8800=>838, 8801=>838, 8804=>838, 8805=>838, 8962=>834, 8968=>473, 8969=>473, 8970=>473, 8971=>473, 8976=>838, 8977=>539, 8984=>928, 8985=>838, 8992=>579, - 8993=>579, 8997=>1000, 9000=>1443, 9085=>1008, 9134=>579, 9167=>945, 9251=>834, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, - 9609=>769, 9610=>769, 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, - 9625=>769, 9626=>769, 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, - 9641=>945, 9642=>678, 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, - 9657=>502, 9658=>769, 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, - 9673=>873, 9674=>494, 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>791, - 9689=>970, 9690=>970, 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>873, 9697=>873, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>590, 9703=>945, 9704=>945, - 9705=>945, 9706=>945, 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, - 9721=>769, 9722=>769, 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9784=>896, 9785=>896, 9786=>896, 9787=>896, 9788=>896, 9791=>614, 9792=>731, 9793=>731, - 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9833=>472, 9834=>638, - 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 10208=>494, 10216=>457, 10217=>457, 10731=>494, 10764=>1782, 10765=>610, 10766=>610, 11026=>945, 11027=>945, 11028=>945, 11029=>945, - 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 63173=>667, 63185=>500, 63188=>500, 64256=>930, 64257=>727, 64258=>727, 64259=>1126, 64260=>1123, 64261=>871, 64262=>971, 65024=>0, - 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, 65037=>0, 65038=>0, 65039=>0, 65533=>1113}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerif-Bold.z'; - font[:ctg]='DejaVuSerif-Bold.ctg.z'; - font[:originalsize]=203488; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifbi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifbi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifbi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerif-BoldOblique'; - font[:desc]={'Ascent'=>939,'Descent'=>-236,'CapHeight'=>939,'Flags'=>96,'FontBBox'=>'[-906 -423 1760 1235]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>600}; - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>600, 32=>348, 33=>439, 34=>521, 35=>838, 36=>696, 37=>950, 38=>903, 39=>306, 40=>473, 41=>473, 42=>523, 43=>838, 44=>348, 45=>415, 46=>348, - 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>369, 59=>369, 60=>838, 61=>838, 62=>838, - 63=>586, 64=>1000, 65=>776, 66=>845, 67=>796, 68=>867, 69=>762, 70=>710, 71=>854, 72=>945, 73=>468, 74=>473, 75=>869, 76=>703, 77=>1107, 78=>914, - 79=>871, 80=>752, 81=>871, 82=>831, 83=>722, 84=>744, 85=>872, 86=>776, 87=>1123, 88=>776, 89=>714, 90=>730, 91=>473, 92=>365, 93=>473, 94=>838, - 95=>500, 96=>500, 97=>648, 98=>699, 99=>609, 100=>699, 101=>636, 102=>430, 103=>699, 104=>727, 105=>380, 106=>362, 107=>693, 108=>380, 109=>1058, 110=>727, - 111=>667, 112=>699, 113=>699, 114=>527, 115=>563, 116=>462, 117=>727, 118=>581, 119=>861, 120=>596, 121=>581, 122=>568, 123=>643, 124=>364, 125=>643, 126=>838, - 8364=>696, 1027=>690, 8218=>348, 402=>430, 8222=>575, 8230=>1000, 8224=>523, 8225=>523, 710=>500, 8240=>1385, 352=>722, 8249=>400, 338=>1180, 1036=>910, 381=>730, 1039=>945, - 8216=>348, 8217=>348, 8220=>575, 8221=>575, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>563, 8250=>400, 339=>1028, 1116=>677, 382=>568, 376=>714, 160=>348, - 161=>439, 162=>696, 163=>696, 164=>636, 165=>696, 166=>364, 167=>523, 168=>500, 169=>1000, 170=>487, 171=>625, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, - 177=>838, 178=>438, 179=>438, 180=>500, 181=>732, 182=>636, 183=>348, 184=>500, 185=>438, 186=>500, 187=>625, 188=>1043, 189=>1043, 190=>1043, 191=>586, 192=>776, - 193=>776, 194=>776, 195=>776, 196=>776, 197=>776, 198=>1034, 199=>796, 200=>762, 201=>762, 202=>762, 203=>762, 204=>468, 205=>468, 206=>468, 207=>468, 208=>874, - 209=>914, 210=>871, 211=>871, 212=>871, 213=>871, 214=>871, 215=>838, 216=>871, 217=>872, 218=>872, 219=>872, 220=>872, 221=>714, 222=>757, 223=>760, 224=>648, - 225=>648, 226=>648, 227=>648, 228=>648, 229=>648, 230=>975, 231=>609, 232=>636, 233=>636, 234=>636, 235=>636, 236=>380, 237=>380, 238=>380, 239=>380, 240=>667, - 241=>727, 242=>667, 243=>667, 244=>667, 245=>667, 246=>667, 247=>838, 248=>667, 249=>727, 250=>727, 251=>727, 252=>727, 253=>581, 254=>699, 255=>581, 256=>776, - 257=>648, 258=>776, 259=>648, 260=>776, 261=>648, 262=>796, 263=>609, 264=>796, 265=>609, 266=>796, 267=>609, 268=>796, 269=>609, 270=>867, 271=>699, 272=>874, - 273=>699, 274=>762, 275=>636, 276=>762, 277=>636, 278=>762, 279=>636, 280=>762, 281=>636, 282=>762, 283=>636, 284=>854, 285=>699, 286=>854, 287=>699, 288=>854, - 289=>699, 290=>854, 291=>699, 292=>945, 293=>727, 294=>945, 295=>727, 296=>468, 297=>380, 298=>468, 299=>380, 300=>468, 301=>380, 302=>468, 303=>380, 304=>468, - 305=>380, 306=>942, 307=>751, 308=>473, 309=>362, 310=>869, 311=>693, 312=>693, 313=>703, 314=>380, 315=>703, 316=>380, 317=>703, 318=>508, 319=>703, 320=>557, - 321=>710, 322=>385, 323=>914, 324=>727, 325=>914, 326=>727, 327=>914, 328=>727, 329=>1008, 330=>914, 331=>727, 332=>871, 333=>667, 334=>871, 335=>667, 336=>871, - 337=>667, 340=>831, 341=>527, 342=>831, 343=>527, 344=>831, 345=>527, 346=>722, 347=>563, 348=>722, 349=>563, 350=>722, 351=>563, 354=>744, 355=>462, 356=>744, - 357=>462, 358=>744, 359=>462, 360=>872, 361=>727, 362=>872, 363=>727, 364=>872, 365=>727, 366=>872, 367=>727, 368=>872, 369=>727, 370=>872, 371=>727, 372=>1123, - 373=>861, 374=>714, 375=>581, 377=>730, 378=>568, 379=>730, 380=>568, 383=>430, 384=>699, 385=>845, 386=>854, 387=>699, 388=>854, 389=>699, 390=>796, 391=>796, - 392=>609, 393=>874, 394=>867, 395=>854, 396=>699, 397=>667, 398=>762, 399=>871, 400=>696, 401=>710, 403=>854, 404=>771, 405=>1043, 406=>468, 407=>468, 408=>869, - 409=>693, 410=>380, 411=>701, 412=>1058, 413=>914, 414=>727, 415=>871, 416=>871, 417=>667, 418=>1200, 419=>943, 420=>752, 421=>699, 422=>831, 423=>722, 424=>563, - 425=>707, 426=>331, 427=>462, 428=>744, 429=>462, 430=>744, 431=>872, 432=>727, 433=>890, 434=>890, 435=>714, 436=>699, 437=>730, 438=>568, 439=>568, 440=>568, - 441=>568, 443=>696, 444=>754, 445=>568, 446=>536, 448=>295, 449=>492, 450=>459, 451=>295, 452=>1597, 453=>1435, 454=>1267, 455=>1176, 456=>1065, 457=>742, 458=>1387, - 459=>1276, 460=>1089, 461=>776, 462=>648, 463=>468, 464=>380, 465=>871, 466=>667, 467=>872, 468=>727, 469=>872, 470=>727, 471=>872, 472=>727, 473=>872, 474=>727, - 475=>872, 476=>727, 477=>636, 478=>776, 479=>648, 480=>776, 481=>648, 482=>1034, 483=>975, 484=>896, 485=>699, 486=>854, 487=>699, 488=>869, 489=>693, 490=>871, - 491=>667, 492=>871, 493=>667, 494=>568, 495=>568, 496=>362, 497=>1597, 498=>1435, 499=>1267, 500=>854, 501=>699, 502=>1221, 504=>914, 505=>727, 506=>776, 507=>648, - 508=>1034, 509=>975, 510=>871, 511=>667, 512=>776, 513=>648, 514=>776, 515=>648, 516=>762, 517=>636, 518=>762, 519=>636, 520=>468, 521=>380, 522=>468, 523=>380, - 524=>871, 525=>667, 526=>871, 527=>667, 528=>831, 529=>527, 530=>831, 531=>527, 532=>872, 533=>727, 534=>872, 535=>727, 536=>722, 537=>563, 538=>744, 539=>462, - 542=>945, 543=>727, 545=>791, 548=>730, 549=>568, 550=>776, 551=>648, 552=>762, 553=>636, 554=>871, 555=>667, 556=>871, 557=>667, 558=>871, 559=>667, 560=>871, - 561=>667, 562=>714, 563=>581, 564=>573, 565=>922, 566=>564, 567=>362, 568=>1031, 569=>1031, 570=>776, 571=>796, 572=>609, 573=>703, 574=>744, 575=>563, 576=>568, - 577=>660, 578=>547, 581=>776, 592=>648, 593=>699, 594=>699, 595=>699, 596=>609, 597=>609, 598=>699, 599=>730, 600=>636, 601=>636, 602=>907, 603=>608, 604=>562, - 605=>907, 606=>720, 607=>387, 608=>699, 609=>699, 610=>626, 611=>712, 612=>627, 613=>727, 614=>727, 615=>727, 616=>380, 617=>380, 618=>380, 619=>409, 620=>514, - 621=>380, 622=>795, 623=>1058, 624=>1058, 625=>1058, 626=>727, 627=>727, 628=>712, 629=>667, 630=>1061, 631=>749, 632=>667, 633=>571, 634=>571, 635=>571, 636=>527, - 637=>527, 638=>452, 639=>487, 640=>801, 641=>801, 642=>563, 643=>331, 644=>430, 645=>540, 646=>331, 647=>492, 648=>462, 649=>727, 650=>679, 651=>694, 652=>641, - 653=>907, 654=>635, 655=>727, 656=>568, 657=>568, 658=>568, 659=>568, 660=>536, 661=>536, 662=>536, 663=>545, 664=>871, 665=>695, 666=>720, 667=>626, 668=>732, - 669=>384, 670=>740, 671=>646, 672=>699, 673=>536, 674=>536, 675=>1117, 676=>1179, 677=>1117, 678=>911, 679=>715, 680=>909, 681=>1039, 682=>790, 683=>795, 684=>662, - 685=>443, 686=>613, 687=>717, 688=>521, 689=>519, 690=>313, 691=>414, 692=>414, 693=>480, 694=>527, 695=>662, 696=>485, 697=>302, 699=>348, 700=>348, 701=>348, - 702=>366, 703=>366, 704=>313, 705=>313, 711=>500, 712=>282, 713=>500, 716=>282, 720=>369, 721=>369, 722=>366, 723=>366, 726=>392, 728=>500, 729=>500, 730=>500, - 731=>500, 733=>500, 734=>417, 736=>458, 737=>292, 738=>395, 739=>475, 740=>313, 741=>484, 742=>484, 743=>484, 744=>484, 745=>484, 750=>553, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>302, 885=>302, 890=>500, 894=>369, 900=>500, 901=>500, 902=>776, 903=>348, 904=>947, 905=>1136, 906=>662, 908=>887, 910=>953, 911=>911, - 912=>484, 913=>776, 914=>845, 915=>710, 916=>776, 917=>762, 918=>730, 919=>945, 920=>871, 921=>468, 922=>869, 923=>776, 924=>1107, 925=>914, 926=>704, 927=>871, - 928=>945, 929=>752, 931=>707, 932=>744, 933=>714, 934=>871, 935=>776, 936=>913, 937=>890, 938=>468, 939=>714, 940=>770, 941=>608, 942=>727, 943=>484, 944=>694, - 945=>770, 946=>664, 947=>660, 948=>667, 949=>608, 950=>592, 951=>727, 952=>667, 953=>484, 954=>750, 955=>701, 956=>732, 957=>694, 958=>592, 959=>667, 960=>732, - 961=>665, 962=>609, 963=>737, 964=>673, 965=>694, 966=>905, 967=>658, 968=>941, 969=>952, 970=>484, 971=>694, 972=>667, 973=>694, 974=>952, 976=>667, 977=>849, - 978=>764, 979=>969, 980=>764, 981=>941, 982=>952, 983=>655, 984=>871, 985=>667, 986=>796, 987=>609, 988=>710, 989=>527, 990=>590, 991=>660, 992=>796, 993=>667, - 1008=>655, 1009=>665, 1010=>609, 1011=>362, 1012=>871, 1013=>609, 1014=>609, 1015=>757, 1016=>699, 1017=>796, 1018=>1107, 1019=>860, 1020=>692, 1021=>796, 1022=>796, 1023=>796, - 1024=>762, 1025=>762, 1026=>901, 1028=>795, 1029=>722, 1030=>468, 1031=>468, 1032=>473, 1033=>1202, 1034=>1262, 1035=>963, 1037=>945, 1038=>812, 1040=>814, 1041=>854, 1042=>845, - 1043=>690, 1044=>889, 1045=>762, 1046=>1312, 1047=>721, 1048=>945, 1049=>945, 1050=>910, 1051=>884, 1052=>1107, 1053=>945, 1054=>871, 1055=>945, 1056=>752, 1057=>796, 1058=>744, - 1059=>812, 1060=>949, 1061=>776, 1062=>966, 1063=>913, 1064=>1268, 1065=>1293, 1066=>957, 1067=>1202, 1068=>825, 1069=>795, 1070=>1287, 1071=>882, 1072=>648, 1073=>722, 1074=>657, - 1075=>563, 1076=>695, 1077=>636, 1078=>1306, 1079=>638, 1080=>727, 1081=>727, 1082=>677, 1083=>732, 1084=>970, 1085=>729, 1086=>667, 1087=>727, 1088=>699, 1089=>609, 1090=>1058, - 1091=>598, 1092=>902, 1093=>596, 1094=>803, 1095=>715, 1096=>1058, 1097=>1134, 1098=>727, 1099=>1018, 1100=>660, 1101=>645, 1102=>1001, 1103=>796, 1104=>636, 1105=>636, 1106=>719, - 1107=>563, 1108=>609, 1109=>563, 1110=>380, 1111=>380, 1112=>362, 1113=>1014, 1114=>1011, 1115=>727, 1117=>727, 1118=>598, 1119=>727, 1122=>880, 1123=>1050, 1138=>871, 1139=>652, - 1140=>916, 1141=>749, 1164=>792, 1165=>664, 1168=>700, 1169=>618, 1170=>710, 1171=>637, 1172=>854, 1173=>705, 1174=>1312, 1175=>1306, 1176=>721, 1177=>638, 1178=>902, 1179=>693, - 1182=>910, 1183=>693, 1184=>999, 1185=>733, 1186=>952, 1187=>805, 1188=>1187, 1189=>980, 1190=>1324, 1191=>1013, 1194=>796, 1195=>609, 1196=>744, 1197=>1142, 1198=>714, 1199=>581, - 1202=>789, 1203=>596, 1204=>1235, 1205=>974, 1206=>913, 1207=>716, 1210=>910, 1211=>727, 1216=>468, 1217=>1312, 1218=>1306, 1219=>869, 1220=>693, 1223=>945, 1224=>732, 1227=>984, - 1228=>732, 1231=>380, 1232=>814, 1233=>648, 1234=>814, 1235=>648, 1236=>1034, 1237=>975, 1238=>762, 1239=>636, 1240=>871, 1241=>636, 1242=>871, 1243=>636, 1244=>1312, 1245=>1306, - 1246=>721, 1247=>638, 1248=>568, 1249=>568, 1250=>945, 1251=>727, 1252=>945, 1253=>727, 1254=>871, 1255=>667, 1256=>871, 1257=>667, 1258=>871, 1259=>667, 1260=>795, 1261=>645, - 1262=>812, 1263=>598, 1264=>812, 1265=>598, 1266=>812, 1267=>598, 1268=>913, 1269=>715, 1270=>690, 1271=>637, 1272=>1202, 1273=>1018, 7426=>940, 7432=>509, 7433=>320, 7444=>989, - 7446=>667, 7447=>667, 7453=>737, 7454=>948, 7455=>948, 7491=>466, 7492=>466, 7493=>498, 7494=>657, 7495=>499, 7496=>498, 7497=>444, 7498=>444, 7499=>412, 7500=>412, 7501=>498, - 7502=>300, 7503=>523, 7504=>729, 7505=>473, 7506=>467, 7507=>427, 7508=>467, 7509=>467, 7510=>499, 7511=>371, 7512=>520, 7513=>434, 7514=>729, 7515=>491, 7543=>640, 7547=>380, - 7557=>380, 7579=>498, 7580=>427, 7581=>427, 7582=>467, 7583=>412, 7584=>383, 7585=>373, 7586=>498, 7587=>522, 7588=>300, 7589=>307, 7590=>300, 7591=>300, 7592=>370, 7593=>368, - 7594=>321, 7595=>430, 7596=>682, 7597=>729, 7598=>588, 7599=>587, 7600=>472, 7601=>467, 7602=>522, 7603=>400, 7604=>387, 7605=>371, 7606=>520, 7607=>475, 7609=>489, 7610=>491, - 7611=>412, 7612=>527, 7613=>412, 7614=>452, 7615=>467, 7680=>776, 7681=>648, 7682=>845, 7683=>699, 7684=>845, 7685=>699, 7686=>845, 7687=>699, 7688=>796, 7689=>609, 7690=>867, - 7691=>699, 7692=>867, 7693=>699, 7694=>867, 7695=>699, 7696=>867, 7697=>699, 7698=>867, 7699=>699, 7700=>762, 7701=>636, 7702=>762, 7703=>636, 7704=>762, 7705=>636, 7706=>762, - 7707=>636, 7710=>710, 7711=>430, 7712=>854, 7713=>699, 7714=>945, 7715=>727, 7716=>945, 7717=>727, 7718=>945, 7719=>727, 7720=>945, 7721=>727, 7722=>945, 7723=>727, 7724=>468, - 7725=>380, 7728=>869, 7729=>693, 7730=>869, 7731=>693, 7732=>869, 7733=>693, 7734=>703, 7735=>380, 7736=>703, 7737=>380, 7738=>703, 7739=>380, 7740=>703, 7741=>380, 7742=>1107, - 7743=>1058, 7744=>1107, 7745=>1058, 7746=>1107, 7747=>1058, 7748=>914, 7749=>727, 7750=>914, 7751=>727, 7752=>914, 7753=>727, 7754=>914, 7755=>727, 7760=>871, 7761=>667, 7762=>871, - 7763=>667, 7764=>752, 7765=>699, 7766=>752, 7767=>699, 7768=>831, 7769=>527, 7770=>831, 7771=>527, 7772=>831, 7773=>527, 7774=>831, 7775=>527, 7776=>722, 7777=>563, 7778=>722, - 7779=>563, 7784=>722, 7785=>563, 7786=>744, 7787=>462, 7788=>744, 7789=>462, 7790=>744, 7791=>462, 7792=>744, 7793=>462, 7794=>872, 7795=>727, 7796=>872, 7797=>727, 7798=>872, - 7799=>727, 7800=>872, 7801=>727, 7802=>872, 7803=>727, 7804=>776, 7805=>581, 7806=>776, 7807=>581, 7808=>1123, 7809=>861, 7810=>1123, 7811=>861, 7812=>1123, 7813=>861, 7814=>1123, - 7815=>861, 7816=>1123, 7817=>861, 7818=>776, 7819=>596, 7820=>776, 7821=>596, 7822=>714, 7823=>581, 7824=>730, 7825=>568, 7826=>730, 7827=>568, 7828=>730, 7829=>568, 7830=>727, - 7831=>462, 7832=>861, 7833=>581, 7834=>1014, 7835=>563, 7840=>776, 7841=>648, 7842=>776, 7843=>648, 7852=>776, 7853=>648, 7854=>776, 7855=>648, 7856=>776, 7857=>648, 7858=>776, - 7859=>648, 7860=>776, 7861=>648, 7862=>776, 7863=>648, 7864=>762, 7865=>636, 7866=>762, 7867=>636, 7868=>762, 7869=>636, 7878=>762, 7879=>636, 7880=>468, 7881=>380, 7882=>468, - 7883=>380, 7884=>871, 7885=>667, 7886=>871, 7887=>667, 7896=>871, 7897=>667, 7908=>872, 7909=>727, 7910=>872, 7911=>727, 7922=>714, 7923=>581, 7924=>714, 7925=>581, 7926=>714, - 7927=>581, 7928=>714, 7929=>581, 7936=>770, 7937=>770, 7938=>770, 7939=>770, 7940=>770, 7941=>770, 7942=>770, 7943=>770, 7944=>776, 7945=>776, 7946=>978, 7947=>978, 7948=>832, - 7949=>849, 7950=>776, 7951=>776, 7952=>608, 7953=>608, 7954=>608, 7955=>608, 7956=>608, 7957=>608, 7960=>917, 7961=>909, 7962=>1169, 7963=>1169, 7964=>1093, 7965=>1120, 7968=>727, - 7969=>727, 7970=>727, 7971=>727, 7972=>727, 7973=>727, 7974=>727, 7975=>727, 7976=>1100, 7977=>1094, 7978=>1358, 7979=>1361, 7980=>1279, 7981=>1308, 7982=>1197, 7983=>1194, 7984=>484, - 7985=>484, 7986=>484, 7987=>484, 7988=>484, 7989=>484, 7990=>484, 7991=>484, 7992=>629, 7993=>617, 7994=>878, 7995=>881, 7996=>799, 7997=>831, 7998=>723, 7999=>714, 8000=>667, - 8001=>667, 8002=>667, 8003=>667, 8004=>667, 8005=>667, 8008=>900, 8009=>935, 8010=>1240, 8011=>1237, 8012=>1035, 8013=>1066, 8016=>694, 8017=>694, 8018=>694, 8019=>694, 8020=>694, - 8021=>694, 8022=>694, 8023=>694, 8025=>922, 8027=>1186, 8029=>1133, 8031=>1019, 8032=>952, 8033=>952, 8034=>952, 8035=>952, 8036=>952, 8037=>952, 8038=>952, 8039=>952, 8040=>931, - 8041=>963, 8042=>1268, 8043=>1274, 8044=>1054, 8045=>1088, 8046=>1023, 8047=>1060, 8048=>770, 8049=>770, 8050=>608, 8051=>608, 8052=>727, 8053=>727, 8054=>484, 8055=>484, 8056=>667, - 8057=>667, 8058=>694, 8059=>694, 8060=>952, 8061=>952, 8064=>770, 8065=>770, 8066=>770, 8067=>770, 8068=>770, 8069=>770, 8070=>770, 8071=>770, 8072=>776, 8073=>776, 8074=>978, - 8075=>978, 8076=>832, 8077=>849, 8078=>776, 8079=>776, 8080=>727, 8081=>727, 8082=>727, 8083=>727, 8084=>727, 8085=>727, 8086=>727, 8087=>727, 8088=>1100, 8089=>1094, 8090=>1358, - 8091=>1361, 8092=>1279, 8093=>1308, 8094=>1197, 8095=>1194, 8096=>952, 8097=>952, 8098=>952, 8099=>952, 8100=>952, 8101=>952, 8102=>952, 8103=>952, 8104=>931, 8105=>963, 8106=>1268, - 8107=>1274, 8108=>1054, 8109=>1088, 8110=>1023, 8111=>1060, 8112=>770, 8113=>770, 8114=>770, 8115=>770, 8116=>770, 8118=>770, 8119=>770, 8120=>776, 8121=>776, 8122=>811, 8123=>776, - 8124=>776, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>727, 8131=>727, 8132=>727, 8134=>727, 8135=>727, 8136=>1000, 8137=>947, 8138=>1191, 8139=>1118, 8140=>945, - 8141=>500, 8142=>500, 8143=>500, 8144=>484, 8145=>484, 8146=>484, 8147=>484, 8150=>484, 8151=>484, 8152=>468, 8153=>468, 8154=>714, 8155=>662, 8157=>500, 8158=>500, 8159=>500, - 8160=>694, 8161=>694, 8162=>694, 8163=>694, 8164=>665, 8165=>665, 8166=>694, 8167=>694, 8168=>714, 8169=>714, 8170=>1019, 8171=>953, 8172=>910, 8173=>500, 8174=>500, 8175=>500, - 8178=>952, 8179=>952, 8180=>952, 8182=>952, 8183=>952, 8184=>1069, 8185=>887, 8186=>1101, 8187=>911, 8188=>890, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, - 8196=>330, 8197=>250, 8198=>167, 8199=>696, 8200=>348, 8201=>200, 8202=>100, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>415, 8209=>415, 8210=>696, 8213=>1000, - 8215=>500, 8219=>348, 8223=>575, 8227=>639, 8228=>348, 8229=>674, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1813, 8252=>629, 8253=>586, 8254=>500, - 8263=>1082, 8264=>856, 8265=>856, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>438, 8308=>438, - 8309=>438, 8310=>438, 8311=>438, 8312=>438, 8313=>438, 8319=>519, 8320=>438, 8321=>438, 8322=>438, 8323=>438, 8324=>438, 8325=>438, 8326=>438, 8327=>438, 8328=>438, 8329=>438, - 8358=>696, 8367=>1155, 8369=>790, 8372=>876, 8373=>696, 8462=>727, 8470=>1087, 8486=>890, 8490=>869, 8491=>776, 8531=>1035, 8532=>1035, 8533=>1035, 8534=>1035, 8535=>1035, 8536=>1035, - 8537=>1035, 8538=>1035, 8539=>1035, 8540=>1035, 8541=>1035, 8542=>1035, 8543=>615, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8706=>534, 8710=>753, 8711=>753, 8719=>842, 8721=>753, - 8722=>838, 8725=>167, 8729=>348, 8730=>657, 8733=>672, 8734=>833, 8735=>838, 8736=>838, 8743=>812, 8744=>812, 8745=>812, 8746=>812, 8747=>579, 8748=>1000, 8749=>1391, 8770=>838, - 8771=>838, 8776=>838, 8800=>838, 8801=>838, 8804=>838, 8805=>838, 8962=>834, 8968=>473, 8969=>473, 8970=>473, 8971=>473, 8976=>838, 8977=>539, 8984=>928, 8985=>838, 8992=>579, - 8993=>579, 8997=>1000, 9000=>1443, 9085=>1008, 9134=>579, 9167=>945, 9251=>834, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, - 9609=>769, 9610=>769, 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, - 9625=>769, 9626=>769, 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, - 9641=>945, 9642=>678, 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, - 9657=>502, 9658=>769, 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, - 9673=>873, 9674=>494, 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>791, - 9689=>970, 9690=>970, 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>873, 9697=>873, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>590, 9703=>945, 9704=>945, - 9705=>945, 9706=>945, 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, - 9721=>769, 9722=>769, 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9784=>896, 9785=>896, 9786=>896, 9787=>896, 9788=>896, 9791=>614, 9792=>731, 9793=>731, - 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9833=>472, 9834=>638, - 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 10208=>494, 10216=>457, 10217=>457, 10731=>494, 10764=>1782, 10765=>610, 10766=>610, 11026=>945, 11027=>945, 11028=>945, 11029=>945, - 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 63172=>563, 63173=>667, 63174=>699, 63175=>727, 63176=>1058, 63185=>500, 63188=>500, 64256=>827, 64257=>727, 64258=>727, 64259=>1108, - 64260=>1146, 64261=>879, 64262=>971, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, - 65037=>0, 65038=>0, 65039=>0, 65533=>1113}; - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerif-BoldOblique.z'; - font[:ctg]='DejaVuSerif-BoldOblique.ctg.z'; - font[:originalsize]=183096; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/DejaVuSerifi.rb --- a/vendor/plugins/rfpdf/lib/fonts/DejaVuSerifi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -TCPDFFontDescriptor.define('DejaVuSerifi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='DejaVuSerif-Oblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-839 -401 1650 1227]','ItalicAngle'=>-11,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-42; - font[:ut]=44; - font[:cw]={ - 0=>600, 32=>318, 33=>402, 34=>460, 35=>838, 36=>636, 37=>950, 38=>890, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>338, 46=>318, - 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, - 63=>536, 64=>1000, 65=>722, 66=>735, 67=>765, 68=>802, 69=>730, 70=>694, 71=>799, 72=>872, 73=>395, 74=>401, 75=>747, 76=>664, 77=>1024, 78=>875, - 79=>820, 80=>673, 81=>820, 82=>753, 83=>685, 84=>667, 85=>843, 86=>722, 87=>1028, 88=>712, 89=>660, 90=>695, 91=>390, 92=>337, 93=>390, 94=>838, - 95=>500, 96=>500, 97=>596, 98=>640, 99=>560, 100=>640, 101=>592, 102=>370, 103=>640, 104=>644, 105=>320, 106=>310, 107=>606, 108=>320, 109=>948, 110=>644, - 111=>602, 112=>640, 113=>640, 114=>478, 115=>513, 116=>402, 117=>644, 118=>565, 119=>856, 120=>564, 121=>565, 122=>527, 123=>636, 124=>337, 125=>636, 126=>838, - 8364=>636, 1027=>662, 8218=>318, 402=>370, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1342, 352=>685, 8249=>400, 338=>1137, 1036=>774, 381=>695, 1039=>872, - 8216=>318, 8217=>318, 8220=>511, 8221=>511, 8226=>590, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>513, 8250=>400, 339=>989, 1116=>616, 382=>527, 376=>660, 160=>318, - 161=>402, 162=>636, 163=>636, 164=>636, 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>475, 171=>612, 172=>838, 173=>338, 174=>1000, 175=>500, 176=>500, - 177=>838, 178=>401, 179=>401, 180=>500, 181=>650, 182=>636, 183=>318, 184=>500, 185=>401, 186=>470, 187=>612, 188=>969, 189=>969, 190=>969, 191=>536, 192=>722, - 193=>722, 194=>722, 195=>722, 196=>722, 197=>722, 198=>1001, 199=>765, 200=>730, 201=>730, 202=>730, 203=>730, 204=>395, 205=>395, 206=>395, 207=>395, 208=>807, - 209=>875, 210=>820, 211=>820, 212=>820, 213=>820, 214=>820, 215=>838, 216=>820, 217=>843, 218=>843, 219=>843, 220=>843, 221=>660, 222=>676, 223=>668, 224=>596, - 225=>596, 226=>596, 227=>596, 228=>596, 229=>596, 230=>940, 231=>560, 232=>592, 233=>592, 234=>592, 235=>592, 236=>320, 237=>320, 238=>320, 239=>320, 240=>602, - 241=>644, 242=>602, 243=>602, 244=>602, 245=>602, 246=>602, 247=>838, 248=>602, 249=>644, 250=>644, 251=>644, 252=>644, 253=>565, 254=>640, 255=>565, 256=>722, - 257=>596, 258=>722, 259=>596, 260=>722, 261=>596, 262=>765, 263=>560, 264=>765, 265=>560, 266=>765, 267=>560, 268=>765, 269=>560, 270=>802, 271=>640, 272=>807, - 273=>640, 274=>730, 275=>592, 276=>730, 277=>592, 278=>730, 279=>592, 280=>730, 281=>592, 282=>730, 283=>592, 284=>799, 285=>640, 286=>799, 287=>640, 288=>799, - 289=>640, 290=>799, 291=>640, 292=>872, 293=>644, 294=>872, 295=>644, 296=>395, 297=>320, 298=>395, 299=>320, 300=>395, 301=>320, 302=>395, 303=>320, 304=>395, - 305=>320, 306=>801, 307=>533, 308=>401, 309=>310, 310=>747, 311=>606, 312=>606, 313=>664, 314=>320, 315=>664, 316=>320, 317=>664, 318=>400, 319=>671, 320=>465, - 321=>669, 322=>324, 323=>875, 324=>644, 325=>875, 326=>644, 327=>875, 328=>644, 329=>866, 330=>875, 331=>644, 332=>820, 333=>602, 334=>820, 335=>602, 336=>820, - 337=>602, 340=>753, 341=>478, 342=>753, 343=>478, 344=>753, 345=>478, 346=>685, 347=>513, 348=>685, 349=>513, 350=>685, 351=>513, 354=>667, 355=>402, 356=>667, - 357=>402, 358=>667, 359=>402, 360=>843, 361=>644, 362=>843, 363=>644, 364=>843, 365=>644, 366=>843, 367=>644, 368=>843, 369=>644, 370=>843, 371=>644, 372=>1028, - 373=>856, 374=>660, 375=>565, 377=>695, 378=>527, 379=>695, 380=>527, 383=>370, 384=>640, 385=>735, 386=>735, 387=>640, 388=>735, 389=>640, 390=>765, 391=>765, - 392=>560, 393=>807, 394=>802, 395=>735, 396=>640, 397=>602, 398=>730, 399=>820, 400=>636, 401=>694, 403=>799, 404=>712, 405=>932, 406=>395, 407=>395, 408=>747, - 409=>606, 410=>320, 411=>634, 412=>948, 413=>875, 414=>644, 415=>820, 416=>820, 417=>602, 418=>1040, 419=>807, 420=>673, 421=>640, 422=>753, 423=>685, 424=>513, - 425=>707, 426=>324, 427=>402, 428=>667, 429=>402, 430=>667, 431=>843, 432=>644, 433=>829, 434=>760, 435=>738, 436=>745, 437=>695, 438=>527, 439=>564, 440=>564, - 441=>564, 443=>636, 444=>687, 445=>564, 446=>536, 448=>295, 449=>492, 450=>459, 451=>295, 452=>1497, 453=>1329, 454=>1167, 455=>1065, 456=>974, 457=>630, 458=>1276, - 459=>1185, 460=>954, 461=>722, 462=>596, 463=>395, 464=>320, 465=>820, 466=>602, 467=>843, 468=>644, 469=>843, 470=>644, 471=>843, 472=>644, 473=>843, 474=>644, - 475=>843, 476=>644, 477=>592, 478=>722, 479=>596, 480=>722, 481=>596, 482=>1001, 483=>940, 484=>848, 485=>640, 486=>799, 487=>640, 488=>747, 489=>606, 490=>820, - 491=>602, 492=>820, 493=>602, 494=>564, 495=>564, 496=>320, 497=>1497, 498=>1329, 499=>1167, 500=>799, 501=>640, 502=>1154, 504=>875, 505=>644, 506=>722, 507=>596, - 508=>1001, 509=>940, 510=>820, 511=>602, 512=>722, 513=>596, 514=>722, 515=>596, 516=>730, 517=>592, 518=>730, 519=>592, 520=>395, 521=>320, 522=>395, 523=>320, - 524=>820, 525=>602, 526=>820, 527=>602, 528=>753, 529=>478, 530=>753, 531=>478, 532=>843, 533=>644, 534=>843, 535=>644, 536=>685, 537=>513, 538=>667, 539=>402, - 542=>872, 543=>644, 545=>814, 548=>695, 549=>527, 550=>722, 551=>596, 552=>730, 553=>592, 554=>820, 555=>602, 556=>820, 557=>602, 558=>820, 559=>602, 560=>820, - 561=>602, 562=>660, 563=>565, 564=>500, 565=>832, 566=>494, 567=>310, 568=>960, 569=>960, 570=>722, 571=>765, 572=>560, 573=>664, 574=>667, 575=>513, 576=>527, - 577=>583, 578=>464, 581=>722, 592=>596, 593=>640, 594=>675, 595=>640, 596=>560, 597=>560, 598=>647, 599=>683, 600=>592, 601=>592, 602=>843, 603=>537, 604=>509, - 605=>773, 606=>613, 607=>315, 608=>683, 609=>640, 610=>544, 611=>712, 612=>564, 613=>644, 614=>644, 615=>644, 616=>320, 617=>392, 618=>320, 619=>380, 620=>454, - 621=>363, 622=>704, 623=>948, 624=>948, 625=>948, 626=>644, 627=>694, 628=>646, 629=>602, 630=>790, 631=>647, 632=>602, 633=>501, 634=>501, 635=>551, 636=>478, - 637=>478, 638=>453, 639=>453, 640=>594, 641=>594, 642=>513, 643=>271, 644=>370, 645=>487, 646=>324, 647=>402, 648=>402, 649=>644, 650=>620, 651=>608, 652=>565, - 653=>856, 654=>565, 655=>655, 656=>597, 657=>560, 658=>564, 659=>560, 660=>536, 661=>536, 662=>536, 663=>513, 664=>820, 665=>563, 666=>613, 667=>654, 668=>667, - 669=>366, 670=>606, 671=>646, 672=>683, 673=>536, 674=>536, 675=>996, 676=>1033, 677=>998, 678=>809, 679=>598, 680=>782, 681=>894, 682=>646, 683=>676, 684=>598, - 685=>443, 686=>781, 687=>767, 688=>433, 689=>430, 690=>264, 691=>347, 692=>347, 693=>430, 694=>392, 695=>585, 696=>423, 697=>278, 699=>318, 700=>318, 701=>318, - 702=>307, 703=>307, 704=>280, 705=>281, 711=>500, 712=>282, 713=>500, 716=>282, 720=>337, 721=>337, 722=>307, 723=>307, 726=>392, 728=>500, 729=>500, 730=>500, - 731=>500, 733=>500, 734=>417, 736=>447, 737=>243, 738=>337, 739=>424, 740=>281, 741=>484, 742=>484, 743=>484, 744=>484, 745=>484, 750=>484, 768=>0, 769=>0, - 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, 784=>0, 785=>0, - 786=>0, 787=>0, 788=>0, 789=>0, 790=>0, 791=>0, 792=>0, 793=>0, 794=>0, 795=>0, 796=>0, 797=>0, 798=>0, 799=>0, 800=>0, 801=>0, - 802=>0, 803=>0, 804=>0, 805=>0, 806=>0, 807=>0, 808=>0, 809=>0, 810=>0, 811=>0, 812=>0, 813=>0, 814=>0, 815=>0, 816=>0, 817=>0, - 818=>0, 819=>0, 820=>0, 821=>0, 822=>0, 823=>0, 824=>0, 825=>0, 826=>0, 827=>0, 828=>0, 829=>0, 830=>0, 831=>0, 835=>0, 847=>0, - 856=>0, 865=>0, 884=>278, 885=>278, 890=>500, 894=>337, 900=>500, 901=>500, 902=>722, 903=>318, 904=>900, 905=>1039, 906=>562, 908=>835, 910=>897, 911=>853, - 912=>392, 913=>722, 914=>735, 915=>694, 916=>722, 917=>730, 918=>695, 919=>872, 920=>820, 921=>395, 922=>747, 923=>722, 924=>1024, 925=>875, 926=>704, 927=>820, - 928=>872, 929=>673, 931=>707, 932=>667, 933=>660, 934=>820, 935=>712, 936=>877, 937=>829, 938=>395, 939=>660, 940=>675, 941=>537, 942=>599, 943=>392, 944=>608, - 945=>675, 946=>578, 947=>598, 948=>602, 949=>537, 950=>542, 951=>599, 952=>602, 953=>392, 954=>656, 955=>634, 956=>650, 957=>608, 958=>551, 959=>602, 960=>657, - 961=>588, 962=>560, 963=>683, 964=>553, 965=>608, 966=>700, 967=>606, 968=>784, 969=>815, 970=>392, 971=>608, 972=>602, 973=>608, 974=>815, 976=>583, 977=>715, - 978=>687, 979=>874, 980=>687, 981=>682, 982=>815, 983=>624, 984=>820, 985=>602, 986=>765, 987=>560, 988=>694, 989=>463, 990=>590, 991=>660, 992=>782, 993=>577, - 1008=>624, 1009=>588, 1010=>560, 1011=>310, 1012=>820, 1013=>560, 1014=>560, 1015=>676, 1016=>640, 1017=>765, 1018=>1024, 1019=>708, 1020=>588, 1021=>765, 1022=>765, 1023=>765, - 1024=>730, 1025=>730, 1026=>799, 1028=>765, 1029=>685, 1030=>395, 1031=>395, 1032=>401, 1033=>1084, 1034=>1118, 1035=>872, 1037=>872, 1038=>723, 1040=>757, 1041=>735, 1042=>735, - 1043=>662, 1044=>813, 1045=>730, 1046=>1124, 1047=>623, 1048=>872, 1049=>860, 1050=>774, 1051=>834, 1052=>1024, 1053=>872, 1054=>820, 1055=>872, 1056=>673, 1057=>765, 1058=>667, - 1059=>723, 1060=>830, 1061=>712, 1062=>872, 1063=>773, 1064=>1141, 1065=>1141, 1066=>794, 1067=>984, 1068=>674, 1069=>765, 1070=>1193, 1071=>808, 1072=>596, 1073=>649, 1074=>592, - 1075=>505, 1076=>639, 1077=>592, 1078=>1149, 1079=>545, 1080=>644, 1081=>644, 1082=>616, 1083=>637, 1084=>873, 1085=>659, 1086=>602, 1087=>644, 1088=>640, 1089=>560, 1090=>948, - 1091=>580, 1092=>783, 1093=>564, 1094=>698, 1095=>622, 1096=>947, 1097=>1001, 1098=>667, 1099=>814, 1100=>544, 1101=>560, 1102=>880, 1103=>662, 1104=>592, 1105=>592, 1106=>624, - 1107=>505, 1108=>560, 1109=>513, 1110=>320, 1111=>320, 1112=>310, 1113=>859, 1114=>878, 1115=>644, 1117=>644, 1118=>580, 1119=>644, 1122=>762, 1123=>882, 1138=>820, 1139=>552, - 1140=>859, 1141=>678, 1164=>690, 1165=>492, 1168=>672, 1169=>529, 1170=>694, 1171=>538, 1172=>730, 1173=>614, 1174=>1124, 1175=>1149, 1176=>623, 1177=>545, 1178=>774, 1179=>606, - 1182=>774, 1183=>606, 1184=>892, 1185=>664, 1186=>872, 1187=>712, 1188=>1139, 1189=>866, 1190=>1206, 1191=>943, 1194=>765, 1195=>560, 1196=>667, 1197=>1013, 1198=>660, 1199=>565, - 1202=>712, 1203=>564, 1204=>1079, 1205=>899, 1206=>749, 1207=>690, 1210=>749, 1211=>644, 1216=>395, 1217=>1124, 1218=>1149, 1219=>747, 1220=>606, 1223=>872, 1224=>667, 1227=>749, - 1228=>667, 1231=>320, 1232=>757, 1233=>596, 1234=>757, 1235=>596, 1236=>1001, 1237=>940, 1238=>730, 1239=>592, 1240=>820, 1241=>592, 1242=>820, 1243=>592, 1244=>1124, 1245=>1149, - 1246=>623, 1247=>545, 1248=>564, 1249=>564, 1250=>872, 1251=>644, 1252=>872, 1253=>644, 1254=>820, 1255=>602, 1256=>820, 1257=>602, 1258=>820, 1259=>602, 1260=>765, 1261=>560, - 1262=>723, 1263=>580, 1264=>723, 1265=>580, 1266=>723, 1267=>580, 1268=>773, 1269=>622, 1270=>662, 1271=>538, 1272=>984, 1273=>814, 7426=>940, 7432=>509, 7433=>320, 7444=>989, - 7446=>602, 7447=>602, 7453=>737, 7454=>948, 7455=>948, 7491=>474, 7492=>334, 7493=>488, 7494=>706, 7495=>488, 7496=>488, 7497=>475, 7498=>475, 7499=>428, 7500=>428, 7501=>488, - 7502=>263, 7503=>453, 7504=>701, 7505=>487, 7506=>473, 7507=>434, 7508=>473, 7509=>473, 7510=>488, 7511=>334, 7512=>487, 7513=>552, 7514=>701, 7515=>460, 7543=>640, 7547=>372, - 7557=>320, 7579=>488, 7580=>434, 7581=>434, 7582=>473, 7583=>428, 7584=>310, 7585=>316, 7586=>488, 7587=>487, 7588=>322, 7589=>332, 7590=>322, 7591=>322, 7592=>318, 7593=>263, - 7594=>263, 7595=>455, 7596=>701, 7597=>701, 7598=>495, 7599=>492, 7600=>487, 7601=>473, 7602=>473, 7603=>416, 7604=>299, 7605=>334, 7606=>487, 7607=>477, 7609=>464, 7610=>460, - 7611=>418, 7612=>418, 7613=>418, 7614=>452, 7615=>473, 7680=>722, 7681=>596, 7682=>735, 7683=>640, 7684=>735, 7685=>640, 7686=>735, 7687=>640, 7688=>765, 7689=>560, 7690=>802, - 7691=>640, 7692=>802, 7693=>640, 7694=>802, 7695=>640, 7696=>802, 7697=>640, 7698=>802, 7699=>640, 7700=>730, 7701=>592, 7702=>730, 7703=>592, 7704=>730, 7705=>592, 7706=>730, - 7707=>592, 7710=>694, 7711=>370, 7712=>799, 7713=>640, 7714=>872, 7715=>644, 7716=>872, 7717=>644, 7718=>872, 7719=>644, 7720=>872, 7721=>644, 7722=>872, 7723=>644, 7724=>395, - 7725=>320, 7728=>747, 7729=>606, 7730=>747, 7731=>606, 7732=>747, 7733=>606, 7734=>664, 7735=>320, 7736=>664, 7737=>320, 7738=>664, 7739=>320, 7740=>664, 7741=>320, 7742=>1024, - 7743=>948, 7744=>1024, 7745=>948, 7746=>1024, 7747=>953, 7748=>875, 7749=>644, 7750=>875, 7751=>644, 7752=>875, 7753=>644, 7754=>875, 7755=>644, 7760=>820, 7761=>602, 7762=>820, - 7763=>602, 7764=>673, 7765=>640, 7766=>673, 7767=>640, 7768=>753, 7769=>478, 7770=>753, 7771=>478, 7772=>753, 7773=>478, 7774=>753, 7775=>478, 7776=>685, 7777=>513, 7778=>685, - 7779=>513, 7784=>685, 7785=>513, 7786=>667, 7787=>402, 7788=>667, 7789=>402, 7790=>667, 7791=>402, 7792=>667, 7793=>402, 7794=>843, 7795=>644, 7796=>843, 7797=>644, 7798=>843, - 7799=>644, 7800=>843, 7801=>644, 7802=>843, 7803=>644, 7804=>722, 7805=>565, 7806=>722, 7807=>565, 7808=>1028, 7809=>856, 7810=>1028, 7811=>856, 7812=>1028, 7813=>856, 7814=>1028, - 7815=>856, 7816=>1028, 7817=>856, 7818=>712, 7819=>564, 7820=>712, 7821=>564, 7822=>660, 7823=>565, 7824=>695, 7825=>527, 7826=>695, 7827=>527, 7828=>695, 7829=>527, 7830=>644, - 7831=>402, 7832=>856, 7833=>565, 7834=>903, 7835=>513, 7840=>722, 7841=>596, 7842=>722, 7843=>596, 7852=>722, 7853=>596, 7854=>722, 7855=>596, 7856=>722, 7857=>596, 7858=>722, - 7859=>596, 7860=>722, 7861=>596, 7862=>722, 7863=>596, 7864=>730, 7865=>592, 7866=>730, 7867=>592, 7868=>730, 7869=>592, 7878=>730, 7879=>592, 7880=>395, 7881=>320, 7882=>395, - 7883=>320, 7884=>820, 7885=>602, 7886=>820, 7887=>602, 7896=>820, 7897=>602, 7908=>843, 7909=>644, 7910=>843, 7911=>644, 7922=>660, 7923=>565, 7924=>660, 7925=>565, 7926=>660, - 7927=>565, 7928=>660, 7929=>565, 7936=>675, 7937=>675, 7938=>675, 7939=>675, 7940=>675, 7941=>675, 7942=>675, 7943=>675, 7944=>722, 7945=>722, 7946=>869, 7947=>869, 7948=>734, - 7949=>763, 7950=>722, 7951=>722, 7952=>537, 7953=>537, 7954=>537, 7955=>537, 7956=>537, 7957=>537, 7960=>853, 7961=>841, 7962=>1067, 7963=>1077, 7964=>1008, 7965=>1035, 7968=>599, - 7969=>599, 7970=>599, 7971=>599, 7972=>599, 7973=>599, 7974=>599, 7975=>599, 7976=>998, 7977=>992, 7978=>1212, 7979=>1224, 7980=>1159, 7981=>1183, 7982=>1098, 7983=>1095, 7984=>392, - 7985=>392, 7986=>392, 7987=>392, 7988=>392, 7989=>392, 7990=>392, 7991=>392, 7992=>521, 7993=>512, 7994=>735, 7995=>738, 7996=>679, 7997=>706, 7998=>624, 7999=>615, 8000=>602, - 8001=>602, 8002=>602, 8003=>602, 8004=>602, 8005=>602, 8008=>820, 8009=>859, 8010=>1120, 8011=>1127, 8012=>937, 8013=>964, 8016=>608, 8017=>608, 8018=>608, 8019=>608, 8020=>608, - 8021=>608, 8022=>608, 8023=>608, 8025=>851, 8027=>1079, 8029=>1044, 8031=>953, 8032=>815, 8033=>815, 8034=>815, 8035=>815, 8036=>815, 8037=>815, 8038=>815, 8039=>815, 8040=>829, - 8041=>870, 8042=>1131, 8043=>1137, 8044=>946, 8045=>976, 8046=>938, 8047=>970, 8048=>675, 8049=>675, 8050=>537, 8051=>537, 8052=>599, 8053=>599, 8054=>392, 8055=>392, 8056=>602, - 8057=>602, 8058=>608, 8059=>608, 8060=>815, 8061=>815, 8064=>675, 8065=>675, 8066=>675, 8067=>675, 8068=>675, 8069=>675, 8070=>675, 8071=>675, 8072=>722, 8073=>722, 8074=>869, - 8075=>869, 8076=>734, 8077=>763, 8078=>722, 8079=>722, 8080=>599, 8081=>599, 8082=>599, 8083=>599, 8084=>599, 8085=>599, 8086=>599, 8087=>599, 8088=>998, 8089=>992, 8090=>1212, - 8091=>1224, 8092=>1159, 8093=>1183, 8094=>1098, 8095=>1095, 8096=>815, 8097=>815, 8098=>815, 8099=>815, 8100=>815, 8101=>815, 8102=>815, 8103=>815, 8104=>829, 8105=>870, 8106=>1131, - 8107=>1137, 8108=>946, 8109=>976, 8110=>938, 8111=>970, 8112=>675, 8113=>675, 8114=>675, 8115=>675, 8116=>675, 8118=>675, 8119=>675, 8120=>722, 8121=>722, 8122=>722, 8123=>722, - 8124=>722, 8125=>500, 8126=>500, 8127=>500, 8128=>500, 8129=>500, 8130=>599, 8131=>599, 8132=>599, 8134=>599, 8135=>599, 8136=>912, 8137=>900, 8138=>1063, 8139=>1039, 8140=>872, - 8141=>500, 8142=>500, 8143=>500, 8144=>392, 8145=>392, 8146=>392, 8147=>392, 8150=>392, 8151=>392, 8152=>395, 8153=>395, 8154=>588, 8155=>562, 8157=>500, 8158=>500, 8159=>500, - 8160=>608, 8161=>608, 8162=>608, 8163=>608, 8164=>588, 8165=>588, 8166=>608, 8167=>608, 8168=>660, 8169=>660, 8170=>921, 8171=>897, 8172=>790, 8173=>500, 8174=>500, 8175=>500, - 8178=>815, 8179=>815, 8180=>815, 8182=>815, 8183=>815, 8184=>961, 8185=>835, 8186=>984, 8187=>853, 8188=>829, 8189=>500, 8190=>500, 8192=>500, 8193=>1000, 8194=>500, 8195=>1000, - 8196=>330, 8197=>250, 8198=>167, 8199=>636, 8200=>318, 8201=>200, 8202=>100, 8203=>0, 8204=>0, 8205=>0, 8206=>0, 8207=>0, 8208=>338, 8209=>338, 8210=>636, 8213=>1000, - 8215=>500, 8219=>318, 8223=>511, 8227=>590, 8228=>334, 8229=>667, 8234=>0, 8235=>0, 8236=>0, 8237=>0, 8238=>0, 8239=>200, 8241=>1734, 8252=>527, 8253=>536, 8254=>500, - 8263=>976, 8264=>753, 8265=>753, 8287=>222, 8288=>0, 8289=>0, 8290=>0, 8291=>0, 8298=>0, 8299=>0, 8300=>0, 8301=>0, 8302=>0, 8303=>0, 8304=>401, 8308=>401, - 8309=>401, 8310=>401, 8311=>401, 8312=>401, 8313=>401, 8319=>433, 8320=>401, 8321=>401, 8322=>401, 8323=>401, 8324=>401, 8325=>401, 8326=>401, 8327=>401, 8328=>401, 8329=>401, - 8358=>660, 8367=>1057, 8369=>706, 8372=>780, 8373=>636, 8462=>644, 8470=>946, 8486=>829, 8490=>747, 8491=>722, 8531=>969, 8532=>969, 8533=>969, 8534=>969, 8535=>969, 8536=>969, - 8537=>969, 8538=>969, 8539=>969, 8540=>969, 8541=>969, 8542=>969, 8543=>568, 8592=>838, 8593=>838, 8594=>838, 8595=>838, 8706=>517, 8710=>698, 8711=>698, 8719=>796, 8721=>714, - 8722=>838, 8725=>167, 8729=>318, 8730=>637, 8733=>677, 8734=>833, 8735=>838, 8736=>838, 8743=>732, 8744=>732, 8745=>732, 8746=>732, 8747=>521, 8748=>852, 8749=>1182, 8770=>838, - 8771=>838, 8776=>838, 8800=>838, 8801=>838, 8804=>838, 8805=>838, 8962=>764, 8968=>390, 8969=>390, 8970=>390, 8971=>390, 8976=>838, 8977=>513, 8984=>1000, 8985=>838, 8992=>521, - 8993=>521, 8997=>1000, 9000=>1443, 9085=>919, 9134=>521, 9167=>945, 9251=>764, 9600=>769, 9601=>769, 9602=>769, 9603=>769, 9604=>769, 9605=>769, 9606=>769, 9607=>769, 9608=>769, - 9609=>769, 9610=>769, 9611=>769, 9612=>769, 9613=>769, 9614=>769, 9615=>769, 9616=>769, 9617=>769, 9618=>769, 9619=>769, 9620=>769, 9621=>769, 9622=>769, 9623=>769, 9624=>769, - 9625=>769, 9626=>769, 9627=>769, 9628=>769, 9629=>769, 9630=>769, 9631=>769, 9632=>945, 9633=>945, 9634=>945, 9635=>945, 9636=>945, 9637=>945, 9638=>945, 9639=>945, 9640=>945, - 9641=>945, 9642=>678, 9643=>678, 9644=>945, 9645=>945, 9646=>550, 9647=>550, 9648=>769, 9649=>769, 9650=>769, 9651=>769, 9652=>502, 9653=>502, 9654=>769, 9655=>769, 9656=>502, - 9657=>502, 9658=>769, 9659=>769, 9660=>769, 9661=>769, 9662=>502, 9663=>502, 9664=>769, 9665=>769, 9666=>502, 9667=>502, 9668=>769, 9669=>769, 9670=>769, 9671=>769, 9672=>769, - 9673=>873, 9674=>494, 9675=>873, 9676=>873, 9677=>873, 9678=>873, 9679=>873, 9680=>873, 9681=>873, 9682=>873, 9683=>873, 9684=>873, 9685=>873, 9686=>527, 9687=>527, 9688=>791, - 9689=>970, 9690=>970, 9691=>970, 9692=>387, 9693=>387, 9694=>387, 9695=>387, 9696=>873, 9697=>873, 9698=>769, 9699=>769, 9700=>769, 9701=>769, 9702=>590, 9703=>945, 9704=>945, - 9705=>945, 9706=>945, 9707=>945, 9708=>769, 9709=>769, 9710=>769, 9711=>1119, 9712=>945, 9713=>945, 9714=>945, 9715=>945, 9716=>873, 9717=>873, 9718=>873, 9719=>873, 9720=>769, - 9721=>769, 9722=>769, 9723=>830, 9724=>830, 9725=>732, 9726=>732, 9727=>769, 9728=>896, 9784=>896, 9785=>896, 9786=>896, 9787=>896, 9788=>896, 9791=>614, 9792=>731, 9793=>731, - 9794=>896, 9795=>896, 9796=>896, 9797=>896, 9798=>896, 9799=>896, 9824=>896, 9825=>896, 9826=>896, 9827=>896, 9828=>896, 9829=>896, 9830=>896, 9831=>896, 9833=>472, 9834=>638, - 9835=>896, 9836=>896, 9837=>472, 9838=>357, 9839=>484, 10208=>494, 10216=>390, 10217=>390, 10731=>494, 10764=>1513, 10765=>521, 10766=>521, 11026=>945, 11027=>945, 11028=>945, 11029=>945, - 11030=>769, 11031=>769, 11032=>769, 11033=>769, 11034=>945, 63172=>505, 63173=>602, 63174=>640, 63175=>644, 63176=>947, 63185=>500, 63188=>500, 64256=>708, 64257=>667, 64258=>667, 64259=>941, - 64260=>986, 64261=>744, 64262=>916, 65024=>0, 65025=>0, 65026=>0, 65027=>0, 65028=>0, 65029=>0, 65030=>0, 65031=>0, 65032=>0, 65033=>0, 65034=>0, 65035=>0, 65036=>0, - 65037=>0, 65038=>0, 65039=>0, 65533=>1025} - font[:enc]=''; - font[:diff]=''; - font[:file]='DejaVuSerif-Oblique.z'; - font[:ctg]='DejaVuSerif-Oblique.ctg.z'; - font[:originalsize]=181932; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMono.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMono.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMono.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMono.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMonoBold.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMonoBold.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMonoBold.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMonoBold.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMonoBoldOblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMonoBoldOblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMonoBoldOblique.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMonoBoldOblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMonoOblique.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMonoOblique.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/FreeMonoOblique.z Binary file vendor/plugins/rfpdf/lib/fonts/FreeMonoOblique.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/courier.rb --- a/vendor/plugins/rfpdf/lib/fonts/courier.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -TCPDFFontDescriptor.define('courier') do |font| - font[:cw] = {} - 0.upto(255) do |i| - font[:cw][i]=600 - end -end -TCPDFFontDescriptor.define('courierb') do |font| - font[:cw] = {} - 0.upto(255) do |i| - font[:cw][i]=600 - end -end -TCPDFFontDescriptor.define('courierbi') do |font| - font[:cw] = {} - 0.upto(255) do |i| - font[:cw][i]=600 - end -end -TCPDFFontDescriptor.define('courieri') do |font| - font[:cw] = {} - 0.upto(255) do |i| - font[:cw][i]=600 - end -end - diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/freemono.rb --- a/vendor/plugins/rfpdf/lib/fonts/freemono.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -TCPDFFontDescriptor.define('freemono') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='FreeMono'; - font[:desc]={'Ascent'=>1057,'Descent'=>-319,'CapHeight'=>1057,'Flags'=>32,'FontBBox'=>'[-557 -319 699 1057]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-100; - font[:ut]=50; - font[:cw]={ - 13=>333, 32=>600, 33=>600, 34=>600, 35=>600, 36=>600, 37=>600, 38=>600, 39=>600, 40=>600, 41=>600, 42=>600, 43=>600, 44=>600, 45=>600, 46=>600, - 47=>600, 48=>600, 49=>600, 50=>600, 51=>600, 52=>600, 53=>600, 54=>600, 55=>600, 56=>600, 57=>600, 58=>600, 59=>600, 60=>600, 61=>600, 62=>600, - 63=>600, 64=>600, 65=>600, 66=>600, 67=>600, 68=>600, 69=>600, 70=>600, 71=>600, 72=>600, 73=>600, 74=>600, 75=>600, 76=>600, 77=>600, 78=>600, - 79=>600, 80=>600, 81=>600, 82=>600, 83=>600, 84=>600, 85=>600, 86=>600, 87=>600, 88=>600, 89=>600, 90=>600, 91=>600, 92=>600, 93=>600, 94=>600, - 95=>600, 96=>600, 97=>600, 98=>600, 99=>600, 100=>600, 101=>600, 102=>600, 103=>600, 104=>600, 105=>600, 106=>600, 107=>600, 108=>600, 109=>600, 110=>600, - 111=>600, 112=>600, 113=>600, 114=>600, 115=>600, 116=>600, 117=>600, 118=>600, 119=>600, 120=>600, 121=>600, 122=>600, 123=>600, 124=>600, 125=>600, 126=>600, - 8364=>600, 1027=>600, 8218=>600, 402=>600, 8222=>600, 8230=>600, 8224=>600, 8225=>600, 710=>600, 8240=>600, 352=>600, 8249=>600, 338=>600, 1036=>600, 381=>600, 1039=>600, - 8216=>600, 8217=>600, 8220=>600, 8221=>600, 8226=>600, 8211=>600, 8212=>600, 732=>600, 8482=>600, 353=>600, 8250=>600, 339=>600, 1116=>600, 382=>600, 376=>600, 160=>600, - 161=>600, 162=>600, 163=>600, 164=>600, 165=>600, 166=>600, 167=>600, 168=>600, 169=>600, 170=>600, 171=>600, 172=>600, 173=>600, 174=>600, 175=>600, 176=>600, - 177=>600, 178=>600, 179=>600, 180=>600, 181=>600, 182=>600, 183=>600, 184=>600, 185=>600, 186=>600, 187=>600, 188=>600, 189=>600, 190=>600, 191=>600, 192=>600, - 193=>600, 194=>600, 195=>600, 196=>600, 197=>600, 198=>600, 199=>600, 200=>600, 201=>600, 202=>600, 203=>600, 204=>600, 205=>600, 206=>600, 207=>600, 208=>600, - 209=>600, 210=>600, 211=>600, 212=>600, 213=>600, 214=>600, 215=>600, 216=>600, 217=>600, 218=>600, 219=>600, 220=>600, 221=>600, 222=>600, 223=>600, 224=>600, - 225=>600, 226=>600, 227=>600, 228=>600, 229=>600, 230=>600, 231=>600, 232=>600, 233=>600, 234=>600, 235=>600, 236=>600, 237=>600, 238=>600, 239=>600, 240=>600, - 241=>600, 242=>600, 243=>600, 244=>600, 245=>600, 246=>600, 247=>600, 248=>600, 249=>600, 250=>600, 251=>600, 252=>600, 253=>600, 254=>600, 255=>600, 256=>600, - 257=>600, 258=>600, 259=>600, 260=>600, 261=>600, 262=>600, 263=>600, 264=>600, 265=>600, 266=>600, 267=>600, 268=>600, 269=>600, 270=>600, 271=>600, 272=>600, - 273=>600, 274=>600, 275=>600, 276=>600, 277=>600, 278=>600, 279=>600, 280=>600, 281=>600, 282=>600, 283=>600, 284=>600, 285=>600, 286=>600, 287=>600, 288=>600, - 289=>600, 290=>600, 291=>600, 292=>600, 293=>600, 294=>600, 295=>600, 296=>600, 297=>600, 298=>600, 299=>600, 300=>600, 301=>600, 302=>600, 303=>600, 304=>600, - 305=>600, 306=>600, 307=>600, 308=>600, 309=>600, 310=>600, 311=>600, 312=>600, 313=>600, 314=>600, 315=>600, 316=>600, 317=>600, 318=>600, 319=>600, 320=>600, - 321=>600, 322=>600, 323=>600, 324=>600, 325=>600, 326=>600, 327=>600, 328=>600, 329=>600, 330=>600, 331=>600, 332=>600, 333=>600, 334=>600, 335=>600, 336=>600, - 337=>600, 340=>600, 341=>600, 342=>600, 343=>600, 344=>600, 345=>600, 346=>600, 347=>600, 348=>600, 349=>600, 350=>600, 351=>600, 354=>600, 355=>600, 356=>600, - 357=>600, 358=>600, 359=>600, 360=>600, 361=>600, 362=>600, 363=>600, 364=>600, 365=>600, 366=>600, 367=>600, 368=>600, 369=>600, 370=>600, 371=>600, 372=>600, - 373=>600, 374=>600, 375=>600, 377=>600, 378=>600, 379=>600, 380=>600, 383=>600, 384=>600, 385=>600, 386=>600, 387=>600, 388=>600, 389=>600, 390=>600, 391=>600, - 392=>600, 393=>600, 394=>600, 395=>600, 396=>600, 397=>600, 398=>600, 399=>600, 400=>600, 401=>600, 403=>600, 404=>600, 405=>600, 406=>600, 407=>600, 408=>600, - 409=>600, 410=>600, 411=>600, 412=>600, 413=>600, 414=>600, 415=>600, 416=>600, 417=>600, 418=>600, 419=>600, 420=>600, 421=>600, 422=>600, 423=>600, 424=>600, - 425=>600, 426=>600, 427=>600, 428=>600, 429=>600, 430=>600, 431=>600, 432=>600, 433=>600, 434=>600, 435=>600, 436=>600, 437=>600, 438=>600, 439=>600, 440=>600, - 441=>600, 442=>600, 443=>600, 444=>600, 445=>600, 446=>600, 447=>600, 448=>600, 449=>600, 450=>600, 451=>600, 452=>600, 453=>600, 454=>600, 455=>600, 456=>600, - 457=>600, 458=>600, 459=>600, 460=>600, 461=>600, 462=>600, 463=>600, 464=>600, 465=>600, 466=>600, 467=>600, 468=>600, 469=>600, 470=>600, 471=>600, 472=>600, - 473=>600, 474=>600, 475=>600, 476=>600, 477=>600, 478=>600, 479=>600, 480=>600, 481=>600, 482=>600, 483=>600, 484=>600, 485=>600, 486=>600, 487=>600, 488=>600, - 489=>600, 490=>600, 491=>600, 492=>600, 493=>600, 494=>600, 495=>600, 496=>600, 497=>600, 498=>600, 499=>600, 500=>600, 501=>600, 502=>600, 503=>600, 504=>600, - 505=>600, 506=>600, 507=>600, 508=>600, 509=>600, 510=>600, 511=>600, 512=>600, 513=>600, 514=>600, 515=>600, 516=>600, 517=>600, 518=>600, 519=>600, 520=>600, - 521=>600, 522=>600, 523=>600, 524=>600, 525=>600, 526=>600, 527=>600, 528=>600, 529=>600, 530=>600, 531=>600, 532=>600, 533=>600, 534=>600, 535=>600, 536=>600, - 537=>600, 538=>600, 539=>600, 540=>600, 541=>600, 542=>600, 543=>600, 548=>600, 549=>600, 550=>600, 551=>600, 552=>600, 553=>600, 554=>600, 555=>600, 556=>600, - 557=>600, 558=>600, 559=>600, 560=>600, 561=>600, 562=>600, 563=>600, 577=>600, 578=>600, 592=>600, 593=>600, 594=>600, 595=>600, 596=>600, 597=>600, 598=>600, - 599=>600, 600=>600, 601=>600, 602=>600, 603=>600, 604=>600, 607=>600, 608=>600, 609=>600, 610=>600, 611=>600, 612=>600, 613=>600, 614=>600, 615=>600, 616=>600, - 617=>600, 618=>600, 619=>600, 620=>600, 621=>600, 623=>600, 624=>600, 625=>600, 626=>600, 627=>600, 628=>600, 629=>600, 630=>600, 632=>600, 633=>600, 634=>600, - 635=>600, 636=>600, 637=>600, 638=>600, 639=>600, 640=>600, 641=>600, 642=>600, 643=>600, 644=>600, 645=>600, 646=>600, 647=>600, 648=>600, 649=>600, 652=>600, - 653=>600, 654=>600, 655=>600, 656=>600, 657=>600, 658=>600, 660=>600, 661=>600, 662=>600, 663=>600, 665=>600, 667=>600, 668=>600, 669=>600, 670=>600, 671=>600, - 672=>600, 673=>600, 674=>600, 675=>600, 676=>600, 678=>600, 679=>600, 699=>600, 700=>600, 701=>600, 702=>600, 703=>600, 711=>600, 712=>600, 713=>600, 714=>600, - 715=>600, 720=>600, 721=>600, 722=>600, 723=>600, 724=>600, 725=>600, 726=>600, 727=>600, 728=>600, 729=>600, 730=>600, 731=>600, 733=>600, 735=>600, 750=>600, - 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, - 784=>0, 785=>0, 795=>0, 801=>0, 802=>0, 807=>0, 808=>0, 819=>600, 821=>0, 822=>0, 823=>0, 824=>0, 834=>0, 836=>0, 890=>600, 900=>600, - 901=>600, 902=>600, 903=>600, 904=>600, 905=>600, 906=>600, 908=>600, 910=>600, 911=>600, 912=>600, 913=>600, 914=>600, 915=>600, 916=>600, 917=>600, 918=>600, - 919=>600, 920=>600, 921=>600, 922=>600, 923=>600, 924=>600, 925=>600, 926=>600, 927=>600, 928=>600, 929=>600, 930=>600, 931=>600, 932=>600, 933=>600, 934=>600, - 935=>600, 936=>600, 937=>600, 938=>600, 939=>600, 940=>600, 941=>600, 942=>600, 943=>600, 944=>600, 945=>600, 946=>600, 947=>600, 948=>600, 949=>600, 950=>600, - 951=>600, 952=>600, 953=>600, 954=>600, 955=>600, 956=>600, 957=>600, 958=>600, 959=>600, 960=>600, 961=>600, 962=>600, 963=>600, 964=>600, 965=>600, 966=>600, - 967=>600, 968=>600, 969=>600, 970=>600, 971=>600, 972=>600, 973=>600, 974=>600, 976=>600, 977=>600, 978=>600, 979=>600, 981=>600, 986=>600, 987=>600, 988=>600, - 1024=>600, 1025=>600, 1026=>600, 1028=>600, 1029=>600, 1030=>600, 1031=>600, 1032=>600, 1033=>600, 1034=>600, 1035=>600, 1037=>600, 1038=>600, 1040=>600, 1041=>600, 1042=>600, - 1043=>600, 1044=>600, 1045=>600, 1046=>600, 1047=>600, 1048=>600, 1049=>600, 1050=>600, 1051=>600, 1052=>600, 1053=>600, 1054=>600, 1055=>600, 1056=>600, 1057=>600, 1058=>600, - 1059=>600, 1060=>600, 1061=>600, 1062=>600, 1063=>600, 1064=>600, 1065=>600, 1066=>600, 1067=>600, 1068=>600, 1069=>600, 1070=>600, 1071=>600, 1072=>600, 1073=>600, 1074=>600, - 1075=>600, 1076=>600, 1077=>600, 1078=>600, 1079=>600, 1080=>600, 1081=>600, 1082=>600, 1083=>600, 1084=>600, 1085=>600, 1086=>600, 1087=>600, 1088=>600, 1089=>600, 1090=>600, - 1091=>600, 1092=>600, 1093=>600, 1094=>600, 1095=>600, 1096=>600, 1097=>600, 1098=>600, 1099=>600, 1100=>600, 1101=>600, 1102=>600, 1103=>600, 1104=>600, 1105=>600, 1106=>600, - 1107=>600, 1108=>600, 1109=>600, 1110=>600, 1111=>600, 1112=>600, 1113=>600, 1114=>600, 1115=>600, 1117=>600, 1118=>600, 1119=>600, 1124=>600, 1130=>600, 1132=>600, 1136=>600, - 1137=>600, 1164=>600, 1165=>600, 1166=>600, 1167=>600, 1168=>600, 1169=>600, 1170=>600, 1171=>600, 1172=>600, 1173=>600, 1174=>600, 1175=>600, 1176=>600, 1177=>600, 1178=>600, - 1179=>600, 1180=>600, 1181=>600, 1182=>600, 1183=>600, 1184=>600, 1185=>600, 1186=>600, 1187=>600, 1188=>600, 1189=>600, 1190=>600, 1191=>600, 1192=>600, 1193=>600, 1194=>600, - 1195=>600, 1196=>600, 1197=>600, 1198=>600, 1199=>600, 1200=>600, 1201=>600, 1202=>600, 1203=>600, 1204=>600, 1205=>600, 1206=>600, 1207=>600, 1208=>600, 1209=>600, 1210=>600, - 1211=>600, 1212=>600, 1213=>600, 1214=>600, 1215=>600, 1216=>600, 1217=>600, 1218=>600, 1219=>600, 1220=>600, 1223=>600, 1224=>600, 1227=>600, 1228=>600, 1232=>600, 1233=>600, - 1234=>600, 1235=>600, 1236=>600, 1237=>600, 1238=>600, 1239=>600, 1240=>600, 1241=>600, 1242=>600, 1243=>600, 1244=>600, 1245=>600, 1246=>600, 1247=>600, 1248=>600, 1249=>600, - 1250=>600, 1251=>600, 1252=>600, 1253=>600, 1254=>600, 1255=>600, 1256=>600, 1257=>600, 1258=>600, 1259=>600, 1260=>600, 1261=>600, 1262=>600, 1263=>600, 1264=>600, 1265=>600, - 1266=>600, 1267=>600, 1268=>600, 1269=>600, 1272=>600, 1273=>600, 1329=>600, 1330=>600, 1331=>600, 1332=>600, 1333=>600, 1334=>600, 1335=>600, 1336=>600, 1337=>600, 1338=>600, - 1339=>600, 1340=>600, 1341=>600, 1342=>600, 1343=>600, 1344=>600, 1345=>600, 1346=>600, 1347=>600, 1348=>600, 1349=>600, 1350=>600, 1351=>600, 1352=>600, 1353=>600, 1354=>600, - 1355=>600, 1356=>600, 1357=>600, 1358=>600, 1359=>600, 1360=>600, 1361=>600, 1362=>600, 1363=>600, 1364=>600, 1365=>600, 1366=>600, 1377=>600, 1378=>600, 1379=>600, 1380=>600, - 1381=>600, 1382=>600, 1383=>600, 1384=>600, 1385=>600, 1386=>600, 1387=>600, 1388=>600, 1389=>600, 1390=>600, 1391=>600, 1392=>600, 1393=>600, 1394=>600, 1395=>600, 1396=>600, - 1397=>600, 1398=>600, 1399=>600, 1400=>600, 1401=>600, 1402=>600, 1403=>600, 1404=>600, 1405=>600, 1406=>600, 1407=>600, 1408=>600, 1409=>600, 1410=>600, 1411=>600, 1412=>600, - 1413=>600, 1414=>600, 1418=>600, 1456=>600, 1457=>600, 1458=>600, 1459=>600, 1460=>600, 1461=>600, 1462=>600, 1463=>600, 1464=>600, 1465=>600, 1467=>600, 1468=>600, 1469=>600, - 1470=>600, 1471=>600, 1472=>600, 1473=>600, 1474=>600, 1475=>600, 1476=>600, 1488=>600, 1489=>600, 1490=>600, 1491=>600, 1492=>600, 1493=>600, 1494=>600, 1495=>600, 1496=>600, - 1497=>600, 1498=>600, 1499=>600, 1500=>600, 1501=>600, 1502=>600, 1503=>600, 1504=>600, 1505=>600, 1506=>600, 1507=>600, 1508=>600, 1509=>600, 1510=>600, 1511=>600, 1512=>600, - 1513=>600, 1514=>600, 1520=>600, 1521=>600, 1522=>600, 1523=>600, 1524=>600, 5792=>600, 5793=>600, 5794=>600, 5795=>600, 5796=>600, 5797=>600, 5798=>600, 5799=>600, 5800=>600, - 5801=>600, 5802=>600, 5803=>600, 5804=>600, 5805=>600, 5806=>600, 5807=>600, 5808=>600, 5809=>600, 5810=>600, 5811=>600, 5812=>600, 5813=>600, 5814=>600, 5815=>600, 5816=>600, - 5817=>600, 5818=>600, 5819=>600, 5820=>600, 5821=>600, 5822=>600, 5823=>600, 5824=>600, 5825=>600, 5826=>600, 5827=>600, 5828=>600, 5829=>600, 5830=>600, 5831=>600, 5832=>600, - 5833=>600, 5834=>600, 5835=>600, 5836=>600, 5837=>600, 5838=>600, 5839=>600, 5840=>600, 5841=>600, 5842=>600, 5843=>600, 5844=>600, 5845=>600, 5846=>600, 5847=>600, 5848=>600, - 5849=>600, 5850=>600, 5851=>600, 5852=>600, 5853=>600, 5854=>600, 5855=>600, 5856=>600, 5857=>600, 5858=>600, 5859=>600, 5860=>600, 5861=>600, 5862=>600, 5863=>600, 5864=>600, - 5865=>600, 5866=>600, 5867=>600, 5868=>600, 5869=>600, 5870=>600, 5871=>600, 5872=>600, 7680=>600, 7681=>600, 7682=>600, 7683=>600, 7684=>600, 7685=>600, 7686=>600, 7687=>600, - 7688=>600, 7689=>600, 7690=>600, 7691=>600, 7692=>600, 7693=>600, 7694=>600, 7695=>600, 7696=>600, 7697=>600, 7698=>600, 7699=>600, 7700=>600, 7701=>600, 7702=>600, 7703=>600, - 7704=>600, 7705=>600, 7706=>600, 7707=>600, 7708=>600, 7709=>600, 7710=>600, 7711=>600, 7712=>600, 7713=>600, 7714=>600, 7715=>600, 7716=>600, 7717=>600, 7718=>600, 7719=>600, - 7720=>600, 7721=>600, 7722=>600, 7723=>600, 7724=>600, 7725=>600, 7726=>600, 7727=>600, 7728=>600, 7729=>600, 7730=>600, 7731=>600, 7732=>600, 7733=>600, 7734=>600, 7735=>600, - 7736=>600, 7737=>600, 7738=>600, 7739=>600, 7740=>600, 7741=>600, 7742=>600, 7743=>600, 7744=>600, 7745=>600, 7746=>600, 7747=>600, 7748=>600, 7749=>600, 7750=>600, 7751=>600, - 7752=>600, 7753=>600, 7754=>600, 7755=>600, 7756=>600, 7757=>600, 7758=>600, 7759=>600, 7760=>600, 7761=>600, 7762=>600, 7763=>600, 7764=>600, 7765=>600, 7766=>600, 7767=>600, - 7768=>600, 7769=>600, 7770=>600, 7771=>600, 7772=>600, 7773=>600, 7774=>600, 7775=>600, 7776=>600, 7777=>600, 7778=>600, 7779=>600, 7780=>600, 7781=>600, 7782=>600, 7783=>600, - 7784=>600, 7785=>600, 7786=>600, 7787=>600, 7788=>600, 7789=>600, 7790=>600, 7791=>600, 7792=>600, 7793=>600, 7794=>600, 7795=>600, 7796=>600, 7797=>600, 7798=>600, 7799=>600, - 7800=>600, 7801=>600, 7802=>600, 7803=>600, 7804=>600, 7805=>600, 7806=>600, 7807=>600, 7808=>600, 7809=>600, 7810=>600, 7811=>600, 7812=>600, 7813=>600, 7814=>600, 7815=>600, - 7816=>600, 7817=>600, 7818=>600, 7819=>600, 7820=>600, 7821=>600, 7822=>600, 7823=>600, 7824=>600, 7825=>600, 7826=>600, 7827=>600, 7828=>600, 7829=>600, 7830=>600, 7831=>600, - 7832=>600, 7833=>600, 7834=>600, 7835=>600, 7840=>600, 7841=>600, 7842=>600, 7843=>600, 7844=>600, 7845=>600, 7846=>600, 7847=>600, 7848=>600, 7849=>600, 7850=>600, 7851=>600, - 7852=>600, 7853=>600, 7854=>600, 7855=>600, 7856=>600, 7857=>600, 7858=>600, 7859=>600, 7860=>600, 7861=>600, 7862=>600, 7863=>600, 7864=>600, 7865=>600, 7866=>600, 7867=>600, - 7868=>600, 7869=>600, 7870=>600, 7871=>600, 7872=>600, 7873=>600, 7874=>600, 7875=>600, 7876=>600, 7877=>600, 7878=>600, 7879=>600, 7880=>600, 7881=>600, 7882=>600, 7883=>600, - 7884=>600, 7885=>600, 7886=>600, 7887=>600, 7888=>600, 7889=>600, 7890=>600, 7891=>600, 7892=>600, 7893=>600, 7894=>600, 7895=>600, 7896=>600, 7897=>600, 7898=>600, 7899=>600, - 7900=>600, 7901=>600, 7902=>600, 7903=>600, 7904=>600, 7905=>600, 7906=>600, 7907=>600, 7908=>600, 7909=>600, 7910=>600, 7911=>600, 7912=>600, 7913=>600, 7914=>600, 7915=>600, - 7916=>600, 7917=>600, 7918=>600, 7919=>600, 7920=>600, 7921=>600, 7922=>600, 7923=>600, 7924=>600, 7925=>600, 7926=>600, 7927=>600, 7928=>600, 7929=>600, 7936=>600, 7937=>600, - 7938=>600, 7939=>600, 7940=>600, 7941=>600, 7942=>600, 7943=>600, 7944=>600, 7945=>600, 7946=>600, 7947=>600, 7948=>600, 7949=>600, 7950=>600, 7951=>600, 7952=>600, 7953=>600, - 7954=>600, 7955=>600, 7956=>600, 7957=>600, 7960=>600, 7961=>600, 7962=>600, 7963=>600, 7964=>600, 7965=>600, 7968=>600, 7969=>600, 7970=>600, 7971=>600, 7972=>600, 7973=>600, - 7974=>600, 7975=>600, 7976=>600, 7977=>600, 7978=>600, 7979=>600, 7980=>600, 7981=>600, 7982=>600, 7983=>600, 7984=>600, 7985=>600, 7986=>600, 7987=>600, 7988=>600, 7989=>600, - 7990=>600, 7991=>600, 7992=>600, 7993=>600, 7994=>600, 7995=>600, 7996=>600, 7997=>600, 7998=>600, 7999=>600, 8000=>600, 8001=>600, 8002=>600, 8003=>600, 8004=>600, 8005=>600, - 8008=>600, 8009=>600, 8010=>600, 8011=>600, 8012=>600, 8013=>600, 8016=>600, 8017=>600, 8018=>600, 8019=>600, 8020=>600, 8021=>600, 8022=>600, 8023=>600, 8025=>600, 8027=>600, - 8029=>600, 8031=>600, 8032=>600, 8033=>600, 8034=>600, 8035=>600, 8036=>600, 8037=>600, 8038=>600, 8039=>600, 8040=>600, 8041=>600, 8042=>600, 8043=>600, 8044=>600, 8045=>600, - 8046=>600, 8047=>600, 8048=>600, 8049=>600, 8050=>600, 8051=>600, 8052=>600, 8053=>600, 8054=>600, 8055=>600, 8056=>600, 8057=>600, 8058=>600, 8059=>600, 8060=>600, 8061=>600, - 8064=>600, 8065=>600, 8066=>600, 8067=>600, 8068=>600, 8069=>600, 8070=>600, 8071=>600, 8072=>600, 8073=>600, 8074=>600, 8075=>600, 8076=>600, 8077=>600, 8078=>600, 8079=>600, - 8080=>600, 8081=>600, 8082=>600, 8083=>600, 8084=>600, 8085=>600, 8086=>600, 8087=>600, 8088=>600, 8089=>600, 8090=>600, 8091=>600, 8092=>600, 8093=>600, 8094=>600, 8095=>600, - 8096=>600, 8097=>600, 8098=>600, 8099=>600, 8100=>600, 8101=>600, 8102=>600, 8103=>600, 8104=>600, 8105=>600, 8106=>600, 8107=>600, 8108=>600, 8109=>600, 8110=>600, 8111=>600, - 8112=>600, 8113=>600, 8114=>600, 8115=>600, 8116=>600, 8118=>600, 8119=>600, 8120=>600, 8121=>600, 8122=>600, 8123=>600, 8124=>600, 8125=>600, 8126=>600, 8127=>600, 8128=>600, - 8129=>600, 8130=>600, 8131=>600, 8132=>600, 8134=>600, 8135=>600, 8136=>600, 8137=>600, 8138=>600, 8139=>600, 8140=>600, 8141=>600, 8142=>600, 8143=>600, 8144=>600, 8145=>600, - 8146=>600, 8147=>600, 8150=>600, 8151=>600, 8152=>600, 8153=>600, 8154=>600, 8155=>600, 8157=>600, 8158=>600, 8159=>600, 8160=>600, 8161=>600, 8162=>600, 8163=>600, 8164=>600, - 8165=>600, 8166=>600, 8167=>600, 8168=>600, 8169=>600, 8170=>600, 8171=>600, 8172=>600, 8173=>600, 8175=>600, 8178=>600, 8179=>600, 8180=>600, 8182=>600, 8183=>600, 8184=>600, - 8185=>600, 8186=>600, 8187=>600, 8188=>600, 8189=>600, 8190=>600, 8208=>600, 8213=>600, 8215=>600, 8219=>600, 8223=>600, 8229=>600, 8241=>600, 8242=>600, 8243=>600, 8244=>600, - 8245=>600, 8246=>600, 8247=>600, 8252=>600, 8253=>600, 8254=>600, 8259=>600, 8260=>600, 8261=>600, 8262=>600, 8264=>600, 8265=>600, 8267=>600, 8304=>600, 8305=>600, 8306=>600, - 8307=>600, 8308=>600, 8309=>600, 8310=>600, 8311=>600, 8312=>600, 8313=>600, 8314=>600, 8315=>600, 8316=>600, 8317=>600, 8318=>600, 8319=>600, 8320=>600, 8321=>600, 8322=>600, - 8323=>600, 8324=>600, 8325=>600, 8326=>600, 8327=>600, 8328=>600, 8329=>600, 8330=>600, 8331=>600, 8332=>600, 8333=>600, 8334=>600, 8355=>600, 8356=>600, 8359=>600, 8362=>600, - 8448=>600, 8449=>600, 8450=>600, 8451=>600, 8453=>600, 8454=>600, 8455=>600, 8461=>600, 8464=>600, 8465=>600, 8466=>600, 8467=>600, 8468=>600, 8469=>600, 8470=>600, 8471=>600, - 8472=>600, 8473=>600, 8474=>600, 8477=>600, 8478=>600, 8484=>600, 8485=>600, 8486=>600, 8487=>600, 8490=>600, 8491=>600, 8498=>600, 8501=>600, 8531=>600, 8532=>600, 8533=>600, - 8534=>600, 8535=>600, 8536=>600, 8537=>600, 8538=>600, 8539=>600, 8540=>600, 8541=>600, 8542=>600, 8543=>600, 8544=>600, 8545=>600, 8546=>600, 8547=>600, 8548=>600, 8549=>600, - 8550=>600, 8551=>600, 8552=>600, 8553=>600, 8554=>600, 8555=>600, 8556=>600, 8557=>600, 8558=>600, 8559=>600, 8592=>600, 8593=>600, 8594=>600, 8595=>600, 8596=>600, 8597=>600, - 8598=>600, 8599=>600, 8600=>600, 8601=>600, 8602=>600, 8603=>600, 8604=>600, 8605=>600, 8606=>600, 8607=>600, 8608=>600, 8609=>600, 8610=>600, 8611=>600, 8612=>600, 8613=>600, - 8614=>600, 8615=>600, 8616=>600, 8617=>600, 8618=>600, 8619=>600, 8620=>600, 8621=>600, 8622=>600, 8623=>600, 8624=>600, 8625=>600, 8626=>600, 8627=>600, 8628=>600, 8629=>600, - 8630=>600, 8631=>600, 8632=>600, 8633=>600, 8634=>600, 8635=>600, 8636=>600, 8637=>600, 8638=>600, 8639=>600, 8640=>600, 8641=>600, 8642=>600, 8643=>600, 8644=>600, 8645=>600, - 8646=>600, 8647=>600, 8648=>600, 8649=>600, 8650=>600, 8651=>600, 8652=>600, 8653=>600, 8654=>600, 8655=>600, 8656=>600, 8657=>600, 8658=>600, 8659=>600, 8660=>600, 8661=>600, - 8704=>600, 8705=>600, 8706=>600, 8707=>600, 8708=>600, 8709=>600, 8710=>600, 8711=>600, 8712=>600, 8713=>600, 8714=>600, 8715=>600, 8716=>600, 8717=>600, 8719=>600, 8721=>600, - 8722=>600, 8723=>600, 8724=>600, 8725=>600, 8729=>600, 8730=>600, 8731=>600, 8732=>600, 8733=>600, 8734=>600, 8735=>600, 8743=>600, 8744=>600, 8745=>600, 8746=>600, 8747=>600, - 8748=>600, 8749=>600, 8750=>600, 8751=>600, 8752=>600, 8756=>600, 8757=>600, 8759=>600, 8764=>600, 8765=>600, 8769=>600, 8770=>600, 8771=>600, 8772=>600, 8773=>600, 8776=>600, - 8784=>600, 8785=>600, 8786=>600, 8787=>600, 8793=>600, 8794=>600, 8800=>600, 8801=>600, 8804=>600, 8805=>600, 8806=>600, 8807=>600, 8810=>600, 8811=>600, 8812=>600, 8814=>600, - 8815=>600, 8822=>600, 8823=>600, 8834=>600, 8835=>600, 8838=>600, 8839=>600, 8853=>600, 8854=>600, 8855=>600, 8856=>600, 8857=>600, 8858=>600, 8859=>600, 8860=>600, 8861=>600, - 8866=>600, 8867=>600, 8868=>600, 8869=>600, 8870=>600, 8871=>600, 8872=>600, 8873=>600, 8874=>600, 8875=>600, 8876=>600, 8877=>600, 8878=>600, 8879=>600, 8894=>600, 8901=>600, - 8902=>600, 8960=>600, 8962=>600, 8963=>600, 8968=>600, 8969=>600, 8970=>600, 8971=>600, 8972=>600, 8973=>600, 8974=>600, 8975=>600, 8976=>600, 8981=>600, 8988=>600, 8989=>600, - 8990=>600, 8991=>600, 9001=>600, 9002=>600, 9115=>600, 9116=>600, 9117=>600, 9118=>600, 9119=>600, 9120=>600, 9121=>600, 9122=>600, 9123=>600, 9124=>600, 9125=>600, 9126=>600, - 9127=>600, 9128=>600, 9129=>600, 9130=>600, 9131=>600, 9132=>600, 9133=>600, 9134=>600, 9135=>600, 9136=>600, 9137=>600, 9138=>600, 9139=>600, 9140=>600, 9143=>600, 9146=>600, - 9147=>600, 9148=>600, 9149=>600, 9472=>600, 9473=>600, 9474=>600, 9475=>600, 9476=>600, 9477=>600, 9478=>600, 9479=>600, 9480=>600, 9481=>600, 9482=>600, 9483=>600, 9484=>600, - 9485=>600, 9486=>600, 9487=>600, 9488=>600, 9489=>600, 9490=>600, 9491=>600, 9492=>600, 9493=>600, 9494=>600, 9495=>600, 9496=>600, 9497=>600, 9498=>600, 9499=>600, 9500=>600, - 9501=>600, 9502=>600, 9503=>600, 9504=>600, 9505=>600, 9506=>600, 9507=>600, 9508=>600, 9509=>600, 9510=>600, 9511=>600, 9512=>600, 9513=>600, 9514=>600, 9515=>600, 9516=>600, - 9517=>600, 9518=>600, 9519=>600, 9520=>600, 9521=>600, 9522=>600, 9523=>600, 9524=>600, 9525=>600, 9526=>600, 9527=>600, 9528=>600, 9529=>600, 9530=>600, 9531=>600, 9532=>600, - 9533=>600, 9534=>600, 9535=>600, 9536=>600, 9537=>600, 9538=>600, 9539=>600, 9540=>600, 9541=>600, 9542=>600, 9543=>600, 9544=>600, 9545=>600, 9546=>600, 9547=>600, 9548=>600, - 9549=>600, 9550=>600, 9551=>600, 9552=>600, 9553=>600, 9554=>600, 9555=>600, 9556=>600, 9557=>600, 9558=>600, 9559=>600, 9560=>600, 9561=>600, 9562=>600, 9563=>600, 9564=>600, - 9565=>600, 9566=>600, 9567=>600, 9568=>600, 9569=>600, 9570=>600, 9571=>600, 9572=>600, 9573=>600, 9574=>600, 9575=>600, 9576=>600, 9577=>600, 9578=>600, 9579=>600, 9580=>600, - 9581=>600, 9582=>600, 9583=>600, 9584=>600, 9585=>600, 9586=>600, 9587=>600, 9588=>600, 9589=>600, 9590=>600, 9591=>600, 9592=>600, 9593=>600, 9594=>600, 9595=>600, 9596=>600, - 9597=>600, 9598=>600, 9599=>600, 9600=>600, 9601=>600, 9602=>600, 9603=>600, 9604=>600, 9605=>600, 9606=>600, 9607=>600, 9608=>600, 9609=>600, 9610=>600, 9611=>600, 9612=>600, - 9613=>600, 9614=>600, 9615=>600, 9616=>600, 9617=>600, 9618=>600, 9619=>600, 9620=>600, 9621=>600, 9622=>600, 9623=>600, 9624=>600, 9625=>600, 9626=>600, 9627=>600, 9628=>600, - 9629=>600, 9630=>600, 9631=>600, 9632=>600, 9633=>600, 9634=>600, 9635=>600, 9636=>600, 9637=>600, 9638=>600, 9639=>600, 9640=>600, 9641=>600, 9642=>600, 9643=>600, 9644=>600, - 9645=>600, 9646=>600, 9647=>600, 9648=>600, 9649=>600, 9650=>600, 9651=>600, 9652=>600, 9653=>600, 9654=>600, 9655=>600, 9656=>600, 9657=>600, 9658=>600, 9659=>600, 9660=>600, - 9661=>600, 9662=>600, 9663=>600, 9664=>600, 9665=>600, 9666=>600, 9667=>600, 9668=>600, 9669=>600, 9670=>600, 9671=>600, 9672=>600, 9673=>600, 9674=>600, 9675=>600, 9676=>600, - 9677=>600, 9678=>600, 9679=>600, 9680=>600, 9681=>600, 9682=>600, 9683=>600, 9684=>600, 9685=>600, 9686=>600, 9687=>600, 9688=>600, 9689=>600, 9690=>600, 9691=>600, 9692=>600, - 9693=>600, 9694=>600, 9695=>600, 9696=>600, 9697=>600, 9698=>600, 9699=>600, 9700=>600, 9701=>600, 9702=>600, 9703=>600, 9704=>600, 9705=>600, 9706=>600, 9707=>600, 9708=>600, - 9709=>600, 9710=>600, 9711=>600, 9712=>600, 9713=>600, 9714=>600, 9715=>600, 9716=>600, 9717=>600, 9718=>600, 9719=>600, 9720=>600, 9721=>600, 9722=>600, 9723=>600, 9724=>600, - 9725=>600, 9726=>600, 9727=>600, 9728=>600, 9729=>600, 9730=>600, 9733=>600, 9734=>600, 9735=>600, 9736=>600, 9737=>600, 9744=>600, 9745=>600, 9746=>600, 9756=>600, 9758=>600, - 9766=>600, 9768=>600, 9769=>600, 9774=>600, 9776=>600, 9777=>600, 9778=>600, 9779=>600, 9780=>600, 9781=>600, 9782=>600, 9783=>600, 9785=>600, 9786=>600, 9787=>600, 9788=>600, - 9791=>600, 9792=>600, 9793=>600, 9794=>600, 9833=>600, 9834=>600, 9835=>600, 9836=>600, 9837=>600, 9838=>600, 9839=>600, 10214=>600, 10215=>600, 10216=>600, 10217=>600, 10218=>600, - 10219=>600, 10240=>600, 10241=>600, 10242=>600, 10243=>600, 10244=>600, 10245=>600, 10246=>600, 10247=>600, 10248=>600, 10249=>600, 10250=>600, 10251=>600, 10252=>600, 10253=>600, 10254=>600, - 10255=>600, 10256=>600, 10257=>600, 10258=>600, 10259=>600, 10260=>600, 10261=>600, 10262=>600, 10263=>600, 10264=>600, 10265=>600, 10266=>600, 10267=>600, 10268=>600, 10269=>600, 10270=>600, - 10271=>600, 10272=>600, 10273=>600, 10274=>600, 10275=>600, 10276=>600, 10277=>600, 10278=>600, 10279=>600, 10280=>600, 10281=>600, 10282=>600, 10283=>600, 10284=>600, 10285=>600, 10286=>600, - 10287=>600, 10288=>600, 10289=>600, 10290=>600, 10291=>600, 10292=>600, 10293=>600, 10294=>600, 10295=>600, 10296=>600, 10297=>600, 10298=>600, 10299=>600, 10300=>600, 10301=>600, 10302=>600, - 10303=>600, 10304=>600, 10305=>600, 10306=>600, 10307=>600, 10308=>600, 10309=>600, 10310=>600, 10311=>600, 10312=>600, 10313=>600, 10314=>600, 10315=>600, 10316=>600, 10317=>600, 10318=>600, - 10319=>600, 10320=>600, 10321=>600, 10322=>600, 10323=>600, 10324=>600, 10325=>600, 10326=>600, 10327=>600, 10328=>600, 10329=>600, 10330=>600, 10331=>600, 10332=>600, 10333=>600, 10334=>600, - 10335=>600, 10336=>600, 10337=>600, 10338=>600, 10339=>600, 10340=>600, 10341=>600, 10342=>600, 10343=>600, 10344=>600, 10345=>600, 10346=>600, 10347=>600, 10348=>600, 10349=>600, 10350=>600, - 10351=>600, 10352=>600, 10353=>600, 10354=>600, 10355=>600, 10356=>600, 10357=>600, 10358=>600, 10359=>600, 10360=>600, 10361=>600, 10362=>600, 10363=>600, 10364=>600, 10365=>600, 10366=>600, - 10367=>600, 10368=>600, 10369=>600, 10370=>600, 10371=>600, 10372=>600, 10373=>600, 10374=>600, 10375=>600, 10376=>600, 10377=>600, 10378=>600, 10379=>600, 10380=>600, 10381=>600, 10382=>600, - 10383=>600, 10384=>600, 10385=>600, 10386=>600, 10387=>600, 10388=>600, 10389=>600, 10390=>600, 10391=>600, 10392=>600, 10393=>600, 10394=>600, 10395=>600, 10396=>600, 10397=>600, 10398=>600, - 10399=>600, 10400=>600, 10401=>600, 10402=>600, 10403=>600, 10404=>600, 10405=>600, 10406=>600, 10407=>600, 10408=>600, 10409=>600, 10410=>600, 10411=>600, 10412=>600, 10413=>600, 10414=>600, - 10415=>600, 10416=>600, 10417=>600, 10418=>600, 10419=>600, 10420=>600, 10421=>600, 10422=>600, 10423=>600, 10424=>600, 10425=>600, 10426=>600, 10427=>600, 10428=>600, 10429=>600, 10430=>600, - 10431=>600, 10432=>600, 10433=>600, 10434=>600, 10435=>600, 10436=>600, 10437=>600, 10438=>600, 10439=>600, 10440=>600, 10441=>600, 10442=>600, 10443=>600, 10444=>600, 10445=>600, 10446=>600, - 10447=>600, 10448=>600, 10449=>600, 10450=>600, 10451=>600, 10452=>600, 10453=>600, 10454=>600, 10455=>600, 10456=>600, 10457=>600, 10458=>600, 10459=>600, 10460=>600, 10461=>600, 10462=>600, - 10463=>600, 10464=>600, 10465=>600, 10466=>600, 10467=>600, 10468=>600, 10469=>600, 10470=>600, 10471=>600, 10472=>600, 10473=>600, 10474=>600, 10475=>600, 10476=>600, 10477=>600, 10478=>600, - 10479=>600, 10480=>600, 10481=>600, 10482=>600, 10483=>600, 10484=>600, 10485=>600, 10486=>600, 10487=>600, 10488=>600, 10489=>600, 10490=>600, 10491=>600, 10492=>600, 10493=>600, 10494=>600, - 10495=>600, 63171=>600, 64256=>600, 64257=>600, 64258=>600, 64261=>600, 64262=>600, 64285=>600, 64286=>600, 64287=>600, 64288=>600, 64289=>600, 64290=>600, 64291=>600, 64292=>600, 64293=>600, - 64294=>600, 64295=>600, 64296=>600, 64297=>600, 64298=>600, 64299=>600, 64300=>600, 64301=>600, 64302=>600, 64303=>600, 64304=>600, 64305=>600, 64306=>600, 64307=>600, 64308=>600, 64309=>600, - 64310=>600, 64312=>600, 64313=>600, 64314=>600, 64315=>600, 64316=>600, 64318=>600, 64320=>600, 64321=>600, 64323=>600, 64324=>600, 64326=>600, 64327=>600, 64328=>600, 64329=>600, 64330=>600, - 64331=>600, 64332=>600, 64333=>600, 64334=>600, 64335=>600, 65533=>600, 8174=>600} - font[:enc]=''; - font[:diff]=''; - font[:file]='FreeMono.z'; - font[:ctg]='FreeMono.ctg.z'; - font[:originalsize]=293572; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/freemonob.rb --- a/vendor/plugins/rfpdf/lib/fonts/freemonob.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -TCPDFFontDescriptor.define('freemonob') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='FreeMonoBold'; - font[:desc]={'Ascent'=>1155,'Descent'=>-365,'CapHeight'=>1155,'Flags'=>32,'FontBBox'=>'[-656 -365 950 1155]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>600} - font[:up]=-100; - font[:ut]=50; - font[:cw]={ - 13=>333, 32=>600, 33=>600, 34=>600, 35=>600, 36=>600, 37=>600, 38=>600, 39=>600, 40=>600, 41=>600, 42=>600, 43=>600, 44=>600, 45=>600, 46=>600, - 47=>600, 48=>600, 49=>600, 50=>600, 51=>600, 52=>600, 53=>600, 54=>600, 55=>600, 56=>600, 57=>600, 58=>600, 59=>600, 60=>600, 61=>600, 62=>600, - 63=>600, 64=>600, 65=>600, 66=>600, 67=>600, 68=>600, 69=>600, 70=>600, 71=>600, 72=>600, 73=>600, 74=>600, 75=>600, 76=>600, 77=>600, 78=>600, - 79=>600, 80=>600, 81=>600, 82=>600, 83=>600, 84=>600, 85=>600, 86=>600, 87=>600, 88=>600, 89=>600, 90=>600, 91=>600, 92=>600, 93=>600, 94=>600, - 95=>600, 96=>600, 97=>600, 98=>600, 99=>600, 100=>600, 101=>600, 102=>600, 103=>600, 104=>600, 105=>600, 106=>600, 107=>600, 108=>600, 109=>600, 110=>600, - 111=>600, 112=>600, 113=>600, 114=>600, 115=>600, 116=>600, 117=>600, 118=>600, 119=>600, 120=>600, 121=>600, 122=>600, 123=>600, 124=>600, 125=>600, 126=>600, - 8364=>600, 1027=>600, 8218=>600, 402=>600, 8222=>600, 8230=>600, 8224=>600, 8225=>600, 710=>600, 8240=>600, 352=>600, 8249=>600, 338=>600, 1036=>600, 381=>600, 1039=>600, - 8216=>600, 8217=>600, 8220=>600, 8221=>600, 8226=>600, 8211=>600, 8212=>600, 732=>600, 8482=>600, 353=>600, 8250=>600, 339=>600, 1116=>600, 382=>600, 376=>600, 160=>600, - 161=>600, 162=>600, 163=>600, 164=>600, 165=>600, 166=>600, 167=>600, 168=>600, 169=>600, 170=>600, 171=>600, 172=>600, 173=>600, 174=>600, 175=>600, 176=>600, - 177=>600, 178=>600, 179=>600, 180=>600, 181=>600, 182=>600, 183=>600, 184=>600, 185=>600, 186=>600, 187=>600, 188=>600, 189=>600, 190=>600, 191=>600, 192=>600, - 193=>600, 194=>600, 195=>600, 196=>600, 197=>600, 198=>600, 199=>600, 200=>600, 201=>600, 202=>600, 203=>600, 204=>600, 205=>600, 206=>600, 207=>600, 208=>600, - 209=>600, 210=>600, 211=>600, 212=>600, 213=>600, 214=>600, 215=>600, 216=>600, 217=>600, 218=>600, 219=>600, 220=>600, 221=>600, 222=>600, 223=>600, 224=>600, - 225=>600, 226=>600, 227=>600, 228=>600, 229=>600, 230=>600, 231=>600, 232=>600, 233=>600, 234=>600, 235=>600, 236=>600, 237=>600, 238=>600, 239=>600, 240=>600, - 241=>600, 242=>600, 243=>600, 244=>600, 245=>600, 246=>600, 247=>600, 248=>600, 249=>600, 250=>600, 251=>600, 252=>600, 253=>600, 254=>600, 255=>600, 256=>600, - 257=>600, 258=>600, 259=>600, 260=>600, 261=>600, 262=>600, 263=>600, 264=>600, 265=>600, 266=>600, 267=>600, 268=>600, 269=>600, 270=>600, 271=>600, 272=>600, - 273=>600, 274=>600, 275=>600, 276=>600, 277=>600, 278=>600, 279=>600, 280=>600, 281=>600, 282=>600, 283=>600, 284=>600, 285=>600, 286=>600, 287=>600, 288=>600, - 289=>600, 290=>600, 291=>600, 292=>600, 293=>600, 294=>600, 295=>600, 296=>600, 297=>600, 298=>600, 299=>600, 300=>600, 301=>600, 302=>600, 303=>600, 304=>600, - 305=>600, 306=>600, 307=>600, 308=>600, 309=>600, 310=>600, 311=>600, 312=>600, 313=>600, 314=>600, 315=>600, 316=>600, 317=>600, 318=>600, 319=>600, 320=>600, - 321=>600, 322=>600, 323=>600, 324=>600, 325=>600, 326=>600, 327=>600, 328=>600, 329=>600, 330=>600, 331=>600, 332=>600, 333=>600, 334=>600, 335=>600, 336=>600, - 337=>600, 340=>600, 341=>600, 342=>600, 343=>600, 344=>600, 345=>600, 346=>600, 347=>600, 348=>600, 349=>600, 350=>600, 351=>600, 354=>600, 355=>600, 356=>600, - 357=>600, 358=>600, 359=>600, 360=>600, 361=>600, 362=>600, 363=>600, 364=>600, 365=>600, 366=>600, 367=>600, 368=>600, 369=>600, 370=>600, 371=>600, 372=>600, - 373=>600, 374=>600, 375=>600, 377=>600, 378=>600, 379=>600, 380=>600, 383=>600, 384=>600, 385=>600, 386=>600, 387=>600, 390=>600, 391=>600, 392=>600, 393=>600, - 394=>600, 395=>600, 396=>600, 397=>600, 398=>600, 400=>600, 401=>600, 403=>600, 405=>600, 406=>600, 407=>600, 409=>600, 410=>600, 411=>600, 412=>600, 413=>600, - 414=>600, 415=>600, 416=>600, 417=>600, 418=>600, 419=>600, 420=>600, 421=>600, 422=>600, 423=>600, 424=>600, 425=>600, 427=>600, 428=>600, 429=>600, 430=>600, - 431=>600, 432=>600, 435=>600, 436=>600, 437=>600, 438=>600, 439=>600, 440=>600, 443=>600, 448=>600, 449=>600, 451=>600, 455=>600, 456=>600, 457=>600, 459=>600, - 460=>600, 461=>600, 462=>600, 463=>600, 464=>600, 465=>600, 466=>600, 467=>600, 468=>600, 469=>600, 470=>600, 471=>600, 472=>600, 473=>600, 474=>600, 475=>600, - 476=>600, 477=>600, 478=>600, 479=>600, 480=>600, 481=>600, 482=>600, 483=>600, 484=>600, 485=>600, 486=>600, 487=>600, 488=>600, 489=>600, 490=>600, 491=>600, - 492=>600, 493=>600, 494=>600, 496=>600, 500=>600, 501=>600, 502=>600, 504=>600, 505=>600, 506=>600, 507=>600, 508=>600, 509=>600, 510=>600, 511=>600, 512=>600, - 513=>600, 514=>600, 515=>600, 516=>600, 517=>600, 518=>600, 519=>600, 520=>600, 521=>600, 522=>600, 523=>600, 524=>600, 525=>600, 526=>600, 527=>600, 528=>600, - 529=>600, 530=>600, 531=>600, 532=>600, 533=>600, 534=>600, 535=>600, 536=>600, 537=>600, 538=>600, 539=>600, 542=>600, 543=>600, 548=>600, 549=>600, 550=>600, - 551=>600, 552=>600, 553=>600, 554=>600, 555=>600, 556=>600, 557=>600, 558=>600, 559=>600, 560=>600, 561=>600, 562=>600, 563=>600, 592=>600, 593=>600, 594=>600, - 595=>600, 596=>600, 598=>600, 599=>600, 600=>600, 601=>600, 603=>600, 604=>600, 607=>600, 608=>600, 609=>600, 613=>600, 614=>600, 615=>600, 616=>600, 617=>600, - 618=>600, 619=>600, 621=>600, 623=>600, 624=>600, 625=>600, 626=>600, 627=>600, 628=>600, 629=>600, 633=>600, 634=>600, 635=>600, 636=>600, 637=>600, 638=>600, - 639=>600, 640=>600, 641=>600, 642=>600, 643=>600, 644=>600, 645=>600, 647=>600, 648=>600, 649=>600, 652=>600, 653=>600, 654=>600, 656=>600, 660=>600, 661=>600, - 662=>600, 663=>600, 664=>600, 668=>600, 670=>600, 671=>600, 672=>600, 673=>600, 674=>600, 711=>600, 720=>600, 721=>600, 728=>600, 729=>600, 730=>600, 731=>600, - 733=>600, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, - 783=>0, 784=>0, 785=>0, 795=>0, 801=>0, 802=>0, 807=>0, 808=>0, 823=>0, 884=>600, 885=>600, 890=>600, 894=>600, 900=>600, 901=>600, 902=>600, - 903=>600, 904=>600, 905=>600, 906=>600, 908=>600, 910=>600, 911=>600, 912=>600, 913=>600, 914=>600, 915=>600, 916=>600, 917=>600, 918=>600, 919=>600, 920=>600, - 921=>600, 922=>600, 923=>600, 924=>600, 925=>600, 926=>600, 927=>600, 928=>600, 929=>600, 931=>600, 932=>600, 933=>600, 934=>600, 935=>600, 936=>600, 937=>600, - 938=>600, 939=>600, 940=>600, 941=>600, 942=>600, 943=>600, 944=>600, 945=>600, 946=>600, 947=>600, 948=>600, 949=>600, 950=>600, 951=>600, 952=>600, 953=>600, - 954=>600, 955=>600, 956=>600, 957=>600, 958=>600, 959=>600, 960=>600, 961=>600, 962=>600, 963=>600, 964=>600, 965=>600, 966=>600, 967=>600, 968=>600, 969=>600, - 970=>600, 971=>600, 972=>600, 973=>600, 974=>600, 976=>600, 977=>600, 981=>600, 1009=>600, 1024=>600, 1025=>600, 1026=>600, 1028=>600, 1029=>600, 1030=>600, 1031=>600, - 1032=>600, 1033=>600, 1034=>600, 1035=>600, 1037=>600, 1038=>600, 1040=>600, 1041=>600, 1042=>600, 1043=>600, 1044=>600, 1045=>600, 1046=>600, 1047=>600, 1048=>600, 1049=>600, - 1050=>600, 1051=>600, 1052=>600, 1053=>600, 1054=>600, 1055=>600, 1056=>600, 1057=>600, 1058=>600, 1059=>600, 1060=>600, 1061=>600, 1062=>600, 1063=>600, 1064=>600, 1065=>600, - 1066=>600, 1067=>600, 1068=>600, 1069=>600, 1070=>600, 1071=>600, 1072=>600, 1073=>600, 1074=>600, 1075=>600, 1076=>600, 1077=>600, 1078=>600, 1079=>600, 1080=>600, 1081=>600, - 1082=>600, 1083=>600, 1084=>600, 1085=>600, 1086=>600, 1087=>600, 1088=>600, 1089=>600, 1090=>600, 1091=>600, 1092=>600, 1093=>600, 1094=>600, 1095=>600, 1096=>600, 1097=>600, - 1098=>600, 1099=>600, 1100=>600, 1101=>600, 1102=>600, 1103=>600, 1104=>600, 1105=>600, 1106=>600, 1107=>600, 1108=>600, 1109=>600, 1110=>600, 1111=>600, 1112=>600, 1113=>600, - 1114=>600, 1115=>600, 1117=>600, 1118=>600, 1119=>600, 1164=>600, 1165=>600, 1166=>600, 1167=>600, 1168=>600, 1169=>600, 1170=>600, 1171=>600, 1172=>600, 1173=>600, 1174=>600, - 1175=>600, 1176=>600, 1177=>600, 1178=>600, 1179=>600, 1180=>600, 1181=>600, 1182=>600, 1183=>600, 1184=>600, 1185=>600, 1186=>600, 1187=>600, 1188=>600, 1189=>600, 1190=>600, - 1191=>600, 1192=>600, 1193=>600, 1194=>600, 1195=>600, 1196=>600, 1197=>600, 1198=>600, 1199=>600, 1200=>600, 1201=>600, 1202=>600, 1203=>600, 1204=>600, 1205=>600, 1206=>600, - 1207=>600, 1208=>600, 1209=>600, 1210=>600, 1211=>600, 1212=>600, 1213=>600, 1214=>600, 1215=>600, 1216=>600, 1217=>600, 1218=>600, 1219=>600, 1220=>600, 1221=>600, 1222=>600, - 1223=>600, 1224=>600, 1225=>600, 1226=>600, 1227=>600, 1228=>600, 1229=>600, 1230=>600, 1231=>600, 1232=>600, 1233=>600, 1234=>600, 1235=>600, 1236=>600, 1237=>600, 1238=>600, - 1239=>600, 1240=>600, 1241=>600, 1242=>600, 1243=>600, 1244=>600, 1245=>600, 1246=>600, 1247=>600, 1248=>600, 1249=>600, 1250=>600, 1251=>600, 1252=>600, 1253=>600, 1254=>600, - 1255=>600, 1256=>600, 1257=>600, 1258=>600, 1259=>600, 1260=>600, 1261=>600, 1262=>600, 1263=>600, 1264=>600, 1265=>600, 1266=>600, 1267=>600, 1268=>600, 1269=>600, 1270=>600, - 1271=>600, 1272=>600, 1273=>600, 1456=>600, 1457=>600, 1458=>600, 1459=>600, 1460=>600, 1461=>600, 1462=>600, 1463=>600, 1464=>600, 1465=>600, 1467=>600, 1468=>600, 1469=>600, - 1470=>600, 1471=>600, 1472=>600, 1473=>600, 1474=>600, 1475=>600, 1476=>600, 1488=>600, 1489=>600, 1490=>600, 1491=>600, 1492=>600, 1493=>600, 1494=>600, 1495=>600, 1496=>600, - 1497=>600, 1498=>600, 1499=>600, 1500=>600, 1501=>600, 1502=>600, 1503=>600, 1504=>600, 1505=>600, 1506=>600, 1507=>600, 1508=>600, 1509=>600, 1510=>600, 1511=>600, 1512=>600, - 1513=>600, 1514=>600, 1520=>600, 1521=>600, 1522=>600, 1523=>600, 1524=>600, 7680=>600, 7681=>600, 7682=>600, 7683=>600, 7684=>600, 7685=>600, 7686=>600, 7687=>600, 7688=>600, - 7689=>600, 7690=>600, 7691=>600, 7692=>600, 7693=>600, 7694=>600, 7695=>600, 7696=>600, 7697=>600, 7698=>600, 7699=>600, 7700=>600, 7701=>600, 7702=>600, 7703=>600, 7704=>600, - 7705=>600, 7706=>600, 7707=>600, 7708=>600, 7709=>600, 7710=>600, 7711=>600, 7712=>600, 7713=>600, 7714=>600, 7715=>600, 7716=>600, 7717=>600, 7718=>600, 7719=>600, 7720=>600, - 7721=>600, 7722=>600, 7723=>600, 7724=>600, 7725=>600, 7726=>600, 7727=>600, 7728=>600, 7729=>600, 7730=>600, 7731=>600, 7732=>600, 7733=>600, 7734=>600, 7735=>600, 7736=>600, - 7737=>600, 7738=>600, 7739=>600, 7740=>600, 7741=>600, 7742=>600, 7743=>600, 7744=>600, 7745=>600, 7746=>600, 7747=>600, 7748=>600, 7749=>600, 7750=>600, 7751=>600, 7752=>600, - 7753=>600, 7754=>600, 7755=>600, 7756=>600, 7757=>600, 7758=>600, 7759=>600, 7760=>600, 7761=>600, 7762=>600, 7763=>600, 7764=>600, 7765=>600, 7766=>600, 7767=>600, 7768=>600, - 7769=>600, 7770=>600, 7771=>600, 7772=>600, 7773=>600, 7774=>600, 7775=>600, 7776=>600, 7777=>600, 7778=>600, 7779=>600, 7780=>600, 7781=>600, 7782=>600, 7783=>600, 7784=>600, - 7785=>600, 7786=>600, 7787=>600, 7788=>600, 7789=>600, 7790=>600, 7791=>600, 7792=>600, 7793=>600, 7794=>600, 7795=>600, 7796=>600, 7797=>600, 7798=>600, 7799=>600, 7800=>600, - 7801=>600, 7802=>600, 7803=>600, 7804=>600, 7805=>600, 7806=>600, 7807=>600, 7808=>600, 7809=>600, 7810=>600, 7811=>600, 7812=>600, 7813=>600, 7814=>600, 7815=>600, 7816=>600, - 7817=>600, 7818=>600, 7819=>600, 7820=>600, 7821=>600, 7822=>600, 7823=>600, 7824=>600, 7825=>600, 7826=>600, 7827=>600, 7828=>600, 7829=>600, 7830=>600, 7831=>600, 7832=>600, - 7833=>600, 7835=>600, 7840=>600, 7841=>600, 7842=>600, 7843=>600, 7844=>600, 7845=>600, 7846=>600, 7847=>600, 7848=>600, 7849=>600, 7850=>600, 7851=>600, 7852=>600, 7853=>600, - 7854=>600, 7855=>600, 7856=>600, 7857=>600, 7858=>600, 7859=>600, 7860=>600, 7861=>600, 7862=>600, 7863=>600, 7864=>600, 7865=>600, 7866=>600, 7867=>600, 7868=>600, 7869=>600, - 7870=>600, 7871=>600, 7872=>600, 7873=>600, 7874=>600, 7875=>600, 7876=>600, 7877=>600, 7878=>600, 7879=>600, 7880=>600, 7881=>600, 7882=>600, 7883=>600, 7884=>600, 7885=>600, - 7886=>600, 7887=>600, 7888=>600, 7889=>600, 7890=>600, 7891=>600, 7892=>600, 7893=>600, 7894=>600, 7895=>600, 7896=>600, 7897=>600, 7898=>600, 7899=>600, 7900=>600, 7901=>600, - 7902=>600, 7903=>600, 7904=>600, 7905=>600, 7906=>600, 7907=>600, 7908=>600, 7909=>600, 7910=>600, 7911=>600, 7912=>600, 7913=>600, 7914=>600, 7915=>600, 7916=>600, 7917=>600, - 7918=>600, 7919=>600, 7920=>600, 7921=>600, 7922=>600, 7923=>600, 7924=>600, 7925=>600, 7926=>600, 7927=>600, 7928=>600, 7929=>600, 8209=>600, 8213=>600, 8219=>600, 8223=>600, - 8242=>600, 8243=>600, 8244=>600, 8245=>600, 8246=>600, 8247=>600, 8252=>600, 8260=>600, 8261=>600, 8262=>600, 8264=>600, 8265=>600, 8267=>600, 8292=>600, 8304=>600, 8305=>600, - 8306=>600, 8307=>600, 8308=>600, 8309=>600, 8310=>600, 8311=>600, 8312=>600, 8313=>600, 8314=>600, 8315=>600, 8316=>600, 8317=>600, 8318=>600, 8319=>600, 8320=>600, 8321=>600, - 8322=>600, 8323=>600, 8324=>600, 8325=>600, 8326=>600, 8327=>600, 8328=>600, 8329=>600, 8355=>600, 8356=>600, 8362=>600, 8466=>600, 8470=>600, 8486=>600, 8487=>600, 8490=>600, - 8491=>600, 8531=>600, 8532=>600, 8533=>600, 8534=>600, 8535=>600, 8536=>600, 8537=>600, 8538=>600, 8539=>600, 8540=>600, 8541=>600, 8542=>600, 8543=>600, 8592=>600, 8593=>600, - 8594=>600, 8595=>600, 8706=>600, 8709=>600, 8710=>600, 8711=>600, 8721=>600, 8722=>600, 8725=>600, 8730=>600, 8733=>600, 8734=>600, 8735=>600, 8800=>600, 8801=>600, 8804=>600, - 8805=>600, 8976=>600, 9472=>600, 9473=>600, 9474=>600, 9475=>600, 9476=>600, 9477=>600, 9478=>600, 9479=>600, 9480=>600, 9481=>600, 9482=>600, 9483=>600, 9484=>600, 9485=>600, - 9486=>600, 9487=>600, 9488=>600, 9489=>600, 9490=>600, 9491=>600, 9492=>600, 9493=>600, 9494=>600, 9495=>600, 9496=>600, 9497=>600, 9498=>600, 9499=>600, 9500=>600, 9501=>600, - 9502=>600, 9503=>600, 9504=>600, 9505=>600, 9506=>600, 9507=>600, 9508=>600, 9509=>600, 9510=>600, 9511=>600, 9512=>600, 9513=>600, 9514=>600, 9515=>600, 9516=>600, 9517=>600, - 9518=>600, 9519=>600, 9520=>600, 9521=>600, 9522=>600, 9523=>600, 9524=>600, 9525=>600, 9526=>600, 9527=>600, 9528=>600, 9529=>600, 9530=>600, 9531=>600, 9532=>600, 9533=>600, - 9534=>600, 9535=>600, 9536=>600, 9537=>600, 9538=>600, 9539=>600, 9540=>600, 9541=>600, 9542=>600, 9543=>600, 9544=>600, 9545=>600, 9546=>600, 9547=>600, 9548=>600, 9549=>600, - 9550=>600, 9551=>600, 9552=>600, 9553=>600, 9554=>600, 9555=>600, 9556=>600, 9557=>600, 9558=>600, 9559=>600, 9560=>600, 9561=>600, 9562=>600, 9563=>600, 9564=>600, 9565=>600, - 9566=>600, 9567=>600, 9568=>600, 9569=>600, 9570=>600, 9571=>600, 9572=>600, 9573=>600, 9574=>600, 9575=>600, 9576=>600, 9577=>600, 9578=>600, 9579=>600, 9580=>600, 9581=>600, - 9582=>600, 9583=>600, 9584=>600, 9585=>600, 9586=>600, 9587=>600, 9588=>600, 9589=>600, 9590=>600, 9591=>600, 9592=>600, 9593=>600, 9594=>600, 9595=>600, 9596=>600, 9597=>600, - 9598=>600, 9599=>600, 9600=>600, 9601=>600, 9602=>600, 9603=>600, 9604=>600, 9605=>600, 9606=>600, 9607=>600, 9608=>600, 9609=>600, 9610=>600, 9611=>600, 9612=>600, 9613=>600, - 9614=>600, 9615=>600, 9616=>600, 9617=>600, 9618=>600, 9619=>600, 9620=>600, 9621=>600, 9632=>600, 9633=>600, 9635=>600, 9636=>600, 9637=>600, 9638=>600, 9639=>600, 9640=>600, - 9641=>600, 9642=>600, 9643=>600, 9644=>600, 9645=>600, 9646=>600, 9647=>600, 9648=>600, 9649=>600, 9650=>600, 9651=>600, 9652=>600, 9653=>600, 9654=>600, 9655=>600, 9656=>600, - 9657=>600, 9658=>600, 9660=>600, 9661=>600, 9662=>600, 9663=>600, 9664=>600, 9665=>600, 9666=>600, 9667=>600, 9668=>600, 9669=>600, 9670=>600, 9671=>600, 9673=>600, 9674=>600, - 9675=>600, 9677=>600, 9679=>600, 9680=>600, 9681=>600, 9682=>600, 9683=>600, 9684=>600, 9685=>600, 9686=>600, 9687=>600, 9688=>600, 9689=>600, 9698=>600, 9699=>600, 9700=>600, - 9701=>600, 9702=>600, 9703=>600, 9704=>600, 9705=>600, 9706=>600, 9707=>600, 9708=>600, 9709=>600, 9710=>600, 9712=>600, 9713=>600, 9714=>600, 9715=>600, 9716=>600, 9717=>600, - 9718=>600, 9719=>600, 9735=>600, 9736=>600, 9737=>600, 9776=>600, 9777=>600, 9778=>600, 9779=>600, 9780=>600, 9781=>600, 9782=>600, 9783=>600, 9785=>600, 9786=>600, 9787=>600, - 9833=>600, 9834=>600, 9835=>600, 9836=>600, 63166=>600, 63171=>600, 64256=>600, 64257=>600, 64258=>600} - font[:enc]=''; - font[:diff]=''; - font[:file]='FreeMonoBold.z'; - font[:ctg]='FreeMonoBold.ctg.z'; - font[:originalsize]=175016; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/freemonobi.rb --- a/vendor/plugins/rfpdf/lib/fonts/freemonobi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -TCPDFFontDescriptor.define('freemonobi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='FreeMonoBoldOblique'; - font[:desc]={'Ascent'=>1111,'Descent'=>-278,'CapHeight'=>1111,'Flags'=>96,'FontBBox'=>'[-513 -278 840 1111]','ItalicAngle'=>-12,'StemV'=>120,'MissingWidth'=>600} - font[:up]=-100; - font[:ut]=50; - font[:cw]={ - 13=>333, 32=>600, 33=>600, 34=>600, 35=>600, 36=>600, 37=>600, 38=>600, 39=>600, 40=>600, 41=>600, 42=>600, 43=>600, 44=>600, 45=>600, 46=>600, - 47=>600, 48=>600, 49=>600, 50=>600, 51=>600, 52=>600, 53=>600, 54=>600, 55=>600, 56=>600, 57=>600, 58=>600, 59=>600, 60=>600, 61=>600, 62=>600, - 63=>600, 64=>600, 65=>600, 66=>600, 67=>600, 68=>600, 69=>600, 70=>600, 71=>600, 72=>600, 73=>600, 74=>600, 75=>600, 76=>600, 77=>600, 78=>600, - 79=>600, 80=>600, 81=>600, 82=>600, 83=>600, 84=>600, 85=>600, 86=>600, 87=>600, 88=>600, 89=>600, 90=>600, 91=>600, 92=>600, 93=>600, 94=>600, - 95=>600, 96=>600, 97=>600, 98=>600, 99=>600, 100=>600, 101=>600, 102=>600, 103=>600, 104=>600, 105=>600, 106=>600, 107=>600, 108=>600, 109=>600, 110=>600, - 111=>600, 112=>600, 113=>600, 114=>600, 115=>600, 116=>600, 117=>600, 118=>600, 119=>600, 120=>600, 121=>600, 122=>600, 123=>600, 124=>600, 125=>600, 126=>600, - 8364=>600, 1027=>600, 8218=>600, 402=>600, 8222=>600, 8230=>600, 8224=>600, 8225=>600, 710=>600, 8240=>600, 352=>600, 8249=>600, 338=>600, 1036=>600, 381=>600, 1039=>600, - 8216=>600, 8217=>600, 8220=>600, 8221=>600, 8226=>600, 8211=>600, 8212=>600, 732=>600, 8482=>600, 353=>600, 8250=>600, 339=>600, 1116=>600, 382=>600, 376=>600, 160=>600, - 161=>600, 162=>600, 163=>600, 164=>600, 165=>600, 166=>600, 167=>600, 168=>600, 169=>600, 170=>600, 171=>600, 172=>600, 173=>600, 174=>600, 175=>600, 176=>600, - 177=>600, 178=>600, 179=>600, 180=>600, 181=>600, 182=>600, 183=>600, 184=>600, 185=>600, 186=>600, 187=>600, 188=>600, 189=>600, 190=>600, 191=>600, 192=>600, - 193=>600, 194=>600, 195=>600, 196=>600, 197=>600, 198=>600, 199=>600, 200=>600, 201=>600, 202=>600, 203=>600, 204=>600, 205=>600, 206=>600, 207=>600, 208=>600, - 209=>600, 210=>600, 211=>600, 212=>600, 213=>600, 214=>600, 215=>600, 216=>600, 217=>600, 218=>600, 219=>600, 220=>600, 221=>600, 222=>600, 223=>600, 224=>600, - 225=>600, 226=>600, 227=>600, 228=>600, 229=>600, 230=>600, 231=>600, 232=>600, 233=>600, 234=>600, 235=>600, 236=>600, 237=>600, 238=>600, 239=>600, 240=>600, - 241=>600, 242=>600, 243=>600, 244=>600, 245=>600, 246=>600, 247=>600, 248=>600, 249=>600, 250=>600, 251=>600, 252=>600, 253=>600, 254=>600, 255=>600, 256=>600, - 257=>600, 258=>600, 259=>600, 260=>600, 261=>600, 262=>600, 263=>600, 264=>600, 265=>600, 266=>600, 267=>600, 268=>600, 269=>600, 270=>600, 271=>600, 272=>600, - 273=>600, 274=>600, 275=>600, 276=>600, 277=>600, 278=>600, 279=>600, 280=>600, 281=>600, 282=>600, 283=>600, 284=>600, 285=>600, 286=>600, 287=>600, 288=>600, - 289=>600, 290=>600, 291=>600, 292=>600, 293=>600, 294=>600, 295=>600, 296=>600, 297=>600, 298=>600, 299=>600, 300=>600, 301=>600, 302=>600, 303=>600, 304=>600, - 305=>600, 306=>600, 307=>600, 308=>600, 309=>600, 310=>600, 311=>600, 312=>600, 313=>600, 314=>600, 315=>600, 316=>600, 317=>600, 318=>600, 319=>600, 320=>600, - 321=>600, 322=>600, 323=>600, 324=>600, 325=>600, 326=>600, 327=>600, 328=>600, 329=>600, 330=>600, 331=>600, 332=>600, 333=>600, 334=>600, 335=>600, 336=>600, - 337=>600, 340=>600, 341=>600, 342=>600, 343=>600, 344=>600, 345=>600, 346=>600, 347=>600, 348=>600, 349=>600, 350=>600, 351=>600, 354=>600, 355=>600, 356=>600, - 357=>600, 358=>600, 359=>600, 360=>600, 361=>600, 362=>600, 363=>600, 364=>600, 365=>600, 366=>600, 367=>600, 368=>600, 369=>600, 370=>600, 371=>600, 372=>600, - 373=>600, 374=>600, 375=>600, 377=>600, 378=>600, 379=>600, 380=>600, 383=>600, 425=>600, 461=>600, 462=>600, 463=>600, 464=>600, 465=>600, 466=>600, 467=>600, - 468=>600, 469=>600, 470=>600, 471=>600, 472=>600, 473=>600, 474=>600, 475=>600, 476=>600, 477=>600, 478=>600, 479=>600, 482=>600, 483=>600, 486=>600, 487=>600, - 488=>600, 489=>600, 490=>600, 491=>600, 492=>600, 493=>600, 496=>600, 500=>600, 501=>600, 504=>600, 505=>600, 506=>600, 507=>600, 508=>600, 509=>600, 510=>600, - 511=>600, 512=>600, 513=>600, 514=>600, 515=>600, 516=>600, 517=>600, 518=>600, 519=>600, 520=>600, 521=>600, 522=>600, 523=>600, 524=>600, 525=>600, 526=>600, - 527=>600, 528=>600, 529=>600, 530=>600, 531=>600, 532=>600, 533=>600, 534=>600, 535=>600, 536=>600, 537=>600, 538=>600, 539=>600, 593=>600, 617=>600, 711=>600, - 728=>600, 729=>0, 730=>600, 731=>600, 733=>600, 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 774=>0, 775=>0, 776=>0, 778=>0, 779=>0, 780=>0, - 783=>0, 784=>0, 785=>0, 900=>600, 901=>600, 902=>600, 904=>600, 912=>600, 913=>600, 914=>600, 915=>600, 916=>600, 917=>600, 918=>600, 919=>600, 920=>600, - 921=>600, 922=>600, 923=>600, 924=>600, 925=>600, 926=>600, 927=>600, 928=>600, 929=>600, 931=>600, 932=>600, 933=>600, 934=>600, 935=>600, 936=>600, 937=>600, - 938=>600, 939=>600, 945=>600, 946=>600, 947=>600, 950=>600, 951=>600, 952=>600, 953=>600, 954=>600, 955=>600, 956=>600, 957=>600, 959=>600, 970=>600, 1024=>600, - 1025=>600, 1026=>600, 1028=>600, 1029=>600, 1030=>600, 1031=>600, 1032=>600, 1033=>600, 1034=>600, 1035=>600, 1037=>600, 1038=>600, 1040=>600, 1041=>600, 1042=>600, 1043=>600, - 1044=>600, 1045=>600, 1046=>600, 1047=>600, 1048=>600, 1049=>600, 1050=>600, 1051=>600, 1052=>600, 1053=>600, 1054=>600, 1055=>600, 1056=>600, 1057=>600, 1058=>600, 1059=>600, - 1060=>600, 1061=>600, 1062=>600, 1063=>600, 1064=>600, 1065=>600, 1066=>600, 1067=>600, 1068=>600, 1069=>600, 1070=>600, 1071=>600, 1072=>600, 1073=>600, 1074=>600, 1075=>600, - 1076=>600, 1077=>600, 1078=>600, 1079=>600, 1080=>600, 1081=>600, 1082=>600, 1083=>600, 1084=>600, 1085=>600, 1086=>600, 1087=>600, 1088=>600, 1089=>600, 1090=>600, 1091=>600, - 1092=>600, 1093=>600, 1094=>600, 1095=>600, 1096=>600, 1097=>600, 1098=>600, 1099=>600, 1100=>600, 1101=>600, 1102=>600, 1103=>600, 1104=>600, 1105=>600, 1106=>600, 1107=>600, - 1108=>600, 1109=>600, 1110=>600, 1111=>600, 1112=>600, 1113=>600, 1114=>600, 1115=>600, 1117=>600, 1118=>600, 1119=>600, 1164=>600, 1165=>600, 1166=>600, 1167=>600, 1168=>600, - 1169=>600, 1170=>600, 1171=>600, 1172=>600, 1173=>600, 1174=>600, 1175=>600, 1176=>600, 1177=>600, 1178=>600, 1179=>600, 1180=>600, 1181=>600, 1182=>600, 1183=>600, 1184=>600, - 1185=>600, 1186=>600, 1187=>600, 1188=>600, 1189=>600, 1190=>600, 1191=>600, 1192=>600, 1193=>600, 1194=>600, 1195=>600, 1196=>600, 1197=>600, 1198=>600, 1199=>600, 1200=>600, - 1201=>600, 1202=>600, 1203=>600, 1204=>600, 1205=>600, 1206=>600, 1207=>600, 1208=>600, 1209=>600, 1210=>600, 1211=>600, 1212=>600, 1213=>600, 1214=>600, 1215=>600, 1216=>600, - 1217=>600, 1218=>600, 1219=>600, 1220=>600, 1223=>600, 1224=>600, 1227=>600, 1228=>600, 1232=>600, 1233=>600, 1234=>600, 1235=>600, 1236=>600, 1237=>600, 1238=>600, 1239=>600, - 1240=>600, 1241=>600, 1242=>600, 1243=>600, 1244=>600, 1245=>600, 1246=>600, 1247=>600, 1248=>600, 1249=>600, 1250=>600, 1251=>600, 1252=>600, 1253=>600, 1254=>600, 1255=>600, - 1256=>600, 1257=>600, 1258=>600, 1259=>600, 1260=>600, 1261=>600, 1262=>600, 1263=>600, 1264=>600, 1265=>600, 1266=>600, 1267=>600, 1268=>600, 1269=>600, 1272=>600, 1273=>600, - 1456=>600, 1457=>600, 1458=>600, 1459=>600, 1460=>600, 1461=>600, 1462=>600, 1463=>600, 1464=>600, 1465=>600, 1467=>600, 1468=>600, 1469=>600, 1470=>600, 1471=>600, 1472=>600, - 1473=>600, 1474=>600, 1475=>600, 1476=>600, 1488=>600, 1489=>600, 1490=>600, 1491=>600, 1492=>600, 1493=>600, 1494=>600, 1495=>600, 1496=>600, 1497=>600, 1498=>600, 1499=>600, - 1500=>600, 1501=>600, 1502=>600, 1503=>600, 1504=>600, 1505=>600, 1506=>600, 1507=>600, 1508=>600, 1509=>600, 1510=>600, 1511=>600, 1512=>600, 1513=>600, 1514=>600, 1520=>600, - 1521=>600, 1522=>600, 1523=>600, 1524=>600, 8213=>600, 8260=>600, 8304=>600, 8305=>600, 8306=>600, 8307=>600, 8308=>600, 8309=>600, 8310=>600, 8311=>600, 8312=>600, 8313=>600, - 8320=>600, 8321=>600, 8322=>600, 8323=>600, 8324=>600, 8325=>600, 8326=>600, 8327=>600, 8328=>600, 8329=>600, 8362=>600, 8470=>600, 8486=>600, 8531=>600, 8532=>600, 8533=>600, - 8534=>600, 8535=>600, 8536=>600, 8537=>600, 8538=>600, 8539=>600, 8540=>600, 8541=>600, 8542=>600, 8543=>600, 8592=>600, 8593=>600, 8594=>600, 8595=>600, 8706=>600, 8710=>600, - 8721=>600, 8722=>600, 8730=>600, 8734=>600, 8800=>600, 8804=>600, 8805=>600, 9674=>600, 9833=>600, 9834=>600, 9835=>600, 9836=>600, 63166=>600, 63171=>600, 64257=>600, 64258=>600} - font[:enc]=''; - font[:diff]=''; - font[:file]='FreeMonoBoldOblique.z'; - font[:ctg]='FreeMonoBoldOblique.ctg.z'; - font[:originalsize]=128384; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/freemonoi.rb --- a/vendor/plugins/rfpdf/lib/fonts/freemonoi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -TCPDFFontDescriptor.define('freemonoi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='FreeMonoOblique'; - font[:desc]={'Ascent'=>1000,'Descent'=>-273,'CapHeight'=>1000,'Flags'=>96,'FontBBox'=>'[-577 -273 779 1000]','ItalicAngle'=>-12,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-100; - font[:ut]=50; - font[:cw]={ - 13=>333, 32=>600, 33=>600, 34=>600, 35=>600, 36=>600, 37=>600, 38=>600, 39=>600, 40=>600, 41=>600, 42=>600, 43=>600, 44=>600, 45=>600, 46=>600, - 47=>600, 48=>600, 49=>600, 50=>600, 51=>600, 52=>600, 53=>600, 54=>600, 55=>600, 56=>600, 57=>600, 58=>600, 59=>600, 60=>600, 61=>600, 62=>600, - 63=>600, 64=>600, 65=>600, 66=>600, 67=>600, 68=>600, 69=>600, 70=>600, 71=>600, 72=>600, 73=>600, 74=>600, 75=>600, 76=>600, 77=>600, 78=>600, - 79=>600, 80=>600, 81=>600, 82=>600, 83=>600, 84=>600, 85=>600, 86=>600, 87=>600, 88=>600, 89=>600, 90=>600, 91=>600, 92=>600, 93=>600, 94=>600, - 95=>600, 96=>600, 97=>600, 98=>600, 99=>600, 100=>600, 101=>600, 102=>600, 103=>600, 104=>600, 105=>600, 106=>600, 107=>600, 108=>600, 109=>600, 110=>600, - 111=>600, 112=>600, 113=>600, 114=>600, 115=>600, 116=>600, 117=>600, 118=>600, 119=>600, 120=>600, 121=>600, 122=>600, 123=>600, 124=>600, 125=>600, 126=>600, - 8364=>600, 1027=>600, 8218=>600, 402=>600, 8222=>600, 8230=>600, 8224=>600, 8225=>600, 710=>600, 8240=>600, 352=>600, 8249=>600, 338=>600, 1036=>600, 381=>600, 1039=>600, - 8216=>600, 8217=>600, 8220=>600, 8221=>600, 8226=>600, 8211=>600, 8212=>600, 732=>600, 8482=>600, 353=>600, 8250=>600, 339=>600, 1116=>600, 382=>600, 376=>600, 160=>600, - 161=>600, 162=>600, 163=>600, 164=>600, 165=>600, 166=>600, 167=>600, 168=>600, 169=>600, 170=>600, 171=>600, 172=>600, 173=>600, 174=>600, 175=>600, 176=>600, - 177=>600, 178=>600, 179=>600, 180=>600, 181=>600, 182=>600, 183=>600, 184=>600, 185=>600, 186=>600, 187=>600, 188=>600, 189=>600, 190=>600, 191=>600, 192=>600, - 193=>600, 194=>600, 195=>600, 196=>600, 197=>600, 198=>600, 199=>600, 200=>600, 201=>600, 202=>600, 203=>600, 204=>600, 205=>600, 206=>600, 207=>600, 208=>600, - 209=>600, 210=>600, 211=>600, 212=>600, 213=>600, 214=>600, 215=>600, 216=>600, 217=>600, 218=>600, 219=>600, 220=>600, 221=>600, 222=>600, 223=>600, 224=>600, - 225=>600, 226=>600, 227=>600, 228=>600, 229=>600, 230=>600, 231=>600, 232=>600, 233=>600, 234=>600, 235=>600, 236=>600, 237=>600, 238=>600, 239=>600, 240=>600, - 241=>600, 242=>600, 243=>600, 244=>600, 245=>600, 246=>600, 247=>600, 248=>600, 249=>600, 250=>600, 251=>600, 252=>600, 253=>600, 254=>600, 255=>600, 256=>600, - 257=>600, 258=>600, 259=>600, 260=>600, 261=>600, 262=>600, 263=>600, 264=>600, 265=>600, 266=>600, 267=>600, 268=>600, 269=>600, 270=>600, 271=>600, 272=>600, - 273=>600, 274=>600, 275=>600, 276=>600, 277=>600, 278=>600, 279=>600, 280=>600, 281=>600, 282=>600, 283=>600, 284=>600, 285=>600, 286=>600, 287=>600, 288=>600, - 289=>600, 290=>600, 291=>600, 292=>600, 293=>600, 294=>600, 295=>600, 296=>600, 297=>600, 298=>600, 299=>600, 300=>600, 301=>600, 302=>600, 303=>600, 304=>600, - 305=>600, 306=>600, 307=>600, 308=>600, 309=>600, 310=>600, 311=>600, 312=>600, 313=>600, 314=>600, 315=>600, 316=>600, 317=>600, 318=>600, 319=>600, 320=>600, - 321=>600, 322=>600, 323=>600, 324=>600, 325=>600, 326=>600, 327=>600, 328=>600, 329=>600, 330=>600, 331=>600, 332=>600, 333=>600, 334=>600, 335=>600, 336=>600, - 337=>600, 340=>600, 341=>600, 342=>600, 343=>600, 344=>600, 345=>600, 346=>600, 347=>600, 348=>600, 349=>600, 350=>600, 351=>600, 354=>600, 355=>600, 356=>600, - 357=>600, 358=>600, 359=>600, 360=>600, 361=>600, 362=>600, 363=>600, 364=>600, 365=>600, 366=>600, 367=>600, 368=>600, 369=>600, 370=>600, 371=>600, 372=>600, - 373=>600, 374=>600, 375=>600, 377=>600, 378=>600, 379=>600, 380=>600, 383=>600, 384=>600, 385=>600, 386=>600, 387=>600, 388=>600, 389=>600, 390=>600, 391=>600, - 392=>600, 393=>600, 394=>600, 395=>600, 396=>600, 397=>600, 398=>600, 399=>600, 400=>600, 401=>600, 403=>600, 404=>600, 405=>600, 406=>600, 407=>600, 408=>600, - 409=>600, 410=>600, 411=>600, 412=>600, 413=>600, 414=>600, 415=>600, 416=>600, 417=>600, 418=>600, 419=>600, 420=>600, 421=>600, 422=>600, 423=>600, 424=>600, - 425=>600, 426=>600, 427=>600, 428=>600, 429=>600, 430=>600, 431=>600, 432=>600, 433=>600, 434=>600, 435=>600, 436=>600, 437=>600, 438=>600, 439=>600, 440=>600, - 441=>600, 442=>600, 443=>600, 444=>600, 445=>600, 446=>600, 448=>600, 449=>600, 450=>600, 451=>600, 452=>600, 453=>600, 454=>600, 455=>600, 456=>600, 457=>600, - 458=>600, 459=>600, 460=>600, 461=>600, 462=>600, 463=>600, 464=>600, 465=>600, 466=>600, 467=>600, 468=>600, 469=>600, 470=>600, 471=>600, 472=>600, 473=>600, - 474=>600, 475=>600, 476=>600, 477=>600, 478=>600, 479=>600, 480=>600, 481=>600, 482=>600, 483=>600, 484=>600, 485=>600, 486=>600, 487=>600, 488=>600, 489=>600, - 490=>600, 491=>600, 492=>600, 493=>600, 494=>600, 495=>600, 496=>600, 497=>600, 498=>600, 499=>600, 500=>600, 501=>600, 502=>600, 504=>600, 505=>600, 506=>600, - 507=>600, 508=>600, 509=>600, 510=>600, 511=>600, 512=>600, 513=>600, 514=>600, 515=>600, 516=>600, 517=>600, 518=>600, 519=>600, 520=>600, 521=>600, 522=>600, - 523=>600, 524=>600, 525=>600, 526=>600, 527=>600, 528=>600, 529=>600, 530=>600, 531=>600, 532=>600, 533=>600, 534=>600, 535=>600, 536=>600, 537=>600, 538=>600, - 539=>600, 542=>600, 543=>600, 548=>600, 549=>600, 550=>600, 551=>600, 552=>600, 553=>600, 554=>600, 555=>600, 556=>600, 557=>600, 558=>600, 559=>600, 560=>600, - 561=>600, 562=>600, 563=>600, 592=>600, 593=>600, 594=>600, 595=>600, 596=>600, 597=>600, 598=>600, 599=>600, 600=>600, 601=>600, 602=>600, 603=>600, 604=>600, - 605=>600, 606=>600, 607=>600, 608=>600, 609=>600, 610=>600, 611=>600, 612=>600, 613=>600, 614=>600, 615=>600, 616=>600, 617=>600, 618=>600, 619=>600, 620=>600, - 621=>600, 622=>600, 623=>600, 624=>600, 625=>600, 626=>600, 627=>600, 628=>600, 629=>600, 630=>600, 631=>600, 632=>600, 633=>600, 634=>600, 635=>600, 636=>600, - 637=>600, 638=>600, 639=>600, 640=>600, 641=>600, 642=>600, 643=>600, 644=>600, 645=>600, 646=>600, 647=>600, 648=>600, 649=>600, 650=>600, 651=>600, 652=>600, - 653=>600, 654=>600, 655=>600, 656=>600, 657=>600, 658=>600, 659=>600, 660=>600, 661=>600, 662=>600, 663=>600, 664=>600, 665=>600, 666=>600, 667=>600, 668=>600, - 669=>600, 670=>600, 671=>600, 672=>600, 673=>600, 674=>600, 711=>600, 712=>600, 713=>600, 714=>600, 715=>600, 728=>600, 729=>600, 730=>600, 731=>600, 733=>600, - 768=>0, 769=>0, 770=>0, 771=>0, 772=>0, 773=>0, 774=>0, 775=>0, 776=>0, 777=>0, 778=>0, 779=>0, 780=>0, 781=>0, 782=>0, 783=>0, - 807=>0, 808=>0, 821=>0, 822=>0, 823=>0, 824=>0, 901=>600, 902=>600, 904=>600, 905=>600, 906=>600, 908=>600, 910=>600, 911=>600, 912=>600, 913=>600, - 914=>600, 915=>600, 916=>600, 917=>600, 918=>600, 919=>600, 920=>600, 921=>600, 922=>600, 923=>600, 924=>600, 925=>600, 926=>600, 927=>600, 928=>600, 929=>600, - 931=>600, 932=>600, 933=>600, 934=>600, 935=>600, 936=>600, 937=>600, 938=>600, 939=>600, 940=>600, 941=>600, 942=>600, 943=>600, 944=>600, 945=>600, 946=>600, - 947=>600, 948=>600, 949=>600, 950=>600, 951=>600, 952=>600, 953=>600, 954=>600, 955=>600, 956=>600, 957=>600, 958=>600, 959=>600, 960=>600, 961=>600, 962=>600, - 963=>600, 964=>600, 965=>600, 966=>600, 967=>600, 968=>600, 969=>600, 970=>600, 971=>600, 972=>600, 973=>600, 974=>600, 1024=>600, 1025=>600, 1026=>600, 1028=>600, - 1029=>600, 1030=>600, 1031=>600, 1032=>600, 1033=>600, 1034=>600, 1035=>600, 1037=>600, 1038=>600, 1040=>600, 1041=>600, 1042=>600, 1043=>600, 1044=>600, 1045=>600, 1046=>600, - 1047=>600, 1048=>600, 1049=>600, 1050=>600, 1051=>600, 1052=>600, 1053=>600, 1054=>600, 1055=>600, 1056=>600, 1057=>600, 1058=>600, 1059=>600, 1060=>600, 1061=>600, 1062=>600, - 1063=>600, 1064=>600, 1065=>600, 1066=>600, 1067=>600, 1068=>600, 1069=>600, 1070=>600, 1071=>600, 1072=>600, 1073=>600, 1074=>600, 1075=>600, 1076=>600, 1077=>600, 1078=>600, - 1079=>600, 1080=>600, 1081=>600, 1082=>600, 1083=>600, 1084=>600, 1085=>600, 1086=>600, 1087=>600, 1088=>600, 1089=>600, 1090=>600, 1091=>600, 1092=>600, 1093=>600, 1094=>600, - 1095=>600, 1096=>600, 1097=>600, 1098=>600, 1099=>600, 1100=>600, 1101=>600, 1102=>600, 1103=>600, 1104=>600, 1105=>600, 1106=>600, 1107=>600, 1108=>600, 1109=>600, 1110=>600, - 1111=>600, 1112=>600, 1113=>600, 1114=>600, 1115=>600, 1117=>600, 1118=>600, 1119=>600, 1164=>600, 1165=>600, 1166=>600, 1167=>600, 1168=>600, 1169=>600, 1170=>600, 1171=>600, - 1172=>600, 1173=>600, 1174=>600, 1175=>600, 1176=>600, 1177=>600, 1178=>600, 1179=>600, 1180=>600, 1181=>600, 1182=>600, 1183=>600, 1184=>600, 1185=>600, 1186=>600, 1187=>600, - 1188=>600, 1189=>600, 1190=>600, 1191=>600, 1192=>600, 1193=>600, 1194=>600, 1195=>600, 1196=>600, 1197=>600, 1198=>600, 1199=>600, 1200=>600, 1201=>600, 1202=>600, 1203=>600, - 1204=>600, 1205=>600, 1206=>600, 1207=>600, 1208=>600, 1209=>600, 1210=>600, 1211=>600, 1212=>600, 1213=>600, 1214=>600, 1215=>600, 1216=>600, 1217=>600, 1218=>600, 1219=>600, - 1220=>600, 1223=>600, 1224=>600, 1227=>600, 1228=>600, 1232=>600, 1233=>600, 1234=>600, 1235=>600, 1236=>600, 1237=>600, 1238=>600, 1239=>600, 1240=>600, 1241=>600, 1242=>600, - 1243=>600, 1244=>600, 1245=>600, 1246=>600, 1247=>600, 1248=>600, 1249=>600, 1250=>600, 1251=>600, 1252=>600, 1253=>600, 1254=>600, 1255=>600, 1256=>600, 1257=>600, 1258=>600, - 1259=>600, 1260=>600, 1261=>600, 1262=>600, 1263=>600, 1264=>600, 1265=>600, 1266=>600, 1267=>600, 1268=>600, 1269=>600, 1272=>600, 1273=>600, 1328=>600, 1329=>600, 1330=>600, - 1331=>600, 1332=>600, 1333=>600, 1334=>600, 1335=>600, 1336=>600, 1337=>600, 1338=>600, 1339=>600, 1340=>600, 1341=>600, 1342=>600, 1343=>600, 1344=>600, 1345=>600, 1346=>600, - 1347=>600, 1348=>600, 1349=>600, 1350=>600, 1351=>600, 1352=>600, 1353=>600, 1354=>600, 1355=>600, 1356=>600, 1357=>600, 1358=>600, 1359=>600, 1360=>600, 1361=>600, 1362=>600, - 1363=>600, 1364=>600, 1365=>600, 1366=>600, 1367=>600, 1368=>600, 1369=>600, 1370=>600, 1371=>600, 1372=>600, 1373=>600, 1374=>600, 1375=>600, 1376=>600, 1377=>600, 1378=>600, - 1379=>600, 1380=>600, 1381=>600, 1382=>600, 1383=>600, 1384=>600, 1385=>600, 1386=>600, 1387=>600, 1388=>600, 1389=>600, 1390=>600, 1391=>600, 1392=>600, 1393=>600, 1394=>600, - 1395=>600, 1396=>600, 1397=>600, 1398=>600, 1399=>600, 1400=>600, 1401=>600, 1402=>600, 1403=>600, 1404=>600, 1405=>600, 1406=>600, 1407=>600, 1408=>600, 1409=>600, 1410=>600, - 1411=>600, 1412=>600, 1413=>600, 1414=>600, 1415=>600, 1416=>600, 1417=>600, 1418=>600, 1456=>600, 1457=>600, 1458=>600, 1459=>600, 1460=>600, 1461=>600, 1462=>600, 1463=>600, - 1464=>600, 1465=>600, 1467=>600, 1468=>600, 1469=>600, 1470=>600, 1471=>600, 1472=>600, 1473=>600, 1474=>600, 1475=>600, 1476=>600, 1488=>600, 1489=>600, 1490=>600, 1491=>600, - 1492=>600, 1493=>600, 1494=>600, 1495=>600, 1496=>600, 1497=>600, 1498=>600, 1499=>600, 1500=>600, 1501=>600, 1502=>600, 1503=>600, 1504=>600, 1505=>600, 1506=>600, 1507=>600, - 1508=>600, 1509=>600, 1510=>600, 1511=>600, 1512=>600, 1513=>600, 1514=>600, 1520=>600, 1521=>600, 1522=>600, 1523=>600, 1524=>600, 8213=>600, 8241=>600, 8242=>600, 8243=>600, - 8244=>600, 8245=>600, 8246=>600, 8247=>600, 8252=>600, 8253=>600, 8260=>600, 8261=>600, 8262=>600, 8263=>600, 8264=>600, 8265=>600, 8304=>600, 8305=>600, 8306=>600, 8307=>600, - 8308=>600, 8309=>600, 8310=>600, 8311=>600, 8312=>600, 8313=>600, 8314=>600, 8315=>600, 8316=>600, 8317=>600, 8318=>600, 8319=>600, 8320=>600, 8321=>600, 8322=>600, 8323=>600, - 8324=>600, 8325=>600, 8326=>600, 8327=>600, 8328=>600, 8329=>600, 8356=>600, 8362=>600, 8448=>600, 8449=>600, 8450=>600, 8451=>600, 8452=>600, 8453=>600, 8454=>600, 8455=>600, - 8456=>600, 8457=>600, 8458=>600, 8459=>600, 8460=>600, 8461=>600, 8462=>600, 8463=>600, 8464=>600, 8465=>600, 8466=>600, 8467=>600, 8468=>600, 8469=>600, 8470=>600, 8471=>600, - 8472=>600, 8473=>600, 8474=>600, 8475=>600, 8476=>600, 8477=>600, 8478=>600, 8479=>600, 8484=>600, 8486=>600, 8487=>600, 8490=>600, 8491=>600, 8531=>600, 8532=>600, 8533=>600, - 8534=>600, 8535=>600, 8536=>600, 8537=>600, 8538=>600, 8539=>600, 8540=>600, 8541=>600, 8542=>600, 8543=>600, 8592=>600, 8593=>600, 8594=>600, 8595=>600, 8596=>600, 8597=>600, - 8598=>600, 8599=>600, 8600=>600, 8601=>600, 8616=>600, 8706=>600, 8710=>600, 8721=>600, 8722=>600, 8730=>600, 8734=>600, 8800=>600, 8804=>600, 8805=>600, 9674=>600, 9833=>600, - 9834=>600, 9835=>600, 9836=>600, 9837=>600, 9838=>600, 9839=>600, 63171=>600, 64257=>600, 64258=>600, 64285=>600, 64286=>600, 64287=>600, 64288=>600, 64289=>600, 64290=>600, 64291=>600, - 64292=>600, 64293=>600, 64294=>600, 64295=>600, 64296=>600, 64297=>600, 64298=>600, 64299=>600, 64300=>600, 64301=>600, 64302=>600, 64303=>600, 64304=>600, 64305=>600, 64306=>600, 64307=>600, - 64308=>600, 64309=>600, 64310=>600, 64312=>600, 64313=>600, 64314=>600, 64315=>600, 64316=>600, 64318=>600, 64320=>600, 64321=>600, 64323=>600, 64324=>600, 64326=>600, 64327=>600, 64328=>600, - 64329=>600, 64330=>600, 64331=>600, 64332=>600, 64333=>600, 64334=>600, 64335=>600} - font[:enc]=''; - font[:diff]=''; - font[:file]='FreeMonoOblique.z'; - font[:ctg]='FreeMonoOblique.ctg.z'; - font[:originalsize]=175484; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/sjis.rb --- a/vendor/plugins/rfpdf/lib/fonts/sjis.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,834 +0,0 @@ -TCPDFFontDescriptor.define('sjis') do |font| - font[:type]='Type0'; - font[:name]='KozMinPro-Regular-Acro'; - font[:desc]={'Ascent'=>995,'Descent'=>-203,'CapHeight'=>6,'Flags'=>32,'FontBBox'=>'[-50 -203 1041 995]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>1000} - font[:up]=-120; - font[:ut]=40 - font[:cMap]='90msp-RKSJ-H' - font[:cw]={ - 0=>1000, 32=>500, 33=>500, 34=>500, 35=>500, 36=>500, 37=>500, 38=>500, 39=>500, 40=>500, 41=>500, 42=>500, 43=>500, 44=>500, 45=>500, 46=>500, - 47=>500, 48=>500, 49=>500, 50=>500, 51=>500, 52=>500, 53=>500, 54=>500, 55=>500, 56=>500, 57=>500, 58=>500, 59=>500, 60=>500, 61=>500, 62=>500, - 63=>500, 64=>500, 65=>500, 66=>500, 67=>500, 68=>500, 69=>500, 70=>500, 71=>500, 72=>500, 73=>500, 74=>500, 75=>500, 76=>500, 77=>500, 78=>500, - 79=>500, 80=>500, 81=>500, 82=>500, 83=>500, 84=>500, 85=>500, 86=>500, 87=>500, 88=>500, 89=>500, 90=>500, 91=>500, 92=>500, 93=>500, 94=>500, - 95=>500, 96=>500, 97=>500, 98=>500, 99=>500, 100=>500, 101=>500, 102=>500, 103=>500, 104=>500, 105=>500, 106=>500, 107=>500, 108=>500, 109=>500, 110=>500, - 111=>500, 112=>500, 113=>500, 114=>500, 115=>500, 116=>500, 117=>500, 118=>500, 119=>500, 120=>500, 121=>500, 122=>500, 123=>500, 124=>500, 125=>500, 126=>500, - 8364=>1000, 402=>500, 8230=>1000, 8224=>1000, 8225=>1000, 710=>500, 8240=>1000, 338=>875, 8216=>1000, 8217=>1000, 8220=>1000, 8221=>1000, 732=>500, 339=>875, 160=>446, 161=>500, - 162=>500, 163=>500, 164=>1000, 165=>500, 166=>500, 167=>1000, 168=>1000, 169=>500, 170=>500, 171=>500, 172=>490, 173=>500, 174=>500, 175=>500, 176=>1000, 177=>1000, - 178=>500, 179=>500, 180=>1000, 181=>500, 182=>1000, 183=>500, 184=>500, 185=>500, 186=>500, 187=>500, 188=>500, 189=>500, 190=>500, 191=>500, 192=>500, 193=>500, - 194=>500, 195=>500, 196=>500, 197=>500, 198=>875, 199=>500, 200=>500, 201=>500, 202=>500, 203=>500, 204=>500, 205=>500, 206=>500, 207=>500, 208=>500, 209=>500, - 210=>500, 211=>500, 212=>500, 213=>500, 214=>500, 215=>1000, 216=>500, 217=>500, 218=>500, 219=>500, 220=>500, 221=>500, 222=>500, 223=>500, 224=>500, 225=>500, - 226=>500, 227=>500, 228=>500, 229=>500, 230=>813, 231=>500, 232=>500, 233=>500, 234=>500, 235=>500, 236=>500, 237=>500, 238=>500, 239=>500, 240=>500, 241=>500, - 242=>500, 243=>500, 244=>500, 245=>500, 246=>500, 247=>1000, 248=>500, 249=>500, 250=>500, 251=>500, 252=>500, 253=>500, 254=>500, 255=>500, 305=>500, 321=>500, - 322=>500, 331=>500, 593=>500, 602=>500, 658=>500, 711=>500, 714=>500, 715=>500, 728=>500, 730=>500, 913=>1000, 914=>1000, 915=>1000, 916=>1000, 917=>1000, 918=>1000, - 919=>1000, 920=>1000, 921=>1000, 922=>1000, 923=>1000, 924=>1000, 925=>1000, 926=>1000, 927=>1000, 928=>1000, 929=>1000, 931=>1000, 932=>1000, 933=>1000, 934=>1000, 935=>1000, - 936=>1000, 937=>1000, 945=>1000, 946=>1000, 947=>1000, 948=>1000, 949=>1000, 950=>1000, 951=>1000, 952=>1000, 953=>1000, 954=>1000, 955=>1000, 956=>1000, 957=>1000, 958=>1000, - 959=>1000, 960=>1000, 961=>1000, 962=>1000, 963=>1000, 964=>1000, 965=>1000, 966=>1000, 967=>1000, 968=>1000, 969=>1000, 977=>1000, 981=>1000, 1025=>1000, 1040=>1000, 1041=>1000, - 1042=>1000, 1043=>1000, 1044=>1000, 1045=>1000, 1046=>1000, 1047=>1000, 1048=>1000, 1049=>1000, 1050=>1000, 1051=>1000, 1052=>1000, 1053=>1000, 1054=>1000, 1055=>1000, 1056=>1000, 1057=>1000, - 1058=>1000, 1059=>1000, 1060=>1000, 1061=>1000, 1062=>1000, 1063=>1000, 1064=>1000, 1065=>1000, 1066=>1000, 1067=>1000, 1068=>1000, 1069=>1000, 1070=>1000, 1071=>1000, 1072=>1000, 1073=>1000, - 1074=>1000, 1075=>1000, 1076=>1000, 1077=>1000, 1078=>1000, 1079=>1000, 1080=>1000, 1081=>1000, 1082=>1000, 1083=>1000, 1084=>1000, 1085=>1000, 1086=>1000, 1087=>1000, 1088=>1000, 1089=>1000, - 1090=>1000, 1091=>1000, 1092=>1000, 1093=>1000, 1094=>1000, 1095=>1000, 1096=>1000, 1097=>1000, 1098=>1000, 1099=>1000, 1100=>1000, 1101=>1000, 1102=>1000, 1103=>1000, 1105=>1000, 8195=>915, - 8208=>1000, 8213=>1000, 8214=>915, 8215=>500, 8229=>1000, 8242=>1000, 8243=>1000, 8251=>1000, 8254=>766, 8451=>1000, 8467=>1000, 8470=>915, 8481=>1000, 8491=>1000, 8544=>915, 8545=>915, - 8546=>915, 8547=>915, 8548=>915, 8549=>915, 8550=>915, 8551=>915, 8552=>915, 8553=>915, 8592=>1000, 8593=>1000, 8594=>1000, 8595=>1000, 8658=>1000, 8660=>1000, 8704=>1000, 8706=>1000, - 8707=>1000, 8711=>1000, 8712=>1000, 8715=>1000, 8722=>915, 8730=>1000, 8733=>1000, 8734=>1000, 8735=>915, 8736=>1000, 8741=>1000, 8743=>1000, 8744=>1000, 8745=>1000, 8746=>1000, 8747=>1000, - 8748=>1000, 8749=>1000, 8750=>915, 8756=>1000, 8757=>1000, 8765=>1000, 8771=>1000, 8786=>1000, 8800=>1000, 8801=>1000, 8806=>1000, 8807=>1000, 8810=>1000, 8811=>1000, 8818=>977, 8819=>977, - 8834=>1000, 8835=>1000, 8838=>1000, 8839=>1000, 8869=>1000, 8895=>915, 8978=>1000, 9312=>1000, 9313=>1000, 9314=>1000, 9315=>1000, 9316=>1000, 9317=>1000, 9318=>1000, 9319=>1000, 9320=>1000, - 9321=>1000, 9322=>1000, 9323=>1000, 9324=>1000, 9325=>1000, 9326=>1000, 9327=>1000, 9328=>1000, 9329=>1000, 9330=>1000, 9331=>1000, 9472=>1000, 9473=>1000, 9474=>1000, 9475=>1000, 9484=>1000, - 9487=>1000, 9488=>1000, 9491=>1000, 9492=>1000, 9495=>1000, 9496=>1000, 9499=>1000, 9500=>1000, 9501=>1000, 9504=>1000, 9507=>1000, 9508=>1000, 9509=>1000, 9512=>1000, 9515=>1000, 9516=>1000, - 9519=>1000, 9520=>1000, 9523=>1000, 9524=>1000, 9527=>1000, 9528=>1000, 9531=>1000, 9532=>1000, 9535=>1000, 9538=>1000, 9547=>1000, 9632=>1000, 9633=>1000, 9634=>977, 9650=>1000, 9651=>1000, - 9660=>1000, 9661=>1000, 9670=>1000, 9671=>1000, 9675=>1000, 9678=>1000, 9679=>1000, 9711=>1000, 9733=>1000, 9734=>1000, 9792=>1000, 9794=>1000, 9825=>977, 9826=>977, 9828=>977, 9831=>977, - 9834=>1000, 9837=>1000, 9839=>1000, 12288=>1000, 12289=>1000, 12290=>1000, 12291=>1000, 12293=>1000, 12294=>1000, 12295=>1000, 12296=>1000, 12297=>1000, 12298=>1000, 12299=>1000, 12300=>1000, 12301=>1000, - 12302=>1000, 12303=>1000, 12304=>1000, 12305=>1000, 12306=>1000, 12307=>1000, 12308=>1000, 12309=>1000, 12316=>1000, 12339=>1000, 12340=>1000, 12341=>1000, 12353=>1000, 12354=>1000, 12355=>1000, 12356=>1000, - 12357=>1000, 12358=>1000, 12359=>1000, 12360=>1000, 12361=>1000, 12362=>1000, 12363=>1000, 12364=>1000, 12365=>1000, 12366=>1000, 12367=>1000, 12368=>1000, 12369=>1000, 12370=>1000, 12371=>1000, 12372=>1000, - 12373=>1000, 12374=>1000, 12375=>1000, 12376=>1000, 12377=>1000, 12378=>1000, 12379=>1000, 12380=>1000, 12381=>1000, 12382=>1000, 12383=>1000, 12384=>1000, 12385=>1000, 12386=>1000, 12387=>1000, 12388=>1000, - 12389=>1000, 12390=>1000, 12391=>1000, 12392=>1000, 12393=>1000, 12394=>1000, 12395=>1000, 12396=>1000, 12397=>1000, 12398=>1000, 12399=>1000, 12400=>1000, 12401=>1000, 12402=>1000, 12403=>1000, 12404=>1000, - 12405=>1000, 12406=>1000, 12407=>1000, 12408=>1000, 12409=>1000, 12410=>1000, 12411=>1000, 12412=>1000, 12413=>1000, 12414=>1000, 12415=>1000, 12416=>1000, 12417=>1000, 12418=>1000, 12419=>1000, 12420=>1000, - 12421=>1000, 12422=>1000, 12423=>1000, 12424=>1000, 12425=>1000, 12426=>1000, 12427=>1000, 12428=>1000, 12429=>1000, 12430=>1000, 12431=>1000, 12432=>1000, 12433=>1000, 12434=>1000, 12435=>1000, 12436=>1000, - 12437=>1000, 12438=>1000, 12443=>1000, 12444=>1000, 12445=>1000, 12446=>1000, 12449=>1000, 12450=>1000, 12451=>1000, 12452=>1000, 12453=>1000, 12454=>1000, 12455=>1000, 12456=>1000, 12457=>1000, 12458=>1000, - 12459=>1000, 12460=>1000, 12461=>1000, 12462=>1000, 12463=>1000, 12464=>1000, 12465=>1000, 12466=>1000, 12467=>1000, 12468=>1000, 12469=>1000, 12470=>1000, 12471=>1000, 12472=>1000, 12473=>1000, 12474=>1000, - 12475=>1000, 12476=>1000, 12477=>1000, 12478=>1000, 12479=>1000, 12480=>1000, 12481=>1000, 12482=>1000, 12483=>1000, 12484=>1000, 12485=>1000, 12486=>1000, 12487=>1000, 12488=>1000, 12489=>1000, 12490=>1000, - 12491=>1000, 12492=>1000, 12493=>1000, 12494=>1000, 12495=>1000, 12496=>1000, 12497=>1000, 12498=>1000, 12499=>1000, 12500=>1000, 12501=>1000, 12502=>1000, 12503=>1000, 12504=>1000, 12505=>1000, 12506=>1000, - 12507=>1000, 12508=>1000, 12509=>1000, 12510=>1000, 12511=>1000, 12512=>1000, 12513=>1000, 12514=>1000, 12515=>1000, 12516=>1000, 12517=>1000, 12518=>1000, 12519=>1000, 12520=>1000, 12521=>1000, 12522=>1000, - 12523=>1000, 12524=>1000, 12525=>1000, 12526=>1000, 12527=>1000, 12528=>1000, 12529=>1000, 12530=>1000, 12531=>1000, 12532=>1000, 12533=>1000, 12534=>1000, 12535=>1000, 12536=>1000, 12537=>1000, 12538=>1000, - 12539=>1000, 12540=>1000, 12541=>1000, 12542=>1000, 12849=>1000, 12850=>915, 12857=>915, 12964=>915, 12965=>915, 12966=>915, 12967=>915, 12968=>915, 13059=>915, 13069=>915, 13076=>915, 13080=>915, - 13090=>915, 13091=>915, 13094=>915, 13095=>915, 13099=>915, 13110=>915, 13115=>915, 13129=>915, 13130=>915, 13133=>915, 13137=>915, 13143=>915, 13179=>915, 13180=>915, 13181=>915, 13182=>915, - 13198=>915, 13199=>915, 13212=>915, 13213=>915, 13214=>915, 13217=>915, 13252=>915, 13259=>1000, 13261=>915, 19968=>1000, 19969=>1000, 19970=>1000, 19971=>1000, 19972=>1000, 19973=>1000, 19975=>1000, - 19976=>1000, 19977=>1000, 19978=>1000, 19979=>1000, 19980=>1000, 19981=>1000, 19982=>1000, 19984=>1000, 19985=>1000, 19986=>1000, 19988=>1000, 19989=>1000, 19990=>1000, 19991=>1000, 19992=>1000, 19993=>1000, - 19998=>1000, 19999=>1000, 20001=>1000, 20003=>1000, 20004=>1000, 20006=>1000, 20008=>1000, 20010=>1000, 20011=>1000, 20013=>1000, 20014=>1000, 20015=>1000, 20016=>1000, 20017=>1000, 20018=>1000, 20021=>1000, - 20022=>1000, 20024=>1000, 20025=>1000, 20027=>1000, 20028=>1000, 20031=>1000, 20032=>1000, 20033=>1000, 20034=>1000, 20035=>1000, 20036=>1000, 20037=>1000, 20039=>1000, 20043=>1000, 20045=>1000, 20046=>1000, - 20047=>1000, 20049=>1000, 20053=>1000, 20054=>1000, 20055=>1000, 20056=>1000, 20057=>1000, 20058=>1000, 20060=>1000, 20061=>1000, 20062=>1000, 20063=>1000, 20066=>1000, 20067=>1000, 20072=>1000, 20073=>1000, - 20081=>1000, 20083=>1000, 20084=>1000, 20085=>1000, 20089=>1000, 20094=>1000, 20095=>1000, 20096=>1000, 20098=>1000, 20101=>1000, 20102=>1000, 20104=>1000, 20105=>1000, 20106=>1000, 20107=>1000, 20108=>1000, - 20109=>1000, 20110=>1000, 20113=>1000, 20114=>1000, 20116=>1000, 20117=>1000, 20118=>1000, 20119=>1000, 20120=>1000, 20121=>1000, 20123=>1000, 20124=>1000, 20125=>1000, 20126=>1000, 20127=>1000, 20128=>1000, - 20129=>1000, 20130=>1000, 20132=>1000, 20133=>1000, 20134=>1000, 20136=>1000, 20139=>1000, 20140=>1000, 20141=>1000, 20142=>1000, 20143=>1000, 20144=>1000, 20147=>1000, 20150=>1000, 20153=>1000, 20154=>1000, - 20160=>1000, 20161=>1000, 20162=>1000, 20163=>1000, 20164=>1000, 20166=>1000, 20167=>1000, 20170=>1000, 20171=>1000, 20173=>1000, 20174=>1000, 20175=>1000, 20176=>1000, 20180=>1000, 20181=>1000, 20182=>1000, - 20183=>1000, 20184=>1000, 20185=>1000, 20186=>1000, 20187=>1000, 20189=>1000, 20190=>1000, 20191=>1000, 20192=>1000, 20193=>1000, 20194=>1000, 20195=>1000, 20196=>1000, 20197=>1000, 20200=>1000, 20205=>1000, - 20206=>1000, 20207=>1000, 20208=>1000, 20209=>1000, 20210=>1000, 20211=>1000, 20213=>1000, 20214=>1000, 20215=>1000, 20219=>1000, 20220=>1000, 20221=>1000, 20222=>1000, 20223=>1000, 20224=>1000, 20225=>1000, - 20226=>1000, 20227=>1000, 20232=>1000, 20233=>1000, 20234=>1000, 20235=>1000, 20236=>1000, 20237=>1000, 20238=>1000, 20239=>1000, 20240=>1000, 20241=>1000, 20242=>1000, 20245=>1000, 20246=>1000, 20247=>1000, - 20249=>1000, 20250=>1000, 20252=>1000, 20253=>1000, 20270=>1000, 20271=>1000, 20272=>1000, 20273=>1000, 20275=>1000, 20276=>1000, 20277=>1000, 20278=>1000, 20279=>1000, 20280=>1000, 20281=>1000, 20282=>1000, - 20283=>1000, 20284=>1000, 20285=>1000, 20286=>1000, 20288=>1000, 20290=>1000, 20291=>1000, 20294=>1000, 20295=>1000, 20296=>1000, 20297=>1000, 20299=>1000, 20300=>1000, 20301=>1000, 20302=>1000, 20303=>1000, - 20304=>1000, 20305=>1000, 20306=>1000, 20307=>1000, 20308=>1000, 20309=>1000, 20310=>1000, 20311=>1000, 20312=>1000, 20313=>1000, 20314=>1000, 20315=>1000, 20316=>1000, 20317=>1000, 20318=>1000, 20319=>1000, - 20320=>1000, 20323=>1000, 20329=>1000, 20330=>1000, 20332=>1000, 20334=>1000, 20335=>1000, 20336=>1000, 20337=>1000, 20339=>1000, 20341=>1000, 20342=>1000, 20343=>1000, 20344=>1000, 20345=>1000, 20346=>1000, - 20347=>1000, 20348=>1000, 20349=>1000, 20350=>1000, 20351=>1000, 20353=>1000, 20354=>1000, 20355=>1000, 20356=>1000, 20357=>1000, 20358=>1000, 20360=>1000, 20361=>1000, 20362=>1000, 20363=>1000, 20364=>1000, - 20365=>1000, 20366=>1000, 20367=>1000, 20368=>1000, 20369=>1000, 20370=>1000, 20371=>1000, 20372=>1000, 20374=>1000, 20375=>1000, 20376=>1000, 20377=>1000, 20378=>1000, 20379=>1000, 20381=>1000, 20382=>1000, - 20383=>1000, 20384=>1000, 20385=>1000, 20395=>1000, 20397=>1000, 20398=>1000, 20399=>1000, 20402=>1000, 20405=>1000, 20406=>1000, 20407=>1000, 20409=>1000, 20411=>1000, 20412=>1000, 20413=>1000, 20414=>1000, - 20415=>1000, 20416=>1000, 20417=>1000, 20418=>1000, 20419=>1000, 20420=>1000, 20421=>1000, 20422=>1000, 20424=>1000, 20425=>1000, 20426=>1000, 20427=>1000, 20428=>1000, 20429=>1000, 20430=>1000, 20431=>1000, - 20432=>1000, 20433=>1000, 20434=>1000, 20436=>1000, 20439=>1000, 20440=>1000, 20442=>1000, 20443=>1000, 20444=>1000, 20445=>1000, 20447=>1000, 20448=>1000, 20449=>1000, 20450=>1000, 20451=>1000, 20452=>1000, - 20453=>1000, 20462=>1000, 20463=>1000, 20464=>1000, 20466=>1000, 20467=>1000, 20469=>1000, 20470=>1000, 20472=>1000, 20474=>1000, 20476=>1000, 20477=>1000, 20478=>1000, 20479=>1000, 20480=>1000, 20481=>1000, - 20484=>1000, 20485=>1000, 20486=>1000, 20487=>1000, 20489=>1000, 20490=>1000, 20491=>1000, 20492=>1000, 20493=>1000, 20494=>1000, 20495=>1000, 20496=>1000, 20497=>1000, 20498=>1000, 20499=>1000, 20500=>1000, - 20502=>1000, 20503=>1000, 20504=>1000, 20505=>1000, 20506=>1000, 20507=>1000, 20508=>1000, 20509=>1000, 20510=>1000, 20511=>1000, 20513=>1000, 20514=>1000, 20515=>1000, 20516=>1000, 20517=>1000, 20518=>1000, - 20519=>1000, 20520=>1000, 20521=>1000, 20522=>1000, 20523=>1000, 20524=>1000, 20525=>1000, 20526=>1000, 20528=>1000, 20530=>1000, 20531=>1000, 20533=>1000, 20534=>1000, 20537=>1000, 20539=>1000, 20544=>1000, - 20545=>1000, 20546=>1000, 20547=>1000, 20549=>1000, 20550=>1000, 20551=>1000, 20552=>1000, 20553=>1000, 20554=>1000, 20556=>1000, 20558=>1000, 20559=>1000, 20560=>1000, 20561=>1000, 20562=>1000, 20563=>1000, - 20565=>1000, 20566=>1000, 20567=>1000, 20569=>1000, 20570=>1000, 20572=>1000, 20575=>1000, 20576=>1000, 20578=>1000, 20579=>1000, 20581=>1000, 20582=>1000, 20583=>1000, 20586=>1000, 20588=>1000, 20589=>1000, - 20592=>1000, 20593=>1000, 20594=>1000, 20596=>1000, 20597=>1000, 20598=>1000, 20600=>1000, 20605=>1000, 20608=>1000, 20609=>1000, 20611=>1000, 20612=>1000, 20613=>1000, 20614=>1000, 20618=>1000, 20621=>1000, - 20622=>1000, 20623=>1000, 20624=>1000, 20625=>1000, 20626=>1000, 20627=>1000, 20628=>1000, 20630=>1000, 20632=>1000, 20633=>1000, 20634=>1000, 20635=>1000, 20636=>1000, 20638=>1000, 20639=>1000, 20640=>1000, - 20641=>1000, 20642=>1000, 20650=>1000, 20652=>1000, 20653=>1000, 20655=>1000, 20656=>1000, 20658=>1000, 20659=>1000, 20660=>1000, 20661=>1000, 20663=>1000, 20665=>1000, 20666=>1000, 20669=>1000, 20670=>1000, - 20672=>1000, 20674=>1000, 20675=>1000, 20676=>1000, 20677=>1000, 20679=>1000, 20681=>1000, 20682=>1000, 20684=>1000, 20685=>1000, 20686=>1000, 20687=>1000, 20688=>1000, 20689=>1000, 20691=>1000, 20692=>1000, - 20693=>1000, 20694=>1000, 20696=>1000, 20698=>1000, 20700=>1000, 20701=>1000, 20702=>1000, 20703=>1000, 20706=>1000, 20707=>1000, 20708=>1000, 20709=>1000, 20710=>1000, 20711=>1000, 20712=>1000, 20713=>1000, - 20717=>1000, 20718=>1000, 20719=>1000, 20721=>1000, 20722=>1000, 20724=>1000, 20725=>1000, 20726=>1000, 20729=>1000, 20730=>1000, 20731=>1000, 20734=>1000, 20736=>1000, 20737=>1000, 20738=>1000, 20739=>1000, - 20740=>1000, 20742=>1000, 20743=>1000, 20744=>1000, 20745=>1000, 20747=>1000, 20748=>1000, 20749=>1000, 20750=>1000, 20752=>1000, 20754=>1000, 20756=>1000, 20757=>1000, 20758=>1000, 20759=>1000, 20760=>1000, - 20761=>1000, 20762=>1000, 20763=>1000, 20764=>1000, 20765=>1000, 20766=>1000, 20767=>1000, 20769=>1000, 20771=>1000, 20775=>1000, 20776=>1000, 20778=>1000, 20780=>1000, 20781=>1000, 20783=>1000, 20785=>1000, - 20786=>1000, 20787=>1000, 20788=>1000, 20789=>1000, 20791=>1000, 20792=>1000, 20793=>1000, 20794=>1000, 20795=>1000, 20796=>1000, 20799=>1000, 20800=>1000, 20801=>1000, 20802=>1000, 20803=>1000, 20804=>1000, - 20805=>1000, 20806=>1000, 20807=>1000, 20808=>1000, 20809=>1000, 20810=>1000, 20811=>1000, 20812=>1000, 20813=>1000, 20814=>1000, 20815=>1000, 20816=>1000, 20818=>1000, 20819=>1000, 20820=>1000, 20821=>1000, - 20823=>1000, 20824=>1000, 20826=>1000, 20828=>1000, 20831=>1000, 20834=>1000, 20836=>1000, 20837=>1000, 20838=>1000, 20840=>1000, 20841=>1000, 20842=>1000, 20843=>1000, 20844=>1000, 20845=>1000, 20846=>1000, - 20849=>1000, 20853=>1000, 20854=>1000, 20855=>1000, 20856=>1000, 20860=>1000, 20862=>1000, 20864=>1000, 20866=>1000, 20867=>1000, 20868=>1000, 20869=>1000, 20870=>1000, 20873=>1000, 20874=>1000, 20875=>1000, - 20876=>1000, 20877=>1000, 20878=>1000, 20879=>1000, 20880=>1000, 20881=>1000, 20882=>1000, 20883=>1000, 20885=>1000, 20886=>1000, 20887=>1000, 20888=>1000, 20889=>1000, 20893=>1000, 20896=>1000, 20897=>1000, - 20898=>1000, 20899=>1000, 20900=>1000, 20901=>1000, 20902=>1000, 20904=>1000, 20905=>1000, 20906=>1000, 20907=>1000, 20908=>1000, 20909=>1000, 20912=>1000, 20913=>1000, 20914=>1000, 20915=>1000, 20916=>1000, - 20917=>1000, 20918=>1000, 20919=>1000, 20920=>1000, 20922=>1000, 20924=>1000, 20925=>1000, 20926=>1000, 20927=>1000, 20930=>1000, 20932=>1000, 20933=>1000, 20934=>1000, 20936=>1000, 20937=>1000, 20939=>1000, - 20940=>1000, 20941=>1000, 20943=>1000, 20945=>1000, 20946=>1000, 20947=>1000, 20949=>1000, 20950=>1000, 20952=>1000, 20955=>1000, 20956=>1000, 20957=>1000, 20958=>1000, 20960=>1000, 20961=>1000, 20962=>1000, - 20965=>1000, 20966=>1000, 20967=>1000, 20969=>1000, 20970=>1000, 20972=>1000, 20973=>1000, 20974=>1000, 20976=>1000, 20977=>1000, 20978=>1000, 20979=>1000, 20980=>1000, 20981=>1000, 20982=>1000, 20983=>1000, - 20984=>1000, 20985=>1000, 20986=>1000, 20989=>1000, 20990=>1000, 20992=>1000, 20993=>1000, 20994=>1000, 20995=>1000, 20996=>1000, 20997=>1000, 20998=>1000, 20999=>1000, 21000=>1000, 21002=>1000, 21003=>1000, - 21006=>1000, 21009=>1000, 21010=>1000, 21011=>1000, 21012=>1000, 21013=>1000, 21014=>1000, 21015=>1000, 21016=>1000, 21021=>1000, 21026=>1000, 21028=>1000, 21029=>1000, 21031=>1000, 21032=>1000, 21033=>1000, - 21034=>1000, 21038=>1000, 21040=>1000, 21041=>1000, 21042=>1000, 21043=>1000, 21045=>1000, 21046=>1000, 21047=>1000, 21048=>1000, 21049=>1000, 21050=>1000, 21051=>1000, 21052=>1000, 21059=>1000, 21060=>1000, - 21061=>1000, 21063=>1000, 21065=>1000, 21066=>1000, 21067=>1000, 21068=>1000, 21069=>1000, 21071=>1000, 21076=>1000, 21077=>1000, 21078=>1000, 21079=>1000, 21080=>1000, 21082=>1000, 21083=>1000, 21084=>1000, - 21086=>1000, 21087=>1000, 21088=>1000, 21089=>1000, 21091=>1000, 21092=>1000, 21093=>1000, 21094=>1000, 21097=>1000, 21098=>1000, 21102=>1000, 21103=>1000, 21104=>1000, 21105=>1000, 21106=>1000, 21107=>1000, - 21108=>1000, 21109=>1000, 21111=>1000, 21112=>1000, 21113=>1000, 21117=>1000, 21119=>1000, 21120=>1000, 21122=>1000, 21123=>1000, 21125=>1000, 21127=>1000, 21128=>1000, 21129=>1000, 21130=>1000, 21132=>1000, - 21133=>1000, 21137=>1000, 21138=>1000, 21139=>1000, 21140=>1000, 21141=>1000, 21142=>1000, 21143=>1000, 21144=>1000, 21146=>1000, 21147=>1000, 21148=>1000, 21151=>1000, 21152=>1000, 21155=>1000, 21156=>1000, - 21157=>1000, 21158=>1000, 21159=>1000, 21161=>1000, 21162=>1000, 21163=>1000, 21164=>1000, 21165=>1000, 21167=>1000, 21168=>1000, 21169=>1000, 21172=>1000, 21173=>1000, 21174=>1000, 21175=>1000, 21176=>1000, - 21177=>1000, 21178=>1000, 21179=>1000, 21180=>1000, 21181=>1000, 21182=>1000, 21184=>1000, 21185=>1000, 21187=>1000, 21188=>1000, 21189=>1000, 21190=>1000, 21191=>1000, 21192=>1000, 21193=>1000, 21196=>1000, - 21197=>1000, 21199=>1000, 21201=>1000, 21202=>1000, 21204=>1000, 21205=>1000, 21206=>1000, 21207=>1000, 21208=>1000, 21209=>1000, 21211=>1000, 21212=>1000, 21213=>1000, 21214=>1000, 21215=>1000, 21216=>1000, - 21217=>1000, 21218=>1000, 21219=>1000, 21220=>1000, 21221=>1000, 21222=>1000, 21223=>1000, 21224=>1000, 21225=>1000, 21226=>1000, 21228=>1000, 21232=>1000, 21233=>1000, 21234=>1000, 21235=>1000, 21236=>1000, - 21237=>1000, 21238=>1000, 21239=>1000, 21240=>1000, 21241=>1000, 21242=>1000, 21246=>1000, 21247=>1000, 21248=>1000, 21249=>1000, 21250=>1000, 21251=>1000, 21253=>1000, 21254=>1000, 21255=>1000, 21256=>1000, - 21258=>1000, 21259=>1000, 21260=>1000, 21261=>1000, 21263=>1000, 21264=>1000, 21265=>1000, 21267=>1000, 21269=>1000, 21270=>1000, 21271=>1000, 21272=>1000, 21273=>1000, 21274=>1000, 21275=>1000, 21276=>1000, - 21277=>1000, 21278=>1000, 21279=>1000, 21280=>1000, 21281=>1000, 21283=>1000, 21284=>1000, 21285=>1000, 21287=>1000, 21288=>1000, 21289=>1000, 21290=>1000, 21291=>1000, 21292=>1000, 21293=>1000, 21295=>1000, - 21296=>1000, 21297=>1000, 21298=>1000, 21299=>1000, 21301=>1000, 21304=>1000, 21305=>1000, 21306=>1000, 21307=>1000, 21308=>1000, 21309=>1000, 21310=>1000, 21311=>1000, 21312=>1000, 21313=>1000, 21314=>1000, - 21315=>1000, 21317=>1000, 21318=>1000, 21319=>1000, 21320=>1000, 21321=>1000, 21322=>1000, 21323=>1000, 21324=>1000, 21325=>1000, 21329=>1000, 21330=>1000, 21331=>1000, 21332=>1000, 21335=>1000, 21336=>1000, - 21337=>1000, 21338=>1000, 21339=>1000, 21340=>1000, 21342=>1000, 21344=>1000, 21345=>1000, 21347=>1000, 21349=>1000, 21350=>1000, 21353=>1000, 21356=>1000, 21357=>1000, 21358=>1000, 21359=>1000, 21360=>1000, - 21361=>1000, 21362=>1000, 21363=>1000, 21364=>1000, 21365=>1000, 21367=>1000, 21368=>1000, 21369=>1000, 21371=>1000, 21374=>1000, 21375=>1000, 21378=>1000, 21379=>1000, 21380=>1000, 21383=>1000, 21384=>1000, - 21390=>1000, 21395=>1000, 21396=>1000, 21398=>1000, 21400=>1000, 21401=>1000, 21402=>1000, 21405=>1000, 21407=>1000, 21408=>1000, 21409=>1000, 21412=>1000, 21413=>1000, 21414=>1000, 21416=>1000, 21417=>1000, - 21418=>1000, 21419=>1000, 21421=>1000, 21422=>1000, 21423=>1000, 21424=>1000, 21426=>1000, 21427=>1000, 21428=>1000, 21429=>1000, 21430=>1000, 21431=>1000, 21432=>1000, 21434=>1000, 21435=>1000, 21437=>1000, - 21440=>1000, 21442=>1000, 21443=>1000, 21445=>1000, 21448=>1000, 21449=>1000, 21450=>1000, 21451=>1000, 21452=>1000, 21453=>1000, 21454=>1000, 21455=>1000, 21458=>1000, 21459=>1000, 21460=>1000, 21461=>1000, - 21462=>1000, 21463=>1000, 21465=>1000, 21466=>1000, 21467=>1000, 21469=>1000, 21470=>1000, 21471=>1000, 21472=>1000, 21473=>1000, 21474=>1000, 21475=>1000, 21476=>1000, 21477=>1000, 21478=>1000, 21479=>1000, - 21480=>1000, 21481=>1000, 21482=>1000, 21483=>1000, 21484=>1000, 21485=>1000, 21486=>1000, 21487=>1000, 21488=>1000, 21489=>1000, 21490=>1000, 21491=>1000, 21493=>1000, 21494=>1000, 21495=>1000, 21496=>1000, - 21498=>1000, 21505=>1000, 21506=>1000, 21507=>1000, 21508=>1000, 21512=>1000, 21513=>1000, 21514=>1000, 21515=>1000, 21516=>1000, 21517=>1000, 21518=>1000, 21519=>1000, 21520=>1000, 21521=>1000, 21523=>1000, - 21530=>1000, 21531=>1000, 21533=>1000, 21535=>1000, 21536=>1000, 21537=>1000, 21542=>1000, 21543=>1000, 21544=>1000, 21545=>1000, 21546=>1000, 21547=>1000, 21548=>1000, 21549=>1000, 21550=>1000, 21551=>1000, - 21553=>1000, 21556=>1000, 21557=>1000, 21558=>1000, 21560=>1000, 21561=>1000, 21563=>1000, 21564=>1000, 21565=>1000, 21566=>1000, 21568=>1000, 21570=>1000, 21571=>1000, 21572=>1000, 21574=>1000, 21575=>1000, - 21576=>1000, 21577=>1000, 21578=>1000, 21581=>1000, 21582=>1000, 21583=>1000, 21585=>1000, 21598=>1000, 21599=>1000, 21602=>1000, 21604=>1000, 21606=>1000, 21607=>1000, 21608=>1000, 21609=>1000, 21610=>1000, - 21611=>1000, 21613=>1000, 21614=>1000, 21616=>1000, 21617=>1000, 21619=>1000, 21620=>1000, 21621=>1000, 21622=>1000, 21623=>1000, 21627=>1000, 21628=>1000, 21629=>1000, 21631=>1000, 21632=>1000, 21633=>1000, - 21635=>1000, 21636=>1000, 21637=>1000, 21638=>1000, 21640=>1000, 21641=>1000, 21642=>1000, 21643=>1000, 21644=>1000, 21645=>1000, 21646=>1000, 21647=>1000, 21648=>1000, 21649=>1000, 21650=>1000, 21653=>1000, - 21654=>1000, 21660=>1000, 21663=>1000, 21665=>1000, 21666=>1000, 21668=>1000, 21669=>1000, 21670=>1000, 21671=>1000, 21672=>1000, 21673=>1000, 21674=>1000, 21675=>1000, 21676=>1000, 21677=>1000, 21678=>1000, - 21679=>1000, 21681=>1000, 21682=>1000, 21683=>1000, 21687=>1000, 21688=>1000, 21689=>1000, 21690=>1000, 21691=>1000, 21692=>1000, 21693=>1000, 21694=>1000, 21695=>1000, 21696=>1000, 21697=>1000, 21698=>1000, - 21700=>1000, 21702=>1000, 21703=>1000, 21704=>1000, 21705=>1000, 21706=>1000, 21709=>1000, 21710=>1000, 21720=>1000, 21728=>1000, 21729=>1000, 21730=>1000, 21733=>1000, 21734=>1000, 21736=>1000, 21737=>1000, - 21738=>1000, 21740=>1000, 21741=>1000, 21742=>1000, 21743=>1000, 21746=>1000, 21750=>1000, 21754=>1000, 21756=>1000, 21757=>1000, 21758=>1000, 21759=>1000, 21760=>1000, 21761=>1000, 21764=>1000, 21765=>1000, - 21766=>1000, 21767=>1000, 21768=>1000, 21769=>1000, 21772=>1000, 21773=>1000, 21774=>1000, 21775=>1000, 21776=>1000, 21780=>1000, 21781=>1000, 21782=>1000, 21802=>1000, 21803=>1000, 21806=>1000, 21807=>1000, - 21809=>1000, 21810=>1000, 21811=>1000, 21813=>1000, 21814=>1000, 21816=>1000, 21817=>1000, 21819=>1000, 21820=>1000, 21821=>1000, 21822=>1000, 21824=>1000, 21825=>1000, 21828=>1000, 21829=>1000, 21830=>1000, - 21831=>1000, 21833=>1000, 21834=>1000, 21836=>1000, 21837=>1000, 21839=>1000, 21840=>1000, 21841=>1000, 21843=>1000, 21846=>1000, 21847=>1000, 21848=>1000, 21850=>1000, 21851=>1000, 21852=>1000, 21853=>1000, - 21854=>1000, 21856=>1000, 21857=>1000, 21859=>1000, 21860=>1000, 21862=>1000, 21883=>1000, 21884=>1000, 21886=>1000, 21887=>1000, 21888=>1000, 21889=>1000, 21890=>1000, 21891=>1000, 21892=>1000, 21894=>1000, - 21895=>1000, 21896=>1000, 21897=>1000, 21898=>1000, 21899=>1000, 21902=>1000, 21903=>1000, 21905=>1000, 21906=>1000, 21907=>1000, 21908=>1000, 21911=>1000, 21912=>1000, 21913=>1000, 21914=>1000, 21916=>1000, - 21917=>1000, 21918=>1000, 21919=>1000, 21923=>1000, 21924=>1000, 21927=>1000, 21928=>1000, 21929=>1000, 21930=>1000, 21931=>1000, 21932=>1000, 21933=>1000, 21934=>1000, 21936=>1000, 21938=>1000, 21942=>1000, - 21951=>1000, 21953=>1000, 21955=>1000, 21956=>1000, 21957=>1000, 21958=>1000, 21959=>1000, 21961=>1000, 21963=>1000, 21964=>1000, 21966=>1000, 21969=>1000, 21970=>1000, 21971=>1000, 21972=>1000, 21975=>1000, - 21976=>1000, 21978=>1000, 21979=>1000, 21980=>1000, 21982=>1000, 21983=>1000, 21986=>1000, 21987=>1000, 21988=>1000, 21993=>1000, 22006=>1000, 22007=>1000, 22009=>1000, 22013=>1000, 22014=>1000, 22015=>1000, - 22021=>1000, 22022=>1000, 22024=>1000, 22025=>1000, 22026=>1000, 22029=>1000, 22030=>1000, 22031=>1000, 22032=>1000, 22033=>1000, 22034=>1000, 22036=>1000, 22038=>1000, 22039=>1000, 22040=>1000, 22041=>1000, - 22043=>1000, 22057=>1000, 22060=>1000, 22063=>1000, 22064=>1000, 22065=>1000, 22066=>1000, 22067=>1000, 22068=>1000, 22069=>1000, 22070=>1000, 22071=>1000, 22072=>1000, 22073=>1000, 22075=>1000, 22076=>1000, - 22077=>1000, 22079=>1000, 22080=>1000, 22081=>1000, 22082=>1000, 22083=>1000, 22084=>1000, 22086=>1000, 22089=>1000, 22091=>1000, 22092=>1000, 22093=>1000, 22094=>1000, 22095=>1000, 22096=>1000, 22100=>1000, - 22107=>1000, 22110=>1000, 22112=>1000, 22113=>1000, 22114=>1000, 22115=>1000, 22116=>1000, 22118=>1000, 22120=>1000, 22121=>1000, 22122=>1000, 22123=>1000, 22124=>1000, 22125=>1000, 22127=>1000, 22129=>1000, - 22130=>1000, 22132=>1000, 22133=>1000, 22136=>1000, 22138=>1000, 22144=>1000, 22148=>1000, 22149=>1000, 22150=>1000, 22151=>1000, 22152=>1000, 22154=>1000, 22155=>1000, 22156=>1000, 22159=>1000, 22164=>1000, - 22165=>1000, 22169=>1000, 22170=>1000, 22173=>1000, 22174=>1000, 22175=>1000, 22176=>1000, 22178=>1000, 22181=>1000, 22182=>1000, 22183=>1000, 22184=>1000, 22185=>1000, 22187=>1000, 22188=>1000, 22189=>1000, - 22190=>1000, 22193=>1000, 22195=>1000, 22196=>1000, 22198=>1000, 22199=>1000, 22204=>1000, 22206=>1000, 22208=>1000, 22209=>1000, 22210=>1000, 22211=>1000, 22213=>1000, 22216=>1000, 22217=>1000, 22218=>1000, - 22219=>1000, 22220=>1000, 22221=>1000, 22222=>1000, 22223=>1000, 22224=>1000, 22225=>1000, 22227=>1000, 22231=>1000, 22232=>1000, 22233=>1000, 22234=>1000, 22235=>1000, 22236=>1000, 22237=>1000, 22238=>1000, - 22239=>1000, 22240=>1000, 22241=>1000, 22243=>1000, 22244=>1000, 22245=>1000, 22246=>1000, 22247=>1000, 22248=>1000, 22251=>1000, 22253=>1000, 22254=>1000, 22256=>1000, 22257=>1000, 22258=>1000, 22259=>1000, - 22262=>1000, 22263=>1000, 22265=>1000, 22266=>1000, 22269=>1000, 22271=>1000, 22272=>1000, 22273=>1000, 22274=>1000, 22275=>1000, 22276=>1000, 22279=>1000, 22280=>1000, 22281=>1000, 22282=>1000, 22283=>1000, - 22284=>1000, 22285=>1000, 22287=>1000, 22289=>1000, 22290=>1000, 22291=>1000, 22293=>1000, 22294=>1000, 22296=>1000, 22298=>1000, 22299=>1000, 22300=>1000, 22301=>1000, 22303=>1000, 22304=>1000, 22306=>1000, - 22307=>1000, 22308=>1000, 22309=>1000, 22310=>1000, 22311=>1000, 22312=>1000, 22313=>1000, 22314=>1000, 22316=>1000, 22317=>1000, 22318=>1000, 22319=>1000, 22320=>1000, 22323=>1000, 22324=>1000, 22327=>1000, - 22328=>1000, 22331=>1000, 22333=>1000, 22334=>1000, 22335=>1000, 22336=>1000, 22338=>1000, 22341=>1000, 22342=>1000, 22343=>1000, 22346=>1000, 22348=>1000, 22349=>1000, 22350=>1000, 22351=>1000, 22352=>1000, - 22353=>1000, 22354=>1000, 22361=>1000, 22369=>1000, 22370=>1000, 22372=>1000, 22373=>1000, 22374=>1000, 22375=>1000, 22376=>1000, 22377=>1000, 22378=>1000, 22379=>1000, 22381=>1000, 22382=>1000, 22383=>1000, - 22384=>1000, 22385=>1000, 22387=>1000, 22388=>1000, 22389=>1000, 22391=>1000, 22393=>1000, 22394=>1000, 22395=>1000, 22396=>1000, 22398=>1000, 22399=>1000, 22401=>1000, 22402=>1000, 22403=>1000, 22408=>1000, - 22409=>1000, 22411=>1000, 22412=>1000, 22419=>1000, 22420=>1000, 22421=>1000, 22423=>1000, 22425=>1000, 22426=>1000, 22428=>1000, 22429=>1000, 22430=>1000, 22431=>1000, 22432=>1000, 22433=>1000, 22434=>1000, - 22435=>1000, 22436=>1000, 22439=>1000, 22440=>1000, 22441=>1000, 22442=>1000, 22444=>1000, 22448=>1000, 22451=>1000, 22456=>1000, 22461=>1000, 22464=>1000, 22467=>1000, 22470=>1000, 22471=>1000, 22472=>1000, - 22475=>1000, 22476=>1000, 22478=>1000, 22479=>1000, 22482=>1000, 22483=>1000, 22484=>1000, 22485=>1000, 22486=>1000, 22492=>1000, 22493=>1000, 22494=>1000, 22495=>1000, 22496=>1000, 22497=>1000, 22499=>1000, - 22500=>1000, 22502=>1000, 22503=>1000, 22505=>1000, 22509=>1000, 22512=>1000, 22516=>1000, 22517=>1000, 22518=>1000, 22519=>1000, 22520=>1000, 22521=>1000, 22522=>1000, 22524=>1000, 22525=>1000, 22526=>1000, - 22527=>1000, 22528=>1000, 22530=>1000, 22531=>1000, 22532=>1000, 22533=>1000, 22534=>1000, 22536=>1000, 22537=>1000, 22538=>1000, 22539=>1000, 22540=>1000, 22541=>1000, 22549=>1000, 22553=>1000, 22555=>1000, - 22557=>1000, 22558=>1000, 22559=>1000, 22560=>1000, 22561=>1000, 22564=>1000, 22566=>1000, 22567=>1000, 22570=>1000, 22573=>1000, 22575=>1000, 22576=>1000, 22577=>1000, 22578=>1000, 22580=>1000, 22581=>1000, - 22585=>1000, 22586=>1000, 22589=>1000, 22591=>1000, 22592=>1000, 22593=>1000, 22601=>1000, 22602=>1000, 22603=>1000, 22604=>1000, 22605=>1000, 22607=>1000, 22608=>1000, 22609=>1000, 22610=>1000, 22612=>1000, - 22613=>1000, 22615=>1000, 22616=>1000, 22617=>1000, 22618=>1000, 22622=>1000, 22623=>1000, 22625=>1000, 22626=>1000, 22628=>1000, 22631=>1000, 22632=>1000, 22633=>1000, 22635=>1000, 22640=>1000, 22642=>1000, - 22645=>1000, 22648=>1000, 22649=>1000, 22652=>1000, 22654=>1000, 22655=>1000, 22656=>1000, 22657=>1000, 22659=>1000, 22661=>1000, 22663=>1000, 22664=>1000, 22665=>1000, 22666=>1000, 22668=>1000, 22669=>1000, - 22671=>1000, 22672=>1000, 22675=>1000, 22676=>1000, 22678=>1000, 22679=>1000, 22684=>1000, 22685=>1000, 22686=>1000, 22687=>1000, 22688=>1000, 22689=>1000, 22690=>1000, 22694=>1000, 22696=>1000, 22697=>1000, - 22699=>1000, 22702=>1000, 22705=>1000, 22706=>1000, 22707=>1000, 22712=>1000, 22713=>1000, 22714=>1000, 22715=>1000, 22716=>1000, 22718=>1000, 22721=>1000, 22722=>1000, 22724=>1000, 22725=>1000, 22727=>1000, - 22728=>1000, 22730=>1000, 22732=>1000, 22733=>1000, 22734=>1000, 22736=>1000, 22737=>1000, 22738=>1000, 22739=>1000, 22740=>1000, 22741=>1000, 22742=>1000, 22743=>1000, 22744=>1000, 22745=>1000, 22746=>1000, - 22748=>1000, 22749=>1000, 22750=>1000, 22751=>1000, 22753=>1000, 22754=>1000, 22756=>1000, 22757=>1000, 22761=>1000, 22763=>1000, 22764=>1000, 22766=>1000, 22767=>1000, 22768=>1000, 22769=>1000, 22770=>1000, - 22771=>1000, 22775=>1000, 22777=>1000, 22778=>1000, 22779=>1000, 22780=>1000, 22781=>1000, 22786=>1000, 22789=>1000, 22790=>1000, 22793=>1000, 22794=>1000, 22795=>1000, 22796=>1000, 22799=>1000, 22800=>1000, - 22802=>1000, 22803=>1000, 22804=>1000, 22805=>1000, 22806=>1000, 22808=>1000, 22809=>1000, 22810=>1000, 22811=>1000, 22812=>1000, 22813=>1000, 22817=>1000, 22818=>1000, 22819=>1000, 22820=>1000, 22821=>1000, - 22823=>1000, 22824=>1000, 22825=>1000, 22826=>1000, 22827=>1000, 22828=>1000, 22829=>1000, 22830=>1000, 22831=>1000, 22832=>1000, 22833=>1000, 22834=>1000, 22835=>1000, 22837=>1000, 22838=>1000, 22839=>1000, - 22840=>1000, 22846=>1000, 22847=>1000, 22851=>1000, 22852=>1000, 22854=>1000, 22855=>1000, 22856=>1000, 22857=>1000, 22862=>1000, 22863=>1000, 22864=>1000, 22865=>1000, 22866=>1000, 22867=>1000, 22868=>1000, - 22869=>1000, 22871=>1000, 22872=>1000, 22873=>1000, 22874=>1000, 22875=>1000, 22877=>1000, 22878=>1000, 22879=>1000, 22880=>1000, 22881=>1000, 22882=>1000, 22883=>1000, 22885=>1000, 22887=>1000, 22888=>1000, - 22889=>1000, 22890=>1000, 22891=>1000, 22892=>1000, 22893=>1000, 22894=>1000, 22895=>1000, 22898=>1000, 22899=>1000, 22900=>1000, 22901=>1000, 22902=>1000, 22904=>1000, 22905=>1000, 22907=>1000, 22908=>1000, - 22909=>1000, 22913=>1000, 22914=>1000, 22915=>1000, 22916=>1000, 22922=>1000, 22923=>1000, 22924=>1000, 22925=>1000, 22926=>1000, 22930=>1000, 22931=>1000, 22933=>1000, 22934=>1000, 22935=>1000, 22937=>1000, - 22939=>1000, 22941=>1000, 22943=>1000, 22947=>1000, 22948=>1000, 22949=>1000, 22951=>1000, 22952=>1000, 22956=>1000, 22957=>1000, 22958=>1000, 22959=>1000, 22960=>1000, 22962=>1000, 22963=>1000, 22967=>1000, - 22969=>1000, 22970=>1000, 22971=>1000, 22972=>1000, 22974=>1000, 22977=>1000, 22979=>1000, 22980=>1000, 22982=>1000, 22984=>1000, 22985=>1000, 22986=>1000, 22987=>1000, 22989=>1000, 22992=>1000, 22993=>1000, - 22994=>1000, 22995=>1000, 22996=>1000, 23001=>1000, 23002=>1000, 23004=>1000, 23005=>1000, 23006=>1000, 23007=>1000, 23011=>1000, 23012=>1000, 23013=>1000, 23014=>1000, 23015=>1000, 23016=>1000, 23018=>1000, - 23019=>1000, 23022=>1000, 23023=>1000, 23025=>1000, 23026=>1000, 23028=>1000, 23030=>1000, 23031=>1000, 23035=>1000, 23039=>1000, 23040=>1000, 23041=>1000, 23043=>1000, 23044=>1000, 23049=>1000, 23052=>1000, - 23053=>1000, 23054=>1000, 23057=>1000, 23058=>1000, 23059=>1000, 23064=>1000, 23066=>1000, 23068=>1000, 23070=>1000, 23071=>1000, 23072=>1000, 23075=>1000, 23076=>1000, 23077=>1000, 23079=>1000, 23080=>1000, - 23081=>1000, 23082=>1000, 23085=>1000, 23087=>1000, 23088=>1000, 23093=>1000, 23094=>1000, 23100=>1000, 23104=>1000, 23105=>1000, 23108=>1000, 23109=>1000, 23110=>1000, 23111=>1000, 23112=>1000, 23113=>1000, - 23116=>1000, 23120=>1000, 23125=>1000, 23130=>1000, 23134=>1000, 23138=>1000, 23139=>1000, 23141=>1000, 23142=>1000, 23143=>1000, 23146=>1000, 23148=>1000, 23149=>1000, 23159=>1000, 23162=>1000, 23163=>1000, - 23166=>1000, 23167=>1000, 23179=>1000, 23184=>1000, 23186=>1000, 23187=>1000, 23190=>1000, 23193=>1000, 23194=>1000, 23195=>1000, 23196=>1000, 23198=>1000, 23199=>1000, 23200=>1000, 23202=>1000, 23207=>1000, - 23212=>1000, 23217=>1000, 23218=>1000, 23219=>1000, 23221=>1000, 23224=>1000, 23226=>1000, 23227=>1000, 23228=>1000, 23229=>1000, 23230=>1000, 23231=>1000, 23233=>1000, 23234=>1000, 23236=>1000, 23238=>1000, - 23240=>1000, 23241=>1000, 23243=>1000, 23244=>1000, 23247=>1000, 23248=>1000, 23254=>1000, 23255=>1000, 23258=>1000, 23260=>1000, 23264=>1000, 23265=>1000, 23267=>1000, 23269=>1000, 23270=>1000, 23273=>1000, - 23274=>1000, 23278=>1000, 23285=>1000, 23286=>1000, 23290=>1000, 23291=>1000, 23293=>1000, 23296=>1000, 23297=>1000, 23304=>1000, 23305=>1000, 23307=>1000, 23308=>1000, 23318=>1000, 23319=>1000, 23321=>1000, - 23323=>1000, 23325=>1000, 23329=>1000, 23330=>1000, 23333=>1000, 23338=>1000, 23340=>1000, 23341=>1000, 23344=>1000, 23346=>1000, 23348=>1000, 23350=>1000, 23352=>1000, 23358=>1000, 23360=>1000, 23361=>1000, - 23363=>1000, 23365=>1000, 23371=>1000, 23372=>1000, 23376=>1000, 23377=>1000, 23378=>1000, 23380=>1000, 23381=>1000, 23382=>1000, 23383=>1000, 23384=>1000, 23386=>1000, 23387=>1000, 23388=>1000, 23389=>1000, - 23390=>1000, 23391=>1000, 23395=>1000, 23396=>1000, 23397=>1000, 23398=>1000, 23400=>1000, 23401=>1000, 23403=>1000, 23406=>1000, 23407=>1000, 23408=>1000, 23409=>1000, 23411=>1000, 23413=>1000, 23416=>1000, - 23418=>1000, 23420=>1000, 23421=>1000, 23422=>1000, 23423=>1000, 23424=>1000, 23425=>1000, 23427=>1000, 23428=>1000, 23429=>1000, 23430=>1000, 23431=>1000, 23432=>1000, 23433=>1000, 23434=>1000, 23435=>1000, - 23436=>1000, 23437=>1000, 23438=>1000, 23439=>1000, 23440=>1000, 23441=>1000, 23443=>1000, 23444=>1000, 23445=>1000, 23446=>1000, 23447=>1000, 23448=>1000, 23449=>1000, 23450=>1000, 23451=>1000, 23452=>1000, - 23453=>1000, 23455=>1000, 23458=>1000, 23459=>1000, 23460=>1000, 23461=>1000, 23462=>1000, 23464=>1000, 23465=>1000, 23468=>1000, 23469=>1000, 23470=>1000, 23471=>1000, 23472=>1000, 23473=>1000, 23474=>1000, - 23475=>1000, 23476=>1000, 23477=>1000, 23478=>1000, 23479=>1000, 23480=>1000, 23481=>1000, 23482=>1000, 23484=>1000, 23487=>1000, 23488=>1000, 23489=>1000, 23490=>1000, 23491=>1000, 23492=>1000, 23493=>1000, - 23494=>1000, 23495=>1000, 23497=>1000, 23500=>1000, 23501=>1000, 23503=>1000, 23504=>1000, 23506=>1000, 23507=>1000, 23508=>1000, 23510=>1000, 23511=>1000, 23512=>1000, 23513=>1000, 23514=>1000, 23515=>1000, - 23517=>1000, 23518=>1000, 23519=>1000, 23520=>1000, 23521=>1000, 23522=>1000, 23524=>1000, 23525=>1000, 23526=>1000, 23527=>1000, 23528=>1000, 23529=>1000, 23531=>1000, 23532=>1000, 23534=>1000, 23535=>1000, - 23536=>1000, 23537=>1000, 23539=>1000, 23540=>1000, 23541=>1000, 23542=>1000, 23544=>1000, 23546=>1000, 23549=>1000, 23550=>1000, 23551=>1000, 23553=>1000, 23554=>1000, 23556=>1000, 23557=>1000, 23558=>1000, - 23559=>1000, 23560=>1000, 23561=>1000, 23562=>1000, 23563=>1000, 23564=>1000, 23565=>1000, 23566=>1000, 23567=>1000, 23569=>1000, 23571=>1000, 23574=>1000, 23575=>1000, 23578=>1000, 23582=>1000, 23583=>1000, - 23584=>1000, 23586=>1000, 23587=>1000, 23588=>1000, 23590=>1000, 23592=>1000, 23593=>1000, 23595=>1000, 23596=>1000, 23597=>1000, 23598=>1000, 23600=>1000, 23601=>1000, 23602=>1000, 23605=>1000, 23606=>1000, - 23608=>1000, 23609=>1000, 23610=>1000, 23611=>1000, 23612=>1000, 23613=>1000, 23614=>1000, 23615=>1000, 23616=>1000, 23617=>1000, 23621=>1000, 23622=>1000, 23624=>1000, 23626=>1000, 23627=>1000, 23629=>1000, - 23630=>1000, 23631=>1000, 23632=>1000, 23633=>1000, 23635=>1000, 23637=>1000, 23641=>1000, 23642=>1000, 23644=>1000, 23646=>1000, 23648=>1000, 23649=>1000, 23650=>1000, 23651=>1000, 23652=>1000, 23653=>1000, - 23655=>1000, 23656=>1000, 23657=>1000, 23660=>1000, 23661=>1000, 23662=>1000, 23663=>1000, 23664=>1000, 23665=>1000, 23668=>1000, 23669=>1000, 23670=>1000, 23673=>1000, 23674=>1000, 23675=>1000, 23676=>1000, - 23677=>1000, 23687=>1000, 23688=>1000, 23690=>1000, 23692=>1000, 23695=>1000, 23696=>1000, 23697=>1000, 23698=>1000, 23700=>1000, 23709=>1000, 23711=>1000, 23712=>1000, 23713=>1000, 23714=>1000, 23715=>1000, - 23718=>1000, 23720=>1000, 23721=>1000, 23722=>1000, 23723=>1000, 23724=>1000, 23729=>1000, 23730=>1000, 23731=>1000, 23732=>1000, 23733=>1000, 23734=>1000, 23735=>1000, 23736=>1000, 23738=>1000, 23739=>1000, - 23740=>1000, 23742=>1000, 23749=>1000, 23751=>1000, 23753=>1000, 23755=>1000, 23762=>1000, 23767=>1000, 23769=>1000, 23773=>1000, 23776=>1000, 23777=>1000, 23784=>1000, 23785=>1000, 23786=>1000, 23789=>1000, - 23790=>1000, 23791=>1000, 23792=>1000, 23793=>1000, 23794=>1000, 23796=>1000, 23797=>1000, 23798=>1000, 23802=>1000, 23803=>1000, 23805=>1000, 23809=>1000, 23814=>1000, 23815=>1000, 23819=>1000, 23821=>1000, - 23822=>1000, 23825=>1000, 23826=>1000, 23828=>1000, 23829=>1000, 23830=>1000, 23831=>1000, 23832=>1000, 23833=>1000, 23834=>1000, 23835=>1000, 23839=>1000, 23842=>1000, 23843=>1000, 23844=>1000, 23846=>1000, - 23847=>1000, 23849=>1000, 23851=>1000, 23857=>1000, 23860=>1000, 23865=>1000, 23869=>1000, 23871=>1000, 23874=>1000, 23875=>1000, 23878=>1000, 23880=>1000, 23882=>1000, 23883=>1000, 23884=>1000, 23886=>1000, - 23888=>1000, 23889=>1000, 23890=>1000, 23893=>1000, 23897=>1000, 23900=>1000, 23903=>1000, 23904=>1000, 23905=>1000, 23906=>1000, 23908=>1000, 23913=>1000, 23914=>1000, 23916=>1000, 23917=>1000, 23919=>1000, - 23920=>1000, 23923=>1000, 23926=>1000, 23929=>1000, 23930=>1000, 23934=>1000, 23935=>1000, 23937=>1000, 23938=>1000, 23939=>1000, 23940=>1000, 23943=>1000, 23944=>1000, 23946=>1000, 23947=>1000, 23948=>1000, - 23952=>1000, 23954=>1000, 23955=>1000, 23956=>1000, 23957=>1000, 23961=>1000, 23963=>1000, 23965=>1000, 23967=>1000, 23968=>1000, 23970=>1000, 23975=>1000, 23979=>1000, 23980=>1000, 23982=>1000, 23984=>1000, - 23986=>1000, 23988=>1000, 23991=>1000, 23992=>1000, 23993=>1000, 23994=>1000, 23996=>1000, 23997=>1000, 24003=>1000, 24007=>1000, 24009=>1000, 24011=>1000, 24012=>1000, 24013=>1000, 24014=>1000, 24016=>1000, - 24018=>1000, 24019=>1000, 24022=>1000, 24024=>1000, 24025=>1000, 24027=>1000, 24029=>1000, 24030=>1000, 24032=>1000, 24033=>1000, 24035=>1000, 24036=>1000, 24037=>1000, 24038=>1000, 24039=>1000, 24040=>1000, - 24041=>1000, 24043=>1000, 24046=>1000, 24049=>1000, 24050=>1000, 24051=>1000, 24052=>1000, 24053=>1000, 24055=>1000, 24056=>1000, 24057=>1000, 24059=>1000, 24061=>1000, 24062=>1000, 24064=>1000, 24066=>1000, - 24067=>1000, 24070=>1000, 24071=>1000, 24075=>1000, 24076=>1000, 24077=>1000, 24081=>1000, 24082=>1000, 24084=>1000, 24085=>1000, 24086=>1000, 24088=>1000, 24089=>1000, 24090=>1000, 24091=>1000, 24093=>1000, - 24095=>1000, 24096=>1000, 24101=>1000, 24104=>1000, 24107=>1000, 24109=>1000, 24110=>1000, 24111=>1000, 24112=>1000, 24114=>1000, 24115=>1000, 24117=>1000, 24118=>1000, 24119=>1000, 24120=>1000, 24125=>1000, - 24126=>1000, 24128=>1000, 24131=>1000, 24132=>1000, 24133=>1000, 24135=>1000, 24137=>1000, 24139=>1000, 24140=>1000, 24142=>1000, 24144=>1000, 24145=>1000, 24148=>1000, 24149=>1000, 24150=>1000, 24151=>1000, - 24152=>1000, 24155=>1000, 24156=>1000, 24158=>1000, 24159=>1000, 24161=>1000, 24162=>1000, 24163=>1000, 24164=>1000, 24168=>1000, 24170=>1000, 24171=>1000, 24172=>1000, 24173=>1000, 24174=>1000, 24176=>1000, - 24178=>1000, 24179=>1000, 24180=>1000, 24181=>1000, 24182=>1000, 24184=>1000, 24185=>1000, 24186=>1000, 24187=>1000, 24188=>1000, 24189=>1000, 24190=>1000, 24191=>1000, 24192=>1000, 24193=>1000, 24195=>1000, - 24196=>1000, 24199=>1000, 24202=>1000, 24203=>1000, 24206=>1000, 24207=>1000, 24213=>1000, 24214=>1000, 24215=>1000, 24218=>1000, 24220=>1000, 24224=>1000, 24226=>1000, 24228=>1000, 24229=>1000, 24230=>1000, - 24231=>1000, 24232=>1000, 24234=>1000, 24235=>1000, 24236=>1000, 24237=>1000, 24241=>1000, 24243=>1000, 24245=>1000, 24246=>1000, 24247=>1000, 24248=>1000, 24253=>1000, 24254=>1000, 24255=>1000, 24257=>1000, - 24258=>1000, 24259=>1000, 24262=>1000, 24264=>1000, 24265=>1000, 24266=>1000, 24267=>1000, 24268=>1000, 24270=>1000, 24271=>1000, 24272=>1000, 24273=>1000, 24274=>1000, 24275=>1000, 24276=>1000, 24277=>1000, - 24278=>1000, 24282=>1000, 24283=>1000, 24284=>1000, 24285=>1000, 24286=>1000, 24287=>1000, 24288=>1000, 24289=>1000, 24290=>1000, 24291=>1000, 24293=>1000, 24296=>1000, 24297=>1000, 24299=>1000, 24300=>1000, - 24304=>1000, 24305=>1000, 24307=>1000, 24308=>1000, 24310=>1000, 24311=>1000, 24312=>1000, 24314=>1000, 24315=>1000, 24316=>1000, 24318=>1000, 24319=>1000, 24321=>1000, 24322=>1000, 24323=>1000, 24324=>1000, - 24326=>1000, 24327=>1000, 24328=>1000, 24329=>1000, 24330=>1000, 24331=>1000, 24332=>1000, 24333=>1000, 24334=>1000, 24335=>1000, 24336=>1000, 24337=>1000, 24339=>1000, 24340=>1000, 24341=>1000, 24342=>1000, - 24343=>1000, 24344=>1000, 24345=>1000, 24347=>1000, 24348=>1000, 24349=>1000, 24351=>1000, 24353=>1000, 24354=>1000, 24355=>1000, 24356=>1000, 24357=>1000, 24358=>1000, 24359=>1000, 24360=>1000, 24361=>1000, - 24363=>1000, 24364=>1000, 24365=>1000, 24366=>1000, 24367=>1000, 24368=>1000, 24369=>1000, 24372=>1000, 24373=>1000, 24374=>1000, 24375=>1000, 24376=>1000, 24379=>1000, 24380=>1000, 24381=>1000, 24382=>1000, - 24383=>1000, 24384=>1000, 24385=>1000, 24388=>1000, 24389=>1000, 24391=>1000, 24392=>1000, 24394=>1000, 24396=>1000, 24397=>1000, 24398=>1000, 24400=>1000, 24401=>1000, 24403=>1000, 24404=>1000, 24406=>1000, - 24407=>1000, 24408=>1000, 24409=>1000, 24411=>1000, 24412=>1000, 24413=>1000, 24416=>1000, 24417=>1000, 24418=>1000, 24419=>1000, 24420=>1000, 24422=>1000, 24423=>1000, 24425=>1000, 24426=>1000, 24427=>1000, - 24428=>1000, 24429=>1000, 24431=>1000, 24432=>1000, 24433=>1000, 24434=>1000, 24435=>1000, 24436=>1000, 24437=>1000, 24439=>1000, 24440=>1000, 24441=>1000, 24442=>1000, 24444=>1000, 24445=>1000, 24446=>1000, - 24447=>1000, 24448=>1000, 24449=>1000, 24450=>1000, 24451=>1000, 24452=>1000, 24453=>1000, 24455=>1000, 24456=>1000, 24457=>1000, 24458=>1000, 24459=>1000, 24460=>1000, 24461=>1000, 24463=>1000, 24464=>1000, - 24465=>1000, 24466=>1000, 24467=>1000, 24470=>1000, 24471=>1000, 24472=>1000, 24473=>1000, 24476=>1000, 24477=>1000, 24478=>1000, 24480=>1000, 24481=>1000, 24482=>1000, 24484=>1000, 24487=>1000, 24488=>1000, - 24489=>1000, 24490=>1000, 24491=>1000, 24492=>1000, 24493=>1000, 24494=>1000, 24495=>1000, 24496=>1000, 24497=>1000, 24499=>1000, 24500=>1000, 24503=>1000, 24504=>1000, 24505=>1000, 24508=>1000, 24509=>1000, - 24515=>1000, 24516=>1000, 24517=>1000, 24519=>1000, 24520=>1000, 24521=>1000, 24523=>1000, 24524=>1000, 24525=>1000, 24528=>1000, 24529=>1000, 24530=>1000, 24531=>1000, 24532=>1000, 24534=>1000, 24535=>1000, - 24536=>1000, 24537=>1000, 24540=>1000, 24541=>1000, 24542=>1000, 24544=>1000, 24545=>1000, 24546=>1000, 24548=>1000, 24552=>1000, 24553=>1000, 24554=>1000, 24555=>1000, 24556=>1000, 24557=>1000, 24558=>1000, - 24559=>1000, 24560=>1000, 24561=>1000, 24562=>1000, 24563=>1000, 24565=>1000, 24566=>1000, 24568=>1000, 24570=>1000, 24571=>1000, 24572=>1000, 24573=>1000, 24575=>1000, 24583=>1000, 24586=>1000, 24589=>1000, - 24590=>1000, 24591=>1000, 24592=>1000, 24594=>1000, 24595=>1000, 24596=>1000, 24597=>1000, 24598=>1000, 24599=>1000, 24600=>1000, 24601=>1000, 24602=>1000, 24603=>1000, 24604=>1000, 24605=>1000, 24607=>1000, - 24608=>1000, 24609=>1000, 24612=>1000, 24613=>1000, 24614=>1000, 24615=>1000, 24616=>1000, 24617=>1000, 24618=>1000, 24619=>1000, 24621=>1000, 24623=>1000, 24625=>1000, 24627=>1000, 24629=>1000, 24634=>1000, - 24640=>1000, 24641=>1000, 24642=>1000, 24643=>1000, 24646=>1000, 24647=>1000, 24648=>1000, 24649=>1000, 24650=>1000, 24651=>1000, 24652=>1000, 24653=>1000, 24656=>1000, 24657=>1000, 24658=>1000, 24660=>1000, - 24661=>1000, 24662=>1000, 24663=>1000, 24665=>1000, 24666=>1000, 24669=>1000, 24671=>1000, 24672=>1000, 24673=>1000, 24674=>1000, 24675=>1000, 24676=>1000, 24677=>1000, 24679=>1000, 24680=>1000, 24681=>1000, - 24682=>1000, 24683=>1000, 24684=>1000, 24685=>1000, 24687=>1000, 24688=>1000, 24689=>1000, 24693=>1000, 24695=>1000, 24702=>1000, 24703=>1000, 24705=>1000, 24706=>1000, 24707=>1000, 24708=>1000, 24709=>1000, - 24710=>1000, 24712=>1000, 24713=>1000, 24714=>1000, 24715=>1000, 24716=>1000, 24717=>1000, 24718=>1000, 24721=>1000, 24722=>1000, 24723=>1000, 24724=>1000, 24725=>1000, 24726=>1000, 24727=>1000, 24728=>1000, - 24730=>1000, 24731=>1000, 24733=>1000, 24734=>1000, 24735=>1000, 24736=>1000, 24738=>1000, 24739=>1000, 24740=>1000, 24741=>1000, 24742=>1000, 24743=>1000, 24744=>1000, 24745=>1000, 24746=>1000, 24752=>1000, - 24753=>1000, 24754=>1000, 24755=>1000, 24756=>1000, 24757=>1000, 24758=>1000, 24759=>1000, 24760=>1000, 24763=>1000, 24764=>1000, 24765=>1000, 24766=>1000, 24770=>1000, 24772=>1000, 24773=>1000, 24774=>1000, - 24775=>1000, 24776=>1000, 24777=>1000, 24778=>1000, 24779=>1000, 24782=>1000, 24783=>1000, 24785=>1000, 24787=>1000, 24788=>1000, 24789=>1000, 24792=>1000, 24793=>1000, 24794=>1000, 24795=>1000, 24796=>1000, - 24797=>1000, 24798=>1000, 24799=>1000, 24800=>1000, 24801=>1000, 24802=>1000, 24803=>1000, 24805=>1000, 24807=>1000, 24808=>1000, 24816=>1000, 24817=>1000, 24818=>1000, 24819=>1000, 24820=>1000, 24821=>1000, - 24822=>1000, 24823=>1000, 24824=>1000, 24825=>1000, 24826=>1000, 24827=>1000, 24828=>1000, 24829=>1000, 24832=>1000, 24833=>1000, 24834=>1000, 24835=>1000, 24838=>1000, 24839=>1000, 24840=>1000, 24841=>1000, - 24842=>1000, 24844=>1000, 24845=>1000, 24846=>1000, 24847=>1000, 24848=>1000, 24849=>1000, 24850=>1000, 24851=>1000, 24852=>1000, 24853=>1000, 24854=>1000, 24855=>1000, 24857=>1000, 24858=>1000, 24859=>1000, - 24860=>1000, 24862=>1000, 24863=>1000, 24864=>1000, 24865=>1000, 24866=>1000, 24871=>1000, 24872=>1000, 24874=>1000, 24875=>1000, 24876=>1000, 24880=>1000, 24881=>1000, 24884=>1000, 24885=>1000, 24886=>1000, - 24887=>1000, 24889=>1000, 24892=>1000, 24893=>1000, 24894=>1000, 24895=>1000, 24897=>1000, 24898=>1000, 24900=>1000, 24901=>1000, 24902=>1000, 24903=>1000, 24904=>1000, 24905=>1000, 24906=>1000, 24907=>1000, - 24908=>1000, 24909=>1000, 24910=>1000, 24915=>1000, 24917=>1000, 24920=>1000, 24921=>1000, 24922=>1000, 24925=>1000, 24926=>1000, 24927=>1000, 24928=>1000, 24930=>1000, 24931=>1000, 24933=>1000, 24935=>1000, - 24936=>1000, 24939=>1000, 24940=>1000, 24942=>1000, 24943=>1000, 24944=>1000, 24945=>1000, 24946=>1000, 24947=>1000, 24948=>1000, 24949=>1000, 24950=>1000, 24951=>1000, 24952=>1000, 24955=>1000, 24956=>1000, - 24958=>1000, 24959=>1000, 24960=>1000, 24961=>1000, 24962=>1000, 24963=>1000, 24964=>1000, 24967=>1000, 24970=>1000, 24971=>1000, 24973=>1000, 24974=>1000, 24976=>1000, 24977=>1000, 24978=>1000, 24979=>1000, - 24980=>1000, 24982=>1000, 24983=>1000, 24984=>1000, 24985=>1000, 24986=>1000, 24988=>1000, 24989=>1000, 24991=>1000, 24992=>1000, 24996=>1000, 24997=>1000, 24999=>1000, 25000=>1000, 25001=>1000, 25002=>1000, - 25003=>1000, 25004=>1000, 25005=>1000, 25006=>1000, 25010=>1000, 25014=>1000, 25016=>1000, 25017=>1000, 25018=>1000, 25020=>1000, 25022=>1000, 25024=>1000, 25025=>1000, 25026=>1000, 25027=>1000, 25030=>1000, - 25031=>1000, 25032=>1000, 25033=>1000, 25034=>1000, 25035=>1000, 25036=>1000, 25037=>1000, 25038=>1000, 25039=>1000, 25040=>1000, 25045=>1000, 25052=>1000, 25053=>1000, 25054=>1000, 25055=>1000, 25057=>1000, - 25058=>1000, 25059=>1000, 25061=>1000, 25062=>1000, 25063=>1000, 25065=>1000, 25068=>1000, 25069=>1000, 25071=>1000, 25074=>1000, 25076=>1000, 25078=>1000, 25079=>1000, 25080=>1000, 25082=>1000, 25084=>1000, - 25085=>1000, 25086=>1000, 25087=>1000, 25088=>1000, 25089=>1000, 25091=>1000, 25092=>1000, 25095=>1000, 25096=>1000, 25097=>1000, 25098=>1000, 25100=>1000, 25101=>1000, 25102=>1000, 25104=>1000, 25105=>1000, - 25106=>1000, 25107=>1000, 25108=>1000, 25109=>1000, 25110=>1000, 25114=>1000, 25115=>1000, 25116=>1000, 25117=>1000, 25118=>1000, 25119=>1000, 25120=>1000, 25121=>1000, 25122=>1000, 25123=>1000, 25126=>1000, - 25127=>1000, 25129=>1000, 25130=>1000, 25131=>1000, 25134=>1000, 25135=>1000, 25136=>1000, 25138=>1000, 25139=>1000, 25140=>1000, 25144=>1000, 25145=>1000, 25147=>1000, 25149=>1000, 25151=>1000, 25152=>1000, - 25153=>1000, 25154=>1000, 25155=>1000, 25156=>1000, 25158=>1000, 25159=>1000, 25160=>1000, 25161=>1000, 25163=>1000, 25164=>1000, 25165=>1000, 25166=>1000, 25168=>1000, 25169=>1000, 25170=>1000, 25171=>1000, - 25172=>1000, 25173=>1000, 25174=>1000, 25176=>1000, 25178=>1000, 25179=>1000, 25180=>1000, 25182=>1000, 25184=>1000, 25187=>1000, 25188=>1000, 25192=>1000, 25197=>1000, 25198=>1000, 25199=>1000, 25201=>1000, - 25203=>1000, 25206=>1000, 25209=>1000, 25210=>1000, 25212=>1000, 25213=>1000, 25214=>1000, 25215=>1000, 25216=>1000, 25218=>1000, 25219=>1000, 25220=>1000, 25225=>1000, 25226=>1000, 25229=>1000, 25230=>1000, - 25231=>1000, 25232=>1000, 25233=>1000, 25234=>1000, 25235=>1000, 25236=>1000, 25237=>1000, 25238=>1000, 25239=>1000, 25240=>1000, 25243=>1000, 25244=>1000, 25246=>1000, 25254=>1000, 25256=>1000, 25259=>1000, - 25260=>1000, 25265=>1000, 25267=>1000, 25269=>1000, 25270=>1000, 25271=>1000, 25273=>1000, 25274=>1000, 25275=>1000, 25276=>1000, 25277=>1000, 25278=>1000, 25279=>1000, 25282=>1000, 25284=>1000, 25285=>1000, - 25286=>1000, 25287=>1000, 25288=>1000, 25289=>1000, 25290=>1000, 25292=>1000, 25293=>1000, 25294=>1000, 25295=>1000, 25296=>1000, 25297=>1000, 25298=>1000, 25299=>1000, 25300=>1000, 25301=>1000, 25302=>1000, - 25303=>1000, 25304=>1000, 25305=>1000, 25306=>1000, 25307=>1000, 25308=>1000, 25309=>1000, 25312=>1000, 25313=>1000, 25322=>1000, 25324=>1000, 25325=>1000, 25326=>1000, 25327=>1000, 25329=>1000, 25330=>1000, - 25331=>1000, 25332=>1000, 25333=>1000, 25334=>1000, 25335=>1000, 25340=>1000, 25341=>1000, 25342=>1000, 25343=>1000, 25345=>1000, 25346=>1000, 25347=>1000, 25348=>1000, 25351=>1000, 25352=>1000, 25353=>1000, - 25354=>1000, 25355=>1000, 25356=>1000, 25357=>1000, 25360=>1000, 25361=>1000, 25363=>1000, 25366=>1000, 25368=>1000, 25369=>1000, 25375=>1000, 25383=>1000, 25384=>1000, 25385=>1000, 25386=>1000, 25387=>1000, - 25389=>1000, 25391=>1000, 25397=>1000, 25398=>1000, 25401=>1000, 25402=>1000, 25404=>1000, 25405=>1000, 25406=>1000, 25407=>1000, 25409=>1000, 25410=>1000, 25411=>1000, 25412=>1000, 25414=>1000, 25417=>1000, - 25418=>1000, 25419=>1000, 25420=>1000, 25421=>1000, 25422=>1000, 25423=>1000, 25424=>1000, 25426=>1000, 25427=>1000, 25428=>1000, 25429=>1000, 25431=>1000, 25432=>1000, 25435=>1000, 25436=>1000, 25445=>1000, - 25446=>1000, 25447=>1000, 25448=>1000, 25449=>1000, 25451=>1000, 25452=>1000, 25453=>1000, 25454=>1000, 25457=>1000, 25458=>1000, 25460=>1000, 25461=>1000, 25462=>1000, 25463=>1000, 25464=>1000, 25466=>1000, - 25467=>1000, 25468=>1000, 25469=>1000, 25471=>1000, 25472=>1000, 25474=>1000, 25475=>1000, 25476=>1000, 25479=>1000, 25480=>1000, 25481=>1000, 25482=>1000, 25484=>1000, 25486=>1000, 25487=>1000, 25488=>1000, - 25490=>1000, 25492=>1000, 25493=>1000, 25494=>1000, 25496=>1000, 25497=>1000, 25498=>1000, 25499=>1000, 25502=>1000, 25503=>1000, 25504=>1000, 25505=>1000, 25506=>1000, 25507=>1000, 25508=>1000, 25509=>1000, - 25510=>1000, 25511=>1000, 25512=>1000, 25513=>1000, 25514=>1000, 25515=>1000, 25516=>1000, 25517=>1000, 25518=>1000, 25519=>1000, 25522=>1000, 25524=>1000, 25525=>1000, 25531=>1000, 25533=>1000, 25534=>1000, - 25536=>1000, 25537=>1000, 25539=>1000, 25540=>1000, 25541=>1000, 25542=>1000, 25544=>1000, 25545=>1000, 25550=>1000, 25551=>1000, 25552=>1000, 25553=>1000, 25554=>1000, 25555=>1000, 25556=>1000, 25557=>1000, - 25558=>1000, 25562=>1000, 25563=>1000, 25564=>1000, 25568=>1000, 25569=>1000, 25571=>1000, 25573=>1000, 25577=>1000, 25578=>1000, 25580=>1000, 25582=>1000, 25586=>1000, 25587=>1000, 25588=>1000, 25589=>1000, - 25590=>1000, 25592=>1000, 25593=>1000, 25594=>1000, 25606=>1000, 25609=>1000, 25610=>1000, 25613=>1000, 25615=>1000, 25616=>1000, 25618=>1000, 25619=>1000, 25620=>1000, 25622=>1000, 25623=>1000, 25624=>1000, - 25628=>1000, 25630=>1000, 25632=>1000, 25634=>1000, 25636=>1000, 25637=>1000, 25638=>1000, 25640=>1000, 25641=>1000, 25642=>1000, 25644=>1000, 25645=>1000, 25647=>1000, 25648=>1000, 25652=>1000, 25653=>1000, - 25654=>1000, 25658=>1000, 25661=>1000, 25662=>1000, 25663=>1000, 25666=>1000, 25675=>1000, 25678=>1000, 25679=>1000, 25681=>1000, 25682=>1000, 25683=>1000, 25684=>1000, 25688=>1000, 25690=>1000, 25691=>1000, - 25692=>1000, 25693=>1000, 25695=>1000, 25696=>1000, 25697=>1000, 25699=>1000, 25703=>1000, 25705=>1000, 25709=>1000, 25711=>1000, 25715=>1000, 25716=>1000, 25718=>1000, 25720=>1000, 25722=>1000, 25723=>1000, - 25725=>1000, 25731=>1000, 25733=>1000, 25735=>1000, 25736=>1000, 25743=>1000, 25744=>1000, 25745=>1000, 25746=>1000, 25747=>1000, 25749=>1000, 25752=>1000, 25753=>1000, 25754=>1000, 25755=>1000, 25757=>1000, - 25758=>1000, 25759=>1000, 25761=>1000, 25763=>1000, 25764=>1000, 25765=>1000, 25766=>1000, 25768=>1000, 25769=>1000, 25771=>1000, 25772=>1000, 25773=>1000, 25774=>1000, 25776=>1000, 25778=>1000, 25779=>1000, - 25785=>1000, 25787=>1000, 25788=>1000, 25789=>1000, 25790=>1000, 25791=>1000, 25793=>1000, 25794=>1000, 25796=>1000, 25797=>1000, 25799=>1000, 25801=>1000, 25802=>1000, 25803=>1000, 25804=>1000, 25805=>1000, - 25806=>1000, 25808=>1000, 25809=>1000, 25810=>1000, 25812=>1000, 25813=>1000, 25815=>1000, 25816=>1000, 25818=>1000, 25824=>1000, 25825=>1000, 25826=>1000, 25827=>1000, 25828=>1000, 25829=>1000, 25830=>1000, - 25831=>1000, 25833=>1000, 25834=>1000, 25836=>1000, 25837=>1000, 25839=>1000, 25840=>1000, 25841=>1000, 25842=>1000, 25844=>1000, 25845=>1000, 25846=>1000, 25847=>1000, 25850=>1000, 25851=>1000, 25853=>1000, - 25854=>1000, 25855=>1000, 25856=>1000, 25857=>1000, 25860=>1000, 25861=>1000, 25864=>1000, 25865=>1000, 25866=>1000, 25871=>1000, 25875=>1000, 25876=>1000, 25878=>1000, 25880=>1000, 25881=>1000, 25883=>1000, - 25884=>1000, 25885=>1000, 25886=>1000, 25887=>1000, 25890=>1000, 25891=>1000, 25892=>1000, 25894=>1000, 25897=>1000, 25898=>1000, 25899=>1000, 25900=>1000, 25902=>1000, 25903=>1000, 25905=>1000, 25908=>1000, - 25909=>1000, 25910=>1000, 25911=>1000, 25912=>1000, 25913=>1000, 25914=>1000, 25915=>1000, 25916=>1000, 25917=>1000, 25918=>1000, 25919=>1000, 25923=>1000, 25925=>1000, 25927=>1000, 25928=>1000, 25929=>1000, - 25933=>1000, 25934=>1000, 25935=>1000, 25936=>1000, 25937=>1000, 25938=>1000, 25940=>1000, 25941=>1000, 25942=>1000, 25943=>1000, 25944=>1000, 25945=>1000, 25949=>1000, 25950=>1000, 25951=>1000, 25952=>1000, - 25954=>1000, 25955=>1000, 25958=>1000, 25959=>1000, 25963=>1000, 25964=>1000, 25968=>1000, 25970=>1000, 25972=>1000, 25973=>1000, 25975=>1000, 25976=>1000, 25978=>1000, 25981=>1000, 25985=>1000, 25986=>1000, - 25987=>1000, 25989=>1000, 25991=>1000, 25992=>1000, 25993=>1000, 25994=>1000, 25996=>1000, 25998=>1000, 26000=>1000, 26001=>1000, 26002=>1000, 26005=>1000, 26007=>1000, 26008=>1000, 26009=>1000, 26011=>1000, - 26012=>1000, 26013=>1000, 26015=>1000, 26016=>1000, 26017=>1000, 26019=>1000, 26020=>1000, 26021=>1000, 26022=>1000, 26023=>1000, 26027=>1000, 26028=>1000, 26029=>1000, 26030=>1000, 26031=>1000, 26032=>1000, - 26034=>1000, 26035=>1000, 26036=>1000, 26039=>1000, 26041=>1000, 26044=>1000, 26045=>1000, 26047=>1000, 26049=>1000, 26050=>1000, 26051=>1000, 26052=>1000, 26053=>1000, 26054=>1000, 26056=>1000, 26057=>1000, - 26059=>1000, 26060=>1000, 26062=>1000, 26063=>1000, 26064=>1000, 26066=>1000, 26068=>1000, 26070=>1000, 26071=>1000, 26072=>1000, 26073=>1000, 26075=>1000, 26079=>1000, 26080=>1000, 26081=>1000, 26082=>1000, - 26085=>1000, 26086=>1000, 26087=>1000, 26088=>1000, 26089=>1000, 26092=>1000, 26093=>1000, 26096=>1000, 26097=>1000, 26098=>1000, 26100=>1000, 26101=>1000, 26105=>1000, 26106=>1000, 26107=>1000, 26110=>1000, - 26111=>1000, 26112=>1000, 26114=>1000, 26115=>1000, 26116=>1000, 26118=>1000, 26119=>1000, 26120=>1000, 26121=>1000, 26122=>1000, 26124=>1000, 26125=>1000, 26126=>1000, 26127=>1000, 26129=>1000, 26130=>1000, - 26131=>1000, 26132=>1000, 26133=>1000, 26134=>1000, 26140=>1000, 26141=>1000, 26142=>1000, 26143=>1000, 26144=>1000, 26145=>1000, 26146=>1000, 26147=>1000, 26148=>1000, 26149=>1000, 26150=>1000, 26151=>1000, - 26152=>1000, 26153=>1000, 26154=>1000, 26155=>1000, 26156=>1000, 26157=>1000, 26158=>1000, 26159=>1000, 26160=>1000, 26161=>1000, 26163=>1000, 26164=>1000, 26165=>1000, 26166=>1000, 26167=>1000, 26169=>1000, - 26172=>1000, 26175=>1000, 26176=>1000, 26177=>1000, 26178=>1000, 26179=>1000, 26180=>1000, 26181=>1000, 26182=>1000, 26185=>1000, 26186=>1000, 26187=>1000, 26188=>1000, 26190=>1000, 26191=>1000, 26193=>1000, - 26194=>1000, 26199=>1000, 26200=>1000, 26201=>1000, 26203=>1000, 26204=>1000, 26205=>1000, 26206=>1000, 26207=>1000, 26208=>1000, 26209=>1000, 26210=>1000, 26212=>1000, 26213=>1000, 26214=>1000, 26215=>1000, - 26216=>1000, 26217=>1000, 26218=>1000, 26219=>1000, 26220=>1000, 26222=>1000, 26223=>1000, 26224=>1000, 26227=>1000, 26228=>1000, 26229=>1000, 26230=>1000, 26231=>1000, 26232=>1000, 26233=>1000, 26234=>1000, - 26235=>1000, 26236=>1000, 26238=>1000, 26239=>1000, 26240=>1000, 26241=>1000, 26243=>1000, 26244=>1000, 26247=>1000, 26248=>1000, 26249=>1000, 26251=>1000, 26252=>1000, 26253=>1000, 26254=>1000, 26256=>1000, - 26257=>1000, 26258=>1000, 26262=>1000, 26263=>1000, 26264=>1000, 26265=>1000, 26266=>1000, 26267=>1000, 26268=>1000, 26269=>1000, 26271=>1000, 26272=>1000, 26274=>1000, 26276=>1000, 26278=>1000, 26283=>1000, - 26285=>1000, 26286=>1000, 26289=>1000, 26290=>1000, 26292=>1000, 26293=>1000, 26296=>1000, 26297=>1000, 26299=>1000, 26300=>1000, 26302=>1000, 26303=>1000, 26304=>1000, 26305=>1000, 26306=>1000, 26307=>1000, - 26308=>1000, 26311=>1000, 26312=>1000, 26313=>1000, 26316=>1000, 26318=>1000, 26319=>1000, 26324=>1000, 26326=>1000, 26329=>1000, 26330=>1000, 26331=>1000, 26332=>1000, 26333=>1000, 26335=>1000, 26336=>1000, - 26342=>1000, 26344=>1000, 26345=>1000, 26347=>1000, 26348=>1000, 26350=>1000, 26352=>1000, 26354=>1000, 26355=>1000, 26356=>1000, 26357=>1000, 26359=>1000, 26360=>1000, 26361=>1000, 26362=>1000, 26363=>1000, - 26364=>1000, 26365=>1000, 26366=>1000, 26367=>1000, 26368=>1000, 26371=>1000, 26373=>1000, 26375=>1000, 26376=>1000, 26377=>1000, 26379=>1000, 26381=>1000, 26382=>1000, 26383=>1000, 26387=>1000, 26388=>1000, - 26389=>1000, 26390=>1000, 26391=>1000, 26393=>1000, 26395=>1000, 26396=>1000, 26397=>1000, 26398=>1000, 26399=>1000, 26400=>1000, 26402=>1000, 26406=>1000, 26407=>1000, 26408=>1000, 26410=>1000, 26411=>1000, - 26412=>1000, 26413=>1000, 26414=>1000, 26417=>1000, 26419=>1000, 26420=>1000, 26422=>1000, 26423=>1000, 26424=>1000, 26426=>1000, 26429=>1000, 26430=>1000, 26431=>1000, 26433=>1000, 26437=>1000, 26438=>1000, - 26439=>1000, 26440=>1000, 26441=>1000, 26444=>1000, 26446=>1000, 26447=>1000, 26448=>1000, 26449=>1000, 26451=>1000, 26452=>1000, 26453=>1000, 26454=>1000, 26457=>1000, 26460=>1000, 26461=>1000, 26462=>1000, - 26463=>1000, 26464=>1000, 26465=>1000, 26466=>1000, 26467=>1000, 26468=>1000, 26469=>1000, 26470=>1000, 26474=>1000, 26476=>1000, 26477=>1000, 26478=>1000, 26479=>1000, 26480=>1000, 26481=>1000, 26482=>1000, - 26483=>1000, 26484=>1000, 26485=>1000, 26486=>1000, 26487=>1000, 26491=>1000, 26492=>1000, 26494=>1000, 26495=>1000, 26497=>1000, 26500=>1000, 26501=>1000, 26503=>1000, 26505=>1000, 26507=>1000, 26508=>1000, - 26510=>1000, 26511=>1000, 26512=>1000, 26513=>1000, 26515=>1000, 26517=>1000, 26518=>1000, 26519=>1000, 26520=>1000, 26521=>1000, 26522=>1000, 26523=>1000, 26524=>1000, 26525=>1000, 26528=>1000, 26529=>1000, - 26530=>1000, 26534=>1000, 26537=>1000, 26543=>1000, 26544=>1000, 26545=>1000, 26546=>1000, 26547=>1000, 26548=>1000, 26549=>1000, 26550=>1000, 26551=>1000, 26552=>1000, 26553=>1000, 26555=>1000, 26556=>1000, - 26557=>1000, 26560=>1000, 26561=>1000, 26562=>1000, 26563=>1000, 26564=>1000, 26565=>1000, 26566=>1000, 26568=>1000, 26569=>1000, 26570=>1000, 26574=>1000, 26575=>1000, 26576=>1000, 26577=>1000, 26578=>1000, - 26579=>1000, 26580=>1000, 26583=>1000, 26584=>1000, 26585=>1000, 26586=>1000, 26588=>1000, 26589=>1000, 26590=>1000, 26593=>1000, 26594=>1000, 26596=>1000, 26598=>1000, 26599=>1000, 26601=>1000, 26604=>1000, - 26606=>1000, 26607=>1000, 26608=>1000, 26609=>1000, 26610=>1000, 26611=>1000, 26612=>1000, 26613=>1000, 26614=>1000, 26615=>1000, 26617=>1000, 26619=>1000, 26622=>1000, 26623=>1000, 26625=>1000, 26626=>1000, - 26627=>1000, 26628=>1000, 26643=>1000, 26644=>1000, 26646=>1000, 26647=>1000, 26649=>1000, 26653=>1000, 26654=>1000, 26655=>1000, 26657=>1000, 26658=>1000, 26663=>1000, 26664=>1000, 26665=>1000, 26666=>1000, - 26667=>1000, 26668=>1000, 26669=>1000, 26671=>1000, 26672=>1000, 26673=>1000, 26674=>1000, 26675=>1000, 26676=>1000, 26680=>1000, 26681=>1000, 26683=>1000, 26684=>1000, 26685=>1000, 26687=>1000, 26688=>1000, - 26689=>1000, 26690=>1000, 26691=>1000, 26692=>1000, 26693=>1000, 26694=>1000, 26696=>1000, 26698=>1000, 26700=>1000, 26701=>1000, 26702=>1000, 26704=>1000, 26705=>1000, 26706=>1000, 26707=>1000, 26708=>1000, - 26709=>1000, 26711=>1000, 26712=>1000, 26713=>1000, 26715=>1000, 26716=>1000, 26717=>1000, 26719=>1000, 26723=>1000, 26727=>1000, 26731=>1000, 26734=>1000, 26735=>1000, 26736=>1000, 26737=>1000, 26738=>1000, - 26740=>1000, 26741=>1000, 26742=>1000, 26743=>1000, 26745=>1000, 26746=>1000, 26747=>1000, 26748=>1000, 26750=>1000, 26751=>1000, 26753=>1000, 26754=>1000, 26755=>1000, 26756=>1000, 26757=>1000, 26758=>1000, - 26760=>1000, 26765=>1000, 26767=>1000, 26771=>1000, 26772=>1000, 26774=>1000, 26775=>1000, 26776=>1000, 26778=>1000, 26779=>1000, 26780=>1000, 26781=>1000, 26783=>1000, 26784=>1000, 26785=>1000, 26786=>1000, - 26787=>1000, 26789=>1000, 26790=>1000, 26791=>1000, 26792=>1000, 26793=>1000, 26794=>1000, 26797=>1000, 26798=>1000, 26799=>1000, 26800=>1000, 26801=>1000, 26802=>1000, 26803=>1000, 26805=>1000, 26806=>1000, - 26809=>1000, 26810=>1000, 26811=>1000, 26812=>1000, 26820=>1000, 26821=>1000, 26822=>1000, 26824=>1000, 26825=>1000, 26826=>1000, 26827=>1000, 26828=>1000, 26829=>1000, 26831=>1000, 26832=>1000, 26833=>1000, - 26834=>1000, 26835=>1000, 26836=>1000, 26837=>1000, 26838=>1000, 26839=>1000, 26840=>1000, 26841=>1000, 26842=>1000, 26844=>1000, 26845=>1000, 26847=>1000, 26848=>1000, 26849=>1000, 26851=>1000, 26853=>1000, - 26855=>1000, 26856=>1000, 26858=>1000, 26859=>1000, 26860=>1000, 26861=>1000, 26862=>1000, 26863=>1000, 26864=>1000, 26865=>1000, 26866=>1000, 26869=>1000, 26870=>1000, 26873=>1000, 26874=>1000, 26875=>1000, - 26876=>1000, 26877=>1000, 26880=>1000, 26881=>1000, 26884=>1000, 26885=>1000, 26886=>1000, 26888=>1000, 26889=>1000, 26890=>1000, 26891=>1000, 26892=>1000, 26893=>1000, 26894=>1000, 26895=>1000, 26896=>1000, - 26897=>1000, 26898=>1000, 26899=>1000, 26902=>1000, 26903=>1000, 26905=>1000, 26906=>1000, 26907=>1000, 26908=>1000, 26913=>1000, 26914=>1000, 26915=>1000, 26917=>1000, 26918=>1000, 26920=>1000, 26922=>1000, - 26928=>1000, 26929=>1000, 26931=>1000, 26932=>1000, 26933=>1000, 26934=>1000, 26936=>1000, 26937=>1000, 26939=>1000, 26941=>1000, 26943=>1000, 26946=>1000, 26949=>1000, 26953=>1000, 26954=>1000, 26958=>1000, - 26963=>1000, 26964=>1000, 26965=>1000, 26967=>1000, 26969=>1000, 26970=>1000, 26971=>1000, 26972=>1000, 26973=>1000, 26974=>1000, 26976=>1000, 26977=>1000, 26978=>1000, 26979=>1000, 26980=>1000, 26981=>1000, - 26982=>1000, 26984=>1000, 26985=>1000, 26986=>1000, 26987=>1000, 26988=>1000, 26989=>1000, 26990=>1000, 26991=>1000, 26992=>1000, 26993=>1000, 26994=>1000, 26995=>1000, 26996=>1000, 26997=>1000, 26999=>1000, - 27000=>1000, 27001=>1000, 27002=>1000, 27003=>1000, 27004=>1000, 27005=>1000, 27006=>1000, 27007=>1000, 27008=>1000, 27009=>1000, 27010=>1000, 27018=>1000, 27021=>1000, 27022=>1000, 27025=>1000, 27026=>1000, - 27028=>1000, 27029=>1000, 27030=>1000, 27032=>1000, 27035=>1000, 27036=>1000, 27040=>1000, 27041=>1000, 27045=>1000, 27046=>1000, 27047=>1000, 27048=>1000, 27051=>1000, 27053=>1000, 27054=>1000, 27055=>1000, - 27057=>1000, 27058=>1000, 27060=>1000, 27063=>1000, 27064=>1000, 27066=>1000, 27067=>1000, 27068=>1000, 27070=>1000, 27071=>1000, 27073=>1000, 27075=>1000, 27077=>1000, 27079=>1000, 27080=>1000, 27082=>1000, - 27083=>1000, 27084=>1000, 27085=>1000, 27086=>1000, 27088=>1000, 27089=>1000, 27091=>1000, 27094=>1000, 27095=>1000, 27096=>1000, 27097=>1000, 27101=>1000, 27102=>1000, 27106=>1000, 27109=>1000, 27111=>1000, - 27112=>1000, 27115=>1000, 27117=>1000, 27118=>1000, 27119=>1000, 27121=>1000, 27122=>1000, 27123=>1000, 27125=>1000, 27129=>1000, 27131=>1000, 27133=>1000, 27134=>1000, 27135=>1000, 27136=>1000, 27137=>1000, - 27138=>1000, 27139=>1000, 27141=>1000, 27146=>1000, 27147=>1000, 27148=>1000, 27151=>1000, 27153=>1000, 27154=>1000, 27155=>1000, 27156=>1000, 27157=>1000, 27159=>1000, 27161=>1000, 27162=>1000, 27163=>1000, - 27165=>1000, 27166=>1000, 27167=>1000, 27168=>1000, 27169=>1000, 27170=>1000, 27171=>1000, 27172=>1000, 27176=>1000, 27177=>1000, 27178=>1000, 27179=>1000, 27182=>1000, 27184=>1000, 27186=>1000, 27188=>1000, - 27189=>1000, 27190=>1000, 27191=>1000, 27192=>1000, 27193=>1000, 27194=>1000, 27195=>1000, 27197=>1000, 27198=>1000, 27199=>1000, 27204=>1000, 27205=>1000, 27206=>1000, 27207=>1000, 27208=>1000, 27209=>1000, - 27210=>1000, 27211=>1000, 27214=>1000, 27216=>1000, 27217=>1000, 27218=>1000, 27221=>1000, 27222=>1000, 27224=>1000, 27225=>1000, 27227=>1000, 27231=>1000, 27233=>1000, 27234=>1000, 27236=>1000, 27238=>1000, - 27239=>1000, 27242=>1000, 27243=>1000, 27249=>1000, 27250=>1000, 27251=>1000, 27256=>1000, 27262=>1000, 27263=>1000, 27264=>1000, 27265=>1000, 27267=>1000, 27268=>1000, 27270=>1000, 27271=>1000, 27273=>1000, - 27275=>1000, 27277=>1000, 27278=>1000, 27280=>1000, 27281=>1000, 27287=>1000, 27291=>1000, 27292=>1000, 27293=>1000, 27294=>1000, 27295=>1000, 27296=>1000, 27298=>1000, 27299=>1000, 27301=>1000, 27306=>1000, - 27307=>1000, 27308=>1000, 27310=>1000, 27311=>1000, 27312=>1000, 27313=>1000, 27315=>1000, 27316=>1000, 27320=>1000, 27323=>1000, 27325=>1000, 27326=>1000, 27327=>1000, 27329=>1000, 27330=>1000, 27331=>1000, - 27334=>1000, 27336=>1000, 27337=>1000, 27340=>1000, 27344=>1000, 27345=>1000, 27347=>1000, 27348=>1000, 27349=>1000, 27350=>1000, 27354=>1000, 27355=>1000, 27356=>1000, 27357=>1000, 27358=>1000, 27359=>1000, - 27362=>1000, 27364=>1000, 27367=>1000, 27368=>1000, 27370=>1000, 27372=>1000, 27376=>1000, 27377=>1000, 27378=>1000, 27386=>1000, 27387=>1000, 27388=>1000, 27389=>1000, 27394=>1000, 27395=>1000, 27396=>1000, - 27397=>1000, 27398=>1000, 27399=>1000, 27401=>1000, 27402=>1000, 27407=>1000, 27408=>1000, 27409=>1000, 27410=>1000, 27414=>1000, 27415=>1000, 27419=>1000, 27421=>1000, 27422=>1000, 27423=>1000, 27424=>1000, - 27425=>1000, 27427=>1000, 27428=>1000, 27431=>1000, 27432=>1000, 27435=>1000, 27436=>1000, 27439=>1000, 27442=>1000, 27445=>1000, 27446=>1000, 27447=>1000, 27448=>1000, 27449=>1000, 27450=>1000, 27451=>1000, - 27453=>1000, 27454=>1000, 27455=>1000, 27459=>1000, 27462=>1000, 27463=>1000, 27465=>1000, 27466=>1000, 27468=>1000, 27469=>1000, 27470=>1000, 27472=>1000, 27474=>1000, 27475=>1000, 27476=>1000, 27478=>1000, - 27480=>1000, 27481=>1000, 27483=>1000, 27485=>1000, 27487=>1000, 27488=>1000, 27489=>1000, 27490=>1000, 27491=>1000, 27492=>1000, 27494=>1000, 27495=>1000, 27497=>1000, 27498=>1000, 27499=>1000, 27502=>1000, - 27503=>1000, 27504=>1000, 27507=>1000, 27508=>1000, 27509=>1000, 27512=>1000, 27513=>1000, 27515=>1000, 27517=>1000, 27518=>1000, 27519=>1000, 27520=>1000, 27522=>1000, 27523=>1000, 27524=>1000, 27525=>1000, - 27526=>1000, 27529=>1000, 27530=>1000, 27531=>1000, 27533=>1000, 27541=>1000, 27542=>1000, 27543=>1000, 27544=>1000, 27547=>1000, 27550=>1000, 27551=>1000, 27552=>1000, 27554=>1000, 27555=>1000, 27556=>1000, - 27560=>1000, 27561=>1000, 27562=>1000, 27563=>1000, 27564=>1000, 27565=>1000, 27566=>1000, 27567=>1000, 27568=>1000, 27569=>1000, 27570=>1000, 27571=>1000, 27572=>1000, 27573=>1000, 27575=>1000, 27576=>1000, - 27577=>1000, 27578=>1000, 27579=>1000, 27580=>1000, 27581=>1000, 27582=>1000, 27583=>1000, 27584=>1000, 27587=>1000, 27588=>1000, 27589=>1000, 27590=>1000, 27593=>1000, 27595=>1000, 27596=>1000, 27597=>1000, - 27598=>1000, 27602=>1000, 27603=>1000, 27604=>1000, 27606=>1000, 27608=>1000, 27610=>1000, 27611=>1000, 27615=>1000, 27617=>1000, 27619=>1000, 27622=>1000, 27623=>1000, 27627=>1000, 27628=>1000, 27630=>1000, - 27631=>1000, 27633=>1000, 27635=>1000, 27639=>1000, 27641=>1000, 27647=>1000, 27650=>1000, 27652=>1000, 27653=>1000, 27656=>1000, 27657=>1000, 27661=>1000, 27662=>1000, 27663=>1000, 27664=>1000, 27665=>1000, - 27666=>1000, 27667=>1000, 27668=>1000, 27671=>1000, 27673=>1000, 27675=>1000, 27679=>1000, 27683=>1000, 27684=>1000, 27686=>1000, 27687=>1000, 27688=>1000, 27692=>1000, 27694=>1000, 27699=>1000, 27700=>1000, - 27701=>1000, 27702=>1000, 27703=>1000, 27704=>1000, 27706=>1000, 27707=>1000, 27710=>1000, 27711=>1000, 27712=>1000, 27713=>1000, 27714=>1000, 27722=>1000, 27723=>1000, 27725=>1000, 27726=>1000, 27727=>1000, - 27728=>1000, 27730=>1000, 27732=>1000, 27733=>1000, 27735=>1000, 27737=>1000, 27738=>1000, 27739=>1000, 27740=>1000, 27741=>1000, 27742=>1000, 27743=>1000, 27744=>1000, 27746=>1000, 27751=>1000, 27752=>1000, - 27754=>1000, 27755=>1000, 27757=>1000, 27759=>1000, 27760=>1000, 27762=>1000, 27763=>1000, 27764=>1000, 27766=>1000, 27768=>1000, 27769=>1000, 27770=>1000, 27771=>1000, 27773=>1000, 27774=>1000, 27777=>1000, - 27778=>1000, 27779=>1000, 27781=>1000, 27782=>1000, 27783=>1000, 27784=>1000, 27785=>1000, 27788=>1000, 27789=>1000, 27792=>1000, 27794=>1000, 27795=>1000, 27796=>1000, 27797=>1000, 27798=>1000, 27799=>1000, - 27800=>1000, 27801=>1000, 27802=>1000, 27803=>1000, 27804=>1000, 27807=>1000, 27809=>1000, 27810=>1000, 27819=>1000, 27822=>1000, 27824=>1000, 27825=>1000, 27826=>1000, 27827=>1000, 27828=>1000, 27832=>1000, - 27833=>1000, 27834=>1000, 27835=>1000, 27836=>1000, 27837=>1000, 27838=>1000, 27839=>1000, 27841=>1000, 27842=>1000, 27844=>1000, 27845=>1000, 27846=>1000, 27849=>1000, 27850=>1000, 27852=>1000, 27853=>1000, - 27855=>1000, 27856=>1000, 27857=>1000, 27858=>1000, 27859=>1000, 27860=>1000, 27861=>1000, 27862=>1000, 27863=>1000, 27865=>1000, 27866=>1000, 27867=>1000, 27868=>1000, 27869=>1000, 27872=>1000, 27873=>1000, - 27874=>1000, 27875=>1000, 27877=>1000, 27879=>1000, 27880=>1000, 27881=>1000, 27882=>1000, 27883=>1000, 27884=>1000, 27886=>1000, 27887=>1000, 27888=>1000, 27889=>1000, 27890=>1000, 27891=>1000, 27892=>1000, - 27908=>1000, 27911=>1000, 27914=>1000, 27915=>1000, 27916=>1000, 27918=>1000, 27919=>1000, 27921=>1000, 27922=>1000, 27923=>1000, 27927=>1000, 27929=>1000, 27930=>1000, 27931=>1000, 27934=>1000, 27935=>1000, - 27941=>1000, 27942=>1000, 27943=>1000, 27944=>1000, 27945=>1000, 27946=>1000, 27947=>1000, 27950=>1000, 27951=>1000, 27953=>1000, 27954=>1000, 27955=>1000, 27957=>1000, 27958=>1000, 27960=>1000, 27961=>1000, - 27963=>1000, 27964=>1000, 27965=>1000, 27966=>1000, 27967=>1000, 27969=>1000, 27972=>1000, 27973=>1000, 27991=>1000, 27993=>1000, 27994=>1000, 27996=>1000, 27998=>1000, 27999=>1000, 28001=>1000, 28003=>1000, - 28004=>1000, 28005=>1000, 28006=>1000, 28007=>1000, 28009=>1000, 28010=>1000, 28012=>1000, 28014=>1000, 28015=>1000, 28016=>1000, 28020=>1000, 28023=>1000, 28024=>1000, 28025=>1000, 28028=>1000, 28034=>1000, - 28037=>1000, 28039=>1000, 28040=>1000, 28044=>1000, 28046=>1000, 28049=>1000, 28050=>1000, 28051=>1000, 28052=>1000, 28053=>1000, 28054=>1000, 28055=>1000, 28056=>1000, 28057=>1000, 28059=>1000, 28060=>1000, - 28074=>1000, 28076=>1000, 28079=>1000, 28082=>1000, 28084=>1000, 28085=>1000, 28087=>1000, 28088=>1000, 28089=>1000, 28092=>1000, 28093=>1000, 28095=>1000, 28096=>1000, 28100=>1000, 28101=>1000, 28102=>1000, - 28103=>1000, 28104=>1000, 28106=>1000, 28107=>1000, 28108=>1000, 28110=>1000, 28111=>1000, 28113=>1000, 28114=>1000, 28117=>1000, 28118=>1000, 28120=>1000, 28121=>1000, 28123=>1000, 28125=>1000, 28126=>1000, - 28127=>1000, 28128=>1000, 28129=>1000, 28130=>1000, 28132=>1000, 28133=>1000, 28134=>1000, 28136=>1000, 28137=>1000, 28138=>1000, 28139=>1000, 28140=>1000, 28142=>1000, 28143=>1000, 28144=>1000, 28145=>1000, - 28146=>1000, 28147=>1000, 28148=>1000, 28149=>1000, 28150=>1000, 28151=>1000, 28152=>1000, 28153=>1000, 28154=>1000, 28155=>1000, 28156=>1000, 28160=>1000, 28164=>1000, 28165=>1000, 28167=>1000, 28168=>1000, - 28169=>1000, 28170=>1000, 28171=>1000, 28179=>1000, 28181=>1000, 28185=>1000, 28186=>1000, 28187=>1000, 28189=>1000, 28190=>1000, 28191=>1000, 28192=>1000, 28193=>1000, 28194=>1000, 28195=>1000, 28196=>1000, - 28197=>1000, 28198=>1000, 28199=>1000, 28201=>1000, 28203=>1000, 28204=>1000, 28205=>1000, 28206=>1000, 28207=>1000, 28210=>1000, 28214=>1000, 28216=>1000, 28217=>1000, 28218=>1000, 28219=>1000, 28220=>1000, - 28222=>1000, 28227=>1000, 28228=>1000, 28229=>1000, 28232=>1000, 28233=>1000, 28234=>1000, 28235=>1000, 28237=>1000, 28238=>1000, 28239=>1000, 28241=>1000, 28242=>1000, 28243=>1000, 28244=>1000, 28246=>1000, - 28247=>1000, 28248=>1000, 28251=>1000, 28252=>1000, 28253=>1000, 28254=>1000, 28255=>1000, 28258=>1000, 28259=>1000, 28263=>1000, 28264=>1000, 28267=>1000, 28270=>1000, 28271=>1000, 28274=>1000, 28275=>1000, - 28278=>1000, 28283=>1000, 28285=>1000, 28286=>1000, 28287=>1000, 28288=>1000, 28290=>1000, 28300=>1000, 28301=>1000, 28303=>1000, 28304=>1000, 28307=>1000, 28310=>1000, 28312=>1000, 28313=>1000, 28316=>1000, - 28317=>1000, 28319=>1000, 28320=>1000, 28322=>1000, 28325=>1000, 28327=>1000, 28330=>1000, 28333=>1000, 28334=>1000, 28335=>1000, 28337=>1000, 28338=>1000, 28339=>1000, 28342=>1000, 28343=>1000, 28346=>1000, - 28347=>1000, 28349=>1000, 28351=>1000, 28352=>1000, 28353=>1000, 28354=>1000, 28355=>1000, 28356=>1000, 28357=>1000, 28359=>1000, 28360=>1000, 28361=>1000, 28362=>1000, 28363=>1000, 28364=>1000, 28365=>1000, - 28366=>1000, 28367=>1000, 28369=>1000, 28371=>1000, 28372=>1000, 28373=>1000, 28381=>1000, 28382=>1000, 28395=>1000, 28396=>1000, 28397=>1000, 28398=>1000, 28399=>1000, 28402=>1000, 28404=>1000, 28407=>1000, - 28408=>1000, 28409=>1000, 28411=>1000, 28413=>1000, 28414=>1000, 28415=>1000, 28417=>1000, 28418=>1000, 28420=>1000, 28422=>1000, 28424=>1000, 28425=>1000, 28426=>1000, 28428=>1000, 28429=>1000, 28431=>1000, - 28433=>1000, 28435=>1000, 28436=>1000, 28437=>1000, 28438=>1000, 28440=>1000, 28442=>1000, 28443=>1000, 28448=>1000, 28450=>1000, 28451=>1000, 28454=>1000, 28457=>1000, 28458=>1000, 28459=>1000, 28460=>1000, - 28461=>1000, 28463=>1000, 28464=>1000, 28465=>1000, 28466=>1000, 28467=>1000, 28470=>1000, 28472=>1000, 28475=>1000, 28476=>1000, 28478=>1000, 28479=>1000, 28481=>1000, 28485=>1000, 28495=>1000, 28497=>1000, - 28498=>1000, 28499=>1000, 28500=>1000, 28503=>1000, 28504=>1000, 28505=>1000, 28506=>1000, 28507=>1000, 28508=>1000, 28509=>1000, 28510=>1000, 28511=>1000, 28513=>1000, 28514=>1000, 28516=>1000, 28518=>1000, - 28520=>1000, 28524=>1000, 28525=>1000, 28526=>1000, 28527=>1000, 28528=>1000, 28532=>1000, 28536=>1000, 28538=>1000, 28540=>1000, 28541=>1000, 28542=>1000, 28544=>1000, 28545=>1000, 28546=>1000, 28547=>1000, - 28548=>1000, 28550=>1000, 28551=>1000, 28552=>1000, 28555=>1000, 28556=>1000, 28557=>1000, 28558=>1000, 28560=>1000, 28561=>1000, 28562=>1000, 28563=>1000, 28564=>1000, 28566=>1000, 28567=>1000, 28570=>1000, - 28575=>1000, 28576=>1000, 28577=>1000, 28579=>1000, 28580=>1000, 28581=>1000, 28582=>1000, 28583=>1000, 28584=>1000, 28586=>1000, 28590=>1000, 28591=>1000, 28592=>1000, 28593=>1000, 28595=>1000, 28597=>1000, - 28598=>1000, 28601=>1000, 28604=>1000, 28608=>1000, 28609=>1000, 28610=>1000, 28611=>1000, 28613=>1000, 28614=>1000, 28615=>1000, 28616=>1000, 28618=>1000, 28628=>1000, 28629=>1000, 28632=>1000, 28634=>1000, - 28635=>1000, 28638=>1000, 28639=>1000, 28640=>1000, 28641=>1000, 28644=>1000, 28648=>1000, 28649=>1000, 28651=>1000, 28652=>1000, 28654=>1000, 28655=>1000, 28656=>1000, 28657=>1000, 28659=>1000, 28661=>1000, - 28662=>1000, 28665=>1000, 28666=>1000, 28668=>1000, 28669=>1000, 28670=>1000, 28672=>1000, 28673=>1000, 28677=>1000, 28678=>1000, 28679=>1000, 28681=>1000, 28683=>1000, 28685=>1000, 28687=>1000, 28689=>1000, - 28693=>1000, 28695=>1000, 28696=>1000, 28698=>1000, 28699=>1000, 28701=>1000, 28702=>1000, 28703=>1000, 28704=>1000, 28707=>1000, 28710=>1000, 28711=>1000, 28712=>1000, 28716=>1000, 28719=>1000, 28720=>1000, - 28722=>1000, 28724=>1000, 28727=>1000, 28729=>1000, 28732=>1000, 28734=>1000, 28739=>1000, 28740=>1000, 28744=>1000, 28745=>1000, 28746=>1000, 28747=>1000, 28748=>1000, 28750=>1000, 28753=>1000, 28756=>1000, - 28757=>1000, 28760=>1000, 28765=>1000, 28766=>1000, 28771=>1000, 28772=>1000, 28773=>1000, 28779=>1000, 28780=>1000, 28782=>1000, 28783=>1000, 28784=>1000, 28789=>1000, 28790=>1000, 28792=>1000, 28796=>1000, - 28797=>1000, 28798=>1000, 28801=>1000, 28805=>1000, 28806=>1000, 28809=>1000, 28810=>1000, 28814=>1000, 28818=>1000, 28820=>1000, 28821=>1000, 28822=>1000, 28823=>1000, 28824=>1000, 28825=>1000, 28827=>1000, - 28836=>1000, 28843=>1000, 28844=>1000, 28845=>1000, 28846=>1000, 28847=>1000, 28848=>1000, 28849=>1000, 28851=>1000, 28852=>1000, 28855=>1000, 28856=>1000, 28857=>1000, 28858=>1000, 28859=>1000, 28872=>1000, - 28874=>1000, 28875=>1000, 28879=>1000, 28881=>1000, 28883=>1000, 28884=>1000, 28885=>1000, 28886=>1000, 28888=>1000, 28889=>1000, 28892=>1000, 28893=>1000, 28895=>1000, 28900=>1000, 28913=>1000, 28921=>1000, - 28922=>1000, 28925=>1000, 28931=>1000, 28932=>1000, 28933=>1000, 28934=>1000, 28935=>1000, 28937=>1000, 28939=>1000, 28940=>1000, 28943=>1000, 28948=>1000, 28953=>1000, 28954=>1000, 28956=>1000, 28958=>1000, - 28960=>1000, 28961=>1000, 28966=>1000, 28971=>1000, 28973=>1000, 28975=>1000, 28976=>1000, 28977=>1000, 28982=>1000, 28984=>1000, 28988=>1000, 28993=>1000, 28997=>1000, 28998=>1000, 28999=>1000, 29001=>1000, - 29002=>1000, 29003=>1000, 29004=>1000, 29006=>1000, 29008=>1000, 29010=>1000, 29013=>1000, 29014=>1000, 29015=>1000, 29017=>1000, 29018=>1000, 29020=>1000, 29022=>1000, 29024=>1000, 29026=>1000, 29028=>1000, - 29029=>1000, 29030=>1000, 29031=>1000, 29032=>1000, 29033=>1000, 29036=>1000, 29038=>1000, 29049=>1000, 29053=>1000, 29056=>1000, 29060=>1000, 29061=>1000, 29063=>1000, 29064=>1000, 29066=>1000, 29068=>1000, - 29071=>1000, 29074=>1000, 29076=>1000, 29077=>1000, 29081=>1000, 29082=>1000, 29083=>1000, 29087=>1000, 29088=>1000, 29090=>1000, 29096=>1000, 29100=>1000, 29103=>1000, 29104=>1000, 29105=>1000, 29106=>1000, - 29107=>1000, 29113=>1000, 29114=>1000, 29118=>1000, 29119=>1000, 29120=>1000, 29121=>1000, 29123=>1000, 29124=>1000, 29128=>1000, 29129=>1000, 29131=>1000, 29132=>1000, 29134=>1000, 29136=>1000, 29138=>1000, - 29139=>1000, 29140=>1000, 29141=>1000, 29142=>1000, 29143=>1000, 29145=>1000, 29146=>1000, 29148=>1000, 29151=>1000, 29152=>1000, 29157=>1000, 29158=>1000, 29159=>1000, 29164=>1000, 29165=>1000, 29166=>1000, - 29173=>1000, 29176=>1000, 29177=>1000, 29179=>1000, 29180=>1000, 29182=>1000, 29183=>1000, 29184=>1000, 29190=>1000, 29191=>1000, 29192=>1000, 29193=>1000, 29197=>1000, 29200=>1000, 29203=>1000, 29207=>1000, - 29210=>1000, 29211=>1000, 29213=>1000, 29215=>1000, 29220=>1000, 29224=>1000, 29226=>1000, 29227=>1000, 29228=>1000, 29229=>1000, 29231=>1000, 29232=>1000, 29234=>1000, 29236=>1000, 29237=>1000, 29238=>1000, - 29240=>1000, 29241=>1000, 29242=>1000, 29243=>1000, 29244=>1000, 29245=>1000, 29246=>1000, 29247=>1000, 29248=>1000, 29249=>1000, 29250=>1000, 29251=>1000, 29253=>1000, 29254=>1000, 29255=>1000, 29256=>1000, - 29259=>1000, 29260=>1000, 29262=>1000, 29263=>1000, 29264=>1000, 29266=>1000, 29267=>1000, 29269=>1000, 29270=>1000, 29272=>1000, 29273=>1000, 29274=>1000, 29275=>1000, 29276=>1000, 29277=>1000, 29278=>1000, - 29279=>1000, 29280=>1000, 29281=>1000, 29282=>1000, 29283=>1000, 29287=>1000, 29288=>1000, 29289=>1000, 29291=>1000, 29294=>1000, 29295=>1000, 29297=>1000, 29298=>1000, 29300=>1000, 29303=>1000, 29304=>1000, - 29305=>1000, 29307=>1000, 29308=>1000, 29309=>1000, 29310=>1000, 29311=>1000, 29312=>1000, 29313=>1000, 29314=>1000, 29316=>1000, 29319=>1000, 29321=>1000, 29325=>1000, 29326=>1000, 29330=>1000, 29331=>1000, - 29334=>1000, 29339=>1000, 29344=>1000, 29346=>1000, 29351=>1000, 29352=>1000, 29356=>1000, 29357=>1000, 29358=>1000, 29359=>1000, 29361=>1000, 29362=>1000, 29364=>1000, 29366=>1000, 29369=>1000, 29374=>1000, - 29377=>1000, 29378=>1000, 29379=>1000, 29380=>1000, 29382=>1000, 29383=>1000, 29385=>1000, 29388=>1000, 29390=>1000, 29392=>1000, 29394=>1000, 29397=>1000, 29398=>1000, 29399=>1000, 29400=>1000, 29401=>1000, - 29403=>1000, 29407=>1000, 29408=>1000, 29409=>1000, 29410=>1000, 29413=>1000, 29417=>1000, 29420=>1000, 29421=>1000, 29427=>1000, 29428=>1000, 29431=>1000, 29432=>1000, 29433=>1000, 29434=>1000, 29435=>1000, - 29436=>1000, 29437=>1000, 29438=>1000, 29442=>1000, 29444=>1000, 29445=>1000, 29447=>1000, 29450=>1000, 29451=>1000, 29453=>1000, 29458=>1000, 29459=>1000, 29462=>1000, 29463=>1000, 29464=>1000, 29465=>1000, - 29467=>1000, 29468=>1000, 29469=>1000, 29470=>1000, 29471=>1000, 29474=>1000, 29476=>1000, 29477=>1000, 29479=>1000, 29480=>1000, 29481=>1000, 29482=>1000, 29483=>1000, 29484=>1000, 29486=>1000, 29487=>1000, - 29489=>1000, 29490=>1000, 29492=>1000, 29493=>1000, 29494=>1000, 29495=>1000, 29498=>1000, 29499=>1000, 29501=>1000, 29502=>1000, 29503=>1000, 29507=>1000, 29508=>1000, 29509=>1000, 29517=>1000, 29518=>1000, - 29519=>1000, 29520=>1000, 29522=>1000, 29526=>1000, 29527=>1000, 29528=>1000, 29533=>1000, 29534=>1000, 29535=>1000, 29536=>1000, 29539=>1000, 29542=>1000, 29543=>1000, 29544=>1000, 29545=>1000, 29546=>1000, - 29547=>1000, 29548=>1000, 29550=>1000, 29551=>1000, 29552=>1000, 29553=>1000, 29554=>1000, 29557=>1000, 29559=>1000, 29560=>1000, 29561=>1000, 29562=>1000, 29563=>1000, 29564=>1000, 29568=>1000, 29569=>1000, - 29571=>1000, 29572=>1000, 29573=>1000, 29574=>1000, 29575=>1000, 29577=>1000, 29579=>1000, 29582=>1000, 29584=>1000, 29587=>1000, 29589=>1000, 29590=>1000, 29591=>1000, 29592=>1000, 29596=>1000, 29598=>1000, - 29599=>1000, 29600=>1000, 29602=>1000, 29605=>1000, 29606=>1000, 29609=>1000, 29610=>1000, 29611=>1000, 29613=>1000, 29618=>1000, 29619=>1000, 29621=>1000, 29623=>1000, 29625=>1000, 29627=>1000, 29628=>1000, - 29629=>1000, 29631=>1000, 29632=>1000, 29634=>1000, 29637=>1000, 29638=>1000, 29640=>1000, 29641=>1000, 29642=>1000, 29643=>1000, 29644=>1000, 29645=>1000, 29646=>1000, 29647=>1000, 29650=>1000, 29651=>1000, - 29654=>1000, 29657=>1000, 29661=>1000, 29662=>1000, 29664=>1000, 29665=>1000, 29667=>1000, 29669=>1000, 29670=>1000, 29671=>1000, 29673=>1000, 29674=>1000, 29677=>1000, 29678=>1000, 29681=>1000, 29684=>1000, - 29685=>1000, 29687=>1000, 29688=>1000, 29689=>1000, 29690=>1000, 29691=>1000, 29693=>1000, 29694=>1000, 29695=>1000, 29696=>1000, 29697=>1000, 29699=>1000, 29700=>1000, 29701=>1000, 29702=>1000, 29703=>1000, - 29705=>1000, 29706=>1000, 29713=>1000, 29722=>1000, 29723=>1000, 29730=>1000, 29732=>1000, 29733=>1000, 29734=>1000, 29736=>1000, 29737=>1000, 29738=>1000, 29739=>1000, 29740=>1000, 29741=>1000, 29742=>1000, - 29743=>1000, 29744=>1000, 29745=>1000, 29746=>1000, 29747=>1000, 29748=>1000, 29749=>1000, 29750=>1000, 29753=>1000, 29754=>1000, 29759=>1000, 29760=>1000, 29761=>1000, 29763=>1000, 29764=>1000, 29766=>1000, - 29767=>1000, 29771=>1000, 29773=>1000, 29777=>1000, 29778=>1000, 29781=>1000, 29783=>1000, 29785=>1000, 29786=>1000, 29787=>1000, 29788=>1000, 29789=>1000, 29790=>1000, 29791=>1000, 29792=>1000, 29794=>1000, - 29795=>1000, 29796=>1000, 29798=>1000, 29799=>1000, 29800=>1000, 29801=>1000, 29802=>1000, 29803=>1000, 29805=>1000, 29806=>1000, 29807=>1000, 29808=>1000, 29809=>1000, 29810=>1000, 29811=>1000, 29814=>1000, - 29822=>1000, 29824=>1000, 29825=>1000, 29827=>1000, 29829=>1000, 29830=>1000, 29831=>1000, 29833=>1000, 29835=>1000, 29839=>1000, 29840=>1000, 29841=>1000, 29842=>1000, 29848=>1000, 29849=>1000, 29850=>1000, - 29852=>1000, 29854=>1000, 29855=>1000, 29856=>1000, 29857=>1000, 29858=>1000, 29859=>1000, 29862=>1000, 29863=>1000, 29864=>1000, 29865=>1000, 29866=>1000, 29867=>1000, 29870=>1000, 29871=>1000, 29872=>1000, - 29873=>1000, 29874=>1000, 29877=>1000, 29881=>1000, 29883=>1000, 29885=>1000, 29887=>1000, 29896=>1000, 29897=>1000, 29898=>1000, 29900=>1000, 29903=>1000, 29904=>1000, 29907=>1000, 29908=>1000, 29912=>1000, - 29914=>1000, 29915=>1000, 29916=>1000, 29918=>1000, 29919=>1000, 29920=>1000, 29922=>1000, 29923=>1000, 29924=>1000, 29926=>1000, 29927=>1000, 29928=>1000, 29929=>1000, 29930=>1000, 29931=>1000, 29934=>1000, - 29935=>1000, 29936=>1000, 29937=>1000, 29938=>1000, 29940=>1000, 29942=>1000, 29943=>1000, 29944=>1000, 29946=>1000, 29947=>1000, 29948=>1000, 29951=>1000, 29953=>1000, 29955=>1000, 29956=>1000, 29957=>1000, - 29958=>1000, 29964=>1000, 29965=>1000, 29966=>1000, 29969=>1000, 29970=>1000, 29971=>1000, 29973=>1000, 29974=>1000, 29975=>1000, 29976=>1000, 29978=>1000, 29980=>1000, 29982=>1000, 29983=>1000, 29984=>1000, - 29985=>1000, 29987=>1000, 29988=>1000, 29989=>1000, 29990=>1000, 29991=>1000, 29992=>1000, 29993=>1000, 29994=>1000, 29995=>1000, 29996=>1000, 29999=>1000, 30000=>1000, 30001=>1000, 30002=>1000, 30003=>1000, - 30006=>1000, 30007=>1000, 30008=>1000, 30009=>1000, 30010=>1000, 30011=>1000, 30012=>1000, 30013=>1000, 30014=>1000, 30015=>1000, 30016=>1000, 30019=>1000, 30020=>1000, 30022=>1000, 30023=>1000, 30024=>1000, - 30025=>1000, 30026=>1000, 30027=>1000, 30028=>1000, 30029=>1000, 30030=>1000, 30031=>1000, 30032=>1000, 30033=>1000, 30034=>1000, 30036=>1000, 30039=>1000, 30041=>1000, 30042=>1000, 30043=>1000, 30044=>1000, - 30045=>1000, 30046=>1000, 30047=>1000, 30048=>1000, 30049=>1000, 30050=>1000, 30052=>1000, 30053=>1000, 30054=>1000, 30055=>1000, 30057=>1000, 30058=>1000, 30059=>1000, 30061=>1000, 30063=>1000, 30064=>1000, - 30065=>1000, 30067=>1000, 30068=>1000, 30070=>1000, 30071=>1000, 30072=>1000, 30073=>1000, 30074=>1000, 30075=>1000, 30076=>1000, 30077=>1000, 30078=>1000, 30079=>1000, 30081=>1000, 30082=>1000, 30085=>1000, - 30086=>1000, 30087=>1000, 30089=>1000, 30090=>1000, 30091=>1000, 30094=>1000, 30095=>1000, 30096=>1000, 30097=>1000, 30098=>1000, 30099=>1000, 30100=>1000, 30101=>1000, 30105=>1000, 30106=>1000, 30108=>1000, - 30109=>1000, 30114=>1000, 30115=>1000, 30116=>1000, 30117=>1000, 30123=>1000, 30129=>1000, 30130=>1000, 30131=>1000, 30132=>1000, 30133=>1000, 30136=>1000, 30137=>1000, 30138=>1000, 30140=>1000, 30141=>1000, - 30142=>1000, 30143=>1000, 30144=>1000, 30145=>1000, 30146=>1000, 30147=>1000, 30148=>1000, 30149=>1000, 30150=>1000, 30151=>1000, 30154=>1000, 30156=>1000, 30157=>1000, 30158=>1000, 30159=>1000, 30162=>1000, - 30164=>1000, 30165=>1000, 30167=>1000, 30168=>1000, 30169=>1000, 30171=>1000, 30172=>1000, 30174=>1000, 30175=>1000, 30176=>1000, 30177=>1000, 30178=>1000, 30179=>1000, 30180=>1000, 30183=>1000, 30185=>1000, - 30188=>1000, 30190=>1000, 30191=>1000, 30192=>1000, 30193=>1000, 30194=>1000, 30195=>1000, 30196=>1000, 30201=>1000, 30202=>1000, 30204=>1000, 30206=>1000, 30207=>1000, 30208=>1000, 30209=>1000, 30210=>1000, - 30211=>1000, 30212=>1000, 30215=>1000, 30216=>1000, 30217=>1000, 30218=>1000, 30219=>1000, 30220=>1000, 30221=>1000, 30223=>1000, 30226=>1000, 30227=>1000, 30229=>1000, 30230=>1000, 30233=>1000, 30235=>1000, - 30236=>1000, 30237=>1000, 30238=>1000, 30239=>1000, 30240=>1000, 30241=>1000, 30242=>1000, 30243=>1000, 30244=>1000, 30245=>1000, 30246=>1000, 30247=>1000, 30249=>1000, 30253=>1000, 30256=>1000, 30258=>1000, - 30259=>1000, 30260=>1000, 30261=>1000, 30264=>1000, 30265=>1000, 30266=>1000, 30267=>1000, 30268=>1000, 30272=>1000, 30273=>1000, 30274=>1000, 30275=>1000, 30276=>1000, 30277=>1000, 30278=>1000, 30279=>1000, - 30280=>1000, 30281=>1000, 30282=>1000, 30283=>1000, 30284=>1000, 30290=>1000, 30293=>1000, 30294=>1000, 30296=>1000, 30297=>1000, 30300=>1000, 30303=>1000, 30305=>1000, 30306=>1000, 30308=>1000, 30309=>1000, - 30311=>1000, 30312=>1000, 30313=>1000, 30314=>1000, 30316=>1000, 30317=>1000, 30318=>1000, 30319=>1000, 30320=>1000, 30321=>1000, 30322=>1000, 30324=>1000, 30326=>1000, 30328=>1000, 30330=>1000, 30331=>1000, - 30332=>1000, 30333=>1000, 30334=>1000, 30336=>1000, 30337=>1000, 30338=>1000, 30339=>1000, 30340=>1000, 30341=>1000, 30342=>1000, 30343=>1000, 30344=>1000, 30347=>1000, 30348=>1000, 30349=>1000, 30350=>1000, - 30352=>1000, 30355=>1000, 30357=>1000, 30358=>1000, 30361=>1000, 30362=>1000, 30363=>1000, 30364=>1000, 30365=>1000, 30366=>1000, 30367=>1000, 30368=>1000, 30370=>1000, 30371=>1000, 30372=>1000, 30373=>1000, - 30374=>1000, 30375=>1000, 30376=>1000, 30378=>1000, 30381=>1000, 30382=>1000, 30384=>1000, 30388=>1000, 30391=>1000, 30392=>1000, 30393=>1000, 30394=>1000, 30397=>1000, 30399=>1000, 30401=>1000, 30402=>1000, - 30403=>1000, 30405=>1000, 30406=>1000, 30408=>1000, 30409=>1000, 30410=>1000, 30411=>1000, 30412=>1000, 30413=>1000, 30414=>1000, 30418=>1000, 30420=>1000, 30422=>1000, 30423=>1000, 30425=>1000, 30427=>1000, - 30428=>1000, 30430=>1000, 30431=>1000, 30432=>1000, 30433=>1000, 30435=>1000, 30436=>1000, 30437=>1000, 30438=>1000, 30439=>1000, 30440=>1000, 30442=>1000, 30444=>1000, 30446=>1000, 30448=>1000, 30449=>1000, - 30450=>1000, 30452=>1000, 30454=>1000, 30456=>1000, 30457=>1000, 30459=>1000, 30460=>1000, 30462=>1000, 30464=>1000, 30465=>1000, 30468=>1000, 30470=>1000, 30471=>1000, 30472=>1000, 30473=>1000, 30474=>1000, - 30475=>1000, 30476=>1000, 30478=>1000, 30482=>1000, 30484=>1000, 30485=>1000, 30487=>1000, 30489=>1000, 30490=>1000, 30491=>1000, 30492=>1000, 30494=>1000, 30495=>1000, 30496=>1000, 30498=>1000, 30500=>1000, - 30501=>1000, 30502=>1000, 30504=>1000, 30505=>1000, 30509=>1000, 30510=>1000, 30511=>1000, 30516=>1000, 30517=>1000, 30518=>1000, 30519=>1000, 30520=>1000, 30521=>1000, 30522=>1000, 30524=>1000, 30525=>1000, - 30526=>1000, 30528=>1000, 30530=>1000, 30533=>1000, 30534=>1000, 30535=>1000, 30538=>1000, 30541=>1000, 30542=>1000, 30543=>1000, 30546=>1000, 30550=>1000, 30551=>1000, 30554=>1000, 30555=>1000, 30556=>1000, - 30558=>1000, 30559=>1000, 30560=>1000, 30561=>1000, 30562=>1000, 30563=>1000, 30564=>1000, 30565=>1000, 30566=>1000, 30567=>1000, 30568=>1000, 30570=>1000, 30571=>1000, 30572=>1000, 30576=>1000, 30578=>1000, - 30579=>1000, 30580=>1000, 30585=>1000, 30586=>1000, 30589=>1000, 30590=>1000, 30591=>1000, 30592=>1000, 30596=>1000, 30603=>1000, 30604=>1000, 30605=>1000, 30606=>1000, 30609=>1000, 30612=>1000, 30613=>1000, - 30614=>1000, 30618=>1000, 30622=>1000, 30623=>1000, 30624=>1000, 30626=>1000, 30629=>1000, 30631=>1000, 30634=>1000, 30636=>1000, 30637=>1000, 30638=>1000, 30639=>1000, 30640=>1000, 30641=>1000, 30643=>1000, - 30645=>1000, 30646=>1000, 30649=>1000, 30651=>1000, 30652=>1000, 30653=>1000, 30654=>1000, 30655=>1000, 30659=>1000, 30663=>1000, 30665=>1000, 30669=>1000, 30673=>1000, 30674=>1000, 30677=>1000, 30679=>1000, - 30681=>1000, 30682=>1000, 30683=>1000, 30684=>1000, 30686=>1000, 30687=>1000, 30688=>1000, 30690=>1000, 30691=>1000, 30692=>1000, 30693=>1000, 30694=>1000, 30695=>1000, 30697=>1000, 30698=>1000, 30700=>1000, - 30701=>1000, 30702=>1000, 30703=>1000, 30704=>1000, 30705=>1000, 30707=>1000, 30708=>1000, 30712=>1000, 30715=>1000, 30716=>1000, 30722=>1000, 30725=>1000, 30726=>1000, 30729=>1000, 30732=>1000, 30733=>1000, - 30734=>1000, 30737=>1000, 30738=>1000, 30740=>1000, 30741=>1000, 30749=>1000, 30752=>1000, 30753=>1000, 30754=>1000, 30755=>1000, 30757=>1000, 30758=>1000, 30759=>1000, 30765=>1000, 30766=>1000, 30768=>1000, - 30770=>1000, 30772=>1000, 30773=>1000, 30775=>1000, 30778=>1000, 30783=>1000, 30787=>1000, 30788=>1000, 30789=>1000, 30791=>1000, 30792=>1000, 30796=>1000, 30798=>1000, 30802=>1000, 30812=>1000, 30813=>1000, - 30814=>1000, 30816=>1000, 30817=>1000, 30819=>1000, 30820=>1000, 30824=>1000, 30826=>1000, 30827=>1000, 30828=>1000, 30830=>1000, 30831=>1000, 30834=>1000, 30836=>1000, 30842=>1000, 30844=>1000, 30846=>1000, - 30849=>1000, 30854=>1000, 30855=>1000, 30858=>1000, 30860=>1000, 30861=>1000, 30862=>1000, 30863=>1000, 30865=>1000, 30867=>1000, 30868=>1000, 30869=>1000, 30871=>1000, 30872=>1000, 30874=>1000, 30877=>1000, - 30878=>1000, 30879=>1000, 30881=>1000, 30883=>1000, 30884=>1000, 30887=>1000, 30888=>1000, 30889=>1000, 30890=>1000, 30892=>1000, 30893=>1000, 30895=>1000, 30896=>1000, 30897=>1000, 30898=>1000, 30899=>1000, - 30901=>1000, 30906=>1000, 30907=>1000, 30908=>1000, 30909=>1000, 30910=>1000, 30911=>1000, 30913=>1000, 30917=>1000, 30918=>1000, 30919=>1000, 30920=>1000, 30921=>1000, 30922=>1000, 30923=>1000, 30924=>1000, - 30926=>1000, 30928=>1000, 30929=>1000, 30930=>1000, 30931=>1000, 30932=>1000, 30933=>1000, 30934=>1000, 30938=>1000, 30939=>1000, 30943=>1000, 30944=>1000, 30945=>1000, 30948=>1000, 30950=>1000, 30951=>1000, - 30952=>1000, 30954=>1000, 30956=>1000, 30959=>1000, 30962=>1000, 30963=>1000, 30964=>1000, 30966=>1000, 30967=>1000, 30970=>1000, 30971=>1000, 30973=>1000, 30975=>1000, 30976=>1000, 30977=>1000, 30982=>1000, - 30983=>1000, 30988=>1000, 30990=>1000, 30992=>1000, 30993=>1000, 30994=>1000, 31001=>1000, 31002=>1000, 31004=>1000, 31006=>1000, 31007=>1000, 31008=>1000, 31013=>1000, 31014=>1000, 31015=>1000, 31017=>1000, - 31018=>1000, 31019=>1000, 31020=>1000, 31021=>1000, 31024=>1000, 31025=>1000, 31028=>1000, 31029=>1000, 31034=>1000, 31035=>1000, 31036=>1000, 31037=>1000, 31038=>1000, 31039=>1000, 31040=>1000, 31041=>1000, - 31044=>1000, 31045=>1000, 31046=>1000, 31047=>1000, 31048=>1000, 31049=>1000, 31050=>1000, 31051=>1000, 31055=>1000, 31056=>1000, 31057=>1000, 31059=>1000, 31060=>1000, 31061=>1000, 31062=>1000, 31063=>1000, - 31064=>1000, 31066=>1000, 31067=>1000, 31068=>1000, 31069=>1000, 31070=>1000, 31071=>1000, 31072=>1000, 31074=>1000, 31077=>1000, 31079=>1000, 31080=>1000, 31081=>1000, 31083=>1000, 31085=>1000, 31090=>1000, - 31095=>1000, 31097=>1000, 31098=>1000, 31099=>1000, 31100=>1000, 31102=>1000, 31103=>1000, 31104=>1000, 31105=>1000, 31108=>1000, 31109=>1000, 31114=>1000, 31115=>1000, 31116=>1000, 31117=>1000, 31118=>1000, - 31119=>1000, 31121=>1000, 31123=>1000, 31124=>1000, 31125=>1000, 31126=>1000, 31128=>1000, 31131=>1000, 31132=>1000, 31133=>1000, 31137=>1000, 31142=>1000, 31143=>1000, 31144=>1000, 31145=>1000, 31146=>1000, - 31147=>1000, 31150=>1000, 31151=>1000, 31152=>1000, 31153=>1000, 31155=>1000, 31156=>1000, 31160=>1000, 31161=>1000, 31162=>1000, 31163=>1000, 31165=>1000, 31166=>1000, 31167=>1000, 31168=>1000, 31169=>1000, - 31170=>1000, 31172=>1000, 31175=>1000, 31176=>1000, 31177=>1000, 31178=>1000, 31179=>1000, 31183=>1000, 31185=>1000, 31186=>1000, 31188=>1000, 31189=>1000, 31190=>1000, 31192=>1000, 31194=>1000, 31197=>1000, - 31198=>1000, 31199=>1000, 31200=>1000, 31201=>1000, 31202=>1000, 31203=>1000, 31204=>1000, 31205=>1000, 31206=>1000, 31207=>1000, 31209=>1000, 31210=>1000, 31211=>1000, 31212=>1000, 31213=>1000, 31216=>1000, - 31217=>1000, 31224=>1000, 31227=>1000, 31228=>1000, 31232=>1000, 31234=>1000, 31235=>1000, 31239=>1000, 31240=>1000, 31241=>1000, 31242=>1000, 31243=>1000, 31244=>1000, 31245=>1000, 31246=>1000, 31249=>1000, - 31252=>1000, 31253=>1000, 31255=>1000, 31256=>1000, 31257=>1000, 31258=>1000, 31259=>1000, 31260=>1000, 31262=>1000, 31263=>1000, 31264=>1000, 31265=>1000, 31271=>1000, 31275=>1000, 31277=>1000, 31278=>1000, - 31279=>1000, 31280=>1000, 31281=>1000, 31282=>1000, 31284=>1000, 31285=>1000, 31287=>1000, 31288=>1000, 31289=>1000, 31290=>1000, 31291=>1000, 31292=>1000, 31293=>1000, 31294=>1000, 31295=>1000, 31296=>1000, - 31298=>1000, 31299=>1000, 31300=>1000, 31301=>1000, 31302=>1000, 31303=>1000, 31304=>1000, 31305=>1000, 31308=>1000, 31309=>1000, 31310=>1000, 31311=>1000, 31312=>1000, 31317=>1000, 31318=>1000, 31319=>1000, - 31321=>1000, 31324=>1000, 31325=>1000, 31327=>1000, 31328=>1000, 31329=>1000, 31330=>1000, 31331=>1000, 31333=>1000, 31335=>1000, 31337=>1000, 31338=>1000, 31339=>1000, 31341=>1000, 31344=>1000, 31348=>1000, - 31349=>1000, 31350=>1000, 31352=>1000, 31353=>1000, 31354=>1000, 31357=>1000, 31358=>1000, 31359=>1000, 31360=>1000, 31361=>1000, 31362=>1000, 31363=>1000, 31364=>1000, 31365=>1000, 31366=>1000, 31368=>1000, - 31370=>1000, 31371=>1000, 31376=>1000, 31377=>1000, 31378=>1000, 31379=>1000, 31380=>1000, 31381=>1000, 31382=>1000, 31383=>1000, 31384=>1000, 31390=>1000, 31391=>1000, 31392=>1000, 31395=>1000, 31401=>1000, - 31402=>1000, 31404=>1000, 31406=>1000, 31407=>1000, 31408=>1000, 31411=>1000, 31413=>1000, 31414=>1000, 31417=>1000, 31418=>1000, 31419=>1000, 31420=>1000, 31423=>1000, 31427=>1000, 31428=>1000, 31429=>1000, - 31430=>1000, 31431=>1000, 31432=>1000, 31433=>1000, 31434=>1000, 31435=>1000, 31436=>1000, 31437=>1000, 31438=>1000, 31439=>1000, 31441=>1000, 31442=>1000, 31443=>1000, 31445=>1000, 31449=>1000, 31450=>1000, - 31451=>1000, 31452=>1000, 31453=>1000, 31455=>1000, 31456=>1000, 31457=>1000, 31458=>1000, 31459=>1000, 31461=>1000, 31462=>1000, 31463=>1000, 31464=>1000, 31465=>1000, 31466=>1000, 31467=>1000, 31468=>1000, - 31469=>1000, 31471=>1000, 31472=>1000, 31473=>1000, 31476=>1000, 31478=>1000, 31480=>1000, 31481=>1000, 31482=>1000, 31483=>1000, 31485=>1000, 31486=>1000, 31487=>1000, 31490=>1000, 31492=>1000, 31494=>1000, - 31495=>1000, 31496=>1000, 31498=>1000, 31499=>1000, 31503=>1000, 31505=>1000, 31508=>1000, 31512=>1000, 31513=>1000, 31515=>1000, 31518=>1000, 31519=>1000, 31520=>1000, 31523=>1000, 31525=>1000, 31526=>1000, - 31527=>1000, 31528=>1000, 31529=>1000, 31530=>1000, 31531=>1000, 31532=>1000, 31533=>1000, 31534=>1000, 31535=>1000, 31536=>1000, 31537=>1000, 31539=>1000, 31540=>1000, 31541=>1000, 31542=>1000, 31545=>1000, - 31549=>1000, 31551=>1000, 31552=>1000, 31553=>1000, 31557=>1000, 31558=>1000, 31559=>1000, 31560=>1000, 31561=>1000, 31563=>1000, 31564=>1000, 31565=>1000, 31566=>1000, 31567=>1000, 31568=>1000, 31569=>1000, - 31570=>1000, 31572=>1000, 31573=>1000, 31574=>1000, 31581=>1000, 31584=>1000, 31588=>1000, 31589=>1000, 31590=>1000, 31591=>1000, 31593=>1000, 31594=>1000, 31596=>1000, 31597=>1000, 31598=>1000, 31599=>1000, - 31600=>1000, 31601=>1000, 31602=>1000, 31603=>1000, 31604=>1000, 31605=>1000, 31607=>1000, 31610=>1000, 31620=>1000, 31622=>1000, 31623=>1000, 31625=>1000, 31627=>1000, 31629=>1000, 31630=>1000, 31631=>1000, - 31632=>1000, 31633=>1000, 31634=>1000, 31636=>1000, 31637=>1000, 31638=>1000, 31639=>1000, 31640=>1000, 31641=>1000, 31642=>1000, 31643=>1000, 31644=>1000, 31645=>1000, 31646=>1000, 31647=>1000, 31648=>1000, - 31649=>1000, 31653=>1000, 31658=>1000, 31660=>1000, 31661=>1000, 31663=>1000, 31664=>1000, 31665=>1000, 31666=>1000, 31668=>1000, 31669=>1000, 31670=>1000, 31672=>1000, 31674=>1000, 31675=>1000, 31676=>1000, - 31677=>1000, 31680=>1000, 31681=>1000, 31682=>1000, 31684=>1000, 31685=>1000, 31686=>1000, 31687=>1000, 31688=>1000, 31689=>1000, 31690=>1000, 31691=>1000, 31692=>1000, 31695=>1000, 31700=>1000, 31702=>1000, - 31703=>1000, 31705=>1000, 31706=>1000, 31707=>1000, 31709=>1000, 31712=>1000, 31716=>1000, 31717=>1000, 31718=>1000, 31720=>1000, 31721=>1000, 31722=>1000, 31725=>1000, 31730=>1000, 31731=>1000, 31732=>1000, - 31733=>1000, 31734=>1000, 31735=>1000, 31736=>1000, 31737=>1000, 31738=>1000, 31740=>1000, 31742=>1000, 31744=>1000, 31745=>1000, 31746=>1000, 31747=>1000, 31748=>1000, 31750=>1000, 31751=>1000, 31753=>1000, - 31755=>1000, 31756=>1000, 31757=>1000, 31758=>1000, 31759=>1000, 31761=>1000, 31762=>1000, 31763=>1000, 31764=>1000, 31767=>1000, 31769=>1000, 31771=>1000, 31775=>1000, 31776=>1000, 31777=>1000, 31779=>1000, - 31781=>1000, 31782=>1000, 31783=>1000, 31784=>1000, 31786=>1000, 31787=>1000, 31788=>1000, 31793=>1000, 31795=>1000, 31796=>1000, 31798=>1000, 31799=>1000, 31800=>1000, 31801=>1000, 31802=>1000, 31805=>1000, - 31806=>1000, 31807=>1000, 31808=>1000, 31811=>1000, 31814=>1000, 31818=>1000, 31820=>1000, 31821=>1000, 31823=>1000, 31824=>1000, 31825=>1000, 31826=>1000, 31827=>1000, 31828=>1000, 31829=>1000, 31830=>1000, - 31832=>1000, 31833=>1000, 31834=>1000, 31835=>1000, 31836=>1000, 31837=>1000, 31838=>1000, 31839=>1000, 31840=>1000, 31841=>1000, 31843=>1000, 31844=>1000, 31845=>1000, 31847=>1000, 31849=>1000, 31852=>1000, - 31853=>1000, 31854=>1000, 31856=>1000, 31858=>1000, 31859=>1000, 31861=>1000, 31865=>1000, 31868=>1000, 31869=>1000, 31870=>1000, 31873=>1000, 31874=>1000, 31875=>1000, 31878=>1000, 31879=>1000, 31881=>1000, - 31883=>1000, 31885=>1000, 31887=>1000, 31888=>1000, 31890=>1000, 31892=>1000, 31893=>1000, 31895=>1000, 31896=>1000, 31899=>1000, 31902=>1000, 31903=>1000, 31904=>1000, 31905=>1000, 31906=>1000, 31908=>1000, - 31909=>1000, 31910=>1000, 31911=>1000, 31912=>1000, 31915=>1000, 31917=>1000, 31918=>1000, 31920=>1000, 31921=>1000, 31922=>1000, 31923=>1000, 31926=>1000, 31927=>1000, 31929=>1000, 31930=>1000, 31931=>1000, - 31932=>1000, 31933=>1000, 31934=>1000, 31935=>1000, 31936=>1000, 31938=>1000, 31940=>1000, 31941=>1000, 31943=>1000, 31944=>1000, 31945=>1000, 31946=>1000, 31949=>1000, 31950=>1000, 31951=>1000, 31954=>1000, - 31955=>1000, 31956=>1000, 31957=>1000, 31958=>1000, 31959=>1000, 31960=>1000, 31961=>1000, 31962=>1000, 31964=>1000, 31965=>1000, 31966=>1000, 31967=>1000, 31968=>1000, 31970=>1000, 31974=>1000, 31975=>1000, - 31977=>1000, 31979=>1000, 31983=>1000, 31986=>1000, 31988=>1000, 31989=>1000, 31990=>1000, 31992=>1000, 31994=>1000, 31995=>1000, 31998=>1000, 32000=>1000, 32002=>1000, 32003=>1000, 32004=>1000, 32005=>1000, - 32006=>1000, 32007=>1000, 32008=>1000, 32009=>1000, 32010=>1000, 32011=>1000, 32013=>1000, 32015=>1000, 32016=>1000, 32017=>1000, 32018=>1000, 32019=>1000, 32020=>1000, 32021=>1000, 32022=>1000, 32023=>1000, - 32024=>1000, 32025=>1000, 32026=>1000, 32027=>1000, 32028=>1000, 32029=>1000, 32030=>1000, 32032=>1000, 32033=>1000, 32034=>1000, 32035=>1000, 32038=>1000, 32042=>1000, 32043=>1000, 32044=>1000, 32045=>1000, - 32046=>1000, 32047=>1000, 32048=>1000, 32049=>1000, 32050=>1000, 32051=>1000, 32053=>1000, 32057=>1000, 32058=>1000, 32060=>1000, 32061=>1000, 32062=>1000, 32063=>1000, 32064=>1000, 32065=>1000, 32066=>1000, - 32067=>1000, 32068=>1000, 32069=>1000, 32070=>1000, 32071=>1000, 32072=>1000, 32075=>1000, 32076=>1000, 32077=>1000, 32078=>1000, 32079=>1000, 32080=>1000, 32081=>1000, 32083=>1000, 32086=>1000, 32087=>1000, - 32089=>1000, 32090=>1000, 32091=>1000, 32092=>1000, 32093=>1000, 32094=>1000, 32097=>1000, 32098=>1000, 32099=>1000, 32101=>1000, 32102=>1000, 32103=>1000, 32104=>1000, 32106=>1000, 32110=>1000, 32112=>1000, - 32113=>1000, 32114=>1000, 32115=>1000, 32117=>1000, 32118=>1000, 32120=>1000, 32121=>1000, 32122=>1000, 32123=>1000, 32125=>1000, 32127=>1000, 32129=>1000, 32130=>1000, 32131=>1000, 32133=>1000, 32134=>1000, - 32136=>1000, 32137=>1000, 32139=>1000, 32140=>1000, 32141=>1000, 32143=>1000, 32145=>1000, 32147=>1000, 32150=>1000, 32151=>1000, 32153=>1000, 32154=>1000, 32155=>1000, 32156=>1000, 32157=>1000, 32158=>1000, - 32159=>1000, 32160=>1000, 32162=>1000, 32163=>1000, 32166=>1000, 32167=>1000, 32170=>1000, 32171=>1000, 32172=>1000, 32173=>1000, 32174=>1000, 32175=>1000, 32176=>1000, 32177=>1000, 32178=>1000, 32179=>1000, - 32180=>1000, 32181=>1000, 32182=>1000, 32183=>1000, 32184=>1000, 32185=>1000, 32186=>1000, 32187=>1000, 32189=>1000, 32190=>1000, 32191=>1000, 32194=>1000, 32195=>1000, 32196=>1000, 32197=>1000, 32198=>1000, - 32199=>1000, 32202=>1000, 32203=>1000, 32204=>1000, 32205=>1000, 32206=>1000, 32207=>1000, 32209=>1000, 32210=>1000, 32213=>1000, 32214=>1000, 32215=>1000, 32216=>1000, 32217=>1000, 32218=>1000, 32220=>1000, - 32221=>1000, 32222=>1000, 32224=>1000, 32225=>1000, 32226=>1000, 32228=>1000, 32229=>1000, 32230=>1000, 32232=>1000, 32233=>1000, 32234=>1000, 32235=>1000, 32236=>1000, 32237=>1000, 32239=>1000, 32241=>1000, - 32242=>1000, 32244=>1000, 32245=>1000, 32246=>1000, 32249=>1000, 32250=>1000, 32251=>1000, 32256=>1000, 32257=>1000, 32260=>1000, 32261=>1000, 32264=>1000, 32265=>1000, 32266=>1000, 32267=>1000, 32272=>1000, - 32273=>1000, 32274=>1000, 32277=>1000, 32279=>1000, 32283=>1000, 32284=>1000, 32285=>1000, 32286=>1000, 32287=>1000, 32288=>1000, 32289=>1000, 32290=>1000, 32291=>1000, 32294=>1000, 32295=>1000, 32296=>1000, - 32299=>1000, 32300=>1000, 32301=>1000, 32302=>1000, 32303=>1000, 32305=>1000, 32306=>1000, 32307=>1000, 32309=>1000, 32310=>1000, 32311=>1000, 32313=>1000, 32314=>1000, 32315=>1000, 32317=>1000, 32318=>1000, - 32319=>1000, 32321=>1000, 32323=>1000, 32324=>1000, 32325=>1000, 32326=>1000, 32327=>1000, 32330=>1000, 32331=>1000, 32333=>1000, 32334=>1000, 32336=>1000, 32338=>1000, 32340=>1000, 32341=>1000, 32342=>1000, - 32344=>1000, 32345=>1000, 32346=>1000, 32349=>1000, 32350=>1000, 32351=>1000, 32353=>1000, 32354=>1000, 32357=>1000, 32358=>1000, 32359=>1000, 32361=>1000, 32362=>1000, 32363=>1000, 32365=>1000, 32366=>1000, - 32367=>1000, 32368=>1000, 32371=>1000, 32376=>1000, 32377=>1000, 32379=>1000, 32380=>1000, 32381=>1000, 32382=>1000, 32383=>1000, 32385=>1000, 32386=>1000, 32387=>1000, 32390=>1000, 32391=>1000, 32392=>1000, - 32393=>1000, 32394=>1000, 32396=>1000, 32397=>1000, 32398=>1000, 32399=>1000, 32400=>1000, 32401=>1000, 32402=>1000, 32403=>1000, 32404=>1000, 32405=>1000, 32406=>1000, 32408=>1000, 32410=>1000, 32411=>1000, - 32412=>1000, 32413=>1000, 32414=>1000, 32566=>1000, 32568=>1000, 32570=>1000, 32571=>1000, 32572=>1000, 32573=>1000, 32574=>1000, 32575=>1000, 32579=>1000, 32580=>1000, 32581=>1000, 32583=>1000, 32588=>1000, - 32589=>1000, 32590=>1000, 32591=>1000, 32592=>1000, 32593=>1000, 32594=>1000, 32595=>1000, 32596=>1000, 32597=>1000, 32600=>1000, 32603=>1000, 32604=>1000, 32605=>1000, 32607=>1000, 32608=>1000, 32609=>1000, - 32611=>1000, 32612=>1000, 32613=>1000, 32614=>1000, 32615=>1000, 32616=>1000, 32617=>1000, 32618=>1000, 32619=>1000, 32621=>1000, 32622=>1000, 32624=>1000, 32625=>1000, 32626=>1000, 32629=>1000, 32631=>1000, - 32632=>1000, 32633=>1000, 32637=>1000, 32638=>1000, 32639=>1000, 32640=>1000, 32642=>1000, 32643=>1000, 32645=>1000, 32646=>1000, 32647=>1000, 32648=>1000, 32650=>1000, 32651=>1000, 32652=>1000, 32653=>1000, - 32654=>1000, 32655=>1000, 32656=>1000, 32657=>1000, 32660=>1000, 32662=>1000, 32663=>1000, 32666=>1000, 32668=>1000, 32669=>1000, 32670=>1000, 32673=>1000, 32674=>1000, 32675=>1000, 32676=>1000, 32678=>1000, - 32680=>1000, 32681=>1000, 32682=>1000, 32685=>1000, 32686=>1000, 32687=>1000, 32690=>1000, 32692=>1000, 32694=>1000, 32696=>1000, 32697=>1000, 32700=>1000, 32701=>1000, 32703=>1000, 32704=>1000, 32705=>1000, - 32707=>1000, 32709=>1000, 32710=>1000, 32712=>1000, 32714=>1000, 32716=>1000, 32718=>1000, 32719=>1000, 32722=>1000, 32724=>1000, 32725=>1000, 32731=>1000, 32735=>1000, 32736=>1000, 32737=>1000, 32739=>1000, - 32741=>1000, 32742=>1000, 32744=>1000, 32745=>1000, 32747=>1000, 32748=>1000, 32750=>1000, 32751=>1000, 32752=>1000, 32754=>1000, 32755=>1000, 32761=>1000, 32762=>1000, 32763=>1000, 32764=>1000, 32765=>1000, - 32766=>1000, 32767=>1000, 32768=>1000, 32769=>1000, 32771=>1000, 32772=>1000, 32773=>1000, 32774=>1000, 32775=>1000, 32776=>1000, 32778=>1000, 32779=>1000, 32780=>1000, 32781=>1000, 32782=>1000, 32783=>1000, - 32784=>1000, 32785=>1000, 32786=>1000, 32787=>1000, 32788=>1000, 32789=>1000, 32790=>1000, 32791=>1000, 32792=>1000, 32793=>1000, 32796=>1000, 32797=>1000, 32798=>1000, 32799=>1000, 32800=>1000, 32801=>1000, - 32804=>1000, 32806=>1000, 32808=>1000, 32812=>1000, 32814=>1000, 32816=>1000, 32819=>1000, 32820=>1000, 32821=>1000, 32822=>1000, 32823=>1000, 32825=>1000, 32826=>1000, 32827=>1000, 32828=>1000, 32829=>1000, - 32830=>1000, 32831=>1000, 32832=>1000, 32836=>1000, 32838=>1000, 32842=>1000, 32850=>1000, 32854=>1000, 32856=>1000, 32858=>1000, 32862=>1000, 32863=>1000, 32864=>1000, 32865=>1000, 32866=>1000, 32868=>1000, - 32870=>1000, 32872=>1000, 32877=>1000, 32879=>1000, 32880=>1000, 32881=>1000, 32882=>1000, 32883=>1000, 32884=>1000, 32885=>1000, 32886=>1000, 32887=>1000, 32889=>1000, 32893=>1000, 32894=>1000, 32895=>1000, - 32897=>1000, 32900=>1000, 32901=>1000, 32902=>1000, 32903=>1000, 32904=>1000, 32905=>1000, 32907=>1000, 32908=>1000, 32910=>1000, 32915=>1000, 32918=>1000, 32920=>1000, 32922=>1000, 32923=>1000, 32924=>1000, - 32925=>1000, 32926=>1000, 32929=>1000, 32930=>1000, 32933=>1000, 32934=>1000, 32935=>1000, 32937=>1000, 32938=>1000, 32939=>1000, 32940=>1000, 32941=>1000, 32943=>1000, 32945=>1000, 32946=>1000, 32948=>1000, - 32952=>1000, 32953=>1000, 32954=>1000, 32963=>1000, 32964=>1000, 32966=>1000, 32968=>1000, 32972=>1000, 32973=>1000, 32974=>1000, 32975=>1000, 32978=>1000, 32980=>1000, 32981=>1000, 32982=>1000, 32983=>1000, - 32984=>1000, 32985=>1000, 32986=>1000, 32987=>1000, 32989=>1000, 32990=>1000, 32992=>1000, 32993=>1000, 32996=>1000, 32997=>1000, 33005=>1000, 33006=>1000, 33007=>1000, 33008=>1000, 33009=>1000, 33010=>1000, - 33011=>1000, 33012=>1000, 33014=>1000, 33016=>1000, 33017=>1000, 33018=>1000, 33020=>1000, 33021=>1000, 33022=>1000, 33026=>1000, 33027=>1000, 33029=>1000, 33030=>1000, 33031=>1000, 33032=>1000, 33033=>1000, - 33034=>1000, 33035=>1000, 33046=>1000, 33047=>1000, 33048=>1000, 33050=>1000, 33051=>1000, 33052=>1000, 33054=>1000, 33056=>1000, 33059=>1000, 33060=>1000, 33063=>1000, 33065=>1000, 33068=>1000, 33071=>1000, - 33072=>1000, 33073=>1000, 33075=>1000, 33077=>1000, 33081=>1000, 33082=>1000, 33084=>1000, 33086=>1000, 33093=>1000, 33094=>1000, 33095=>1000, 33098=>1000, 33099=>1000, 33100=>1000, 33102=>1000, 33104=>1000, - 33105=>1000, 33106=>1000, 33107=>1000, 33108=>1000, 33109=>1000, 33111=>1000, 33119=>1000, 33120=>1000, 33121=>1000, 33125=>1000, 33126=>1000, 33127=>1000, 33128=>1000, 33129=>1000, 33131=>1000, 33133=>1000, - 33134=>1000, 33135=>1000, 33136=>1000, 33137=>1000, 33140=>1000, 33143=>1000, 33144=>1000, 33145=>1000, 33146=>1000, 33151=>1000, 33152=>1000, 33153=>1000, 33154=>1000, 33155=>1000, 33156=>1000, 33157=>1000, - 33158=>1000, 33160=>1000, 33162=>1000, 33163=>1000, 33166=>1000, 33167=>1000, 33168=>1000, 33171=>1000, 33173=>1000, 33174=>1000, 33176=>1000, 33178=>1000, 33179=>1000, 33180=>1000, 33181=>1000, 33182=>1000, - 33184=>1000, 33186=>1000, 33187=>1000, 33188=>1000, 33192=>1000, 33193=>1000, 33198=>1000, 33200=>1000, 33202=>1000, 33203=>1000, 33204=>1000, 33205=>1000, 33208=>1000, 33210=>1000, 33211=>1000, 33213=>1000, - 33214=>1000, 33215=>1000, 33216=>1000, 33218=>1000, 33219=>1000, 33221=>1000, 33222=>1000, 33224=>1000, 33225=>1000, 33226=>1000, 33227=>1000, 33229=>1000, 33230=>1000, 33231=>1000, 33233=>1000, 33235=>1000, - 33237=>1000, 33239=>1000, 33240=>1000, 33241=>1000, 33242=>1000, 33243=>1000, 33245=>1000, 33246=>1000, 33247=>1000, 33248=>1000, 33249=>1000, 33251=>1000, 33252=>1000, 33253=>1000, 33255=>1000, 33256=>1000, - 33258=>1000, 33259=>1000, 33260=>1000, 33261=>1000, 33264=>1000, 33265=>1000, 33266=>1000, 33267=>1000, 33268=>1000, 33269=>1000, 33270=>1000, 33272=>1000, 33273=>1000, 33274=>1000, 33275=>1000, 33276=>1000, - 33277=>1000, 33278=>1000, 33279=>1000, 33280=>1000, 33281=>1000, 33282=>1000, 33283=>1000, 33285=>1000, 33287=>1000, 33288=>1000, 33289=>1000, 33290=>1000, 33292=>1000, 33293=>1000, 33294=>1000, 33295=>1000, - 33296=>1000, 33298=>1000, 33299=>1000, 33300=>1000, 33302=>1000, 33303=>1000, 33304=>1000, 33305=>1000, 33306=>1000, 33307=>1000, 33308=>1000, 33309=>1000, 33310=>1000, 33311=>1000, 33313=>1000, 33314=>1000, - 33320=>1000, 33321=>1000, 33322=>1000, 33323=>1000, 33324=>1000, 33326=>1000, 33330=>1000, 33331=>1000, 33332=>1000, 33333=>1000, 33334=>1000, 33335=>1000, 33336=>1000, 33337=>1000, 33338=>1000, 33344=>1000, - 33347=>1000, 33348=>1000, 33349=>1000, 33350=>1000, 33351=>1000, 33355=>1000, 33358=>1000, 33359=>1000, 33361=>1000, 33366=>1000, 33368=>1000, 33369=>1000, 33370=>1000, 33372=>1000, 33373=>1000, 33375=>1000, - 33376=>1000, 33378=>1000, 33379=>1000, 33380=>1000, 33382=>1000, 33383=>1000, 33384=>1000, 33386=>1000, 33387=>1000, 33389=>1000, 33390=>1000, 33391=>1000, 33393=>1000, 33394=>1000, 33396=>1000, 33398=>1000, - 33399=>1000, 33400=>1000, 33403=>1000, 33405=>1000, 33406=>1000, 33407=>1000, 33408=>1000, 33409=>1000, 33411=>1000, 33412=>1000, 33415=>1000, 33417=>1000, 33418=>1000, 33419=>1000, 33421=>1000, 33422=>1000, - 33425=>1000, 33426=>1000, 33428=>1000, 33430=>1000, 33432=>1000, 33433=>1000, 33434=>1000, 33435=>1000, 33437=>1000, 33439=>1000, 33440=>1000, 33441=>1000, 33443=>1000, 33444=>1000, 33445=>1000, 33446=>1000, - 33447=>1000, 33448=>1000, 33449=>1000, 33450=>1000, 33451=>1000, 33452=>1000, 33453=>1000, 33454=>1000, 33455=>1000, 33456=>1000, 33457=>1000, 33458=>1000, 33459=>1000, 33460=>1000, 33463=>1000, 33464=>1000, - 33465=>1000, 33466=>1000, 33467=>1000, 33468=>1000, 33469=>1000, 33470=>1000, 33471=>1000, 33477=>1000, 33478=>1000, 33488=>1000, 33489=>1000, 33490=>1000, 33491=>1000, 33492=>1000, 33493=>1000, 33495=>1000, - 33497=>1000, 33498=>1000, 33499=>1000, 33500=>1000, 33502=>1000, 33503=>1000, 33504=>1000, 33505=>1000, 33506=>1000, 33507=>1000, 33508=>1000, 33509=>1000, 33510=>1000, 33511=>1000, 33512=>1000, 33514=>1000, - 33515=>1000, 33517=>1000, 33519=>1000, 33521=>1000, 33523=>1000, 33524=>1000, 33526=>1000, 33527=>1000, 33529=>1000, 33530=>1000, 33531=>1000, 33533=>1000, 33534=>1000, 33536=>1000, 33537=>1000, 33538=>1000, - 33539=>1000, 33540=>1000, 33541=>1000, 33542=>1000, 33543=>1000, 33544=>1000, 33545=>1000, 33546=>1000, 33547=>1000, 33550=>1000, 33558=>1000, 33559=>1000, 33560=>1000, 33563=>1000, 33564=>1000, 33565=>1000, - 33566=>1000, 33567=>1000, 33569=>1000, 33570=>1000, 33571=>1000, 33576=>1000, 33579=>1000, 33580=>1000, 33581=>1000, 33582=>1000, 33583=>1000, 33584=>1000, 33585=>1000, 33586=>1000, 33587=>1000, 33588=>1000, - 33589=>1000, 33590=>1000, 33591=>1000, 33592=>1000, 33593=>1000, 33594=>1000, 33596=>1000, 33597=>1000, 33600=>1000, 33602=>1000, 33603=>1000, 33604=>1000, 33605=>1000, 33607=>1000, 33609=>1000, 33610=>1000, - 33613=>1000, 33614=>1000, 33615=>1000, 33616=>1000, 33617=>1000, 33618=>1000, 33619=>1000, 33620=>1000, 33621=>1000, 33622=>1000, 33623=>1000, 33624=>1000, 33634=>1000, 33648=>1000, 33651=>1000, 33653=>1000, - 33655=>1000, 33656=>1000, 33659=>1000, 33660=>1000, 33661=>1000, 33663=>1000, 33664=>1000, 33666=>1000, 33668=>1000, 33669=>1000, 33670=>1000, 33671=>1000, 33673=>1000, 33674=>1000, 33677=>1000, 33678=>1000, - 33682=>1000, 33683=>1000, 33684=>1000, 33685=>1000, 33686=>1000, 33688=>1000, 33689=>1000, 33690=>1000, 33691=>1000, 33692=>1000, 33693=>1000, 33694=>1000, 33695=>1000, 33696=>1000, 33698=>1000, 33702=>1000, - 33703=>1000, 33704=>1000, 33705=>1000, 33706=>1000, 33707=>1000, 33708=>1000, 33709=>1000, 33713=>1000, 33717=>1000, 33725=>1000, 33726=>1000, 33727=>1000, 33728=>1000, 33729=>1000, 33733=>1000, 33735=>1000, - 33737=>1000, 33738=>1000, 33740=>1000, 33742=>1000, 33743=>1000, 33744=>1000, 33745=>1000, 33747=>1000, 33748=>1000, 33750=>1000, 33752=>1000, 33756=>1000, 33757=>1000, 33759=>1000, 33760=>1000, 33768=>1000, - 33769=>1000, 33770=>1000, 33771=>1000, 33775=>1000, 33776=>1000, 33777=>1000, 33778=>1000, 33780=>1000, 33782=>1000, 33783=>1000, 33784=>1000, 33785=>1000, 33787=>1000, 33788=>1000, 33789=>1000, 33793=>1000, - 33795=>1000, 33796=>1000, 33798=>1000, 33799=>1000, 33802=>1000, 33803=>1000, 33804=>1000, 33805=>1000, 33806=>1000, 33807=>1000, 33809=>1000, 33811=>1000, 33813=>1000, 33817=>1000, 33824=>1000, 33826=>1000, - 33833=>1000, 33834=>1000, 33836=>1000, 33839=>1000, 33841=>1000, 33845=>1000, 33848=>1000, 33849=>1000, 33852=>1000, 33853=>1000, 33861=>1000, 33862=>1000, 33863=>1000, 33864=>1000, 33865=>1000, 33866=>1000, - 33869=>1000, 33870=>1000, 33871=>1000, 33873=>1000, 33874=>1000, 33878=>1000, 33879=>1000, 33880=>1000, 33881=>1000, 33882=>1000, 33883=>1000, 33884=>1000, 33888=>1000, 33889=>1000, 33890=>1000, 33891=>1000, - 33892=>1000, 33893=>1000, 33894=>1000, 33895=>1000, 33897=>1000, 33898=>1000, 33899=>1000, 33900=>1000, 33901=>1000, 33902=>1000, 33903=>1000, 33904=>1000, 33905=>1000, 33907=>1000, 33908=>1000, 33909=>1000, - 33910=>1000, 33911=>1000, 33912=>1000, 33913=>1000, 33914=>1000, 33916=>1000, 33917=>1000, 33921=>1000, 33922=>1000, 33924=>1000, 33925=>1000, 33931=>1000, 33936=>1000, 33938=>1000, 33939=>1000, 33940=>1000, - 33941=>1000, 33945=>1000, 33948=>1000, 33950=>1000, 33951=>1000, 33953=>1000, 33958=>1000, 33960=>1000, 33961=>1000, 33962=>1000, 33965=>1000, 33967=>1000, 33969=>1000, 33970=>1000, 33972=>1000, 33976=>1000, - 33977=>1000, 33978=>1000, 33979=>1000, 33980=>1000, 33981=>1000, 33982=>1000, 33983=>1000, 33984=>1000, 33985=>1000, 33986=>1000, 33988=>1000, 33990=>1000, 33991=>1000, 33992=>1000, 33993=>1000, 33994=>1000, - 33995=>1000, 33996=>1000, 33997=>1000, 33999=>1000, 34000=>1000, 34001=>1000, 34003=>1000, 34006=>1000, 34009=>1000, 34010=>1000, 34012=>1000, 34023=>1000, 34026=>1000, 34028=>1000, 34030=>1000, 34031=>1000, - 34032=>1000, 34033=>1000, 34034=>1000, 34036=>1000, 34039=>1000, 34042=>1000, 34043=>1000, 34044=>1000, 34045=>1000, 34047=>1000, 34048=>1000, 34050=>1000, 34051=>1000, 34054=>1000, 34055=>1000, 34060=>1000, - 34062=>1000, 34064=>1000, 34065=>1000, 34067=>1000, 34068=>1000, 34069=>1000, 34071=>1000, 34072=>1000, 34074=>1000, 34076=>1000, 34078=>1000, 34079=>1000, 34081=>1000, 34082=>1000, 34083=>1000, 34084=>1000, - 34085=>1000, 34086=>1000, 34087=>1000, 34090=>1000, 34091=>1000, 34092=>1000, 34093=>1000, 34095=>1000, 34098=>1000, 34099=>1000, 34100=>1000, 34101=>1000, 34102=>1000, 34109=>1000, 34111=>1000, 34112=>1000, - 34113=>1000, 34115=>1000, 34118=>1000, 34120=>1000, 34121=>1000, 34122=>1000, 34123=>1000, 34126=>1000, 34127=>1000, 34128=>1000, 34129=>1000, 34130=>1000, 34131=>1000, 34133=>1000, 34134=>1000, 34135=>1000, - 34136=>1000, 34137=>1000, 34138=>1000, 34140=>1000, 34141=>1000, 34142=>1000, 34143=>1000, 34144=>1000, 34145=>1000, 34146=>1000, 34147=>1000, 34148=>1000, 34152=>1000, 34153=>1000, 34154=>1000, 34155=>1000, - 34157=>1000, 34159=>1000, 34167=>1000, 34169=>1000, 34170=>1000, 34171=>1000, 34173=>1000, 34174=>1000, 34175=>1000, 34176=>1000, 34177=>1000, 34180=>1000, 34181=>1000, 34182=>1000, 34183=>1000, 34184=>1000, - 34185=>1000, 34186=>1000, 34187=>1000, 34188=>1000, 34191=>1000, 34192=>1000, 34193=>1000, 34195=>1000, 34196=>1000, 34199=>1000, 34200=>1000, 34201=>1000, 34203=>1000, 34204=>1000, 34205=>1000, 34207=>1000, - 34208=>1000, 34210=>1000, 34212=>1000, 34213=>1000, 34214=>1000, 34215=>1000, 34216=>1000, 34217=>1000, 34218=>1000, 34219=>1000, 34220=>1000, 34221=>1000, 34222=>1000, 34223=>1000, 34224=>1000, 34228=>1000, - 34230=>1000, 34231=>1000, 34232=>1000, 34233=>1000, 34234=>1000, 34236=>1000, 34237=>1000, 34238=>1000, 34239=>1000, 34241=>1000, 34242=>1000, 34247=>1000, 34249=>1000, 34250=>1000, 34251=>1000, 34253=>1000, - 34254=>1000, 34255=>1000, 34256=>1000, 34261=>1000, 34264=>1000, 34266=>1000, 34268=>1000, 34269=>1000, 34271=>1000, 34272=>1000, 34276=>1000, 34277=>1000, 34278=>1000, 34280=>1000, 34281=>1000, 34282=>1000, - 34285=>1000, 34291=>1000, 34294=>1000, 34295=>1000, 34297=>1000, 34298=>1000, 34299=>1000, 34300=>1000, 34302=>1000, 34303=>1000, 34304=>1000, 34306=>1000, 34308=>1000, 34309=>1000, 34310=>1000, 34311=>1000, - 34314=>1000, 34315=>1000, 34317=>1000, 34318=>1000, 34320=>1000, 34321=>1000, 34322=>1000, 34323=>1000, 34326=>1000, 34327=>1000, 34328=>1000, 34329=>1000, 34330=>1000, 34331=>1000, 34334=>1000, 34337=>1000, - 34338=>1000, 34343=>1000, 34345=>1000, 34349=>1000, 34351=>1000, 34352=>1000, 34358=>1000, 34360=>1000, 34362=>1000, 34364=>1000, 34365=>1000, 34367=>1000, 34368=>1000, 34369=>1000, 34370=>1000, 34374=>1000, - 34381=>1000, 34382=>1000, 34384=>1000, 34386=>1000, 34387=>1000, 34388=>1000, 34389=>1000, 34390=>1000, 34391=>1000, 34392=>1000, 34393=>1000, 34394=>1000, 34396=>1000, 34397=>1000, 34398=>1000, 34399=>1000, - 34400=>1000, 34401=>1000, 34402=>1000, 34403=>1000, 34404=>1000, 34407=>1000, 34409=>1000, 34411=>1000, 34412=>1000, 34415=>1000, 34417=>1000, 34421=>1000, 34422=>1000, 34423=>1000, 34425=>1000, 34426=>1000, - 34427=>1000, 34440=>1000, 34442=>1000, 34443=>1000, 34444=>1000, 34445=>1000, 34449=>1000, 34451=>1000, 34453=>1000, 34454=>1000, 34456=>1000, 34458=>1000, 34460=>1000, 34465=>1000, 34467=>1000, 34468=>1000, - 34470=>1000, 34471=>1000, 34472=>1000, 34473=>1000, 34474=>1000, 34475=>1000, 34477=>1000, 34479=>1000, 34480=>1000, 34481=>1000, 34483=>1000, 34484=>1000, 34485=>1000, 34486=>1000, 34487=>1000, 34488=>1000, - 34489=>1000, 34495=>1000, 34496=>1000, 34497=>1000, 34499=>1000, 34500=>1000, 34501=>1000, 34502=>1000, 34503=>1000, 34505=>1000, 34507=>1000, 34509=>1000, 34510=>1000, 34513=>1000, 34514=>1000, 34516=>1000, - 34517=>1000, 34519=>1000, 34521=>1000, 34522=>1000, 34523=>1000, 34524=>1000, 34526=>1000, 34527=>1000, 34528=>1000, 34531=>1000, 34532=>1000, 34533=>1000, 34535=>1000, 34537=>1000, 34540=>1000, 34541=>1000, - 34542=>1000, 34543=>1000, 34552=>1000, 34553=>1000, 34554=>1000, 34555=>1000, 34556=>1000, 34557=>1000, 34558=>1000, 34560=>1000, 34562=>1000, 34563=>1000, 34564=>1000, 34565=>1000, 34566=>1000, 34567=>1000, - 34568=>1000, 34569=>1000, 34570=>1000, 34571=>1000, 34573=>1000, 34574=>1000, 34575=>1000, 34576=>1000, 34577=>1000, 34578=>1000, 34579=>1000, 34580=>1000, 34584=>1000, 34585=>1000, 34586=>1000, 34588=>1000, - 34590=>1000, 34591=>1000, 34593=>1000, 34595=>1000, 34597=>1000, 34600=>1000, 34601=>1000, 34606=>1000, 34607=>1000, 34609=>1000, 34610=>1000, 34612=>1000, 34615=>1000, 34617=>1000, 34618=>1000, 34619=>1000, - 34620=>1000, 34621=>1000, 34622=>1000, 34623=>1000, 34624=>1000, 34627=>1000, 34629=>1000, 34633=>1000, 34635=>1000, 34636=>1000, 34637=>1000, 34638=>1000, 34643=>1000, 34645=>1000, 34647=>1000, 34648=>1000, - 34649=>1000, 34653=>1000, 34655=>1000, 34656=>1000, 34657=>1000, 34659=>1000, 34660=>1000, 34661=>1000, 34662=>1000, 34664=>1000, 34666=>1000, 34670=>1000, 34671=>1000, 34673=>1000, 34674=>1000, 34676=>1000, - 34678=>1000, 34680=>1000, 34683=>1000, 34687=>1000, 34690=>1000, 34691=>1000, 34692=>1000, 34693=>1000, 34694=>1000, 34695=>1000, 34696=>1000, 34697=>1000, 34699=>1000, 34700=>1000, 34701=>1000, 34704=>1000, - 34707=>1000, 34709=>1000, 34711=>1000, 34712=>1000, 34713=>1000, 34718=>1000, 34719=>1000, 34720=>1000, 34722=>1000, 34723=>1000, 34727=>1000, 34731=>1000, 34732=>1000, 34733=>1000, 34734=>1000, 34735=>1000, - 34737=>1000, 34739=>1000, 34741=>1000, 34746=>1000, 34747=>1000, 34749=>1000, 34750=>1000, 34751=>1000, 34752=>1000, 34753=>1000, 34756=>1000, 34758=>1000, 34759=>1000, 34760=>1000, 34761=>1000, 34762=>1000, - 34763=>1000, 34766=>1000, 34768=>1000, 34770=>1000, 34773=>1000, 34774=>1000, 34777=>1000, 34778=>1000, 34780=>1000, 34783=>1000, 34784=>1000, 34786=>1000, 34787=>1000, 34788=>1000, 34794=>1000, 34795=>1000, - 34797=>1000, 34799=>1000, 34801=>1000, 34802=>1000, 34803=>1000, 34806=>1000, 34807=>1000, 34808=>1000, 34809=>1000, 34810=>1000, 34811=>1000, 34814=>1000, 34815=>1000, 34817=>1000, 34819=>1000, 34821=>1000, - 34822=>1000, 34823=>1000, 34825=>1000, 34826=>1000, 34827=>1000, 34829=>1000, 34830=>1000, 34831=>1000, 34832=>1000, 34833=>1000, 34834=>1000, 34835=>1000, 34836=>1000, 34837=>1000, 34838=>1000, 34840=>1000, - 34841=>1000, 34842=>1000, 34843=>1000, 34844=>1000, 34846=>1000, 34847=>1000, 34849=>1000, 34850=>1000, 34851=>1000, 34855=>1000, 34856=>1000, 34861=>1000, 34862=>1000, 34864=>1000, 34865=>1000, 34866=>1000, - 34869=>1000, 34870=>1000, 34873=>1000, 34874=>1000, 34875=>1000, 34876=>1000, 34880=>1000, 34881=>1000, 34882=>1000, 34883=>1000, 34884=>1000, 34885=>1000, 34886=>1000, 34888=>1000, 34889=>1000, 34890=>1000, - 34891=>1000, 34892=>1000, 34893=>1000, 34894=>1000, 34897=>1000, 34898=>1000, 34899=>1000, 34901=>1000, 34902=>1000, 34903=>1000, 34904=>1000, 34905=>1000, 34906=>1000, 34907=>1000, 34908=>1000, 34909=>1000, - 34910=>1000, 34911=>1000, 34912=>1000, 34913=>1000, 34914=>1000, 34915=>1000, 34916=>1000, 34920=>1000, 34921=>1000, 34923=>1000, 34928=>1000, 34929=>1000, 34930=>1000, 34933=>1000, 34935=>1000, 34937=>1000, - 34939=>1000, 34941=>1000, 34942=>1000, 34943=>1000, 34944=>1000, 34945=>1000, 34946=>1000, 34952=>1000, 34955=>1000, 34957=>1000, 34962=>1000, 34966=>1000, 34967=>1000, 34968=>1000, 34969=>1000, 34970=>1000, - 34971=>1000, 34972=>1000, 34974=>1000, 34975=>1000, 34976=>1000, 34978=>1000, 34980=>1000, 34984=>1000, 34986=>1000, 34987=>1000, 34990=>1000, 34992=>1000, 34993=>1000, 34996=>1000, 34997=>1000, 34999=>1000, - 35002=>1000, 35005=>1000, 35006=>1000, 35007=>1000, 35008=>1000, 35009=>1000, 35010=>1000, 35011=>1000, 35012=>1000, 35013=>1000, 35018=>1000, 35019=>1000, 35020=>1000, 35021=>1000, 35022=>1000, 35023=>1000, - 35025=>1000, 35026=>1000, 35027=>1000, 35028=>1000, 35029=>1000, 35032=>1000, 35033=>1000, 35035=>1000, 35036=>1000, 35037=>1000, 35038=>1000, 35039=>1000, 35041=>1000, 35047=>1000, 35048=>1000, 35055=>1000, - 35056=>1000, 35057=>1000, 35058=>1000, 35059=>1000, 35060=>1000, 35061=>1000, 35063=>1000, 35064=>1000, 35065=>1000, 35068=>1000, 35069=>1000, 35070=>1000, 35073=>1000, 35074=>1000, 35076=>1000, 35078=>1000, - 35079=>1000, 35082=>1000, 35084=>1000, 35085=>1000, 35086=>1000, 35087=>1000, 35088=>1000, 35090=>1000, 35091=>1000, 35093=>1000, 35094=>1000, 35096=>1000, 35097=>1000, 35098=>1000, 35100=>1000, 35101=>1000, - 35102=>1000, 35104=>1000, 35109=>1000, 35110=>1000, 35111=>1000, 35112=>1000, 35114=>1000, 35115=>1000, 35120=>1000, 35121=>1000, 35122=>1000, 35125=>1000, 35126=>1000, 35128=>1000, 35129=>1000, 35130=>1000, - 35131=>1000, 35134=>1000, 35136=>1000, 35137=>1000, 35138=>1000, 35139=>1000, 35140=>1000, 35141=>1000, 35142=>1000, 35145=>1000, 35148=>1000, 35149=>1000, 35151=>1000, 35154=>1000, 35158=>1000, 35159=>1000, - 35162=>1000, 35163=>1000, 35164=>1000, 35166=>1000, 35167=>1000, 35168=>1000, 35169=>1000, 35170=>1000, 35171=>1000, 35172=>1000, 35174=>1000, 35178=>1000, 35179=>1000, 35181=>1000, 35182=>1000, 35183=>1000, - 35184=>1000, 35186=>1000, 35187=>1000, 35188=>1000, 35189=>1000, 35191=>1000, 35194=>1000, 35195=>1000, 35196=>1000, 35197=>1000, 35198=>1000, 35199=>1000, 35201=>1000, 35203=>1000, 35206=>1000, 35207=>1000, - 35208=>1000, 35209=>1000, 35210=>1000, 35211=>1000, 35213=>1000, 35215=>1000, 35216=>1000, 35219=>1000, 35220=>1000, 35221=>1000, 35222=>1000, 35223=>1000, 35224=>1000, 35226=>1000, 35227=>1000, 35228=>1000, - 35231=>1000, 35232=>1000, 35233=>1000, 35237=>1000, 35238=>1000, 35239=>1000, 35241=>1000, 35242=>1000, 35244=>1000, 35247=>1000, 35248=>1000, 35250=>1000, 35251=>1000, 35252=>1000, 35253=>1000, 35254=>1000, - 35255=>1000, 35258=>1000, 35260=>1000, 35261=>1000, 35263=>1000, 35264=>1000, 35282=>1000, 35284=>1000, 35285=>1000, 35286=>1000, 35287=>1000, 35288=>1000, 35290=>1000, 35292=>1000, 35293=>1000, 35299=>1000, - 35301=>1000, 35302=>1000, 35303=>1000, 35305=>1000, 35307=>1000, 35309=>1000, 35313=>1000, 35315=>1000, 35316=>1000, 35318=>1000, 35320=>1000, 35321=>1000, 35325=>1000, 35327=>1000, 35328=>1000, 35330=>1000, - 35331=>1000, 35332=>1000, 35333=>1000, 35335=>1000, 35336=>1000, 35338=>1000, 35340=>1000, 35342=>1000, 35343=>1000, 35344=>1000, 35345=>1000, 35346=>1000, 35347=>1000, 35348=>1000, 35349=>1000, 35350=>1000, - 35351=>1000, 35352=>1000, 35355=>1000, 35357=>1000, 35358=>1000, 35359=>1000, 35360=>1000, 35362=>1000, 35363=>1000, 35364=>1000, 35365=>1000, 35366=>1000, 35370=>1000, 35371=>1000, 35372=>1000, 35373=>1000, - 35375=>1000, 35377=>1000, 35379=>1000, 35380=>1000, 35381=>1000, 35382=>1000, 35383=>1000, 35386=>1000, 35387=>1000, 35388=>1000, 35389=>1000, 35390=>1000, 35392=>1000, 35393=>1000, 35395=>1000, 35397=>1000, - 35398=>1000, 35399=>1000, 35400=>1000, 35401=>1000, 35405=>1000, 35406=>1000, 35408=>1000, 35409=>1000, 35410=>1000, 35411=>1000, 35412=>1000, 35413=>1000, 35414=>1000, 35415=>1000, 35416=>1000, 35419=>1000, - 35420=>1000, 35421=>1000, 35422=>1000, 35424=>1000, 35425=>1000, 35426=>1000, 35427=>1000, 35429=>1000, 35430=>1000, 35431=>1000, 35433=>1000, 35435=>1000, 35436=>1000, 35437=>1000, 35438=>1000, 35440=>1000, - 35441=>1000, 35442=>1000, 35443=>1000, 35445=>1000, 35446=>1000, 35447=>1000, 35449=>1000, 35450=>1000, 35451=>1000, 35452=>1000, 35454=>1000, 35455=>1000, 35456=>1000, 35458=>1000, 35459=>1000, 35460=>1000, - 35461=>1000, 35462=>1000, 35463=>1000, 35465=>1000, 35467=>1000, 35468=>1000, 35469=>1000, 35471=>1000, 35472=>1000, 35473=>1000, 35474=>1000, 35475=>1000, 35477=>1000, 35478=>1000, 35479=>1000, 35480=>1000, - 35481=>1000, 35482=>1000, 35486=>1000, 35487=>1000, 35488=>1000, 35489=>1000, 35491=>1000, 35492=>1000, 35493=>1000, 35494=>1000, 35495=>1000, 35496=>1000, 35497=>1000, 35500=>1000, 35501=>1000, 35502=>1000, - 35503=>1000, 35504=>1000, 35506=>1000, 35507=>1000, 35510=>1000, 35511=>1000, 35513=>1000, 35515=>1000, 35516=>1000, 35518=>1000, 35519=>1000, 35522=>1000, 35523=>1000, 35524=>1000, 35526=>1000, 35527=>1000, - 35528=>1000, 35529=>1000, 35530=>1000, 35531=>1000, 35532=>1000, 35533=>1000, 35535=>1000, 35537=>1000, 35538=>1000, 35539=>1000, 35540=>1000, 35541=>1000, 35542=>1000, 35543=>1000, 35546=>1000, 35547=>1000, - 35548=>1000, 35549=>1000, 35550=>1000, 35551=>1000, 35552=>1000, 35553=>1000, 35554=>1000, 35556=>1000, 35558=>1000, 35559=>1000, 35563=>1000, 35564=>1000, 35565=>1000, 35566=>1000, 35568=>1000, 35569=>1000, - 35571=>1000, 35572=>1000, 35573=>1000, 35574=>1000, 35575=>1000, 35576=>1000, 35578=>1000, 35580=>1000, 35582=>1000, 35583=>1000, 35584=>1000, 35585=>1000, 35586=>1000, 35588=>1000, 35589=>1000, 35590=>1000, - 35591=>1000, 35594=>1000, 35595=>1000, 35596=>1000, 35598=>1000, 35600=>1000, 35601=>1000, 35604=>1000, 35606=>1000, 35607=>1000, 35609=>1000, 35610=>1000, 35611=>1000, 35612=>1000, 35613=>1000, 35614=>1000, - 35615=>1000, 35616=>1000, 35617=>1000, 35622=>1000, 35624=>1000, 35627=>1000, 35628=>1000, 35629=>1000, 35632=>1000, 35635=>1000, 35639=>1000, 35641=>1000, 35644=>1000, 35646=>1000, 35649=>1000, 35650=>1000, - 35651=>1000, 35652=>1000, 35653=>1000, 35654=>1000, 35656=>1000, 35657=>1000, 35660=>1000, 35661=>1000, 35662=>1000, 35663=>1000, 35666=>1000, 35667=>1000, 35668=>1000, 35670=>1000, 35672=>1000, 35673=>1000, - 35674=>1000, 35675=>1000, 35676=>1000, 35678=>1000, 35679=>1000, 35683=>1000, 35686=>1000, 35691=>1000, 35692=>1000, 35693=>1000, 35695=>1000, 35696=>1000, 35697=>1000, 35698=>1000, 35700=>1000, 35702=>1000, - 35703=>1000, 35704=>1000, 35705=>1000, 35708=>1000, 35709=>1000, 35710=>1000, 35711=>1000, 35712=>1000, 35713=>1000, 35715=>1000, 35716=>1000, 35717=>1000, 35722=>1000, 35723=>1000, 35724=>1000, 35725=>1000, - 35726=>1000, 35727=>1000, 35728=>1000, 35730=>1000, 35731=>1000, 35732=>1000, 35733=>1000, 35734=>1000, 35737=>1000, 35738=>1000, 35740=>1000, 35742=>1000, 35743=>1000, 35895=>1000, 35896=>1000, 35897=>1000, - 35898=>1000, 35901=>1000, 35902=>1000, 35903=>1000, 35905=>1000, 35909=>1000, 35910=>1000, 35911=>1000, 35912=>1000, 35913=>1000, 35914=>1000, 35915=>1000, 35916=>1000, 35918=>1000, 35919=>1000, 35920=>1000, - 35921=>1000, 35923=>1000, 35924=>1000, 35925=>1000, 35927=>1000, 35928=>1000, 35929=>1000, 35930=>1000, 35931=>1000, 35933=>1000, 35937=>1000, 35938=>1000, 35939=>1000, 35940=>1000, 35942=>1000, 35944=>1000, - 35945=>1000, 35946=>1000, 35947=>1000, 35948=>1000, 35949=>1000, 35955=>1000, 35957=>1000, 35958=>1000, 35960=>1000, 35961=>1000, 35962=>1000, 35963=>1000, 35964=>1000, 35966=>1000, 35970=>1000, 35973=>1000, - 35974=>1000, 35975=>1000, 35977=>1000, 35978=>1000, 35979=>1000, 35980=>1000, 35981=>1000, 35982=>1000, 35984=>1000, 35986=>1000, 35987=>1000, 35988=>1000, 35992=>1000, 35993=>1000, 35995=>1000, 35996=>1000, - 35997=>1000, 35998=>1000, 36000=>1000, 36001=>1000, 36002=>1000, 36004=>1000, 36007=>1000, 36008=>1000, 36009=>1000, 36010=>1000, 36011=>1000, 36012=>1000, 36013=>1000, 36014=>1000, 36015=>1000, 36016=>1000, - 36018=>1000, 36019=>1000, 36020=>1000, 36022=>1000, 36023=>1000, 36024=>1000, 36025=>1000, 36026=>1000, 36027=>1000, 36028=>1000, 36029=>1000, 36031=>1000, 36032=>1000, 36033=>1000, 36034=>1000, 36035=>1000, - 36036=>1000, 36037=>1000, 36038=>1000, 36039=>1000, 36040=>1000, 36041=>1000, 36042=>1000, 36043=>1000, 36045=>1000, 36046=>1000, 36047=>1000, 36049=>1000, 36051=>1000, 36053=>1000, 36054=>1000, 36057=>1000, - 36058=>1000, 36059=>1000, 36060=>1000, 36061=>1000, 36062=>1000, 36064=>1000, 36065=>1000, 36066=>1000, 36067=>1000, 36068=>1000, 36070=>1000, 36072=>1000, 36074=>1000, 36076=>1000, 36077=>1000, 36079=>1000, - 36080=>1000, 36082=>1000, 36084=>1000, 36085=>1000, 36087=>1000, 36088=>1000, 36090=>1000, 36091=>1000, 36092=>1000, 36093=>1000, 36094=>1000, 36095=>1000, 36097=>1000, 36099=>1000, 36100=>1000, 36101=>1000, - 36103=>1000, 36104=>1000, 36105=>1000, 36106=>1000, 36107=>1000, 36109=>1000, 36111=>1000, 36112=>1000, 36114=>1000, 36115=>1000, 36116=>1000, 36118=>1000, 36119=>1000, 36123=>1000, 36196=>1000, 36197=>1000, - 36198=>1000, 36199=>1000, 36201=>1000, 36203=>1000, 36204=>1000, 36205=>1000, 36206=>1000, 36208=>1000, 36209=>1000, 36211=>1000, 36212=>1000, 36214=>1000, 36215=>1000, 36223=>1000, 36225=>1000, 36226=>1000, - 36228=>1000, 36229=>1000, 36232=>1000, 36234=>1000, 36237=>1000, 36240=>1000, 36241=>1000, 36245=>1000, 36249=>1000, 36254=>1000, 36255=>1000, 36256=>1000, 36259=>1000, 36262=>1000, 36264=>1000, 36267=>1000, - 36268=>1000, 36271=>1000, 36274=>1000, 36275=>1000, 36277=>1000, 36279=>1000, 36281=>1000, 36282=>1000, 36283=>1000, 36284=>1000, 36286=>1000, 36288=>1000, 36290=>1000, 36293=>1000, 36294=>1000, 36295=>1000, - 36296=>1000, 36298=>1000, 36299=>1000, 36300=>1000, 36302=>1000, 36303=>1000, 36305=>1000, 36308=>1000, 36309=>1000, 36310=>1000, 36311=>1000, 36313=>1000, 36314=>1000, 36315=>1000, 36317=>1000, 36319=>1000, - 36321=>1000, 36323=>1000, 36324=>1000, 36325=>1000, 36327=>1000, 36328=>1000, 36330=>1000, 36331=>1000, 36332=>1000, 36335=>1000, 36336=>1000, 36337=>1000, 36338=>1000, 36339=>1000, 36340=>1000, 36341=>1000, - 36348=>1000, 36349=>1000, 36351=>1000, 36353=>1000, 36356=>1000, 36357=>1000, 36358=>1000, 36360=>1000, 36361=>1000, 36362=>1000, 36363=>1000, 36367=>1000, 36368=>1000, 36369=>1000, 36372=>1000, 36374=>1000, - 36381=>1000, 36382=>1000, 36383=>1000, 36384=>1000, 36385=>1000, 36386=>1000, 36387=>1000, 36390=>1000, 36391=>1000, 36394=>1000, 36400=>1000, 36401=>1000, 36403=>1000, 36404=>1000, 36405=>1000, 36406=>1000, - 36407=>1000, 36408=>1000, 36409=>1000, 36413=>1000, 36416=>1000, 36417=>1000, 36418=>1000, 36420=>1000, 36423=>1000, 36424=>1000, 36425=>1000, 36426=>1000, 36427=>1000, 36428=>1000, 36429=>1000, 36430=>1000, - 36431=>1000, 36432=>1000, 36436=>1000, 36437=>1000, 36441=>1000, 36443=>1000, 36444=>1000, 36445=>1000, 36446=>1000, 36447=>1000, 36448=>1000, 36449=>1000, 36450=>1000, 36451=>1000, 36452=>1000, 36457=>1000, - 36460=>1000, 36461=>1000, 36463=>1000, 36464=>1000, 36465=>1000, 36466=>1000, 36468=>1000, 36470=>1000, 36473=>1000, 36474=>1000, 36475=>1000, 36476=>1000, 36481=>1000, 36482=>1000, 36483=>1000, 36484=>1000, - 36485=>1000, 36487=>1000, 36489=>1000, 36490=>1000, 36491=>1000, 36493=>1000, 36496=>1000, 36497=>1000, 36498=>1000, 36499=>1000, 36500=>1000, 36501=>1000, 36505=>1000, 36506=>1000, 36507=>1000, 36509=>1000, - 36510=>1000, 36513=>1000, 36514=>1000, 36519=>1000, 36521=>1000, 36522=>1000, 36523=>1000, 36524=>1000, 36525=>1000, 36526=>1000, 36527=>1000, 36528=>1000, 36529=>1000, 36531=>1000, 36533=>1000, 36538=>1000, - 36539=>1000, 36542=>1000, 36544=>1000, 36545=>1000, 36547=>1000, 36548=>1000, 36549=>1000, 36550=>1000, 36551=>1000, 36552=>1000, 36554=>1000, 36555=>1000, 36556=>1000, 36557=>1000, 36559=>1000, 36561=>1000, - 36562=>1000, 36564=>1000, 36571=>1000, 36572=>1000, 36575=>1000, 36578=>1000, 36579=>1000, 36584=>1000, 36587=>1000, 36589=>1000, 36590=>1000, 36592=>1000, 36593=>1000, 36599=>1000, 36600=>1000, 36601=>1000, - 36602=>1000, 36603=>1000, 36604=>1000, 36605=>1000, 36606=>1000, 36608=>1000, 36610=>1000, 36611=>1000, 36613=>1000, 36615=>1000, 36616=>1000, 36617=>1000, 36618=>1000, 36620=>1000, 36623=>1000, 36624=>1000, - 36626=>1000, 36627=>1000, 36628=>1000, 36629=>1000, 36630=>1000, 36631=>1000, 36632=>1000, 36633=>1000, 36635=>1000, 36636=>1000, 36637=>1000, 36638=>1000, 36639=>1000, 36640=>1000, 36641=>1000, 36643=>1000, - 36645=>1000, 36646=>1000, 36647=>1000, 36648=>1000, 36649=>1000, 36650=>1000, 36652=>1000, 36653=>1000, 36654=>1000, 36655=>1000, 36659=>1000, 36660=>1000, 36661=>1000, 36662=>1000, 36663=>1000, 36664=>1000, - 36665=>1000, 36666=>1000, 36667=>1000, 36670=>1000, 36671=>1000, 36672=>1000, 36673=>1000, 36674=>1000, 36675=>1000, 36676=>1000, 36677=>1000, 36678=>1000, 36679=>1000, 36681=>1000, 36684=>1000, 36685=>1000, - 36686=>1000, 36687=>1000, 36689=>1000, 36690=>1000, 36691=>1000, 36692=>1000, 36693=>1000, 36695=>1000, 36696=>1000, 36700=>1000, 36701=>1000, 36702=>1000, 36703=>1000, 36705=>1000, 36706=>1000, 36707=>1000, - 36708=>1000, 36709=>1000, 36763=>1000, 36764=>1000, 36765=>1000, 36766=>1000, 36767=>1000, 36768=>1000, 36769=>1000, 36771=>1000, 36772=>1000, 36773=>1000, 36774=>1000, 36775=>1000, 36776=>1000, 36781=>1000, - 36782=>1000, 36783=>1000, 36784=>1000, 36785=>1000, 36786=>1000, 36789=>1000, 36790=>1000, 36791=>1000, 36792=>1000, 36794=>1000, 36795=>1000, 36796=>1000, 36798=>1000, 36799=>1000, 36800=>1000, 36801=>1000, - 36802=>1000, 36804=>1000, 36805=>1000, 36806=>1000, 36810=>1000, 36811=>1000, 36813=>1000, 36814=>1000, 36816=>1000, 36817=>1000, 36818=>1000, 36819=>1000, 36820=>1000, 36821=>1000, 36826=>1000, 36832=>1000, - 36834=>1000, 36835=>1000, 36836=>1000, 36837=>1000, 36838=>1000, 36840=>1000, 36841=>1000, 36842=>1000, 36843=>1000, 36845=>1000, 36846=>1000, 36847=>1000, 36848=>1000, 36849=>1000, 36852=>1000, 36853=>1000, - 36854=>1000, 36855=>1000, 36856=>1000, 36857=>1000, 36858=>1000, 36859=>1000, 36861=>1000, 36862=>1000, 36864=>1000, 36865=>1000, 36866=>1000, 36867=>1000, 36868=>1000, 36869=>1000, 36870=>1000, 36872=>1000, - 36875=>1000, 36876=>1000, 36877=>1000, 36878=>1000, 36879=>1000, 36880=>1000, 36881=>1000, 36883=>1000, 36884=>1000, 36885=>1000, 36886=>1000, 36887=>1000, 36888=>1000, 36889=>1000, 36890=>1000, 36891=>1000, - 36893=>1000, 36894=>1000, 36895=>1000, 36896=>1000, 36897=>1000, 36898=>1000, 36899=>1000, 36903=>1000, 36904=>1000, 36905=>1000, 36906=>1000, 36908=>1000, 36909=>1000, 36910=>1000, 36911=>1000, 36913=>1000, - 36914=>1000, 36915=>1000, 36916=>1000, 36917=>1000, 36918=>1000, 36919=>1000, 36920=>1000, 36921=>1000, 36924=>1000, 36926=>1000, 36927=>1000, 36929=>1000, 36930=>1000, 36931=>1000, 36932=>1000, 36933=>1000, - 36935=>1000, 36937=>1000, 36938=>1000, 36939=>1000, 36940=>1000, 36941=>1000, 36942=>1000, 36943=>1000, 36944=>1000, 36945=>1000, 36946=>1000, 36947=>1000, 36948=>1000, 36949=>1000, 36950=>1000, 36952=>1000, - 36953=>1000, 36955=>1000, 36956=>1000, 36957=>1000, 36958=>1000, 36960=>1000, 36961=>1000, 36962=>1000, 36963=>1000, 36965=>1000, 36966=>1000, 36967=>1000, 36968=>1000, 36969=>1000, 36972=>1000, 36973=>1000, - 36974=>1000, 36975=>1000, 36976=>1000, 36978=>1000, 36980=>1000, 36981=>1000, 36982=>1000, 36983=>1000, 36984=>1000, 36985=>1000, 36986=>1000, 36988=>1000, 36989=>1000, 36991=>1000, 36992=>1000, 36993=>1000, - 36994=>1000, 36995=>1000, 36996=>1000, 36997=>1000, 36999=>1000, 37000=>1000, 37001=>1000, 37002=>1000, 37003=>1000, 37004=>1000, 37006=>1000, 37007=>1000, 37008=>1000, 37009=>1000, 37013=>1000, 37015=>1000, - 37016=>1000, 37017=>1000, 37019=>1000, 37024=>1000, 37025=>1000, 37026=>1000, 37027=>1000, 37029=>1000, 37030=>1000, 37032=>1000, 37034=>1000, 37039=>1000, 37040=>1000, 37041=>1000, 37042=>1000, 37043=>1000, - 37044=>1000, 37045=>1000, 37046=>1000, 37048=>1000, 37053=>1000, 37054=>1000, 37057=>1000, 37059=>1000, 37060=>1000, 37061=>1000, 37063=>1000, 37064=>1000, 37066=>1000, 37068=>1000, 37070=>1000, 37074=>1000, - 37077=>1000, 37079=>1000, 37080=>1000, 37081=>1000, 37083=>1000, 37084=>1000, 37085=>1000, 37086=>1000, 37087=>1000, 37089=>1000, 37090=>1000, 37092=>1000, 37093=>1000, 37096=>1000, 37099=>1000, 37101=>1000, - 37103=>1000, 37104=>1000, 37108=>1000, 37109=>1000, 37110=>1000, 37111=>1000, 37117=>1000, 37118=>1000, 37119=>1000, 37120=>1000, 37122=>1000, 37124=>1000, 37125=>1000, 37126=>1000, 37128=>1000, 37133=>1000, - 37136=>1000, 37138=>1000, 37140=>1000, 37141=>1000, 37142=>1000, 37143=>1000, 37144=>1000, 37145=>1000, 37146=>1000, 37148=>1000, 37150=>1000, 37152=>1000, 37154=>1000, 37155=>1000, 37157=>1000, 37159=>1000, - 37161=>1000, 37165=>1000, 37166=>1000, 37167=>1000, 37168=>1000, 37169=>1000, 37170=>1000, 37172=>1000, 37174=>1000, 37175=>1000, 37177=>1000, 37178=>1000, 37180=>1000, 37181=>1000, 37187=>1000, 37191=>1000, - 37192=>1000, 37193=>1000, 37194=>1000, 37195=>1000, 37196=>1000, 37197=>1000, 37198=>1000, 37199=>1000, 37202=>1000, 37203=>1000, 37204=>1000, 37206=>1000, 37207=>1000, 37208=>1000, 37209=>1000, 37210=>1000, - 37211=>1000, 37217=>1000, 37218=>1000, 37219=>1000, 37220=>1000, 37221=>1000, 37223=>1000, 37225=>1000, 37226=>1000, 37228=>1000, 37229=>1000, 37234=>1000, 37235=>1000, 37236=>1000, 37237=>1000, 37239=>1000, - 37240=>1000, 37241=>1000, 37242=>1000, 37243=>1000, 37249=>1000, 37250=>1000, 37251=>1000, 37253=>1000, 37254=>1000, 37255=>1000, 37257=>1000, 37258=>1000, 37259=>1000, 37261=>1000, 37262=>1000, 37264=>1000, - 37265=>1000, 37266=>1000, 37267=>1000, 37268=>1000, 37269=>1000, 37271=>1000, 37272=>1000, 37276=>1000, 37278=>1000, 37281=>1000, 37282=>1000, 37284=>1000, 37286=>1000, 37288=>1000, 37290=>1000, 37291=>1000, - 37292=>1000, 37293=>1000, 37294=>1000, 37295=>1000, 37296=>1000, 37297=>1000, 37298=>1000, 37299=>1000, 37300=>1000, 37301=>1000, 37302=>1000, 37304=>1000, 37306=>1000, 37307=>1000, 37308=>1000, 37309=>1000, - 37311=>1000, 37312=>1000, 37313=>1000, 37314=>1000, 37315=>1000, 37317=>1000, 37318=>1000, 37319=>1000, 37320=>1000, 37321=>1000, 37323=>1000, 37324=>1000, 37325=>1000, 37326=>1000, 37327=>1000, 37328=>1000, - 37329=>1000, 37331=>1000, 37332=>1000, 37334=>1000, 37335=>1000, 37336=>1000, 37337=>1000, 37338=>1000, 37339=>1000, 37340=>1000, 37341=>1000, 37342=>1000, 37343=>1000, 37345=>1000, 37347=>1000, 37348=>1000, - 37349=>1000, 37350=>1000, 37351=>1000, 37353=>1000, 37354=>1000, 37356=>1000, 37357=>1000, 37358=>1000, 37359=>1000, 37360=>1000, 37361=>1000, 37365=>1000, 37366=>1000, 37367=>1000, 37369=>1000, 37371=>1000, - 37372=>1000, 37373=>1000, 37375=>1000, 37376=>1000, 37377=>1000, 37380=>1000, 37381=>1000, 37382=>1000, 37383=>1000, 37385=>1000, 37386=>1000, 37388=>1000, 37389=>1000, 37390=>1000, 37392=>1000, 37393=>1000, - 37394=>1000, 37395=>1000, 37396=>1000, 37397=>1000, 37398=>1000, 37400=>1000, 37404=>1000, 37405=>1000, 37406=>1000, 37411=>1000, 37412=>1000, 37413=>1000, 37414=>1000, 37416=>1000, 37417=>1000, 37420=>1000, - 37422=>1000, 37423=>1000, 37424=>1000, 37427=>1000, 37428=>1000, 37429=>1000, 37430=>1000, 37431=>1000, 37432=>1000, 37433=>1000, 37434=>1000, 37436=>1000, 37438=>1000, 37439=>1000, 37440=>1000, 37442=>1000, - 37443=>1000, 37444=>1000, 37445=>1000, 37446=>1000, 37447=>1000, 37448=>1000, 37449=>1000, 37450=>1000, 37451=>1000, 37453=>1000, 37454=>1000, 37455=>1000, 37456=>1000, 37457=>1000, 37463=>1000, 37464=>1000, - 37465=>1000, 37466=>1000, 37467=>1000, 37468=>1000, 37469=>1000, 37470=>1000, 37472=>1000, 37473=>1000, 37474=>1000, 37476=>1000, 37477=>1000, 37478=>1000, 37479=>1000, 37480=>1000, 37481=>1000, 37486=>1000, - 37487=>1000, 37488=>1000, 37489=>1000, 37493=>1000, 37494=>1000, 37495=>1000, 37496=>1000, 37497=>1000, 37499=>1000, 37500=>1000, 37501=>1000, 37502=>1000, 37503=>1000, 37504=>1000, 37507=>1000, 37509=>1000, - 37512=>1000, 37513=>1000, 37514=>1000, 37517=>1000, 37518=>1000, 37521=>1000, 37522=>1000, 37523=>1000, 37525=>1000, 37526=>1000, 37527=>1000, 37528=>1000, 37529=>1000, 37530=>1000, 37531=>1000, 37532=>1000, - 37535=>1000, 37536=>1000, 37540=>1000, 37541=>1000, 37543=>1000, 37544=>1000, 37547=>1000, 37549=>1000, 37551=>1000, 37554=>1000, 37558=>1000, 37559=>1000, 37560=>1000, 37561=>1000, 37562=>1000, 37563=>1000, - 37564=>1000, 37565=>1000, 37567=>1000, 37568=>1000, 37569=>1000, 37570=>1000, 37571=>1000, 37573=>1000, 37574=>1000, 37575=>1000, 37576=>1000, 37579=>1000, 37580=>1000, 37581=>1000, 37582=>1000, 37583=>1000, - 37584=>1000, 37586=>1000, 37587=>1000, 37589=>1000, 37591=>1000, 37592=>1000, 37593=>1000, 37596=>1000, 37597=>1000, 37599=>1000, 37600=>1000, 37601=>1000, 37603=>1000, 37604=>1000, 37605=>1000, 37607=>1000, - 37608=>1000, 37609=>1000, 37610=>1000, 37612=>1000, 37613=>1000, 37614=>1000, 37616=>1000, 37618=>1000, 37619=>1000, 37624=>1000, 37625=>1000, 37626=>1000, 37627=>1000, 37628=>1000, 37631=>1000, 37632=>1000, - 37634=>1000, 37638=>1000, 37640=>1000, 37645=>1000, 37647=>1000, 37648=>1000, 37649=>1000, 37652=>1000, 37653=>1000, 37656=>1000, 37657=>1000, 37658=>1000, 37660=>1000, 37661=>1000, 37662=>1000, 37663=>1000, - 37664=>1000, 37665=>1000, 37666=>1000, 37667=>1000, 37668=>1000, 37669=>1000, 37670=>1000, 37671=>1000, 37672=>1000, 37673=>1000, 37674=>1000, 37675=>1000, 37676=>1000, 37678=>1000, 37679=>1000, 37682=>1000, - 37683=>1000, 37684=>1000, 37685=>1000, 37686=>1000, 37687=>1000, 37690=>1000, 37691=>1000, 37700=>1000, 37703=>1000, 37704=>1000, 37705=>1000, 37707=>1000, 37709=>1000, 37712=>1000, 37713=>1000, 37714=>1000, - 37716=>1000, 37717=>1000, 37718=>1000, 37719=>1000, 37720=>1000, 37722=>1000, 37723=>1000, 37724=>1000, 37726=>1000, 37728=>1000, 37732=>1000, 37733=>1000, 37735=>1000, 37737=>1000, 37738=>1000, 37740=>1000, - 37741=>1000, 37742=>1000, 37743=>1000, 37744=>1000, 37745=>1000, 37747=>1000, 37748=>1000, 37749=>1000, 37750=>1000, 37754=>1000, 37756=>1000, 37757=>1000, 37758=>1000, 37759=>1000, 37760=>1000, 37761=>1000, - 37762=>1000, 37768=>1000, 37770=>1000, 37771=>1000, 37772=>1000, 37773=>1000, 37775=>1000, 37778=>1000, 37780=>1000, 37781=>1000, 37782=>1000, 37783=>1000, 37784=>1000, 37786=>1000, 37787=>1000, 37790=>1000, - 37793=>1000, 37795=>1000, 37796=>1000, 37798=>1000, 37799=>1000, 37800=>1000, 37801=>1000, 37803=>1000, 37804=>1000, 37805=>1000, 37806=>1000, 37808=>1000, 37812=>1000, 37813=>1000, 37814=>1000, 37817=>1000, - 37818=>1000, 37825=>1000, 37827=>1000, 37828=>1000, 37829=>1000, 37830=>1000, 37831=>1000, 37832=>1000, 37833=>1000, 37834=>1000, 37835=>1000, 37836=>1000, 37837=>1000, 37840=>1000, 37841=>1000, 37843=>1000, - 37846=>1000, 37847=>1000, 37848=>1000, 37849=>1000, 37852=>1000, 37853=>1000, 37854=>1000, 37855=>1000, 37857=>1000, 37858=>1000, 37860=>1000, 37861=>1000, 37862=>1000, 37863=>1000, 37864=>1000, 37879=>1000, - 37880=>1000, 37881=>1000, 37882=>1000, 37883=>1000, 37885=>1000, 37889=>1000, 37890=>1000, 37891=>1000, 37892=>1000, 37895=>1000, 37896=>1000, 37897=>1000, 37901=>1000, 37902=>1000, 37903=>1000, 37904=>1000, - 37907=>1000, 37908=>1000, 37909=>1000, 37910=>1000, 37911=>1000, 37912=>1000, 37913=>1000, 37914=>1000, 37919=>1000, 37921=>1000, 37931=>1000, 37934=>1000, 37935=>1000, 37937=>1000, 37938=>1000, 37939=>1000, - 37940=>1000, 37941=>1000, 37942=>1000, 37944=>1000, 37946=>1000, 37947=>1000, 37949=>1000, 37951=>1000, 37953=>1000, 37955=>1000, 37956=>1000, 37957=>1000, 37960=>1000, 37962=>1000, 37964=>1000, 37969=>1000, - 37970=>1000, 37971=>1000, 37973=>1000, 37977=>1000, 37978=>1000, 37979=>1000, 37980=>1000, 37982=>1000, 37983=>1000, 37984=>1000, 37985=>1000, 37986=>1000, 37987=>1000, 37992=>1000, 37994=>1000, 37995=>1000, - 37997=>1000, 37998=>1000, 37999=>1000, 38000=>1000, 38001=>1000, 38002=>1000, 38005=>1000, 38007=>1000, 38012=>1000, 38013=>1000, 38014=>1000, 38015=>1000, 38017=>1000, 38019=>1000, 38020=>1000, 38263=>1000, - 38264=>1000, 38265=>1000, 38270=>1000, 38272=>1000, 38274=>1000, 38275=>1000, 38276=>1000, 38279=>1000, 38280=>1000, 38281=>1000, 38282=>1000, 38283=>1000, 38284=>1000, 38285=>1000, 38286=>1000, 38287=>1000, - 38289=>1000, 38290=>1000, 38291=>1000, 38292=>1000, 38294=>1000, 38296=>1000, 38297=>1000, 38301=>1000, 38302=>1000, 38303=>1000, 38304=>1000, 38305=>1000, 38306=>1000, 38307=>1000, 38308=>1000, 38309=>1000, - 38310=>1000, 38311=>1000, 38312=>1000, 38313=>1000, 38315=>1000, 38316=>1000, 38317=>1000, 38322=>1000, 38324=>1000, 38326=>1000, 38329=>1000, 38330=>1000, 38331=>1000, 38332=>1000, 38333=>1000, 38334=>1000, - 38335=>1000, 38339=>1000, 38342=>1000, 38343=>1000, 38344=>1000, 38345=>1000, 38346=>1000, 38347=>1000, 38348=>1000, 38349=>1000, 38352=>1000, 38353=>1000, 38354=>1000, 38355=>1000, 38356=>1000, 38357=>1000, - 38358=>1000, 38360=>1000, 38361=>1000, 38362=>1000, 38364=>1000, 38365=>1000, 38366=>1000, 38367=>1000, 38368=>1000, 38369=>1000, 38370=>1000, 38372=>1000, 38373=>1000, 38374=>1000, 38428=>1000, 38429=>1000, - 38430=>1000, 38433=>1000, 38434=>1000, 38436=>1000, 38437=>1000, 38438=>1000, 38440=>1000, 38442=>1000, 38444=>1000, 38446=>1000, 38447=>1000, 38449=>1000, 38450=>1000, 38451=>1000, 38455=>1000, 38456=>1000, - 38457=>1000, 38458=>1000, 38459=>1000, 38460=>1000, 38461=>1000, 38463=>1000, 38464=>1000, 38465=>1000, 38466=>1000, 38468=>1000, 38475=>1000, 38476=>1000, 38477=>1000, 38479=>1000, 38480=>1000, 38482=>1000, - 38484=>1000, 38486=>1000, 38487=>1000, 38488=>1000, 38491=>1000, 38492=>1000, 38493=>1000, 38494=>1000, 38495=>1000, 38497=>1000, 38498=>1000, 38499=>1000, 38500=>1000, 38501=>1000, 38502=>1000, 38506=>1000, - 38508=>1000, 38510=>1000, 38512=>1000, 38514=>1000, 38515=>1000, 38516=>1000, 38517=>1000, 38518=>1000, 38519=>1000, 38520=>1000, 38522=>1000, 38523=>1000, 38524=>1000, 38525=>1000, 38526=>1000, 38527=>1000, - 38529=>1000, 38530=>1000, 38531=>1000, 38532=>1000, 38533=>1000, 38534=>1000, 38536=>1000, 38537=>1000, 38538=>1000, 38539=>1000, 38541=>1000, 38542=>1000, 38543=>1000, 38545=>1000, 38548=>1000, 38549=>1000, - 38550=>1000, 38551=>1000, 38552=>1000, 38553=>1000, 38554=>1000, 38555=>1000, 38556=>1000, 38557=>1000, 38559=>1000, 38560=>1000, 38563=>1000, 38564=>1000, 38565=>1000, 38566=>1000, 38567=>1000, 38568=>1000, - 38569=>1000, 38570=>1000, 38574=>1000, 38575=>1000, 38576=>1000, 38577=>1000, 38578=>1000, 38579=>1000, 38580=>1000, 38582=>1000, 38583=>1000, 38584=>1000, 38585=>1000, 38586=>1000, 38587=>1000, 38588=>1000, - 38592=>1000, 38593=>1000, 38596=>1000, 38597=>1000, 38598=>1000, 38599=>1000, 38601=>1000, 38602=>1000, 38603=>1000, 38604=>1000, 38605=>1000, 38606=>1000, 38609=>1000, 38610=>1000, 38613=>1000, 38614=>1000, - 38616=>1000, 38617=>1000, 38618=>1000, 38619=>1000, 38620=>1000, 38621=>1000, 38622=>1000, 38623=>1000, 38626=>1000, 38627=>1000, 38632=>1000, 38633=>1000, 38634=>1000, 38635=>1000, 38639=>1000, 38640=>1000, - 38641=>1000, 38642=>1000, 38646=>1000, 38647=>1000, 38649=>1000, 38650=>1000, 38651=>1000, 38656=>1000, 38658=>1000, 38659=>1000, 38660=>1000, 38661=>1000, 38662=>1000, 38663=>1000, 38664=>1000, 38665=>1000, - 38666=>1000, 38669=>1000, 38670=>1000, 38671=>1000, 38673=>1000, 38675=>1000, 38678=>1000, 38681=>1000, 38682=>1000, 38683=>1000, 38684=>1000, 38685=>1000, 38686=>1000, 38689=>1000, 38690=>1000, 38691=>1000, - 38692=>1000, 38695=>1000, 38696=>1000, 38698=>1000, 38704=>1000, 38705=>1000, 38706=>1000, 38707=>1000, 38712=>1000, 38713=>1000, 38715=>1000, 38717=>1000, 38718=>1000, 38721=>1000, 38722=>1000, 38723=>1000, - 38724=>1000, 38726=>1000, 38728=>1000, 38729=>1000, 38730=>1000, 38733=>1000, 38734=>1000, 38735=>1000, 38737=>1000, 38738=>1000, 38741=>1000, 38742=>1000, 38743=>1000, 38744=>1000, 38745=>1000, 38746=>1000, - 38747=>1000, 38748=>1000, 38750=>1000, 38752=>1000, 38753=>1000, 38754=>1000, 38755=>1000, 38756=>1000, 38758=>1000, 38759=>1000, 38760=>1000, 38761=>1000, 38762=>1000, 38763=>1000, 38765=>1000, 38766=>1000, - 38769=>1000, 38771=>1000, 38772=>1000, 38774=>1000, 38775=>1000, 38776=>1000, 38777=>1000, 38778=>1000, 38779=>1000, 38780=>1000, 38781=>1000, 38783=>1000, 38784=>1000, 38785=>1000, 38788=>1000, 38789=>1000, - 38790=>1000, 38793=>1000, 38795=>1000, 38797=>1000, 38799=>1000, 38800=>1000, 38805=>1000, 38806=>1000, 38807=>1000, 38808=>1000, 38809=>1000, 38810=>1000, 38812=>1000, 38814=>1000, 38815=>1000, 38816=>1000, - 38818=>1000, 38819=>1000, 38822=>1000, 38824=>1000, 38827=>1000, 38828=>1000, 38829=>1000, 38830=>1000, 38833=>1000, 38834=>1000, 38835=>1000, 38836=>1000, 38837=>1000, 38838=>1000, 38840=>1000, 38841=>1000, - 38842=>1000, 38844=>1000, 38846=>1000, 38847=>1000, 38849=>1000, 38851=>1000, 38852=>1000, 38853=>1000, 38854=>1000, 38855=>1000, 38856=>1000, 38857=>1000, 38858=>1000, 38859=>1000, 38860=>1000, 38861=>1000, - 38862=>1000, 38864=>1000, 38865=>1000, 38867=>1000, 38868=>1000, 38871=>1000, 38872=>1000, 38873=>1000, 38875=>1000, 38876=>1000, 38877=>1000, 38878=>1000, 38880=>1000, 38881=>1000, 38884=>1000, 38893=>1000, - 38894=>1000, 38895=>1000, 38897=>1000, 38898=>1000, 38899=>1000, 38900=>1000, 38901=>1000, 38902=>1000, 38903=>1000, 38904=>1000, 38906=>1000, 38907=>1000, 38911=>1000, 38913=>1000, 38914=>1000, 38915=>1000, - 38917=>1000, 38918=>1000, 38919=>1000, 38920=>1000, 38922=>1000, 38924=>1000, 38925=>1000, 38926=>1000, 38927=>1000, 38928=>1000, 38929=>1000, 38930=>1000, 38931=>1000, 38932=>1000, 38934=>1000, 38935=>1000, - 38936=>1000, 38937=>1000, 38938=>1000, 38940=>1000, 38942=>1000, 38944=>1000, 38945=>1000, 38947=>1000, 38948=>1000, 38949=>1000, 38950=>1000, 38955=>1000, 38956=>1000, 38957=>1000, 38958=>1000, 38959=>1000, - 38960=>1000, 38962=>1000, 38963=>1000, 38964=>1000, 38965=>1000, 38967=>1000, 38968=>1000, 38971=>1000, 38972=>1000, 38973=>1000, 38974=>1000, 38980=>1000, 38982=>1000, 38983=>1000, 38986=>1000, 38987=>1000, - 38988=>1000, 38989=>1000, 38990=>1000, 38991=>1000, 38993=>1000, 38994=>1000, 38995=>1000, 38996=>1000, 38997=>1000, 38998=>1000, 38999=>1000, 39000=>1000, 39001=>1000, 39002=>1000, 39003=>1000, 39006=>1000, - 39010=>1000, 39011=>1000, 39013=>1000, 39014=>1000, 39015=>1000, 39018=>1000, 39019=>1000, 39020=>1000, 39023=>1000, 39024=>1000, 39025=>1000, 39027=>1000, 39028=>1000, 39080=>1000, 39082=>1000, 39083=>1000, - 39085=>1000, 39086=>1000, 39087=>1000, 39088=>1000, 39089=>1000, 39092=>1000, 39094=>1000, 39095=>1000, 39096=>1000, 39098=>1000, 39099=>1000, 39103=>1000, 39106=>1000, 39107=>1000, 39108=>1000, 39109=>1000, - 39110=>1000, 39112=>1000, 39116=>1000, 39131=>1000, 39132=>1000, 39135=>1000, 39137=>1000, 39138=>1000, 39139=>1000, 39141=>1000, 39142=>1000, 39143=>1000, 39145=>1000, 39146=>1000, 39147=>1000, 39149=>1000, - 39150=>1000, 39151=>1000, 39154=>1000, 39155=>1000, 39156=>1000, 39158=>1000, 39164=>1000, 39165=>1000, 39166=>1000, 39170=>1000, 39171=>1000, 39173=>1000, 39175=>1000, 39176=>1000, 39177=>1000, 39178=>1000, - 39180=>1000, 39184=>1000, 39185=>1000, 39186=>1000, 39187=>1000, 39188=>1000, 39189=>1000, 39190=>1000, 39191=>1000, 39192=>1000, 39194=>1000, 39195=>1000, 39196=>1000, 39197=>1000, 39198=>1000, 39199=>1000, - 39200=>1000, 39201=>1000, 39202=>1000, 39204=>1000, 39206=>1000, 39207=>1000, 39208=>1000, 39211=>1000, 39212=>1000, 39214=>1000, 39217=>1000, 39218=>1000, 39219=>1000, 39220=>1000, 39221=>1000, 39225=>1000, - 39226=>1000, 39227=>1000, 39228=>1000, 39229=>1000, 39230=>1000, 39232=>1000, 39233=>1000, 39234=>1000, 39237=>1000, 39238=>1000, 39239=>1000, 39240=>1000, 39241=>1000, 39243=>1000, 39244=>1000, 39245=>1000, - 39246=>1000, 39248=>1000, 39249=>1000, 39250=>1000, 39252=>1000, 39253=>1000, 39255=>1000, 39256=>1000, 39257=>1000, 39259=>1000, 39260=>1000, 39262=>1000, 39263=>1000, 39264=>1000, 39318=>1000, 39319=>1000, - 39320=>1000, 39321=>1000, 39323=>1000, 39325=>1000, 39326=>1000, 39327=>1000, 39333=>1000, 39334=>1000, 39336=>1000, 39340=>1000, 39341=>1000, 39342=>1000, 39344=>1000, 39345=>1000, 39346=>1000, 39347=>1000, - 39348=>1000, 39349=>1000, 39353=>1000, 39354=>1000, 39356=>1000, 39357=>1000, 39359=>1000, 39361=>1000, 39363=>1000, 39364=>1000, 39365=>1000, 39366=>1000, 39368=>1000, 39369=>1000, 39376=>1000, 39377=>1000, - 39378=>1000, 39379=>1000, 39380=>1000, 39381=>1000, 39384=>1000, 39385=>1000, 39386=>1000, 39387=>1000, 39388=>1000, 39389=>1000, 39390=>1000, 39391=>1000, 39394=>1000, 39399=>1000, 39402=>1000, 39403=>1000, - 39404=>1000, 39405=>1000, 39406=>1000, 39408=>1000, 39409=>1000, 39410=>1000, 39412=>1000, 39413=>1000, 39416=>1000, 39417=>1000, 39419=>1000, 39421=>1000, 39422=>1000, 39423=>1000, 39425=>1000, 39426=>1000, - 39427=>1000, 39428=>1000, 39429=>1000, 39435=>1000, 39436=>1000, 39438=>1000, 39439=>1000, 39440=>1000, 39441=>1000, 39442=>1000, 39443=>1000, 39446=>1000, 39449=>1000, 39454=>1000, 39456=>1000, 39458=>1000, - 39459=>1000, 39460=>1000, 39463=>1000, 39464=>1000, 39467=>1000, 39469=>1000, 39470=>1000, 39472=>1000, 39475=>1000, 39477=>1000, 39478=>1000, 39479=>1000, 39480=>1000, 39486=>1000, 39488=>1000, 39489=>1000, - 39490=>1000, 39491=>1000, 39492=>1000, 39493=>1000, 39495=>1000, 39498=>1000, 39499=>1000, 39500=>1000, 39501=>1000, 39502=>1000, 39505=>1000, 39508=>1000, 39509=>1000, 39510=>1000, 39511=>1000, 39514=>1000, - 39515=>1000, 39517=>1000, 39519=>1000, 39522=>1000, 39524=>1000, 39525=>1000, 39529=>1000, 39530=>1000, 39531=>1000, 39592=>1000, 39594=>1000, 39596=>1000, 39597=>1000, 39598=>1000, 39599=>1000, 39600=>1000, - 39602=>1000, 39604=>1000, 39605=>1000, 39606=>1000, 39608=>1000, 39609=>1000, 39611=>1000, 39612=>1000, 39614=>1000, 39615=>1000, 39616=>1000, 39617=>1000, 39619=>1000, 39620=>1000, 39622=>1000, 39624=>1000, - 39630=>1000, 39631=>1000, 39632=>1000, 39633=>1000, 39634=>1000, 39635=>1000, 39636=>1000, 39637=>1000, 39638=>1000, 39639=>1000, 39640=>1000, 39641=>1000, 39643=>1000, 39644=>1000, 39646=>1000, 39647=>1000, - 39648=>1000, 39650=>1000, 39651=>1000, 39652=>1000, 39653=>1000, 39654=>1000, 39655=>1000, 39657=>1000, 39658=>1000, 39659=>1000, 39660=>1000, 39661=>1000, 39662=>1000, 39663=>1000, 39665=>1000, 39666=>1000, - 39667=>1000, 39668=>1000, 39669=>1000, 39671=>1000, 39673=>1000, 39674=>1000, 39675=>1000, 39677=>1000, 39679=>1000, 39680=>1000, 39681=>1000, 39682=>1000, 39683=>1000, 39684=>1000, 39685=>1000, 39686=>1000, - 39688=>1000, 39689=>1000, 39691=>1000, 39692=>1000, 39693=>1000, 39694=>1000, 39696=>1000, 39698=>1000, 39702=>1000, 39704=>1000, 39705=>1000, 39706=>1000, 39707=>1000, 39708=>1000, 39711=>1000, 39712=>1000, - 39714=>1000, 39715=>1000, 39717=>1000, 39718=>1000, 39719=>1000, 39720=>1000, 39721=>1000, 39722=>1000, 39723=>1000, 39725=>1000, 39726=>1000, 39727=>1000, 39729=>1000, 39730=>1000, 39731=>1000, 39732=>1000, - 39733=>1000, 39735=>1000, 39737=>1000, 39738=>1000, 39739=>1000, 39740=>1000, 39741=>1000, 39745=>1000, 39746=>1000, 39747=>1000, 39748=>1000, 39749=>1000, 39752=>1000, 39755=>1000, 39756=>1000, 39757=>1000, - 39758=>1000, 39759=>1000, 39761=>1000, 39764=>1000, 39765=>1000, 39766=>1000, 39767=>1000, 39768=>1000, 39770=>1000, 39771=>1000, 39774=>1000, 39777=>1000, 39779=>1000, 39781=>1000, 39782=>1000, 39784=>1000, - 39786=>1000, 39787=>1000, 39788=>1000, 39789=>1000, 39790=>1000, 39791=>1000, 39794=>1000, 39795=>1000, 39796=>1000, 39797=>1000, 39799=>1000, 39800=>1000, 39801=>1000, 39807=>1000, 39808=>1000, 39811=>1000, - 39812=>1000, 39813=>1000, 39814=>1000, 39815=>1000, 39817=>1000, 39818=>1000, 39819=>1000, 39821=>1000, 39822=>1000, 39823=>1000, 39824=>1000, 39825=>1000, 39826=>1000, 39827=>1000, 39828=>1000, 39830=>1000, - 39831=>1000, 39834=>1000, 39837=>1000, 39838=>1000, 39839=>1000, 39840=>1000, 39846=>1000, 39847=>1000, 39848=>1000, 39849=>1000, 39850=>1000, 39851=>1000, 39852=>1000, 39853=>1000, 39854=>1000, 39856=>1000, - 39857=>1000, 39858=>1000, 39860=>1000, 39863=>1000, 39864=>1000, 39865=>1000, 39867=>1000, 39868=>1000, 39870=>1000, 39871=>1000, 39872=>1000, 39873=>1000, 39878=>1000, 39879=>1000, 39880=>1000, 39881=>1000, - 39882=>1000, 39886=>1000, 39887=>1000, 39888=>1000, 39889=>1000, 39890=>1000, 39892=>1000, 39894=>1000, 39895=>1000, 39896=>1000, 39899=>1000, 39901=>1000, 39903=>1000, 39905=>1000, 39906=>1000, 39907=>1000, - 39908=>1000, 39909=>1000, 39911=>1000, 39912=>1000, 39914=>1000, 39915=>1000, 39919=>1000, 39920=>1000, 39921=>1000, 39922=>1000, 39923=>1000, 39925=>1000, 39927=>1000, 39928=>1000, 39929=>1000, 39930=>1000, - 39933=>1000, 39935=>1000, 39936=>1000, 39938=>1000, 39940=>1000, 39942=>1000, 39944=>1000, 39945=>1000, 39946=>1000, 39947=>1000, 39948=>1000, 39949=>1000, 39951=>1000, 39952=>1000, 39953=>1000, 39954=>1000, - 39955=>1000, 39956=>1000, 39957=>1000, 39958=>1000, 39960=>1000, 39961=>1000, 39962=>1000, 39963=>1000, 39964=>1000, 39966=>1000, 39969=>1000, 39970=>1000, 39971=>1000, 39972=>1000, 39973=>1000, 39974=>1000, - 39975=>1000, 39976=>1000, 39977=>1000, 39978=>1000, 39981=>1000, 39982=>1000, 39983=>1000, 39984=>1000, 39985=>1000, 39986=>1000, 39989=>1000, 39990=>1000, 39991=>1000, 39993=>1000, 39994=>1000, 39995=>1000, - 39997=>1000, 39998=>1000, 40001=>1000, 40003=>1000, 40004=>1000, 40005=>1000, 40006=>1000, 40007=>1000, 40008=>1000, 40009=>1000, 40010=>1000, 40014=>1000, 40015=>1000, 40016=>1000, 40018=>1000, 40019=>1000, - 40020=>1000, 40022=>1000, 40023=>1000, 40024=>1000, 40026=>1000, 40027=>1000, 40028=>1000, 40029=>1000, 40030=>1000, 40031=>1000, 40032=>1000, 40035=>1000, 40039=>1000, 40040=>1000, 40041=>1000, 40042=>1000, - 40043=>1000, 40046=>1000, 40048=>1000, 40050=>1000, 40053=>1000, 40054=>1000, 40055=>1000, 40056=>1000, 40059=>1000, 40165=>1000, 40166=>1000, 40167=>1000, 40169=>1000, 40171=>1000, 40172=>1000, 40176=>1000, - 40178=>1000, 40179=>1000, 40180=>1000, 40182=>1000, 40183=>1000, 40185=>1000, 40194=>1000, 40195=>1000, 40198=>1000, 40199=>1000, 40200=>1000, 40201=>1000, 40203=>1000, 40206=>1000, 40209=>1000, 40210=>1000, - 40213=>1000, 40215=>1000, 40216=>1000, 40219=>1000, 40220=>1000, 40221=>1000, 40222=>1000, 40223=>1000, 40227=>1000, 40230=>1000, 40232=>1000, 40234=>1000, 40235=>1000, 40236=>1000, 40239=>1000, 40240=>1000, - 40242=>1000, 40243=>1000, 40244=>1000, 40250=>1000, 40251=>1000, 40252=>1000, 40253=>1000, 40254=>1000, 40255=>1000, 40257=>1000, 40258=>1000, 40259=>1000, 40260=>1000, 40261=>1000, 40262=>1000, 40263=>1000, - 40264=>1000, 40266=>1000, 40272=>1000, 40273=>1000, 40275=>1000, 40276=>1000, 40281=>1000, 40284=>1000, 40285=>1000, 40286=>1000, 40287=>1000, 40288=>1000, 40289=>1000, 40290=>1000, 40291=>1000, 40292=>1000, - 40293=>1000, 40297=>1000, 40298=>1000, 40299=>1000, 40300=>1000, 40303=>1000, 40304=>1000, 40306=>1000, 40310=>1000, 40311=>1000, 40314=>1000, 40315=>1000, 40316=>1000, 40318=>1000, 40323=>1000, 40324=>1000, - 40326=>1000, 40327=>1000, 40329=>1000, 40330=>1000, 40333=>1000, 40334=>1000, 40335=>1000, 40338=>1000, 40339=>1000, 40341=>1000, 40342=>1000, 40343=>1000, 40344=>1000, 40346=>1000, 40353=>1000, 40356=>1000, - 40361=>1000, 40362=>1000, 40363=>1000, 40364=>1000, 40366=>1000, 40367=>1000, 40369=>1000, 40370=>1000, 40372=>1000, 40373=>1000, 40376=>1000, 40377=>1000, 40378=>1000, 40379=>1000, 40380=>1000, 40383=>1000, - 40385=>1000, 40386=>1000, 40387=>1000, 40388=>1000, 40390=>1000, 40391=>1000, 40393=>1000, 40394=>1000, 40399=>1000, 40403=>1000, 40404=>1000, 40405=>1000, 40406=>1000, 40407=>1000, 40409=>1000, 40410=>1000, - 40414=>1000, 40415=>1000, 40416=>1000, 40421=>1000, 40422=>1000, 40423=>1000, 40425=>1000, 40427=>1000, 40429=>1000, 40430=>1000, 40431=>1000, 40432=>1000, 40434=>1000, 40435=>1000, 40436=>1000, 40440=>1000, - 40441=>1000, 40442=>1000, 40445=>1000, 40446=>1000, 40450=>1000, 40455=>1000, 40458=>1000, 40462=>1000, 40464=>1000, 40465=>1000, 40466=>1000, 40469=>1000, 40470=>1000, 40473=>1000, 40474=>1000, 40475=>1000, - 40476=>1000, 40477=>1000, 40478=>1000, 40565=>1000, 40568=>1000, 40569=>1000, 40570=>1000, 40571=>1000, 40572=>1000, 40573=>1000, 40575=>1000, 40576=>1000, 40577=>1000, 40578=>1000, 40579=>1000, 40580=>1000, - 40581=>1000, 40583=>1000, 40584=>1000, 40587=>1000, 40588=>1000, 40590=>1000, 40591=>1000, 40593=>1000, 40594=>1000, 40595=>1000, 40597=>1000, 40598=>1000, 40599=>1000, 40600=>1000, 40603=>1000, 40605=>1000, - 40606=>1000, 40607=>1000, 40612=>1000, 40613=>1000, 40614=>1000, 40616=>1000, 40617=>1000, 40618=>1000, 40620=>1000, 40621=>1000, 40622=>1000, 40623=>1000, 40624=>1000, 40627=>1000, 40628=>1000, 40629=>1000, - 40632=>1000, 40633=>1000, 40634=>1000, 40635=>1000, 40636=>1000, 40638=>1000, 40639=>1000, 40644=>1000, 40646=>1000, 40648=>1000, 40651=>1000, 40652=>1000, 40653=>1000, 40654=>1000, 40655=>1000, 40656=>1000, - 40657=>1000, 40658=>1000, 40660=>1000, 40661=>1000, 40664=>1000, 40665=>1000, 40667=>1000, 40668=>1000, 40669=>1000, 40670=>1000, 40671=>1000, 40672=>1000, 40676=>1000, 40677=>1000, 40679=>1000, 40680=>1000, - 40684=>1000, 40685=>1000, 40686=>1000, 40687=>1000, 40688=>1000, 40689=>1000, 40690=>1000, 40692=>1000, 40693=>1000, 40694=>1000, 40695=>1000, 40696=>1000, 40697=>1000, 40699=>1000, 40700=>1000, 40701=>1000, - 40703=>1000, 40706=>1000, 40707=>1000, 40711=>1000, 40712=>1000, 40713=>1000, 40718=>1000, 40719=>1000, 40720=>1000, 40721=>1000, 40722=>1000, 40723=>1000, 40724=>1000, 40725=>1000, 40726=>1000, 40727=>1000, - 40729=>1000, 40730=>1000, 40731=>1000, 40735=>1000, 40736=>1000, 40737=>1000, 40738=>1000, 40742=>1000, 40746=>1000, 40747=>1000, 40748=>1000, 40751=>1000, 40753=>1000, 40754=>1000, 40756=>1000, 40759=>1000, - 40761=>1000, 40762=>1000, 40763=>1000, 40764=>1000, 40765=>1000, 40766=>1000, 40767=>1000, 40769=>1000, 40771=>1000, 40772=>1000, 40773=>1000, 40774=>1000, 40775=>1000, 40778=>1000, 40779=>1000, 40782=>1000, - 40783=>1000, 40786=>1000, 40787=>1000, 40788=>1000, 40789=>1000, 40790=>1000, 40791=>1000, 40792=>1000, 40794=>1000, 40797=>1000, 40798=>1000, 40799=>1000, 40800=>1000, 40801=>1000, 40802=>1000, 40803=>1000, - 40806=>1000, 40807=>1000, 40808=>1000, 40809=>1000, 40810=>1000, 40812=>1000, 40813=>1000, 40814=>1000, 40815=>1000, 40816=>1000, 40817=>1000, 40818=>1000, 40819=>1000, 40821=>1000, 40822=>1000, 40823=>1000, - 40826=>1000, 40829=>1000, 40845=>1000, 40847=>1000, 40848=>1000, 40849=>1000, 40850=>1000, 40852=>1000, 40853=>1000, 40854=>1000, 40855=>1000, 40860=>1000, 40861=>1000, 40862=>1000, 40864=>1000, 40865=>1000, - 40866=>1000, 40867=>1000, 40869=>1000, 63785=>1000, 63964=>1000, 64014=>1000, 64015=>1000, 64016=>1000, 64017=>1000, 64018=>1000, 64019=>1000, 64020=>1000, 64021=>1000, 64022=>1000, 64023=>1000, 64024=>1000, - 64025=>1000, 64026=>1000, 64027=>1000, 64028=>1000, 64029=>1000, 64030=>1000, 64031=>1000, 64032=>1000, 64033=>1000, 64034=>1000, 64035=>1000, 64036=>1000, 64037=>1000, 64038=>1000, 64039=>1000, 64040=>1000, - 64041=>1000, 64042=>1000, 64043=>1000, 64044=>1000, 64045=>1000, 65281=>1000, 65282=>1000, 65283=>1000, 65284=>1000, 65285=>1000, 65286=>1000, 65287=>1000, 65288=>1000, 65289=>1000, 65290=>1000, 65291=>1000, - 65292=>1000, 65293=>1000, 65294=>1000, 65295=>1000, 65296=>1000, 65297=>1000, 65298=>1000, 65299=>1000, 65300=>1000, 65301=>1000, 65302=>1000, 65303=>1000, 65304=>1000, 65305=>1000, 65306=>1000, 65307=>1000, - 65308=>1000, 65309=>1000, 65310=>1000, 65311=>1000, 65312=>1000, 65313=>1000, 65314=>1000, 65315=>1000, 65316=>1000, 65317=>1000, 65318=>1000, 65319=>1000, 65320=>1000, 65321=>1000, 65322=>1000, 65323=>1000, - 65324=>1000, 65325=>1000, 65326=>1000, 65327=>1000, 65328=>1000, 65329=>1000, 65330=>1000, 65331=>1000, 65332=>1000, 65333=>1000, 65334=>1000, 65335=>1000, 65336=>1000, 65337=>1000, 65338=>1000, 65339=>1000, - 65340=>1000, 65341=>1000, 65342=>1000, 65343=>1000, 65344=>1000, 65345=>1000, 65346=>1000, 65347=>1000, 65348=>1000, 65349=>1000, 65350=>1000, 65351=>1000, 65352=>1000, 65353=>1000, 65354=>1000, 65355=>1000, - 65356=>1000, 65357=>1000, 65358=>1000, 65359=>1000, 65360=>1000, 65361=>1000, 65362=>1000, 65363=>1000, 65364=>1000, 65365=>1000, 65366=>1000, 65367=>1000, 65368=>1000, 65369=>1000, 65370=>1000, 65371=>1000, - 65372=>1000, 65373=>1000, 65374=>1000, 65377=>500, 65378=>500, 65379=>500, 65380=>500, 65381=>500, 65382=>500, 65383=>500, 65384=>500, 65385=>500, 65386=>500, 65387=>500, 65388=>500, 65389=>500, - 65390=>500, 65391=>500, 65392=>500, 65393=>500, 65394=>500, 65395=>500, 65396=>500, 65397=>500, 65398=>500, 65399=>500, 65400=>500, 65401=>500, 65402=>500, 65403=>500, 65404=>500, 65405=>500, - 65406=>500, 65407=>500, 65408=>500, 65409=>500, 65410=>500, 65411=>500, 65412=>500, 65413=>500, 65414=>500, 65415=>500, 65416=>500, 65417=>500, 65418=>500, 65419=>500, 65420=>500, 65421=>500, - 65422=>500, 65423=>500, 65424=>500, 65425=>500, 65426=>500, 65427=>500, 65428=>500, 65429=>500, 65430=>500, 65431=>500, 65432=>500, 65433=>500, 65434=>500, 65435=>500, 65436=>500, 65437=>500, - 65438=>500, 65439=>500, 65504=>1000, 65505=>1000, 65506=>1000, 65507=>1000, 65509=>1000} - font[:enc]=''; - font[:diff]=''; - font[:file]=''; - font[:registry]={'ordering'=>'Japan1','supplement'=>2} -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/symbol.rb --- a/vendor/plugins/rfpdf/lib/fonts/symbol.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -TCPDFFontDescriptor.define('symbol') do |font| - font[:cw]={ - 0.chr=>250,1.chr=>250,2.chr=>250,3.chr=>250,4.chr=>250,5.chr=>250,6.chr=>250,7.chr=>250,8.chr=>250,9.chr=>250,10.chr=>250,11.chr=>250,12.chr=>250,13.chr=>250,14.chr=>250,15.chr=>250,16.chr=>250,17.chr=>250,18.chr=>250,19.chr=>250,20.chr=>250,21.chr=>250, - 22.chr=>250,23.chr=>250,24.chr=>250,25.chr=>250,26.chr=>250,27.chr=>250,28.chr=>250,29.chr=>250,30.chr=>250,31.chr=>250,' '=>250,'!'=>333,'"'=>713,'#'=>500,'$'=>549,'%'=>833,'&'=>778,'\''=>439,'('=>333,')'=>333,'*'=>500,'+'=>549, - ','=>250,'-'=>549,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>549,'='=>549,'>'=>549,'?'=>444,'@'=>549,'A'=>722, - 'B'=>667,'C'=>722,'D'=>612,'E'=>611,'F'=>763,'G'=>603,'H'=>722,'I'=>333,'J'=>631,'K'=>722,'L'=>686,'M'=>889,'N'=>722,'O'=>722,'P'=>768,'Q'=>741,'R'=>556,'S'=>592,'T'=>611,'U'=>690,'V'=>439,'W'=>768, - 'X'=>645,'Y'=>795,'Z'=>611,'['=>333,'\\'=>863,']'=>333,'^'=>658,'_'=>500,'`'=>500,'a'=>631,'b'=>549,'c'=>549,'d'=>494,'e'=>439,'f'=>521,'g'=>411,'h'=>603,'i'=>329,'j'=>603,'k'=>549,'l'=>549,'m'=>576, - 'n'=>521,'o'=>549,'p'=>549,'q'=>521,'r'=>549,'s'=>603,'t'=>439,'u'=>576,'v'=>713,'w'=>686,'x'=>493,'y'=>686,'z'=>494,'{'=>480,'|'=>200,'}'=>480,'~'=>549,127.chr=>0,128.chr=>0,129.chr=>0,130.chr=>0,131.chr=>0, - 132.chr=>0,133.chr=>0,134.chr=>0,135.chr=>0,136.chr=>0,137.chr=>0,138.chr=>0,139.chr=>0,140.chr=>0,141.chr=>0,142.chr=>0,143.chr=>0,144.chr=>0,145.chr=>0,146.chr=>0,147.chr=>0,148.chr=>0,149.chr=>0,150.chr=>0,151.chr=>0,152.chr=>0,153.chr=>0, - 154.chr=>0,155.chr=>0,156.chr=>0,157.chr=>0,158.chr=>0,159.chr=>0,160.chr=>750,161.chr=>620,162.chr=>247,163.chr=>549,164.chr=>167,165.chr=>713,166.chr=>500,167.chr=>753,168.chr=>753,169.chr=>753,170.chr=>753,171.chr=>1042,172.chr=>987,173.chr=>603,174.chr=>987,175.chr=>603, - 176.chr=>400,177.chr=>549,178.chr=>411,179.chr=>549,180.chr=>549,181.chr=>713,182.chr=>494,183.chr=>460,184.chr=>549,185.chr=>549,186.chr=>549,187.chr=>549,188.chr=>1000,189.chr=>603,190.chr=>1000,191.chr=>658,192.chr=>823,193.chr=>686,194.chr=>795,195.chr=>987,196.chr=>768,197.chr=>768, - 198.chr=>823,199.chr=>768,200.chr=>768,201.chr=>713,202.chr=>713,203.chr=>713,204.chr=>713,205.chr=>713,206.chr=>713,207.chr=>713,208.chr=>768,209.chr=>713,210.chr=>790,211.chr=>790,212.chr=>890,213.chr=>823,214.chr=>549,215.chr=>250,216.chr=>713,217.chr=>603,218.chr=>603,219.chr=>1042, - 220.chr=>987,221.chr=>603,222.chr=>987,223.chr=>603,224.chr=>494,225.chr=>329,226.chr=>790,227.chr=>790,228.chr=>786,229.chr=>713,230.chr=>384,231.chr=>384,232.chr=>384,233.chr=>384,234.chr=>384,235.chr=>384,236.chr=>494,237.chr=>494,238.chr=>494,239.chr=>494,240.chr=>0,241.chr=>329, - 242.chr=>274,243.chr=>686,244.chr=>686,245.chr=>686,246.chr=>384,247.chr=>384,248.chr=>384,249.chr=>384,250.chr=>384,251.chr=>384,252.chr=>494,253.chr=>494,254.chr=>494,255.chr=>0); -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/times.rb --- a/vendor/plugins/rfpdf/lib/fonts/times.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -TCPDFFontDescriptor.define('times') do |font| - font[:cw]={ - 0.chr=>250,1.chr=>250,2.chr=>250,3.chr=>250,4.chr=>250,5.chr=>250,6.chr=>250,7.chr=>250,8.chr=>250,9.chr=>250,10.chr=>250,11.chr=>250,12.chr=>250,13.chr=>250,14.chr=>250,15.chr=>250,16.chr=>250,17.chr=>250,18.chr=>250,19.chr=>250,20.chr=>250,21.chr=>250, - 22.chr=>250,23.chr=>250,24.chr=>250,25.chr=>250,26.chr=>250,27.chr=>250,28.chr=>250,29.chr=>250,30.chr=>250,31.chr=>250,' '=>250,'!'=>333,'"'=>408,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>180,'('=>333,')'=>333,'*'=>500,'+'=>564, - ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>278,';'=>278,'<'=>564,'='=>564,'>'=>564,'?'=>444,'@'=>921,'A'=>722, - 'B'=>667,'C'=>667,'D'=>722,'E'=>611,'F'=>556,'G'=>722,'H'=>722,'I'=>333,'J'=>389,'K'=>722,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>556,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>722,'W'=>944, - 'X'=>722,'Y'=>722,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>469,'_'=>500,'`'=>333,'a'=>444,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778, - 'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>333,'s'=>389,'t'=>278,'u'=>500,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>480,'|'=>200,'}'=>480,'~'=>541,127.chr=>350,128.chr=>500,129.chr=>350,130.chr=>333,131.chr=>500, - 132.chr=>444,133.chr=>1000,134.chr=>500,135.chr=>500,136.chr=>333,137.chr=>1000,138.chr=>556,139.chr=>333,140.chr=>889,141.chr=>350,142.chr=>611,143.chr=>350,144.chr=>350,145.chr=>333,146.chr=>333,147.chr=>444,148.chr=>444,149.chr=>350,150.chr=>500,151.chr=>1000,152.chr=>333,153.chr=>980, - 154.chr=>389,155.chr=>333,156.chr=>722,157.chr=>350,158.chr=>444,159.chr=>722,160.chr=>250,161.chr=>333,162.chr=>500,163.chr=>500,164.chr=>500,165.chr=>500,166.chr=>200,167.chr=>500,168.chr=>333,169.chr=>760,170.chr=>276,171.chr=>500,172.chr=>564,173.chr=>333,174.chr=>760,175.chr=>333, - 176.chr=>400,177.chr=>564,178.chr=>300,179.chr=>300,180.chr=>333,181.chr=>500,182.chr=>453,183.chr=>250,184.chr=>333,185.chr=>300,186.chr=>310,187.chr=>500,188.chr=>750,189.chr=>750,190.chr=>750,191.chr=>444,192.chr=>722,193.chr=>722,194.chr=>722,195.chr=>722,196.chr=>722,197.chr=>722, - 198.chr=>889,199.chr=>667,200.chr=>611,201.chr=>611,202.chr=>611,203.chr=>611,204.chr=>333,205.chr=>333,206.chr=>333,207.chr=>333,208.chr=>722,209.chr=>722,210.chr=>722,211.chr=>722,212.chr=>722,213.chr=>722,214.chr=>722,215.chr=>564,216.chr=>722,217.chr=>722,218.chr=>722,219.chr=>722, - 220.chr=>722,221.chr=>722,222.chr=>556,223.chr=>500,224.chr=>444,225.chr=>444,226.chr=>444,227.chr=>444,228.chr=>444,229.chr=>444,230.chr=>667,231.chr=>444,232.chr=>444,233.chr=>444,234.chr=>444,235.chr=>444,236.chr=>278,237.chr=>278,238.chr=>278,239.chr=>278,240.chr=>500,241.chr=>500, - 242.chr=>500,243.chr=>500,244.chr=>500,245.chr=>500,246.chr=>500,247.chr=>564,248.chr=>500,249.chr=>500,250.chr=>500,251.chr=>500,252.chr=>500,253.chr=>500,254.chr=>500,255.chr=>500); -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/timesb.rb --- a/vendor/plugins/rfpdf/lib/fonts/timesb.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -TCPDFFontDescriptor.define('timesb') do |font| - font[:cw]={ - 0.chr=>250,1.chr=>250,2.chr=>250,3.chr=>250,4.chr=>250,5.chr=>250,6.chr=>250,7.chr=>250,8.chr=>250,9.chr=>250,10.chr=>250,11.chr=>250,12.chr=>250,13.chr=>250,14.chr=>250,15.chr=>250,16.chr=>250,17.chr=>250,18.chr=>250,19.chr=>250,20.chr=>250,21.chr=>250, - 22.chr=>250,23.chr=>250,24.chr=>250,25.chr=>250,26.chr=>250,27.chr=>250,28.chr=>250,29.chr=>250,30.chr=>250,31.chr=>250,' '=>250,'!'=>333,'"'=>555,'#'=>500,'$'=>500,'%'=>1000,'&'=>833,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570, - ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>930,'A'=>722, - 'B'=>667,'C'=>722,'D'=>722,'E'=>667,'F'=>611,'G'=>778,'H'=>778,'I'=>389,'J'=>500,'K'=>778,'L'=>667,'M'=>944,'N'=>722,'O'=>778,'P'=>611,'Q'=>778,'R'=>722,'S'=>556,'T'=>667,'U'=>722,'V'=>722,'W'=>1000, - 'X'=>722,'Y'=>722,'Z'=>667,'['=>333,'\\'=>278,']'=>333,'^'=>581,'_'=>500,'`'=>333,'a'=>500,'b'=>556,'c'=>444,'d'=>556,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>333,'k'=>556,'l'=>278,'m'=>833, - 'n'=>556,'o'=>500,'p'=>556,'q'=>556,'r'=>444,'s'=>389,'t'=>333,'u'=>556,'v'=>500,'w'=>722,'x'=>500,'y'=>500,'z'=>444,'{'=>394,'|'=>220,'}'=>394,'~'=>520,127.chr=>350,128.chr=>500,129.chr=>350,130.chr=>333,131.chr=>500, - 132.chr=>500,133.chr=>1000,134.chr=>500,135.chr=>500,136.chr=>333,137.chr=>1000,138.chr=>556,139.chr=>333,140.chr=>1000,141.chr=>350,142.chr=>667,143.chr=>350,144.chr=>350,145.chr=>333,146.chr=>333,147.chr=>500,148.chr=>500,149.chr=>350,150.chr=>500,151.chr=>1000,152.chr=>333,153.chr=>1000, - 154.chr=>389,155.chr=>333,156.chr=>722,157.chr=>350,158.chr=>444,159.chr=>722,160.chr=>250,161.chr=>333,162.chr=>500,163.chr=>500,164.chr=>500,165.chr=>500,166.chr=>220,167.chr=>500,168.chr=>333,169.chr=>747,170.chr=>300,171.chr=>500,172.chr=>570,173.chr=>333,174.chr=>747,175.chr=>333, - 176.chr=>400,177.chr=>570,178.chr=>300,179.chr=>300,180.chr=>333,181.chr=>556,182.chr=>540,183.chr=>250,184.chr=>333,185.chr=>300,186.chr=>330,187.chr=>500,188.chr=>750,189.chr=>750,190.chr=>750,191.chr=>500,192.chr=>722,193.chr=>722,194.chr=>722,195.chr=>722,196.chr=>722,197.chr=>722, - 198.chr=>1000,199.chr=>722,200.chr=>667,201.chr=>667,202.chr=>667,203.chr=>667,204.chr=>389,205.chr=>389,206.chr=>389,207.chr=>389,208.chr=>722,209.chr=>722,210.chr=>778,211.chr=>778,212.chr=>778,213.chr=>778,214.chr=>778,215.chr=>570,216.chr=>778,217.chr=>722,218.chr=>722,219.chr=>722, - 220.chr=>722,221.chr=>722,222.chr=>611,223.chr=>556,224.chr=>500,225.chr=>500,226.chr=>500,227.chr=>500,228.chr=>500,229.chr=>500,230.chr=>722,231.chr=>444,232.chr=>444,233.chr=>444,234.chr=>444,235.chr=>444,236.chr=>278,237.chr=>278,238.chr=>278,239.chr=>278,240.chr=>500,241.chr=>556, - 242.chr=>500,243.chr=>500,244.chr=>500,245.chr=>500,246.chr=>500,247.chr=>570,248.chr=>500,249.chr=>556,250.chr=>556,251.chr=>556,252.chr=>556,253.chr=>500,254.chr=>556,255.chr=>500); -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/timesbi.rb --- a/vendor/plugins/rfpdf/lib/fonts/timesbi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -TCPDFFontDescriptor.define('timesbi') do |font| - font[:cw]={ - 0.chr=>250,1.chr=>250,2.chr=>250,3.chr=>250,4.chr=>250,5.chr=>250,6.chr=>250,7.chr=>250,8.chr=>250,9.chr=>250,10.chr=>250,11.chr=>250,12.chr=>250,13.chr=>250,14.chr=>250,15.chr=>250,16.chr=>250,17.chr=>250,18.chr=>250,19.chr=>250,20.chr=>250,21.chr=>250, - 22.chr=>250,23.chr=>250,24.chr=>250,25.chr=>250,26.chr=>250,27.chr=>250,28.chr=>250,29.chr=>250,30.chr=>250,31.chr=>250,' '=>250,'!'=>389,'"'=>555,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>278,'('=>333,')'=>333,'*'=>500,'+'=>570, - ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>570,'='=>570,'>'=>570,'?'=>500,'@'=>832,'A'=>667, - 'B'=>667,'C'=>667,'D'=>722,'E'=>667,'F'=>667,'G'=>722,'H'=>778,'I'=>389,'J'=>500,'K'=>667,'L'=>611,'M'=>889,'N'=>722,'O'=>722,'P'=>611,'Q'=>722,'R'=>667,'S'=>556,'T'=>611,'U'=>722,'V'=>667,'W'=>889, - 'X'=>667,'Y'=>611,'Z'=>611,'['=>333,'\\'=>278,']'=>333,'^'=>570,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>333,'g'=>500,'h'=>556,'i'=>278,'j'=>278,'k'=>500,'l'=>278,'m'=>778, - 'n'=>556,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>556,'v'=>444,'w'=>667,'x'=>500,'y'=>444,'z'=>389,'{'=>348,'|'=>220,'}'=>348,'~'=>570,127.chr=>350,128.chr=>500,129.chr=>350,130.chr=>333,131.chr=>500, - 132.chr=>500,133.chr=>1000,134.chr=>500,135.chr=>500,136.chr=>333,137.chr=>1000,138.chr=>556,139.chr=>333,140.chr=>944,141.chr=>350,142.chr=>611,143.chr=>350,144.chr=>350,145.chr=>333,146.chr=>333,147.chr=>500,148.chr=>500,149.chr=>350,150.chr=>500,151.chr=>1000,152.chr=>333,153.chr=>1000, - 154.chr=>389,155.chr=>333,156.chr=>722,157.chr=>350,158.chr=>389,159.chr=>611,160.chr=>250,161.chr=>389,162.chr=>500,163.chr=>500,164.chr=>500,165.chr=>500,166.chr=>220,167.chr=>500,168.chr=>333,169.chr=>747,170.chr=>266,171.chr=>500,172.chr=>606,173.chr=>333,174.chr=>747,175.chr=>333, - 176.chr=>400,177.chr=>570,178.chr=>300,179.chr=>300,180.chr=>333,181.chr=>576,182.chr=>500,183.chr=>250,184.chr=>333,185.chr=>300,186.chr=>300,187.chr=>500,188.chr=>750,189.chr=>750,190.chr=>750,191.chr=>500,192.chr=>667,193.chr=>667,194.chr=>667,195.chr=>667,196.chr=>667,197.chr=>667, - 198.chr=>944,199.chr=>667,200.chr=>667,201.chr=>667,202.chr=>667,203.chr=>667,204.chr=>389,205.chr=>389,206.chr=>389,207.chr=>389,208.chr=>722,209.chr=>722,210.chr=>722,211.chr=>722,212.chr=>722,213.chr=>722,214.chr=>722,215.chr=>570,216.chr=>722,217.chr=>722,218.chr=>722,219.chr=>722, - 220.chr=>722,221.chr=>611,222.chr=>611,223.chr=>500,224.chr=>500,225.chr=>500,226.chr=>500,227.chr=>500,228.chr=>500,229.chr=>500,230.chr=>722,231.chr=>444,232.chr=>444,233.chr=>444,234.chr=>444,235.chr=>444,236.chr=>278,237.chr=>278,238.chr=>278,239.chr=>278,240.chr=>500,241.chr=>556, - 242.chr=>500,243.chr=>500,244.chr=>500,245.chr=>500,246.chr=>500,247.chr=>570,248.chr=>500,249.chr=>556,250.chr=>556,251.chr=>556,252.chr=>556,253.chr=>444,254.chr=>500,255.chr=>444); -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/timesi.rb --- a/vendor/plugins/rfpdf/lib/fonts/timesi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -TCPDFFontDescriptor.define('timesi') do |font| - font[:cw]={ - 0.chr=>250,1.chr=>250,2.chr=>250,3.chr=>250,4.chr=>250,5.chr=>250,6.chr=>250,7.chr=>250,8.chr=>250,9.chr=>250,10.chr=>250,11.chr=>250,12.chr=>250,13.chr=>250,14.chr=>250,15.chr=>250,16.chr=>250,17.chr=>250,18.chr=>250,19.chr=>250,20.chr=>250,21.chr=>250, - 22.chr=>250,23.chr=>250,24.chr=>250,25.chr=>250,26.chr=>250,27.chr=>250,28.chr=>250,29.chr=>250,30.chr=>250,31.chr=>250,' '=>250,'!'=>333,'"'=>420,'#'=>500,'$'=>500,'%'=>833,'&'=>778,'\''=>214,'('=>333,')'=>333,'*'=>500,'+'=>675, - ','=>250,'-'=>333,'.'=>250,'/'=>278,'0'=>500,'1'=>500,'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>333,';'=>333,'<'=>675,'='=>675,'>'=>675,'?'=>500,'@'=>920,'A'=>611, - 'B'=>611,'C'=>667,'D'=>722,'E'=>611,'F'=>611,'G'=>722,'H'=>722,'I'=>333,'J'=>444,'K'=>667,'L'=>556,'M'=>833,'N'=>667,'O'=>722,'P'=>611,'Q'=>722,'R'=>611,'S'=>500,'T'=>556,'U'=>722,'V'=>611,'W'=>833, - 'X'=>611,'Y'=>556,'Z'=>556,'['=>389,'\\'=>278,']'=>389,'^'=>422,'_'=>500,'`'=>333,'a'=>500,'b'=>500,'c'=>444,'d'=>500,'e'=>444,'f'=>278,'g'=>500,'h'=>500,'i'=>278,'j'=>278,'k'=>444,'l'=>278,'m'=>722, - 'n'=>500,'o'=>500,'p'=>500,'q'=>500,'r'=>389,'s'=>389,'t'=>278,'u'=>500,'v'=>444,'w'=>667,'x'=>444,'y'=>444,'z'=>389,'{'=>400,'|'=>275,'}'=>400,'~'=>541,127.chr=>350,128.chr=>500,129.chr=>350,130.chr=>333,131.chr=>500, - 132.chr=>556,133.chr=>889,134.chr=>500,135.chr=>500,136.chr=>333,137.chr=>1000,138.chr=>500,139.chr=>333,140.chr=>944,141.chr=>350,142.chr=>556,143.chr=>350,144.chr=>350,145.chr=>333,146.chr=>333,147.chr=>556,148.chr=>556,149.chr=>350,150.chr=>500,151.chr=>889,152.chr=>333,153.chr=>980, - 154.chr=>389,155.chr=>333,156.chr=>667,157.chr=>350,158.chr=>389,159.chr=>556,160.chr=>250,161.chr=>389,162.chr=>500,163.chr=>500,164.chr=>500,165.chr=>500,166.chr=>275,167.chr=>500,168.chr=>333,169.chr=>760,170.chr=>276,171.chr=>500,172.chr=>675,173.chr=>333,174.chr=>760,175.chr=>333, - 176.chr=>400,177.chr=>675,178.chr=>300,179.chr=>300,180.chr=>333,181.chr=>500,182.chr=>523,183.chr=>250,184.chr=>333,185.chr=>300,186.chr=>310,187.chr=>500,188.chr=>750,189.chr=>750,190.chr=>750,191.chr=>500,192.chr=>611,193.chr=>611,194.chr=>611,195.chr=>611,196.chr=>611,197.chr=>611, - 198.chr=>889,199.chr=>667,200.chr=>611,201.chr=>611,202.chr=>611,203.chr=>611,204.chr=>333,205.chr=>333,206.chr=>333,207.chr=>333,208.chr=>722,209.chr=>667,210.chr=>722,211.chr=>722,212.chr=>722,213.chr=>722,214.chr=>722,215.chr=>675,216.chr=>722,217.chr=>722,218.chr=>722,219.chr=>722, - 220.chr=>722,221.chr=>556,222.chr=>611,223.chr=>500,224.chr=>500,225.chr=>500,226.chr=>500,227.chr=>500,228.chr=>500,229.chr=>500,230.chr=>667,231.chr=>444,232.chr=>444,233.chr=>444,234.chr=>444,235.chr=>444,236.chr=>278,237.chr=>278,238.chr=>278,239.chr=>278,240.chr=>500,241.chr=>500, - 242.chr=>500,243.chr=>500,244.chr=>500,245.chr=>500,246.chr=>500,247.chr=>675,248.chr=>500,249.chr=>500,250.chr=>500,251.chr=>500,252.chr=>500,253.chr=>444,254.chr=>500,255.chr=>444); -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/vera.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/vera.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/vera.rb --- a/vendor/plugins/rfpdf/lib/fonts/vera.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('vera') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSans-Roman'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-183 -236 1287 928]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-104; - font[:ut]=70; - font[:cw]={ - 270=>600, 32=>318, 33=>401, 34=>460, 35=>838, 36=>636, 37=>950, 38=>780, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>361, 46=>318, - 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, - 63=>531, 64=>1000, 65=>684, 66=>686, 67=>698, 68=>770, 69=>632, 70=>575, 71=>775, 72=>752, 73=>295, 74=>295, 75=>656, 76=>557, 77=>863, 78=>748, - 79=>787, 80=>603, 81=>787, 82=>695, 83=>635, 84=>611, 85=>732, 86=>684, 87=>989, 88=>685, 89=>611, 90=>685, 91=>390, 92=>337, 93=>390, 94=>838, - 95=>500, 96=>500, 97=>613, 98=>635, 99=>550, 100=>635, 101=>615, 102=>352, 103=>635, 104=>634, 105=>278, 106=>278, 107=>579, 108=>278, 109=>974, 110=>634, - 111=>612, 112=>635, 113=>635, 114=>411, 115=>521, 116=>392, 117=>634, 118=>592, 119=>818, 120=>592, 121=>592, 122=>525, 123=>636, 124=>337, 125=>636, 126=>838, - 8364=>636, 8218=>318, 402=>636, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1342, 352=>635, 8249=>400, 338=>1070, 381=>685, 8216=>318, 8217=>318, 8220=>518, - 8221=>518, 8226=>590, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>521, 8250=>400, 339=>1023, 382=>525, 376=>611, 160=>636, 161=>401, 162=>636, 163=>636, 164=>636, - 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>471, 171=>612, 172=>838, 173=>361, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>401, 179=>401, 180=>500, - 181=>636, 182=>636, 183=>318, 184=>500, 185=>401, 186=>471, 187=>612, 188=>969, 189=>969, 190=>969, 191=>531, 192=>684, 193=>684, 194=>684, 195=>684, 196=>684, - 197=>684, 198=>974, 199=>698, 200=>632, 201=>632, 202=>632, 203=>632, 204=>295, 205=>295, 206=>295, 207=>295, 208=>775, 209=>748, 210=>787, 211=>787, 212=>787, - 213=>787, 214=>787, 215=>838, 216=>787, 217=>732, 218=>732, 219=>732, 220=>732, 221=>611, 222=>605, 223=>630, 224=>613, 225=>613, 226=>613, 227=>613, 228=>613, - 229=>613, 230=>982, 231=>550, 232=>615, 233=>615, 234=>615, 235=>615, 236=>278, 237=>278, 238=>278, 239=>278, 240=>612, 241=>634, 242=>612, 243=>612, 244=>612, - 245=>612, 246=>612, 247=>838, 248=>612, 249=>634, 250=>634, 251=>634, 252=>634, 253=>592, 254=>635, 255=>592, 8800=>838, 8734=>833, 8804=>838, 8805=>838, 8706=>517, - 8721=>674, 8719=>757, 960=>589, 8747=>521, 937=>764, 8730=>637, 8776=>838, 8710=>669, 9674=>494, 8725=>167, 64257=>630, 64258=>630, 305=>278, 728=>500, 729=>500, 730=>500, - 733=>500, 731=>500, 711=>500, 321=>562, 322=>284, 8722=>838, 286=>775, 287=>635, 304=>295, 350=>635, 351=>521, 262=>698, 263=>550, 268=>698, 269=>550, 273=>635, - 8729=>318} - font[:enc]=''; - font[:diff]=''; - font[:file]='vera.z'; - font[:ctg]='vera.ctg.z'; - font[:originalsize]=65932; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/vera.z Binary file vendor/plugins/rfpdf/lib/fonts/vera.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verab.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/verab.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verab.rb --- a/vendor/plugins/rfpdf/lib/fonts/verab.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('verab') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSans-Bold'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-199 -236 1417 928]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>600} - font[:up]=-111; - font[:ut]=126; - font[:cw]={ - 270=>600, 32=>348, 33=>456, 34=>521, 35=>838, 36=>696, 37=>1002, 38=>872, 39=>306, 40=>457, 41=>457, 42=>523, 43=>838, 44=>380, 45=>415, 46=>380, - 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>400, 59=>400, 60=>838, 61=>838, 62=>838, - 63=>580, 64=>1000, 65=>774, 66=>762, 67=>734, 68=>830, 69=>683, 70=>683, 71=>821, 72=>837, 73=>372, 74=>372, 75=>775, 76=>637, 77=>995, 78=>837, - 79=>850, 80=>733, 81=>850, 82=>770, 83=>720, 84=>682, 85=>812, 86=>774, 87=>1103, 88=>771, 89=>724, 90=>725, 91=>457, 92=>365, 93=>457, 94=>838, - 95=>500, 96=>500, 97=>675, 98=>716, 99=>593, 100=>716, 101=>678, 102=>435, 103=>716, 104=>712, 105=>343, 106=>343, 107=>665, 108=>343, 109=>1042, 110=>712, - 111=>687, 112=>716, 113=>716, 114=>493, 115=>595, 116=>478, 117=>712, 118=>652, 119=>924, 120=>645, 121=>652, 122=>582, 123=>712, 124=>365, 125=>712, 126=>838, - 8364=>696, 8218=>380, 402=>696, 8222=>657, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1440, 352=>720, 8249=>412, 338=>1167, 381=>725, 8216=>380, 8217=>380, 8220=>657, - 8221=>657, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>595, 8250=>412, 339=>1094, 382=>582, 376=>724, 160=>696, 161=>456, 162=>696, 163=>696, 164=>636, - 165=>696, 166=>365, 167=>500, 168=>500, 169=>1000, 170=>564, 171=>646, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>438, 179=>438, 180=>500, - 181=>736, 182=>636, 183=>380, 184=>500, 185=>438, 186=>564, 187=>646, 188=>1035, 189=>1035, 190=>1035, 191=>580, 192=>774, 193=>774, 194=>774, 195=>774, 196=>774, - 197=>774, 198=>1085, 199=>734, 200=>683, 201=>683, 202=>683, 203=>683, 204=>372, 205=>372, 206=>372, 207=>372, 208=>838, 209=>837, 210=>850, 211=>850, 212=>850, - 213=>850, 214=>850, 215=>838, 216=>850, 217=>812, 218=>812, 219=>812, 220=>812, 221=>724, 222=>738, 223=>719, 224=>675, 225=>675, 226=>675, 227=>675, 228=>675, - 229=>675, 230=>1048, 231=>593, 232=>678, 233=>678, 234=>678, 235=>678, 236=>343, 237=>343, 238=>343, 239=>343, 240=>687, 241=>712, 242=>687, 243=>687, 244=>687, - 245=>687, 246=>687, 247=>838, 248=>687, 249=>712, 250=>712, 251=>712, 252=>712, 253=>652, 254=>716, 255=>652, 8800=>838, 8734=>833, 8804=>838, 8805=>838, 8706=>544, - 8721=>718, 8719=>787, 960=>644, 8747=>610, 937=>769, 8730=>667, 8776=>838, 8710=>697, 9674=>494, 8725=>167, 64257=>741, 64258=>741, 305=>343, 728=>500, 729=>500, 730=>500, - 733=>500, 731=>500, 711=>500, 321=>642, 322=>371, 8722=>838, 286=>821, 287=>716, 304=>372, 350=>720, 351=>595, 262=>734, 263=>593, 268=>734, 269=>593, 273=>716, - 8729=>380} - font[:enc]=''; - font[:diff]=''; - font[:file]='verab.z'; - font[:ctg]='verab.ctg.z'; - font[:originalsize]=58716; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verab.z Binary file vendor/plugins/rfpdf/lib/fonts/verab.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verabi.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/verabi.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verabi.rb --- a/vendor/plugins/rfpdf/lib/fonts/verabi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('verabi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSans-BoldOblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-278 -236 1401 928]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>600} - font[:up]=-111; - font[:ut]=126; - font[:cw]={ - 270=>600, 32=>348, 33=>456, 34=>521, 35=>696, 36=>696, 37=>1002, 38=>872, 39=>306, 40=>457, 41=>457, 42=>523, 43=>838, 44=>380, 45=>415, 46=>380, - 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>400, 59=>400, 60=>838, 61=>838, 62=>838, - 63=>580, 64=>1000, 65=>774, 66=>762, 67=>734, 68=>830, 69=>683, 70=>683, 71=>821, 72=>837, 73=>372, 74=>372, 75=>775, 76=>637, 77=>995, 78=>837, - 79=>850, 80=>733, 81=>850, 82=>770, 83=>720, 84=>682, 85=>812, 86=>774, 87=>1103, 88=>771, 89=>724, 90=>725, 91=>457, 92=>365, 93=>457, 94=>838, - 95=>500, 96=>500, 97=>675, 98=>716, 99=>593, 100=>716, 101=>678, 102=>435, 103=>716, 104=>712, 105=>343, 106=>343, 107=>665, 108=>343, 109=>1042, 110=>712, - 111=>687, 112=>716, 113=>716, 114=>493, 115=>595, 116=>478, 117=>712, 118=>652, 119=>924, 120=>645, 121=>652, 122=>582, 123=>712, 124=>365, 125=>712, 126=>838, - 8364=>696, 8218=>380, 402=>696, 8222=>644, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1454, 352=>720, 8249=>412, 338=>1167, 381=>725, 8216=>380, 8217=>380, 8220=>644, - 8221=>644, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>595, 8250=>412, 339=>1094, 382=>582, 376=>724, 160=>696, 161=>456, 162=>696, 163=>696, 164=>636, - 165=>696, 166=>365, 167=>500, 168=>500, 169=>1000, 170=>564, 171=>650, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>438, 179=>438, 180=>500, - 181=>736, 182=>636, 183=>380, 184=>500, 185=>438, 186=>564, 187=>650, 188=>1065, 189=>1065, 190=>1065, 191=>580, 192=>774, 193=>774, 194=>774, 195=>774, 196=>774, - 197=>774, 198=>1085, 199=>734, 200=>683, 201=>683, 202=>683, 203=>683, 204=>372, 205=>372, 206=>372, 207=>372, 208=>845, 209=>837, 210=>850, 211=>850, 212=>850, - 213=>850, 214=>850, 215=>838, 216=>850, 217=>812, 218=>812, 219=>812, 220=>812, 221=>724, 222=>742, 223=>719, 224=>675, 225=>675, 226=>675, 227=>675, 228=>675, - 229=>675, 230=>1048, 231=>593, 232=>678, 233=>678, 234=>678, 235=>678, 236=>343, 237=>343, 238=>343, 239=>343, 240=>687, 241=>712, 242=>687, 243=>687, 244=>687, - 245=>687, 246=>687, 247=>838, 248=>687, 249=>712, 250=>712, 251=>712, 252=>712, 253=>652, 254=>716, 255=>652, 8800=>838, 8734=>833, 8804=>838, 8805=>838, 8706=>544, - 8721=>718, 8719=>787, 960=>644, 8747=>610, 937=>769, 8730=>667, 8776=>838, 8710=>697, 9674=>494, 8725=>167, 64257=>787, 64258=>787, 305=>343, 728=>500, 729=>500, 730=>500, - 733=>500, 731=>500, 711=>500, 321=>660, 322=>375, 8722=>838, 286=>821, 287=>716, 304=>372, 350=>720, 351=>595, 262=>734, 263=>593, 268=>734, 269=>593, 273=>716, - 8729=>380} - font[:enc]=''; - font[:diff]=''; - font[:file]='verabi.z'; - font[:ctg]='verabi.ctg.z'; - font[:originalsize]=63208; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verabi.z Binary file vendor/plugins/rfpdf/lib/fonts/verabi.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verai.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/verai.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verai.rb --- a/vendor/plugins/rfpdf/lib/fonts/verai.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('verai') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSans-Oblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>96,'FontBBox'=>'[-262 -236 1259 928]','ItalicAngle'=>-11,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-104; - font[:ut]=70; - font[:cw]={ - 270=>600, 32=>318, 33=>401, 34=>460, 35=>838, 36=>636, 37=>950, 38=>780, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>361, 46=>318, - 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, - 63=>531, 64=>1000, 65=>684, 66=>686, 67=>698, 68=>770, 69=>632, 70=>575, 71=>775, 72=>752, 73=>295, 74=>295, 75=>656, 76=>557, 77=>863, 78=>748, - 79=>787, 80=>603, 81=>787, 82=>695, 83=>635, 84=>611, 85=>732, 86=>684, 87=>989, 88=>685, 89=>611, 90=>685, 91=>390, 92=>337, 93=>390, 94=>838, - 95=>500, 96=>500, 97=>613, 98=>635, 99=>550, 100=>635, 101=>615, 102=>352, 103=>635, 104=>634, 105=>278, 106=>278, 107=>579, 108=>278, 109=>974, 110=>634, - 111=>612, 112=>635, 113=>635, 114=>411, 115=>521, 116=>392, 117=>634, 118=>592, 119=>818, 120=>592, 121=>592, 122=>525, 123=>636, 124=>337, 125=>636, 126=>838, - 8364=>636, 8218=>318, 402=>636, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1350, 352=>635, 8249=>400, 338=>1070, 381=>685, 8216=>318, 8217=>318, 8220=>518, - 8221=>518, 8226=>590, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>521, 8250=>400, 339=>1028, 382=>525, 376=>611, 160=>636, 161=>401, 162=>636, 163=>636, 164=>636, - 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>471, 171=>617, 172=>838, 173=>361, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>401, 179=>401, 180=>500, - 181=>636, 182=>636, 183=>318, 184=>500, 185=>401, 186=>471, 187=>617, 188=>969, 189=>969, 190=>969, 191=>531, 192=>684, 193=>684, 194=>684, 195=>684, 196=>684, - 197=>684, 198=>974, 199=>698, 200=>632, 201=>632, 202=>632, 203=>632, 204=>295, 205=>295, 206=>295, 207=>295, 208=>775, 209=>748, 210=>787, 211=>787, 212=>787, - 213=>787, 214=>787, 215=>838, 216=>787, 217=>732, 218=>732, 219=>732, 220=>732, 221=>611, 222=>608, 223=>630, 224=>613, 225=>613, 226=>613, 227=>613, 228=>613, - 229=>613, 230=>995, 231=>550, 232=>615, 233=>615, 234=>615, 235=>615, 236=>278, 237=>278, 238=>278, 239=>278, 240=>612, 241=>634, 242=>612, 243=>612, 244=>612, - 245=>612, 246=>612, 247=>838, 248=>612, 249=>634, 250=>634, 251=>634, 252=>634, 253=>592, 254=>635, 255=>592, 8800=>838, 8734=>833, 8804=>838, 8805=>838, 8706=>517, - 8721=>674, 8719=>757, 960=>589, 8747=>521, 937=>764, 8730=>637, 8776=>838, 8710=>669, 9674=>494, 8725=>167, 64257=>646, 64258=>646, 305=>278, 728=>500, 729=>500, 730=>500, - 733=>500, 731=>500, 711=>500, 321=>562, 322=>287, 8722=>838, 286=>775, 287=>635, 304=>295, 350=>635, 351=>521, 262=>698, 263=>550, 268=>698, 269=>550, 273=>635, - 8729=>318} - font[:enc]=''; - font[:diff]=''; - font[:file]='verai.z'; - font[:ctg]='verai.ctg.z'; - font[:originalsize]=63684; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verai.z Binary file vendor/plugins/rfpdf/lib/fonts/verai.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramo.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/veramo.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramo.rb --- a/vendor/plugins/rfpdf/lib/fonts/veramo.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('veramo') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSansMono-Roman'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>33,'FontBBox'=>'[-5 -236 606 font[:928]]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>602} - font[:up]=-104; - font[:ut]=69; - font[:cw]={ - 270=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 381=>602, 8216=>602, 8217=>602, 8220=>602, - 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 382=>602, 376=>602, 160=>602, 161=>602, 162=>602, 163=>602, 164=>602, - 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, 177=>602, 178=>602, 179=>602, 180=>602, - 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, 193=>602, 194=>602, 195=>602, 196=>602, - 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, 209=>602, 210=>602, 211=>602, 212=>602, - 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, 225=>602, 226=>602, 227=>602, 228=>602, - 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, 241=>602, 242=>602, 243=>602, 244=>602, - 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 8800=>602, 8734=>602, 8804=>602, 8805=>602, 8706=>602, - 8721=>602, 8719=>602, 960=>602, 8747=>602, 937=>602, 8730=>602, 8776=>602, 8710=>602, 9674=>602, 8725=>602, 64257=>602, 64258=>602, 305=>602, 728=>602, 729=>602, 730=>602, - 733=>602, 731=>602, 711=>602, 321=>602, 322=>602, 8722=>602, 286=>602, 287=>602, 304=>602, 350=>602, 351=>602, 262=>602, 263=>602, 268=>602, 269=>602, 273=>602, - 8729=>602} - font[:enc]=''; - font[:diff]=''; - font[:file]='veramo.z'; - font[:ctg]='veramo.ctg.z'; - font[:originalsize]=49224; -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramo.z Binary file vendor/plugins/rfpdf/lib/fonts/veramo.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramob.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/veramob.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramob.rb --- a/vendor/plugins/rfpdf/lib/fonts/veramob.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('veramob') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSansMono-Bold'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>33,'FontBBox'=>'[-19 -236 606 928]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>602} - font[:up]=-108; - font[:ut]=120; - font[:cw]={ - 270=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 381=>602, 8216=>602, 8217=>602, 8220=>602, - 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 382=>602, 376=>602, 160=>602, 161=>602, 162=>602, 163=>602, 164=>602, - 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, 177=>602, 178=>602, 179=>602, 180=>602, - 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, 193=>602, 194=>602, 195=>602, 196=>602, - 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, 209=>602, 210=>602, 211=>602, 212=>602, - 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, 225=>602, 226=>602, 227=>602, 228=>602, - 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, 241=>602, 242=>602, 243=>602, 244=>602, - 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 8800=>602, 8734=>602, 8804=>602, 8805=>602, 8706=>602, - 8721=>602, 8719=>602, 960=>602, 8747=>602, 937=>602, 8730=>602, 8776=>602, 8710=>602, 9674=>602, 8725=>602, 64257=>602, 64258=>602, 305=>602, 728=>602, 729=>602, 730=>602, - 733=>602, 731=>602, 711=>602, 321=>602, 322=>602, 8722=>602, 286=>602, 287=>602, 304=>602, 350=>602, 351=>602, 262=>602, 263=>602, 268=>602, 269=>602, 273=>602, - 8729=>602} - font[:enc]=''; - font[:diff]=''; - font[:file]='veramob.z'; - font[:ctg]='veramob.ctg.z'; - font[:originalsize]=49052; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramob.z Binary file vendor/plugins/rfpdf/lib/fonts/veramob.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramobi.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/veramobi.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramobi.rb --- a/vendor/plugins/rfpdf/lib/fonts/veramobi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('veramobi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSansMono-BoldOb'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>97,'FontBBox'=>'[-73 -236 681 928]','ItalicAngle'=>-11,'StemV'=>120,'MissingWidth'=>602} - font[:up]=-108; - font[:ut]=120; - font[:cw]={ - 270=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 381=>602, 8216=>602, 8217=>602, 8220=>602, - 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 382=>602, 376=>602, 160=>602, 161=>602, 162=>602, 163=>602, 164=>602, - 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, 177=>602, 178=>602, 179=>602, 180=>602, - 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, 193=>602, 194=>602, 195=>602, 196=>602, - 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, 209=>602, 210=>602, 211=>602, 212=>602, - 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, 225=>602, 226=>602, 227=>602, 228=>602, - 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, 241=>602, 242=>602, 243=>602, 244=>602, - 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 8800=>602, 8734=>602, 8804=>602, 8805=>602, 8706=>602, - 8721=>602, 8719=>602, 960=>602, 8747=>602, 937=>602, 8730=>602, 8776=>602, 8710=>602, 9674=>602, 8725=>602, 64257=>602, 64258=>602, 305=>602, 728=>602, 729=>602, 730=>602, - 733=>602, 731=>602, 711=>602, 321=>602, 322=>602, 8722=>602, 286=>602, 287=>602, 304=>602, 350=>602, 351=>602, 262=>602, 263=>602, 268=>602, 269=>602, 273=>602, - 8729=>602} - font[:enc]=''; - font[:diff]=''; - font[:file]='veramobi.z'; - font[:ctg]='veramobi.ctg.z'; - font[:originalsize]=55032; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramobi.z Binary file vendor/plugins/rfpdf/lib/fonts/veramobi.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramoi.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/veramoi.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramoi.rb --- a/vendor/plugins/rfpdf/lib/fonts/veramoi.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('veramoi') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSansMono-Oblique'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>97,'FontBBox'=>'[-71 -236 691 928]','ItalicAngle'=>-11,'StemV'=>70,'MissingWidth'=>602} - font[:up]=-104; - font[:ut]=69; - font[:cw]={ - 270=>602, 32=>602, 33=>602, 34=>602, 35=>602, 36=>602, 37=>602, 38=>602, 39=>602, 40=>602, 41=>602, 42=>602, 43=>602, 44=>602, 45=>602, 46=>602, - 47=>602, 48=>602, 49=>602, 50=>602, 51=>602, 52=>602, 53=>602, 54=>602, 55=>602, 56=>602, 57=>602, 58=>602, 59=>602, 60=>602, 61=>602, 62=>602, - 63=>602, 64=>602, 65=>602, 66=>602, 67=>602, 68=>602, 69=>602, 70=>602, 71=>602, 72=>602, 73=>602, 74=>602, 75=>602, 76=>602, 77=>602, 78=>602, - 79=>602, 80=>602, 81=>602, 82=>602, 83=>602, 84=>602, 85=>602, 86=>602, 87=>602, 88=>602, 89=>602, 90=>602, 91=>602, 92=>602, 93=>602, 94=>602, - 95=>602, 96=>602, 97=>602, 98=>602, 99=>602, 100=>602, 101=>602, 102=>602, 103=>602, 104=>602, 105=>602, 106=>602, 107=>602, 108=>602, 109=>602, 110=>602, - 111=>602, 112=>602, 113=>602, 114=>602, 115=>602, 116=>602, 117=>602, 118=>602, 119=>602, 120=>602, 121=>602, 122=>602, 123=>602, 124=>602, 125=>602, 126=>602, - 8364=>602, 8218=>602, 402=>602, 8222=>602, 8230=>602, 8224=>602, 8225=>602, 710=>602, 8240=>602, 352=>602, 8249=>602, 338=>602, 381=>602, 8216=>602, 8217=>602, 8220=>602, - 8221=>602, 8226=>602, 8211=>602, 8212=>602, 732=>602, 8482=>602, 353=>602, 8250=>602, 339=>602, 382=>602, 376=>602, 160=>602, 161=>602, 162=>602, 163=>602, 164=>602, - 165=>602, 166=>602, 167=>602, 168=>602, 169=>602, 170=>602, 171=>602, 172=>602, 173=>602, 174=>602, 175=>602, 176=>602, 177=>602, 178=>602, 179=>602, 180=>602, - 181=>602, 182=>602, 183=>602, 184=>602, 185=>602, 186=>602, 187=>602, 188=>602, 189=>602, 190=>602, 191=>602, 192=>602, 193=>602, 194=>602, 195=>602, 196=>602, - 197=>602, 198=>602, 199=>602, 200=>602, 201=>602, 202=>602, 203=>602, 204=>602, 205=>602, 206=>602, 207=>602, 208=>602, 209=>602, 210=>602, 211=>602, 212=>602, - 213=>602, 214=>602, 215=>602, 216=>602, 217=>602, 218=>602, 219=>602, 220=>602, 221=>602, 222=>602, 223=>602, 224=>602, 225=>602, 226=>602, 227=>602, 228=>602, - 229=>602, 230=>602, 231=>602, 232=>602, 233=>602, 234=>602, 235=>602, 236=>602, 237=>602, 238=>602, 239=>602, 240=>602, 241=>602, 242=>602, 243=>602, 244=>602, - 245=>602, 246=>602, 247=>602, 248=>602, 249=>602, 250=>602, 251=>602, 252=>602, 253=>602, 254=>602, 255=>602, 8800=>602, 8734=>602, 8804=>602, 8805=>602, 8706=>602, - 8721=>602, 8719=>602, 960=>602, 8747=>602, 937=>602, 8730=>602, 8776=>602, 8710=>602, 9674=>602, 8725=>602, 64257=>602, 64258=>602, 305=>602, 728=>602, 729=>602, 730=>602, - 733=>602, 731=>602, 711=>602, 321=>602, 322=>602, 8722=>602, 286=>602, 287=>602, 304=>602, 350=>602, 351=>602, 262=>602, 263=>602, 268=>602, 269=>602, 273=>602, - 8729=>602} - font[:enc]=''; - font[:diff]=''; - font[:file]='veramoi.z'; - font[:ctg]='veramoi.ctg.z'; - font[:originalsize]=54508; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veramoi.z Binary file vendor/plugins/rfpdf/lib/fonts/veramoi.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verase.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/verase.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verase.rb --- a/vendor/plugins/rfpdf/lib/fonts/verase.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('verase') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSerif-Roman'; - font[:desc]={'Ascent'=>928,'Descent'=>-236,'CapHeight'=>928,'Flags'=>32,'FontBBox'=>'[-183 -236 1287 928]','ItalicAngle'=>0,'StemV'=>70,'MissingWidth'=>600} - font[:up]=-104; - font[:ut]=65; - font[:cw]={ - 270=>600, 32=>318, 33=>402, 34=>460, 35=>838, 36=>636, 37=>950, 38=>890, 39=>275, 40=>390, 41=>390, 42=>500, 43=>838, 44=>318, 45=>338, 46=>318, - 47=>337, 48=>636, 49=>636, 50=>636, 51=>636, 52=>636, 53=>636, 54=>636, 55=>636, 56=>636, 57=>636, 58=>337, 59=>337, 60=>838, 61=>838, 62=>838, - 63=>536, 64=>1000, 65=>722, 66=>735, 67=>765, 68=>802, 69=>730, 70=>694, 71=>799, 72=>872, 73=>395, 74=>401, 75=>747, 76=>664, 77=>1024, 78=>875, - 79=>820, 80=>673, 81=>820, 82=>753, 83=>685, 84=>667, 85=>843, 86=>722, 87=>1028, 88=>712, 89=>660, 90=>695, 91=>390, 92=>337, 93=>390, 94=>838, - 95=>500, 96=>500, 97=>596, 98=>640, 99=>560, 100=>640, 101=>592, 102=>370, 103=>640, 104=>644, 105=>320, 106=>310, 107=>606, 108=>320, 109=>948, 110=>644, - 111=>602, 112=>640, 113=>640, 114=>478, 115=>513, 116=>402, 117=>644, 118=>565, 119=>856, 120=>564, 121=>565, 122=>527, 123=>636, 124=>337, 125=>636, 126=>838, - 8364=>636, 8218=>318, 402=>636, 8222=>518, 8230=>1000, 8224=>500, 8225=>500, 710=>500, 8240=>1342, 352=>685, 8249=>400, 338=>1137, 381=>695, 8216=>318, 8217=>318, 8220=>511, - 8221=>511, 8226=>590, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>513, 8250=>400, 339=>989, 382=>527, 376=>660, 160=>636, 161=>402, 162=>636, 163=>636, 164=>636, - 165=>636, 166=>337, 167=>500, 168=>500, 169=>1000, 170=>475, 171=>612, 172=>838, 173=>338, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>401, 179=>401, 180=>500, - 181=>650, 182=>636, 183=>318, 184=>500, 185=>401, 186=>470, 187=>612, 188=>969, 189=>969, 190=>969, 191=>536, 192=>722, 193=>722, 194=>722, 195=>722, 196=>722, - 197=>722, 198=>1001, 199=>765, 200=>730, 201=>730, 202=>730, 203=>730, 204=>395, 205=>395, 206=>395, 207=>395, 208=>807, 209=>875, 210=>820, 211=>820, 212=>820, - 213=>820, 214=>820, 215=>838, 216=>820, 217=>843, 218=>843, 219=>843, 220=>843, 221=>660, 222=>676, 223=>668, 224=>596, 225=>596, 226=>596, 227=>596, 228=>596, - 229=>596, 230=>940, 231=>560, 232=>592, 233=>592, 234=>592, 235=>592, 236=>320, 237=>320, 238=>320, 239=>320, 240=>602, 241=>644, 242=>602, 243=>602, 244=>602, - 245=>602, 246=>602, 247=>838, 248=>602, 249=>644, 250=>644, 251=>644, 252=>644, 253=>565, 254=>640, 255=>565, 8800=>838, 8734=>833, 8804=>838, 8805=>838, 8706=>517, - 8721=>714, 8719=>796, 960=>657, 8747=>521, 937=>829, 8730=>637, 8776=>838, 8710=>698, 9674=>494, 8725=>167, 64257=>667, 64258=>667, 305=>320, 728=>500, 729=>500, 730=>500, - 733=>500, 731=>500, 711=>500, 321=>669, 322=>324, 8722=>838, 286=>799, 287=>640, 304=>395, 350=>685, 351=>513, 262=>765, 263=>560, 268=>765, 269=>560, 273=>640, - 8729=>318} - font[:enc]=''; - font[:diff]=''; - font[:file]='verase.z'; - font[:ctg]='verase.ctg.z'; - font[:originalsize]=60280; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/verase.z Binary file vendor/plugins/rfpdf/lib/fonts/verase.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veraseb.ctg.z Binary file vendor/plugins/rfpdf/lib/fonts/veraseb.ctg.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veraseb.rb --- a/vendor/plugins/rfpdf/lib/fonts/veraseb.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -TCPDFFontDescriptor.define('veraseb') do |font| - font[:type]='TrueTypeUnicode'; - font[:name]='BitstreamVeraSerif-Bold'; - font[:desc]={'Ascent'=>939,'Descent'=>-236,'CapHeight'=>939,'Flags'=>32,'FontBBox'=>'[-186 -236 1361 939]','ItalicAngle'=>0,'StemV'=>120,'MissingWidth'=>600} - font[:up]=-106; - font[:ut]=117; - font[:cw]={ - 270=>600, 32=>348, 33=>439, 34=>521, 35=>838, 36=>696, 37=>950, 38=>903, 39=>306, 40=>473, 41=>473, 42=>523, 43=>838, 44=>348, 45=>415, 46=>348, - 47=>365, 48=>696, 49=>696, 50=>696, 51=>696, 52=>696, 53=>696, 54=>696, 55=>696, 56=>696, 57=>696, 58=>369, 59=>369, 60=>838, 61=>838, 62=>838, - 63=>586, 64=>1000, 65=>776, 66=>845, 67=>796, 68=>867, 69=>762, 70=>710, 71=>854, 72=>945, 73=>468, 74=>473, 75=>869, 76=>703, 77=>1107, 78=>914, - 79=>871, 80=>752, 81=>871, 82=>831, 83=>722, 84=>744, 85=>872, 86=>776, 87=>1123, 88=>776, 89=>714, 90=>730, 91=>473, 92=>365, 93=>473, 94=>838, - 95=>500, 96=>500, 97=>648, 98=>699, 99=>609, 100=>699, 101=>636, 102=>430, 103=>699, 104=>727, 105=>380, 106=>362, 107=>693, 108=>380, 109=>1058, 110=>727, - 111=>667, 112=>699, 113=>699, 114=>527, 115=>563, 116=>462, 117=>727, 118=>581, 119=>861, 120=>596, 121=>581, 122=>568, 123=>643, 124=>364, 125=>643, 126=>838, - 8364=>696, 8218=>348, 402=>696, 8222=>575, 8230=>1000, 8224=>523, 8225=>523, 710=>500, 8240=>1385, 352=>722, 8249=>400, 338=>1180, 381=>730, 8216=>348, 8217=>348, 8220=>575, - 8221=>575, 8226=>639, 8211=>500, 8212=>1000, 732=>500, 8482=>1000, 353=>563, 8250=>400, 339=>1028, 382=>568, 376=>714, 160=>696, 161=>439, 162=>696, 163=>696, 164=>636, - 165=>696, 166=>364, 167=>523, 168=>500, 169=>1000, 170=>487, 171=>625, 172=>838, 173=>415, 174=>1000, 175=>500, 176=>500, 177=>838, 178=>438, 179=>438, 180=>500, - 181=>732, 182=>636, 183=>348, 184=>500, 185=>438, 186=>500, 187=>625, 188=>1043, 189=>1043, 190=>1043, 191=>586, 192=>776, 193=>776, 194=>776, 195=>776, 196=>776, - 197=>776, 198=>1034, 199=>796, 200=>762, 201=>762, 202=>762, 203=>762, 204=>468, 205=>468, 206=>468, 207=>468, 208=>874, 209=>914, 210=>871, 211=>871, 212=>871, - 213=>871, 214=>871, 215=>838, 216=>871, 217=>872, 218=>872, 219=>872, 220=>872, 221=>714, 222=>757, 223=>760, 224=>648, 225=>648, 226=>648, 227=>648, 228=>648, - 229=>648, 230=>975, 231=>609, 232=>636, 233=>636, 234=>636, 235=>636, 236=>380, 237=>380, 238=>380, 239=>380, 240=>667, 241=>727, 242=>667, 243=>667, 244=>667, - 245=>667, 246=>667, 247=>838, 248=>667, 249=>727, 250=>727, 251=>727, 252=>727, 253=>581, 254=>699, 255=>581, 8800=>838, 8734=>833, 8804=>838, 8805=>838, 8706=>534, - 8721=>753, 8719=>842, 960=>732, 8747=>579, 937=>890, 8730=>657, 8776=>838, 8710=>753, 9674=>494, 8725=>167, 64257=>727, 64258=>727, 305=>380, 728=>500, 729=>500, 730=>500, - 733=>500, 731=>500, 711=>500, 321=>710, 322=>385, 8722=>838, 286=>854, 287=>699, 304=>468, 350=>722, 351=>563, 262=>796, 263=>609, 268=>796, 269=>609, 273=>699, - 8729=>348} - font[:enc]=''; - font[:diff]=''; - font[:file]='veraseb.z'; - font[:ctg]='veraseb.ctg.z'; - font[:originalsize]=58736; -end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/veraseb.z Binary file vendor/plugins/rfpdf/lib/fonts/veraseb.z has changed diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fonts/zapfdingbats.rb --- a/vendor/plugins/rfpdf/lib/fonts/zapfdingbats.rb Fri Feb 24 20:18:25 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -TCPDFFontDescriptor.define('zapfdingbats') do |font| - font[:cw]={ - 0.chr=>0,1.chr=>0,2.chr=>0,3.chr=>0,4.chr=>0,5.chr=>0,6.chr=>0,7.chr=>0,8.chr=>0,9.chr=>0,10.chr=>0,11.chr=>0,12.chr=>0,13.chr=>0,14.chr=>0,15.chr=>0,16.chr=>0,17.chr=>0,18.chr=>0,19.chr=>0,20.chr=>0,21.chr=>0, - 22.chr=>0,23.chr=>0,24.chr=>0,25.chr=>0,26.chr=>0,27.chr=>0,28.chr=>0,29.chr=>0,30.chr=>0,31.chr=>0,' '=>278,'!'=>974,'"'=>961,'#'=>974,'$'=>980,'%'=>719,'&'=>789,'\''=>790,'('=>791,')'=>690,'*'=>960,'+'=>939, - ','=>549,'-'=>855,'.'=>911,'/'=>933,'0'=>911,'1'=>945,'2'=>974,'3'=>755,'4'=>846,'5'=>762,'6'=>761,'7'=>571,'8'=>677,'9'=>763,':'=>760,';'=>759,'<'=>754,'='=>494,'>'=>552,'?'=>537,'@'=>577,'A'=>692, - 'B'=>786,'C'=>788,'D'=>788,'E'=>790,'F'=>793,'G'=>794,'H'=>816,'I'=>823,'J'=>789,'K'=>841,'L'=>823,'M'=>833,'N'=>816,'O'=>831,'P'=>923,'Q'=>744,'R'=>723,'S'=>749,'T'=>790,'U'=>792,'V'=>695,'W'=>776, - 'X'=>768,'Y'=>792,'Z'=>759,'['=>707,'\\'=>708,']'=>682,'^'=>701,'_'=>826,'`'=>815,'a'=>789,'b'=>789,'c'=>707,'d'=>687,'e'=>696,'f'=>689,'g'=>786,'h'=>787,'i'=>713,'j'=>791,'k'=>785,'l'=>791,'m'=>873, - 'n'=>761,'o'=>762,'p'=>762,'q'=>759,'r'=>759,'s'=>892,'t'=>892,'u'=>788,'v'=>784,'w'=>438,'x'=>138,'y'=>277,'z'=>415,'{'=>392,'|'=>392,'}'=>668,'~'=>668,127.chr=>0,128.chr=>390,129.chr=>390,130.chr=>317,131.chr=>317, - 132.chr=>276,133.chr=>276,134.chr=>509,135.chr=>509,136.chr=>410,137.chr=>410,138.chr=>234,139.chr=>234,140.chr=>334,141.chr=>334,142.chr=>0,143.chr=>0,144.chr=>0,145.chr=>0,146.chr=>0,147.chr=>0,148.chr=>0,149.chr=>0,150.chr=>0,151.chr=>0,152.chr=>0,153.chr=>0, - 154.chr=>0,155.chr=>0,156.chr=>0,157.chr=>0,158.chr=>0,159.chr=>0,160.chr=>0,161.chr=>732,162.chr=>544,163.chr=>544,164.chr=>910,165.chr=>667,166.chr=>760,167.chr=>760,168.chr=>776,169.chr=>595,170.chr=>694,171.chr=>626,172.chr=>788,173.chr=>788,174.chr=>788,175.chr=>788, - 176.chr=>788,177.chr=>788,178.chr=>788,179.chr=>788,180.chr=>788,181.chr=>788,182.chr=>788,183.chr=>788,184.chr=>788,185.chr=>788,186.chr=>788,187.chr=>788,188.chr=>788,189.chr=>788,190.chr=>788,191.chr=>788,192.chr=>788,193.chr=>788,194.chr=>788,195.chr=>788,196.chr=>788,197.chr=>788, - 198.chr=>788,199.chr=>788,200.chr=>788,201.chr=>788,202.chr=>788,203.chr=>788,204.chr=>788,205.chr=>788,206.chr=>788,207.chr=>788,208.chr=>788,209.chr=>788,210.chr=>788,211.chr=>788,212.chr=>894,213.chr=>838,214.chr=>1016,215.chr=>458,216.chr=>748,217.chr=>924,218.chr=>748,219.chr=>918, - 220.chr=>927,221.chr=>928,222.chr=>928,223.chr=>834,224.chr=>873,225.chr=>828,226.chr=>924,227.chr=>924,228.chr=>917,229.chr=>930,230.chr=>931,231.chr=>463,232.chr=>883,233.chr=>836,234.chr=>836,235.chr=>867,236.chr=>867,237.chr=>696,238.chr=>696,239.chr=>874,240.chr=>0,241.chr=>874, - 242.chr=>760,243.chr=>946,244.chr=>771,245.chr=>865,246.chr=>771,247.chr=>888,248.chr=>967,249.chr=>888,250.chr=>831,251.chr=>873,252.chr=>927,253.chr=>970,254.chr=>918,255.chr=>0); -end \ No newline at end of file diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fpdf/chinese.rb --- a/vendor/plugins/rfpdf/lib/fpdf/chinese.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/rfpdf/lib/fpdf/chinese.rb Mon Feb 27 13:53:18 2012 +0000 @@ -144,13 +144,18 @@ def MultiCell(w,h,txt,border=0,align='L',fill=0,ln=1) if(@current_font['type']=='Type0') - MBMultiCell(w,h,txt,border,align,fill) + MBMultiCell(w,h,txt,border,align,fill,ln) else - super(w,h,txt,border,align,fill) + super(w,h,txt,border,align,fill,ln) end end - def MBMultiCell(w,h,txt,border=0,align='L',fill=0) + def MBMultiCell(w,h,txt,border=0,align='L',fill=0,ln=1) + + # save current position + prevx = @x; + prevy = @y; + #Multi-byte version of MultiCell() cw=@current_font['cw'] if(w==0) @@ -233,18 +238,30 @@ b+='B' end Cell(w,h,s[j,i-j],b,2,align,fill) - @x=@l_margin + + # move cursor to specified position + if (ln == 1) + # go to the beginning of the next line + @x=@l_margin + elsif (ln == 0) + # go to the top-right of the cell + @y = prevy; + @x = prevx + w; + elsif (ln == 2) + # go to the bottom-left of the cell + @x = prevx; + end end def Write(h,txt,link='',fill=0) if(@current_font['type']=='Type0') - MBWrite(h,txt,link) + MBWrite(h,txt,link,fill) else - super(h,txt,link) + super(h,txt,link,fill) end end - def MBWrite(h,txt,link) + def MBWrite(h,txt,link,fill=0) #Multi-byte version of Write() cw=@current_font['cw'] w=@w-@r_margin-@x @@ -263,7 +280,7 @@ ascii=(c<128) if(c.chr=="\n") #Explicit line break - Cell(w,h,s[j,i-j],0,2,'',0,link) + Cell(w,h,s[j,i-j],0,2,'',fill,link) i+=1 sep=-1 j=i @@ -296,9 +313,9 @@ if(i==j) i+=ascii ? 1 : 2 end - Cell(w,h,s[j,i-j],0,2,'',0,link) + Cell(w,h,s[j,i-j],0,2,'',fill,link) else - Cell(w,h,s[j,sep-j],0,2,'',0,link) + Cell(w,h,s[j,sep-j],0,2,'',fill,link) i=(s[sep].chr==' ') ? sep+1 : sep end sep=-1 @@ -316,7 +333,7 @@ end #Last chunk if(i!=j) - Cell(l/1000*@font_size,h,s[j,i-j],0,0,'',0,link) + Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link) end end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fpdf/japanese.rb --- a/vendor/plugins/rfpdf/lib/fpdf/japanese.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/rfpdf/lib/fpdf/japanese.rb Mon Feb 27 13:53:18 2012 +0000 @@ -120,13 +120,18 @@ def MultiCell(w,h,txt,border=0,align='L',fill=0,ln=1) if(@current_font['type']=='Type0') - SJISMultiCell(w,h,txt,border,align,fill) + SJISMultiCell(w,h,txt,border,align,fill,ln) else - super(w,h,txt,border,align,fill) + super(w,h,txt,border,align,fill,ln) end end - def SJISMultiCell(w,h,txt,border=0,align='L',fill=0) + def SJISMultiCell(w,h,txt,border=0,align='L',fill=0,ln=1) + + # save current position + prevx = @x; + prevy = @y; + #Output text with automatic or explicit line breaks cw=@current_font['cw'] if(w==0) @@ -221,18 +226,30 @@ b+='B' end Cell(w,h,s[j,i-j],b,2,align,fill) - @x=@l_margin + + # move cursor to specified position + if (ln == 1) + # go to the beginning of the next line + @x=@l_margin + elsif (ln == 0) + # go to the top-right of the cell + @y = prevy; + @x = prevx + w; + elsif (ln == 2) + # go to the bottom-left of the cell + @x = prevx; + end end def Write(h,txt,link='',fill=0) if(@current_font['type']=='Type0') - SJISWrite(h,txt,link) + SJISWrite(h,txt,link,fill) else - super(h,txt,link) + super(h,txt,link,fill) end end - def SJISWrite(h,txt,link) + def SJISWrite(h,txt,link,fill=0) #SJIS version of Write() cw=@current_font['cw'] w=@w-@r_margin-@x @@ -250,7 +267,7 @@ o=c if(o==10) #Explicit line break - Cell(w,h,s[j,i-j],0,2,'',0,link) + Cell(w,h,s[j,i-j],0,2,'',fill,link) i+=1 sep=-1 j=i @@ -298,9 +315,9 @@ if(i==j) i+=n end - Cell(w,h,s[j,i-j],0,2,'',0,link) + Cell(w,h,s[j,i-j],0,2,'',fill,link) else - Cell(w,h,s[j,sep-j],0,2,'',0,link) + Cell(w,h,s[j,sep-j],0,2,'',fill,link) i=(s[sep].chr==' ') ? sep+1 : sep end sep=-1 @@ -321,7 +338,7 @@ end #Last chunk if(i!=j) - Cell(l/1000*@font_size,h,s[j,i-j],0,0,'',0,link) + Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link) end end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/fpdf/korean.rb --- a/vendor/plugins/rfpdf/lib/fpdf/korean.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/rfpdf/lib/fpdf/korean.rb Mon Feb 27 13:53:18 2012 +0000 @@ -113,13 +113,18 @@ def MultiCell(w,h,txt,border=0,align='L',fill=0,ln=1) if(@current_font['type']=='Type0') - MBMultiCell(w,h,txt,border,align,fill) + MBMultiCell(w,h,txt,border,align,fill,ln) else - super(w,h,txt,border,align,fill) + super(w,h,txt,border,align,fill,ln) end end - def MBMultiCell(w,h,txt,border=0,align='L',fill=0) + def MBMultiCell(w,h,txt,border=0,align='L',fill=0,ln=1) + + # save current position + prevx = @x; + prevy = @y; + #Multi-byte version of MultiCell() cw=@current_font['cw'] if(w==0) @@ -202,18 +207,30 @@ b+='B' end Cell(w,h,s[j,i-j],b,2,align,fill) - @x=@l_margin + + # move cursor to specified position + if (ln == 1) + # go to the beginning of the next line + @x=@l_margin + elsif (ln == 0) + # go to the top-right of the cell + @y = prevy; + @x = prevx + w; + elsif (ln == 2) + # go to the bottom-left of the cell + @x = prevx; + end end def Write(h,txt,link='',fill=0) if(@current_font['type']=='Type0') - MBWrite(h,txt,link) + MBWrite(h,txt,link,fill) else - super(h,txt,link) + super(h,txt,link,fill) end end - def MBWrite(h,txt,link) + def MBWrite(h,txt,link,fill=0) #Multi-byte version of Write() cw=@current_font['cw'] w=@w-@r_margin-@x @@ -232,7 +249,7 @@ ascii=(c<128) if(c.chr=="\n") #Explicit line break - Cell(w,h,s[j,i-j],0,2,'',0,link) + Cell(w,h,s[j,i-j],0,2,'',fill,link) i+=1 sep=-1 j=i @@ -265,9 +282,9 @@ if(i==j) i+=ascii ? 1 : 2 end - Cell(w,h,s[j,i-j],0,2,'',0,link) + Cell(w,h,s[j,i-j],0,2,'',fill,link) else - Cell(w,h,s[j,sep-j],0,2,'',0,link) + Cell(w,h,s[j,sep-j],0,2,'',fill,link) i=(s[sep].chr==' ') ? sep+1 : sep end sep=-1 @@ -285,7 +302,7 @@ end #Last chunk if(i!=j) - Cell(l/1000*@font_size,h,s[j,i-j],0,0,'',0,link) + Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link) end end diff -r 487d96eac004 -r 5e80956cc792 vendor/plugins/rfpdf/lib/tcpdf.rb --- a/vendor/plugins/rfpdf/lib/tcpdf.rb Fri Feb 24 20:18:25 2012 +0000 +++ b/vendor/plugins/rfpdf/lib/tcpdf.rb Mon Feb 27 13:53:18 2012 +0000 @@ -72,6 +72,10 @@ include Core::RFPDF include RFPDF::Math + def logger + Rails.logger + end + cattr_accessor :k_cell_height_ratio @@k_cell_height_ratio = 1.25 @@ -82,10 +86,10 @@ @@k_small_ratio = 2/3.0 cattr_accessor :k_path_cache - @@k_path_cache = File.join(RAILS_ROOT, 'tmp') + @@k_path_cache = Rails.root.join('tmp') cattr_accessor :k_path_url_cache - @@k_path_url_cache = File.join(RAILS_ROOT, 'tmp') + @@k_path_url_cache = Rails.root.join('tmp') cattr_accessor :decoder @@ -98,6 +102,8 @@ attr_accessor :color_flag attr_accessor :default_table_columns + + attr_accessor :max_table_columns attr_accessor :default_font @@ -141,11 +147,11 @@ attr_accessor :links - attr_accessor :listordered + attr_accessor :list_ordered - attr_accessor :listcount + attr_accessor :list_count - attr_accessor :lispacer + attr_accessor :li_spacer attr_accessor :n @@ -226,6 +232,12 @@ @diffs ||= [] @color_flag ||= false @default_table_columns ||= 4 + @table_columns ||= 0 + @max_table_columns ||= [] + @tr_id ||= 0 + @max_td_page ||= [] + @max_td_y ||= [] + @t_columns ||= 0 @default_font ||= "FreeSans" if unicode @default_font ||= "Helvetica" @draw_color ||= '0 G' @@ -248,9 +260,15 @@ @is_unicode = unicode @lasth ||= 0 @links ||= [] - @listordered ||= false - @listcount ||= 0 - @lispacer ||= "" + @list_ordered ||= [] + @list_count ||= [] + @li_spacer ||= "" + @li_count ||= 0 + @spacer ||= "" + @quote_count ||= 0 + @prevquote_count ||= 0 + @quote_top ||= [] + @quote_page ||= [] @n ||= 2 @offsets ||= [] @orientation_changes ||= [] @@ -272,6 +290,7 @@ @tempfontsize ||= 10 @text_color ||= '0 g' @underline ||= false + @deleted ||= false @ws ||= 0 #Standard Unicode fonts @@ -737,7 +756,7 @@ Open(); end family=@font_family; - style=@font_style + (@underline ? 'U' : ''); + style=@font_style + (@underline ? 'U' : '') + (@deleted ? 'D' : ''); size=@font_size_pt; lw=@line_width; dc=@draw_color; @@ -1312,6 +1331,7 @@ style=style.upcase style=style.gsub('U',''); + style=style.gsub('D',''); if (style == 'IB') style = 'BI'; end @@ -1394,7 +1414,7 @@ # #Removes bold # :pdf->SetFont(''); # #Times bold, italic and underlined 14 - # :pdf->SetFont('Times','BIU'); + # :pdf->SetFont('Times','BIUD'); #

    # If the file corresponding to the requested font is not found, the error "Could not include font metric file" is generated. # @param string :family Family font. It can be either a name defined by AddFont() or one of the standard families (case insensitive):
    • Courier (fixed-width)
    • Helvetica or Arial (synonymous; sans serif)
    • Times (serif)
    • Symbol (symbolic)
    • ZapfDingbats (symbolic)
    It is also possible to pass an empty string. In that case, the current family is retained. @@ -1426,6 +1446,12 @@ else @underline=false; end + if (style.include?('D')) + @deleted=true; + style= style.gsub('D',''); + else + @deleted=false; + end if (style=='IB') style='BI'; end @@ -1573,7 +1599,7 @@ #Output a string s=sprintf('BT %.2f %.2f Td (%s) Tj ET', x * @k, (@h-y) * @k, escapetext(txt)); if (@underline and (txt!='')) - s += ' ' + dounderline(x, y, txt); + s += ' ' + dolinetxt(x, y, txt); end if (@color_flag) s='q ' + @text_color + ' ' + s + ' Q'; @@ -1661,19 +1687,25 @@ k=@k; if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak()) #Automatic page break - x = @x; - ws = @ws; - if (ws > 0) - @ws = 0; - out('0 Tw'); - end - AddPage(@cur_orientation); - @x = x; - if (ws > 0) - @ws = ws; - out(sprintf('%.3f Tw', ws * k)); + if @pages[@page+1].nil? + x = @x; + ws = @ws; + if (ws > 0) + @ws = 0; + out('0 Tw'); + end + AddPage(@cur_orientation); + @x = x; + if (ws > 0) + @ws = ws; + out(sprintf('%.3f Tw', ws * k)); + end + else + @page += 1; + @y=@t_margin; end end + if (w == 0) w = @w - @r_margin - @x; end @@ -1717,7 +1749,10 @@ txt2 = escapetext(txt); s<= 1 + if (y + info['h'] * rescale_x / (@img_scale * @k) > @page_break_trigger and !@in_footer and AcceptPageBreak()) + #Automatic page break + if @pages[@page+1].nil? + ws = @ws; + if (ws > 0) + @ws = 0; + out('0 Tw'); + end + AddPage(@cur_orientation); + if (ws > 0) + @ws = ws; + out(sprintf('%.3f Tw', ws * @k)); + end + else + @page += 1; + end + y=@t_margin; + end + rescale_y = (@page_break_trigger - y) / (info['h'] / (@img_scale * @k)) + rescale_y = 1 if rescale_y >= 1 + rescale = rescale_y >= rescale_x ? rescale_x : rescale_y + #Put image at 72 dpi # 2004-06-14 :: Nicola Asuni, scale factor where added - w = info['w'] / (@img_scale * @k); - h = info['h'] / (@img_scale * @k); - end - if (w == 0) + w = info['w'] * rescale / (@img_scale * @k); + h = info['h'] * rescale / (@img_scale * @k); + elsif (w == 0) w = h * info['w'] / info['h']; - end - if (h == 0) + elsif (h == 0) h = w * info['h'] / info['w']; end out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', w*@k, h*@k, x*@k, (@h-(y+h))*@k, info['i'])); @@ -2075,6 +2144,29 @@ else @y += h; end + + k=@k; + if (@y > @page_break_trigger and !@in_footer and AcceptPageBreak()) + #Automatic page break + if @pages[@page+1].nil? + x = @x; + ws = @ws; + if (ws > 0) + @ws = 0; + out('0 Tw'); + end + AddPage(@cur_orientation); + @x = x; + if (ws > 0) + @ws = ws; + out(sprintf('%.3f Tw', ws * k)); + end + else + @page += 1; + @y=@t_margin; + end + end + end alias_method :ln, :Ln @@ -2473,6 +2565,7 @@ def putType0(font) #Type0 + newobj(); out('<>'); putstream(pal); out('endobj'); @@ -2766,10 +2859,10 @@ end # - # Underline text + # Underline and Deleted text # @access protected # - def dounderline(x, y, txt) + def dolinetxt(x, y, txt) up = @current_font['up']; ut = @current_font['ut']; w = GetStringWidth(txt) + @ws * txt.count(' '); @@ -2785,7 +2878,7 @@ if (a.empty?) Error('Missing or incorrect image file: ' + file); end - if (a[2]!='JPEG') + if (!a[2].nil? and a[2]!='JPEG') Error('Not a JPEG file: ' + file); end if (a['channels'].nil? or a['channels']==3) @@ -2798,9 +2891,12 @@ bpc=!a['bits'].nil? ? a['bits'] : 8; #Read whole file data=''; - open(file,'rb') do |f| + + open( @@k_path_cache + File::basename(file),'rb') do |f| data< a[0],'h' => a[1],'cs' => colspace,'bpc' => bpc,'f'=>'DCTDecode','data' => data} end @@ -2821,11 +2917,11 @@ end w=freadint(f); h=freadint(f); - bpc=f.read(1)[0]; + bpc=f.read(1).unpack('C')[0]; if (bpc>8) Error('16-bit depth not supported: ' + file); end - ct=f.read(1)[0]; + ct=f.read(1).unpack('C')[0]; if (ct==0) colspace='DeviceGray'; elsif (ct==2) @@ -2835,13 +2931,13 @@ else Error('Alpha channel not supported: ' + file); end - if (f.read(1)[0] != 0) + if (f.read(1).unpack('C')[0] != 0) Error('Unknown compression method: ' + file); end - if (f.read(1)[0]!=0) + if (f.read(1).unpack('C')[0] != 0) Error('Unknown filter method: ' + file); end - if (f.read(1)[0]!=0) + if (f.read(1).unpack('C')[0] != 0) Error('Interlacing not supported: ' + file); end f.read(4); @@ -2861,9 +2957,9 @@ #Read transparency info t=f.read( n); if (ct==0) - trns = t[1][0] + trns = t[1].unpack('C')[0] elsif (ct==2) - trns = t[[1][0], t[3][0], t[5][0]] + trns = t[[1].unpack('C')[0], t[3].unpack('C')[0], t[5].unpack('C')[0]] else pos=t.include?(0.chr); if (pos!=false) @@ -3350,7 +3446,7 @@ # # Allows to preserve some HTML formatting.
    - # Supports: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small + # Supports: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, ins, del, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small # @param string :html text to display # @param boolean :ln if true add a new line after text (default = true) # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0. @@ -3364,12 +3460,38 @@ end @href = nil - @style = {} - html.gsub!(/[\t\r\n\f]/, "")#\0\x0B + @style = ""; + @t_cells = [[]]; + @table_id = 0; + + # pre calculate html.split(/(<[^>]+>)/).each do |element| if "<" == element[0,1] #Tag if (element[1, 1] == '/') + closedHTMLTagCalc(element[2..-2].downcase); + else + #Extract attributes + # get tag name + tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0} + tag = tag[0].downcase; + + # get attributes + attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/) + attrs = {} + attr_array.each do |name, value| + attrs[name.downcase] = value; + end + openHTMLTagCalc(tag, attrs); + end + end + end + @table_id = 0; + + html.split(/(<[A-Za-z!?\/][^>]*?>)/).each do |element| + if "<" == element[0,1] + #Tag + if (element[1, 1] == '/') closedHTMLTagHandler(element[2..-2].downcase); else #Extract attributes @@ -3389,14 +3511,32 @@ else #Text if (@href) + element.gsub!(/[\t\r\n\f]/, ""); addHtmlLink(@href, element, fill); elsif (@tdbegin) - if ((element.strip.length > 0) and (element != " ")) - Cell(@tdwidth, @tdheight, unhtmlentities(element.strip), @tableborder, 0, @tdalign, @tdfill); - elsif (element == " ") - Cell(@tdwidth, @tdheight, '', @tableborder, 0, @tdalign, @tdfill); + element.gsub!(/[\t\r\n\f]/, ""); + element.gsub!(/ /, " "); + base_page = @page; + base_x = @x; + base_y = @y; + + MultiCell(@tdwidth, @tdheight, unhtmlentities(element.strip), @tableborder, @tdalign, @tdfill, 1); + tr_end = @t_cells[@table_id][@tr_id][@td_id]['j1'] + 1; + if @max_td_page[tr_end].nil? or (@max_td_page[tr_end] < @page) + @max_td_page[tr_end] = @page + @max_td_y[tr_end] = @y + elsif (@max_td_page[tr_end] == @page) + @max_td_y[tr_end] = @y if @max_td_y[tr_end].nil? or (@max_td_y[tr_end] < @y) end - elsif ((element.strip.length > 0) and (element != " ")) + + @page = base_page; + @x = base_x + @tdwidth; + @y = base_y; + elsif (@pre_state == true and element.length > 0) + Write(@lasth, unhtmlentities(element), '', fill); + elsif (element.strip.length > 0) + element.gsub!(/[\t\r\n\f]/, ""); + element.gsub!(/ /, " "); Write(@lasth, unhtmlentities(element), '', fill); end end @@ -3422,7 +3562,7 @@ # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. # @see Cell() # - def writeHTMLCell(w, h, x, y, html='', border=0, ln=0, fill=0) + def writeHTMLCell(w, h, x, y, html='', border=0, ln=1, fill=0) if (@lasth == 0) #set row height @@ -3446,6 +3586,24 @@ w = @fw - x - @r_margin; end + b=0; + if (border) + if (border==1) + border='LTRB'; + b='LRT'; + b2='LR'; + elsif border.is_a?(String) + b2=''; + if (border.include?('L')) + b2<<'L'; + end + if (border.include?('R')) + b2<<'R'; + end + b=(border.include?('T')) ? b2 + 'T' : b2; + end + end + # store original margin values l_margin = @l_margin; r_margin = @r_margin; @@ -3461,37 +3619,196 @@ currentY = GetY(); + @auto_page_break = false; # check if a new page has been created if (@page > pagenum) # design a cell around the text on first page currentpage = @page; @page = pagenum; SetY(GetPageHeight() - restspace - GetBreakMargin()); - h = restspace - 1; - Cell(w, h, "", border, ln, 'L', 0); + Cell(w, restspace - 1, "", b, 0, 'L', 0); + b = b2; + @page += 1; + while @page < currentpage + SetY(@t_margin); # put cursor at the beginning of text + Cell(w, @page_break_trigger - @t_margin, "", b, 0, 'L', 0); + @page += 1; + end + if (border.is_a?(String) and border.include?('B')) + b<<'B'; + end # design a cell around the text on last page - @page = currentpage; - h = currentY - @t_margin; SetY(@t_margin); # put cursor at the beginning of text - Cell(w, h, "", border, ln, 'L', 0); + Cell(w, currentY - @t_margin, "", b, 0, 'L', 0); else - h = [h, (currentY - y)].max; SetY(y); # put cursor at the beginning of text # design a cell around the text - Cell(w, h, "", border, ln, 'L', 0); + Cell(w, [h, (currentY - y)].max, "", border, 0, 'L', 0); end + @auto_page_break = true; # restore original margin values SetLeftMargin(l_margin); SetRightMargin(r_margin); - if (ln) - Ln(0); + @lasth = h + + # move cursor to specified position + if (ln == 0) + # go to the top-right of the cell + @x = x + w; + @y = y; + elsif (ln == 1) + # go to the beginning of the next line + @x = @l_margin; + @y = currentY; + elsif (ln == 2) + # go to the bottom-left of the cell (below) + @x = x; + @y = currentY; end end alias_method :write_html_cell, :writeHTMLCell # + # Check html table tag position. + # + # @param array :table potision array + # @param int :current tr tag id number + # @param int :current td tag id number + # @access private + # @return int : next td_id position. + # value 0 mean that can use position. + # + def checkTableBlockingCellPosition(table, tr_id, td_id ) + 0.upto(tr_id) do |j| + 0.upto(@t_cells[table][j].size - 1) do |i| + if @t_cells[table][j][i]['i0'] <= td_id and td_id <= @t_cells[table][j][i]['i1'] + if @t_cells[table][j][i]['j0'] <= tr_id and tr_id <= @t_cells[table][j][i]['j1'] + return @t_cells[table][j][i]['i1'] - td_id + 1; + end + end + end + end + return 0; + end + + # + # Calculate opening tags. + # + # html table cell array : @t_cells + # + # i0: table cell start position + # i1: table cell end position + # j0: table row start position + # j1: table row end position + # + # +------+ + # |i0,j0 | + # | i1,j1| + # +------+ + # + # example html: + # + # + # + # + # + #
    + # + # i: 0 1 2 + # j+----+----+----+ + # :|0,0 |1,0 |2,0 | + # 0| 0,0| 1,0| 2,0| + # +----+----+----+ + # |0,1 |2,1 | + # 1| 1,1| 2,1| + # +----+----+----+ + # |0,2 |1,2 |2,2 | + # 2| | 1,2| 2,2| + # + +----+----+ + # | |1,3 |2,3 | + # 3| 0,3| 1,3| 2,3| + # +----+----+----+ + # + # html table cell array : + # [[[i0=>0,j0=>0,i1=>0,j1=>0],[i0=>1,j0=>0,i1=>1,j1=>0],[i0=>2,j0=>0,i1=>2,j1=>0]], + # [[i0=>0,j0=>1,i1=>1,j1=>1],[i0=>2,j0=>1,i1=>2,j1=>1]], + # [[i0=>0,j0=>2,i1=>0,j1=>3],[i0=>1,j0=>2,i1=>1,j1=>2],[i0=>2,j0=>2,i1=>2,j1=>2]] + # [[i0=>1,j0=>3,i1=>1,j1=>3],[i0=>2,j0=>3,i1=>2,j1=>3]]] + # + # @param string :tag tag name (in upcase) + # @param string :attr tag attribute (in upcase) + # @access private + # + def openHTMLTagCalc(tag, attrs) + #Opening tag + case (tag) + when 'table' + @max_table_columns[@table_id] = 0; + @t_columns = 0; + @tr_id = -1; + when 'tr' + if @max_table_columns[@table_id] < @t_columns + @max_table_columns[@table_id] = @t_columns; + end + @t_columns = 0; + @tr_id += 1; + @td_id = -1; + @t_cells[@table_id].push [] + when 'td', 'th' + @td_id += 1; + if attrs['colspan'].nil? or attrs['colspan'] == '' + colspan = 1; + else + colspan = attrs['colspan'].to_i; + end + if attrs['rowspan'].nil? or attrs['rowspan'] == '' + rowspan = 1; + else + rowspan = attrs['rowspan'].to_i; + end + + i = 0; + while true + next_i_distance = checkTableBlockingCellPosition(@table_id, @tr_id, @td_id + i); + if next_i_distance == 0 + @t_cells[@table_id][@tr_id].push "i0"=>@td_id + i, "j0"=>@tr_id, "i1"=>(@td_id + i + colspan - 1), "j1"=>@tr_id + rowspan - 1 + break; + end + i += next_i_distance; + end + + @t_columns += colspan; + end + end + + # + # Calculate closing tags. + # @param string :tag tag name (in upcase) + # @access private + # + def closedHTMLTagCalc(tag) + #Closing tag + case (tag) + when 'table' + if @max_table_columns[@table_id] < @t_columns + @max_table_columns[@table_id] = @t_columns; + end + @table_id += 1; + @t_cells.push [] + end + end + + # + # Convert to accessible file path + # @param string :attrname image file name + # + def getImageFilename( attrname ) + nil + end + + # # Process opening tags. # @param string :tag tag name (in upcase) # @param string :attr tag attribute (in upcase) @@ -3501,20 +3818,56 @@ def openHTMLTagHandler(tag, attrs, fill=0) #Opening tag case (tag) + when 'pre' + @pre_state = true; + @l_margin += 5; + @r_margin += 5; + @x += 5; + when 'table' + if @default_table_columns < @max_table_columns[@table_id] + @table_columns = @max_table_columns[@table_id]; + else + @table_columns = @default_table_columns; + end + @l_margin += 5; + @r_margin += 5; + @x += 5; + if attrs['border'].nil? or attrs['border'] == '' @tableborder = 0; else @tableborder = attrs['border']; end + @tr_id = -1; + @max_td_page[0] = @page; + @max_td_y[0] = @y; + when 'tr', 'td', 'th' - # SetStyle('b', true) if tag == 'th' - + if tag == 'th' + SetStyle('b', true); + @tdalign = "C"; + end if ((!attrs['width'].nil?) and (attrs['width'] != '')) @tdwidth = (attrs['width'].to_i/4); else - @tdwidth = ((@w - @l_margin - @r_margin) / @default_table_columns); + @tdwidth = ((@w - @l_margin - @r_margin) / @table_columns); end + + if tag == 'tr' + @tr_id += 1; + @td_id = -1; + else + @td_id += 1; + @x = @l_margin + @tdwidth * @t_cells[@table_id][@tr_id][@td_id]['i0']; + end + + if attrs['colspan'].nil? or attrs['border'] == '' + @colspan = 1; + else + @colspan = attrs['colspan'].to_i; + end + @tdwidth *= @colspan; if ((!attrs['height'].nil?) and (attrs['height'] != '')) @tdheight=(attrs['height'].to_i / @k); else @@ -3538,17 +3891,14 @@ @tdbegin=true; when 'hr' - Ln(); + margin = 1; if ((!attrs['width'].nil?) and (attrs['width'] != '')) hrWidth = attrs['width']; else - hrWidth = @w - @l_margin - @r_margin; + hrWidth = @w - @l_margin - @r_margin - margin; end - x = GetX(); - y = GetY(); SetLineWidth(0.2); - Line(x, y, x + hrWidth, y); - SetLineWidth(0.2); + Line(@x + margin, @y, @x + hrWidth, @y); Ln(); when 'strong' @@ -3557,6 +3907,12 @@ when 'em' SetStyle('i', true); + when 'ins' + SetStyle('u', true); + + when 'del' + SetStyle('d', true); + when 'b', 'i', 'u' SetStyle(tag, true); @@ -3565,8 +3921,17 @@ when 'img' if (!attrs['src'].nil?) - # replace relative path with real server path - attrs['src'] = attrs['src'].gsub(@@k_path_url_cache, @@k_path_cache); + # Only generates image include a pdf if RMagick is avalaible + unless Object.const_defined?(:Magick) + Write(@lasth, attrs['src'], '', fill); + return + end + file = getImageFilename(attrs['src']) + if (file.nil?) + Write(@lasth, attrs['src'], '', fill); + return + end + if (attrs['width'].nil?) attrs['width'] = 0; end @@ -3574,40 +3939,80 @@ attrs['height'] = 0; end - Image(attrs['src'], GetX(),GetY(), pixelsToMillimeters(attrs['width']), pixelsToMillimeters(attrs['height'])); - #SetX(@img_rb_x); - SetY(@img_rb_y); - + begin + Image(file, GetX(),GetY(), pixelsToMillimeters(attrs['width']), pixelsToMillimeters(attrs['height'])); + #SetX(@img_rb_x); + SetY(@img_rb_y); + rescue => err + logger.error "pdf: Image: error: #{err.message}" + Write(@lasth, attrs['src'], '', fill); + if File.file?( @@k_path_cache + File::basename(file)) + File.delete( @@k_path_cache + File::basename(file)) + end + end end - when 'ul' - @listordered = false; - @listcount = 0; - - when 'ol' - @listordered = true; - @listcount = 0; + when 'ul', 'ol' + if @li_count == 0 + Ln() if @prevquote_count == @quote_count; # insert Ln for keeping quote lines + @prevquote_count = @quote_count; + end + if @li_state == true + Ln(); + @li_state = false; + end + if tag == 'ul' + @list_ordered[@li_count] = false; + else + @list_ordered[@li_count] = true; + end + @list_count[@li_count] = 0; + @li_count += 1 when 'li' - Ln(); - if (@listordered) - @listcount += 1 - @lispacer = " " + (@listcount).to_s + ". "; + Ln() if @li_state == true + if (@list_ordered[@li_count - 1]) + @list_count[@li_count - 1] += 1; + @li_spacer = " " * @li_count + (@list_count[@li_count - 1]).to_s + ". "; else #unordered list simbol - @lispacer = " - "; + @li_spacer = " " * @li_count + "- "; end - Write(@lasth, @lispacer, '', fill); + Write(@lasth, @spacer + @li_spacer, '', fill); + @li_state = true; - when 'blockquote', 'br' + when 'blockquote' + if (@quote_count == 0) + SetStyle('i', true); + @l_margin += 5; + else + @l_margin += 5 / 2; + end + @x = @l_margin; + @quote_top[@quote_count] = @y; + @quote_page[@quote_count] = @page; + @quote_count += 1 + when 'br' Ln(); - if (@lispacer.length > 0) - @x += GetStringWidth(@lispacer); + + if (@li_spacer.length > 0) + @x += GetStringWidth(@li_spacer); end when 'p' Ln(); - Ln(); + 0.upto(@quote_count - 1) do |i| + if @quote_page[i] == @page; + if @quote_top[i] == @y - @lasth; # fix start line + @quote_top[i] = @y; + end + else + if @quote_page[i] == @page - 1; + @quote_page[i] = @page; # fix start line + @quote_top[i] = @t_margin; + end + end + end when 'sup' currentfont_size = @font_size; @@ -3648,6 +4053,7 @@ @lasth = @font_size * @@k_cell_height_ratio; when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' + Ln(); headsize = (4 - tag[1,1].to_f) * 2 @tempfontsize = @font_size_pt; SetFontSize(@font_size_pt + headsize); @@ -3665,19 +4071,63 @@ def closedHTMLTagHandler(tag) #Closing tag case (tag) + when 'pre' + @pre_state = false; + @l_margin -= 5; + @r_margin -= 5; + @x = @l_margin; + Ln(); + when 'td','th' @tdbegin = false; @tdwidth = 0; @tdheight = 0; @tdalign = "L"; + SetStyle('b', false); @tdfill = 0; SetFillColor(@prevfill_color[0], @prevfill_color[1], @prevfill_color[2]); when 'tr' - Ln(); + @y = @max_td_y[@tr_id + 1]; + @x = @l_margin; + @page = @max_td_page[@tr_id + 1]; when 'table' + # Write Table Line + width = (@w - @l_margin - @r_margin) / @table_columns; + 0.upto(@t_cells[@table_id].size - 1) do |j| + 0.upto(@t_cells[@table_id][j].size - 1) do |i| + @page = @max_td_page[j] + i0=@t_cells[@table_id][j][i]['i0']; + j0=@t_cells[@table_id][j][i]['j0']; + i1=@t_cells[@table_id][j][i]['i1']; + j1=@t_cells[@table_id][j][i]['j1']; + + Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j0]) # top + if ( @page == @max_td_page[j1 + 1]) + Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @max_td_y[j1+1]) # left + Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j1+1]) # right + else + Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @page_break_trigger) # left + Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @page_break_trigger) # right + @page += 1; + while @page < @max_td_page[j1 + 1] + Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @page_break_trigger) # left + Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @page_break_trigger) # right + @page += 1; + end + Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @max_td_y[j1+1]) # left + Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @max_td_y[j1+1]) # right + end + Line(@l_margin + width * i0, @max_td_y[j1+1], @l_margin + width * (i1+1), @max_td_y[j1+1]) # bottom + end + end + + @l_margin -= 5; + @r_margin -= 5; @tableborder=0; + Ln(); + @table_id += 1; when 'strong' SetStyle('b', false); @@ -3685,12 +4135,21 @@ when 'em' SetStyle('i', false); + when 'ins' + SetStyle('u', false); + + when 'del' + SetStyle('d', false); + when 'b', 'i', 'u' SetStyle(tag, false); when 'a' @href = nil; + when 'p' + Ln(); + when 'sup' currentfont_size = @font_size; SetFontSize(@tempfontsize); @@ -3725,14 +4184,47 @@ #@text_color = @prevtext_color; @lasth = @font_size * @@k_cell_height_ratio; - when 'ul' - Ln(); - - when 'ol' - Ln(); + when 'blockquote' + @quote_count -= 1 + if (@quote_page[@quote_count] == @page) + Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @y) # quoto line + else + cur_page = @page; + cur_y = @y; + @page = @quote_page[@quote_count]; + if (@quote_top[@quote_count] < @page_break_trigger) + Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @page_break_trigger) # quoto line + end + @page += 1; + while @page < cur_page + Line(@l_margin - 1, @t_margin, @l_margin - 1, @page_break_trigger) # quoto line + @page += 1; + end + @y = cur_y; + Line(@l_margin - 1, @t_margin, @l_margin - 1, @y) # quoto line + end + if (@quote_count <= 0) + SetStyle('i', false); + @l_margin -= 5; + else + @l_margin -= 5 / 2; + end + @x = @l_margin; + Ln() if @quote_count == 0 + + when 'ul', 'ol' + @li_count -= 1 + if @li_state == true + Ln(); + @li_state = false; + end when 'li' - @lispacer = ""; + @li_spacer = ""; + if @li_state == true + Ln(); + @li_state = false; + end when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' SetFontSize(@tempfontsize); @@ -3740,7 +4232,17 @@ SetStyle('b', false); Ln(); @lasth = @font_size * @@k_cell_height_ratio; - + + if tag == 'h1' or tag == 'h2' or tag == 'h3' or tag == 'h4' + margin = 1; + hrWidth = @w - @l_margin - @r_margin - margin; + if tag == 'h1' or tag == 'h2' + SetLineWidth(0.2); + else + SetLineWidth(0.1); + end + Line(@x + margin, @y, @x + hrWidth, @y); + end end end @@ -3752,11 +4254,16 @@ # def SetStyle(tag, enable) #Modify style and select corresponding font - style=''; - ['b', 'i', 'u'].each do |s| - style << s if tag.downcase == s and enable + ['b', 'i', 'u', 'd'].each do |s| + if tag.downcase == s + if enable + @style << s if ! @style.include?(s) + else + @style = @style.gsub(s,'') + end + end end - SetFont('', style); + SetFont('', @style); end #